UNPKG

@angular-devkit/schematics

Version:
165 lines (164 loc) 6.19 kB
"use strict"; /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.dev/license */ Object.defineProperty(exports, "__esModule", { value: true }); exports.InvalidPipeException = exports.UnknownPipeException = exports.OptionIsNotDefinedException = exports.TEMPLATE_FILENAME_RE = void 0; exports.applyContentTemplate = applyContentTemplate; exports.contentTemplate = contentTemplate; exports.applyPathTemplate = applyPathTemplate; exports.pathTemplate = pathTemplate; exports.renameTemplateFiles = renameTemplateFiles; exports.template = template; exports.applyTemplates = applyTemplates; const core_1 = require("@angular-devkit/core"); const node_os_1 = require("node:os"); const base_1 = require("./base"); exports.TEMPLATE_FILENAME_RE = /\.template$/; class OptionIsNotDefinedException extends core_1.BaseException { constructor(name) { super(`Option "${name}" is not defined.`); } } exports.OptionIsNotDefinedException = OptionIsNotDefinedException; class UnknownPipeException extends core_1.BaseException { constructor(name) { super(`Pipe "${name}" is not defined.`); } } exports.UnknownPipeException = UnknownPipeException; class InvalidPipeException extends core_1.BaseException { constructor(name) { super(`Pipe "${name}" is invalid.`); } } exports.InvalidPipeException = InvalidPipeException; const decoder = new TextDecoder('utf-8', { fatal: true }); function applyContentTemplate(options) { return (entry) => { const { path, content } = entry; try { const decodedContent = decoder.decode(content).replace(/\r?\n/g, node_os_1.EOL); return { path, content: Buffer.from((0, core_1.template)(decodedContent, {})(options)), }; } catch (e) { // The second part should not be needed. But Jest does not support instanceof correctly. // See: https://github.com/jestjs/jest/issues/2549 if (e instanceof TypeError || e.code === 'ERR_ENCODING_INVALID_ENCODED_DATA') { return entry; } throw e; } }; } function contentTemplate(options) { return (0, base_1.forEach)(applyContentTemplate(options)); } function applyPathTemplate(data, options = { interpolationStart: '__', interpolationEnd: '__', pipeSeparator: '@', }) { const is = options.interpolationStart; const ie = options.interpolationEnd; const isL = is.length; const ieL = ie.length; return (entry) => { let path = entry.path; const content = entry.content; const original = path; let start = path.indexOf(is); // + 1 to have at least a length 1 name. `____` is not valid. let end = path.indexOf(ie, start + isL + 1); while (start != -1 && end != -1) { const match = path.substring(start + isL, end); let replacement = data[match]; if (!options.pipeSeparator) { if (typeof replacement == 'function') { replacement = replacement.call(data, original); } if (replacement === undefined) { throw new OptionIsNotDefinedException(match); } } else { const [name, ...pipes] = match.split(options.pipeSeparator); replacement = data[name]; if (typeof replacement == 'function') { replacement = replacement.call(data, original); } if (replacement === undefined) { throw new OptionIsNotDefinedException(name); } replacement = pipes.reduce((acc, pipe) => { if (!pipe) { return acc; } if (!(pipe in data)) { throw new UnknownPipeException(pipe); } const pipeFn = data[pipe]; if (typeof pipeFn != 'function') { throw new InvalidPipeException(pipe); } // Coerce to string. return '' + pipeFn(acc); }, '' + replacement); } path = path.substring(0, start) + replacement + path.substring(end + ieL); start = path.indexOf(options.interpolationStart); // See above. end = path.indexOf(options.interpolationEnd, start + isL + 1); } return { path: (0, core_1.normalize)(path), content }; }; } function pathTemplate(options) { return (0, base_1.forEach)(applyPathTemplate(options)); } /** * Remove every `.template` suffix from file names. */ function renameTemplateFiles() { return (0, base_1.forEach)((entry) => { if (entry.path.match(exports.TEMPLATE_FILENAME_RE)) { return { content: entry.content, path: (0, core_1.normalize)(entry.path.replace(exports.TEMPLATE_FILENAME_RE, '')), }; } else { return entry; } }); } function template(options) { return (0, base_1.chain)([ contentTemplate(options), // Force cast to PathTemplateData. We need the type for the actual pathTemplate() call, // but in this case we cannot do anything as contentTemplate are more permissive. // Since values are coerced to strings in PathTemplates it will be fine in the end. pathTemplate(options), ]); } function applyTemplates(options) { return (0, base_1.forEach)((0, base_1.when)((path) => path.endsWith('.template'), (0, base_1.composeFileOperators)([ applyContentTemplate(options), // See above for this weird cast. applyPathTemplate(options), (entry) => { return { content: entry.content, path: entry.path.replace(exports.TEMPLATE_FILENAME_RE, ''), }; }, ]))); }