@blotch/rsbuild-plugin-angular-lynx 22.2.2 → 22.2.4
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/README.md +2 -1
- package/dist/544.js +21 -0
- package/dist/angular-rebuild-coordinator.d.ts +1 -1
- package/dist/angular.d.ts +3 -2
- package/dist/background-entry.d.ts +96 -0
- package/dist/client/background-hot-updates.d.ts +50 -0
- package/dist/client/background-hot-updates.js +77 -0
- package/dist/client/background-hot-updates.test.d.ts +1 -0
- package/dist/client/css-hot-update.cjs +9 -0
- package/dist/client/css-hot-update.d.ts +44 -0
- package/dist/client/css-hot-update.js +42 -0
- package/dist/client/css-hot-update.test.d.ts +1 -0
- package/dist/client/hmr-background.js +16 -0
- package/dist/client/hmr-main-thread.js +9 -0
- package/dist/client/hmr-protocol.d.ts +74 -0
- package/dist/client/main-thread-hot-updates.d.ts +40 -0
- package/dist/client/main-thread-hot-updates.js +78 -0
- package/dist/client/main-thread-hot-updates.test.d.ts +1 -0
- package/dist/client/testing/test-context.d.ts +16 -0
- package/dist/component-styles-cache.d.ts +5 -35
- package/dist/component-styles.d.ts +73 -0
- package/dist/component-styles.test.d.ts +1 -0
- package/dist/cross-thread-transform.d.ts +38 -0
- package/dist/cross-thread-transform.test.d.ts +1 -0
- package/dist/css.d.ts +2 -2
- package/dist/entry.d.ts +23 -2
- package/dist/hot-updates.d.ts +67 -0
- package/dist/hot-updates.test.d.ts +1 -0
- package/dist/index.js +2559 -173
- package/dist/layers.d.ts +6 -4
- package/dist/logger/dev-logger-middleware.d.ts +13 -7
- package/dist/logger/dev-logger.d.ts +13 -0
- package/dist/polyfills.js +56 -0
- package/dist/polyfills.test.d.ts +1 -0
- package/dist/pure-classes.d.ts +27 -0
- package/dist/pure-classes.test.d.ts +1 -0
- package/dist/resolve.d.ts +19 -0
- package/dist/resolve.test.d.ts +1 -0
- package/dist/split-chunks.d.ts +2 -2
- package/dist/styles/blur-view.css +16 -0
- package/dist/tailwind-v4/calc.d.ts +18 -0
- package/dist/tailwind-v4/calc.test.d.ts +1 -0
- package/dist/tailwind-v4/colors.d.ts +6 -0
- package/dist/tailwind-v4/colors.test.d.ts +1 -0
- package/dist/tailwind-v4/declarations.d.ts +39 -0
- package/dist/tailwind-v4/declarations.test.d.ts +1 -0
- package/dist/tailwind-v4/index.d.ts +23 -0
- package/dist/tailwind-v4/index.test.d.ts +1 -0
- package/dist/tailwind-v4/lynx-properties.d.ts +20 -0
- package/dist/tailwind-v4/selectors.d.ts +6 -0
- package/dist/tailwind-v4/selectors.test.d.ts +1 -0
- package/dist/tailwind-v4/structure.d.ts +51 -0
- package/dist/tailwind-v4/structure.test.d.ts +1 -0
- package/dist/tailwind-v4/variables.d.ts +20 -0
- package/dist/tailwind-v4/variables.test.d.ts +1 -0
- package/dist/tailwind.d.ts +14 -0
- package/dist/transform-module.d.ts +43 -17
- package/dist/utils/angular/component-scope-id.d.ts +5 -3
- package/dist/utils/options.d.ts +40 -1
- package/package.json +5 -2
- package/dist/loaders/thread-globals-loader.d.ts +0 -8
- package/dist/loaders/thread-globals-loader.js +0 -6
- /package/dist/{loaders/thread-globals-loader.test.d.ts → background-entry.test.d.ts} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
/*! LICENSE: index.js.LICENSE.txt */
|
|
2
2
|
import node_fs, { existsSync } from "node:fs";
|
|
3
|
-
import node_path, { join, resolve } from "node:path";
|
|
3
|
+
import node_path, { join, resolve as external_node_path_resolve } from "node:path";
|
|
4
4
|
import { CSSPlugins, LynxEncodePlugin, LynxTemplatePlugin, WebEncodePlugin } from "@lynx-js/template-webpack-plugin";
|
|
5
|
+
import { createRequire } from "node:module";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
5
7
|
import { RuntimeWrapperWebpackPlugin } from "@lynx-js/runtime-wrapper-webpack-plugin";
|
|
6
8
|
import { RuntimeGlobals } from "@lynx-js/webpack-runtime-globals";
|
|
7
9
|
import tiny_invariant from "tiny-invariant";
|
|
8
10
|
import { createHash } from "node:crypto";
|
|
9
|
-
import { fileURLToPath } from "node:url";
|
|
10
|
-
import { createRequire } from "node:module";
|
|
11
11
|
import { availableParallelism } from "node:os";
|
|
12
12
|
import { workspaces } from "@angular-devkit/core";
|
|
13
13
|
import { NodeJsSyncHost } from "@angular-devkit/core/node";
|
|
14
14
|
import { access, constants } from "node:fs/promises";
|
|
15
|
-
import
|
|
16
|
-
import { pluginTailwindCSS } from "rsbuild-plugin-tailwindcss";
|
|
15
|
+
import postcss_value_parser from "postcss-value-parser";
|
|
17
16
|
import * as __rspack_external_typescript from "typescript";
|
|
18
17
|
import * as __rspack_external_node_path_c5b9b54f from "node:path";
|
|
19
18
|
const ANGULAR_CLI_CONTEXT = Symbol.for('@blotch/rsbuild-plugin-angular-lynx:angular-cli-context');
|
|
@@ -90,19 +89,32 @@ const LAYERS = {
|
|
|
90
89
|
};
|
|
91
90
|
const applyLayers = (api)=>{
|
|
92
91
|
api.modifyBundlerChain((chain)=>{
|
|
93
|
-
|
|
92
|
+
for (const [layer, target, isMainThread] of [
|
|
93
|
+
[
|
|
94
|
+
LAYERS.BACKGROUND,
|
|
95
|
+
'es2015',
|
|
96
|
+
false
|
|
97
|
+
],
|
|
98
|
+
[
|
|
99
|
+
LAYERS.MAIN_THREAD,
|
|
100
|
+
'es2019',
|
|
101
|
+
true
|
|
102
|
+
]
|
|
103
|
+
])chain.module.rule("typescript").oneOf(layer).issuerLayer(layer).test(/\.[cm]?[jt]sx?$/).use('builtin:swc-loader').loader('builtin:swc-loader').options({
|
|
94
104
|
jsc: {
|
|
95
|
-
target
|
|
96
|
-
parser: {
|
|
97
|
-
syntax: "typescript"
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}).end();
|
|
101
|
-
chain.module.rule("typescript").oneOf(LAYERS.MAIN_THREAD).layer(LAYERS.MAIN_THREAD).test(/\.[cm]?[jt]sx?$/).use('builtin:swc-loader').loader('builtin:swc-loader').options({
|
|
102
|
-
jsc: {
|
|
103
|
-
target: 'es2019',
|
|
105
|
+
target,
|
|
104
106
|
parser: {
|
|
105
107
|
syntax: "typescript"
|
|
108
|
+
},
|
|
109
|
+
transform: {
|
|
110
|
+
optimizer: {
|
|
111
|
+
simplify: false,
|
|
112
|
+
globals: {
|
|
113
|
+
vars: {
|
|
114
|
+
__MAIN_THREAD__: String(isMainThread)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
106
118
|
}
|
|
107
119
|
}
|
|
108
120
|
}).end();
|
|
@@ -201,8 +213,9 @@ class AngularWebpackPlugin {
|
|
|
201
213
|
name: `${this.constructor.name}:threadGlobals`,
|
|
202
214
|
stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS
|
|
203
215
|
}, ()=>{
|
|
204
|
-
|
|
205
|
-
|
|
216
|
+
this.#markMainThreadHotUpdates(compilation, mainThreadChunkSet);
|
|
217
|
+
for (const [name] of Object.entries(compilation.assets).filter(([n])=>n.endsWith('.js') && !compilation.getAsset(n)?.info.hotModuleReplacement)){
|
|
218
|
+
const isMainThread = mainThreadChunkSet.has(name) || compilation.getAsset(name)?.info['lynx:main-thread'] === true;
|
|
206
219
|
const prefix = `globalThis["__MAIN_THREAD__"]=${isMainThread};`;
|
|
207
220
|
compilation.updateAsset(name, (old)=>new ConcatSource(prefix, old));
|
|
208
221
|
}
|
|
@@ -236,6 +249,16 @@ class AngularWebpackPlugin {
|
|
|
236
249
|
});
|
|
237
250
|
});
|
|
238
251
|
}
|
|
252
|
+
#markMainThreadHotUpdates(compilation, mainThreadChunkSet) {
|
|
253
|
+
for (const chunk of compilation.chunks){
|
|
254
|
+
const files = [
|
|
255
|
+
...chunk.files
|
|
256
|
+
];
|
|
257
|
+
if (files.some((file)=>mainThreadChunkSet.has(file) || !compilation.getAsset(file)?.info.hotModuleReplacement && compilation.getAsset(file)?.info['lynx:main-thread'])) {
|
|
258
|
+
for (const file of files)if (file.endsWith('.js') && compilation.getAsset(file)?.info.hotModuleReplacement) this.#updateMainThreadInfo(compilation, file);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
239
262
|
#updateMainThreadInfo(compilation, name) {
|
|
240
263
|
const asset = compilation.getAsset(name);
|
|
241
264
|
tiny_invariant(asset, `Should have main thread asset ${name}`);
|
|
@@ -249,9 +272,17 @@ const S_LYNX_CONFIG = Symbol.for('@lynx-js/rsbuild-plugin:config');
|
|
|
249
272
|
const PLUGIN_NAME_TEMPLATE = 'lynx:template';
|
|
250
273
|
const PLUGIN_NAME_RUNTIME_WRAPPER = 'lynx:runtime-wrapper';
|
|
251
274
|
const PLUGIN_NAME_ANGULAR = 'lynx:angular';
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
275
|
+
const RULE_BACKGROUND_MODULES = 'lynx:background-modules';
|
|
276
|
+
const PLUGIN_NAME_CSS_HOT_UPDATE = 'lynx:css-hot-update';
|
|
277
|
+
const BLUR_VIEW_STYLESHEET = node_path.resolve(node_path.dirname(fileURLToPath(import.meta.url)), './styles/blur-view.css');
|
|
278
|
+
const HMR_BACKGROUND_CLIENT = node_path.resolve(node_path.dirname(fileURLToPath(import.meta.url)), './client/hmr-background.js');
|
|
279
|
+
const HMR_MAIN_THREAD_CLIENT = node_path.resolve(node_path.dirname(fileURLToPath(import.meta.url)), './client/hmr-main-thread.js');
|
|
280
|
+
const CSS_HOT_UPDATE = node_path.resolve(node_path.dirname(fileURLToPath(import.meta.url)), './client/css-hot-update.cjs');
|
|
281
|
+
const CSS_EXTRACT_HOT_UPDATE = /css-extract-webpack-plugin[\\/]runtime[\\/]hotModuleReplacement\.cjs$/;
|
|
282
|
+
const resolveReloadApp = ()=>createRequire(createRequire(import.meta.url).resolve('@lynx-js/rsbuild-plugin')).resolve('@lynx-js/webpack-dev-transport/reloadApp');
|
|
283
|
+
const applyEntry = (api, options, backgroundEntries, appEntries)=>{
|
|
284
|
+
const { customCSSInheritanceList, debugInfoOutside, defaultDisplayLinear, defaultOverflowVisible, enableA11y, enableAccessibilityElement, enableCSSInheritance, enableCSSInvalidation, enableCSSSelector, enableNewGesture, enableRemoveCSSScope, removeDescendantSelectorScope, targetSdkVersion } = options;
|
|
285
|
+
api.modifyBundlerChain((chain, { environment, isDev, rspack })=>{
|
|
255
286
|
const lynxConfig = api.useExposed(S_LYNX_CONFIG);
|
|
256
287
|
if (!lynxConfig) throw new Error('No Lynx config exposed. `pluginLynx` has to be applied for the Lynx build engine to be configured.');
|
|
257
288
|
const isLynx = 'lynx' === environment.name;
|
|
@@ -261,9 +292,19 @@ const applyEntry = (api, options)=>{
|
|
|
261
292
|
const enabledLiveReload = isDev && !isWeb && false !== liveReload;
|
|
262
293
|
const entries = chain.entryPoints.entries() ?? {};
|
|
263
294
|
chain.entryPoints.clear();
|
|
295
|
+
const preEntry = new Set(environment.config.source.preEntry);
|
|
264
296
|
const mainThreadChunks = [];
|
|
265
297
|
for (const [entryName, entryPoint] of Object.entries(entries)){
|
|
266
|
-
const { imports } = getChunks(entryName, entryPoint.values());
|
|
298
|
+
const { imports: entryImports } = getChunks(entryName, entryPoint.values());
|
|
299
|
+
const mainThreadImports = isLynx ? [
|
|
300
|
+
BLUR_VIEW_STYLESHEET,
|
|
301
|
+
...entryImports
|
|
302
|
+
] : entryImports;
|
|
303
|
+
const backgroundImports = [
|
|
304
|
+
...entryImports.filter((entryImport)=>preEntry.has(entryImport)),
|
|
305
|
+
backgroundEntries.fileFor(environment.name, entryName)
|
|
306
|
+
];
|
|
307
|
+
for (const entryImport of entryImports)if (entryImport.startsWith('.') || node_path.isAbsolute(entryImport)) appEntries.add(node_path.resolve(api.context.rootPath, entryImport));
|
|
267
308
|
const templateFilename = lynxConfig.resolveBundleFilename({
|
|
268
309
|
entryName,
|
|
269
310
|
platform: environment.name
|
|
@@ -278,17 +319,22 @@ const applyEntry = (api, options)=>{
|
|
|
278
319
|
mainThreadChunks.push(mainThreadName);
|
|
279
320
|
chain.entry(mainThreadEntry).add({
|
|
280
321
|
layer: LAYERS.MAIN_THREAD,
|
|
281
|
-
import:
|
|
322
|
+
import: mainThreadImports,
|
|
282
323
|
filename: mainThreadName
|
|
324
|
+
}).when(enabledHMR, (entry)=>{
|
|
325
|
+
entry.prepend({
|
|
326
|
+
layer: LAYERS.MAIN_THREAD,
|
|
327
|
+
import: HMR_MAIN_THREAD_CLIENT
|
|
328
|
+
});
|
|
283
329
|
}).end();
|
|
284
330
|
chain.entry(backgroundEntry).add({
|
|
285
331
|
layer: LAYERS.BACKGROUND,
|
|
286
|
-
import:
|
|
332
|
+
import: backgroundImports,
|
|
287
333
|
filename: backgroundThreadName
|
|
288
334
|
}).when(enabledHMR, (entry)=>{
|
|
289
335
|
entry.prepend({
|
|
290
336
|
layer: LAYERS.BACKGROUND,
|
|
291
|
-
import:
|
|
337
|
+
import: HMR_BACKGROUND_CLIENT
|
|
292
338
|
});
|
|
293
339
|
}).when(enabledHMR || enabledLiveReload, (entry)=>{
|
|
294
340
|
entry.prepend({
|
|
@@ -315,6 +361,7 @@ const applyEntry = (api, options)=>{
|
|
|
315
361
|
customCSSInheritanceList,
|
|
316
362
|
debugInfoOutside,
|
|
317
363
|
defaultDisplayLinear,
|
|
364
|
+
defaultOverflowVisible,
|
|
318
365
|
enableAccessibilityElement,
|
|
319
366
|
enableCSSInheritance,
|
|
320
367
|
enableCSSInvalidation,
|
|
@@ -327,6 +374,14 @@ const applyEntry = (api, options)=>{
|
|
|
327
374
|
}
|
|
328
375
|
]).end();
|
|
329
376
|
}
|
|
377
|
+
chain.module.rule(RULE_BACKGROUND_MODULES).issuerLayer(LAYERS.BACKGROUND).test((file)=>backgroundEntries.isBackgroundModule(file)).sideEffects(true);
|
|
378
|
+
if (enabledHMR) {
|
|
379
|
+
chain.resolve.alias.set('@lynx-js/webpack-dev-transport/reloadApp', resolveReloadApp());
|
|
380
|
+
chain.plugin(PLUGIN_NAME_CSS_HOT_UPDATE).use(rspack.NormalModuleReplacementPlugin, [
|
|
381
|
+
CSS_EXTRACT_HOT_UPDATE,
|
|
382
|
+
CSS_HOT_UPDATE
|
|
383
|
+
]).end();
|
|
384
|
+
}
|
|
330
385
|
if (isLynx) {
|
|
331
386
|
chain.plugin(PLUGIN_NAME_RUNTIME_WRAPPER).use(RuntimeWrapperWebpackPlugin, [
|
|
332
387
|
{
|
|
@@ -473,7 +528,7 @@ const checkThresholds = (thresholds, size, label)=>thresholds.flatMap(({ limit,
|
|
|
473
528
|
}
|
|
474
529
|
];
|
|
475
530
|
});
|
|
476
|
-
const
|
|
531
|
+
const budgets_sum = (sizes)=>sizes.reduce((total, { size })=>total + size, 0);
|
|
477
532
|
const calculateSizes = (budget, assets, componentStyles)=>{
|
|
478
533
|
switch(budget.type){
|
|
479
534
|
case 'initial':
|
|
@@ -487,21 +542,21 @@ const calculateSizes = (budget, assets, componentStyles)=>{
|
|
|
487
542
|
case 'bundle':
|
|
488
543
|
return budget.name ? [
|
|
489
544
|
{
|
|
490
|
-
size:
|
|
545
|
+
size: budgets_sum(assets.filter((asset)=>asset.entryName === budget.name)),
|
|
491
546
|
label: budget.name
|
|
492
547
|
}
|
|
493
548
|
] : [];
|
|
494
549
|
case 'all':
|
|
495
550
|
return [
|
|
496
551
|
{
|
|
497
|
-
size:
|
|
552
|
+
size: budgets_sum(assets),
|
|
498
553
|
label: 'total'
|
|
499
554
|
}
|
|
500
555
|
];
|
|
501
556
|
case 'allScript':
|
|
502
557
|
return [
|
|
503
558
|
{
|
|
504
|
-
size:
|
|
559
|
+
size: budgets_sum(assets),
|
|
505
560
|
label: "total scripts"
|
|
506
561
|
}
|
|
507
562
|
];
|
|
@@ -622,68 +677,111 @@ const buildLynxSchemaSourceFileCache = (tsconfig, shouldInclude = ()=>true)=>{
|
|
|
622
677
|
fileNames
|
|
623
678
|
};
|
|
624
679
|
};
|
|
625
|
-
const generateComponentScopeId = (className, containingFile)=>{
|
|
626
|
-
const hash = createHash('sha256').update(`${className}|${containingFile}`).digest('hex').slice(0, 10);
|
|
627
|
-
return `l${hash}`;
|
|
628
|
-
};
|
|
629
680
|
const componentStyleSizeKey = (containingFile, stylesheetKey)=>`${containingFile}#${stylesheetKey}`;
|
|
630
681
|
const forgetComponentStyleSizes = (componentStyleSizes, containingFile)=>{
|
|
631
682
|
const prefix = componentStyleSizeKey(containingFile, '');
|
|
632
683
|
for (const key of componentStyleSizes.keys())if (key.startsWith(prefix)) componentStyleSizes.delete(key);
|
|
633
684
|
};
|
|
634
685
|
const createTransformStylesheet = (params)=>{
|
|
635
|
-
const { basePath,
|
|
686
|
+
const { basePath, componentStyleSizes } = params;
|
|
636
687
|
return async (data, containingFile, stylesheetFile, order, className)=>{
|
|
637
|
-
const
|
|
638
|
-
|
|
639
|
-
let componentStyles = componentStylesCache.get(containingFile);
|
|
640
|
-
if (!componentStyles) {
|
|
641
|
-
componentStyles = {
|
|
642
|
-
imports: [],
|
|
643
|
-
inlineStyles: [],
|
|
644
|
-
scopeId,
|
|
645
|
-
processedFiles: new Map()
|
|
646
|
-
};
|
|
647
|
-
componentStylesCache.set(containingFile, componentStyles);
|
|
648
|
-
}
|
|
649
|
-
const stylesheetKey = stylesheetFile ?? `__inline_${order}`;
|
|
650
|
-
const previousPath = componentStyles.processedFiles.get(stylesheetKey);
|
|
651
|
-
if (previousPath && !className) return '';
|
|
652
|
-
componentStyleSizes?.set(componentStyleSizeKey(containingFile, stylesheetKey), {
|
|
688
|
+
const key = componentStyleSizeKey(containingFile, stylesheetFile ?? `__inline_${order}`);
|
|
689
|
+
if (componentStyleSizes && (className || !componentStyleSizes.has(key))) componentStyleSizes.set(key, {
|
|
653
690
|
label: node_path.relative(basePath, stylesheetFile ?? containingFile).replace(/\\/g, '/'),
|
|
654
691
|
size: Buffer.byteLength(data)
|
|
655
692
|
});
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
693
|
+
return data;
|
|
694
|
+
};
|
|
695
|
+
};
|
|
696
|
+
const generateComponentScopeId = (className, containingFile)=>{
|
|
697
|
+
const hash = createHash('sha256').update(`${className}|${containingFile}`).digest('hex').slice(0, 10);
|
|
698
|
+
return `l${hash}`;
|
|
699
|
+
};
|
|
700
|
+
const EMULATED = 0;
|
|
701
|
+
const toLynxScopedCss = (css, scopeId)=>css.replaceAll('[_ngcontent-%COMP%]', `._ngcontent-${scopeId}`).replaceAll('[_nghost-%COMP%]', `._nghost-${scopeId}`).replaceAll('%COMP%', scopeId);
|
|
702
|
+
const fillCssVarNamespace = (css)=>css.replaceAll('%NS%', '');
|
|
703
|
+
const propertyName = (property)=>__rspack_external_typescript.isPropertyAssignment(property) && (__rspack_external_typescript.isIdentifier(property.name) || __rspack_external_typescript.isStringLiteral(property.name)) ? property.name.text : null;
|
|
704
|
+
const isDefineComponentCall = (node)=>{
|
|
705
|
+
if (!__rspack_external_typescript.isCallExpression(node)) return false;
|
|
706
|
+
const callee = node.expression;
|
|
707
|
+
const name = __rspack_external_typescript.isPropertyAccessExpression(callee) ? callee.name.text : __rspack_external_typescript.isIdentifier(callee) ? callee.text : null;
|
|
708
|
+
return 'ɵɵdefineComponent' === name;
|
|
709
|
+
};
|
|
710
|
+
const extractComponentStyles = (code, fileName)=>{
|
|
711
|
+
if (!code.includes('ɵɵdefineComponent')) return {
|
|
712
|
+
code,
|
|
713
|
+
components: []
|
|
714
|
+
};
|
|
715
|
+
const sourceFile = __rspack_external_typescript.createSourceFile(fileName, code, __rspack_external_typescript.ScriptTarget.Latest, true, __rspack_external_typescript.ScriptKind.JS);
|
|
716
|
+
const components = [];
|
|
717
|
+
const removals = [];
|
|
718
|
+
const visit = (node)=>{
|
|
719
|
+
if (isDefineComponentCall(node)) {
|
|
720
|
+
const definition = node.arguments[0];
|
|
721
|
+
if (definition && __rspack_external_typescript.isObjectLiteralExpression(definition)) {
|
|
722
|
+
const properties = definition.properties;
|
|
723
|
+
const find = (name)=>properties.find((property)=>propertyName(property) === name);
|
|
724
|
+
const type = find('type')?.initializer;
|
|
725
|
+
const styles = find('styles');
|
|
726
|
+
const encapsulation = find('encapsulation')?.initializer;
|
|
727
|
+
if (type && __rspack_external_typescript.isIdentifier(type) && styles && __rspack_external_typescript.isArrayLiteralExpression(styles.initializer) && styles.initializer.elements.length > 0 && styles.initializer.elements.every(__rspack_external_typescript.isStringLiteralLike)) {
|
|
728
|
+
const emulated = void 0 === encapsulation || __rspack_external_typescript.isNumericLiteral(encapsulation) && Number(encapsulation.text) === EMULATED;
|
|
729
|
+
const scopeId = emulated ? generateComponentScopeId(type.text, fileName) : void 0;
|
|
730
|
+
const stylesheets = styles.initializer.elements.map((element)=>{
|
|
731
|
+
const css = fillCssVarNamespace(element.text);
|
|
732
|
+
return scopeId ? toLynxScopedCss(css, scopeId) : css;
|
|
733
|
+
});
|
|
734
|
+
components.push({
|
|
735
|
+
className: type.text,
|
|
736
|
+
scopeId,
|
|
737
|
+
stylesheets
|
|
738
|
+
});
|
|
739
|
+
const index = properties.indexOf(styles);
|
|
740
|
+
const next = properties[index + 1];
|
|
741
|
+
removals.push({
|
|
742
|
+
start: styles.getStart(sourceFile),
|
|
743
|
+
end: next ? next.getStart(sourceFile) : properties.hasTrailingComma ? properties.end : styles.end
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
}
|
|
675
747
|
}
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
748
|
+
__rspack_external_typescript.forEachChild(node, visit);
|
|
749
|
+
};
|
|
750
|
+
visit(sourceFile);
|
|
751
|
+
let result = code;
|
|
752
|
+
for (const { start, end } of removals.sort((a, b)=>b.start - a.start))result = result.slice(0, start) + result.slice(end);
|
|
753
|
+
return {
|
|
754
|
+
code: result,
|
|
755
|
+
components
|
|
756
|
+
};
|
|
757
|
+
};
|
|
758
|
+
const writeModuleStylesheets = (params)=>{
|
|
759
|
+
const { basePath, cacheDir, fileName, components, onWritten } = params;
|
|
760
|
+
if (0 === components.length) return;
|
|
761
|
+
const prefix = node_path.relative(basePath, fileName).replace(/[/\\]/g, '__').replace(/\.[cm]?[jt]s$/, '');
|
|
762
|
+
const imports = [];
|
|
763
|
+
const scopes = [];
|
|
764
|
+
for (const { className, scopeId, stylesheets } of components){
|
|
765
|
+
stylesheets.forEach((css, index)=>{
|
|
766
|
+
const filePath = node_path.join(cacheDir, `${prefix}.${className}.${index}.css`);
|
|
767
|
+
let current;
|
|
768
|
+
try {
|
|
769
|
+
current = node_fs.readFileSync(filePath, 'utf-8');
|
|
683
770
|
} catch {}
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
771
|
+
if (current !== css) {
|
|
772
|
+
node_fs.writeFileSync(filePath, css);
|
|
773
|
+
onWritten?.(filePath);
|
|
774
|
+
}
|
|
775
|
+
imports.push(filePath);
|
|
776
|
+
});
|
|
777
|
+
if (scopeId) scopes.push({
|
|
778
|
+
className,
|
|
779
|
+
scopeId
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
return {
|
|
783
|
+
imports,
|
|
784
|
+
scopes
|
|
687
785
|
};
|
|
688
786
|
};
|
|
689
787
|
const isLynxUnknownElementMessage = (text)=>(text?.includes('is not a known element') || text?.includes("isn't a known property of")) ?? false;
|
|
@@ -723,12 +821,267 @@ const toAngularDiagnosticError = (message, severity)=>{
|
|
|
723
821
|
error.hideStack = true;
|
|
724
822
|
return error;
|
|
725
823
|
};
|
|
824
|
+
const PURE_CONSTRUCTORS = new Set([
|
|
825
|
+
'Map',
|
|
826
|
+
'Set',
|
|
827
|
+
'WeakMap',
|
|
828
|
+
'WeakSet'
|
|
829
|
+
]);
|
|
830
|
+
/**
|
|
831
|
+
* Wraps each top-level class with private or static members in a pure IIFE,
|
|
832
|
+
* so a bundler can drop the classes nothing uses.
|
|
833
|
+
*
|
|
834
|
+
* The background layer compiles to ES2015 (layers.ts), so SWC lowers private
|
|
835
|
+
* and static class fields. A class declaration keeps its own statement, but the
|
|
836
|
+
* class expressions that bundled libraries are written in (`var X = class
|
|
837
|
+
* {…}`) become a sequence that assigns each private field's `WeakMap` to an
|
|
838
|
+
* outer variable: `var X = (_a = new WeakMap(), class {…})`. The assignment
|
|
839
|
+
* counts as a side effect, so rspack keeps every such class, and every import
|
|
840
|
+
* it uses, even when nothing uses the class. The runtime's own classes are
|
|
841
|
+
* like that (it uses `#private` fields throughout), which kept Angular's
|
|
842
|
+
* renderer and change detection in the background bundle.
|
|
843
|
+
*
|
|
844
|
+
* Angular's build already wraps a class whose static members are Angular's
|
|
845
|
+
* own (`ɵcmp`, `ɵfac` and so on) in `/*#__PURE__*\/ (() => {…})()`; this does
|
|
846
|
+
* the same for the rest. Inside the IIFE, the lowering's assignments are local
|
|
847
|
+
* and the call is marked pure. A class whose static members could have side
|
|
848
|
+
* effects of their own (anything but literals, functions and new collections)
|
|
849
|
+
* is left alone.
|
|
850
|
+
*
|
|
851
|
+
* @param code - The module's code, before SWC lowers it (and, for a `.ts`
|
|
852
|
+
* file, strips its types).
|
|
853
|
+
* @param filename - The module's path, for the parser.
|
|
854
|
+
* @returns The transformed code, or `code` itself when nothing applies.
|
|
855
|
+
*/ const wrapPureClasses = (code, filename)=>{
|
|
856
|
+
if (!code.includes('class')) return code;
|
|
857
|
+
const sourceFile = __rspack_external_typescript.createSourceFile(filename, code, __rspack_external_typescript.ScriptTarget.Latest, true);
|
|
858
|
+
const edits = [];
|
|
859
|
+
const wrap = (classNode)=>{
|
|
860
|
+
edits.push({
|
|
861
|
+
start: classNode.getStart(sourceFile),
|
|
862
|
+
end: classNode.getStart(sourceFile),
|
|
863
|
+
text: '/*#__PURE__*/ (() => '
|
|
864
|
+
}, {
|
|
865
|
+
start: classNode.end,
|
|
866
|
+
end: classNode.end,
|
|
867
|
+
text: ')()'
|
|
868
|
+
});
|
|
869
|
+
};
|
|
870
|
+
for (const statement of sourceFile.statements){
|
|
871
|
+
if (__rspack_external_typescript.isVariableStatement(statement)) {
|
|
872
|
+
const [declaration, ...rest] = statement.declarationList.declarations;
|
|
873
|
+
const value = declaration?.initializer;
|
|
874
|
+
if (0 === rest.length && value && __rspack_external_typescript.isClassExpression(value) && isLoweredPureClass(value)) wrap(value);
|
|
875
|
+
continue;
|
|
876
|
+
}
|
|
877
|
+
if (__rspack_external_typescript.isClassDeclaration(statement) && statement.name && isLoweredPureClass(statement)) {
|
|
878
|
+
const modifiers = __rspack_external_typescript.getModifiers(statement) ?? [];
|
|
879
|
+
const isExport = modifiers.some((modifier)=>modifier.kind === __rspack_external_typescript.SyntaxKind.ExportKeyword);
|
|
880
|
+
const isDefault = modifiers.some((modifier)=>modifier.kind === __rspack_external_typescript.SyntaxKind.DefaultKeyword);
|
|
881
|
+
const name = statement.name.text;
|
|
882
|
+
const start = statement.getStart(sourceFile);
|
|
883
|
+
const classStart = statement.getChildren(sourceFile).find((child)=>child.kind === __rspack_external_typescript.SyntaxKind.ClassKeyword).getStart(sourceFile);
|
|
884
|
+
// `class X {}` becomes `let X = /*#__PURE__*/ (() => class X {})();`.
|
|
885
|
+
edits.push({
|
|
886
|
+
start,
|
|
887
|
+
end: classStart,
|
|
888
|
+
text: `${isExport && !isDefault ? 'export ' : ''}let ${name} = /*#__PURE__*/ (() => `
|
|
889
|
+
}, {
|
|
890
|
+
start: statement.end,
|
|
891
|
+
end: statement.end,
|
|
892
|
+
text: `)();${isDefault ? `\nexport { ${name} as default };` : ''}`
|
|
893
|
+
});
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
if (0 === edits.length) return code;
|
|
897
|
+
edits.sort((a, b)=>b.start - a.start);
|
|
898
|
+
let result = code;
|
|
899
|
+
for (const { start, end, text } of edits)result = result.slice(0, start) + text + result.slice(end);
|
|
900
|
+
return result;
|
|
901
|
+
};
|
|
902
|
+
const isLoweredPureClass = (node)=>{
|
|
903
|
+
if (__rspack_external_typescript.getDecorators(node)?.length) return false;
|
|
904
|
+
const heritage = node.heritageClauses?.find((clause)=>clause.token === __rspack_external_typescript.SyntaxKind.ExtendsKeyword);
|
|
905
|
+
const base = heritage?.types[0]?.expression;
|
|
906
|
+
if (base && !isPureReference(base)) return false;
|
|
907
|
+
let lowered = false;
|
|
908
|
+
for (const member of node.members){
|
|
909
|
+
if (__rspack_external_typescript.isClassStaticBlockDeclaration(member)) return false;
|
|
910
|
+
const isStatic = __rspack_external_typescript.getModifiers(member)?.some((modifier)=>modifier.kind === __rspack_external_typescript.SyntaxKind.StaticKeyword);
|
|
911
|
+
const isPrivate = member.name && __rspack_external_typescript.isPrivateIdentifier(member.name);
|
|
912
|
+
if (member.name && __rspack_external_typescript.isComputedPropertyName(member.name)) return false;
|
|
913
|
+
if (isStatic || isPrivate) lowered = true;
|
|
914
|
+
if (isStatic && __rspack_external_typescript.isPropertyDeclaration(member) && member.initializer && !isPure(member.initializer)) return false;
|
|
915
|
+
}
|
|
916
|
+
return lowered;
|
|
917
|
+
};
|
|
918
|
+
const isPureReference = (node)=>__rspack_external_typescript.isIdentifier(node) || __rspack_external_typescript.isPropertyAccessExpression(node) && isPureReference(node.expression);
|
|
919
|
+
const isPure = (node)=>{
|
|
920
|
+
if (__rspack_external_typescript.isLiteralExpression(node) || __rspack_external_typescript.isNoSubstitutionTemplateLiteral(node) || __rspack_external_typescript.isIdentifier(node) || __rspack_external_typescript.isArrowFunction(node) || __rspack_external_typescript.isFunctionExpression(node) || node.kind === __rspack_external_typescript.SyntaxKind.TrueKeyword || node.kind === __rspack_external_typescript.SyntaxKind.FalseKeyword || node.kind === __rspack_external_typescript.SyntaxKind.NullKeyword) return true;
|
|
921
|
+
if (__rspack_external_typescript.isVoidExpression(node)) return isPure(node.expression);
|
|
922
|
+
if (__rspack_external_typescript.isParenthesizedExpression(node)) return isPure(node.expression);
|
|
923
|
+
if (__rspack_external_typescript.isPrefixUnaryExpression(node)) return isPure(node.operand);
|
|
924
|
+
if (__rspack_external_typescript.isArrayLiteralExpression(node)) return node.elements.every((element)=>!__rspack_external_typescript.isSpreadElement(element) && isPure(element));
|
|
925
|
+
if (__rspack_external_typescript.isObjectLiteralExpression(node)) return node.properties.every((property)=>__rspack_external_typescript.isPropertyAssignment(property) && !__rspack_external_typescript.isComputedPropertyName(property.name) && isPure(property.initializer));
|
|
926
|
+
return __rspack_external_typescript.isNewExpression(node) && __rspack_external_typescript.isIdentifier(node.expression) && PURE_CONSTRUCTORS.has(node.expression.text) && (node.arguments ?? []).every(isPure);
|
|
927
|
+
};
|
|
726
928
|
const seedCompilationSourceFiles = (compilation, sourceFileCache)=>{
|
|
727
929
|
const { sourceFiles } = compilation;
|
|
728
930
|
if (!(sourceFiles instanceof Map)) return false;
|
|
729
931
|
for (const [fileName, sourceFile] of sourceFileCache)sourceFiles.set(fileName, sourceFile);
|
|
730
932
|
return true;
|
|
731
933
|
};
|
|
934
|
+
const IN_PLACE_FIELDS = new Set([
|
|
935
|
+
'template',
|
|
936
|
+
'templateUrl',
|
|
937
|
+
'styles',
|
|
938
|
+
'styleUrl',
|
|
939
|
+
'styleUrls'
|
|
940
|
+
]);
|
|
941
|
+
const hotUpdatesEnabled = (environment)=>'web' !== environment.name && 'development' === environment.config.mode && environment.config.dev?.hmr !== false;
|
|
942
|
+
const hot_updates_hash = (text)=>createHash('sha1').update(text).digest('hex').slice(0, 16);
|
|
943
|
+
const isComponentDecorator = (decorator)=>{
|
|
944
|
+
const call = decorator.expression;
|
|
945
|
+
if (!__rspack_external_typescript.isCallExpression(call)) return false;
|
|
946
|
+
const callee = call.expression;
|
|
947
|
+
const name = __rspack_external_typescript.isPropertyAccessExpression(callee) ? callee.name.text : __rspack_external_typescript.isIdentifier(callee) ? callee.text : void 0;
|
|
948
|
+
return 'Component' === name;
|
|
949
|
+
};
|
|
950
|
+
const hotUpdateSignature = (source, fileName)=>{
|
|
951
|
+
const sourceFile = __rspack_external_typescript.createSourceFile(fileName, source, __rspack_external_typescript.ScriptTarget.Latest, true, __rspack_external_typescript.ScriptKind.TS);
|
|
952
|
+
const removals = [];
|
|
953
|
+
const visit = (node)=>{
|
|
954
|
+
if (__rspack_external_typescript.isDecorator(node) && isComponentDecorator(node)) {
|
|
955
|
+
const metadata = node.expression.arguments[0];
|
|
956
|
+
if (metadata && __rspack_external_typescript.isObjectLiteralExpression(metadata)) {
|
|
957
|
+
for (const property of metadata.properties)if (__rspack_external_typescript.isPropertyAssignment(property) && (__rspack_external_typescript.isIdentifier(property.name) || __rspack_external_typescript.isStringLiteral(property.name)) && IN_PLACE_FIELDS.has(property.name.text)) removals.push({
|
|
958
|
+
start: property.initializer.getStart(sourceFile),
|
|
959
|
+
end: property.initializer.end
|
|
960
|
+
});
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
__rspack_external_typescript.forEachChild(node, visit);
|
|
964
|
+
};
|
|
965
|
+
visit(sourceFile);
|
|
966
|
+
let rest = source;
|
|
967
|
+
for (const { start, end } of removals.reverse())rest = rest.slice(0, start) + rest.slice(end);
|
|
968
|
+
return hot_updates_hash(rest);
|
|
969
|
+
};
|
|
970
|
+
const componentClassNames = (code, fileName)=>{
|
|
971
|
+
if (!code.includes('ɵɵdefineComponent')) return [];
|
|
972
|
+
const sourceFile = __rspack_external_typescript.createSourceFile(fileName, code, __rspack_external_typescript.ScriptTarget.Latest, true, __rspack_external_typescript.ScriptKind.JS);
|
|
973
|
+
const topLevelClasses = new Set(sourceFile.statements.filter(__rspack_external_typescript.isClassDeclaration).flatMap((statement)=>statement.name ? [
|
|
974
|
+
statement.name.text
|
|
975
|
+
] : []));
|
|
976
|
+
const names = [];
|
|
977
|
+
const visit = (node)=>{
|
|
978
|
+
if (__rspack_external_typescript.isCallExpression(node) && (__rspack_external_typescript.isPropertyAccessExpression(node.expression) ? node.expression.name.text : __rspack_external_typescript.isIdentifier(node.expression) ? node.expression.text : void 0) === 'ɵɵdefineComponent') {
|
|
979
|
+
const definition = node.arguments[0];
|
|
980
|
+
const type = definition && __rspack_external_typescript.isObjectLiteralExpression(definition) ? definition.properties.find((property)=>__rspack_external_typescript.isPropertyAssignment(property) && __rspack_external_typescript.isIdentifier(property.name) && 'type' === property.name.text)?.initializer : void 0;
|
|
981
|
+
if (type && __rspack_external_typescript.isIdentifier(type) && topLevelClasses.has(type.text) && !names.includes(type.text)) names.push(type.text);
|
|
982
|
+
}
|
|
983
|
+
__rspack_external_typescript.forEachChild(node, visit);
|
|
984
|
+
};
|
|
985
|
+
visit(sourceFile);
|
|
986
|
+
return names;
|
|
987
|
+
};
|
|
988
|
+
const ACCEPT = 'ɵɵangularLynxHmrAccept';
|
|
989
|
+
const addHotAccept = (code, { components, signature, compiled })=>{
|
|
990
|
+
const list = `[${components.join(', ')}]`;
|
|
991
|
+
return `${code}
|
|
992
|
+
import { ɵhmrAccept as ${ACCEPT} } from '@blotch/angular-lynx';
|
|
993
|
+
if (import.meta.webpackHot) {
|
|
994
|
+
${list} = ${ACCEPT}(import.meta.webpackHot, ${list}, ${JSON.stringify(signature)}, ${JSON.stringify(hot_updates_hash(compiled))});
|
|
995
|
+
}
|
|
996
|
+
`;
|
|
997
|
+
};
|
|
998
|
+
const addEntryHotAccept = (code)=>`${code}
|
|
999
|
+
if (import.meta.webpackHot) {
|
|
1000
|
+
import.meta.webpackHot.accept();
|
|
1001
|
+
}
|
|
1002
|
+
`;
|
|
1003
|
+
const RUNTIME_MODULE = '@blotch/angular-lynx';
|
|
1004
|
+
const TAGGED_CALLS = new Set([
|
|
1005
|
+
'backgroundFn',
|
|
1006
|
+
'createMainThreadRef'
|
|
1007
|
+
]);
|
|
1008
|
+
const TAGGED_CLASSES = new Set([
|
|
1009
|
+
'MainThreadRef'
|
|
1010
|
+
]);
|
|
1011
|
+
const transformCrossThread = (code, filename, options)=>{
|
|
1012
|
+
const calls = findModuleLevelCalls(code, filename);
|
|
1013
|
+
if (0 === calls.length) return code;
|
|
1014
|
+
const fileKey = keyForFile(filename, options.root);
|
|
1015
|
+
const edits = [];
|
|
1016
|
+
calls.forEach((node, index)=>{
|
|
1017
|
+
const edit = tagEdit(node, JSON.stringify(`${fileKey}:${index}`), code);
|
|
1018
|
+
if (edit) edits.push(edit);
|
|
1019
|
+
});
|
|
1020
|
+
edits.sort((a, b)=>b.start - a.start);
|
|
1021
|
+
let result = code;
|
|
1022
|
+
for (const { start, end, text } of edits)result = result.slice(0, start) + text + result.slice(end);
|
|
1023
|
+
return result;
|
|
1024
|
+
};
|
|
1025
|
+
const definesCrossThreadValues = (code, filename)=>findModuleLevelCalls(code, filename).length > 0;
|
|
1026
|
+
const findModuleLevelCalls = (code, filename)=>{
|
|
1027
|
+
if (!code.includes(RUNTIME_MODULE) || !code.includes('backgroundFn') && !code.includes('MainThreadRef')) return [];
|
|
1028
|
+
const sourceFile = __rspack_external_typescript.createSourceFile(filename, code, __rspack_external_typescript.ScriptTarget.Latest, true);
|
|
1029
|
+
const runtime = runtimeBindings(sourceFile);
|
|
1030
|
+
const calls = [];
|
|
1031
|
+
const visit = (node, topLevel)=>{
|
|
1032
|
+
if (topLevel && (__rspack_external_typescript.isCallExpression(node) && isRuntimeReference(node.expression, runtime, TAGGED_CALLS) || __rspack_external_typescript.isNewExpression(node) && isRuntimeReference(node.expression, runtime, TAGGED_CLASSES))) calls.push(node);
|
|
1033
|
+
const childTopLevel = topLevel && !__rspack_external_typescript.isFunctionLike(node) && !__rspack_external_typescript.isClassLike(node);
|
|
1034
|
+
__rspack_external_typescript.forEachChild(node, (child)=>visit(child, childTopLevel));
|
|
1035
|
+
};
|
|
1036
|
+
visit(sourceFile, true);
|
|
1037
|
+
return calls;
|
|
1038
|
+
};
|
|
1039
|
+
const tagEdit = (node, id, code)=>{
|
|
1040
|
+
const args = node.arguments ?? __rspack_external_typescript.factory.createNodeArray();
|
|
1041
|
+
if (args.length > 1 || args.some(__rspack_external_typescript.isSpreadElement)) return;
|
|
1042
|
+
if (1 === args.length) return {
|
|
1043
|
+
start: args[0].end,
|
|
1044
|
+
end: args[0].end,
|
|
1045
|
+
text: `, ${id}`
|
|
1046
|
+
};
|
|
1047
|
+
const close = node.getEnd() - 1;
|
|
1048
|
+
if (')' !== code[close]) return;
|
|
1049
|
+
return {
|
|
1050
|
+
start: close,
|
|
1051
|
+
end: close,
|
|
1052
|
+
text: `undefined, ${id}`
|
|
1053
|
+
};
|
|
1054
|
+
};
|
|
1055
|
+
const runtimeBindings = (sourceFile)=>{
|
|
1056
|
+
const named = new Map();
|
|
1057
|
+
const namespaces = new Set();
|
|
1058
|
+
for (const statement of sourceFile.statements){
|
|
1059
|
+
if (!__rspack_external_typescript.isImportDeclaration(statement) || !__rspack_external_typescript.isStringLiteral(statement.moduleSpecifier) || statement.moduleSpecifier.text !== RUNTIME_MODULE) continue;
|
|
1060
|
+
const bindings = statement.importClause?.namedBindings;
|
|
1061
|
+
if (bindings) {
|
|
1062
|
+
if (__rspack_external_typescript.isNamespaceImport(bindings)) {
|
|
1063
|
+
namespaces.add(bindings.name.text);
|
|
1064
|
+
continue;
|
|
1065
|
+
}
|
|
1066
|
+
for (const element of bindings.elements)named.set(element.name.text, (element.propertyName ?? element.name).text);
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
return {
|
|
1070
|
+
named,
|
|
1071
|
+
namespaces
|
|
1072
|
+
};
|
|
1073
|
+
};
|
|
1074
|
+
const isRuntimeReference = (expression, runtime, exports)=>{
|
|
1075
|
+
if (__rspack_external_typescript.isIdentifier(expression)) {
|
|
1076
|
+
const imported = runtime.named.get(expression.text);
|
|
1077
|
+
return void 0 !== imported && exports.has(imported);
|
|
1078
|
+
}
|
|
1079
|
+
return __rspack_external_typescript.isPropertyAccessExpression(expression) && __rspack_external_typescript.isIdentifier(expression.expression) && runtime.namespaces.has(expression.expression.text) && exports.has(expression.name.text);
|
|
1080
|
+
};
|
|
1081
|
+
const keyForFile = (filename, root)=>{
|
|
1082
|
+
const relative = node_path.relative(root, filename).split(node_path.sep).join('/');
|
|
1083
|
+
return createHash('sha1').update(relative).digest('hex').slice(0, 10);
|
|
1084
|
+
};
|
|
732
1085
|
const MAIN_THREAD_DIRECTIVE = 'main thread';
|
|
733
1086
|
const MAIN_THREAD_DIRECTIVE_ALT = 'main-thread';
|
|
734
1087
|
const transformWorklets = (code, filename)=>{
|
|
@@ -775,10 +1128,10 @@ const isAlreadyWrapped = (node)=>{
|
|
|
775
1128
|
return false;
|
|
776
1129
|
};
|
|
777
1130
|
const buildTransformedCode = (params)=>{
|
|
778
|
-
const { resourcePath,
|
|
1131
|
+
const { resourcePath, stylesheets, root, hot } = params;
|
|
779
1132
|
let code = params.code;
|
|
780
|
-
if (
|
|
781
|
-
const { imports } =
|
|
1133
|
+
if (stylesheets) {
|
|
1134
|
+
const { imports } = stylesheets;
|
|
782
1135
|
let importsString = '';
|
|
783
1136
|
for(let i = 0; i < imports.length; ++i){
|
|
784
1137
|
let relativeImport = node_path.relative(node_path.dirname(resourcePath), imports[i]);
|
|
@@ -787,8 +1140,19 @@ const buildTransformedCode = (params)=>{
|
|
|
787
1140
|
}
|
|
788
1141
|
code = importsString + code;
|
|
789
1142
|
}
|
|
790
|
-
|
|
791
|
-
|
|
1143
|
+
for (const { className, scopeId } of stylesheets?.scopes ?? [])code += `\n;${className}.ɵcmp.id = '${scopeId}';\n`;
|
|
1144
|
+
const transformed = transformCrossThread(transformWorklets(code, resourcePath), resourcePath, {
|
|
1145
|
+
root
|
|
1146
|
+
});
|
|
1147
|
+
if (!hot) return transformed;
|
|
1148
|
+
if (hot.entry) return addEntryHotAccept(transformed);
|
|
1149
|
+
const components = componentClassNames(params.code, resourcePath);
|
|
1150
|
+
if (0 === components.length) return transformed;
|
|
1151
|
+
return addHotAccept(transformed, {
|
|
1152
|
+
components,
|
|
1153
|
+
signature: hotUpdateSignature(hot.source(), resourcePath),
|
|
1154
|
+
compiled: params.code
|
|
1155
|
+
});
|
|
792
1156
|
};
|
|
793
1157
|
const applyAngularConfig = (api, buildOptions)=>{
|
|
794
1158
|
const __dirname = node_path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -805,9 +1169,9 @@ const applyAngularConfig = (api, buildOptions)=>{
|
|
|
805
1169
|
];
|
|
806
1170
|
else config.source.preEntry ??= [];
|
|
807
1171
|
config.source.preEntry.push(node_path.resolve(__dirname, './polyfills'));
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
1172
|
+
const polyfills = buildOptions.polyfills ?? [];
|
|
1173
|
+
if (buildOptions.i18n.hasDefinedSourceLocale && !polyfills.some((polyfill)=>polyfill.startsWith('@angular/localize'))) config.source.preEntry.push('@angular/localize/init');
|
|
1174
|
+
config.source.preEntry.push(...polyfills);
|
|
811
1175
|
config.source.preEntry.push(...buildOptions.styles);
|
|
812
1176
|
config.source.tsconfigPath = buildOptions.tsconfig;
|
|
813
1177
|
config.source.define ??= {};
|
|
@@ -916,7 +1280,7 @@ const normalizeCacheOptions = (projectMetadata, workspaceRoot)=>{
|
|
|
916
1280
|
cacheEnabled = !isCI;
|
|
917
1281
|
break;
|
|
918
1282
|
}
|
|
919
|
-
const cacheBasePath =
|
|
1283
|
+
const cacheBasePath = external_node_path_resolve(workspaceRoot, path);
|
|
920
1284
|
return {
|
|
921
1285
|
enabled: cacheEnabled,
|
|
922
1286
|
basePath: cacheBasePath,
|
|
@@ -1325,7 +1689,7 @@ const reportLynxDiagnostics = (diagnostics)=>{
|
|
|
1325
1689
|
for (const w of cssWarnings)console.warn(` ${w.message}`);
|
|
1326
1690
|
}
|
|
1327
1691
|
};
|
|
1328
|
-
const applyAngularRules = async (api, pluginOptions)=>{
|
|
1692
|
+
const applyAngularRules = async (api, pluginOptions, backgroundEntries, appEntries)=>{
|
|
1329
1693
|
const cli = getAngularCliContext(api);
|
|
1330
1694
|
const { basePath, workspace } = await getAngularWorkspace(cli?.workspaceRoot);
|
|
1331
1695
|
if (pluginOptions.pages) {
|
|
@@ -1365,25 +1729,22 @@ const applyAngularRules = async (api, pluginOptions)=>{
|
|
|
1365
1729
|
const tsconfig = buildOptions.tsconfig;
|
|
1366
1730
|
const compilation = await createAngularCompilation(false, aot);
|
|
1367
1731
|
const typeScriptFileCache = new Map();
|
|
1368
|
-
const
|
|
1369
|
-
node_fs.mkdirSync(
|
|
1732
|
+
const componentCssCacheDir = node_path.join(basePath, 'node_modules', '.cache', 'angular-lynx-css');
|
|
1733
|
+
node_fs.mkdirSync(componentCssCacheDir, {
|
|
1370
1734
|
recursive: true
|
|
1371
1735
|
});
|
|
1372
|
-
const
|
|
1373
|
-
const componentScopeIds = new Map();
|
|
1736
|
+
const moduleStylesheets = new Map();
|
|
1374
1737
|
let componentResourceDependencies = new Map();
|
|
1375
1738
|
const writtenStylesheets = new Set();
|
|
1376
1739
|
let knownSourceFiles = new Set();
|
|
1740
|
+
const backgroundModules = new Set();
|
|
1741
|
+
let angularInputs = new Set();
|
|
1377
1742
|
let angularDiagnostics = {
|
|
1378
1743
|
errors: [],
|
|
1379
1744
|
warnings: []
|
|
1380
1745
|
};
|
|
1381
1746
|
const transformStylesheet = createTransformStylesheet({
|
|
1382
1747
|
basePath,
|
|
1383
|
-
scopedCssCacheDir,
|
|
1384
|
-
componentStylesCache,
|
|
1385
|
-
componentScopeIds,
|
|
1386
|
-
onStylesheetWritten: (filePath)=>writtenStylesheets.add(filePath),
|
|
1387
1748
|
componentStyleSizes
|
|
1388
1749
|
});
|
|
1389
1750
|
const compileAngular = async (changedFiles)=>{
|
|
@@ -1420,8 +1781,22 @@ const applyAngularRules = async (api, pluginOptions)=>{
|
|
|
1420
1781
|
try {
|
|
1421
1782
|
for (const { filename, contents } of (await compilation.emitAffectedFiles())){
|
|
1422
1783
|
const file = node_path.normalize(filename);
|
|
1423
|
-
|
|
1424
|
-
|
|
1784
|
+
const { code, components } = extractComponentStyles('string' == typeof contents ? contents : Buffer.from(contents).toString(), file);
|
|
1785
|
+
const stylesheets = writeModuleStylesheets({
|
|
1786
|
+
basePath,
|
|
1787
|
+
cacheDir: componentCssCacheDir,
|
|
1788
|
+
fileName: file,
|
|
1789
|
+
components,
|
|
1790
|
+
onWritten: (filePath)=>writtenStylesheets.add(filePath)
|
|
1791
|
+
});
|
|
1792
|
+
if (stylesheets) moduleStylesheets.set(file, stylesheets);
|
|
1793
|
+
else moduleStylesheets.delete(file);
|
|
1794
|
+
if (typeScriptFileCache.get(file) !== code) {
|
|
1795
|
+
changedOutputs.add(file);
|
|
1796
|
+
if (definesCrossThreadValues(code, file)) backgroundModules.add(file);
|
|
1797
|
+
else backgroundModules.delete(file);
|
|
1798
|
+
}
|
|
1799
|
+
typeScriptFileCache.set(file, code);
|
|
1425
1800
|
}
|
|
1426
1801
|
} catch (error) {
|
|
1427
1802
|
throw new Error(`Angular failed to emit compiled output for "${tsconfig}". Original error: ${error instanceof Error ? error.stack ?? error.message : String(error)}`);
|
|
@@ -1429,6 +1804,8 @@ const applyAngularRules = async (api, pluginOptions)=>{
|
|
|
1429
1804
|
for (const file of writtenStylesheets)changedOutputs.add(file);
|
|
1430
1805
|
for (const file of changedFiles ?? [])if (!node_fs.existsSync(file)) {
|
|
1431
1806
|
typeScriptFileCache.delete(file);
|
|
1807
|
+
backgroundModules.delete(file);
|
|
1808
|
+
moduleStylesheets.delete(file);
|
|
1432
1809
|
forgetComponentStyleSizes(componentStyleSizes, file);
|
|
1433
1810
|
}
|
|
1434
1811
|
reportLynxDiagnostics([
|
|
@@ -1438,9 +1815,16 @@ const applyAngularRules = async (api, pluginOptions)=>{
|
|
|
1438
1815
|
...scanSourcesForUnsupportedCss(fileNames)
|
|
1439
1816
|
]);
|
|
1440
1817
|
angularDiagnostics = filterAngularDiagnostics(await compilation.diagnoseFiles(useTypeChecking ? DiagnosticModes.All : DiagnosticModes.All & ~DiagnosticModes.Semantic));
|
|
1818
|
+
const inputFiles = result.referencedFiles.map((file)=>node_path.normalize(file));
|
|
1819
|
+
angularInputs = new Set([
|
|
1820
|
+
...inputFiles,
|
|
1821
|
+
...[
|
|
1822
|
+
...componentResourceDependencies.values()
|
|
1823
|
+
].flat()
|
|
1824
|
+
]);
|
|
1441
1825
|
return {
|
|
1442
1826
|
changedOutputs,
|
|
1443
|
-
inputFiles
|
|
1827
|
+
inputFiles
|
|
1444
1828
|
};
|
|
1445
1829
|
};
|
|
1446
1830
|
const coordinator = createAngularRebuildCoordinator({
|
|
@@ -1460,46 +1844,199 @@ const applyAngularRules = async (api, pluginOptions)=>{
|
|
|
1460
1844
|
let compilationClosed = false;
|
|
1461
1845
|
api.onBeforeEnvironmentCompile(async ({ environment, isWatch })=>{
|
|
1462
1846
|
const compiler = compilersByEnvironment.get(environment.name);
|
|
1463
|
-
const
|
|
1847
|
+
const changedFiles = [
|
|
1464
1848
|
...compiler?.modifiedFiles ?? [],
|
|
1465
1849
|
...compiler?.removedFiles ?? []
|
|
1466
|
-
]
|
|
1467
|
-
|
|
1850
|
+
];
|
|
1851
|
+
const outdatedFiles = await coordinator.prepare(environment.name, changedFiles);
|
|
1852
|
+
const changedEntries = backgroundEntries.update(environment.name, {
|
|
1853
|
+
appModules: backgroundModules,
|
|
1854
|
+
watch: isWatch,
|
|
1855
|
+
rebuilt: outdatedFiles.size > 0 || changedFiles.some((file)=>!angularInputs.has(node_path.normalize(file)) && !backgroundEntries.isEntryFile(file))
|
|
1856
|
+
});
|
|
1857
|
+
if (compiler && outdatedFiles.size + changedEntries.length > 0) compiler.modifiedFiles = new Set([
|
|
1468
1858
|
...compiler.modifiedFiles ?? [],
|
|
1469
|
-
...outdatedFiles
|
|
1859
|
+
...outdatedFiles,
|
|
1860
|
+
...changedEntries
|
|
1470
1861
|
]);
|
|
1471
1862
|
if (!isWatch && !compilationClosed) {
|
|
1472
1863
|
compilationClosed = true;
|
|
1473
1864
|
await compilation.close?.();
|
|
1474
1865
|
}
|
|
1475
1866
|
});
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
}, async (context)=>{
|
|
1867
|
+
const transformModule = async (context, background)=>{
|
|
1868
|
+
const hot = hotUpdatesEnabled(context.environment);
|
|
1479
1869
|
const isJs = /\.[cm]?js$/.test(context.resourcePath);
|
|
1480
1870
|
if (isJs) {
|
|
1481
1871
|
const contents = await javascriptTransformer.transformData(context.resourcePath, context.code, {
|
|
1482
1872
|
skipLinker: false,
|
|
1483
1873
|
sideEffects: ()=>Promise.resolve(false)
|
|
1484
1874
|
});
|
|
1875
|
+
const code = transformCrossThread(transformWorklets(Buffer.from(contents).toString(), context.resourcePath), context.resourcePath, {
|
|
1876
|
+
root: api.context.rootPath
|
|
1877
|
+
});
|
|
1878
|
+
if (!background) return {
|
|
1879
|
+
code
|
|
1880
|
+
};
|
|
1881
|
+
const wrapped = wrapPureClasses(code, context.resourcePath);
|
|
1485
1882
|
return {
|
|
1486
|
-
code:
|
|
1883
|
+
code: hot && backgroundEntries.isEntryFile(context.resourcePath) ? addEntryHotAccept(wrapped) : wrapped
|
|
1487
1884
|
};
|
|
1488
1885
|
}
|
|
1489
1886
|
const content = typeScriptFileCache.get(context.resourcePath);
|
|
1490
1887
|
if (!content) throw new Error(`No compiled output found for ${context.resourcePath}`);
|
|
1491
1888
|
for (const dependency of componentResourceDependencies.get(context.resourcePath) ?? [])context.addDependency(dependency);
|
|
1492
|
-
const code =
|
|
1889
|
+
const code = buildTransformedCode({
|
|
1890
|
+
code: 'string' == typeof content ? content : Buffer.from(content).toString(),
|
|
1891
|
+
resourcePath: context.resourcePath,
|
|
1892
|
+
stylesheets: moduleStylesheets.get(context.resourcePath),
|
|
1893
|
+
root: api.context.rootPath,
|
|
1894
|
+
hot: hot && !background ? {
|
|
1895
|
+
entry: appEntries.has(node_path.normalize(context.resourcePath)),
|
|
1896
|
+
source: ()=>node_fs.readFileSync(context.resourcePath, 'utf-8')
|
|
1897
|
+
} : void 0
|
|
1898
|
+
});
|
|
1899
|
+
if (!background) return {
|
|
1900
|
+
code
|
|
1901
|
+
};
|
|
1493
1902
|
return {
|
|
1494
|
-
code:
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
scopeInfo: componentScopeIds.get(context.resourcePath)
|
|
1499
|
-
})
|
|
1903
|
+
code: wrapPureClasses(Buffer.from(await javascriptTransformer.transformData(context.resourcePath, code, {
|
|
1904
|
+
skipLinker: true,
|
|
1905
|
+
sideEffects: ()=>Promise.resolve(false)
|
|
1906
|
+
})).toString(), context.resourcePath)
|
|
1500
1907
|
};
|
|
1908
|
+
};
|
|
1909
|
+
api.transform({
|
|
1910
|
+
test: /\.[cm]?[jt]sx?$/,
|
|
1911
|
+
issuerLayer: LAYERS.MAIN_THREAD
|
|
1912
|
+
}, (context)=>transformModule(context, false));
|
|
1913
|
+
api.transform({
|
|
1914
|
+
test: /\.[cm]?[jt]sx?$/,
|
|
1915
|
+
issuerLayer: LAYERS.BACKGROUND
|
|
1916
|
+
}, (context)=>transformModule(context, true));
|
|
1917
|
+
};
|
|
1918
|
+
const background_entry_RUNTIME_MODULE = '@blotch/angular-lynx';
|
|
1919
|
+
const createBackgroundEntries = ({ rootPath, findLibraryModules = findLibraryBackgroundModules })=>{
|
|
1920
|
+
const cacheDir = node_path.join(rootPath, 'node_modules', '.cache', 'angular-lynx', 'background-entries');
|
|
1921
|
+
const files = new Map();
|
|
1922
|
+
let libraryModules;
|
|
1923
|
+
const getLibraryModules = ()=>libraryModules ??= findLibraryModules(rootPath);
|
|
1924
|
+
let modules = new Set();
|
|
1925
|
+
const rebuilds = new Map();
|
|
1926
|
+
return {
|
|
1927
|
+
fileFor: (environmentName, entryName)=>{
|
|
1928
|
+
const file = node_path.join(cacheDir, environmentName, `${entryName}.js`);
|
|
1929
|
+
let environmentFiles = files.get(environmentName);
|
|
1930
|
+
if (!environmentFiles) {
|
|
1931
|
+
environmentFiles = new Set();
|
|
1932
|
+
files.set(environmentName, environmentFiles);
|
|
1933
|
+
}
|
|
1934
|
+
environmentFiles.add(file);
|
|
1935
|
+
if (!node_fs.existsSync(file)) writeIfChanged(file, renderBackgroundEntry({
|
|
1936
|
+
modules: []
|
|
1937
|
+
}));
|
|
1938
|
+
return file;
|
|
1939
|
+
},
|
|
1940
|
+
isBackgroundModule: (file)=>modules.has(file),
|
|
1941
|
+
isEntryFile: (file)=>[
|
|
1942
|
+
...files.values()
|
|
1943
|
+
].some((environmentFiles)=>environmentFiles.has(file)),
|
|
1944
|
+
update: (environmentName, { appModules, watch, rebuilt })=>{
|
|
1945
|
+
modules = new Set([
|
|
1946
|
+
...getLibraryModules(),
|
|
1947
|
+
...[
|
|
1948
|
+
...appModules
|
|
1949
|
+
].sort()
|
|
1950
|
+
]);
|
|
1951
|
+
const rebuild = (rebuilds.get(environmentName) ?? 0) + (watch && rebuilt ? 1 : 0);
|
|
1952
|
+
rebuilds.set(environmentName, rebuild);
|
|
1953
|
+
const contents = renderBackgroundEntry({
|
|
1954
|
+
modules: [
|
|
1955
|
+
...modules
|
|
1956
|
+
],
|
|
1957
|
+
rebuild: watch ? rebuild : void 0
|
|
1958
|
+
});
|
|
1959
|
+
return [
|
|
1960
|
+
...files.get(environmentName) ?? []
|
|
1961
|
+
].filter((file)=>writeIfChanged(file, contents));
|
|
1962
|
+
}
|
|
1963
|
+
};
|
|
1964
|
+
};
|
|
1965
|
+
const renderBackgroundEntry = ({ modules, rebuild })=>{
|
|
1966
|
+
const lines = [
|
|
1967
|
+
"// The background thread's entry, generated by",
|
|
1968
|
+
'// @blotch/rsbuild-plugin-angular-lynx (see background-entry.ts there).',
|
|
1969
|
+
'// Angular runs on the main thread only, so the background thread loads the',
|
|
1970
|
+
'// runtime and the modules that call backgroundFn(), createMainThreadRef()',
|
|
1971
|
+
'// or new MainThreadRef() at module level.',
|
|
1972
|
+
`import { ɵstartBackgroundThread } from '${background_entry_RUNTIME_MODULE}';`,
|
|
1973
|
+
...modules.map((file)=>`import ${JSON.stringify(file)};`),
|
|
1974
|
+
'ɵstartBackgroundThread();'
|
|
1975
|
+
];
|
|
1976
|
+
if (void 0 !== rebuild) lines.push(`// Rebuild ${rebuild}`);
|
|
1977
|
+
return `${lines.join('\n')}\n`;
|
|
1978
|
+
};
|
|
1979
|
+
const writeIfChanged = (file, contents)=>{
|
|
1980
|
+
if (node_fs.existsSync(file) && node_fs.readFileSync(file, 'utf8') === contents) return false;
|
|
1981
|
+
node_fs.mkdirSync(node_path.dirname(file), {
|
|
1982
|
+
recursive: true
|
|
1501
1983
|
});
|
|
1984
|
+
node_fs.writeFileSync(file, contents);
|
|
1985
|
+
return true;
|
|
1986
|
+
};
|
|
1987
|
+
const JS_FILE = /\.[cm]?js$/;
|
|
1988
|
+
const findLibraryBackgroundModules = (rootPath)=>{
|
|
1989
|
+
const found = new Set();
|
|
1990
|
+
const visited = new Set();
|
|
1991
|
+
const visit = (packageDir, isApp)=>{
|
|
1992
|
+
const manifest = readManifest(packageDir);
|
|
1993
|
+
if (!manifest) return;
|
|
1994
|
+
const names = new Set([
|
|
1995
|
+
...Object.keys(manifest.dependencies ?? {}),
|
|
1996
|
+
...Object.keys(manifest.optionalDependencies ?? {}),
|
|
1997
|
+
...Object.keys(manifest.peerDependencies ?? {}),
|
|
1998
|
+
...isApp ? Object.keys(manifest.devDependencies ?? {}) : []
|
|
1999
|
+
]);
|
|
2000
|
+
names.delete(background_entry_RUNTIME_MODULE);
|
|
2001
|
+
for (const name of names){
|
|
2002
|
+
const dependencyDir = resolvePackageDir(name, packageDir);
|
|
2003
|
+
if (!dependencyDir || visited.has(dependencyDir)) continue;
|
|
2004
|
+
visited.add(dependencyDir);
|
|
2005
|
+
const dependency = readManifest(dependencyDir);
|
|
2006
|
+
if (dependency && dependsOnRuntime(dependency)) {
|
|
2007
|
+
for (const file of listJsFiles(dependencyDir))if (definesCrossThreadValues(node_fs.readFileSync(file, 'utf8'), file)) found.add(file);
|
|
2008
|
+
}
|
|
2009
|
+
visit(dependencyDir, false);
|
|
2010
|
+
}
|
|
2011
|
+
};
|
|
2012
|
+
visit(rootPath, true);
|
|
2013
|
+
return [
|
|
2014
|
+
...found
|
|
2015
|
+
].sort();
|
|
1502
2016
|
};
|
|
2017
|
+
const readManifest = (packageDir)=>{
|
|
2018
|
+
try {
|
|
2019
|
+
return JSON.parse(node_fs.readFileSync(node_path.join(packageDir, 'package.json'), 'utf8'));
|
|
2020
|
+
} catch {
|
|
2021
|
+
return;
|
|
2022
|
+
}
|
|
2023
|
+
};
|
|
2024
|
+
const dependsOnRuntime = (manifest)=>[
|
|
2025
|
+
manifest.dependencies,
|
|
2026
|
+
manifest.optionalDependencies,
|
|
2027
|
+
manifest.peerDependencies
|
|
2028
|
+
].some((dependencies)=>dependencies?.[background_entry_RUNTIME_MODULE] !== void 0);
|
|
2029
|
+
const resolvePackageDir = (name, fromDir)=>{
|
|
2030
|
+
for(let dir = fromDir;; dir = node_path.dirname(dir)){
|
|
2031
|
+
const candidate = node_path.join(dir, 'node_modules', name);
|
|
2032
|
+
if (node_fs.existsSync(node_path.join(candidate, 'package.json'))) return node_fs.realpathSync(candidate);
|
|
2033
|
+
if (node_path.dirname(dir) === dir) return;
|
|
2034
|
+
}
|
|
2035
|
+
};
|
|
2036
|
+
const listJsFiles = (packageDir)=>node_fs.readdirSync(packageDir, {
|
|
2037
|
+
recursive: true,
|
|
2038
|
+
encoding: 'utf8'
|
|
2039
|
+
}).filter((file)=>JS_FILE.test(file) && !file.split(node_path.sep).includes('node_modules')).map((file)=>node_path.join(packageDir, file));
|
|
1503
2040
|
const applyCSS = (api, options)=>{
|
|
1504
2041
|
const { enableRemoveCSSScope, enableCSSSelector, enableCSSInvalidation, targetSdkVersion } = options;
|
|
1505
2042
|
api.modifyRsbuildConfig((config, { mergeRsbuildConfig })=>mergeRsbuildConfig(config, {
|
|
@@ -1525,23 +2062,23 @@ const applyCSS = (api, options)=>{
|
|
|
1525
2062
|
const mainRule = rule.oneOf(mainRuleName);
|
|
1526
2063
|
const parentRuleEntries = rule.entries();
|
|
1527
2064
|
removeLightningCSS(mainRule);
|
|
1528
|
-
mainRule.issuerLayer(LAYERS.
|
|
2065
|
+
mainRule.issuerLayer(LAYERS.MAIN_THREAD).use(CHAIN_ID.USE.MINI_CSS_EXTRACT).loader(CssExtractRspackPlugin.loader).end();
|
|
1529
2066
|
const uses = mainRule.uses.entries() ?? {};
|
|
1530
2067
|
const ruleEntries = mainRule.entries();
|
|
1531
2068
|
const cssLoader = uses[CHAIN_ID.USE.CSS];
|
|
1532
2069
|
if (!cssLoader) continue;
|
|
1533
2070
|
const cssLoaderRule = cssLoader.entries();
|
|
1534
|
-
const
|
|
1535
|
-
if (void 0 !== parentRuleEntries.dependency)
|
|
2071
|
+
const backgroundLayerRule = chain.module.rule(`${ruleName}:${LAYERS.BACKGROUND}`).test(parentRuleEntries.test).merge(ruleEntries).issuerLayer(LAYERS.BACKGROUND);
|
|
2072
|
+
if (void 0 !== parentRuleEntries.dependency) backgroundLayerRule.merge({
|
|
1536
2073
|
dependency: parentRuleEntries.dependency
|
|
1537
2074
|
});
|
|
1538
|
-
|
|
2075
|
+
backgroundLayerRule.use(CHAIN_ID.USE.IGNORE_CSS).loader(node_path.resolve(__dirname, './loaders/ignore-css-loader')).end().uses.merge(uses).delete(CHAIN_ID.USE.MINI_CSS_EXTRACT).delete(CHAIN_ID.USE.LIGHTNINGCSS).delete(CHAIN_ID.USE.CSS).end().use(CHAIN_ID.USE.CSS).after(CHAIN_ID.USE.IGNORE_CSS).merge(cssLoaderRule).options(normalizeCssLoaderOptions(cssLoaderRule.options, true)).end();
|
|
1539
2076
|
}
|
|
1540
2077
|
for (const ruleName of cssRules.filter((rule)=>chain.module.rules.has(rule))){
|
|
1541
2078
|
const inlineRuleName = ruleName === CHAIN_ID.RULE.CSS ? CHAIN_ID.ONE_OF.CSS_INLINE : `${ruleName}-inline`;
|
|
1542
2079
|
removeLightningCSS(chain.module.rule(ruleName).oneOf(inlineRuleName));
|
|
1543
2080
|
}
|
|
1544
|
-
if (
|
|
2081
|
+
if (chain.module.rules.has(CHAIN_ID.RULE.FONT)) {
|
|
1545
2082
|
const fontRule = chain.module.rule(CHAIN_ID.RULE.FONT);
|
|
1546
2083
|
fontRule.oneOfs.clear();
|
|
1547
2084
|
fontRule.type('asset/inline');
|
|
@@ -1597,6 +2134,21 @@ const applyGenerator = (api)=>{
|
|
|
1597
2134
|
}
|
|
1598
2135
|
});
|
|
1599
2136
|
};
|
|
2137
|
+
const applyResolve = (api)=>{
|
|
2138
|
+
api.modifyRspackConfig((config)=>{
|
|
2139
|
+
const resolve = config.resolve ??= {};
|
|
2140
|
+
const conditions = (resolve.conditionNames ?? []).filter((condition)=>'require' !== condition);
|
|
2141
|
+
if (!conditions.includes('module')) conditions.splice(conditions.indexOf('import') + 1, 0, 'module');
|
|
2142
|
+
resolve.byDependency = {
|
|
2143
|
+
...resolve.byDependency,
|
|
2144
|
+
esm: {
|
|
2145
|
+
...resolve.byDependency?.['esm'],
|
|
2146
|
+
conditionNames: conditions
|
|
2147
|
+
}
|
|
2148
|
+
};
|
|
2149
|
+
});
|
|
2150
|
+
};
|
|
2151
|
+
const DEV_LOGS_PATH = '/__dev_logs';
|
|
1600
2152
|
const RESET = '\x1b[0m';
|
|
1601
2153
|
const GRAY = '\x1b[90m';
|
|
1602
2154
|
const RED = '\x1b[31m';
|
|
@@ -1631,7 +2183,9 @@ const formatArg = (arg)=>{
|
|
|
1631
2183
|
if ('string' == typeof arg) return arg;
|
|
1632
2184
|
if ('object' == typeof arg && 'Error' === arg.__type) {
|
|
1633
2185
|
const err = arg;
|
|
1634
|
-
|
|
2186
|
+
const header = err.message ? `${err.name}: ${err.message}` : err.name;
|
|
2187
|
+
if (!err.stack) return header;
|
|
2188
|
+
return err.stack.startsWith(header) ? err.stack : `${header}\n${err.stack}`;
|
|
1635
2189
|
}
|
|
1636
2190
|
try {
|
|
1637
2191
|
return JSON.stringify(arg, null, 2);
|
|
@@ -1639,28 +2193,19 @@ const formatArg = (arg)=>{
|
|
|
1639
2193
|
return String(arg);
|
|
1640
2194
|
}
|
|
1641
2195
|
};
|
|
1642
|
-
|
|
1643
|
-
let logFilePath = '';
|
|
1644
|
-
const getLogFilePath = ()=>logFilePath;
|
|
1645
|
-
const ensureLogFile = ()=>{
|
|
1646
|
-
if (!logFile) {
|
|
1647
|
-
logFilePath = node_path.resolve(process.cwd(), '.dev-logs');
|
|
1648
|
-
logFile = node_fs.createWriteStream(logFilePath, {
|
|
1649
|
-
flags: 'w'
|
|
1650
|
-
});
|
|
1651
|
-
}
|
|
1652
|
-
return logFile;
|
|
1653
|
-
};
|
|
1654
|
-
const writeLog = (entry)=>{
|
|
1655
|
-
const stream = ensureLogFile();
|
|
2196
|
+
const writeLog = (stream, entry)=>{
|
|
1656
2197
|
const color = LEVEL_COLORS[entry.level] || WHITE;
|
|
1657
2198
|
const label = LEVEL_LABELS[entry.level] || entry.level.toUpperCase();
|
|
1658
2199
|
const time = formatTimestamp(entry.timestamp);
|
|
1659
2200
|
const args = entry.args.map(formatArg).join(' ');
|
|
1660
2201
|
stream.write(`${GRAY}${time}${RESET} ${color}${label}${RESET} ${args}\n`);
|
|
1661
2202
|
};
|
|
1662
|
-
const createDevLoggerMiddleware = ()=>
|
|
1663
|
-
|
|
2203
|
+
const createDevLoggerMiddleware = (logFilePath)=>{
|
|
2204
|
+
const logFile = node_fs.createWriteStream(logFilePath, {
|
|
2205
|
+
flags: 'w'
|
|
2206
|
+
});
|
|
2207
|
+
return (req, res, next)=>{
|
|
2208
|
+
if ('OPTIONS' === req.method && req.url === DEV_LOGS_PATH) {
|
|
1664
2209
|
res.writeHead(204, {
|
|
1665
2210
|
'Access-Control-Allow-Origin': '*',
|
|
1666
2211
|
'Access-Control-Allow-Methods': 'POST, OPTIONS',
|
|
@@ -1669,7 +2214,7 @@ const createDevLoggerMiddleware = ()=>(req, res, next)=>{
|
|
|
1669
2214
|
res.end();
|
|
1670
2215
|
return;
|
|
1671
2216
|
}
|
|
1672
|
-
if ('POST' !== req.method ||
|
|
2217
|
+
if ('POST' !== req.method || req.url !== DEV_LOGS_PATH) return void next();
|
|
1673
2218
|
let body = '';
|
|
1674
2219
|
req.on('data', (chunk)=>{
|
|
1675
2220
|
body += chunk.toString();
|
|
@@ -1681,22 +2226,21 @@ const createDevLoggerMiddleware = ()=>(req, res, next)=>{
|
|
|
1681
2226
|
res.end();
|
|
1682
2227
|
try {
|
|
1683
2228
|
const { logs } = JSON.parse(body);
|
|
1684
|
-
for (const entry of logs)writeLog(entry);
|
|
2229
|
+
for (const entry of logs)writeLog(logFile, entry);
|
|
1685
2230
|
} catch {}
|
|
1686
2231
|
});
|
|
1687
2232
|
};
|
|
1688
|
-
|
|
2233
|
+
};
|
|
2234
|
+
const FALLBACK_ORIGIN = 'http://localhost:3000';
|
|
1689
2235
|
const applyDevLogger = (api)=>{
|
|
1690
2236
|
api.modifyRspackConfig((rspackConfig)=>{
|
|
1691
2237
|
if ('development' !== rspackConfig.mode) return rspackConfig;
|
|
1692
2238
|
const publicPath = rspackConfig.output?.publicPath;
|
|
1693
|
-
let
|
|
2239
|
+
let origin = FALLBACK_ORIGIN;
|
|
1694
2240
|
if ('string' == typeof publicPath && publicPath.startsWith('http')) try {
|
|
1695
|
-
|
|
1696
|
-
const logPort = Number(parsed.port || 80) + LOG_PORT_OFFSET;
|
|
1697
|
-
logUrl = `${parsed.protocol}//${parsed.hostname}:${logPort}/__dev_logs`;
|
|
2241
|
+
origin = new URL(publicPath).origin;
|
|
1698
2242
|
} catch {}
|
|
1699
|
-
|
|
2243
|
+
const logUrl = `${origin}${DEV_LOGS_PATH}`;
|
|
1700
2244
|
rspackConfig.plugins = rspackConfig.plugins || [];
|
|
1701
2245
|
rspackConfig.plugins.push({
|
|
1702
2246
|
name: 'lynx:angular:dev-logger-define',
|
|
@@ -1709,22 +2253,12 @@ const applyDevLogger = (api)=>{
|
|
|
1709
2253
|
});
|
|
1710
2254
|
return rspackConfig;
|
|
1711
2255
|
});
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
res.end();
|
|
1719
|
-
});
|
|
1720
|
-
});
|
|
1721
|
-
server.listen(logPort, '0.0.0.0', ()=>{
|
|
1722
|
-
console.log(`[dev-logger] Log server on :${logPort} → tail -f ${getLogFilePath()}`);
|
|
1723
|
-
});
|
|
1724
|
-
server.on('error', (err)=>{
|
|
1725
|
-
if ('EADDRINUSE' === err.code) server.listen(logPort + 1, '0.0.0.0');
|
|
1726
|
-
else console.warn('[dev-logger] Failed to start log server:', err.message);
|
|
1727
|
-
});
|
|
2256
|
+
const logFilePath = node_path.resolve(process.cwd(), '.dev-logs');
|
|
2257
|
+
api.onBeforeStartDevServer(({ server })=>{
|
|
2258
|
+
server.middlewares.use(createDevLoggerMiddleware(logFilePath));
|
|
2259
|
+
});
|
|
2260
|
+
api.onAfterStartDevServer(()=>{
|
|
2261
|
+
console.log(`[dev-logger] LynxLogger output: tail -f ${logFilePath}`);
|
|
1728
2262
|
});
|
|
1729
2263
|
};
|
|
1730
2264
|
const applySplitChunksRule = (api, options)=>{
|
|
@@ -1754,22 +2288,1869 @@ const applySplitChunksRule = (api, options)=>{
|
|
|
1754
2288
|
return rspackConfig;
|
|
1755
2289
|
});
|
|
1756
2290
|
};
|
|
2291
|
+
const foldCalc = (value)=>{
|
|
2292
|
+
if (!value.includes('calc(')) return value;
|
|
2293
|
+
const parsed = postcss_value_parser(value);
|
|
2294
|
+
foldNodes(parsed.nodes);
|
|
2295
|
+
return parsed.toString();
|
|
2296
|
+
};
|
|
2297
|
+
const foldNodes = (nodes)=>{
|
|
2298
|
+
for (const node of nodes){
|
|
2299
|
+
if ('function' !== node.type) continue;
|
|
2300
|
+
const folded = 'calc' === node.value.toLowerCase() ? evaluate(node.nodes) : void 0;
|
|
2301
|
+
if (folded) Object.assign(node, {
|
|
2302
|
+
type: 'word',
|
|
2303
|
+
value: formatDimension(folded)
|
|
2304
|
+
});
|
|
2305
|
+
else foldNodes(node.nodes);
|
|
2306
|
+
}
|
|
2307
|
+
};
|
|
2308
|
+
const INFINITY_VALUE = 9999;
|
|
2309
|
+
const formatDimension = ({ value, unit })=>`${Number(value.toFixed(6))}${unit}`;
|
|
2310
|
+
const evaluate = (nodes)=>{
|
|
2311
|
+
const tokens = tokenize(nodes);
|
|
2312
|
+
if (!tokens) return;
|
|
2313
|
+
let position = 0;
|
|
2314
|
+
const peek = ()=>tokens[position];
|
|
2315
|
+
const factor = ()=>{
|
|
2316
|
+
const token = tokens[position++];
|
|
2317
|
+
return 'object' == typeof token ? token : void 0;
|
|
2318
|
+
};
|
|
2319
|
+
const term = ()=>{
|
|
2320
|
+
let left = factor();
|
|
2321
|
+
while(left && ('*' === peek() || '/' === peek())){
|
|
2322
|
+
const operator = tokens[position++];
|
|
2323
|
+
const right = factor();
|
|
2324
|
+
left = right && ('*' === operator ? multiply(left, right) : divide(left, right));
|
|
2325
|
+
}
|
|
2326
|
+
return left;
|
|
2327
|
+
};
|
|
2328
|
+
const expression = ()=>{
|
|
2329
|
+
let left = term();
|
|
2330
|
+
while(left && ('+' === peek() || '-' === peek())){
|
|
2331
|
+
const operator = tokens[position++];
|
|
2332
|
+
const right = term();
|
|
2333
|
+
left = right && add(left, '-' === operator ? negate(right) : right);
|
|
2334
|
+
}
|
|
2335
|
+
return left;
|
|
2336
|
+
};
|
|
2337
|
+
const result = expression();
|
|
2338
|
+
return position === tokens.length ? result : void 0;
|
|
2339
|
+
};
|
|
2340
|
+
const tokenize = (nodes)=>{
|
|
2341
|
+
const tokens = [];
|
|
2342
|
+
for (const node of nodes){
|
|
2343
|
+
if ('space' === node.type || 'comment' === node.type) continue;
|
|
2344
|
+
if ('function' === node.type) {
|
|
2345
|
+
const name = node.value.toLowerCase();
|
|
2346
|
+
const group = 'calc' === name || '' === name ? evaluate(node.nodes) : void 0;
|
|
2347
|
+
if (!group) return;
|
|
2348
|
+
tokens.push(group);
|
|
2349
|
+
continue;
|
|
2350
|
+
}
|
|
2351
|
+
if ('word' !== node.type) return;
|
|
2352
|
+
if ([
|
|
2353
|
+
'+',
|
|
2354
|
+
'-',
|
|
2355
|
+
'*',
|
|
2356
|
+
'/'
|
|
2357
|
+
].includes(node.value)) {
|
|
2358
|
+
tokens.push(node.value);
|
|
2359
|
+
continue;
|
|
2360
|
+
}
|
|
2361
|
+
if (/^-?infinity$/i.test(node.value)) {
|
|
2362
|
+
tokens.push({
|
|
2363
|
+
value: node.value.startsWith('-') ? -INFINITY_VALUE : INFINITY_VALUE,
|
|
2364
|
+
unit: ''
|
|
2365
|
+
});
|
|
2366
|
+
continue;
|
|
2367
|
+
}
|
|
2368
|
+
const unit = postcss_value_parser.unit(node.value);
|
|
2369
|
+
if (!unit) return;
|
|
2370
|
+
tokens.push({
|
|
2371
|
+
value: Number(unit.number),
|
|
2372
|
+
unit: unit.unit.toLowerCase()
|
|
2373
|
+
});
|
|
2374
|
+
}
|
|
2375
|
+
return tokens;
|
|
2376
|
+
};
|
|
2377
|
+
const negate = ({ value, unit })=>({
|
|
2378
|
+
value: -value,
|
|
2379
|
+
unit
|
|
2380
|
+
});
|
|
2381
|
+
const add = (a, b)=>a.unit === b.unit ? {
|
|
2382
|
+
value: a.value + b.value,
|
|
2383
|
+
unit: a.unit
|
|
2384
|
+
} : void 0;
|
|
2385
|
+
const multiply = (a, b)=>{
|
|
2386
|
+
if (a.unit && b.unit) return;
|
|
2387
|
+
return {
|
|
2388
|
+
value: a.value * b.value,
|
|
2389
|
+
unit: a.unit || b.unit
|
|
2390
|
+
};
|
|
2391
|
+
};
|
|
2392
|
+
const divide = (a, b)=>b.unit || 0 === b.value ? void 0 : {
|
|
2393
|
+
value: a.value / b.value,
|
|
2394
|
+
unit: a.unit
|
|
2395
|
+
};
|
|
2396
|
+
const clampHugeNumbers = (value)=>value.replace(/(-?)\d*\.?\d+e\+?(\d+)([a-z%]*)/gi, (match, sign, exponent, unit)=>Number(exponent) >= 7 ? `${sign}${INFINITY_VALUE}${unit}` : match);
|
|
2397
|
+
const COLOR_FUNCTIONS = new Set([
|
|
2398
|
+
'rgb',
|
|
2399
|
+
'rgba',
|
|
2400
|
+
'hsl',
|
|
2401
|
+
'hsla',
|
|
2402
|
+
'hwb',
|
|
2403
|
+
'lab',
|
|
2404
|
+
'lch',
|
|
2405
|
+
'oklab',
|
|
2406
|
+
'oklch',
|
|
2407
|
+
'color-mix'
|
|
2408
|
+
]);
|
|
2409
|
+
const LOWERED_FUNCTIONS = new Set([
|
|
2410
|
+
...COLOR_FUNCTIONS
|
|
2411
|
+
].filter((name)=>'rgb' !== name && 'rgba' !== name));
|
|
2412
|
+
const NAMED_COLORS = {
|
|
2413
|
+
aliceblue: 'f0f8ff',
|
|
2414
|
+
antiquewhite: 'faebd7',
|
|
2415
|
+
aqua: '00ffff',
|
|
2416
|
+
aquamarine: '7fffd4',
|
|
2417
|
+
azure: 'f0ffff',
|
|
2418
|
+
beige: 'f5f5dc',
|
|
2419
|
+
bisque: 'ffe4c4',
|
|
2420
|
+
black: '000000',
|
|
2421
|
+
blanchedalmond: 'ffebcd',
|
|
2422
|
+
blue: '0000ff',
|
|
2423
|
+
blueviolet: '8a2be2',
|
|
2424
|
+
brown: 'a52a2a',
|
|
2425
|
+
burlywood: 'deb887',
|
|
2426
|
+
cadetblue: '5f9ea0',
|
|
2427
|
+
chartreuse: '7fff00',
|
|
2428
|
+
chocolate: 'd2691e',
|
|
2429
|
+
coral: 'ff7f50',
|
|
2430
|
+
cornflowerblue: '6495ed',
|
|
2431
|
+
cornsilk: 'fff8dc',
|
|
2432
|
+
crimson: 'dc143c',
|
|
2433
|
+
cyan: '00ffff',
|
|
2434
|
+
darkblue: '00008b',
|
|
2435
|
+
darkcyan: '008b8b',
|
|
2436
|
+
darkgoldenrod: 'b8860b',
|
|
2437
|
+
darkgray: 'a9a9a9',
|
|
2438
|
+
darkgreen: '006400',
|
|
2439
|
+
darkgrey: 'a9a9a9',
|
|
2440
|
+
darkkhaki: 'bdb76b',
|
|
2441
|
+
darkmagenta: '8b008b',
|
|
2442
|
+
darkolivegreen: '556b2f',
|
|
2443
|
+
darkorange: 'ff8c00',
|
|
2444
|
+
darkorchid: '9932cc',
|
|
2445
|
+
darkred: '8b0000',
|
|
2446
|
+
darksalmon: 'e9967a',
|
|
2447
|
+
darkseagreen: '8fbc8f',
|
|
2448
|
+
darkslateblue: '483d8b',
|
|
2449
|
+
darkslategray: '2f4f4f',
|
|
2450
|
+
darkslategrey: '2f4f4f',
|
|
2451
|
+
darkturquoise: '00ced1',
|
|
2452
|
+
darkviolet: '9400d3',
|
|
2453
|
+
deeppink: 'ff1493',
|
|
2454
|
+
deepskyblue: '00bfff',
|
|
2455
|
+
dimgray: '696969',
|
|
2456
|
+
dimgrey: '696969',
|
|
2457
|
+
dodgerblue: '1e90ff',
|
|
2458
|
+
firebrick: 'b22222',
|
|
2459
|
+
floralwhite: 'fffaf0',
|
|
2460
|
+
forestgreen: '228b22',
|
|
2461
|
+
fuchsia: 'ff00ff',
|
|
2462
|
+
gainsboro: 'dcdcdc',
|
|
2463
|
+
ghostwhite: 'f8f8ff',
|
|
2464
|
+
gold: 'ffd700',
|
|
2465
|
+
goldenrod: 'daa520',
|
|
2466
|
+
gray: '808080',
|
|
2467
|
+
green: '008000',
|
|
2468
|
+
greenyellow: 'adff2f',
|
|
2469
|
+
grey: '808080',
|
|
2470
|
+
honeydew: 'f0fff0',
|
|
2471
|
+
hotpink: 'ff69b4',
|
|
2472
|
+
indianred: 'cd5c5c',
|
|
2473
|
+
indigo: '4b0082',
|
|
2474
|
+
ivory: 'fffff0',
|
|
2475
|
+
khaki: 'f0e68c',
|
|
2476
|
+
lavender: 'e6e6fa',
|
|
2477
|
+
lavenderblush: 'fff0f5',
|
|
2478
|
+
lawngreen: '7cfc00',
|
|
2479
|
+
lemonchiffon: 'fffacd',
|
|
2480
|
+
lightblue: 'add8e6',
|
|
2481
|
+
lightcoral: 'f08080',
|
|
2482
|
+
lightcyan: 'e0ffff',
|
|
2483
|
+
lightgoldenrodyellow: 'fafad2',
|
|
2484
|
+
lightgray: 'd3d3d3',
|
|
2485
|
+
lightgreen: '90ee90',
|
|
2486
|
+
lightgrey: 'd3d3d3',
|
|
2487
|
+
lightpink: 'ffb6c1',
|
|
2488
|
+
lightsalmon: 'ffa07a',
|
|
2489
|
+
lightseagreen: '20b2aa',
|
|
2490
|
+
lightskyblue: '87cefa',
|
|
2491
|
+
lightslategray: '778899',
|
|
2492
|
+
lightslategrey: '778899',
|
|
2493
|
+
lightsteelblue: 'b0c4de',
|
|
2494
|
+
lightyellow: 'ffffe0',
|
|
2495
|
+
lime: '00ff00',
|
|
2496
|
+
limegreen: '32cd32',
|
|
2497
|
+
linen: 'faf0e6',
|
|
2498
|
+
magenta: 'ff00ff',
|
|
2499
|
+
maroon: '800000',
|
|
2500
|
+
mediumaquamarine: '66cdaa',
|
|
2501
|
+
mediumblue: '0000cd',
|
|
2502
|
+
mediumorchid: 'ba55d3',
|
|
2503
|
+
mediumpurple: '9370db',
|
|
2504
|
+
mediumseagreen: '3cb371',
|
|
2505
|
+
mediumslateblue: '7b68ee',
|
|
2506
|
+
mediumspringgreen: '00fa9a',
|
|
2507
|
+
mediumturquoise: '48d1cc',
|
|
2508
|
+
mediumvioletred: 'c71585',
|
|
2509
|
+
midnightblue: '191970',
|
|
2510
|
+
mintcream: 'f5fffa',
|
|
2511
|
+
mistyrose: 'ffe4e1',
|
|
2512
|
+
moccasin: 'ffe4b5',
|
|
2513
|
+
navajowhite: 'ffdead',
|
|
2514
|
+
navy: '000080',
|
|
2515
|
+
oldlace: 'fdf5e6',
|
|
2516
|
+
olive: '808000',
|
|
2517
|
+
olivedrab: '6b8e23',
|
|
2518
|
+
orange: 'ffa500',
|
|
2519
|
+
orangered: 'ff4500',
|
|
2520
|
+
orchid: 'da70d6',
|
|
2521
|
+
palegoldenrod: 'eee8aa',
|
|
2522
|
+
palegreen: '98fb98',
|
|
2523
|
+
paleturquoise: 'afeeee',
|
|
2524
|
+
palevioletred: 'db7093',
|
|
2525
|
+
papayawhip: 'ffefd5',
|
|
2526
|
+
peachpuff: 'ffdab9',
|
|
2527
|
+
peru: 'cd853f',
|
|
2528
|
+
pink: 'ffc0cb',
|
|
2529
|
+
plum: 'dda0dd',
|
|
2530
|
+
powderblue: 'b0e0e6',
|
|
2531
|
+
purple: '800080',
|
|
2532
|
+
rebeccapurple: '663399',
|
|
2533
|
+
red: 'ff0000',
|
|
2534
|
+
rosybrown: 'bc8f8f',
|
|
2535
|
+
royalblue: '4169e1',
|
|
2536
|
+
saddlebrown: '8b4513',
|
|
2537
|
+
salmon: 'fa8072',
|
|
2538
|
+
sandybrown: 'f4a460',
|
|
2539
|
+
seagreen: '2e8b57',
|
|
2540
|
+
seashell: 'fff5ee',
|
|
2541
|
+
sienna: 'a0522d',
|
|
2542
|
+
silver: 'c0c0c0',
|
|
2543
|
+
skyblue: '87ceeb',
|
|
2544
|
+
slateblue: '6a5acd',
|
|
2545
|
+
slategray: '708090',
|
|
2546
|
+
slategrey: '708090',
|
|
2547
|
+
snow: 'fffafa',
|
|
2548
|
+
springgreen: '00ff7f',
|
|
2549
|
+
steelblue: '4682b4',
|
|
2550
|
+
tan: 'd2b48c',
|
|
2551
|
+
teal: '008080',
|
|
2552
|
+
thistle: 'd8bfd8',
|
|
2553
|
+
tomato: 'ff6347',
|
|
2554
|
+
turquoise: '40e0d0',
|
|
2555
|
+
violet: 'ee82ee',
|
|
2556
|
+
wheat: 'f5deb3',
|
|
2557
|
+
white: 'ffffff',
|
|
2558
|
+
whitesmoke: 'f5f5f5',
|
|
2559
|
+
yellow: 'ffff00',
|
|
2560
|
+
yellowgreen: '9acd32'
|
|
2561
|
+
};
|
|
2562
|
+
const lowerColors = (value, channelVariables = new Set())=>{
|
|
2563
|
+
if (![
|
|
2564
|
+
...LOWERED_FUNCTIONS
|
|
2565
|
+
].some((name)=>value.includes(`${name}(`))) return value;
|
|
2566
|
+
const parsed = postcss_value_parser(value);
|
|
2567
|
+
rewriteColorFunctions(parsed.nodes, channelVariables);
|
|
2568
|
+
return parsed.toString();
|
|
2569
|
+
};
|
|
2570
|
+
const rewriteColorFunctions = (nodes, channelVariables)=>{
|
|
2571
|
+
for (const node of nodes){
|
|
2572
|
+
if ('function' !== node.type) continue;
|
|
2573
|
+
const name = node.value.toLowerCase();
|
|
2574
|
+
const color = LOWERED_FUNCTIONS.has(name) ? parseColor(node) : void 0;
|
|
2575
|
+
if (color) {
|
|
2576
|
+
Object.assign(node, {
|
|
2577
|
+
type: 'word',
|
|
2578
|
+
value: formatRgb(color)
|
|
2579
|
+
});
|
|
2580
|
+
continue;
|
|
2581
|
+
}
|
|
2582
|
+
rewriteColorFunctions(node.nodes, channelVariables);
|
|
2583
|
+
const mixed = 'color-mix' === name ? mixWithChannels(node.nodes, channelVariables) : void 0;
|
|
2584
|
+
if (mixed) Object.assign(node, {
|
|
2585
|
+
type: 'word',
|
|
2586
|
+
value: mixed
|
|
2587
|
+
});
|
|
2588
|
+
}
|
|
2589
|
+
};
|
|
2590
|
+
const mixWithChannels = (nodes, channelVariables)=>{
|
|
2591
|
+
const parts = splitByComma(nodes);
|
|
2592
|
+
if (3 !== parts.length) return;
|
|
2593
|
+
const [, first, second] = parts;
|
|
2594
|
+
const variable = first.find((node)=>'function' === node.type && 'var' === node.value.toLowerCase());
|
|
2595
|
+
const name = variable?.nodes[0]?.value;
|
|
2596
|
+
const percentage = first.filter((node)=>node !== variable).map((node)=>postcss_value_parser.unit(node.value) || {
|
|
2597
|
+
number: '',
|
|
2598
|
+
unit: ''
|
|
2599
|
+
});
|
|
2600
|
+
const isTransparent = 1 === second.length && 'transparent' === second[0].value.toLowerCase();
|
|
2601
|
+
if (!name || !channelVariables.has(name) || 1 !== variable.nodes.length || !isTransparent || percentage.length > 1 || 1 === percentage.length && percentage[0]?.unit !== '%') return;
|
|
2602
|
+
const alpha = percentage[0] ? Number(percentage[0].number) / 100 : 0.5;
|
|
2603
|
+
return `rgba(var(${name}-rgb), ${Number(alpha.toFixed(4))})`;
|
|
2604
|
+
};
|
|
2605
|
+
const formatRgb = ({ r, g, b, alpha })=>{
|
|
2606
|
+
const channel = (value)=>Math.round(255 * clamp01(value));
|
|
2607
|
+
const channels = `${channel(r)}, ${channel(g)}, ${channel(b)}`;
|
|
2608
|
+
const a = Number(clamp01(alpha).toFixed(4));
|
|
2609
|
+
return 1 === a ? `rgb(${channels})` : `rgba(${channels}, ${a})`;
|
|
2610
|
+
};
|
|
2611
|
+
const clamp01 = (value)=>Math.min(1, Math.max(0, value));
|
|
2612
|
+
const parseColor = (node)=>{
|
|
2613
|
+
if ('word' === node.type) {
|
|
2614
|
+
const word = node.value.toLowerCase();
|
|
2615
|
+
if ('transparent' === word) return {
|
|
2616
|
+
r: 0,
|
|
2617
|
+
g: 0,
|
|
2618
|
+
b: 0,
|
|
2619
|
+
alpha: 0
|
|
2620
|
+
};
|
|
2621
|
+
const named = NAMED_COLORS[word];
|
|
2622
|
+
return parseHex('string' == typeof named ? `#${named}` : word);
|
|
2623
|
+
}
|
|
2624
|
+
if ('function' !== node.type) return;
|
|
2625
|
+
const name = node.value.toLowerCase();
|
|
2626
|
+
if (!COLOR_FUNCTIONS.has(name)) return;
|
|
2627
|
+
if ('color-mix' === name) return parseColorMix(node.nodes);
|
|
2628
|
+
const args = colorArguments(node.nodes);
|
|
2629
|
+
if (!args) return;
|
|
2630
|
+
const { channels, alpha } = args;
|
|
2631
|
+
switch(name){
|
|
2632
|
+
case 'rgb':
|
|
2633
|
+
case 'rgba':
|
|
2634
|
+
return withAlpha(rgbFromChannels(channels.map((c)=>colors_channel(c, 255))), alpha);
|
|
2635
|
+
case 'hsl':
|
|
2636
|
+
case 'hsla':
|
|
2637
|
+
return withAlpha(hslToRgb(angle(channels[0]), percent(channels[1]), percent(channels[2])), alpha);
|
|
2638
|
+
case 'hwb':
|
|
2639
|
+
return withAlpha(hwbToRgb(angle(channels[0]), percent(channels[1]), percent(channels[2])), alpha);
|
|
2640
|
+
case 'lab':
|
|
2641
|
+
return withAlpha(labToRgb([
|
|
2642
|
+
colors_channel(channels[0], 100),
|
|
2643
|
+
colors_channel(channels[1], 125),
|
|
2644
|
+
colors_channel(channels[2], 125)
|
|
2645
|
+
]), alpha);
|
|
2646
|
+
case 'lch':
|
|
2647
|
+
return withAlpha(labToRgb(polarToRectangular([
|
|
2648
|
+
colors_channel(channels[0], 100),
|
|
2649
|
+
colors_channel(channels[1], 150),
|
|
2650
|
+
angle(channels[2])
|
|
2651
|
+
])), alpha);
|
|
2652
|
+
case 'oklab':
|
|
2653
|
+
return withAlpha(oklabToRgb([
|
|
2654
|
+
colors_channel(channels[0], 1),
|
|
2655
|
+
colors_channel(channels[1], 0.4),
|
|
2656
|
+
colors_channel(channels[2], 0.4)
|
|
2657
|
+
]), alpha);
|
|
2658
|
+
default:
|
|
2659
|
+
return withAlpha(oklabToRgb(polarToRectangular([
|
|
2660
|
+
colors_channel(channels[0], 1),
|
|
2661
|
+
colors_channel(channels[1], 0.4),
|
|
2662
|
+
angle(channels[2])
|
|
2663
|
+
])), alpha);
|
|
2664
|
+
}
|
|
2665
|
+
};
|
|
2666
|
+
const rgbFromChannels = ([r, g, b])=>({
|
|
2667
|
+
r: r / 255,
|
|
2668
|
+
g: g / 255,
|
|
2669
|
+
b: b / 255,
|
|
2670
|
+
alpha: 1
|
|
2671
|
+
});
|
|
2672
|
+
const withAlpha = (color, alpha)=>({
|
|
2673
|
+
...color,
|
|
2674
|
+
alpha: void 0 === alpha ? 1 : colors_channel(alpha, 1)
|
|
2675
|
+
});
|
|
2676
|
+
const parseHex = (word)=>{
|
|
2677
|
+
const match = /^#([\da-f]{3,4}|[\da-f]{6}|[\da-f]{8})$/i.exec(word);
|
|
2678
|
+
if (!match) return;
|
|
2679
|
+
let hex = match[1];
|
|
2680
|
+
if (hex.length <= 4) hex = [
|
|
2681
|
+
...hex
|
|
2682
|
+
].map((digit)=>digit + digit).join('');
|
|
2683
|
+
const byte = (index)=>Number.parseInt(hex.slice(2 * index, 2 * index + 2), 16) / 255;
|
|
2684
|
+
return {
|
|
2685
|
+
r: byte(0),
|
|
2686
|
+
g: byte(1),
|
|
2687
|
+
b: byte(2),
|
|
2688
|
+
alpha: 8 === hex.length ? byte(3) : 1
|
|
2689
|
+
};
|
|
2690
|
+
};
|
|
2691
|
+
const colorArguments = (nodes)=>{
|
|
2692
|
+
const words = [];
|
|
2693
|
+
let alpha;
|
|
2694
|
+
let afterSlash = false;
|
|
2695
|
+
for (const node of nodes)if ('space' !== node.type && 'comment' !== node.type) {
|
|
2696
|
+
if ('div' === node.type) {
|
|
2697
|
+
afterSlash ||= '/' === node.value;
|
|
2698
|
+
continue;
|
|
2699
|
+
}
|
|
2700
|
+
if ('word' !== node.type) return;
|
|
2701
|
+
if (afterSlash) alpha = node.value;
|
|
2702
|
+
else words.push(node.value);
|
|
2703
|
+
}
|
|
2704
|
+
if (void 0 === alpha && 4 === words.length) alpha = words.pop();
|
|
2705
|
+
if (3 !== words.length || ![
|
|
2706
|
+
...words,
|
|
2707
|
+
...void 0 === alpha ? [] : [
|
|
2708
|
+
alpha
|
|
2709
|
+
]
|
|
2710
|
+
].every(isNumeric)) return;
|
|
2711
|
+
return {
|
|
2712
|
+
channels: words,
|
|
2713
|
+
alpha
|
|
2714
|
+
};
|
|
2715
|
+
};
|
|
2716
|
+
const isNumeric = (word)=>'none' === word.toLowerCase() || false !== postcss_value_parser.unit(word);
|
|
2717
|
+
const colors_channel = (word, full)=>{
|
|
2718
|
+
const { number, unit } = postcss_value_parser.unit(word) || {
|
|
2719
|
+
number: '0',
|
|
2720
|
+
unit: ''
|
|
2721
|
+
};
|
|
2722
|
+
return '%' === unit ? Number(number) / 100 * full : Number(number);
|
|
2723
|
+
};
|
|
2724
|
+
const percent = (word)=>colors_channel(word, 100) / 100;
|
|
2725
|
+
const angle = (word)=>{
|
|
2726
|
+
const { number, unit } = postcss_value_parser.unit(word) || {
|
|
2727
|
+
number: '0',
|
|
2728
|
+
unit: ''
|
|
2729
|
+
};
|
|
2730
|
+
const value = Number(number);
|
|
2731
|
+
switch(unit.toLowerCase()){
|
|
2732
|
+
case 'rad':
|
|
2733
|
+
return 180 * value / Math.PI;
|
|
2734
|
+
case 'grad':
|
|
2735
|
+
return 0.9 * value;
|
|
2736
|
+
case 'turn':
|
|
2737
|
+
return 360 * value;
|
|
2738
|
+
default:
|
|
2739
|
+
return value;
|
|
2740
|
+
}
|
|
2741
|
+
};
|
|
2742
|
+
const hslToRgb = (hue, saturation, lightness)=>{
|
|
2743
|
+
const h = (hue % 360 + 360) % 360;
|
|
2744
|
+
const f = (n)=>{
|
|
2745
|
+
const k = (n + h / 30) % 12;
|
|
2746
|
+
const a = saturation * Math.min(lightness, 1 - lightness);
|
|
2747
|
+
return lightness - a * Math.max(-1, Math.min(k - 3, 9 - k, 1));
|
|
2748
|
+
};
|
|
2749
|
+
return {
|
|
2750
|
+
r: f(0),
|
|
2751
|
+
g: f(8),
|
|
2752
|
+
b: f(4),
|
|
2753
|
+
alpha: 1
|
|
2754
|
+
};
|
|
2755
|
+
};
|
|
2756
|
+
const hwbToRgb = (hue, whiteness, blackness)=>{
|
|
2757
|
+
if (whiteness + blackness >= 1) {
|
|
2758
|
+
const gray = whiteness / (whiteness + blackness);
|
|
2759
|
+
return {
|
|
2760
|
+
r: gray,
|
|
2761
|
+
g: gray,
|
|
2762
|
+
b: gray,
|
|
2763
|
+
alpha: 1
|
|
2764
|
+
};
|
|
2765
|
+
}
|
|
2766
|
+
const { r, g, b } = hslToRgb(hue, 1, 0.5);
|
|
2767
|
+
const scale = (value)=>value * (1 - whiteness - blackness) + whiteness;
|
|
2768
|
+
return {
|
|
2769
|
+
r: scale(r),
|
|
2770
|
+
g: scale(g),
|
|
2771
|
+
b: scale(b),
|
|
2772
|
+
alpha: 1
|
|
2773
|
+
};
|
|
2774
|
+
};
|
|
2775
|
+
const polarToRectangular = ([lightness, chroma, hue])=>{
|
|
2776
|
+
const radians = hue * Math.PI / 180;
|
|
2777
|
+
return [
|
|
2778
|
+
lightness,
|
|
2779
|
+
chroma * Math.cos(radians),
|
|
2780
|
+
chroma * Math.sin(radians)
|
|
2781
|
+
];
|
|
2782
|
+
};
|
|
2783
|
+
const rectangularToPolar = ([lightness, a, b])=>{
|
|
2784
|
+
const hue = 180 * Math.atan2(b, a) / Math.PI;
|
|
2785
|
+
return [
|
|
2786
|
+
lightness,
|
|
2787
|
+
Math.hypot(a, b),
|
|
2788
|
+
(hue + 360) % 360
|
|
2789
|
+
];
|
|
2790
|
+
};
|
|
2791
|
+
const gammaEncode = (value)=>{
|
|
2792
|
+
const sign = value < 0 ? -1 : 1;
|
|
2793
|
+
const abs = Math.abs(value);
|
|
2794
|
+
return abs > 0.0031308 ? sign * (1.055 * abs ** (1 / 2.4) - 0.055) : 12.92 * value;
|
|
2795
|
+
};
|
|
2796
|
+
const gammaDecode = (value)=>{
|
|
2797
|
+
const sign = value < 0 ? -1 : 1;
|
|
2798
|
+
const abs = Math.abs(value);
|
|
2799
|
+
return abs > 0.04045 ? sign * ((abs + 0.055) / 1.055) ** 2.4 : value / 12.92;
|
|
2800
|
+
};
|
|
2801
|
+
const oklabToLinearRgb = ([l, a, b])=>{
|
|
2802
|
+
const lms = [
|
|
2803
|
+
(l + 0.3963377773761749 * a + 0.2158037573099136 * b) ** 3,
|
|
2804
|
+
(l - 0.1055613458156586 * a - 0.0638541728258133 * b) ** 3,
|
|
2805
|
+
(l - 0.0894841775298119 * a - 1.2914855480194092 * b) ** 3
|
|
2806
|
+
];
|
|
2807
|
+
return [
|
|
2808
|
+
4.0767416360759583 * lms[0] - 3.3077115392580629 * lms[1] + 0.2309699031821043 * lms[2],
|
|
2809
|
+
-1.2684379732850315 * lms[0] + 2.6097573492876882 * lms[1] - 0.341319376002657 * lms[2],
|
|
2810
|
+
-0.0041960761386756 * lms[0] - 0.7034186179359363 * lms[1] + 1.7076146940746117 * lms[2]
|
|
2811
|
+
];
|
|
2812
|
+
};
|
|
2813
|
+
const linearRgbToOklab = ([r, g, b])=>{
|
|
2814
|
+
const lms = [
|
|
2815
|
+
Math.cbrt(0.4122214694707629 * r + 0.5363325372617349 * g + 0.0514459932675022 * b),
|
|
2816
|
+
Math.cbrt(0.2119034958178251 * r + 0.6806995506452344 * g + 0.1073969535369406 * b),
|
|
2817
|
+
Math.cbrt(0.0883024591900564 * r + 0.2817188391361215 * g + 0.6299787016738223 * b)
|
|
2818
|
+
];
|
|
2819
|
+
return [
|
|
2820
|
+
0.2104542553 * lms[0] + 0.793617785 * lms[1] - 0.0040720468 * lms[2],
|
|
2821
|
+
1.9779984951 * lms[0] - 2.428592205 * lms[1] + 0.4505937099 * lms[2],
|
|
2822
|
+
0.0259040371 * lms[0] + 0.7827717662 * lms[1] - 0.808675766 * lms[2]
|
|
2823
|
+
];
|
|
2824
|
+
};
|
|
2825
|
+
const encodeRgb = ([r, g, b])=>({
|
|
2826
|
+
r: gammaEncode(r),
|
|
2827
|
+
g: gammaEncode(g),
|
|
2828
|
+
b: gammaEncode(b),
|
|
2829
|
+
alpha: 1
|
|
2830
|
+
});
|
|
2831
|
+
const rgbToOklab = ({ r, g, b })=>linearRgbToOklab([
|
|
2832
|
+
gammaDecode(r),
|
|
2833
|
+
gammaDecode(g),
|
|
2834
|
+
gammaDecode(b)
|
|
2835
|
+
]);
|
|
2836
|
+
const isInGamut = ({ r, g, b })=>[
|
|
2837
|
+
r,
|
|
2838
|
+
g,
|
|
2839
|
+
b
|
|
2840
|
+
].every((value)=>value >= -0.000001 && value <= 1 + 1e-6);
|
|
2841
|
+
const clip = ({ r, g, b, alpha })=>({
|
|
2842
|
+
r: clamp01(r),
|
|
2843
|
+
g: clamp01(g),
|
|
2844
|
+
b: clamp01(b),
|
|
2845
|
+
alpha
|
|
2846
|
+
});
|
|
2847
|
+
const oklabToRgb = (oklab)=>{
|
|
2848
|
+
const color = encodeRgb(oklabToLinearRgb(oklab));
|
|
2849
|
+
if (isInGamut(color)) return color;
|
|
2850
|
+
const [lightness, chroma, hue] = rectangularToPolar(oklab);
|
|
2851
|
+
if (lightness >= 1) return {
|
|
2852
|
+
r: 1,
|
|
2853
|
+
g: 1,
|
|
2854
|
+
b: 1,
|
|
2855
|
+
alpha: 1
|
|
2856
|
+
};
|
|
2857
|
+
if (lightness <= 0) return {
|
|
2858
|
+
r: 0,
|
|
2859
|
+
g: 0,
|
|
2860
|
+
b: 0,
|
|
2861
|
+
alpha: 1
|
|
2862
|
+
};
|
|
2863
|
+
const JND = 0.02;
|
|
2864
|
+
const EPSILON = 0.0001;
|
|
2865
|
+
const atChroma = (c)=>encodeRgb(oklabToLinearRgb(polarToRectangular([
|
|
2866
|
+
lightness,
|
|
2867
|
+
c,
|
|
2868
|
+
hue
|
|
2869
|
+
])));
|
|
2870
|
+
const deltaE = (a, b)=>Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2]);
|
|
2871
|
+
let clipped = clip(color);
|
|
2872
|
+
if (deltaE(rgbToOklab(clipped), oklab) < JND) return clipped;
|
|
2873
|
+
let min = 0;
|
|
2874
|
+
let max = chroma;
|
|
2875
|
+
let minInGamut = true;
|
|
2876
|
+
while(max - min > EPSILON){
|
|
2877
|
+
const c = (min + max) / 2;
|
|
2878
|
+
const current = atChroma(c);
|
|
2879
|
+
if (minInGamut && isInGamut(current)) {
|
|
2880
|
+
min = c;
|
|
2881
|
+
continue;
|
|
2882
|
+
}
|
|
2883
|
+
clipped = clip(current);
|
|
2884
|
+
const e = deltaE(rgbToOklab(clipped), polarToRectangular([
|
|
2885
|
+
lightness,
|
|
2886
|
+
c,
|
|
2887
|
+
hue
|
|
2888
|
+
]));
|
|
2889
|
+
if (e < JND) {
|
|
2890
|
+
if (JND - e < EPSILON) break;
|
|
2891
|
+
minInGamut = false;
|
|
2892
|
+
min = c;
|
|
2893
|
+
} else max = c;
|
|
2894
|
+
}
|
|
2895
|
+
return clipped;
|
|
2896
|
+
};
|
|
2897
|
+
const labToRgb = ([l, a, b])=>{
|
|
2898
|
+
const k = 24389 / 27;
|
|
2899
|
+
const e = 216 / 24389;
|
|
2900
|
+
const fy = (l + 16) / 116;
|
|
2901
|
+
const fx = a / 500 + fy;
|
|
2902
|
+
const fz = fy - b / 200;
|
|
2903
|
+
const xyz = [
|
|
2904
|
+
(fx ** 3 > e ? fx ** 3 : (116 * fx - 16) / k) * 0.3457 / 0.3585,
|
|
2905
|
+
l > k * e ? fy ** 3 : l / k,
|
|
2906
|
+
(fz ** 3 > e ? fz ** 3 : (116 * fz - 16) / k) * 0.2958 / 0.3585
|
|
2907
|
+
];
|
|
2908
|
+
const d65 = [
|
|
2909
|
+
0.955473421488075 * xyz[0] - 0.02309845494876471 * xyz[1] + 0.06325924320057072 * xyz[2],
|
|
2910
|
+
-0.0283697093338637 * xyz[0] + 1.0099953980813041 * xyz[1] + 0.021041441191917323 * xyz[2],
|
|
2911
|
+
0.012314014864481998 * xyz[0] - 0.020507649298898964 * xyz[1] + 1.330365926242124 * xyz[2]
|
|
2912
|
+
];
|
|
2913
|
+
const linear = [
|
|
2914
|
+
3.2409699419045226 * d65[0] - 1.537383177570094 * d65[1] - 0.4986107602930034 * d65[2],
|
|
2915
|
+
-0.9692436362808796 * d65[0] + 1.8759675015077202 * d65[1] + 0.04155505740717559 * d65[2],
|
|
2916
|
+
0.05563007969699366 * d65[0] - 0.20397695888897652 * d65[1] + 1.0569715142428786 * d65[2]
|
|
2917
|
+
];
|
|
2918
|
+
const color = encodeRgb(linear);
|
|
2919
|
+
return isInGamut(color) ? color : oklabToRgb(linearRgbToOklab(linear));
|
|
2920
|
+
};
|
|
2921
|
+
const parseColorMix = (nodes)=>{
|
|
2922
|
+
const parts = splitByComma(nodes);
|
|
2923
|
+
if (3 !== parts.length) return;
|
|
2924
|
+
const space = mixSpace(parts[0]);
|
|
2925
|
+
const first = mixColor(parts[1]);
|
|
2926
|
+
const second = mixColor(parts[2]);
|
|
2927
|
+
if (!space || !first || !second) return;
|
|
2928
|
+
let p1 = first.percentage;
|
|
2929
|
+
let p2 = second.percentage;
|
|
2930
|
+
if (void 0 === p1 && void 0 === p2) p1 = p2 = 50;
|
|
2931
|
+
else if (void 0 === p1) p1 = 100 - p2;
|
|
2932
|
+
else if (void 0 === p2) p2 = 100 - p1;
|
|
2933
|
+
const sum = p1 + p2;
|
|
2934
|
+
if (sum <= 0) return;
|
|
2935
|
+
const mixed = interpolate(space, first.color, second.color, p2 / sum);
|
|
2936
|
+
return {
|
|
2937
|
+
...mixed,
|
|
2938
|
+
alpha: mixed.alpha * Math.min(sum, 100) / 100
|
|
2939
|
+
};
|
|
2940
|
+
};
|
|
2941
|
+
const splitByComma = (nodes)=>{
|
|
2942
|
+
const parts = [
|
|
2943
|
+
[]
|
|
2944
|
+
];
|
|
2945
|
+
for (const node of nodes)if ('div' === node.type && ',' === node.value) parts.push([]);
|
|
2946
|
+
else if ('space' !== node.type && 'comment' !== node.type) parts[parts.length - 1].push(node);
|
|
2947
|
+
return parts;
|
|
2948
|
+
};
|
|
2949
|
+
const MIX_SPACES = new Set([
|
|
2950
|
+
'srgb',
|
|
2951
|
+
'srgb-linear',
|
|
2952
|
+
'oklab',
|
|
2953
|
+
'oklch'
|
|
2954
|
+
]);
|
|
2955
|
+
const mixSpace = (nodes)=>{
|
|
2956
|
+
const words = nodes.map((node)=>node.value.toLowerCase());
|
|
2957
|
+
const [keyword, space, ...hue] = words;
|
|
2958
|
+
const defaultHue = 0 === hue.length || 'shorter' === hue[0] && 'hue' === hue[1];
|
|
2959
|
+
return 'in' === keyword && MIX_SPACES.has(space) && defaultHue ? space : void 0;
|
|
2960
|
+
};
|
|
2961
|
+
const mixColor = (nodes)=>{
|
|
2962
|
+
let color;
|
|
2963
|
+
let percentage;
|
|
2964
|
+
for (const node of nodes){
|
|
2965
|
+
const unit = 'word' === node.type && postcss_value_parser.unit(node.value);
|
|
2966
|
+
if (unit && '%' === unit.unit && void 0 === percentage) percentage = Number(unit.number);
|
|
2967
|
+
else {
|
|
2968
|
+
if (color) return;
|
|
2969
|
+
color = parseColor(node);
|
|
2970
|
+
if (!color) return;
|
|
2971
|
+
}
|
|
2972
|
+
}
|
|
2973
|
+
return color && {
|
|
2974
|
+
color,
|
|
2975
|
+
percentage
|
|
2976
|
+
};
|
|
2977
|
+
};
|
|
2978
|
+
const interpolate = (space, from, to, weight)=>{
|
|
2979
|
+
const alpha = from.alpha * (1 - weight) + to.alpha * weight;
|
|
2980
|
+
if (0 === alpha) return {
|
|
2981
|
+
r: 0,
|
|
2982
|
+
g: 0,
|
|
2983
|
+
b: 0,
|
|
2984
|
+
alpha: 0
|
|
2985
|
+
};
|
|
2986
|
+
const blend = (a, b)=>(a * from.alpha * (1 - weight) + b * to.alpha * weight) / alpha;
|
|
2987
|
+
switch(space){
|
|
2988
|
+
case 'srgb':
|
|
2989
|
+
return {
|
|
2990
|
+
r: blend(from.r, to.r),
|
|
2991
|
+
g: blend(from.g, to.g),
|
|
2992
|
+
b: blend(from.b, to.b),
|
|
2993
|
+
alpha
|
|
2994
|
+
};
|
|
2995
|
+
case 'srgb-linear':
|
|
2996
|
+
return {
|
|
2997
|
+
...encodeRgb([
|
|
2998
|
+
blend(gammaDecode(from.r), gammaDecode(to.r)),
|
|
2999
|
+
blend(gammaDecode(from.g), gammaDecode(to.g)),
|
|
3000
|
+
blend(gammaDecode(from.b), gammaDecode(to.b))
|
|
3001
|
+
]),
|
|
3002
|
+
alpha
|
|
3003
|
+
};
|
|
3004
|
+
case 'oklab':
|
|
3005
|
+
{
|
|
3006
|
+
const a = rgbToOklab(from);
|
|
3007
|
+
const b = rgbToOklab(to);
|
|
3008
|
+
return {
|
|
3009
|
+
...oklabToRgb([
|
|
3010
|
+
blend(a[0], b[0]),
|
|
3011
|
+
blend(a[1], b[1]),
|
|
3012
|
+
blend(a[2], b[2])
|
|
3013
|
+
]),
|
|
3014
|
+
alpha
|
|
3015
|
+
};
|
|
3016
|
+
}
|
|
3017
|
+
default:
|
|
3018
|
+
{
|
|
3019
|
+
const a = rectangularToPolar(rgbToOklab(from));
|
|
3020
|
+
const b = rectangularToPolar(rgbToOklab(to));
|
|
3021
|
+
const powerless = (color, source)=>color[1] < 1e-4 || 0 === source.alpha;
|
|
3022
|
+
const hueA = powerless(a, from) ? b[2] : a[2];
|
|
3023
|
+
const hueB = powerless(b, to) ? a[2] : b[2];
|
|
3024
|
+
let delta = hueB - hueA;
|
|
3025
|
+
if (delta > 180) delta -= 360;
|
|
3026
|
+
else if (delta < -180) delta += 360;
|
|
3027
|
+
const hue = hueA + delta * weight;
|
|
3028
|
+
return {
|
|
3029
|
+
...oklabToRgb(polarToRectangular([
|
|
3030
|
+
blend(a[0], b[0]),
|
|
3031
|
+
blend(a[1], b[1]),
|
|
3032
|
+
hue
|
|
3033
|
+
])),
|
|
3034
|
+
alpha
|
|
3035
|
+
};
|
|
3036
|
+
}
|
|
3037
|
+
}
|
|
3038
|
+
};
|
|
3039
|
+
const LYNX_PROPERTIES = new Set([
|
|
3040
|
+
'-x-animation-color-interpolation',
|
|
3041
|
+
'-x-app-region',
|
|
3042
|
+
'-x-auto-font-size',
|
|
3043
|
+
'-x-auto-font-size-line-ranges',
|
|
3044
|
+
'-x-auto-font-size-preset-sizes',
|
|
3045
|
+
'-x-box-match-parent-size',
|
|
3046
|
+
'-x-box-propagate-min-constraints',
|
|
3047
|
+
'-x-caret-gradient',
|
|
3048
|
+
'-x-caret-height',
|
|
3049
|
+
'-x-caret-radius',
|
|
3050
|
+
'-x-caret-width',
|
|
3051
|
+
'-x-handle-color',
|
|
3052
|
+
'-x-handle-size',
|
|
3053
|
+
'-x-placeholder-color',
|
|
3054
|
+
'-x-placeholder-font-family',
|
|
3055
|
+
'-x-placeholder-font-size',
|
|
3056
|
+
'-x-placeholder-font-style',
|
|
3057
|
+
'-x-placeholder-font-weight',
|
|
3058
|
+
'-x-text-decoration-gap',
|
|
3059
|
+
'-x-text-decoration-width',
|
|
3060
|
+
'adapt-font-size',
|
|
3061
|
+
'align-content',
|
|
3062
|
+
'align-items',
|
|
3063
|
+
'align-self',
|
|
3064
|
+
'animation',
|
|
3065
|
+
'animation-delay',
|
|
3066
|
+
'animation-direction',
|
|
3067
|
+
'animation-duration',
|
|
3068
|
+
'animation-fill-mode',
|
|
3069
|
+
'animation-iteration-count',
|
|
3070
|
+
'animation-name',
|
|
3071
|
+
'animation-play-state',
|
|
3072
|
+
'animation-timing-function',
|
|
3073
|
+
'aspect-ratio',
|
|
3074
|
+
'background',
|
|
3075
|
+
'background-clip',
|
|
3076
|
+
'background-color',
|
|
3077
|
+
'background-image',
|
|
3078
|
+
'background-origin',
|
|
3079
|
+
'background-position',
|
|
3080
|
+
'background-repeat',
|
|
3081
|
+
'background-size',
|
|
3082
|
+
'border',
|
|
3083
|
+
'border-bottom',
|
|
3084
|
+
'border-bottom-color',
|
|
3085
|
+
'border-bottom-left-radius',
|
|
3086
|
+
'border-bottom-right-radius',
|
|
3087
|
+
'border-bottom-style',
|
|
3088
|
+
'border-bottom-width',
|
|
3089
|
+
'border-color',
|
|
3090
|
+
'border-end-end-radius',
|
|
3091
|
+
'border-end-start-radius',
|
|
3092
|
+
'border-inline-end-color',
|
|
3093
|
+
'border-inline-end-style',
|
|
3094
|
+
'border-inline-end-width',
|
|
3095
|
+
'border-inline-start-color',
|
|
3096
|
+
'border-inline-start-style',
|
|
3097
|
+
'border-inline-start-width',
|
|
3098
|
+
'border-left',
|
|
3099
|
+
'border-left-color',
|
|
3100
|
+
'border-left-style',
|
|
3101
|
+
'border-left-width',
|
|
3102
|
+
'border-radius',
|
|
3103
|
+
'border-right',
|
|
3104
|
+
'border-right-color',
|
|
3105
|
+
'border-right-style',
|
|
3106
|
+
'border-right-width',
|
|
3107
|
+
'border-start-end-radius',
|
|
3108
|
+
'border-start-start-radius',
|
|
3109
|
+
'border-style',
|
|
3110
|
+
'border-top',
|
|
3111
|
+
'border-top-color',
|
|
3112
|
+
'border-top-left-radius',
|
|
3113
|
+
'border-top-right-radius',
|
|
3114
|
+
'border-top-style',
|
|
3115
|
+
'border-top-width',
|
|
3116
|
+
'border-width',
|
|
3117
|
+
'bottom',
|
|
3118
|
+
'box-shadow',
|
|
3119
|
+
'box-sizing',
|
|
3120
|
+
'caret-color',
|
|
3121
|
+
'clip-path',
|
|
3122
|
+
'color',
|
|
3123
|
+
'column-gap',
|
|
3124
|
+
'content',
|
|
3125
|
+
'cursor',
|
|
3126
|
+
'direction',
|
|
3127
|
+
'display',
|
|
3128
|
+
'enter-transition-name',
|
|
3129
|
+
'exit-transition-name',
|
|
3130
|
+
'filter',
|
|
3131
|
+
'flex',
|
|
3132
|
+
'flex-basis',
|
|
3133
|
+
'flex-direction',
|
|
3134
|
+
'flex-flow',
|
|
3135
|
+
'flex-grow',
|
|
3136
|
+
'flex-shrink',
|
|
3137
|
+
'flex-wrap',
|
|
3138
|
+
'font-family',
|
|
3139
|
+
'font-feature-settings',
|
|
3140
|
+
'font-optical-sizing',
|
|
3141
|
+
'font-size',
|
|
3142
|
+
'font-style',
|
|
3143
|
+
'font-variation-settings',
|
|
3144
|
+
'font-weight',
|
|
3145
|
+
'gap',
|
|
3146
|
+
'grid-auto-columns',
|
|
3147
|
+
'grid-auto-flow',
|
|
3148
|
+
'grid-auto-rows',
|
|
3149
|
+
'grid-column',
|
|
3150
|
+
'grid-column-end',
|
|
3151
|
+
'grid-column-gap',
|
|
3152
|
+
'grid-column-span',
|
|
3153
|
+
'grid-column-start',
|
|
3154
|
+
'grid-row',
|
|
3155
|
+
'grid-row-end',
|
|
3156
|
+
'grid-row-gap',
|
|
3157
|
+
'grid-row-span',
|
|
3158
|
+
'grid-row-start',
|
|
3159
|
+
'grid-template-columns',
|
|
3160
|
+
'grid-template-rows',
|
|
3161
|
+
'height',
|
|
3162
|
+
'hyphens',
|
|
3163
|
+
'image-rendering',
|
|
3164
|
+
'implicit-animation',
|
|
3165
|
+
'inset-inline-end',
|
|
3166
|
+
'inset-inline-start',
|
|
3167
|
+
'justify-content',
|
|
3168
|
+
'justify-items',
|
|
3169
|
+
'justify-self',
|
|
3170
|
+
'layout-animation-create-delay',
|
|
3171
|
+
'layout-animation-create-duration',
|
|
3172
|
+
'layout-animation-create-property',
|
|
3173
|
+
'layout-animation-create-timing-function',
|
|
3174
|
+
'layout-animation-delete-delay',
|
|
3175
|
+
'layout-animation-delete-duration',
|
|
3176
|
+
'layout-animation-delete-property',
|
|
3177
|
+
'layout-animation-delete-timing-function',
|
|
3178
|
+
'layout-animation-update-delay',
|
|
3179
|
+
'layout-animation-update-duration',
|
|
3180
|
+
'layout-animation-update-timing-function',
|
|
3181
|
+
'left',
|
|
3182
|
+
'letter-spacing',
|
|
3183
|
+
'line-height',
|
|
3184
|
+
'line-spacing',
|
|
3185
|
+
'linear-cross-gravity',
|
|
3186
|
+
'linear-direction',
|
|
3187
|
+
'linear-gravity',
|
|
3188
|
+
'linear-layout-gravity',
|
|
3189
|
+
'linear-orientation',
|
|
3190
|
+
'linear-weight',
|
|
3191
|
+
'linear-weight-sum',
|
|
3192
|
+
'list-cross-axis-gap',
|
|
3193
|
+
'list-main-axis-gap',
|
|
3194
|
+
'margin',
|
|
3195
|
+
'margin-bottom',
|
|
3196
|
+
'margin-inline-end',
|
|
3197
|
+
'margin-inline-start',
|
|
3198
|
+
'margin-left',
|
|
3199
|
+
'margin-right',
|
|
3200
|
+
'margin-top',
|
|
3201
|
+
'mask',
|
|
3202
|
+
'mask-clip',
|
|
3203
|
+
'mask-composite',
|
|
3204
|
+
'mask-image',
|
|
3205
|
+
'mask-origin',
|
|
3206
|
+
'mask-position',
|
|
3207
|
+
'mask-repeat',
|
|
3208
|
+
'mask-size',
|
|
3209
|
+
'max-height',
|
|
3210
|
+
'max-width',
|
|
3211
|
+
'min-height',
|
|
3212
|
+
'min-width',
|
|
3213
|
+
'offset-distance',
|
|
3214
|
+
'offset-path',
|
|
3215
|
+
'offset-rotate',
|
|
3216
|
+
'opacity',
|
|
3217
|
+
'order',
|
|
3218
|
+
'outline',
|
|
3219
|
+
'outline-color',
|
|
3220
|
+
'outline-style',
|
|
3221
|
+
'outline-width',
|
|
3222
|
+
'overflow',
|
|
3223
|
+
'overflow-x',
|
|
3224
|
+
'overflow-y',
|
|
3225
|
+
'padding',
|
|
3226
|
+
'padding-bottom',
|
|
3227
|
+
'padding-inline-end',
|
|
3228
|
+
'padding-inline-start',
|
|
3229
|
+
'padding-left',
|
|
3230
|
+
'padding-right',
|
|
3231
|
+
'padding-top',
|
|
3232
|
+
'pause-transition-name',
|
|
3233
|
+
'perspective',
|
|
3234
|
+
'pointer-events',
|
|
3235
|
+
'position',
|
|
3236
|
+
'relative-align-bottom',
|
|
3237
|
+
'relative-align-inline-end',
|
|
3238
|
+
'relative-align-inline-start',
|
|
3239
|
+
'relative-align-left',
|
|
3240
|
+
'relative-align-right',
|
|
3241
|
+
'relative-align-top',
|
|
3242
|
+
'relative-bottom-of',
|
|
3243
|
+
'relative-center',
|
|
3244
|
+
'relative-id',
|
|
3245
|
+
'relative-inline-end-of',
|
|
3246
|
+
'relative-inline-start-of',
|
|
3247
|
+
'relative-layout-once',
|
|
3248
|
+
'relative-left-of',
|
|
3249
|
+
'relative-right-of',
|
|
3250
|
+
'relative-top-of',
|
|
3251
|
+
'resume-transition-name',
|
|
3252
|
+
'right',
|
|
3253
|
+
'row-gap',
|
|
3254
|
+
'text-align',
|
|
3255
|
+
'text-decoration',
|
|
3256
|
+
'text-decoration-color',
|
|
3257
|
+
'text-decoration-thickness',
|
|
3258
|
+
'text-indent',
|
|
3259
|
+
'text-overflow',
|
|
3260
|
+
'text-shadow',
|
|
3261
|
+
'text-stroke',
|
|
3262
|
+
'text-stroke-color',
|
|
3263
|
+
'text-stroke-width',
|
|
3264
|
+
'top',
|
|
3265
|
+
'transform',
|
|
3266
|
+
'transform-origin',
|
|
3267
|
+
'transition',
|
|
3268
|
+
'transition-delay',
|
|
3269
|
+
'transition-duration',
|
|
3270
|
+
'transition-property',
|
|
3271
|
+
'transition-timing-function',
|
|
3272
|
+
'vertical-align',
|
|
3273
|
+
'visibility',
|
|
3274
|
+
'white-space',
|
|
3275
|
+
'width',
|
|
3276
|
+
'word-break',
|
|
3277
|
+
'z-index'
|
|
3278
|
+
]);
|
|
3279
|
+
const LYNX_KEYWORDS = new Map(Object.entries({
|
|
3280
|
+
'-x-animation-color-interpolation': [
|
|
3281
|
+
'auto',
|
|
3282
|
+
'srgb',
|
|
3283
|
+
'linearrgb'
|
|
3284
|
+
],
|
|
3285
|
+
'-x-app-region': [
|
|
3286
|
+
'none',
|
|
3287
|
+
'drag',
|
|
3288
|
+
'no-drag'
|
|
3289
|
+
],
|
|
3290
|
+
'-x-placeholder-font-style': [
|
|
3291
|
+
'normal',
|
|
3292
|
+
'italic',
|
|
3293
|
+
'oblique'
|
|
3294
|
+
],
|
|
3295
|
+
'-x-placeholder-font-weight': [
|
|
3296
|
+
'normal',
|
|
3297
|
+
'bold',
|
|
3298
|
+
'100',
|
|
3299
|
+
'200',
|
|
3300
|
+
'300',
|
|
3301
|
+
'400',
|
|
3302
|
+
'500',
|
|
3303
|
+
'600',
|
|
3304
|
+
'700',
|
|
3305
|
+
'800',
|
|
3306
|
+
'900'
|
|
3307
|
+
],
|
|
3308
|
+
'align-content': [
|
|
3309
|
+
'flex-start',
|
|
3310
|
+
'flex-end',
|
|
3311
|
+
'center',
|
|
3312
|
+
'stretch',
|
|
3313
|
+
'space-between',
|
|
3314
|
+
'space-around',
|
|
3315
|
+
'start',
|
|
3316
|
+
'end'
|
|
3317
|
+
],
|
|
3318
|
+
'box-sizing': [
|
|
3319
|
+
'border-box',
|
|
3320
|
+
'content-box',
|
|
3321
|
+
'auto'
|
|
3322
|
+
],
|
|
3323
|
+
direction: [
|
|
3324
|
+
'normal',
|
|
3325
|
+
'lynx-rtl',
|
|
3326
|
+
'rtl',
|
|
3327
|
+
'ltr'
|
|
3328
|
+
],
|
|
3329
|
+
display: [
|
|
3330
|
+
'none',
|
|
3331
|
+
'flex',
|
|
3332
|
+
'grid',
|
|
3333
|
+
'linear',
|
|
3334
|
+
'relative',
|
|
3335
|
+
'block',
|
|
3336
|
+
'auto',
|
|
3337
|
+
'-x-box'
|
|
3338
|
+
],
|
|
3339
|
+
'flex-direction': [
|
|
3340
|
+
'column',
|
|
3341
|
+
'row',
|
|
3342
|
+
'row-reverse',
|
|
3343
|
+
'column-reverse'
|
|
3344
|
+
],
|
|
3345
|
+
'flex-wrap': [
|
|
3346
|
+
'wrap',
|
|
3347
|
+
'nowrap',
|
|
3348
|
+
'wrap-reverse'
|
|
3349
|
+
],
|
|
3350
|
+
'font-optical-sizing': [
|
|
3351
|
+
'none',
|
|
3352
|
+
'auto'
|
|
3353
|
+
],
|
|
3354
|
+
'font-style': [
|
|
3355
|
+
'normal',
|
|
3356
|
+
'italic',
|
|
3357
|
+
'oblique'
|
|
3358
|
+
],
|
|
3359
|
+
'font-weight': [
|
|
3360
|
+
'normal',
|
|
3361
|
+
'bold',
|
|
3362
|
+
'100',
|
|
3363
|
+
'200',
|
|
3364
|
+
'300',
|
|
3365
|
+
'400',
|
|
3366
|
+
'500',
|
|
3367
|
+
'600',
|
|
3368
|
+
'700',
|
|
3369
|
+
'800',
|
|
3370
|
+
'900'
|
|
3371
|
+
],
|
|
3372
|
+
hyphens: [
|
|
3373
|
+
'none',
|
|
3374
|
+
'manual',
|
|
3375
|
+
'auto'
|
|
3376
|
+
],
|
|
3377
|
+
'image-rendering': [
|
|
3378
|
+
'auto',
|
|
3379
|
+
'crisp-edges',
|
|
3380
|
+
'pixelated'
|
|
3381
|
+
],
|
|
3382
|
+
'justify-content': [
|
|
3383
|
+
'flex-start',
|
|
3384
|
+
'center',
|
|
3385
|
+
'flex-end',
|
|
3386
|
+
'space-between',
|
|
3387
|
+
'space-around',
|
|
3388
|
+
'space-evenly',
|
|
3389
|
+
'stretch',
|
|
3390
|
+
'start',
|
|
3391
|
+
'end'
|
|
3392
|
+
],
|
|
3393
|
+
'linear-cross-gravity': [
|
|
3394
|
+
'none',
|
|
3395
|
+
'start',
|
|
3396
|
+
'end',
|
|
3397
|
+
'center',
|
|
3398
|
+
'stretch'
|
|
3399
|
+
],
|
|
3400
|
+
'linear-gravity': [
|
|
3401
|
+
'none',
|
|
3402
|
+
'top',
|
|
3403
|
+
'bottom',
|
|
3404
|
+
'left',
|
|
3405
|
+
'right',
|
|
3406
|
+
'center-vertical',
|
|
3407
|
+
'center-horizontal',
|
|
3408
|
+
'space-between',
|
|
3409
|
+
'start',
|
|
3410
|
+
'end',
|
|
3411
|
+
'center'
|
|
3412
|
+
],
|
|
3413
|
+
'linear-layout-gravity': [
|
|
3414
|
+
'none',
|
|
3415
|
+
'top',
|
|
3416
|
+
'bottom',
|
|
3417
|
+
'left',
|
|
3418
|
+
'right',
|
|
3419
|
+
'center-vertical',
|
|
3420
|
+
'center-horizontal',
|
|
3421
|
+
'fill-vertical',
|
|
3422
|
+
'fill-horizontal',
|
|
3423
|
+
'center',
|
|
3424
|
+
'stretch',
|
|
3425
|
+
'start',
|
|
3426
|
+
'end'
|
|
3427
|
+
],
|
|
3428
|
+
'linear-orientation': [
|
|
3429
|
+
'horizontal',
|
|
3430
|
+
'vertical',
|
|
3431
|
+
'horizontal-reverse',
|
|
3432
|
+
'vertical-reverse',
|
|
3433
|
+
'row',
|
|
3434
|
+
'column',
|
|
3435
|
+
'row-reverse',
|
|
3436
|
+
'column-reverse'
|
|
3437
|
+
],
|
|
3438
|
+
'pointer-events': [
|
|
3439
|
+
'auto',
|
|
3440
|
+
'none'
|
|
3441
|
+
],
|
|
3442
|
+
position: [
|
|
3443
|
+
'absolute',
|
|
3444
|
+
'relative',
|
|
3445
|
+
'fixed',
|
|
3446
|
+
'sticky'
|
|
3447
|
+
],
|
|
3448
|
+
'relative-center': [
|
|
3449
|
+
'none',
|
|
3450
|
+
'vertical',
|
|
3451
|
+
'horizontal',
|
|
3452
|
+
'both'
|
|
3453
|
+
],
|
|
3454
|
+
'text-align': [
|
|
3455
|
+
'left',
|
|
3456
|
+
'center',
|
|
3457
|
+
'right',
|
|
3458
|
+
'start',
|
|
3459
|
+
'end',
|
|
3460
|
+
'justify'
|
|
3461
|
+
],
|
|
3462
|
+
'text-overflow': [
|
|
3463
|
+
'clip',
|
|
3464
|
+
'ellipsis'
|
|
3465
|
+
],
|
|
3466
|
+
visibility: [
|
|
3467
|
+
'hidden',
|
|
3468
|
+
'visible',
|
|
3469
|
+
'none',
|
|
3470
|
+
'collapse'
|
|
3471
|
+
],
|
|
3472
|
+
'white-space': [
|
|
3473
|
+
'normal',
|
|
3474
|
+
'nowrap'
|
|
3475
|
+
],
|
|
3476
|
+
'word-break': [
|
|
3477
|
+
'normal',
|
|
3478
|
+
'break-all',
|
|
3479
|
+
'keep-all'
|
|
3480
|
+
]
|
|
3481
|
+
}).map(([property, keywords])=>[
|
|
3482
|
+
property,
|
|
3483
|
+
new Set(keywords)
|
|
3484
|
+
]));
|
|
3485
|
+
const COMPOSED_TRANSFORM = "translate3d(var(--tw-translate-x), var(--tw-translate-y), var(--tw-translate-z)) rotate(var(--tw-rotate)) scale(var(--tw-scale-x), var(--tw-scale-y)) var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)";
|
|
3486
|
+
const TRANSFORM_DEFAULTS = new Map([
|
|
3487
|
+
[
|
|
3488
|
+
'--tw-translate-x',
|
|
3489
|
+
'0'
|
|
3490
|
+
],
|
|
3491
|
+
[
|
|
3492
|
+
'--tw-translate-y',
|
|
3493
|
+
'0'
|
|
3494
|
+
],
|
|
3495
|
+
[
|
|
3496
|
+
'--tw-translate-z',
|
|
3497
|
+
'0'
|
|
3498
|
+
],
|
|
3499
|
+
[
|
|
3500
|
+
'--tw-rotate',
|
|
3501
|
+
'0deg'
|
|
3502
|
+
],
|
|
3503
|
+
[
|
|
3504
|
+
'--tw-scale-x',
|
|
3505
|
+
'1'
|
|
3506
|
+
],
|
|
3507
|
+
[
|
|
3508
|
+
'--tw-scale-y',
|
|
3509
|
+
'1'
|
|
3510
|
+
]
|
|
3511
|
+
]);
|
|
3512
|
+
const lowerDeclarations = (rule, channelVariables = new Set())=>{
|
|
3513
|
+
const composed = [];
|
|
3514
|
+
for (const declaration of rule.nodes.slice())if ('decl' === declaration.type) {
|
|
3515
|
+
declaration.value = lowerColors(declaration.value, channelVariables);
|
|
3516
|
+
if (lowerTransformProperty(declaration)) {
|
|
3517
|
+
composed.push(declaration);
|
|
3518
|
+
continue;
|
|
3519
|
+
}
|
|
3520
|
+
lowerValue(declaration);
|
|
3521
|
+
expandLogical(declaration);
|
|
3522
|
+
}
|
|
3523
|
+
if (composed.length > 0) {
|
|
3524
|
+
composed[composed.length - 1].before({
|
|
3525
|
+
prop: 'transform',
|
|
3526
|
+
value: COMPOSED_TRANSFORM
|
|
3527
|
+
});
|
|
3528
|
+
for (const declaration of composed)declaration.remove();
|
|
3529
|
+
}
|
|
3530
|
+
dropUnsupportedProperties(rule);
|
|
3531
|
+
return {
|
|
3532
|
+
composesTransform: composed.length > 0
|
|
3533
|
+
};
|
|
3534
|
+
};
|
|
3535
|
+
const TRANSFORM_VARIABLES = /^--tw-(?:translate-[xyz]|rotate(?:-[xyz])?|skew-[xy]|scale-[xyz])$/;
|
|
3536
|
+
const lowerTransformVariables = (root)=>{
|
|
3537
|
+
root.walkDecls(TRANSFORM_VARIABLES, (declaration)=>{
|
|
3538
|
+
declaration.value = transformValue(declaration.prop, declaration.value);
|
|
3539
|
+
});
|
|
3540
|
+
};
|
|
3541
|
+
const lowerTransformProperty = (declaration)=>{
|
|
3542
|
+
const { prop } = declaration;
|
|
3543
|
+
const values = splitSpaces(declaration.value);
|
|
3544
|
+
switch(prop){
|
|
3545
|
+
case 'translate':
|
|
3546
|
+
if (!isTailwindComposition(values, '--tw-translate-')) {
|
|
3547
|
+
const [x, y = '0', z = '0'] = 'none' === values[0] ? [
|
|
3548
|
+
'0',
|
|
3549
|
+
'0',
|
|
3550
|
+
'0'
|
|
3551
|
+
] : values;
|
|
3552
|
+
setVariables(declaration, {
|
|
3553
|
+
'--tw-translate-x': x,
|
|
3554
|
+
'--tw-translate-y': y,
|
|
3555
|
+
'--tw-translate-z': z
|
|
3556
|
+
});
|
|
3557
|
+
}
|
|
3558
|
+
break;
|
|
3559
|
+
case 'rotate':
|
|
3560
|
+
if (1 !== values.length) return false;
|
|
3561
|
+
setVariables(declaration, {
|
|
3562
|
+
'--tw-rotate': 'none' === values[0] ? '0deg' : values[0]
|
|
3563
|
+
});
|
|
3564
|
+
break;
|
|
3565
|
+
case 'scale':
|
|
3566
|
+
if (!isTailwindComposition(values, '--tw-scale-')) {
|
|
3567
|
+
const [x, y = x] = 'none' === values[0] ? [
|
|
3568
|
+
'1',
|
|
3569
|
+
'1'
|
|
3570
|
+
] : values;
|
|
3571
|
+
setVariables(declaration, {
|
|
3572
|
+
'--tw-scale-x': x,
|
|
3573
|
+
'--tw-scale-y': y
|
|
3574
|
+
});
|
|
3575
|
+
}
|
|
3576
|
+
break;
|
|
3577
|
+
case 'transform':
|
|
3578
|
+
if (!isTailwindComposition(values, '--tw-')) return false;
|
|
3579
|
+
break;
|
|
3580
|
+
default:
|
|
3581
|
+
return false;
|
|
3582
|
+
}
|
|
3583
|
+
return true;
|
|
3584
|
+
};
|
|
3585
|
+
const isTailwindComposition = (values, prefix)=>values.length > 0 && values.every((value)=>value.startsWith(`var(${prefix}`));
|
|
3586
|
+
const setVariables = (declaration, variables)=>{
|
|
3587
|
+
for (const [prop, value] of Object.entries(variables))declaration.before({
|
|
3588
|
+
prop,
|
|
3589
|
+
value: transformValue(prop, value)
|
|
3590
|
+
});
|
|
3591
|
+
};
|
|
3592
|
+
const transformValue = (prop, value)=>{
|
|
3593
|
+
const folded = foldCalc(value);
|
|
3594
|
+
if (!prop.startsWith('--tw-scale-')) return folded;
|
|
3595
|
+
const unit = postcss_value_parser.unit(folded);
|
|
3596
|
+
return unit && '%' === unit.unit ? String(Number(unit.number) / 100) : folded;
|
|
3597
|
+
};
|
|
3598
|
+
const splitSpaces = (value)=>postcss_value_parser(value).nodes.filter((node)=>'space' !== node.type && 'comment' !== node.type).map((node)=>postcss_value_parser.stringify(node));
|
|
3599
|
+
const lowerValue = (declaration)=>{
|
|
3600
|
+
switch(declaration.prop){
|
|
3601
|
+
case 'opacity':
|
|
3602
|
+
{
|
|
3603
|
+
const unit = postcss_value_parser.unit(declaration.value);
|
|
3604
|
+
if (unit && '%' === unit.unit) declaration.value = String(Number(unit.number) / 100);
|
|
3605
|
+
break;
|
|
3606
|
+
}
|
|
3607
|
+
case 'text-decoration-line':
|
|
3608
|
+
declaration.prop = 'text-decoration';
|
|
3609
|
+
break;
|
|
3610
|
+
case 'transition-property':
|
|
3611
|
+
declaration.value = lowerTransitionProperty(declaration.value);
|
|
3612
|
+
break;
|
|
3613
|
+
case '--tw-gradient-position':
|
|
3614
|
+
declaration.value = lowerGradientPosition(declaration);
|
|
3615
|
+
break;
|
|
3616
|
+
default:
|
|
3617
|
+
if (/\binfinity\b/i.test(declaration.value)) declaration.value = foldCalc(declaration.value);
|
|
3618
|
+
declaration.value = clampHugeNumbers(declaration.value);
|
|
3619
|
+
break;
|
|
3620
|
+
}
|
|
3621
|
+
};
|
|
3622
|
+
const lowerTransitionProperty = (value)=>{
|
|
3623
|
+
const properties = value.split(',').map((property)=>{
|
|
3624
|
+
const name = property.trim().toLowerCase();
|
|
3625
|
+
return [
|
|
3626
|
+
'translate',
|
|
3627
|
+
'rotate',
|
|
3628
|
+
'scale'
|
|
3629
|
+
].includes(name) ? 'transform' : name;
|
|
3630
|
+
}).filter((name)=>'all' === name || 'none' === name || LYNX_PROPERTIES.has(name));
|
|
3631
|
+
return [
|
|
3632
|
+
...new Set(properties)
|
|
3633
|
+
].join(', ') || 'none';
|
|
3634
|
+
};
|
|
3635
|
+
const lowerGradientPosition = (declaration)=>{
|
|
3636
|
+
const position = declaration.value.replace(/\s*\bin\s+[a-z0-9-]+(?:\s+(?:shorter|longer|increasing|decreasing)\s+hue)?/gi, '').trim();
|
|
3637
|
+
if (position) return position;
|
|
3638
|
+
let gradient = 'linear';
|
|
3639
|
+
declaration.parent?.walkDecls('background-image', ({ value })=>{
|
|
3640
|
+
gradient = /^(radial|conic)-gradient\(/.exec(value)?.[1] ?? gradient;
|
|
3641
|
+
});
|
|
3642
|
+
return ({
|
|
3643
|
+
linear: 'to bottom',
|
|
3644
|
+
radial: 'ellipse',
|
|
3645
|
+
conic: 'from 0deg'
|
|
3646
|
+
})[gradient];
|
|
3647
|
+
};
|
|
3648
|
+
const LOGICAL_PAIRS = {
|
|
3649
|
+
'padding-inline': [
|
|
3650
|
+
'padding-left',
|
|
3651
|
+
'padding-right'
|
|
3652
|
+
],
|
|
3653
|
+
'padding-block': [
|
|
3654
|
+
'padding-top',
|
|
3655
|
+
'padding-bottom'
|
|
3656
|
+
],
|
|
3657
|
+
'margin-inline': [
|
|
3658
|
+
'margin-left',
|
|
3659
|
+
'margin-right'
|
|
3660
|
+
],
|
|
3661
|
+
'margin-block': [
|
|
3662
|
+
'margin-top',
|
|
3663
|
+
'margin-bottom'
|
|
3664
|
+
],
|
|
3665
|
+
'inset-inline': [
|
|
3666
|
+
'left',
|
|
3667
|
+
'right'
|
|
3668
|
+
],
|
|
3669
|
+
'inset-block': [
|
|
3670
|
+
'top',
|
|
3671
|
+
'bottom'
|
|
3672
|
+
],
|
|
3673
|
+
'border-inline-width': [
|
|
3674
|
+
'border-left-width',
|
|
3675
|
+
'border-right-width'
|
|
3676
|
+
],
|
|
3677
|
+
'border-block-width': [
|
|
3678
|
+
'border-top-width',
|
|
3679
|
+
'border-bottom-width'
|
|
3680
|
+
],
|
|
3681
|
+
'border-inline-style': [
|
|
3682
|
+
'border-left-style',
|
|
3683
|
+
'border-right-style'
|
|
3684
|
+
],
|
|
3685
|
+
'border-block-style': [
|
|
3686
|
+
'border-top-style',
|
|
3687
|
+
'border-bottom-style'
|
|
3688
|
+
],
|
|
3689
|
+
'border-inline-color': [
|
|
3690
|
+
'border-left-color',
|
|
3691
|
+
'border-right-color'
|
|
3692
|
+
],
|
|
3693
|
+
'border-block-color': [
|
|
3694
|
+
'border-top-color',
|
|
3695
|
+
'border-bottom-color'
|
|
3696
|
+
]
|
|
3697
|
+
};
|
|
3698
|
+
const LOGICAL_BOTH_SIDES = {
|
|
3699
|
+
'border-inline': [
|
|
3700
|
+
'border-left',
|
|
3701
|
+
'border-right'
|
|
3702
|
+
],
|
|
3703
|
+
'border-block': [
|
|
3704
|
+
'border-top',
|
|
3705
|
+
'border-bottom'
|
|
3706
|
+
]
|
|
3707
|
+
};
|
|
3708
|
+
const LOGICAL_LONGHANDS = {
|
|
3709
|
+
'padding-inline-start': 'padding-left',
|
|
3710
|
+
'padding-inline-end': 'padding-right',
|
|
3711
|
+
'padding-block-start': 'padding-top',
|
|
3712
|
+
'padding-block-end': 'padding-bottom',
|
|
3713
|
+
'margin-inline-start': 'margin-left',
|
|
3714
|
+
'margin-inline-end': 'margin-right',
|
|
3715
|
+
'margin-block-start': 'margin-top',
|
|
3716
|
+
'margin-block-end': 'margin-bottom',
|
|
3717
|
+
'inset-inline-start': 'left',
|
|
3718
|
+
'inset-inline-end': 'right',
|
|
3719
|
+
'inset-block-start': 'top',
|
|
3720
|
+
'inset-block-end': 'bottom',
|
|
3721
|
+
'border-inline-start': 'border-left',
|
|
3722
|
+
'border-inline-end': 'border-right',
|
|
3723
|
+
'border-block-start': 'border-top',
|
|
3724
|
+
'border-block-end': 'border-bottom',
|
|
3725
|
+
'border-inline-start-width': 'border-left-width',
|
|
3726
|
+
'border-inline-end-width': 'border-right-width',
|
|
3727
|
+
'border-block-start-width': 'border-top-width',
|
|
3728
|
+
'border-block-end-width': 'border-bottom-width',
|
|
3729
|
+
'border-inline-start-style': 'border-left-style',
|
|
3730
|
+
'border-inline-end-style': 'border-right-style',
|
|
3731
|
+
'border-block-start-style': 'border-top-style',
|
|
3732
|
+
'border-block-end-style': 'border-bottom-style',
|
|
3733
|
+
'border-inline-start-color': 'border-left-color',
|
|
3734
|
+
'border-inline-end-color': 'border-right-color',
|
|
3735
|
+
'border-block-start-color': 'border-top-color',
|
|
3736
|
+
'border-block-end-color': 'border-bottom-color',
|
|
3737
|
+
'border-start-start-radius': 'border-top-left-radius',
|
|
3738
|
+
'border-start-end-radius': 'border-top-right-radius',
|
|
3739
|
+
'border-end-start-radius': 'border-bottom-left-radius',
|
|
3740
|
+
'border-end-end-radius': 'border-bottom-right-radius'
|
|
3741
|
+
};
|
|
3742
|
+
const expandLogical = (declaration)=>{
|
|
3743
|
+
const { prop, value, important } = declaration;
|
|
3744
|
+
const longhand = LOGICAL_LONGHANDS[prop];
|
|
3745
|
+
if (longhand) {
|
|
3746
|
+
declaration.prop = longhand;
|
|
3747
|
+
return;
|
|
3748
|
+
}
|
|
3749
|
+
let expanded;
|
|
3750
|
+
const pair = LOGICAL_PAIRS[prop];
|
|
3751
|
+
const bothSides = LOGICAL_BOTH_SIDES[prop];
|
|
3752
|
+
if (pair) {
|
|
3753
|
+
const [start, end = start] = splitSpaces(value);
|
|
3754
|
+
expanded = [
|
|
3755
|
+
[
|
|
3756
|
+
pair[0],
|
|
3757
|
+
start
|
|
3758
|
+
],
|
|
3759
|
+
[
|
|
3760
|
+
pair[1],
|
|
3761
|
+
end
|
|
3762
|
+
]
|
|
3763
|
+
];
|
|
3764
|
+
} else if (bothSides) expanded = [
|
|
3765
|
+
[
|
|
3766
|
+
bothSides[0],
|
|
3767
|
+
value
|
|
3768
|
+
],
|
|
3769
|
+
[
|
|
3770
|
+
bothSides[1],
|
|
3771
|
+
value
|
|
3772
|
+
]
|
|
3773
|
+
];
|
|
3774
|
+
else if ('inset' === prop) {
|
|
3775
|
+
const [top, right = top, bottom = top, left = right] = splitSpaces(value);
|
|
3776
|
+
expanded = [
|
|
3777
|
+
[
|
|
3778
|
+
'top',
|
|
3779
|
+
top
|
|
3780
|
+
],
|
|
3781
|
+
[
|
|
3782
|
+
'right',
|
|
3783
|
+
right
|
|
3784
|
+
],
|
|
3785
|
+
[
|
|
3786
|
+
'bottom',
|
|
3787
|
+
bottom
|
|
3788
|
+
],
|
|
3789
|
+
[
|
|
3790
|
+
'left',
|
|
3791
|
+
left
|
|
3792
|
+
]
|
|
3793
|
+
];
|
|
3794
|
+
}
|
|
3795
|
+
if (!expanded) return;
|
|
3796
|
+
for (const [physical, physicalValue] of expanded)declaration.before({
|
|
3797
|
+
prop: physical,
|
|
3798
|
+
value: physicalValue,
|
|
3799
|
+
important
|
|
3800
|
+
});
|
|
3801
|
+
declaration.remove();
|
|
3802
|
+
};
|
|
3803
|
+
const dropUnsupportedProperties = (rule)=>{
|
|
3804
|
+
rule.each((node)=>{
|
|
3805
|
+
if ('decl' !== node.type || node.prop.startsWith('--')) return;
|
|
3806
|
+
const prop = node.prop.toLowerCase();
|
|
3807
|
+
const keywords = LYNX_KEYWORDS.get(prop);
|
|
3808
|
+
const value = node.value.trim().toLowerCase();
|
|
3809
|
+
if (!LYNX_PROPERTIES.has(prop) || void 0 !== keywords && /^[a-z-]+$/.test(value) && !GLOBAL_KEYWORDS.has(value) && !keywords.has(value)) node.remove();
|
|
3810
|
+
});
|
|
3811
|
+
};
|
|
3812
|
+
const GLOBAL_KEYWORDS = new Set([
|
|
3813
|
+
'inherit',
|
|
3814
|
+
'initial',
|
|
3815
|
+
'unset',
|
|
3816
|
+
'revert'
|
|
3817
|
+
]);
|
|
3818
|
+
const lowerSelectors = (rule)=>{
|
|
3819
|
+
const selectors = rule.selectors.filter((selector)=>!/(?<!\\):host\b/.test(selector)).flatMap(unwrapWhereAndIs);
|
|
3820
|
+
if (0 === selectors.length) return false;
|
|
3821
|
+
rule.selectors = selectors.every((selector)=>NOT_LAST_CHILD.test(selector)) && mirrorBetweenChildren(rule) ? selectors.map((selector)=>selector.replace(NOT_LAST_CHILD, ' > * + *')) : selectors;
|
|
3822
|
+
return true;
|
|
3823
|
+
};
|
|
3824
|
+
const unwrapWhereAndIs = (selector)=>{
|
|
3825
|
+
const match = /^:(?:where|is)\(/i.exec(selector);
|
|
3826
|
+
if (!match || closingParenthesis(selector, match[0].length) !== selector.length - 1) return [
|
|
3827
|
+
selector
|
|
3828
|
+
];
|
|
3829
|
+
return splitTopLevel(selector.slice(match[0].length, -1)).flatMap(unwrapWhereAndIs);
|
|
3830
|
+
};
|
|
3831
|
+
const closingParenthesis = (text, start)=>{
|
|
3832
|
+
let depth = 1;
|
|
3833
|
+
for(let index = start; index < text.length; index++){
|
|
3834
|
+
const character = text[index];
|
|
3835
|
+
if ('\\' === character) index++;
|
|
3836
|
+
else if ('(' === character) depth++;
|
|
3837
|
+
else if (')' === character && 0 === --depth) return index;
|
|
3838
|
+
}
|
|
3839
|
+
return -1;
|
|
3840
|
+
};
|
|
3841
|
+
const splitTopLevel = (list)=>{
|
|
3842
|
+
const parts = [];
|
|
3843
|
+
let depth = 0;
|
|
3844
|
+
let current = '';
|
|
3845
|
+
for(let index = 0; index < list.length; index++){
|
|
3846
|
+
const character = list[index];
|
|
3847
|
+
if ('\\' === character) {
|
|
3848
|
+
current += list.slice(index, index + 2);
|
|
3849
|
+
index++;
|
|
3850
|
+
continue;
|
|
3851
|
+
}
|
|
3852
|
+
if ('(' === character) depth++;
|
|
3853
|
+
else if (')' === character) depth--;
|
|
3854
|
+
else if (',' === character && 0 === depth) {
|
|
3855
|
+
parts.push(current.trim());
|
|
3856
|
+
current = '';
|
|
3857
|
+
continue;
|
|
3858
|
+
}
|
|
3859
|
+
current += character;
|
|
3860
|
+
}
|
|
3861
|
+
parts.push(current.trim());
|
|
3862
|
+
return parts;
|
|
3863
|
+
};
|
|
3864
|
+
const NOT_LAST_CHILD = /\s*>\s*:not\(:last-child\)$/;
|
|
3865
|
+
const OPPOSITE_SIDES = {
|
|
3866
|
+
top: 'bottom',
|
|
3867
|
+
bottom: 'top',
|
|
3868
|
+
left: 'right',
|
|
3869
|
+
right: 'left',
|
|
3870
|
+
'block-start': 'block-end',
|
|
3871
|
+
'block-end': 'block-start',
|
|
3872
|
+
'inline-start': 'inline-end',
|
|
3873
|
+
'inline-end': 'inline-start'
|
|
3874
|
+
};
|
|
3875
|
+
const mirrorBetweenChildren = (rule)=>{
|
|
3876
|
+
const sidesOnly = rule.nodes.every((node)=>'decl' !== node.type || node.prop.startsWith('--') || /^(margin|padding|border)-/.test(node.prop));
|
|
3877
|
+
if (!sidesOnly) return false;
|
|
3878
|
+
rule.walkDecls((declaration)=>{
|
|
3879
|
+
if (declaration.prop.startsWith('--')) return;
|
|
3880
|
+
declaration.prop = declaration.prop.replace(/\b(top|bottom|left|right|block-start|block-end|inline-start|inline-end)\b/, (side)=>OPPOSITE_SIDES[side]);
|
|
3881
|
+
});
|
|
3882
|
+
return true;
|
|
3883
|
+
};
|
|
3884
|
+
const flattenNesting = (root)=>{
|
|
3885
|
+
root.each((node)=>{
|
|
3886
|
+
flattenNode(node);
|
|
3887
|
+
});
|
|
3888
|
+
};
|
|
3889
|
+
const flattenNode = (node)=>{
|
|
3890
|
+
if ('rule' === node.type) flattenRule(node);
|
|
3891
|
+
else if ('atrule' === node.type && node.nodes) node.each((child)=>{
|
|
3892
|
+
flattenNode(child);
|
|
3893
|
+
});
|
|
3894
|
+
};
|
|
3895
|
+
const flattenRule = (rule)=>{
|
|
3896
|
+
let last = rule;
|
|
3897
|
+
for (const child of rule.nodes.slice())if ('rule' === child.type) {
|
|
3898
|
+
child.selectors = resolveNested(child.selectors, rule.selectors);
|
|
3899
|
+
last.after(child);
|
|
3900
|
+
last = flattenRule(child);
|
|
3901
|
+
} else if ('atrule' === child.type) {
|
|
3902
|
+
wrapDeclarations(child, rule);
|
|
3903
|
+
last.after(child);
|
|
3904
|
+
last = child;
|
|
3905
|
+
flattenNode(child);
|
|
3906
|
+
}
|
|
3907
|
+
return last;
|
|
3908
|
+
};
|
|
3909
|
+
const wrapDeclarations = (atRule, rule)=>{
|
|
3910
|
+
if (!atRule.nodes) return;
|
|
3911
|
+
for (const child of atRule.nodes)if ('rule' === child.type) child.selectors = resolveNested(child.selectors, rule.selectors);
|
|
3912
|
+
else if ('atrule' === child.type) wrapDeclarations(child, rule);
|
|
3913
|
+
const declarations = atRule.nodes.filter((node)=>'decl' === node.type);
|
|
3914
|
+
if (declarations.length > 0) {
|
|
3915
|
+
const wrapper = rule.clone();
|
|
3916
|
+
wrapper.removeAll();
|
|
3917
|
+
wrapper.append(declarations);
|
|
3918
|
+
atRule.prepend(wrapper);
|
|
3919
|
+
}
|
|
3920
|
+
};
|
|
3921
|
+
const resolveNested = (selectors, parents)=>parents.flatMap((parent)=>selectors.map((selector)=>/(?<!\\)&/.test(selector) ? selector.replaceAll(/(?<!\\)&/g, parent) : `${parent} ${selector}`));
|
|
3922
|
+
const unwrapLayers = (container)=>{
|
|
3923
|
+
container.each((node)=>{
|
|
3924
|
+
if ('atrule' !== node.type) return;
|
|
3925
|
+
if ('layer' === node.name.toLowerCase()) if (node.nodes) {
|
|
3926
|
+
unwrapLayers(node);
|
|
3927
|
+
node.replaceWith(node.nodes);
|
|
3928
|
+
} else node.remove();
|
|
3929
|
+
else if (node.nodes) unwrapLayers(node);
|
|
3930
|
+
});
|
|
3931
|
+
};
|
|
3932
|
+
const takePropertyRegistrations = (root)=>{
|
|
3933
|
+
const initialValues = new Map();
|
|
3934
|
+
root.walkAtRules(/^property$/i, (atRule)=>{
|
|
3935
|
+
atRule.walkDecls('initial-value', (declaration)=>{
|
|
3936
|
+
initialValues.set(atRule.params.trim(), declaration.value);
|
|
3937
|
+
});
|
|
3938
|
+
atRule.remove();
|
|
3939
|
+
});
|
|
3940
|
+
root.walkAtRules(/^supports$/i, (atRule)=>{
|
|
3941
|
+
const rules = atRule.nodes?.filter((node)=>'rule' === node.type) ?? [];
|
|
3942
|
+
if (rules.length > 0 && rules.every((rule)=>rule.selector.includes('::backdrop'))) atRule.remove();
|
|
3943
|
+
});
|
|
3944
|
+
return initialValues;
|
|
3945
|
+
};
|
|
3946
|
+
const removeEmptyContainers = (container)=>{
|
|
3947
|
+
container.each((node)=>{
|
|
3948
|
+
if ('rule' !== node.type && 'atrule' !== node.type) return;
|
|
3949
|
+
if (!node.nodes) return;
|
|
3950
|
+
removeEmptyContainers(node);
|
|
3951
|
+
if (node.nodes.every((child)=>'comment' === child.type)) node.remove();
|
|
3952
|
+
});
|
|
3953
|
+
};
|
|
3954
|
+
const IMPLIED_KEYFRAME_VALUES = {
|
|
3955
|
+
transform: 'none',
|
|
3956
|
+
opacity: '1'
|
|
3957
|
+
};
|
|
3958
|
+
const completeKeyframes = (root)=>{
|
|
3959
|
+
root.walkAtRules(/^(?:-webkit-)?keyframes$/i, (atRule)=>{
|
|
3960
|
+
const offsets = new Set();
|
|
3961
|
+
const properties = new Set();
|
|
3962
|
+
atRule.walkRules((rule)=>{
|
|
3963
|
+
for (const selector of rule.selectors)offsets.add({
|
|
3964
|
+
from: '0%',
|
|
3965
|
+
to: '100%'
|
|
3966
|
+
}[selector.toLowerCase()] ?? selector);
|
|
3967
|
+
rule.walkDecls(({ prop })=>{
|
|
3968
|
+
if (prop in IMPLIED_KEYFRAME_VALUES) properties.add(prop);
|
|
3969
|
+
});
|
|
3970
|
+
});
|
|
3971
|
+
const first = atRule.first;
|
|
3972
|
+
if (0 === properties.size || first?.type !== 'rule') return;
|
|
3973
|
+
for (const [offset, selector] of [
|
|
3974
|
+
[
|
|
3975
|
+
'0%',
|
|
3976
|
+
'from'
|
|
3977
|
+
],
|
|
3978
|
+
[
|
|
3979
|
+
'100%',
|
|
3980
|
+
'to'
|
|
3981
|
+
]
|
|
3982
|
+
]){
|
|
3983
|
+
if (offsets.has(offset)) continue;
|
|
3984
|
+
const keyframe = first.clone({
|
|
3985
|
+
selector
|
|
3986
|
+
});
|
|
3987
|
+
keyframe.removeAll();
|
|
3988
|
+
for (const prop of properties)keyframe.append({
|
|
3989
|
+
prop,
|
|
3990
|
+
value: IMPLIED_KEYFRAME_VALUES[prop]
|
|
3991
|
+
});
|
|
3992
|
+
if ('from' === selector) atRule.prepend(keyframe);
|
|
3993
|
+
else atRule.append(keyframe);
|
|
3994
|
+
}
|
|
3995
|
+
});
|
|
3996
|
+
};
|
|
3997
|
+
const resolveNestedVariables = (root, registrations)=>{
|
|
3998
|
+
const theme = themeVariables(root);
|
|
3999
|
+
root.walkDecls(/^--/, (declaration)=>{
|
|
4000
|
+
if (!declaration.value.includes('var(')) return;
|
|
4001
|
+
const parsed = postcss_value_parser(declaration.value);
|
|
4002
|
+
const lookup = (name)=>sameRuleValue(declaration, name) ?? theme.get(name) ?? registrations.get(name);
|
|
4003
|
+
if (resolveInFunctions(parsed.nodes, false, lookup, new Set())) declaration.value = foldCalc(parsed.toString());
|
|
4004
|
+
});
|
|
4005
|
+
};
|
|
4006
|
+
const themeVariables = (root)=>{
|
|
4007
|
+
const variables = new Map();
|
|
4008
|
+
root.walkRules((rule)=>{
|
|
4009
|
+
if (rule.selectors.includes(':root')) rule.walkDecls(/^--/, ({ prop, value })=>{
|
|
4010
|
+
variables.set(prop, value);
|
|
4011
|
+
});
|
|
4012
|
+
});
|
|
4013
|
+
return variables;
|
|
4014
|
+
};
|
|
4015
|
+
const sameRuleValue = (declaration, name)=>{
|
|
4016
|
+
let value;
|
|
4017
|
+
declaration.parent.each((node)=>{
|
|
4018
|
+
if ('decl' === node.type && node.prop === name && node !== declaration) value = node.value;
|
|
4019
|
+
});
|
|
4020
|
+
return value;
|
|
4021
|
+
};
|
|
4022
|
+
const resolveInFunctions = (nodes, insideFunction, lookup, seen)=>{
|
|
4023
|
+
let changed = false;
|
|
4024
|
+
for (const node of nodes){
|
|
4025
|
+
if ('function' !== node.type) continue;
|
|
4026
|
+
if ('var' !== node.value.toLowerCase()) {
|
|
4027
|
+
changed = resolveInFunctions(node.nodes, true, lookup, seen) || changed;
|
|
4028
|
+
continue;
|
|
4029
|
+
}
|
|
4030
|
+
const resolved = insideFunction ? resolveVariable(node, lookup, seen) : void 0;
|
|
4031
|
+
if (void 0 === resolved) {
|
|
4032
|
+
changed = resolveInFunctions(node.nodes, insideFunction, lookup, seen) || changed;
|
|
4033
|
+
continue;
|
|
4034
|
+
}
|
|
4035
|
+
Object.assign(node, {
|
|
4036
|
+
type: 'word',
|
|
4037
|
+
value: resolved
|
|
4038
|
+
});
|
|
4039
|
+
changed = true;
|
|
4040
|
+
}
|
|
4041
|
+
return changed;
|
|
4042
|
+
};
|
|
4043
|
+
const resolveVariable = (node, lookup, seen)=>{
|
|
4044
|
+
const name = node.nodes[0]?.value ?? '';
|
|
4045
|
+
if (seen.has(name)) return;
|
|
4046
|
+
const commaIndex = node.nodes.findIndex((child)=>'div' === child.type && ',' === child.value);
|
|
4047
|
+
const fallback = -1 === commaIndex ? void 0 : postcss_value_parser.stringify(node.nodes.slice(commaIndex + 1)).trim();
|
|
4048
|
+
const value = lookup(name) ?? fallback;
|
|
4049
|
+
if (void 0 === value) return;
|
|
4050
|
+
const parsed = postcss_value_parser(value);
|
|
4051
|
+
resolveInFunctions(parsed.nodes, true, lookup, new Set([
|
|
4052
|
+
...seen,
|
|
4053
|
+
name
|
|
4054
|
+
]));
|
|
4055
|
+
return parsed.toString();
|
|
4056
|
+
};
|
|
4057
|
+
const TAILWIND_POSTCSS = '@tailwindcss/postcss';
|
|
4058
|
+
const tailwindForLynx = ()=>({
|
|
4059
|
+
postcssPlugin: 'angular-lynx-tailwind',
|
|
4060
|
+
OnceExit (root, { result, rule }) {
|
|
4061
|
+
if (!compiledByTailwind(result)) return;
|
|
4062
|
+
lowerForLynx(root, (selector)=>rule({
|
|
4063
|
+
selector
|
|
4064
|
+
}));
|
|
4065
|
+
}
|
|
4066
|
+
});
|
|
4067
|
+
tailwindForLynx.postcss = true;
|
|
4068
|
+
const compiledByTailwind = (result)=>result.messages.some((message)=>message.plugin === TAILWIND_POSTCSS);
|
|
4069
|
+
const lowerForLynx = (root, createRule)=>{
|
|
4070
|
+
flattenNesting(root);
|
|
4071
|
+
unwrapLayers(root);
|
|
4072
|
+
const registrations = takePropertyRegistrations(root);
|
|
4073
|
+
const defaults = new Map(registrations);
|
|
4074
|
+
const channelVariables = colorChannelVariables(root);
|
|
4075
|
+
root.walkRules((rule)=>{
|
|
4076
|
+
const inKeyframes = rule.parent?.type === 'atrule' && /keyframes$/i.test(rule.parent.name);
|
|
4077
|
+
if (!inKeyframes && !lowerSelectors(rule)) return void rule.remove();
|
|
4078
|
+
if (lowerDeclarations(rule, channelVariables).composesTransform) {
|
|
4079
|
+
for (const [name, value] of TRANSFORM_DEFAULTS)if (!defaults.has(name)) defaults.set(name, value);
|
|
4080
|
+
}
|
|
4081
|
+
});
|
|
4082
|
+
unwrapLoweredColorMixSupports(root);
|
|
4083
|
+
resolveNestedVariables(root, registrations);
|
|
4084
|
+
lowerTransformVariables(root);
|
|
4085
|
+
completeKeyframes(root);
|
|
4086
|
+
removeEmptyContainers(root);
|
|
4087
|
+
if (defaults.size > 0) {
|
|
4088
|
+
const defaultsRule = createRule('*');
|
|
4089
|
+
for (const [prop, value] of defaults)defaultsRule.append({
|
|
4090
|
+
prop,
|
|
4091
|
+
value
|
|
4092
|
+
});
|
|
4093
|
+
const imports = root.nodes.filter((node)=>'atrule' === node.type && /^(charset|import)$/i.test(node.name));
|
|
4094
|
+
if (imports.length > 0) imports[imports.length - 1].after(defaultsRule);
|
|
4095
|
+
else root.prepend(defaultsRule);
|
|
4096
|
+
}
|
|
4097
|
+
};
|
|
4098
|
+
const colorChannelVariables = (root)=>{
|
|
4099
|
+
const names = new Set();
|
|
4100
|
+
root.walkDecls(/^--.+-rgb$/, ({ prop })=>{
|
|
4101
|
+
names.add(prop.slice(0, -4));
|
|
4102
|
+
});
|
|
4103
|
+
return names;
|
|
4104
|
+
};
|
|
4105
|
+
const unwrapLoweredColorMixSupports = (root)=>{
|
|
4106
|
+
root.walkAtRules(/^supports$/i, (atRule)=>{
|
|
4107
|
+
if (!atRule.params.includes('color-mix(') || !atRule.nodes) return;
|
|
4108
|
+
let mixes = false;
|
|
4109
|
+
atRule.walkDecls((declaration)=>{
|
|
4110
|
+
mixes ||= declaration.value.includes('color-mix(');
|
|
4111
|
+
});
|
|
4112
|
+
if (!mixes) atRule.replaceWith(atRule.nodes);
|
|
4113
|
+
});
|
|
4114
|
+
};
|
|
1757
4115
|
const TAILWIND_CONFIG_FILES = [
|
|
1758
4116
|
'tailwind.config.ts',
|
|
1759
4117
|
'tailwind.config.js',
|
|
1760
4118
|
'tailwind.config.mjs',
|
|
1761
4119
|
'tailwind.config.cjs'
|
|
1762
4120
|
];
|
|
4121
|
+
const isTailwind = (plugin)=>'function' == typeof plugin ? 'tailwindcss' === plugin.name : plugin?.postcssPlugin === 'tailwindcss';
|
|
4122
|
+
const isTailwind4 = (plugin)=>plugin?.postcssPlugin === '@tailwindcss/postcss';
|
|
1763
4123
|
const applyTailwind = (api)=>{
|
|
1764
4124
|
const configFile = findUp(TAILWIND_CONFIG_FILES, process.cwd());
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
4125
|
+
let warned = false;
|
|
4126
|
+
api.modifyRsbuildConfig((config, { mergeRsbuildConfig })=>mergeRsbuildConfig(config, {
|
|
4127
|
+
tools: {
|
|
4128
|
+
postcss: ({ postcssOptions }, { addPlugins })=>{
|
|
4129
|
+
const configured = 'object' == typeof postcssOptions ? postcssOptions.plugins ?? [] : [];
|
|
4130
|
+
if (configFile && !configured.some(isTailwind)) {
|
|
4131
|
+
const require = createRequire(configFile);
|
|
4132
|
+
const { version } = require('tailwindcss/package.json');
|
|
4133
|
+
if (Number.parseInt(version, 10) < 4) {
|
|
4134
|
+
const tailwindcss = require('tailwindcss');
|
|
4135
|
+
addPlugins(tailwindcss({
|
|
4136
|
+
config: configFile
|
|
4137
|
+
}));
|
|
4138
|
+
} else if (!configured.some(isTailwind4) && !warned) {
|
|
4139
|
+
warned = true;
|
|
4140
|
+
api.logger.warn(`Found ${configFile}, but Tailwind CSS ${version} is installed, which doesn't run from a Tailwind config file. List @tailwindcss/postcss in a .postcssrc.json, or run \`ng generate @blotch/angular-lynx:add-tailwind\`.`);
|
|
4141
|
+
}
|
|
4142
|
+
}
|
|
4143
|
+
addPlugins(tailwindForLynx());
|
|
4144
|
+
}
|
|
4145
|
+
}
|
|
4146
|
+
}));
|
|
1772
4147
|
};
|
|
4148
|
+
const DEPRECATED_OPTIONS = [
|
|
4149
|
+
'enableICU',
|
|
4150
|
+
'enableParallelElement',
|
|
4151
|
+
'pipelineSchedulerConfig'
|
|
4152
|
+
];
|
|
4153
|
+
const deprecatedOptionsIn = (options)=>DEPRECATED_OPTIONS.filter((name)=>options?.[name] !== void 0);
|
|
1773
4154
|
const normalizeOptions = (options)=>{
|
|
1774
4155
|
const defaultOptions = {
|
|
1775
4156
|
customCSSInheritanceList: void 0,
|
|
@@ -1779,20 +4160,19 @@ const normalizeOptions = (options)=>{
|
|
|
1779
4160
|
enableCSSInheritance: false,
|
|
1780
4161
|
enableCSSInvalidation: false,
|
|
1781
4162
|
enableCSSSelector: true,
|
|
1782
|
-
enableICU: false,
|
|
1783
4163
|
enableNewGesture: true,
|
|
1784
|
-
enableParallelElement: true,
|
|
1785
4164
|
defaultDisplayLinear: true,
|
|
1786
4165
|
enableRemoveCSSScope: false,
|
|
1787
4166
|
enableSSR: false,
|
|
1788
4167
|
pages: void 0,
|
|
1789
|
-
pipelineSchedulerConfig: 0x00010000,
|
|
1790
4168
|
targetSdkVersion: '3.2',
|
|
1791
4169
|
defaultOverflowVisible: true,
|
|
1792
4170
|
removeDescendantSelectorScope: false,
|
|
1793
4171
|
experimental_isLazyBundle: false
|
|
1794
4172
|
};
|
|
1795
|
-
|
|
4173
|
+
const normalized = Object.assign(defaultOptions, options);
|
|
4174
|
+
for (const name of DEPRECATED_OPTIONS)delete normalized[name];
|
|
4175
|
+
return normalized;
|
|
1796
4176
|
};
|
|
1797
4177
|
const pluginAngularLynx = (options)=>({
|
|
1798
4178
|
name: 'lynx:angular',
|
|
@@ -1801,12 +4181,18 @@ const pluginAngularLynx = (options)=>({
|
|
|
1801
4181
|
ANGULAR_CLI_CONTEXT_PLUGIN_NAME
|
|
1802
4182
|
],
|
|
1803
4183
|
setup: async (api)=>{
|
|
4184
|
+
for (const name of deprecatedOptionsIn(options))api.logger.warn(`pluginAngularLynx(): the \`${name}\` option has no effect and will be removed in a future release. Remove it from your config.`);
|
|
1804
4185
|
const normalizedOptions = normalizeOptions(options);
|
|
4186
|
+
const backgroundEntries = createBackgroundEntries({
|
|
4187
|
+
rootPath: api.context.rootPath
|
|
4188
|
+
});
|
|
1805
4189
|
applyCSS(api, normalizedOptions);
|
|
1806
4190
|
applyTailwind(api);
|
|
1807
|
-
|
|
4191
|
+
const appEntries = new Set();
|
|
4192
|
+
applyEntry(api, normalizedOptions, backgroundEntries, appEntries);
|
|
1808
4193
|
applyLayers(api);
|
|
1809
|
-
|
|
4194
|
+
applyResolve(api);
|
|
4195
|
+
const angularRules = applyAngularRules(api, normalizedOptions, backgroundEntries, appEntries);
|
|
1810
4196
|
applyGenerator(api);
|
|
1811
4197
|
applySplitChunksRule(api, normalizedOptions);
|
|
1812
4198
|
applyDevLogger(api);
|