UNPKG

6.19 kBJavaScriptView Raw
1"use strict";
2/**
3 * @license
4 * Copyright Google LLC All Rights Reserved.
5 *
6 * Use of this source code is governed by an MIT-style license that can be
7 * found in the LICENSE file at https://angular.dev/license
8 */
9Object.defineProperty(exports, "__esModule", { value: true });
10exports.InvalidPipeException = exports.UnknownPipeException = exports.OptionIsNotDefinedException = exports.TEMPLATE_FILENAME_RE = void 0;
11exports.applyContentTemplate = applyContentTemplate;
12exports.contentTemplate = contentTemplate;
13exports.applyPathTemplate = applyPathTemplate;
14exports.pathTemplate = pathTemplate;
15exports.renameTemplateFiles = renameTemplateFiles;
16exports.template = template;
17exports.applyTemplates = applyTemplates;
18const core_1 = require("@angular-devkit/core");
19const node_os_1 = require("node:os");
20const base_1 = require("./base");
21exports.TEMPLATE_FILENAME_RE = /\.template$/;
22class OptionIsNotDefinedException extends core_1.BaseException {
23 constructor(name) {
24 super(`Option "${name}" is not defined.`);
25 }
26}
27exports.OptionIsNotDefinedException = OptionIsNotDefinedException;
28class UnknownPipeException extends core_1.BaseException {
29 constructor(name) {
30 super(`Pipe "${name}" is not defined.`);
31 }
32}
33exports.UnknownPipeException = UnknownPipeException;
34class InvalidPipeException extends core_1.BaseException {
35 constructor(name) {
36 super(`Pipe "${name}" is invalid.`);
37 }
38}
39exports.InvalidPipeException = InvalidPipeException;
40const decoder = new TextDecoder('utf-8', { fatal: true });
41function applyContentTemplate(options) {
42 return (entry) => {
43 const { path, content } = entry;
44 try {
45 const decodedContent = decoder.decode(content).replace(/\r?\n/g, node_os_1.EOL);
46 return {
47 path,
48 content: Buffer.from((0, core_1.template)(decodedContent, {})(options)),
49 };
50 }
51 catch (e) {
52 // The second part should not be needed. But Jest does not support instanceof correctly.
53 // See: https://github.com/jestjs/jest/issues/2549
54 if (e instanceof TypeError ||
55 e.code === 'ERR_ENCODING_INVALID_ENCODED_DATA') {
56 return entry;
57 }
58 throw e;
59 }
60 };
61}
62function contentTemplate(options) {
63 return (0, base_1.forEach)(applyContentTemplate(options));
64}
65function applyPathTemplate(data, options = {
66 interpolationStart: '__',
67 interpolationEnd: '__',
68 pipeSeparator: '@',
69}) {
70 const is = options.interpolationStart;
71 const ie = options.interpolationEnd;
72 const isL = is.length;
73 const ieL = ie.length;
74 return (entry) => {
75 let path = entry.path;
76 const content = entry.content;
77 const original = path;
78 let start = path.indexOf(is);
79 // + 1 to have at least a length 1 name. `____` is not valid.
80 let end = path.indexOf(ie, start + isL + 1);
81 while (start != -1 && end != -1) {
82 const match = path.substring(start + isL, end);
83 let replacement = data[match];
84 if (!options.pipeSeparator) {
85 if (typeof replacement == 'function') {
86 replacement = replacement.call(data, original);
87 }
88 if (replacement === undefined) {
89 throw new OptionIsNotDefinedException(match);
90 }
91 }
92 else {
93 const [name, ...pipes] = match.split(options.pipeSeparator);
94 replacement = data[name];
95 if (typeof replacement == 'function') {
96 replacement = replacement.call(data, original);
97 }
98 if (replacement === undefined) {
99 throw new OptionIsNotDefinedException(name);
100 }
101 replacement = pipes.reduce((acc, pipe) => {
102 if (!pipe) {
103 return acc;
104 }
105 if (!(pipe in data)) {
106 throw new UnknownPipeException(pipe);
107 }
108 const pipeFn = data[pipe];
109 if (typeof pipeFn != 'function') {
110 throw new InvalidPipeException(pipe);
111 }
112 // Coerce to string.
113 return '' + pipeFn(acc);
114 }, '' + replacement);
115 }
116 path = path.substring(0, start) + replacement + path.substring(end + ieL);
117 start = path.indexOf(options.interpolationStart);
118 // See above.
119 end = path.indexOf(options.interpolationEnd, start + isL + 1);
120 }
121 return { path: (0, core_1.normalize)(path), content };
122 };
123}
124function pathTemplate(options) {
125 return (0, base_1.forEach)(applyPathTemplate(options));
126}
127/**
128 * Remove every `.template` suffix from file names.
129 */
130function renameTemplateFiles() {
131 return (0, base_1.forEach)((entry) => {
132 if (entry.path.match(exports.TEMPLATE_FILENAME_RE)) {
133 return {
134 content: entry.content,
135 path: (0, core_1.normalize)(entry.path.replace(exports.TEMPLATE_FILENAME_RE, '')),
136 };
137 }
138 else {
139 return entry;
140 }
141 });
142}
143function template(options) {
144 return (0, base_1.chain)([
145 contentTemplate(options),
146 // Force cast to PathTemplateData. We need the type for the actual pathTemplate() call,
147 // but in this case we cannot do anything as contentTemplate are more permissive.
148 // Since values are coerced to strings in PathTemplates it will be fine in the end.
149 pathTemplate(options),
150 ]);
151}
152function applyTemplates(options) {
153 return (0, base_1.forEach)((0, base_1.when)((path) => path.endsWith('.template'), (0, base_1.composeFileOperators)([
154 applyContentTemplate(options),
155 // See above for this weird cast.
156 applyPathTemplate(options),
157 (entry) => {
158 return {
159 content: entry.content,
160 path: entry.path.replace(exports.TEMPLATE_FILENAME_RE, ''),
161 };
162 },
163 ])));
164}