UNPKG

@nestjs/schematics

Version:

Nest - modern, fast, powerful node.js web framework (@schematics)

175 lines (174 loc) 6.69 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MetadataManager = void 0; const typescript_1 = require("typescript"); class MetadataManager { constructor(content) { this.content = content; } insert(metadata, symbol, staticOptions) { const source = (0, typescript_1.createSourceFile)('filename.ts', this.content, typescript_1.ScriptTarget.ES2017); const moduleDecoratorNode = this.findFirstDecoratorMetadata(source, 'Module'); if (!moduleDecoratorNode) { return; } const matchingProperties = moduleDecoratorNode.properties .filter((prop) => prop.kind === typescript_1.SyntaxKind.PropertyAssignment) .filter((prop) => { const name = prop.name; switch (name.kind) { case typescript_1.SyntaxKind.Identifier: return name.getText(source) === metadata; case typescript_1.SyntaxKind.StringLiteral: return name.text === metadata; default: return false; } }); symbol = this.mergeSymbolAndExpr(symbol, staticOptions); const addBlankLinesIfDynamic = () => { symbol = staticOptions ? this.addBlankLines(symbol) : symbol; }; if (matchingProperties.length === 0) { const expr = moduleDecoratorNode; if (expr.properties.length === 0) { addBlankLinesIfDynamic(); return this.insertMetadataToEmptyModuleDecorator(expr, metadata, symbol); } else { addBlankLinesIfDynamic(); return this.insertNewMetadataToDecorator(expr, source, metadata, symbol); } } else { return this.insertSymbolToMetadata(source, matchingProperties, symbol, staticOptions); } } findFirstDecoratorMetadata(source, identifier) { for (const node of this.getSourceNodes(source)) { const isDecoratorFactoryNode = node.kind === typescript_1.SyntaxKind.Decorator && node.expression.kind === typescript_1.SyntaxKind.CallExpression; if (!isDecoratorFactoryNode) continue; const expr = node.expression; const isExpectedExpression = expr.arguments[0]?.kind === typescript_1.SyntaxKind.ObjectLiteralExpression; if (!isExpectedExpression) continue; if (expr.expression.kind === typescript_1.SyntaxKind.Identifier) { const escapedText = expr.expression.escapedText; const isTargetIdentifier = escapedText ? escapedText.toLowerCase() === identifier.toLowerCase() : true; if (isTargetIdentifier) { return expr.arguments[0]; } } } } getSourceNodes(sourceFile) { const nodes = [sourceFile]; const result = []; while (nodes.length > 0) { const node = nodes.shift(); if (node) { result.push(node); if (node.getChildCount(sourceFile) >= 0) { nodes.unshift(...node.getChildren(sourceFile)); } } } return result; } insertMetadataToEmptyModuleDecorator(expr, metadata, symbol) { const position = expr.getEnd() - 1; const toInsert = ` ${metadata}: [${symbol}]`; return this.content.split('').reduce((content, char, index) => { if (index === position) { return `${content}\n${toInsert}\n${char}`; } else { return `${content}${char}`; } }, ''); } insertNewMetadataToDecorator(expr, source, metadata, symbol) { const node = expr.properties[expr.properties.length - 1]; const position = node.getEnd(); const text = node.getFullText(source); const matches = text.match(/^\r?\n\s*/); let toInsert; if (matches) { toInsert = `,${matches[0]}${metadata}: [${symbol}]`; } else { toInsert = `, ${metadata}: [${symbol}]`; } return this.content.split('').reduce((content, char, index) => { if (index === position) { return `${content}${toInsert}${char}`; } else { return `${content}${char}`; } }, ''); } insertSymbolToMetadata(source, matchingProperties, symbol, staticOptions) { const assignment = matchingProperties[0]; let node; const arrLiteral = assignment.initializer; if (!arrLiteral.elements) { return this.content; } if (arrLiteral.elements.length === 0) { node = arrLiteral; } else { node = arrLiteral.elements; } if (Array.isArray(node)) { const nodeArray = node; const symbolsArray = nodeArray.map((childNode) => childNode.getText(source)); if (symbolsArray.includes(symbol)) { return this.content; } node = node[node.length - 1]; } let toInsert; let position = node.getEnd(); if (node.kind === typescript_1.SyntaxKind.ArrayLiteralExpression) { position--; toInsert = staticOptions ? this.addBlankLines(symbol) : `${symbol}`; } else { const text = node.getFullText(source); const itemSeparator = (text.match(/^\r?\n(\r?)\s+/) || text.match(/^\r?\n/) || ' ')[0]; toInsert = `,${itemSeparator}${symbol}`; } return this.content.split('').reduce((content, char, index) => { if (index === position) { return `${content}${toInsert}${char}`; } else { return `${content}${char}`; } }, ''); } mergeSymbolAndExpr(symbol, staticOptions) { if (!staticOptions) { return symbol; } const spacing = 6; let options = JSON.stringify(staticOptions.value, null, spacing); options = options.replace(/\"([^(\")"]+)\":/g, '$1:'); options = options.replace(/\"/g, `'`); options = options.slice(0, options.length - 1) + ' }'; symbol += `.${staticOptions.name}(${options})`; return symbol; } addBlankLines(expr) { return `\n ${expr}\n `; } } exports.MetadataManager = MetadataManager;