@wix/zero-config-implementation 1.70.0 → 1.72.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/{index-D_XmjZkE.js → index-CSi4SZpQ.js} +1 -1
- package/dist/{index-DnxDZx90.js → index-CdHu4-o-.js} +20462 -18723
- package/dist/index.d.ts +15 -8
- package/dist/index.js +1 -1
- package/package.json +4 -3
- package/src/__fixtures__/cjs-ref-element-entry.cjs +1 -0
- package/src/__fixtures__/cjs-ref-element-lazy-entry.cjs +3 -0
- package/src/__fixtures__/cjs-ref-element-order-entry.cjs +8 -0
- package/src/__fixtures__/cjs-ref-element-order-target.cjs +7 -0
- package/src/__fixtures__/cjs-ref-element-target.cjs +5 -0
- package/src/__fixtures__/esm-ref-element-entry.mjs +3 -0
- package/src/component-renderer.ts +12 -9
- package/src/converters/data-item-builder.test.ts +33 -0
- package/src/converters/to-editor-component.ts +24 -6
- package/src/index.ts +121 -54
- package/src/information-extractors/react/extractors/core/tree-builder.ts +3 -3
- package/src/information-extractors/react/extractors/core/types.ts +4 -5
- package/src/information-extractors/react/extractors/css-properties.ts +2 -0
- package/src/information-extractors/react/extractors/prop-tracker.test.ts +251 -0
- package/src/information-extractors/react/extractors/prop-tracker.ts +78 -14
- package/src/information-extractors/react/types.ts +1 -1
- package/src/information-extractors/react/utils/mock-generator.test.ts +131 -0
- package/src/information-extractors/react/utils/mock-generator.ts +38 -13
- package/src/information-extractors/ts/components.test.ts +52 -0
- package/src/information-extractors/ts/components.ts +3 -1
- package/src/manifest-pipeline.ts +19 -14
- package/src/module-loader.test.ts +150 -0
- package/src/module-loader.ts +48 -8
- package/src/react-runtime-interceptor.ts +64 -0
- package/src/react-runtime-loader.ts +656 -0
- package/src/ref-elements/component-tag.ts +105 -0
- package/src/ref-elements/context.test.ts +179 -0
- package/src/ref-elements/context.ts +280 -0
- package/src/ref-elements/eligible-paths.ts +45 -0
- package/src/ref-elements/module-resolution.test.ts +50 -0
- package/src/ref-elements/module-resolution.ts +21 -0
- package/src/ref-elements/module-specifier.ts +17 -0
- package/src/ref-elements/path-utils.test.ts +14 -0
- package/src/ref-elements/path-utils.ts +55 -0
- package/src/ref-elements/types.ts +17 -0
- package/src/utils/css-class.ts +15 -0
- package/src/jsx-runtime-interceptor.ts +0 -245
package/dist/index.d.ts
CHANGED
|
@@ -302,7 +302,10 @@ export declare interface CoupledComponentInfo {
|
|
|
302
302
|
componentName: string;
|
|
303
303
|
props: Record<string, CoupledProp>;
|
|
304
304
|
elements: ExtractedElement[];
|
|
305
|
-
innerElementProps?: Map<string,
|
|
305
|
+
innerElementProps?: Map<string, {
|
|
306
|
+
elementPropsPath: string;
|
|
307
|
+
props: Record<string, CoupledProp>;
|
|
308
|
+
}>;
|
|
306
309
|
propUsages: TrackingStores['propUsages'];
|
|
307
310
|
}
|
|
308
311
|
|
|
@@ -318,13 +321,12 @@ export declare interface CoupledProp extends PropInfo {
|
|
|
318
321
|
*/
|
|
319
322
|
export declare function createCssPropertiesExtractor(): ReactExtractor;
|
|
320
323
|
|
|
321
|
-
/**
|
|
322
|
-
* Event emitted for each DOM element created during render.
|
|
323
|
-
*/
|
|
324
324
|
export declare interface CreateElementEvent {
|
|
325
|
-
|
|
325
|
+
type: unknown;
|
|
326
|
+
isDomElement: boolean;
|
|
327
|
+
tag?: string;
|
|
326
328
|
props: Record<string, unknown>;
|
|
327
|
-
traceId
|
|
329
|
+
traceId?: string;
|
|
328
330
|
children: unknown[];
|
|
329
331
|
store: ExtractorStore;
|
|
330
332
|
}
|
|
@@ -337,13 +339,18 @@ export declare interface CreateElementListener {
|
|
|
337
339
|
* Creates a prop tracker extractor that:
|
|
338
340
|
* 1. Generates spy-instrumented mock props during beforeRender
|
|
339
341
|
* 2. Detects spy markers in element props during onCreateElement
|
|
340
|
-
* 3.
|
|
342
|
+
* 3. Tracks runtime refElement markers from composite components to rendered DOM
|
|
343
|
+
* 4. Writes prop usage data to the store namespaced by 'prop-tracker'
|
|
341
344
|
*/
|
|
342
|
-
export declare function createPropTrackerExtractor(): {
|
|
345
|
+
export declare function createPropTrackerExtractor(options?: CreatePropTrackerExtractorOptions): {
|
|
343
346
|
extractor: ReactExtractor;
|
|
344
347
|
state: PropTrackerExtractorState;
|
|
345
348
|
};
|
|
346
349
|
|
|
350
|
+
declare interface CreatePropTrackerExtractorOptions {
|
|
351
|
+
eligiblePaths?: string[];
|
|
352
|
+
}
|
|
353
|
+
|
|
347
354
|
/**
|
|
348
355
|
* `ErrorClass.subclass()`
|
|
349
356
|
*
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { B as t, D as e, E as o, I as n, N as c, P as l, R as i, a as p, V as E, b as m, c as x, d as f, e as d, f as u, h as C, i as I, j as k, k as y, l as A, m as D, n as P, o as R, p as h, q as B, r as M, s as T, t as b, w } from "./index-
|
|
1
|
+
import { B as t, D as e, E as o, I as n, N as c, P as l, R as i, a as p, V as E, b as m, c as x, d as f, e as d, f as u, h as C, i as I, j as k, k as y, l as A, m as D, n as P, o as R, p as h, q as B, r as M, s as T, t as b, w } from "./index-CdHu4-o-.js";
|
|
2
2
|
import "react";
|
|
3
3
|
export {
|
|
4
4
|
t as BaseError,
|
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.72.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",
|
|
@@ -40,7 +40,8 @@
|
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@wix/builder-services-wrapper": "^1.42.0",
|
|
43
|
-
"@wix/react-component-schema": "1.7.0"
|
|
43
|
+
"@wix/react-component-schema": "1.7.0",
|
|
44
|
+
"import-meta-resolve": "^4.2.0"
|
|
44
45
|
},
|
|
45
46
|
"devDependencies": {
|
|
46
47
|
"@faker-js/faker": "^10.2.0",
|
|
@@ -81,5 +82,5 @@
|
|
|
81
82
|
]
|
|
82
83
|
}
|
|
83
84
|
},
|
|
84
|
-
"falconPackageHash": "
|
|
85
|
+
"falconPackageHash": "2d1621ee1db1cc5a90b528fc0d45129b0534a3ba693b766403f23b2f"
|
|
85
86
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('./cjs-ref-element-target.cjs')
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* Four complementary layers ensure interception regardless of how JSX is compiled
|
|
11
11
|
* AND regardless of how many React module instances are loaded in the process:
|
|
12
12
|
*
|
|
13
|
-
* 1. **Node.js ESM loader hook** — registered by `
|
|
13
|
+
* 1. **Node.js ESM loader hook** — registered by `ensureReactRuntimeLoader()` in
|
|
14
14
|
* `module-loader.ts` before any user bundle is imported. Redirects
|
|
15
15
|
* `react/jsx-runtime` and `react/jsx-dev-runtime` bare-specifier imports to
|
|
16
16
|
* an in-memory `data:` URL interceptor that reads mutable state from
|
|
@@ -75,7 +75,7 @@ import {
|
|
|
75
75
|
getOriginals,
|
|
76
76
|
setCreateElementInterceptor,
|
|
77
77
|
setJsxInterceptors,
|
|
78
|
-
} from './
|
|
78
|
+
} from './react-runtime-interceptor'
|
|
79
79
|
|
|
80
80
|
export const TRACE_ATTR = 'data-trace-id'
|
|
81
81
|
|
|
@@ -104,18 +104,17 @@ function createInterceptor(
|
|
|
104
104
|
store: ExtractorStore,
|
|
105
105
|
): ElementCreator {
|
|
106
106
|
return (type, elementProps, ...rest) => {
|
|
107
|
-
if (!isDOMTag(type)) {
|
|
108
|
-
return original(type, elementProps, ...rest)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
107
|
const props = (elementProps ?? {}) as Record<string, unknown>
|
|
112
|
-
const
|
|
108
|
+
const isDomElement = isDOMTag(type)
|
|
109
|
+
const traceId = isDomElement ? getNextId() : undefined
|
|
113
110
|
|
|
114
111
|
// Children location differs: createElement uses rest params, jsx/jsxs uses props.children
|
|
115
112
|
const children = rest.length > 0 ? rest : props.children ? [props.children] : []
|
|
116
113
|
|
|
117
114
|
const event: CreateElementEvent = {
|
|
118
|
-
|
|
115
|
+
type,
|
|
116
|
+
isDomElement,
|
|
117
|
+
tag: isDomElement ? type : undefined,
|
|
119
118
|
props: { ...props, children },
|
|
120
119
|
traceId,
|
|
121
120
|
children: children as unknown[],
|
|
@@ -124,6 +123,10 @@ function createInterceptor(
|
|
|
124
123
|
|
|
125
124
|
listeners.forEach((listener) => listener.onCreateElement(event))
|
|
126
125
|
|
|
126
|
+
if (!isDomElement || !traceId) {
|
|
127
|
+
return original(type, elementProps, ...rest)
|
|
128
|
+
}
|
|
129
|
+
|
|
127
130
|
const stampedProps = { ...props, [TRACE_ATTR]: traceId }
|
|
128
131
|
return original(type, stampedProps, ...rest)
|
|
129
132
|
}
|
|
@@ -248,7 +251,7 @@ export function renderWithExtractors(
|
|
|
248
251
|
try {
|
|
249
252
|
// @ts-expect-error Monkey-patch createElement for default-import callers
|
|
250
253
|
React.createElement = interceptedCreateElement
|
|
251
|
-
// The data: URL react shim (registered by
|
|
254
|
+
// The data: URL react shim (registered by ensureReactRuntimeLoader) reads this state on every
|
|
252
255
|
// createElement call, covering Rspack/webpack bundles that use `import * as React from 'react'`.
|
|
253
256
|
setCreateElementInterceptor(interceptedCreateElement)
|
|
254
257
|
// Use the interceptor API for jsx-runtime (includes jsxDEV for dev mode)
|
|
@@ -78,3 +78,36 @@ describe('buildDataItem — arrayItems oneof branching', () => {
|
|
|
78
78
|
expect(arrayItems?.dataItem).toBeUndefined()
|
|
79
79
|
})
|
|
80
80
|
})
|
|
81
|
+
|
|
82
|
+
describe('buildDataItem — container dataType', () => {
|
|
83
|
+
const buildProp = (name: string, type: string, resolvedType: ResolvedType): PropInfo => ({
|
|
84
|
+
name,
|
|
85
|
+
type,
|
|
86
|
+
required: false,
|
|
87
|
+
resolvedType,
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('maps a React `ReactNode` semantic type to dataType container', () => {
|
|
91
|
+
const result = buildDataItem(
|
|
92
|
+
buildProp('content', 'ReactNode', { kind: 'semantic', value: 'ReactNode', source: '@types/react' }),
|
|
93
|
+
)
|
|
94
|
+
expect(result.isOk()).toBe(true)
|
|
95
|
+
expect(result._unsafeUnwrap().dataType).toBe('container')
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
it('maps a React `ReactElement` semantic type to dataType container', () => {
|
|
99
|
+
const result = buildDataItem(
|
|
100
|
+
buildProp('icon', 'ReactElement', { kind: 'semantic', value: 'ReactElement', source: 'react' }),
|
|
101
|
+
)
|
|
102
|
+
expect(result.isOk()).toBe(true)
|
|
103
|
+
expect(result._unsafeUnwrap().dataType).toBe('container')
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
it('maps a Wix `Container` semantic type to dataType container', () => {
|
|
107
|
+
const result = buildDataItem(
|
|
108
|
+
buildProp('children', 'Container', { kind: 'semantic', value: 'Container', source: '@wix/editor-react-types' }),
|
|
109
|
+
)
|
|
110
|
+
expect(result.isOk()).toBe(true)
|
|
111
|
+
expect(result._unsafeUnwrap().dataType).toBe('container')
|
|
112
|
+
})
|
|
113
|
+
})
|
|
@@ -20,7 +20,9 @@ import type {
|
|
|
20
20
|
TrackingStores,
|
|
21
21
|
} from '../information-extractors/react'
|
|
22
22
|
import { getDefaultDisplayForTag, resolveDisplayValue } from '../information-extractors/react'
|
|
23
|
-
import {
|
|
23
|
+
import { buildRefElementManifestKey } from '../ref-elements/path-utils'
|
|
24
|
+
import type { RefElementMatch } from '../ref-elements/types'
|
|
25
|
+
import { findPreferredSemanticClass, normalizeClassNames } from '../utils/css-class'
|
|
24
26
|
import { resolveLonghand } from './css-longhand-resolver'
|
|
25
27
|
import { type CustomClassTrigger, buildCustomStatesBlock } from './custom-states-builder'
|
|
26
28
|
import { buildDataItem } from './data-item-builder'
|
|
@@ -102,12 +104,12 @@ function buildEditorElement(
|
|
|
102
104
|
|
|
103
105
|
function getSemanticBlockName(element: ExtractedElement | undefined): string | undefined {
|
|
104
106
|
if (!element?.attributes.class) return undefined
|
|
105
|
-
return findPreferredSemanticClass(element.attributes.class
|
|
107
|
+
return findPreferredSemanticClass(normalizeClassNames(element.attributes.class))
|
|
106
108
|
}
|
|
107
109
|
|
|
108
110
|
function buildSelector(rootElement?: ExtractedElement): string {
|
|
109
111
|
if (rootElement?.attributes.class) {
|
|
110
|
-
const semanticClass = findPreferredSemanticClass(rootElement.attributes.class
|
|
112
|
+
const semanticClass = findPreferredSemanticClass(normalizeClassNames(rootElement.attributes.class))
|
|
111
113
|
if (semanticClass) return `.${semanticClass}`
|
|
112
114
|
}
|
|
113
115
|
return rootElement?.tag ?? ''
|
|
@@ -141,16 +143,31 @@ function buildElements(
|
|
|
141
143
|
customClassTriggers: CustomClassTrigger[],
|
|
142
144
|
innerElementProps?: CoupledComponentInfo['innerElementProps'],
|
|
143
145
|
propUsages?: TrackingStores['propUsages'],
|
|
146
|
+
parentElementPropsPath?: string,
|
|
144
147
|
): Record<string, ElementItem> {
|
|
145
148
|
const result: Record<string, ElementItem> = {}
|
|
146
149
|
|
|
147
150
|
for (const element of elements) {
|
|
148
|
-
const
|
|
149
|
-
const
|
|
151
|
+
const innerEntry = innerElementProps?.get(element.traceId)
|
|
152
|
+
const refElementMatch = element.extractorData.get('ref-element') as RefElementMatch | undefined
|
|
153
|
+
|
|
154
|
+
if (refElementMatch) {
|
|
155
|
+
result[buildRefElementManifestKey(refElementMatch.elementPropsPath, parentElementPropsPath)] = {
|
|
156
|
+
elementType: ELEMENTS.ELEMENT_TYPE.refElement,
|
|
157
|
+
refElement: {
|
|
158
|
+
selector: refElementMatch.selector,
|
|
159
|
+
type: refElementMatch.refComponentType,
|
|
160
|
+
},
|
|
161
|
+
}
|
|
162
|
+
continue
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const semanticClass = getSemanticBlockName(element)
|
|
166
|
+
|
|
167
|
+
const data = innerEntry && propUsages ? buildData(innerEntry.props, propUsages) : undefined
|
|
150
168
|
const cssProps = buildCssProperties(element)
|
|
151
169
|
const cssCustomProps = nearestCommonAncestorCustomProps.get(element.traceId) ?? {}
|
|
152
170
|
|
|
153
|
-
const semanticClass = getSemanticBlockName(element)
|
|
154
171
|
// Inner-element custom states come from custom-class triggers only; prop
|
|
155
172
|
// triggers (`ElementState<>`) are component-level and attach to the root.
|
|
156
173
|
const states = mergeStates(
|
|
@@ -180,6 +197,7 @@ function buildElements(
|
|
|
180
197
|
customClassTriggers,
|
|
181
198
|
innerElementProps,
|
|
182
199
|
propUsages,
|
|
200
|
+
innerEntry?.elementPropsPath ?? parentElementPropsPath,
|
|
183
201
|
)
|
|
184
202
|
: undefined,
|
|
185
203
|
},
|
package/src/index.ts
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import { WixServicesWrapper } from '@wix/builder-services-wrapper'
|
|
2
2
|
import type { EditorReactComponent } from '@wix/react-component-schema'
|
|
3
|
-
import { Result,
|
|
3
|
+
import { Result, ResultAsync, errAsync, okAsync } from 'neverthrow'
|
|
4
4
|
import React, { type ComponentType } from 'react'
|
|
5
5
|
|
|
6
6
|
import { toEditorReactComponent } from './converters'
|
|
7
|
-
import { IoError, type NotFoundError, ParseError } from './errors'
|
|
7
|
+
import { BaseError, IoError, type NotFoundError, ParseError } from './errors'
|
|
8
8
|
import type { ExtractionError } from './extraction-types'
|
|
9
9
|
import type { RunExtractorsOptions } from './information-extractors/react'
|
|
10
10
|
import { extractCssImports, extractDefaultComponentInfo } from './information-extractors/ts'
|
|
11
|
+
import type { ComponentInfo } from './information-extractors/ts/types'
|
|
11
12
|
import { processComponent } from './manifest-pipeline'
|
|
12
|
-
import { findComponent, findDefaultComponent,
|
|
13
|
+
import { findComponent, findDefaultComponent, loadModuleForExtraction } from './module-loader'
|
|
13
14
|
import type { LoadModuleFailure } from './module-loader'
|
|
15
|
+
import { buildRefElementContext } from './ref-elements/context'
|
|
16
|
+
import type { RefElementContext } from './ref-elements/types'
|
|
14
17
|
import { compileTsFile } from './ts-compiler'
|
|
15
18
|
|
|
16
19
|
const defaultWrapper = (Component: ComponentType<unknown>): ComponentType<unknown> => {
|
|
@@ -65,7 +68,6 @@ export function extractComponentManifestResult(
|
|
|
65
68
|
...options,
|
|
66
69
|
wrapper: options?.wrapper ?? defaultWrapper,
|
|
67
70
|
}
|
|
68
|
-
|
|
69
71
|
// Step 1: Compile TypeScript (fatal)
|
|
70
72
|
return compileTsFile(componentPath)
|
|
71
73
|
.andThen((program) => {
|
|
@@ -89,66 +91,131 @@ export function extractComponentManifestResult(
|
|
|
89
91
|
.andThen(({ program, componentInfo }) => {
|
|
90
92
|
const { componentName } = componentInfo
|
|
91
93
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
94
|
+
return ResultAsync.fromPromise(
|
|
95
|
+
buildRefElementContext(program, componentPath, componentInfo, compiledEntryPath),
|
|
96
|
+
(thrown) =>
|
|
97
|
+
new ParseError(
|
|
98
|
+
`Failed to build the ref-element context for "${componentPath}": ${thrown instanceof Error ? thrown.message : String(thrown)}`,
|
|
99
|
+
{ cause: thrown instanceof Error ? thrown : undefined, props: { phase: 'extract' } },
|
|
100
|
+
),
|
|
101
|
+
).andThen((refElementContext) =>
|
|
102
|
+
// Step 3: Load the compiled package module (non-fatal) — done after TS extraction
|
|
103
|
+
// so componentName is known when reporting failures
|
|
104
|
+
loadModuleForExtraction(compiledEntryPath, refElementContext.runtimeModules)
|
|
105
|
+
.map(({ cleanup, moduleExports }) => ({
|
|
106
|
+
loadComponent: (name: string) => findComponent(moduleExports, name) ?? findDefaultComponent(moduleExports),
|
|
107
|
+
failure: null as LoadModuleFailure | null,
|
|
108
|
+
cleanup,
|
|
109
|
+
}))
|
|
110
|
+
.orElse((failure) =>
|
|
111
|
+
okAsync({
|
|
112
|
+
loadComponent: () => null as ComponentType<unknown> | null,
|
|
113
|
+
cleanup: async () => {},
|
|
114
|
+
failure,
|
|
115
|
+
}),
|
|
116
|
+
)
|
|
117
|
+
.andThen(({ cleanup, failure, loadComponent }) => {
|
|
118
|
+
if (failure) {
|
|
119
|
+
if (failure.esmError) {
|
|
120
|
+
report({
|
|
121
|
+
componentName,
|
|
122
|
+
phase: 'loader',
|
|
123
|
+
error: new IoError('ESM import failed', { cause: failure.esmError, props: { phase: 'loader' } }),
|
|
124
|
+
})
|
|
125
|
+
}
|
|
103
126
|
report({
|
|
104
127
|
componentName,
|
|
105
128
|
phase: 'loader',
|
|
106
|
-
error: new IoError('
|
|
129
|
+
error: new IoError('CJS require failed', { cause: failure.cjsError, props: { phase: 'loader' } }),
|
|
107
130
|
})
|
|
108
131
|
}
|
|
109
|
-
report({
|
|
110
|
-
componentName,
|
|
111
|
-
phase: 'loader',
|
|
112
|
-
error: new IoError('CJS require failed', { cause: failure.cjsError, props: { phase: 'loader' } }),
|
|
113
|
-
})
|
|
114
|
-
}
|
|
115
132
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
133
|
+
// Step 4: Extract CSS imports (non-fatal)
|
|
134
|
+
let cssImportPaths: string[] = []
|
|
135
|
+
const cssResult = Result.fromThrowable(extractCssImports, (thrown) => thrown)(program)
|
|
136
|
+
if (cssResult.isOk()) {
|
|
137
|
+
cssImportPaths = cssResult.value
|
|
138
|
+
} else {
|
|
139
|
+
const thrown = cssResult.error
|
|
140
|
+
report({
|
|
141
|
+
componentName,
|
|
142
|
+
phase: 'css',
|
|
143
|
+
error: new ParseError(
|
|
144
|
+
`Failed to extract CSS imports: ${thrown instanceof Error ? thrown.message : String(thrown)}`,
|
|
145
|
+
{ cause: thrown instanceof Error ? thrown : undefined, props: { phase: 'css' } },
|
|
146
|
+
),
|
|
147
|
+
})
|
|
148
|
+
}
|
|
132
149
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
150
|
+
// Step 5: Process the default-exported component (non-fatal unless render fails after load)
|
|
151
|
+
return ResultAsync.fromPromise(
|
|
152
|
+
processComponentWithCleanup(
|
|
153
|
+
componentInfo,
|
|
154
|
+
loadComponent,
|
|
155
|
+
cssImportPaths,
|
|
156
|
+
!!failure,
|
|
157
|
+
report,
|
|
158
|
+
optionsWithDefaults,
|
|
159
|
+
compiledEntryPath,
|
|
160
|
+
refElementContext,
|
|
161
|
+
cleanup,
|
|
162
|
+
errors,
|
|
163
|
+
),
|
|
164
|
+
normalizeComponentExtractionCleanupFailure,
|
|
165
|
+
)
|
|
166
|
+
}),
|
|
167
|
+
)
|
|
149
168
|
})
|
|
150
169
|
}
|
|
151
170
|
|
|
171
|
+
function normalizeComponentExtractionCleanupFailure(thrown: unknown): InstanceType<typeof BaseError> {
|
|
172
|
+
const normalizedError = BaseError.normalize(thrown)
|
|
173
|
+
if (normalizedError instanceof BaseError) {
|
|
174
|
+
return normalizedError
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return new IoError('Unexpected failure during component extraction cleanup', {
|
|
178
|
+
cause: normalizedError,
|
|
179
|
+
props: { phase: 'loader' },
|
|
180
|
+
})
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
async function processComponentWithCleanup(
|
|
184
|
+
componentInfo: ComponentInfo,
|
|
185
|
+
loadComponent: (name: string) => ComponentType<unknown> | null,
|
|
186
|
+
cssImportPaths: string[],
|
|
187
|
+
didModuleLoadFail: boolean,
|
|
188
|
+
report: (error: ExtractionError) => void,
|
|
189
|
+
options: ExtractComponentManifestOptions,
|
|
190
|
+
compiledEntryPath: string,
|
|
191
|
+
refElementContext: RefElementContext,
|
|
192
|
+
cleanup: () => Promise<void>,
|
|
193
|
+
errors: ExtractionError[],
|
|
194
|
+
): Promise<ManifestResult> {
|
|
195
|
+
try {
|
|
196
|
+
const processResult = processComponent(
|
|
197
|
+
componentInfo,
|
|
198
|
+
loadComponent,
|
|
199
|
+
cssImportPaths,
|
|
200
|
+
didModuleLoadFail,
|
|
201
|
+
report,
|
|
202
|
+
options,
|
|
203
|
+
compiledEntryPath,
|
|
204
|
+
refElementContext.eligiblePaths,
|
|
205
|
+
)
|
|
206
|
+
if (!processResult.ok) {
|
|
207
|
+
throw processResult.error
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return {
|
|
211
|
+
component: toEditorReactComponent(processResult.component),
|
|
212
|
+
errors,
|
|
213
|
+
}
|
|
214
|
+
} finally {
|
|
215
|
+
await cleanup()
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
152
219
|
export async function extractComponentManifest(
|
|
153
220
|
componentPath: string,
|
|
154
221
|
compiledEntryPath: string,
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { camelCase } from 'case-anything'
|
|
9
9
|
import { type DefaultTreeAdapterMap, parseFragment } from 'parse5'
|
|
10
10
|
import { TRACE_ATTR } from '../../../../component-renderer'
|
|
11
|
-
import { findPreferredSemanticClass } from '../../../../utils/css-class'
|
|
11
|
+
import { findPreferredSemanticClass, normalizeClassNames } from '../../../../utils/css-class'
|
|
12
12
|
import { PRESETS_WRAPPER_CLASS_NAME } from '../../utils/mock-generator'
|
|
13
13
|
import type { CssPropertiesData } from '../css-properties'
|
|
14
14
|
import { addTextProperties } from '../css-properties'
|
|
@@ -174,7 +174,7 @@ function getElementNamePart(element: Element, getElementById: (id: string) => El
|
|
|
174
174
|
|
|
175
175
|
const classAttr = getAttribute(element, 'class')
|
|
176
176
|
if (classAttr) {
|
|
177
|
-
const semanticClass = findPreferredSemanticClass(classAttr
|
|
177
|
+
const semanticClass = findPreferredSemanticClass(normalizeClassNames(classAttr))
|
|
178
178
|
if (semanticClass) elementName = semanticClass
|
|
179
179
|
}
|
|
180
180
|
|
|
@@ -197,7 +197,7 @@ function getElementNamePart(element: Element, getElementById: (id: string) => El
|
|
|
197
197
|
function hasClassNameCriteria(element: Element, extractorData: Map<string, unknown>): boolean {
|
|
198
198
|
const classAttr = getAttribute(element, 'class')
|
|
199
199
|
if (classAttr) {
|
|
200
|
-
const semanticClass = findPreferredSemanticClass(classAttr
|
|
200
|
+
const semanticClass = findPreferredSemanticClass(normalizeClassNames(classAttr))
|
|
201
201
|
if (semanticClass) return true
|
|
202
202
|
}
|
|
203
203
|
|
|
@@ -17,13 +17,12 @@ export interface RenderContext {
|
|
|
17
17
|
store: ExtractorStore
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
/**
|
|
21
|
-
* Event emitted for each DOM element created during render.
|
|
22
|
-
*/
|
|
23
20
|
export interface CreateElementEvent {
|
|
24
|
-
|
|
21
|
+
type: unknown
|
|
22
|
+
isDomElement: boolean
|
|
23
|
+
tag?: string
|
|
25
24
|
props: Record<string, unknown>
|
|
26
|
-
traceId
|
|
25
|
+
traceId?: string
|
|
27
26
|
children: unknown[]
|
|
28
27
|
store: ExtractorStore
|
|
29
28
|
}
|
|
@@ -329,6 +329,8 @@ export function createCssPropertiesExtractor(): ReactExtractor {
|
|
|
329
329
|
name: 'css-properties',
|
|
330
330
|
|
|
331
331
|
onCreateElement(event: CreateElementEvent): void {
|
|
332
|
+
if (!event.isDomElement || !event.tag || !event.traceId) return
|
|
333
|
+
|
|
332
334
|
const { tag, props, traceId, store } = event
|
|
333
335
|
const role = props.role as string | undefined
|
|
334
336
|
|