UNPKG

@progress/kendo-angular-schematics

Version:

Kendo UI Schematics for Angular

207 lines 7.76 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.insertImport = exports.nodesByKind = exports.findNode = exports.addSymbolToMetadata = exports.ngModuleMetadata = exports.addExportToModule = exports.addImportToModule = exports.addDeclarationToModule = void 0; const tslib_1 = require("tslib"); const ts = tslib_1.__importStar(require("typescript")); const addDeclarationToModule = (options) => addToModule('declarations', options); exports.addDeclarationToModule = addDeclarationToModule; const addImportToModule = (options) => addToModule('imports', options); exports.addImportToModule = addImportToModule; const addExportToModule = (options) => addToModule('exports', options); exports.addExportToModule = addExportToModule; const addToModule = (metadataField, options) => { const result = (0, exports.addSymbolToMetadata)(options.source, metadataField, options.symbolName); if (options.modulePath) { return result.concat((0, exports.insertImport)(options.source, options.symbolName, options.modulePath)); } return result; }; const ngModuleMetadata = (source) => { const decorator = decoratorMetadata(source, 'NgModule') .filter(node => ofKind(node.arguments[0], ts.SyntaxKind.ObjectLiteralExpression))[0]; if (!decorator) { return null; } return decorator.arguments[0]; }; exports.ngModuleMetadata = ngModuleMetadata; const addSymbolToMetadata = (source, metadataField, symbolName) => { if (!symbolName) return []; const node = (0, exports.ngModuleMetadata)(source); if (!node) { return []; } const property = findProperty(node.properties, metadataField); if (!property) { return [ addMetaField(node, `${metadataField}: [${symbolName}]`) ]; } if (!ofKind(property.initializer, ts.SyntaxKind.ArrayLiteralExpression)) { //We cannot handle it if is not a array literal return []; } const elements = property.initializer.elements; if (elements.length === 0) { return [{ position: property.initializer.getEnd() - 1, toAdd: symbolName }]; } const exists = elements.map(e => e.getText()).find(t => t === symbolName); //already there if (exists) { return []; } return [ format(elements, symbolName) ]; }; exports.addSymbolToMetadata = addSymbolToMetadata; const addMetaField = (node, text) => { if (node.properties.length === 0) { return { position: node.getEnd() - 1, toAdd: text }; } return format(node.properties, text); }; const format = (nodes, text) => { let toAdd = `, ${text}`; const lastNode = nodes[nodes.length - 1]; const matches = lastNode.getFullText().match(/^\r?\n\s*/); if (matches && matches.length > 0) { toAdd = `,${matches[0]}${text}`; } return { position: lastNode.getEnd(), toAdd }; }; const formatNode = (node, text) => { const toAdd = `${text}`; return { position: node.getStart(), toAdd }; }; const anyOf = (kind, possible) => possible.reduce((result, current) => result || current === kind, false); const ofKind = (node, ...kinds) => node && anyOf(node.kind, kinds); const isNgModelIdentifier = (node, name) => (ofKind(node, ts.SyntaxKind.Identifier) && node.getText() === name) || (ofKind(node, ts.SyntaxKind.PropertyAccessExpression) && node.name.escapedText === name); function findNode(node, kind, text) { if (node.kind === kind && node.getText() === text) { return node; } let foundNode = null; ts.forEachChild(node, childNode => { foundNode = foundNode || findNode(childNode, kind, text); }); return foundNode; } exports.findNode = findNode; const nodesByKind = (source, kind) => { const nodes = [source]; const result = []; let node; // eslint-disable-next-line no-cond-assign while (node = nodes.shift()) { if (ofKind(node, kind)) { result.push(node); } if (node.getChildCount()) { nodes.unshift(...node.getChildren()); } } return result; }; exports.nodesByKind = nodesByKind; const findProperty = (props, metadataField) => props .filter(prop => ofKind(prop, ts.SyntaxKind.PropertyAssignment)) .filter(prop => { const name = prop.name; if (ofKind(name, ts.SyntaxKind.Identifier)) { return name.text === metadataField; } if (ofKind(name, ts.SyntaxKind.StringLiteral)) { return name.text === metadataField; } return false; })[0]; const decoratorMetadata = (source, name) => (0, exports.nodesByKind)(source, ts.SyntaxKind.Decorator) .map(decorator => decorator.expression) .filter(expression => expression.kind === ts.SyntaxKind.CallExpression) .map(expression => expression) .filter(node => isNgModelIdentifier(node.expression, name)); const insertImport = (source, symbolName, importFrom) => { const isSideEffectsImport = !symbolName; const allImports = (0, exports.nodesByKind)(source, ts.SyntaxKind.ImportDeclaration); const imports = allImports .filter(node => node.getChildren() .filter(child => ofKind(child, ts.SyntaxKind.StringLiteral)) .map(child => child.text) .indexOf(importFrom) !== -1); if (imports.length) { return exitExisting(imports, symbolName); } let position = 0; let prefix = ''; if (allImports.length) { position = allImports[allImports.length - 1].getEnd(); prefix = '\n'; } else { const useStrict = useStrictNode(source); if (useStrict.length) { position = useStrict[0].getEnd(); prefix = '\n'; } } // missing module declaration const toAdd = isSideEffectsImport ? `${prefix}import '${importFrom}';\n` : `${prefix}import { ${symbolName} } from '${importFrom}';\n`; return [{ position, toAdd }]; }; exports.insertImport = insertImport; const useStrictNode = (source) => (0, exports.nodesByKind)(source, ts.SyntaxKind.StringLiteral) .filter(node => node.text === 'use strict'); const exitExisting = (imports, symbolName) => { const importAsterisk = imports.reduce((acc, cur) => acc || (0, exports.nodesByKind)(cur, ts.SyntaxKind.AsteriskToken).length > 0, false); // symbol is imported with * from the module // e.g import * from '...'; if (importAsterisk) { return []; } const importsText = imports.reduce((acc, cur) => [...acc, ...(0, exports.nodesByKind)(cur, ts.SyntaxKind.Identifier)], []) .filter(node => node.text === symbolName); // module declaration // symbol is not imported if (importsText.length === 0) { const namedImport = (0, exports.nodesByKind)(imports[0], ts.SyntaxKind.NamedImports)[0]; if (!namedImport) { // it should be import 'some-package'; return []; } if (!namedImport.elements.length) { return [ formatNode(namedImport.getLastToken(), symbolName) ]; } return [ format(namedImport.elements, symbolName) ]; } // symbol already imported from the module return []; }; //# sourceMappingURL=ast-utils.js.map