123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 |
- import { execSync } from 'child_process';
- import os from 'os';
- import fs from 'fs';
- import * as path from 'path';
- import Progress from '../util/Progress';
- import Analyzer from './Analyzer';
- type Z8ClassProperties = {
- static: boolean,
- type: string,
- key: string,
- value: string,
- inherited: boolean,
- dynamic: boolean,
- overridden: boolean,
- nearestParent?: string,
- nearestParentRoot?: string
- };
- type ClassMapEntity = {
- name: string,
- root: string,
- filePath: string,
- shortName?: string | null,
- extends: string | null,
- children: string[],
- parentsBranch: string[],
- mixins: string[],
- mixedIn: string[],
- statics: Z8ClassProperties[],
- properties: Z8ClassProperties[],
- dynamicProperties: Z8ClassProperties[],
- isPackage: false
- };
- type ClassMap = {
- [key: string]: ClassMapEntity
- };
- type PackageEntity = {
- name: string,
- root: string,
- isPackage: true
- };
- class Sources {
- private static repoNames: string[] = [];
- private static repoUrls: string[] = [];
- private static repoSourcePaths: string[] = [];
- private static repoSourceCopyPaths: string[] = [];
- private static repoSparseCheckoutPaths: string[] = [];
- private static repoCollectFromPaths: string[] = [];
- public static sourcesPath: string = `${os.homedir()}/.doczilla_js_docs`;
- public static sourcesCopyPath = `${Sources.sourcesPath}/JsSources`;
- public static dzAppPath = `${Sources.sourcesCopyPath}/DZApp.js`;
- public static classMapPath = `${Sources.sourcesCopyPath}/ClassMap.json`;
- public static ClassMap: ClassMap = {};
- public static Z8Locales: { [key: string]: { [key: string]: string } } = {};
- private static init(): void {
- // refresh
- Sources.sourcesPath = '';
- Sources.repoNames = [];
- Sources.repoUrls = [];
- Sources.repoSourcePaths = [];
- Sources.repoSourceCopyPaths = [];
- Sources.repoSparseCheckoutPaths = [];
- Sources.repoCollectFromPaths = [];
- const SourcesConfig = JSON.parse(fs.readFileSync(path.resolve(__dirname,'../config.json'), { encoding: 'utf-8' }).toString()).sources;
- Sources.sourcesPath = `${os.homedir()}/${SourcesConfig.assetsDir}`;
- for(const repoInfo of SourcesConfig.repos) {
- Sources.repoNames.push(repoInfo.name);
- Sources.repoUrls.push(repoInfo.url);
- Sources.repoSourcePaths.push(`${Sources.sourcesPath}/${repoInfo.name}`);
- Sources.repoSourceCopyPaths.push(`${Sources.sourcesCopyPath}/${repoInfo.name}`);
- Sources.repoSparseCheckoutPaths.push(repoInfo.sparseCheckout);
- Sources.repoCollectFromPaths.push(repoInfo.collectFrom);
- }
- }
- public static get(callback?: () => any): ClassMap {
- if(fs.existsSync(Sources.classMapPath)) {
- Sources.ClassMap = JSON.parse(fs.readFileSync(Sources.classMapPath).toString());
- Sources.repoNames = JSON.parse(fs.readFileSync(path.resolve(__dirname,'../config.json'), { encoding: 'utf-8' }).toString()).sources.repos.map((repo: { name: string; }) => repo.name);
- Analyzer.analyze(null, callback, true);
- } else {
- Sources.update(callback);
- }
- return Sources.ClassMap;
- }
- public static getShortenedClassMap(): { [key: string]: { shortName: string | null, filePath: string, name: string } } {
- const classList: { [key: string]: { shortName: string | null, filePath: string, name: string } } = {};
-
- Object.keys(Sources.ClassMap).map((cls) => {
- const scls = Sources.ClassMap[cls];
- classList[cls] = { name: cls, shortName: scls.shortName || null, filePath: scls.filePath };
- });
- return classList;
- }
- public static getRepoNames(): string[] {
- return Sources.repoNames;
- }
- public static time(): Date {
- return fs.statSync(Sources.classMapPath).birthtime;
- }
- public static findClass(className: string): ClassMapEntity | null {
- if(Sources.ClassMap[className])
- return Sources.ClassMap[className];
- const keys = Object.keys(Sources.ClassMap).filter((key) => {
- return Sources.ClassMap[key].shortName === className;
- });
- if(keys.length === 1)
- return Sources.ClassMap[keys[0]];
- return null;
- }
- public static findPackage(root: string, packageName: string): PackageEntity | null {
- const regex = /^(?!.*\.\.)(?!\.)[a-zA-Zа-яА-Я0-9.]+(?<!\.)$/;
- if(!regex.test(packageName))
- return null;
- const keys = Object.keys(Sources.ClassMap).filter((key) => {
- return key.startsWith(packageName) && key !== packageName && Sources.ClassMap[key].root === root;
- });
- if(keys.length > 0)
- return { name: packageName, root: root, isPackage: true };
- return null;
- }
- public static update(callback?: () => any, silent?: boolean): void {
- Sources.init();
- Sources.clone(silent);
- Sources.copy(silent);
- Sources.collect(silent);
- Analyzer.analyze(Sources.ClassMap, callback, silent);
- }
- private static clone(silent?: boolean): void {
- if(!fs.existsSync(Sources.sourcesPath))
- fs.mkdirSync(Sources.sourcesPath);
- const progress = silent ? null : Progress.start('Sources update, Step 1 [Clone/Pull]:', Sources.repoNames.length);
- for(let i = 0; i < Sources.repoNames.length; i++) {
- if(fs.existsSync(Sources.repoSourcePaths[i])) {
- execSync('git pull', { encoding: 'utf8', cwd: Sources.repoSourcePaths[i], stdio: [] });
- progress && progress.next();
- } else {
- execSync(Sources.getCloneCommand(Sources.repoUrls[i]), { encoding: 'utf8', cwd: Sources.sourcesPath, stdio: [] });
- execSync(`git sparse-checkout set ${Sources.repoSparseCheckoutPaths[i]}`, { encoding: 'utf8', cwd: Sources.repoSourcePaths[i], stdio: [] });
- progress && progress.next();
- }
- }
- progress && progress.finish();
- }
- private static copy(silent?: boolean): void {
- if(fs.existsSync(Sources.sourcesCopyPath))
- fs.rmSync(Sources.sourcesCopyPath, { recursive: true, force: true });
- fs.mkdirSync(Sources.sourcesCopyPath);
- const progress = silent ? null : Progress.start('Sources update, Step 2 [Copy]:', Sources.repoNames.length);
- for(let i = 0; i < Sources.repoNames.length; i++) {
- fs.mkdirSync(Sources.repoSourceCopyPaths[i]);
- fs.cpSync(`${Sources.repoSourcePaths[i]}/${Sources.repoCollectFromPaths[i]}`, Sources.repoSourceCopyPaths[i], { recursive: true });
- progress && progress.next();
- }
- progress && progress.finish();
- }
- private static collect(silent?: boolean): void {
- if(fs.existsSync(Sources.dzAppPath))
- fs.rmSync(Sources.dzAppPath, { force: true });
- Sources.ClassMap = {};
- const buildorders = [];
- let totalBuildordersLength = 0;
- for(let i = 0; i < Sources.repoNames.length; i++) {
- const bo = fs.readFileSync(`${Sources.repoSourceCopyPaths[i]}/.buildorder`, 'utf8').toString().replaceAll('\r', '').split('\n').filter((str) => { return str.length > 0; });
- buildorders.push(bo);
- totalBuildordersLength += bo.length;
- }
- const progress = silent ? null : Progress.start('Sources update, Step 3 [Collect]:', totalBuildordersLength);
- for(let i = 0; i < Sources.repoNames.length; i++) {
- Sources.processBuildorder(buildorders[i], Sources.repoSourceCopyPaths[i], Sources.repoNames[i], progress);
- }
- progress && progress.finish();
- }
- private static processBuildorder(buildorder: string[], sourcesRoot: string, pathPrefix: string, progress: Progress | null): void {
- const z8DefinePattern: RegExp = /Z8\.define\('([^']+)'/g;
- const dynamicPropertiesPattern: RegExp = /this\.([\wа-яА-Я_$]+)\s*=;/g;
- const dynamicConfigPropertiesPattern: RegExp = /this\.([\wа-яА-Я_$]+)/g;
- for(const filePath of buildorder) {
- const content = fs.readFileSync(`${sourcesRoot}/${filePath}`, 'utf8').toString();
- const defines: string[] = Array.from(content.matchAll(z8DefinePattern), match => match[1]);
- for(const define of defines) {
- const classRx = new RegExp(`Z8\\.define\\(\'${define}\',\\s*\\{(?:.|[\r\n])+?^\\}\\);?`, 'gm');
- const classContentRxArray = content.match(classRx); // change to `classContent = content.match(classRx)![0]` after `}\n);` issue fixed
- const classContent = classContentRxArray ? classContentRxArray[0] : '';
- const dynamicProperties = Sources.cleanDuplicates(Array.from(classContent.matchAll(dynamicPropertiesPattern), (match) => {
- return {
- static: false,
- type: 'undefined',
- key: match[1],
- value: '',
- inherited: false,
- dynamic: true,
- overridden: false
- };
- }));
- const dynamicConfigProperties = Sources.cleanDuplicates(Array.from(classContent.matchAll(dynamicConfigPropertiesPattern), (match) => {
- return {
- static: false,
- type: 'undefined',
- key: match[1],
- value: '',
- inherited: false,
- dynamic: true,
- overridden: false
- };
- }).filter(item1 => !dynamicProperties.some(item2 => item2.key === item1.key)));
- Sources.ClassMap[define] = { name: define, root: pathPrefix, filePath: `${pathPrefix}/${filePath}`, children: [], extends: null, parentsBranch: [], mixins: [], mixedIn: [], properties: dynamicProperties, dynamicProperties: dynamicConfigProperties, statics: [], isPackage: false };
- }
- fs.writeFileSync(Sources.dzAppPath, content + '\n', { flag: 'a+', encoding: 'utf8' });
- progress && progress.next();
- }
- }
- private static getCloneCommand(repoUrl: string): string {
- return `git clone --depth=1 --single-branch --branch dev --filter=blob:none --sparse ${repoUrl}`;
- }
- private static cleanDuplicates(array: Z8ClassProperties[]): Z8ClassProperties[] {
- for(let i = array.length - 1; i >= 0; i--) {
- const currentItem = array[i];
- const duplicateIndex = array.findIndex((item, index) => index !== i && item.key === currentItem.key);
- if (duplicateIndex !== -1) {
- array.splice(i, 1);
- }
- }
- return array;
- }
- }
- export { Sources, ClassMap, ClassMapEntity, PackageEntity, Z8ClassProperties };
|