mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ADF-2236] Automatic check export (#2933)
* save export in a file * print errors * add position error * color error log and add comment to skip a file * export check ver 2 * ignore source * fix export modules * fix possible nullable value * remove duplicates * improve logs * add travis configuration * fix travis and import * export fix * remove export check js file * add export check js ignore * fix content metadata service export
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -21,3 +21,5 @@ package-lock.*
|
||||
/ng2-components/ng2-alfresco-core/prebuilt-themes/
|
||||
.ng_pkg_build/
|
||||
/demo-shell/dist-dev-temp/
|
||||
/lib/export-new.json
|
||||
/lib/config/exportCheck.js
|
||||
|
@@ -62,6 +62,8 @@ jobs:
|
||||
include:
|
||||
- stage: Check 2.0.0 Project Update
|
||||
script: ./scripts/test-e2e-bc.sh
|
||||
- stage: Check ADF exports
|
||||
script: cd lib && npm run test-export
|
||||
|
||||
# jobs:
|
||||
# include:
|
||||
|
354
lib/config/exportCheck.ts
Normal file
354
lib/config/exportCheck.ts
Normal file
@@ -0,0 +1,354 @@
|
||||
import * as ts from "typescript";
|
||||
import * as fs from "fs";
|
||||
import chalk from "chalk";
|
||||
|
||||
interface DocEntry {
|
||||
position?: {
|
||||
line: number,
|
||||
character: number,
|
||||
fileName: string
|
||||
},
|
||||
name?: string,
|
||||
skipError?: boolean
|
||||
};
|
||||
|
||||
let error_array = [];
|
||||
let warning_array = [];
|
||||
let exportedAllPath: Array<string> = [];
|
||||
let classList: Array<any> = [];
|
||||
|
||||
let add_error = function (error: string, nameClass: string) {
|
||||
let findErrorClass = false;
|
||||
|
||||
error_array.forEach((currentError) => {
|
||||
|
||||
if (currentError.nameClass === nameClass) {
|
||||
findErrorClass = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
if (!findErrorClass) {
|
||||
error_array.push({
|
||||
error: error,
|
||||
nameClass: nameClass
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let count_error = 0;
|
||||
let count_warning = 0;
|
||||
|
||||
let print_errors = function () {
|
||||
error_array.forEach((current_error) => {
|
||||
console.log(chalk.red(`[${++count_error}] ${current_error.error}\n`));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
let add_warning = function (warning: string, nameClass: string, arrayCall: string[]) {
|
||||
|
||||
let findWarningClass = false;
|
||||
|
||||
warning_array.forEach((currentWarning) => {
|
||||
|
||||
if (currentWarning.nameClass === nameClass) {
|
||||
findWarningClass = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
if (!findWarningClass) {
|
||||
warning_array.push({
|
||||
warning: warning,
|
||||
nameClass: nameClass,
|
||||
arrayCall: arrayCall
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let print_warnings = function () {
|
||||
warning_array.forEach((current_warning) => {
|
||||
console.log(chalk.yellow(`[${++count_warning}] ${current_warning.warning} \n ${current_warning.arrayCall} \n`));
|
||||
});
|
||||
}
|
||||
|
||||
let currentErrorPostion = function (exportEntry) {
|
||||
return ` ${exportEntry.position.fileName} (${exportEntry.position.line},${exportEntry.position.character})`
|
||||
}
|
||||
|
||||
let check_export = function (export_old: any, export_new: any) {
|
||||
|
||||
export_old.forEach((currentExport_old) => {
|
||||
|
||||
let currentExport_new = export_new.filter((currentExport_new) => {
|
||||
return currentExport_new.name === currentExport_old.name;
|
||||
});
|
||||
|
||||
if (currentExport_new.length > 1) {
|
||||
|
||||
let arrayCall = [];
|
||||
|
||||
currentExport_new.forEach((error) => {
|
||||
arrayCall.push(`${currentErrorPostion(error)}`);
|
||||
})
|
||||
|
||||
add_warning(`Multiple export ${currentExport_new[0].name} times ${currentExport_new.length}`, currentExport_new[0].name, arrayCall);
|
||||
|
||||
} else if (currentExport_new.length === 0) {
|
||||
if (!currentExport_old.skipError) {
|
||||
add_error(`Not find export ${currentExport_old.name} , old path: [${currentErrorPostion(currentExport_old)}]`, currentExport_old.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
let expandStarExport = function (node: ts.Node): ts.ExportDeclaration {
|
||||
const ed = node as ts.Node as ts.ExportDeclaration;
|
||||
const exports = [{ name: "x" }];
|
||||
const exportSpecifiers = exports.map(e => ts.createExportSpecifier(e.name, e.name));
|
||||
const exportClause = ts.createNamedExports(exportSpecifiers);
|
||||
const newEd = ts.updateExportDeclaration(ed, ed.decorators, ed.modifiers, exportClause, ed.moduleSpecifier);
|
||||
|
||||
return newEd as ts.ExportDeclaration
|
||||
};
|
||||
|
||||
/** Generate documentation for all classes in a set of .ts files */
|
||||
function generatExportList(fileNames: string[], options: ts.CompilerOptions): void {
|
||||
// Build a program using the set of root file names in fileNames
|
||||
let program = ts.createProgram(fileNames, options);
|
||||
// Get the checker, we will use it to find more about classes
|
||||
let checker = program.getTypeChecker();
|
||||
|
||||
let exportCurrentVersion: DocEntry[] = [];
|
||||
|
||||
// Visit every sourceFile in the program
|
||||
for (const sourceFile of program.getSourceFiles()) {
|
||||
if (!sourceFile.isDeclarationFile) {
|
||||
// Walk the tree to search for classes
|
||||
ts.forEachChild(sourceFile, visit);
|
||||
}
|
||||
}
|
||||
|
||||
classList.forEach((classNode) => {
|
||||
if (classNode.symbol.parent) {
|
||||
let pathClass = classNode.symbol.parent.escapedName.replace(/"/g, "");
|
||||
|
||||
exportedAllPath.forEach((currenPath) => {
|
||||
let pathNoExtension = currenPath.replace(/\.[^/.]+$/, "");
|
||||
|
||||
if (pathNoExtension === pathClass) {
|
||||
// console.log('pathClass'+ pathClass);
|
||||
// console.log('pathNoExtension '+ pathNoExtension);
|
||||
extractExport(classNode);
|
||||
return;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
exportCurrentVersion.sort((nameA, nameB) => nameA.name.localeCompare(nameB.name));
|
||||
|
||||
console.log(chalk.green('Saving new export in export-new.json'));
|
||||
|
||||
fs.writeFileSync('export-new.json', JSON.stringify(exportCurrentVersion, undefined, 4));
|
||||
|
||||
try {
|
||||
var export_old = JSON.parse(fs.readFileSync('export-2.0.0.json', 'utf8'));
|
||||
} catch (error) {
|
||||
console.log(chalk.red('export-2.0.0.json not present'));
|
||||
throw new Error('Undetected export comapring file');
|
||||
}
|
||||
|
||||
var export_new = JSON.parse(JSON.stringify(exportCurrentVersion));
|
||||
|
||||
console.log(chalk.green('Comparing export-2.0.0.json and export-new.json'));
|
||||
|
||||
check_export(export_old, export_new);
|
||||
|
||||
print_warnings();
|
||||
print_errors();
|
||||
|
||||
if (error_array.length > 0) {
|
||||
throw new Error('Export problems detected');
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
function extractExport(node: ts.Node) {
|
||||
//skip file with export-check: exclude comment
|
||||
if (node.getFullText(node.getSourceFile()).indexOf('export-check: exclude') > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let { line, character } = node.getSourceFile().getLineAndCharacterOfPosition(node.getStart());
|
||||
//console.log(line + " " + character + " " + node.getSourceFile().fileName);
|
||||
|
||||
let symbol = checker.getSymbolAtLocation(node);
|
||||
|
||||
if (symbol) {
|
||||
let arryCalls = recursiveStackSave(node);
|
||||
|
||||
let className: any = symbol.escapedName;
|
||||
let filename = node.getSourceFile().fileName.substring(node.getSourceFile().fileName.indexOf('lib'), node.getSourceFile().fileName.length);
|
||||
exportCurrentVersion.push(serializeClass(className, line, character, filename, arryCalls));
|
||||
|
||||
// if (className === "ContentMetadataService") {
|
||||
// console.log(chalk.red("exportedAllPath" + exportedAllPath));
|
||||
// console.log(chalk.red("ContentMetadataService"));
|
||||
// recursiveStack(node);
|
||||
// }
|
||||
|
||||
} else {
|
||||
|
||||
let arryCalls = recursiveStackSave(node);
|
||||
|
||||
let className: any = (node as ts.ClassDeclaration).name.escapedText;
|
||||
let filename = node.getSourceFile().fileName.substring(node.getSourceFile().fileName.indexOf('lib'), node.getSourceFile().fileName.length);
|
||||
exportCurrentVersion.push(serializeClass(className, line, character, filename, arryCalls));
|
||||
|
||||
// if (className === "ContentMetadataService") {
|
||||
// console.log(chalk.greenBright("exportedAllPath" + exportedAllPath));
|
||||
// console.log(chalk.greenBright("ContentMetadataService"));
|
||||
// recursiveStack(node);
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function recursiveStackSave(node: ts.Node, arrayCalls?: string[]) {
|
||||
if (!arrayCalls) {
|
||||
arrayCalls = [];
|
||||
}
|
||||
|
||||
let filename = node.getSourceFile().fileName.substring(node.getSourceFile().fileName.indexOf('lib'), node.getSourceFile().fileName.length);
|
||||
let { line, character } = node.getSourceFile().getLineAndCharacterOfPosition(node.getStart());
|
||||
|
||||
arrayCalls.push(node.getSourceFile().fileName);
|
||||
|
||||
if (node.parent) {
|
||||
recursiveStackSave(node.parent, arrayCalls)
|
||||
}
|
||||
|
||||
return arrayCalls;
|
||||
|
||||
}
|
||||
|
||||
function recursiveStack(node: ts.Node) {
|
||||
let filename = node.getSourceFile().fileName.substring(node.getSourceFile().fileName.indexOf('lib'), node.getSourceFile().fileName.length);
|
||||
let { line, character } = node.getSourceFile().getLineAndCharacterOfPosition(node.getStart());
|
||||
console.log(chalk.bgCyan(line + " " + character + " " + node.getSourceFile().fileName));
|
||||
|
||||
if (node.parent) {
|
||||
recursiveStack(node.parent)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** visit nodes finding exported classes */
|
||||
function visit(node: ts.Node) {
|
||||
// Only consider exported nodes
|
||||
|
||||
if (node.kind === ts.SyntaxKind.ClassDeclaration) {
|
||||
|
||||
if (node.decorators) {
|
||||
node.decorators.forEach((decorator) => {
|
||||
visit(decorator as ts.Node);
|
||||
});
|
||||
}
|
||||
|
||||
classList.push(node);
|
||||
}
|
||||
|
||||
if (node.kind === ts.SyntaxKind.PropertyAssignment) {
|
||||
const initializer = (node as ts.PropertyAssignment).initializer;
|
||||
|
||||
visit(initializer as ts.Node);
|
||||
}
|
||||
|
||||
if (node.kind === ts.SyntaxKind.Identifier) {
|
||||
extractExport(node);
|
||||
}
|
||||
|
||||
if (node.kind === ts.SyntaxKind.ArrayLiteralExpression) {
|
||||
(node as ts.ArrayLiteralExpression).elements.forEach((element) => {
|
||||
visit(element as ts.Node);
|
||||
});
|
||||
}
|
||||
|
||||
if (node.kind === ts.SyntaxKind.Decorator &&
|
||||
((node as ts.Decorator).expression as any).expression.text === "NgModule") {
|
||||
|
||||
((node as ts.Decorator).expression as any).arguments.forEach((argument) => {
|
||||
argument.properties.forEach((property) => {
|
||||
if (property.name.escapedText === "exports") {
|
||||
visit(property as ts.Node);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (ts.isExportDeclaration(node)) {
|
||||
if (node.exportClause) {
|
||||
node.exportClause.elements.forEach(exportCurrent => {
|
||||
extractExport(exportCurrent as ts.Node);
|
||||
});
|
||||
} else {
|
||||
(node.parent as any).resolvedModules.forEach((currentModule) => {
|
||||
|
||||
if (currentModule) {
|
||||
let find;
|
||||
exportedAllPath.forEach((currentExported) => {
|
||||
if (currentModule.resolvedFileName === currentExported) {
|
||||
find = currentExported;
|
||||
}
|
||||
})
|
||||
|
||||
if (!find) {
|
||||
exportedAllPath.push(currentModule.resolvedFileName);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
visit(node.moduleSpecifier);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (ts.isModuleDeclaration(node)) {
|
||||
// This is a namespace, visit its children
|
||||
ts.forEachChild(node, visit);
|
||||
}
|
||||
}
|
||||
|
||||
/** Serialize a symbol into a json object */
|
||||
function serializeSymbol(className: string, line?: number, character?: number, fileName?: string, arryCalls?: string[]): DocEntry {
|
||||
|
||||
return {
|
||||
position: {
|
||||
line: line,
|
||||
character: character,
|
||||
fileName: fileName
|
||||
},
|
||||
name: className
|
||||
};
|
||||
}
|
||||
|
||||
/** Serialize a class symbol information */
|
||||
function serializeClass(className: string, line?: number, character?: number, fileName?: string, arryCalls?: string[]) {
|
||||
let details = serializeSymbol(className, line, character, fileName, arryCalls);
|
||||
|
||||
return details;
|
||||
}
|
||||
|
||||
/** True if this is visible outside this file, false otherwise */
|
||||
function isNodeExported(node: ts.Node): boolean {
|
||||
return (ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Export) !== 0 || (!!node.parent && node.parent.kind === ts.SyntaxKind.SourceFile);
|
||||
}
|
||||
}
|
||||
|
||||
generatExportList(process.argv.slice(2), {
|
||||
target: ts.ScriptTarget.ES5, module: ts.ModuleKind.CommonJS, removeComments: false
|
||||
});
|
@@ -16,4 +16,4 @@
|
||||
*/
|
||||
|
||||
export * from './components/content-metadata-card/content-metadata-card.component';
|
||||
export { ContentMetadataModule } from './content-metadata.module';
|
||||
export * from './services/content-metadata.service';
|
||||
|
@@ -70,7 +70,7 @@ export * from './date/date.widget';
|
||||
export * from './amount/amount.widget';
|
||||
export * from './dynamic-table/dynamic-table.widget';
|
||||
export * from './error/error.component';
|
||||
export { DocumentWidgetComponent } from './document/document.widget';
|
||||
export * from './document/document.widget';
|
||||
export * from './date-time/date-time.widget';
|
||||
|
||||
// editors (dynamic table)
|
||||
|
5171
lib/export-2.0.0.json
Normal file
5171
lib/export-2.0.0.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -32,7 +32,9 @@
|
||||
"build-content": "ng-packagr -p ./content-services/package.json",
|
||||
"build-process": "ng-packagr -p ./process-services/package.json",
|
||||
"build-insights": "ng-packagr -p ./insights/package.json",
|
||||
"test-export": "node config/test-export.js",
|
||||
"build-export-check" : "tsc ./config/exportCheck.ts",
|
||||
"export-check": "node ./config/exportCheck.js ./core/public-api.ts ./process-services/public-api.ts ./content-services/public-api.ts ./insights/public-api.ts",
|
||||
"test-export": "npm run build-export-check && npm run export-check",
|
||||
"webpack": "node node_modules/webpack/bin/webpack.js"
|
||||
},
|
||||
"main": "./index.js",
|
||||
|
Reference in New Issue
Block a user