@angular-devkit/build-angular 15.0.0 → 15.1.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +15 -16
- package/src/builders/browser/index.js +0 -9
- package/src/builders/browser-esbuild/angular-compilation.d.ts +26 -0
- package/src/builders/browser-esbuild/angular-compilation.js +172 -0
- package/src/builders/browser-esbuild/angular-host.d.ts +25 -0
- package/src/builders/browser-esbuild/angular-host.js +61 -0
- package/src/builders/browser-esbuild/compiler-plugin.js +56 -236
- package/src/builders/browser-esbuild/javascript-transformer-worker.d.ts +18 -0
- package/src/builders/browser-esbuild/javascript-transformer-worker.js +70 -0
- package/src/builders/browser-esbuild/javascript-transformer.d.ts +48 -0
- package/src/builders/browser-esbuild/javascript-transformer.js +95 -0
- package/src/builders/browser-esbuild/sass-plugin.js +30 -30
- package/src/builders/server/index.js +44 -10
- package/src/builders/server/schema.d.ts +28 -0
- package/src/builders/server/schema.json +46 -0
- package/src/sass/rebasing-importer.d.ts +12 -6
- package/src/sass/rebasing-importer.js +227 -62
- package/src/utils/normalize-asset-patterns.js +4 -5
- package/src/webpack/utils/stats.js +10 -1
|
@@ -15,11 +15,6 @@ const magic_string_1 = __importDefault(require("magic-string"));
|
|
|
15
15
|
const node_fs_1 = require("node:fs");
|
|
16
16
|
const node_path_1 = require("node:path");
|
|
17
17
|
const node_url_1 = require("node:url");
|
|
18
|
-
/**
|
|
19
|
-
* A Regular expression used to find all `url()` functions within a stylesheet.
|
|
20
|
-
* From packages/angular_devkit/build_angular/src/webpack/plugins/postcss-cli-resources.ts
|
|
21
|
-
*/
|
|
22
|
-
const URL_REGEXP = /url(?:\(\s*(['"]?))(.*?)(?:\1\s*\))/g;
|
|
23
18
|
/**
|
|
24
19
|
* A Sass Importer base class that provides the load logic to rebase all `url()` functions
|
|
25
20
|
* within a stylesheet. The rebasing will ensure that the URLs in the output of the Sass compiler
|
|
@@ -43,37 +38,36 @@ class UrlRebasingImporter {
|
|
|
43
38
|
}
|
|
44
39
|
load(canonicalUrl) {
|
|
45
40
|
const stylesheetPath = (0, node_url_1.fileURLToPath)(canonicalUrl);
|
|
41
|
+
const stylesheetDirectory = (0, node_path_1.dirname)(stylesheetPath);
|
|
46
42
|
let contents = (0, node_fs_1.readFileSync)(stylesheetPath, 'utf-8');
|
|
47
43
|
// Rebase any URLs that are found
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
while ((match = URL_REGEXP.exec(contents))) {
|
|
54
|
-
const originalUrl = match[2];
|
|
55
|
-
// If root-relative, absolute or protocol relative url, leave as-is
|
|
56
|
-
if (/^((?:\w+:)?\/\/|data:|chrome:|#|\/)/.test(originalUrl)) {
|
|
57
|
-
continue;
|
|
58
|
-
}
|
|
59
|
-
const rebasedPath = (0, node_path_1.relative)(this.entryDirectory, (0, node_path_1.join)(stylesheetDirectory, originalUrl));
|
|
60
|
-
// Normalize path separators and escape characters
|
|
61
|
-
// https://developer.mozilla.org/en-US/docs/Web/CSS/url#syntax
|
|
62
|
-
const rebasedUrl = './' + rebasedPath.replace(/\\/g, '/').replace(/[()\s'"]/g, '\\$&');
|
|
63
|
-
updatedContents !== null && updatedContents !== void 0 ? updatedContents : (updatedContents = new magic_string_1.default(contents));
|
|
64
|
-
updatedContents.update(match.index, match.index + match[0].length, `url(${rebasedUrl})`);
|
|
44
|
+
let updatedContents;
|
|
45
|
+
for (const { start, end, value } of findUrls(contents)) {
|
|
46
|
+
// Skip if value is empty or a Sass variable
|
|
47
|
+
if (value.length === 0 || value.startsWith('$')) {
|
|
48
|
+
continue;
|
|
65
49
|
}
|
|
66
|
-
if
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
50
|
+
// Skip if root-relative, absolute or protocol relative url
|
|
51
|
+
if (/^((?:\w+:)?\/\/|data:|chrome:|#|\/)/.test(value)) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const rebasedPath = (0, node_path_1.relative)(this.entryDirectory, (0, node_path_1.join)(stylesheetDirectory, value));
|
|
55
|
+
// Normalize path separators and escape characters
|
|
56
|
+
// https://developer.mozilla.org/en-US/docs/Web/CSS/url#syntax
|
|
57
|
+
const rebasedUrl = './' + rebasedPath.replace(/\\/g, '/').replace(/[()\s'"]/g, '\\$&');
|
|
58
|
+
updatedContents !== null && updatedContents !== void 0 ? updatedContents : (updatedContents = new magic_string_1.default(contents));
|
|
59
|
+
updatedContents.update(start, end, rebasedUrl);
|
|
60
|
+
}
|
|
61
|
+
if (updatedContents) {
|
|
62
|
+
contents = updatedContents.toString();
|
|
63
|
+
if (this.rebaseSourceMaps) {
|
|
64
|
+
// Generate an intermediate source map for the rebasing changes
|
|
65
|
+
const map = updatedContents.generateMap({
|
|
66
|
+
hires: true,
|
|
67
|
+
includeContent: true,
|
|
68
|
+
source: canonicalUrl.href,
|
|
69
|
+
});
|
|
70
|
+
this.rebaseSourceMaps.set(canonicalUrl.href, map);
|
|
77
71
|
}
|
|
78
72
|
}
|
|
79
73
|
let syntax;
|
|
@@ -95,6 +89,156 @@ class UrlRebasingImporter {
|
|
|
95
89
|
};
|
|
96
90
|
}
|
|
97
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Determines if a unicode code point is a CSS whitespace character.
|
|
94
|
+
* @param code The unicode code point to test.
|
|
95
|
+
* @returns true, if the code point is CSS whitespace; false, otherwise.
|
|
96
|
+
*/
|
|
97
|
+
function isWhitespace(code) {
|
|
98
|
+
// Based on https://www.w3.org/TR/css-syntax-3/#whitespace
|
|
99
|
+
switch (code) {
|
|
100
|
+
case 0x0009: // tab
|
|
101
|
+
case 0x0020: // space
|
|
102
|
+
case 0x000a: // line feed
|
|
103
|
+
case 0x000c: // form feed
|
|
104
|
+
case 0x000d: // carriage return
|
|
105
|
+
return true;
|
|
106
|
+
default:
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Scans a CSS or Sass file and locates all valid url function values as defined by the CSS
|
|
112
|
+
* syntax specification.
|
|
113
|
+
* @param contents A string containing a CSS or Sass file to scan.
|
|
114
|
+
* @returns An iterable that yields each CSS url function value found.
|
|
115
|
+
*/
|
|
116
|
+
function* findUrls(contents) {
|
|
117
|
+
let pos = 0;
|
|
118
|
+
let width = 1;
|
|
119
|
+
let current = -1;
|
|
120
|
+
const next = () => {
|
|
121
|
+
var _a;
|
|
122
|
+
pos += width;
|
|
123
|
+
current = (_a = contents.codePointAt(pos)) !== null && _a !== void 0 ? _a : -1;
|
|
124
|
+
width = current > 0xffff ? 2 : 1;
|
|
125
|
+
return current;
|
|
126
|
+
};
|
|
127
|
+
// Based on https://www.w3.org/TR/css-syntax-3/#consume-ident-like-token
|
|
128
|
+
while ((pos = contents.indexOf('url(', pos)) !== -1) {
|
|
129
|
+
// Set to position of the (
|
|
130
|
+
pos += 3;
|
|
131
|
+
width = 1;
|
|
132
|
+
// Consume all leading whitespace
|
|
133
|
+
while (isWhitespace(next())) {
|
|
134
|
+
/* empty */
|
|
135
|
+
}
|
|
136
|
+
// Initialize URL state
|
|
137
|
+
const url = { start: pos, end: -1, value: '' };
|
|
138
|
+
let complete = false;
|
|
139
|
+
// If " or ', then consume the value as a string
|
|
140
|
+
if (current === 0x0022 || current === 0x0027) {
|
|
141
|
+
const ending = current;
|
|
142
|
+
// Based on https://www.w3.org/TR/css-syntax-3/#consume-string-token
|
|
143
|
+
while (!complete) {
|
|
144
|
+
switch (next()) {
|
|
145
|
+
case -1: // EOF
|
|
146
|
+
return;
|
|
147
|
+
case 0x000a: // line feed
|
|
148
|
+
case 0x000c: // form feed
|
|
149
|
+
case 0x000d: // carriage return
|
|
150
|
+
// Invalid
|
|
151
|
+
complete = true;
|
|
152
|
+
break;
|
|
153
|
+
case 0x005c: // \ -- character escape
|
|
154
|
+
// If not EOF or newline, add the character after the escape
|
|
155
|
+
switch (next()) {
|
|
156
|
+
case -1:
|
|
157
|
+
return;
|
|
158
|
+
case 0x000a: // line feed
|
|
159
|
+
case 0x000c: // form feed
|
|
160
|
+
case 0x000d: // carriage return
|
|
161
|
+
// Skip when inside a string
|
|
162
|
+
break;
|
|
163
|
+
default:
|
|
164
|
+
// TODO: Handle hex escape codes
|
|
165
|
+
url.value += String.fromCodePoint(current);
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
break;
|
|
169
|
+
case ending:
|
|
170
|
+
// Full string position should include the quotes for replacement
|
|
171
|
+
url.end = pos + 1;
|
|
172
|
+
complete = true;
|
|
173
|
+
yield url;
|
|
174
|
+
break;
|
|
175
|
+
default:
|
|
176
|
+
url.value += String.fromCodePoint(current);
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
next();
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
// Based on https://www.w3.org/TR/css-syntax-3/#consume-url-token
|
|
184
|
+
while (!complete) {
|
|
185
|
+
switch (current) {
|
|
186
|
+
case -1: // EOF
|
|
187
|
+
return;
|
|
188
|
+
case 0x0022: // "
|
|
189
|
+
case 0x0027: // '
|
|
190
|
+
case 0x0028: // (
|
|
191
|
+
// Invalid
|
|
192
|
+
complete = true;
|
|
193
|
+
break;
|
|
194
|
+
case 0x0029: // )
|
|
195
|
+
// URL is valid and complete
|
|
196
|
+
url.end = pos;
|
|
197
|
+
complete = true;
|
|
198
|
+
break;
|
|
199
|
+
case 0x005c: // \ -- character escape
|
|
200
|
+
// If not EOF or newline, add the character after the escape
|
|
201
|
+
switch (next()) {
|
|
202
|
+
case -1: // EOF
|
|
203
|
+
return;
|
|
204
|
+
case 0x000a: // line feed
|
|
205
|
+
case 0x000c: // form feed
|
|
206
|
+
case 0x000d: // carriage return
|
|
207
|
+
// Invalid
|
|
208
|
+
complete = true;
|
|
209
|
+
break;
|
|
210
|
+
default:
|
|
211
|
+
// TODO: Handle hex escape codes
|
|
212
|
+
url.value += String.fromCodePoint(current);
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
break;
|
|
216
|
+
default:
|
|
217
|
+
if (isWhitespace(current)) {
|
|
218
|
+
while (isWhitespace(next())) {
|
|
219
|
+
/* empty */
|
|
220
|
+
}
|
|
221
|
+
// Unescaped whitespace is only valid before the closing )
|
|
222
|
+
if (current === 0x0029) {
|
|
223
|
+
// URL is valid
|
|
224
|
+
url.end = pos;
|
|
225
|
+
}
|
|
226
|
+
complete = true;
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
// Add the character to the url value
|
|
230
|
+
url.value += String.fromCodePoint(current);
|
|
231
|
+
}
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
next();
|
|
235
|
+
}
|
|
236
|
+
// An end position indicates a URL was found
|
|
237
|
+
if (url.end !== -1) {
|
|
238
|
+
yield url;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
98
242
|
/**
|
|
99
243
|
* Provides the Sass importer logic to resolve relative stylesheet imports via both import and use rules
|
|
100
244
|
* and also rebase any `url()` function usage within those stylesheets. The rebasing will ensure that
|
|
@@ -131,17 +275,6 @@ class RelativeUrlRebasingImporter extends UrlRebasingImporter {
|
|
|
131
275
|
const hasStyleExtension = extension === '.scss' || extension === '.sass' || extension === '.css';
|
|
132
276
|
// Remove the style extension if present to allow adding the `.import` suffix
|
|
133
277
|
const filename = (0, node_path_1.basename)(stylesheetPath, hasStyleExtension ? extension : undefined);
|
|
134
|
-
let entries;
|
|
135
|
-
try {
|
|
136
|
-
entries = this.directoryCache.get(directory);
|
|
137
|
-
if (!entries) {
|
|
138
|
-
entries = (0, node_fs_1.readdirSync)(directory, { withFileTypes: true });
|
|
139
|
-
this.directoryCache.set(directory, entries);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
catch {
|
|
143
|
-
return null;
|
|
144
|
-
}
|
|
145
278
|
const importPotentials = new Set();
|
|
146
279
|
const defaultPotentials = new Set();
|
|
147
280
|
if (hasStyleExtension) {
|
|
@@ -168,37 +301,69 @@ class RelativeUrlRebasingImporter extends UrlRebasingImporter {
|
|
|
168
301
|
defaultPotentials.add('_' + filename + '.sass');
|
|
169
302
|
defaultPotentials.add('_' + filename + '.css');
|
|
170
303
|
}
|
|
171
|
-
|
|
172
|
-
|
|
304
|
+
let foundDefaults;
|
|
305
|
+
let foundImports;
|
|
173
306
|
let hasPotentialIndex = false;
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
|
|
307
|
+
let cachedEntries = this.directoryCache.get(directory);
|
|
308
|
+
if (cachedEntries) {
|
|
309
|
+
// If there is a preprocessed cache of the directory, perform an intersection of the potentials
|
|
310
|
+
// and the directory files.
|
|
311
|
+
const { files, directories } = cachedEntries;
|
|
312
|
+
foundDefaults = [...defaultPotentials].filter((potential) => files.has(potential));
|
|
313
|
+
foundImports = [...importPotentials].filter((potential) => files.has(potential));
|
|
314
|
+
hasPotentialIndex = checkDirectory && !hasStyleExtension && directories.has(filename);
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
// If no preprocessed cache exists, get the entries from the file system and, while searching,
|
|
318
|
+
// generate the cache for later requests.
|
|
319
|
+
let entries;
|
|
320
|
+
try {
|
|
321
|
+
entries = (0, node_fs_1.readdirSync)(directory, { withFileTypes: true });
|
|
181
322
|
}
|
|
182
|
-
|
|
183
|
-
|
|
323
|
+
catch {
|
|
324
|
+
return null;
|
|
184
325
|
}
|
|
185
|
-
|
|
186
|
-
|
|
326
|
+
foundDefaults = [];
|
|
327
|
+
foundImports = [];
|
|
328
|
+
cachedEntries = { files: new Set(), directories: new Set() };
|
|
329
|
+
for (const entry of entries) {
|
|
330
|
+
const isDirectory = entry.isDirectory();
|
|
331
|
+
if (isDirectory) {
|
|
332
|
+
cachedEntries.directories.add(entry.name);
|
|
333
|
+
}
|
|
334
|
+
// Record if the name should be checked as a directory with an index file
|
|
335
|
+
if (checkDirectory && !hasStyleExtension && entry.name === filename && isDirectory) {
|
|
336
|
+
hasPotentialIndex = true;
|
|
337
|
+
}
|
|
338
|
+
if (!entry.isFile()) {
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
cachedEntries.files.add(entry.name);
|
|
342
|
+
if (importPotentials.has(entry.name)) {
|
|
343
|
+
foundImports.push(entry.name);
|
|
344
|
+
}
|
|
345
|
+
if (defaultPotentials.has(entry.name)) {
|
|
346
|
+
foundDefaults.push(entry.name);
|
|
347
|
+
}
|
|
187
348
|
}
|
|
349
|
+
this.directoryCache.set(directory, cachedEntries);
|
|
188
350
|
}
|
|
189
351
|
// `foundImports` will only contain elements if `options.fromImport` is true
|
|
190
352
|
const result = (_a = this.checkFound(foundImports)) !== null && _a !== void 0 ? _a : this.checkFound(foundDefaults);
|
|
191
|
-
if (result
|
|
353
|
+
if (result !== null) {
|
|
354
|
+
return (0, node_url_1.pathToFileURL)((0, node_path_1.join)(directory, result));
|
|
355
|
+
}
|
|
356
|
+
if (hasPotentialIndex) {
|
|
192
357
|
// Check for index files using filename as a directory
|
|
193
358
|
return this.resolveImport(url + '/index', fromImport, false);
|
|
194
359
|
}
|
|
195
|
-
return
|
|
360
|
+
return null;
|
|
196
361
|
}
|
|
197
362
|
/**
|
|
198
363
|
* Checks an array of potential stylesheet files to determine if there is a valid
|
|
199
364
|
* stylesheet file. More than one discovered file may indicate an error.
|
|
200
365
|
* @param found An array of discovered stylesheet files.
|
|
201
|
-
* @returns A fully resolved
|
|
366
|
+
* @returns A fully resolved path for a stylesheet file or `null` if not found.
|
|
202
367
|
* @throws If there are ambiguous files discovered.
|
|
203
368
|
*/
|
|
204
369
|
checkFound(found) {
|
|
@@ -217,9 +382,9 @@ class RelativeUrlRebasingImporter extends UrlRebasingImporter {
|
|
|
217
382
|
}
|
|
218
383
|
// Return the non-CSS file (sass/scss files have priority)
|
|
219
384
|
// https://github.com/sass/dart-sass/blob/44d6bb6ac72fe6b93f5bfec371a1fffb18e6b76d/lib/src/importer/utils.dart#L44-L47
|
|
220
|
-
return
|
|
385
|
+
return foundWithoutCss[0];
|
|
221
386
|
}
|
|
222
|
-
return
|
|
387
|
+
return found[0];
|
|
223
388
|
}
|
|
224
389
|
}
|
|
225
390
|
exports.RelativeUrlRebasingImporter = RelativeUrlRebasingImporter;
|
|
@@ -78,13 +78,12 @@ function normalizeAssetPatterns(assetPatterns, workspaceRoot, projectRoot, proje
|
|
|
78
78
|
}
|
|
79
79
|
// Output directory for both is the relative path from source root to input.
|
|
80
80
|
const output = path.relative(resolvedSourceRoot, path.resolve(workspaceRoot, input));
|
|
81
|
-
|
|
82
|
-
return { glob, input, output };
|
|
81
|
+
assetPattern = { glob, input, output };
|
|
83
82
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
return assetPattern;
|
|
83
|
+
if (assetPattern.output.startsWith('..')) {
|
|
84
|
+
throw new Error('An asset cannot be written to a location outside of the output path.');
|
|
87
85
|
}
|
|
86
|
+
return assetPattern;
|
|
88
87
|
});
|
|
89
88
|
}
|
|
90
89
|
exports.normalizeAssetPatterns = normalizeAssetPatterns;
|
|
@@ -279,7 +279,16 @@ function statsWarningsToString(json, statsConfig) {
|
|
|
279
279
|
output += yb(`Warning: ${warning}\n\n`);
|
|
280
280
|
}
|
|
281
281
|
else {
|
|
282
|
-
|
|
282
|
+
let file = warning.file || warning.moduleName;
|
|
283
|
+
// Clean up warning paths
|
|
284
|
+
// Ex: ./src/app/styles.scss.webpack[javascript/auto]!=!./node_modules/css-loader/dist/cjs.js....
|
|
285
|
+
// to ./src/app/styles.scss.webpack
|
|
286
|
+
if (file && !statsConfig.errorDetails) {
|
|
287
|
+
const webpackPathIndex = file.indexOf('.webpack[');
|
|
288
|
+
if (webpackPathIndex !== -1) {
|
|
289
|
+
file = file.substring(0, webpackPathIndex);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
283
292
|
if (file) {
|
|
284
293
|
output += c(file);
|
|
285
294
|
if (warning.loc) {
|