@wix/zero-config-implementation 1.25.0 → 1.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/extraction-types.d.ts +7 -0
- package/dist/index.d.ts +12 -13
- package/dist/index.js +8159 -8139
- package/dist/information-extractors/css/types.d.ts +2 -0
- package/dist/manifest-pipeline.d.ts +3 -9
- package/dist/module-loader.d.ts +12 -5
- package/package.json +2 -2
- package/src/extraction-types.ts +8 -0
- package/src/index.ts +83 -101
- package/src/information-extractors/css/parse.ts +3 -2
- package/src/information-extractors/css/selector-matcher.ts +46 -21
- package/src/information-extractors/css/types.ts +2 -0
- package/src/manifest-pipeline.ts +53 -46
- package/src/module-loader.ts +24 -19
|
@@ -2,18 +2,13 @@ import { ComponentInfo } from './information-extractors/ts';
|
|
|
2
2
|
import { RunExtractorsOptions, CoupledComponentInfo } from './information-extractors/react';
|
|
3
3
|
import { CSSParserAPI } from './information-extractors/css';
|
|
4
4
|
import { ComponentType } from 'react';
|
|
5
|
-
|
|
6
|
-
export interface ExtractionWarning {
|
|
7
|
-
componentName: string;
|
|
8
|
-
phase: 'render' | 'coupling' | 'css' | 'loader' | 'conversion';
|
|
9
|
-
error: string;
|
|
10
|
-
stack?: string;
|
|
11
|
-
}
|
|
5
|
+
import { ExtractionError } from './extraction-types';
|
|
12
6
|
export interface ExtractedCssInfo {
|
|
13
7
|
filePath: string;
|
|
14
8
|
api: CSSParserAPI;
|
|
15
9
|
properties: Map<string, string>;
|
|
16
10
|
customProperties: Map<string, string>;
|
|
11
|
+
isCssModule: boolean;
|
|
17
12
|
}
|
|
18
13
|
export interface ComponentInfoWithCss extends CoupledComponentInfo {
|
|
19
14
|
css: ExtractedCssInfo[];
|
|
@@ -22,7 +17,6 @@ export interface ComponentInfoWithCss extends CoupledComponentInfo {
|
|
|
22
17
|
/** The result of processing a single component through the manifest pipeline. */
|
|
23
18
|
export interface ProcessComponentResult {
|
|
24
19
|
component: ComponentInfoWithCss;
|
|
25
|
-
warnings: ExtractionWarning[];
|
|
26
20
|
}
|
|
27
21
|
/**
|
|
28
22
|
* Processes a single component through the full manifest pipeline:
|
|
@@ -32,4 +26,4 @@ export interface ProcessComponentResult {
|
|
|
32
26
|
* encountered during processing. Always returns a component, falling back
|
|
33
27
|
* to minimal info (without DOM coupling) when rendering fails.
|
|
34
28
|
*/
|
|
35
|
-
export declare function processComponent(componentInfo: ComponentInfo, loadComponent: (componentName: string) => ComponentType<unknown> | null, cssImportPaths: string[], loaderHasError
|
|
29
|
+
export declare function processComponent(componentInfo: ComponentInfo, loadComponent: (componentName: string) => ComponentType<unknown> | null, cssImportPaths: string[], loaderHasError: boolean, report: (error: ExtractionError) => void, options?: RunExtractorsOptions): ProcessComponentResult;
|
package/dist/module-loader.d.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { ResultAsync } from 'neverthrow';
|
|
2
2
|
import { ComponentType } from 'react';
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Structured failure from `loadModule` when both ESM import and CJS require fail.
|
|
5
|
+
* Carries each error separately so callers can report them independently.
|
|
6
|
+
*/
|
|
7
|
+
export interface LoadModuleFailure {
|
|
8
|
+
/** The ESM import error, or null when no ESM was attempted (e.g. empty path). */
|
|
9
|
+
esmError: Error | null;
|
|
10
|
+
/** The CJS require error, or a generic error for the empty-path case. */
|
|
11
|
+
cjsError: Error;
|
|
12
|
+
}
|
|
5
13
|
/**
|
|
6
14
|
* Attempts to load a module, first via ESM `import()`, then via CJS `require`.
|
|
7
15
|
*
|
|
@@ -13,8 +21,7 @@ type IoErrorInstance = InstanceType<typeof IoError>;
|
|
|
13
21
|
*
|
|
14
22
|
* @param entryPath - Absolute path to the module entry point.
|
|
15
23
|
* @returns A `ResultAsync` containing the module exports on success.
|
|
16
|
-
* @errors {
|
|
24
|
+
* @errors {LoadModuleFailure} When both ESM import and CJS require fail.
|
|
17
25
|
*/
|
|
18
|
-
export declare function loadModule(entryPath: string): ResultAsync<Record<string, unknown>,
|
|
26
|
+
export declare function loadModule(entryPath: string): ResultAsync<Record<string, unknown>, LoadModuleFailure>;
|
|
19
27
|
export declare function findComponent(moduleExports: Record<string, unknown>, name: string): ComponentType<unknown> | null;
|
|
20
|
-
export {};
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"registry": "https://registry.npmjs.org/",
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"version": "1.
|
|
7
|
+
"version": "1.27.0",
|
|
8
8
|
"description": "Core library for extracting component manifests from JS and CSS files",
|
|
9
9
|
"type": "module",
|
|
10
10
|
"main": "dist/index.js",
|
|
@@ -83,5 +83,5 @@
|
|
|
83
83
|
]
|
|
84
84
|
}
|
|
85
85
|
},
|
|
86
|
-
"falconPackageHash": "
|
|
86
|
+
"falconPackageHash": "2e095856ec4492a70d52bef24a3f7ac22639454039660a7869423748"
|
|
87
87
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { BaseError } from './errors'
|
|
2
|
+
|
|
3
|
+
/** A non-fatal issue encountered during component extraction. */
|
|
4
|
+
export interface ExtractionError {
|
|
5
|
+
componentName: string
|
|
6
|
+
phase: 'render' | 'coupling' | 'css' | 'loader' | 'conversion'
|
|
7
|
+
error: InstanceType<typeof BaseError>
|
|
8
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,32 +1,16 @@
|
|
|
1
1
|
import type { EditorReactComponent } from '@wix/zero-config-schema'
|
|
2
|
-
import { Result, ResultAsync } from 'neverthrow'
|
|
2
|
+
import { Result, type ResultAsync, okAsync } from 'neverthrow'
|
|
3
3
|
import type { ComponentType } from 'react'
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import type
|
|
7
|
-
|
|
8
|
-
import { compileTsFile } from './ts-compiler'
|
|
9
|
-
|
|
10
|
-
// Error classes
|
|
11
|
-
import { type NotFoundError, ParseError } from './errors'
|
|
12
|
-
|
|
13
|
-
// Component loader helpers
|
|
14
|
-
import { findComponent, loadModule } from './module-loader'
|
|
15
|
-
|
|
5
|
+
import { toEditorReactComponent } from './converters'
|
|
6
|
+
import { IoError, type NotFoundError, ParseError } from './errors'
|
|
7
|
+
import type { ExtractionError } from './extraction-types'
|
|
16
8
|
import type { RunExtractorsOptions } from './information-extractors/react'
|
|
17
|
-
|
|
9
|
+
import { extractCssImports, extractDefaultComponentInfo } from './information-extractors/ts'
|
|
18
10
|
import { processComponent } from './manifest-pipeline'
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
ExtractionWarning,
|
|
23
|
-
ProcessComponentResult,
|
|
24
|
-
} from './manifest-pipeline'
|
|
25
|
-
|
|
26
|
-
export type { EditorReactComponent } from '@wix/zero-config-schema'
|
|
27
|
-
|
|
28
|
-
// Converter
|
|
29
|
-
import { toEditorReactComponent } from './converters'
|
|
11
|
+
import { findComponent, loadModule } from './module-loader'
|
|
12
|
+
import type { LoadModuleFailure } from './module-loader'
|
|
13
|
+
import { compileTsFile } from './ts-compiler'
|
|
30
14
|
|
|
31
15
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
32
16
|
// Types
|
|
@@ -37,15 +21,6 @@ export interface ManifestResult {
|
|
|
37
21
|
errors: ExtractionError[]
|
|
38
22
|
}
|
|
39
23
|
|
|
40
|
-
export type { RunExtractorsOptions } from './information-extractors/react'
|
|
41
|
-
|
|
42
|
-
export interface ExtractionError {
|
|
43
|
-
componentName: string
|
|
44
|
-
phase: 'render' | 'coupling' | 'css' | 'loader' | 'conversion'
|
|
45
|
-
error: string
|
|
46
|
-
stack?: string
|
|
47
|
-
}
|
|
48
|
-
|
|
49
24
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
50
25
|
// Main API
|
|
51
26
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -55,96 +30,100 @@ export interface ExtractionError {
|
|
|
55
30
|
*
|
|
56
31
|
* @param componentPath - Path to the TypeScript source file
|
|
57
32
|
* @param compiledEntryPath - Path to the built JS entry file of the component's package (e.g. dist/index.js)
|
|
58
|
-
* @
|
|
33
|
+
* @param options.onError - Called for each non-fatal extraction error as it occurs
|
|
59
34
|
* @errors
|
|
60
35
|
* - {@link NotFoundError} — Source file does not exist (phase: `compile`)
|
|
61
36
|
* - {@link ParseError} — TypeScript config or component types could not be parsed (phase: `compile` | `extract`)
|
|
62
37
|
*/
|
|
38
|
+
export interface ExtractComponentManifestOptions extends RunExtractorsOptions {
|
|
39
|
+
onError?: (error: ExtractionError) => void
|
|
40
|
+
}
|
|
41
|
+
|
|
63
42
|
export function extractComponentManifest(
|
|
64
43
|
componentPath: string,
|
|
65
44
|
compiledEntryPath: string,
|
|
66
|
-
options?:
|
|
45
|
+
options?: ExtractComponentManifestOptions,
|
|
67
46
|
): ResultAsync<ManifestResult, InstanceType<typeof NotFoundError> | InstanceType<typeof ParseError>> {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
// Surface loader error as a non-fatal error
|
|
118
|
-
if (loaderError) {
|
|
119
|
-
errors.push({
|
|
120
|
-
componentName: componentInfo.componentName,
|
|
47
|
+
const errors: ExtractionError[] = []
|
|
48
|
+
const report = (error: ExtractionError): void => {
|
|
49
|
+
errors.push(error)
|
|
50
|
+
options?.onError?.(error)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Step 1: Compile TypeScript (fatal)
|
|
54
|
+
return compileTsFile(componentPath)
|
|
55
|
+
.andThen((program) => {
|
|
56
|
+
// Step 2: Extract default-exported component types (fatal)
|
|
57
|
+
const safeExtract = Result.fromThrowable(
|
|
58
|
+
(prog: typeof program) => {
|
|
59
|
+
const componentInfo = extractDefaultComponentInfo(prog, componentPath)
|
|
60
|
+
if (!componentInfo) {
|
|
61
|
+
throw new Error(`No default export found in "${componentPath}"`)
|
|
62
|
+
}
|
|
63
|
+
return componentInfo
|
|
64
|
+
},
|
|
65
|
+
(thrown) =>
|
|
66
|
+
new ParseError(
|
|
67
|
+
`Failed to extract component types from "${componentPath}": ${thrown instanceof Error ? thrown.message : String(thrown)}`,
|
|
68
|
+
{ cause: thrown as Error, props: { phase: 'extract' } },
|
|
69
|
+
),
|
|
70
|
+
)
|
|
71
|
+
return safeExtract(program).map((componentInfo) => ({ program, componentInfo }))
|
|
72
|
+
})
|
|
73
|
+
.andThen(({ program, componentInfo }) => {
|
|
74
|
+
const { componentName } = componentInfo
|
|
75
|
+
|
|
76
|
+
// Step 3: Load the compiled package module (non-fatal) — done after TS extraction
|
|
77
|
+
// so componentName is known when reporting failures
|
|
78
|
+
return loadModule(compiledEntryPath)
|
|
79
|
+
.map((moduleExports) => ({
|
|
80
|
+
loadComponent: (name: string) => findComponent(moduleExports, name),
|
|
81
|
+
failure: null as LoadModuleFailure | null,
|
|
82
|
+
}))
|
|
83
|
+
.orElse((failure) => okAsync({ loadComponent: () => null as ComponentType<unknown> | null, failure }))
|
|
84
|
+
.map(({ loadComponent, failure }) => {
|
|
85
|
+
if (failure) {
|
|
86
|
+
if (failure.esmError) {
|
|
87
|
+
report({
|
|
88
|
+
componentName,
|
|
89
|
+
phase: 'loader',
|
|
90
|
+
error: new IoError('ESM import failed', { cause: failure.esmError, props: { phase: 'loader' } }),
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
report({
|
|
94
|
+
componentName,
|
|
121
95
|
phase: 'loader',
|
|
122
|
-
error:
|
|
123
|
-
stack: loaderStack,
|
|
96
|
+
error: new IoError('CJS require failed', { cause: failure.cjsError, props: { phase: 'loader' } }),
|
|
124
97
|
})
|
|
125
98
|
}
|
|
126
99
|
|
|
127
100
|
// Step 4: Extract CSS imports (non-fatal)
|
|
128
101
|
let cssImportPaths: string[] = []
|
|
129
|
-
const
|
|
130
|
-
const cssResult = safeCssImports(program)
|
|
102
|
+
const cssResult = Result.fromThrowable(extractCssImports, (thrown) => thrown)(program)
|
|
131
103
|
if (cssResult.isOk()) {
|
|
132
104
|
cssImportPaths = cssResult.value
|
|
133
105
|
} else {
|
|
134
106
|
const thrown = cssResult.error
|
|
135
|
-
|
|
136
|
-
componentName
|
|
107
|
+
report({
|
|
108
|
+
componentName,
|
|
137
109
|
phase: 'css',
|
|
138
|
-
error:
|
|
139
|
-
|
|
110
|
+
error: new ParseError(
|
|
111
|
+
`Failed to extract CSS imports: ${thrown instanceof Error ? thrown.message : String(thrown)}`,
|
|
112
|
+
{ cause: thrown instanceof Error ? thrown : undefined, props: { phase: 'css' } },
|
|
113
|
+
),
|
|
140
114
|
})
|
|
141
115
|
}
|
|
142
116
|
|
|
143
117
|
// Step 5: Process the default-exported component (non-fatal)
|
|
144
|
-
const processResult = processComponent(
|
|
145
|
-
|
|
118
|
+
const processResult = processComponent(
|
|
119
|
+
componentInfo,
|
|
120
|
+
loadComponent,
|
|
121
|
+
cssImportPaths,
|
|
122
|
+
!!failure,
|
|
123
|
+
report,
|
|
124
|
+
options,
|
|
125
|
+
)
|
|
146
126
|
const component = toEditorReactComponent(processResult.component)
|
|
147
|
-
|
|
148
127
|
return { component, errors }
|
|
149
128
|
})
|
|
150
129
|
})
|
|
@@ -171,6 +150,9 @@ export function extractComponentManifest(
|
|
|
171
150
|
|
|
172
151
|
// ── Tier 1: High-Level API ──────────────────────────────────────────────────
|
|
173
152
|
// extractComponentManifest() is exported above as a named function declaration.
|
|
153
|
+
export type { ExtractionError } from './extraction-types'
|
|
154
|
+
export type { EditorReactComponent } from '@wix/zero-config-schema'
|
|
155
|
+
export type { ComponentInfoWithCss, ExtractedCssInfo, ProcessComponentResult } from './manifest-pipeline'
|
|
174
156
|
|
|
175
157
|
// ── Tier 2: Pipeline Building Blocks ────────────────────────────────────────
|
|
176
158
|
|
|
@@ -187,6 +169,7 @@ export type {
|
|
|
187
169
|
} from './information-extractors/ts/types'
|
|
188
170
|
|
|
189
171
|
/** React render-time extraction */
|
|
172
|
+
export type { RunExtractorsOptions } from './information-extractors/react'
|
|
190
173
|
export {
|
|
191
174
|
runExtractors,
|
|
192
175
|
ExtractorStore,
|
|
@@ -204,8 +187,6 @@ export type {
|
|
|
204
187
|
PropTrackerData,
|
|
205
188
|
PropTrackerExtractorState,
|
|
206
189
|
CssPropertiesData,
|
|
207
|
-
} from './information-extractors/react'
|
|
208
|
-
export type {
|
|
209
190
|
CoupledComponentInfo,
|
|
210
191
|
CoupledProp,
|
|
211
192
|
DOMBinding,
|
|
@@ -231,6 +212,7 @@ export {
|
|
|
231
212
|
|
|
232
213
|
/** Module loader primitives */
|
|
233
214
|
export { loadModule, findComponent } from './module-loader'
|
|
215
|
+
export type { LoadModuleFailure } from './module-loader'
|
|
234
216
|
|
|
235
217
|
// ── Tier 3: Low-Level Renderer ──────────────────────────────────────────────
|
|
236
218
|
|
|
@@ -345,7 +345,8 @@ function extractPropertyNameAndValue(decl: LightningDecl): CSSProperty | null {
|
|
|
345
345
|
if (name) {
|
|
346
346
|
const value = propertyValueToString(decl)
|
|
347
347
|
if (value) {
|
|
348
|
-
|
|
348
|
+
const varRefs = extractVarNamesFromTokens(unparsedValue.value ?? [])
|
|
349
|
+
return { name, value, ...(varRefs.length > 0 && { varRefs }) }
|
|
349
350
|
}
|
|
350
351
|
}
|
|
351
352
|
return null
|
|
@@ -412,7 +413,7 @@ function serializeCustomPropertyValue(valueArray: unknown[]): string {
|
|
|
412
413
|
} else if (tokenValue.type === 'dimension') {
|
|
413
414
|
parts.push(`${tokenValue.value}${tokenValue.unit}`)
|
|
414
415
|
} else if (tokenValue.type === 'white-space') {
|
|
415
|
-
parts.
|
|
416
|
+
// skip — parts.join(' ') already handles separation
|
|
416
417
|
}
|
|
417
418
|
}
|
|
418
419
|
}
|
|
@@ -4,6 +4,45 @@ import type { ExtractedCssInfo } from '../../index'
|
|
|
4
4
|
import type { ExtractedElement } from '../react/extractors/core/tree-builder'
|
|
5
5
|
import type { CSSProperty, CssSelectorMatch, MatchedCssData } from './types'
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Matches selectors composed entirely of one or more class selectors with no combinators,
|
|
9
|
+
* pseudo-classes, tag names, or IDs — e.g. `.wrapper`, `.wrapper.active`.
|
|
10
|
+
* Used to identify selectors eligible for CSS module prefix matching.
|
|
11
|
+
*/
|
|
12
|
+
const SIMPLE_CLASS_SELECTOR_PATTERN = /^(\.[a-zA-Z][\w-]*)+$/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Finds DOM elements matching a CSS selector, with special handling for CSS module files.
|
|
16
|
+
*
|
|
17
|
+
* For CSS module files, class names in the source CSS (e.g. `.wrapper`) are hashed at build
|
|
18
|
+
* time into names like `wrapper_AbCdE`. When the selector is a simple class selector
|
|
19
|
+
* (e.g. `.wrapper` or `.wrapper.active`), this function matches elements whose class list
|
|
20
|
+
* contains a class that exactly equals the local name OR starts with `localName_` /
|
|
21
|
+
* `_localName_` (the two most common Vite CSS module hash patterns).
|
|
22
|
+
*
|
|
23
|
+
* For non-module files, or for selectors that contain combinators or non-class parts
|
|
24
|
+
* (e.g. `div .wrapper`, `#id`), falls back to a direct Cheerio query.
|
|
25
|
+
*/
|
|
26
|
+
function findMatchingElements($: cheerio.CheerioAPI, domSelector: string, isCssModule: boolean) {
|
|
27
|
+
if (isCssModule && SIMPLE_CLASS_SELECTOR_PATTERN.test(domSelector)) {
|
|
28
|
+
const classNames = domSelector.split('.').filter(Boolean)
|
|
29
|
+
return $('[class]').filter((_index, element) => {
|
|
30
|
+
const classAttr = $(element).attr('class')
|
|
31
|
+
if (!classAttr) return false
|
|
32
|
+
const elementClasses = classAttr.trim().split(/\s+/)
|
|
33
|
+
return classNames.every((localName) =>
|
|
34
|
+
elementClasses.some(
|
|
35
|
+
(elementClass) =>
|
|
36
|
+
elementClass === localName ||
|
|
37
|
+
elementClass.startsWith(`${localName}_`) ||
|
|
38
|
+
elementClass.startsWith(`_${localName}_`),
|
|
39
|
+
),
|
|
40
|
+
)
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
return $(domSelector)
|
|
44
|
+
}
|
|
45
|
+
|
|
7
46
|
export function matchCssSelectors(
|
|
8
47
|
html: string,
|
|
9
48
|
elements: ExtractedElement[],
|
|
@@ -28,8 +67,8 @@ export function matchCssSelectors(
|
|
|
28
67
|
if (!domSelector) continue
|
|
29
68
|
|
|
30
69
|
try {
|
|
31
|
-
|
|
32
|
-
const traceId = $(
|
|
70
|
+
findMatchingElements($, domSelector, cssInfo.isCssModule).each((_index, element) => {
|
|
71
|
+
const traceId = $(element).attr(TRACE_ATTR)
|
|
33
72
|
if (!traceId) return
|
|
34
73
|
|
|
35
74
|
// Use reduce to separate regular and custom properties in one pass
|
|
@@ -37,13 +76,13 @@ export function matchCssSelectors(
|
|
|
37
76
|
regular: CSSProperty[]
|
|
38
77
|
custom: Record<string, string>
|
|
39
78
|
}>(
|
|
40
|
-
(
|
|
79
|
+
(accumulator, prop) => {
|
|
41
80
|
if (prop.name.startsWith('--')) {
|
|
42
|
-
|
|
81
|
+
accumulator.custom[prop.name] = prop.value
|
|
43
82
|
} else {
|
|
44
|
-
|
|
83
|
+
accumulator.regular.push(prop)
|
|
45
84
|
}
|
|
46
|
-
return
|
|
85
|
+
return accumulator
|
|
47
86
|
},
|
|
48
87
|
{ regular: [], custom: {} },
|
|
49
88
|
)
|
|
@@ -55,7 +94,7 @@ export function matchCssSelectors(
|
|
|
55
94
|
|
|
56
95
|
// Track which CSS custom properties are used (via var()) by this element
|
|
57
96
|
for (const regularProp of regular) {
|
|
58
|
-
for (const varName of
|
|
97
|
+
for (const varName of regularProp.varRefs ?? []) {
|
|
59
98
|
const traceIdSet = varUsedByTraceId.get(varName) ?? new Set()
|
|
60
99
|
traceIdSet.add(traceId)
|
|
61
100
|
varUsedByTraceId.set(varName, traceIdSet)
|
|
@@ -81,20 +120,6 @@ export function matchCssSelectors(
|
|
|
81
120
|
}
|
|
82
121
|
}
|
|
83
122
|
|
|
84
|
-
/**
|
|
85
|
-
* Extracts all CSS custom property names referenced via var() in a property value string.
|
|
86
|
-
*/
|
|
87
|
-
function extractVarRefs(value: string): string[] {
|
|
88
|
-
const varNames: string[] = []
|
|
89
|
-
const varPattern = /var\(\s*(--[\w-]+)/g
|
|
90
|
-
let varMatch = varPattern.exec(value)
|
|
91
|
-
while (varMatch !== null) {
|
|
92
|
-
varNames.push(varMatch[1])
|
|
93
|
-
varMatch = varPattern.exec(value)
|
|
94
|
-
}
|
|
95
|
-
return varNames
|
|
96
|
-
}
|
|
97
|
-
|
|
98
123
|
function enrichElements(
|
|
99
124
|
elements: ExtractedElement[],
|
|
100
125
|
matchesByTraceId: Map<string, CssSelectorMatch[]>,
|