@contentful/experience-design-system-extraction 2.34.5-dev-build-4a4b9e84.0 → 2.34.5-dev-build-9dff4380.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/package.json +1 -1
- package/dist/src/extract/{adapters/astro/extractor.d.ts → astro.d.ts} +1 -1
- package/dist/src/extract/{adapters/astro/extractor.js → astro.js} +3 -4
- package/dist/src/extract/{adapters/support/file-processing/file-workers.d.ts → file-extraction-workers.d.ts} +13 -1
- package/dist/src/extract/{adapters/support/file-processing/file-workers.js → file-extraction-workers.js} +19 -0
- package/dist/src/extract/{policies/quality/authorability.d.ts → non-authorable-filter.d.ts} +1 -1
- package/dist/src/extract/pipeline.d.ts +7 -0
- package/dist/src/extract/{services/component-deduplicator.js → pipeline.js} +137 -13
- package/dist/src/extract/{adapters/react/extractor.d.ts → react.d.ts} +1 -1
- package/dist/src/extract/{adapters/react/extractor.js → react.js} +353 -9
- package/dist/src/extract/scoring.d.ts +12 -0
- package/dist/src/extract/{policies/quality/scoring.js → scoring.js} +0 -1
- package/dist/src/extract/{policies/quality/source-inspection.d.ts → source-inspection.d.ts} +1 -1
- package/dist/src/extract/{policies/quality/source-inspection.js → source-inspection.js} +1 -1
- package/dist/src/extract/{adapters/support/resolution/source-location.d.ts → source-line-metadata.d.ts} +1 -1
- package/dist/src/extract/{adapters/stencil/extractor.d.ts → stencil.d.ts} +1 -1
- package/dist/src/extract/{adapters/stencil/extractor.js → stencil.js} +2 -3
- package/dist/src/extract/{evidence/structural-slot-evidence.d.ts → structural-slot-evidence.d.ts} +1 -1
- package/dist/src/extract/{evidence/structural-slot-evidence.js → structural-slot-evidence.js} +2 -2
- package/dist/src/extract/{adapters/svelte/extractor.d.ts → svelte.d.ts} +1 -2
- package/dist/src/extract/{adapters/svelte/extractor.js → svelte.js} +91 -7
- package/dist/src/extract/{adapters/support/tsx-shared.d.ts → tsx-shared.d.ts} +1 -1
- package/dist/src/extract/{policies/quality/validation.d.ts → validate.d.ts} +1 -1
- package/dist/src/extract/{adapters/vue-tsx/extractor.d.ts → vue-tsx.d.ts} +1 -1
- package/dist/src/extract/{adapters/vue-tsx/extractor.js → vue-tsx.js} +1 -1
- package/dist/src/extract/{adapters/vue/extractor.d.ts → vue.d.ts} +1 -1
- package/dist/src/extract/{adapters/vue/extractor.js → vue.js} +3 -4
- package/dist/src/extract/{adapters/web-components/extractor.d.ts → web-components.d.ts} +1 -1
- package/dist/src/extract/{adapters/web-components/extractor.js → web-components.js} +213 -4
- package/dist/src/index.d.ts +21 -25
- package/dist/src/index.js +17 -18
- package/dist/src/{extract/services/classification-service.d.ts → pre-classify.d.ts} +1 -1
- package/dist/src/{extract/model/component.d.ts → types.d.ts} +20 -0
- package/package.json +1 -1
- package/dist/src/extract/adapters/react/function-resolution.d.ts +0 -4
- package/dist/src/extract/adapters/react/function-resolution.js +0 -131
- package/dist/src/extract/adapters/react/prop-dataflow.d.ts +0 -14
- package/dist/src/extract/adapters/react/prop-dataflow.js +0 -220
- package/dist/src/extract/adapters/support/file-processing/project-source-files.d.ts +0 -5
- package/dist/src/extract/adapters/support/file-processing/project-source-files.js +0 -13
- package/dist/src/extract/adapters/support/file-processing/result-normalizer.d.ts +0 -6
- package/dist/src/extract/adapters/support/file-processing/result-normalizer.js +0 -6
- package/dist/src/extract/adapters/svelte/ast.d.ts +0 -12
- package/dist/src/extract/adapters/svelte/ast.js +0 -1
- package/dist/src/extract/adapters/svelte/identity.d.ts +0 -1
- package/dist/src/extract/adapters/svelte/identity.js +0 -26
- package/dist/src/extract/adapters/svelte/slots.d.ts +0 -7
- package/dist/src/extract/adapters/svelte/slots.js +0 -63
- package/dist/src/extract/adapters/web-components/properties.d.ts +0 -9
- package/dist/src/extract/adapters/web-components/properties.js +0 -212
- package/dist/src/extract/controller/extract-controller.d.ts +0 -10
- package/dist/src/extract/controller/extract-controller.js +0 -56
- package/dist/src/extract/model/contract.d.ts +0 -16
- package/dist/src/extract/model/contract.js +0 -1
- package/dist/src/extract/model/options.d.ts +0 -15
- package/dist/src/extract/model/options.js +0 -1
- package/dist/src/extract/model/scoring.d.ts +0 -9
- package/dist/src/extract/model/scoring.js +0 -1
- package/dist/src/extract/policies/quality/scoring.d.ts +0 -5
- package/dist/src/extract/services/component-deduplicator.d.ts +0 -2
- package/dist/src/extract/services/extraction-pipeline.d.ts +0 -3
- package/dist/src/extract/services/extraction-pipeline.js +0 -43
- package/dist/src/extract/services/extraction-runner.d.ts +0 -4
- package/dist/src/extract/services/extraction-runner.js +0 -21
- package/dist/src/extract/services/extraction-service.d.ts +0 -13
- package/dist/src/extract/services/extraction-service.js +0 -17
- package/dist/src/extract/services/extractor-registry.d.ts +0 -8
- package/dist/src/extract/services/extractor-registry.js +0 -68
- package/dist/src/extract/services/ports/component-extractor.d.ts +0 -7
- package/dist/src/extract/services/ports/component-extractor.js +0 -1
- package/dist/src/extract/services/quality-service.d.ts +0 -4
- package/dist/src/extract/services/quality-service.js +0 -61
- /package/dist/src/extract/{policies/quality/authorability.js → non-authorable-filter.js} +0 -0
- /package/dist/src/extract/{evidence/source-evidence.d.ts → parse-imported-names.d.ts} +0 -0
- /package/dist/src/extract/{evidence/source-evidence.js → parse-imported-names.js} +0 -0
- /package/dist/src/extract/{adapters/support/resolution/local-module.d.ts → resolve-local-module.d.ts} +0 -0
- /package/dist/src/extract/{adapters/support/resolution/local-module.js → resolve-local-module.js} +0 -0
- /package/dist/src/extract/{adapters/support/resolution/type-property.d.ts → resolve-type-property.d.ts} +0 -0
- /package/dist/src/extract/{adapters/support/resolution/type-property.js → resolve-type-property.js} +0 -0
- /package/dist/src/extract/{evidence/allowed-components.d.ts → slot-allowed-components.d.ts} +0 -0
- /package/dist/src/extract/{evidence/allowed-components.js → slot-allowed-components.js} +0 -0
- /package/dist/src/extract/{evidence/slot-evidence.d.ts → slot-detection.d.ts} +0 -0
- /package/dist/src/extract/{evidence/slot-evidence.js → slot-detection.js} +0 -0
- /package/dist/src/extract/{adapters/support/resolution/source-location.js → source-line-metadata.js} +0 -0
- /package/dist/src/extract/{adapters/support/tsx-shared.js → tsx-shared.js} +0 -0
- /package/dist/src/extract/{policies/quality/validation.js → validate.js} +0 -0
- /package/dist/src/{extract/services/classification-service.js → pre-classify.js} +0 -0
- /package/dist/src/{extract/model/component.js → types.js} +0 -0
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { basename, dirname, join, resolve } from 'node:path';
|
|
2
2
|
import { Project, Node, SyntaxKind } from 'ts-morph';
|
|
3
|
-
import { createSortedExtractionResult } from '
|
|
4
|
-
import {
|
|
5
|
-
import { kebabToPascal } from '../support/tsx-shared.js';
|
|
6
|
-
import { extractAccessorProperties, extractClassProperties, extractJsDocAttributeProps, extractObservedAttributes, hasShoelaceRuntimeBookkeepingField, mergePropLists, mergeProps, } from './properties.js';
|
|
3
|
+
import { createSortedExtractionResult, extractProjectSourceFiles } from './file-extraction-workers.js';
|
|
4
|
+
import { kebabToPascal } from './tsx-shared.js';
|
|
7
5
|
function normalizeComponentName(input) {
|
|
8
6
|
return input.replace(/[^a-zA-Z0-9]/g, '').toLowerCase();
|
|
9
7
|
}
|
|
@@ -13,6 +11,9 @@ function camelToKebab(input) {
|
|
|
13
11
|
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1-$2')
|
|
14
12
|
.toLowerCase();
|
|
15
13
|
}
|
|
14
|
+
function kebabToCamel(input) {
|
|
15
|
+
return input.replace(/-([a-z0-9])/gi, (_, char) => char.toUpperCase());
|
|
16
|
+
}
|
|
16
17
|
function resolveDecoratorInterpolation(node) {
|
|
17
18
|
if (Node.isIdentifier(node)) {
|
|
18
19
|
const definitions = node.getDefinitions();
|
|
@@ -261,6 +262,214 @@ function extractJsDocSlots(classDecl) {
|
|
|
261
262
|
}
|
|
262
263
|
return mergeSlotLists(slots);
|
|
263
264
|
}
|
|
265
|
+
function extractObservedAttributes(classDecl) {
|
|
266
|
+
const props = [];
|
|
267
|
+
const getter = classDecl.getGetAccessor('observedAttributes');
|
|
268
|
+
if (!getter || !getter.isStatic())
|
|
269
|
+
return props;
|
|
270
|
+
const body = getter.getBody();
|
|
271
|
+
if (!body)
|
|
272
|
+
return props;
|
|
273
|
+
// Find the return statement containing an array literal
|
|
274
|
+
body.forEachDescendant((node) => {
|
|
275
|
+
if (!Node.isReturnStatement(node))
|
|
276
|
+
return;
|
|
277
|
+
const expression = node.getExpression();
|
|
278
|
+
if (!expression || !Node.isArrayLiteralExpression(expression))
|
|
279
|
+
return;
|
|
280
|
+
for (const element of expression.getElements()) {
|
|
281
|
+
if (Node.isStringLiteral(element)) {
|
|
282
|
+
const attrName = element.getLiteralValue();
|
|
283
|
+
props.push({
|
|
284
|
+
name: attrName,
|
|
285
|
+
type: 'string',
|
|
286
|
+
required: false,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
return props;
|
|
292
|
+
}
|
|
293
|
+
function hasInternalJsDocTag(member) {
|
|
294
|
+
return member.getJsDocs().some((doc) => doc.getTags().some((tag) => tag.getTagName() === 'internal'));
|
|
295
|
+
}
|
|
296
|
+
const NON_PUBLIC_LIT_DECORATORS = new Set(['consume', 'provide', 'query', 'queryAsync', 'state']);
|
|
297
|
+
const INTERNAL_RUNTIME_FIELD_NAMES = new Set(['dir', 'initialReflectedProperties', 'lang']);
|
|
298
|
+
function isNonPublicLitMember(member) {
|
|
299
|
+
return member.getDecorators().some((decorator) => NON_PUBLIC_LIT_DECORATORS.has(decorator.getName()));
|
|
300
|
+
}
|
|
301
|
+
function hasShoelaceRuntimeBookkeepingField(classDecl) {
|
|
302
|
+
return classDecl.getProperties().some((property) => property.getName() === 'initialReflectedProperties');
|
|
303
|
+
}
|
|
304
|
+
function isInternalRuntimeField(name, applyRuntimeFieldDenylist) {
|
|
305
|
+
return applyRuntimeFieldDenylist && INTERNAL_RUNTIME_FIELD_NAMES.has(name);
|
|
306
|
+
}
|
|
307
|
+
function getExplicitLitPropertyAttributeName(property) {
|
|
308
|
+
const decorator = property.getDecorators().find((candidate) => candidate.getName() === 'property');
|
|
309
|
+
const firstArg = decorator?.getArguments()[0];
|
|
310
|
+
if (!firstArg || !Node.isObjectLiteralExpression(firstArg)) {
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
const attributeProp = firstArg.getProperty('attribute');
|
|
314
|
+
if (!attributeProp || !Node.isPropertyAssignment(attributeProp)) {
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
const initializer = attributeProp.getInitializer();
|
|
318
|
+
if (!initializer || !Node.isStringLiteral(initializer)) {
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
321
|
+
return initializer.getLiteralValue();
|
|
322
|
+
}
|
|
323
|
+
function extractClassProperties(classDecl, applyRuntimeFieldDenylist = false) {
|
|
324
|
+
const props = [];
|
|
325
|
+
for (const property of classDecl.getProperties()) {
|
|
326
|
+
if (property.isStatic())
|
|
327
|
+
continue;
|
|
328
|
+
if (hasInternalJsDocTag(property))
|
|
329
|
+
continue;
|
|
330
|
+
if (isNonPublicLitMember(property))
|
|
331
|
+
continue;
|
|
332
|
+
const name = property.getName();
|
|
333
|
+
if (name.startsWith('#') || isInternalRuntimeField(name, applyRuntimeFieldDenylist))
|
|
334
|
+
continue;
|
|
335
|
+
const scope = property.getScope();
|
|
336
|
+
if (scope === 'private' || scope === 'protected')
|
|
337
|
+
continue;
|
|
338
|
+
const initializer = property.getInitializer();
|
|
339
|
+
const hasDecorators = property.getDecorators().length > 0;
|
|
340
|
+
// Skip undecorated arrow-function properties (internal event handlers / callbacks)
|
|
341
|
+
if (!hasDecorators && initializer && Node.isArrowFunction(initializer)) {
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
// Skip properties initialized with this.attachInternals() (ElementInternals)
|
|
345
|
+
if (initializer &&
|
|
346
|
+
Node.isCallExpression(initializer) &&
|
|
347
|
+
initializer.getExpression().getText() === 'this.attachInternals') {
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
const typeNode = property.getTypeNode();
|
|
351
|
+
const type = typeNode ? typeNode.getText() : 'any';
|
|
352
|
+
const publicName = name.startsWith('_') && hasDecorators ? getExplicitLitPropertyAttributeName(property) : null;
|
|
353
|
+
let defaultValue;
|
|
354
|
+
if (initializer) {
|
|
355
|
+
if (Node.isStringLiteral(initializer)) {
|
|
356
|
+
defaultValue = initializer.getLiteralValue();
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
defaultValue = initializer.getText();
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
props.push({
|
|
363
|
+
name: publicName ? kebabToCamel(publicName) : name,
|
|
364
|
+
type,
|
|
365
|
+
required: false,
|
|
366
|
+
...(defaultValue !== undefined && { defaultValue }),
|
|
367
|
+
sourceStartLine: property.getStartLineNumber(),
|
|
368
|
+
sourceEndLine: property.getEndLineNumber(),
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
return props;
|
|
372
|
+
}
|
|
373
|
+
function extractAccessorProperties(classDecl, applyRuntimeFieldDenylist = false) {
|
|
374
|
+
const props = [];
|
|
375
|
+
const accessors = new Map();
|
|
376
|
+
for (const getter of classDecl.getGetAccessors()) {
|
|
377
|
+
if (getter.isStatic())
|
|
378
|
+
continue;
|
|
379
|
+
if (hasInternalJsDocTag(getter))
|
|
380
|
+
continue;
|
|
381
|
+
if (isNonPublicLitMember(getter))
|
|
382
|
+
continue;
|
|
383
|
+
const name = getter.getName();
|
|
384
|
+
if (name === 'observedAttributes' ||
|
|
385
|
+
name === 'template' ||
|
|
386
|
+
name.startsWith('#') ||
|
|
387
|
+
isInternalRuntimeField(name, applyRuntimeFieldDenylist))
|
|
388
|
+
continue;
|
|
389
|
+
const scope = getter.getScope();
|
|
390
|
+
if (scope === 'private' || scope === 'protected')
|
|
391
|
+
continue;
|
|
392
|
+
const entry = accessors.get(name) ?? {};
|
|
393
|
+
entry.getter = getter;
|
|
394
|
+
accessors.set(name, entry);
|
|
395
|
+
}
|
|
396
|
+
for (const setter of classDecl.getSetAccessors()) {
|
|
397
|
+
if (setter.isStatic())
|
|
398
|
+
continue;
|
|
399
|
+
if (hasInternalJsDocTag(setter))
|
|
400
|
+
continue;
|
|
401
|
+
if (isNonPublicLitMember(setter))
|
|
402
|
+
continue;
|
|
403
|
+
const name = setter.getName();
|
|
404
|
+
if (name === 'observedAttributes' ||
|
|
405
|
+
name === 'template' ||
|
|
406
|
+
name.startsWith('#') ||
|
|
407
|
+
isInternalRuntimeField(name, applyRuntimeFieldDenylist))
|
|
408
|
+
continue;
|
|
409
|
+
const scope = setter.getScope();
|
|
410
|
+
if (scope === 'private' || scope === 'protected')
|
|
411
|
+
continue;
|
|
412
|
+
const entry = accessors.get(name) ?? {};
|
|
413
|
+
entry.setter = setter;
|
|
414
|
+
accessors.set(name, entry);
|
|
415
|
+
}
|
|
416
|
+
for (const [name, { getter, setter }] of accessors) {
|
|
417
|
+
const hasPropertyDecorator = getter?.getDecorators().some((decorator) => decorator.getName() === 'property') ||
|
|
418
|
+
setter?.getDecorators().some((decorator) => decorator.getName() === 'property');
|
|
419
|
+
if (!hasPropertyDecorator && !(getter && setter))
|
|
420
|
+
continue;
|
|
421
|
+
const type = getter?.getReturnTypeNode()?.getText() ?? setter?.getParameters()[0]?.getTypeNode()?.getText() ?? 'any';
|
|
422
|
+
const accessorNode = getter ?? setter;
|
|
423
|
+
props.push({
|
|
424
|
+
name,
|
|
425
|
+
type,
|
|
426
|
+
required: false,
|
|
427
|
+
...(accessorNode
|
|
428
|
+
? {
|
|
429
|
+
sourceStartLine: accessorNode.getStartLineNumber(),
|
|
430
|
+
sourceEndLine: accessorNode.getEndLineNumber(),
|
|
431
|
+
}
|
|
432
|
+
: {}),
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
return props;
|
|
436
|
+
}
|
|
437
|
+
function extractJsDocAttributeProps(classDecl) {
|
|
438
|
+
const props = [];
|
|
439
|
+
for (const doc of classDecl.getJsDocs()) {
|
|
440
|
+
for (const tag of doc.getTags()) {
|
|
441
|
+
if (tag.getTagName() !== 'attribute')
|
|
442
|
+
continue;
|
|
443
|
+
const tagComment = tag.getCommentText();
|
|
444
|
+
const normalizedComment = Array.isArray(tagComment) ? tagComment.join(' ') : tagComment;
|
|
445
|
+
const match = normalizedComment?.match(/(?:\{([^}]+)\}\s+)?([^\s]+)(?:\s*-\s*([\s\S]*))?/);
|
|
446
|
+
if (!match)
|
|
447
|
+
continue;
|
|
448
|
+
const [, type, name, description] = match;
|
|
449
|
+
if (!name || name.startsWith('#'))
|
|
450
|
+
continue;
|
|
451
|
+
props.push({
|
|
452
|
+
name,
|
|
453
|
+
type: type?.trim() || 'any',
|
|
454
|
+
required: false,
|
|
455
|
+
...(description ? { description: description.replace(/\s+/g, ' ').trim() } : {}),
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
return props;
|
|
460
|
+
}
|
|
461
|
+
function mergePropLists(...propLists) {
|
|
462
|
+
const merged = new Map();
|
|
463
|
+
for (const propList of propLists) {
|
|
464
|
+
for (const prop of propList) {
|
|
465
|
+
merged.set(prop.name, prop);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
return [...merged.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
469
|
+
}
|
|
470
|
+
function mergeProps(observed, classProps) {
|
|
471
|
+
return mergePropLists(observed, classProps);
|
|
472
|
+
}
|
|
264
473
|
function collectHtmlTaggedTemplates(root) {
|
|
265
474
|
const templates = [];
|
|
266
475
|
root.forEachDescendant((node) => {
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,25 +1,21 @@
|
|
|
1
|
-
export type { RawComponentDefinition, RawPropDefinition, RawSlotDefinition, ComponentExtractionResult, ExtractionExclusion, ExtractorProgress, ExtractionValidationIssue, ExtractionValidationIssueCode, } from './
|
|
2
|
-
export { stripScoringFields } from './
|
|
3
|
-
export
|
|
4
|
-
export
|
|
5
|
-
export {
|
|
6
|
-
export {
|
|
7
|
-
export
|
|
8
|
-
export {
|
|
9
|
-
export {
|
|
10
|
-
export {
|
|
11
|
-
export {
|
|
12
|
-
export {
|
|
13
|
-
export {
|
|
14
|
-
export {
|
|
15
|
-
export {
|
|
16
|
-
export {
|
|
17
|
-
export {
|
|
18
|
-
export
|
|
19
|
-
export {
|
|
20
|
-
export
|
|
21
|
-
export {
|
|
22
|
-
export { parseImportedNames } from './extract/evidence/source-evidence.js';
|
|
23
|
-
export { CONTENT_NAME_EXCEPTIONS, isReactNodeType, isArrayReactNodeType, shouldBeSlot, } from './extract/evidence/slot-evidence.js';
|
|
24
|
-
export { preClassifyProp, preClassifyComponent } from './extract/services/classification-service.js';
|
|
25
|
-
export type { PreClassification } from './extract/services/classification-service.js';
|
|
1
|
+
export type { RawComponentDefinition, RawPropDefinition, RawSlotDefinition, ComponentExtractionResult, ExtractionExclusion, ExtractorProgress, ExtractorOptions, ComponentExtractor, ExtractionValidationIssue, ExtractionValidationIssueCode, } from './types.js';
|
|
2
|
+
export { stripScoringFields } from './types.js';
|
|
3
|
+
export { extractComponents } from './extract/pipeline.js';
|
|
4
|
+
export { extractReactComponents } from './extract/react.js';
|
|
5
|
+
export { extractVueComponents } from './extract/vue.js';
|
|
6
|
+
export { extractVueTsxComponents } from './extract/vue-tsx.js';
|
|
7
|
+
export { extractStencilComponents } from './extract/stencil.js';
|
|
8
|
+
export { extractAstroComponents } from './extract/astro.js';
|
|
9
|
+
export { extractWebComponentDefinitions } from './extract/web-components.js';
|
|
10
|
+
export { extractSvelteComponents } from './extract/svelte.js';
|
|
11
|
+
export { extractAllowedComponentsFromTypeText, extractAllowedComponentsFromJsdoc, } from './extract/slot-allowed-components.js';
|
|
12
|
+
export { isNonAuthorableComponent } from './extract/non-authorable-filter.js';
|
|
13
|
+
export { computeExtractionScore, deriveNeedsReview } from './extract/scoring.js';
|
|
14
|
+
export type { ExtractionScore, ExtractionScoreOptions, ExtractionConfidence } from './extract/scoring.js';
|
|
15
|
+
export { inspectComponentSource, describeReviewReasons, describeReviewReason, isDataWrapperReviewReason, HIGH_CONFIDENCE_DATA_FETCH_WRAPPER_REASON, POSSIBLE_DATA_FETCH_WRAPPER_REASON, ZERO_SURFACE_RENDERED_UI_REASON, } from './extract/source-inspection.js';
|
|
16
|
+
export type { ComponentSourceInspection } from './extract/source-inspection.js';
|
|
17
|
+
export { validateExtractedComponents, shouldExcludeDueToValidation, formatExclusionWarning, formatExcludedComponentLines, } from './extract/validate.js';
|
|
18
|
+
export { parseImportedNames } from './extract/parse-imported-names.js';
|
|
19
|
+
export { CONTENT_NAME_EXCEPTIONS, isReactNodeType, isArrayReactNodeType, shouldBeSlot, } from './extract/slot-detection.js';
|
|
20
|
+
export { preClassifyProp, preClassifyComponent } from './pre-classify.js';
|
|
21
|
+
export type { PreClassification } from './pre-classify.js';
|
package/dist/src/index.js
CHANGED
|
@@ -1,24 +1,23 @@
|
|
|
1
|
-
export { stripScoringFields } from './
|
|
1
|
+
export { stripScoringFields } from './types.js';
|
|
2
2
|
// Core extraction pipeline
|
|
3
|
-
export { extractComponents } from './extract/
|
|
4
|
-
export { extractEndpoint } from './extract/controller/extract-controller.js';
|
|
3
|
+
export { extractComponents } from './extract/pipeline.js';
|
|
5
4
|
// Framework-specific extractors
|
|
6
|
-
export { extractReactComponents } from './extract/
|
|
7
|
-
export { extractVueComponents } from './extract/
|
|
8
|
-
export { extractVueTsxComponents } from './extract/
|
|
9
|
-
export { extractStencilComponents } from './extract/
|
|
10
|
-
export { extractAstroComponents } from './extract/
|
|
11
|
-
export { extractWebComponentDefinitions } from './extract/
|
|
12
|
-
export { extractSvelteComponents } from './extract/
|
|
13
|
-
export { extractAllowedComponentsFromTypeText, extractAllowedComponentsFromJsdoc, } from './extract/
|
|
5
|
+
export { extractReactComponents } from './extract/react.js';
|
|
6
|
+
export { extractVueComponents } from './extract/vue.js';
|
|
7
|
+
export { extractVueTsxComponents } from './extract/vue-tsx.js';
|
|
8
|
+
export { extractStencilComponents } from './extract/stencil.js';
|
|
9
|
+
export { extractAstroComponents } from './extract/astro.js';
|
|
10
|
+
export { extractWebComponentDefinitions } from './extract/web-components.js';
|
|
11
|
+
export { extractSvelteComponents } from './extract/svelte.js';
|
|
12
|
+
export { extractAllowedComponentsFromTypeText, extractAllowedComponentsFromJsdoc, } from './extract/slot-allowed-components.js';
|
|
14
13
|
// Post-extraction filtering and scoring
|
|
15
|
-
export { isNonAuthorableComponent } from './extract/
|
|
16
|
-
export { computeExtractionScore, deriveNeedsReview } from './extract/
|
|
17
|
-
export { inspectComponentSource, describeReviewReasons, describeReviewReason, isDataWrapperReviewReason, HIGH_CONFIDENCE_DATA_FETCH_WRAPPER_REASON, POSSIBLE_DATA_FETCH_WRAPPER_REASON, ZERO_SURFACE_RENDERED_UI_REASON, } from './extract/
|
|
14
|
+
export { isNonAuthorableComponent } from './extract/non-authorable-filter.js';
|
|
15
|
+
export { computeExtractionScore, deriveNeedsReview } from './extract/scoring.js';
|
|
16
|
+
export { inspectComponentSource, describeReviewReasons, describeReviewReason, isDataWrapperReviewReason, HIGH_CONFIDENCE_DATA_FETCH_WRAPPER_REASON, POSSIBLE_DATA_FETCH_WRAPPER_REASON, ZERO_SURFACE_RENDERED_UI_REASON, } from './extract/source-inspection.js';
|
|
18
17
|
// Validation
|
|
19
|
-
export { validateExtractedComponents, shouldExcludeDueToValidation, formatExclusionWarning, formatExcludedComponentLines, } from './extract/
|
|
20
|
-
export { parseImportedNames } from './extract/
|
|
18
|
+
export { validateExtractedComponents, shouldExcludeDueToValidation, formatExclusionWarning, formatExcludedComponentLines, } from './extract/validate.js';
|
|
19
|
+
export { parseImportedNames } from './extract/parse-imported-names.js';
|
|
21
20
|
// Slot detection helpers
|
|
22
|
-
export { CONTENT_NAME_EXCEPTIONS, isReactNodeType, isArrayReactNodeType, shouldBeSlot, } from './extract/
|
|
21
|
+
export { CONTENT_NAME_EXCEPTIONS, isReactNodeType, isArrayReactNodeType, shouldBeSlot, } from './extract/slot-detection.js';
|
|
23
22
|
// Pre-classification
|
|
24
|
-
export { preClassifyProp, preClassifyComponent } from './
|
|
23
|
+
export { preClassifyProp, preClassifyComponent } from './pre-classify.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { RawPropDefinition, RawComponentDefinition } from '
|
|
1
|
+
import type { RawPropDefinition, RawComponentDefinition } from './types.js';
|
|
2
2
|
export interface PreClassification {
|
|
3
3
|
category: 'content' | 'design' | 'state' | 'exclude';
|
|
4
4
|
cdfTypeHint?: 'string' | 'enum' | 'richtext' | 'media' | 'boolean';
|
|
@@ -76,5 +76,25 @@ export type ExtractorProgress = {
|
|
|
76
76
|
filesProcessed: number;
|
|
77
77
|
componentsFound: number;
|
|
78
78
|
};
|
|
79
|
+
/**
|
|
80
|
+
* Optional extraction-time settings forwarded from the CLI through the
|
|
81
|
+
* pipeline to each extractor. Only the Svelte extractor currently consumes
|
|
82
|
+
* any of these; other extractors ignore the value.
|
|
83
|
+
*/
|
|
84
|
+
export interface ExtractorOptions {
|
|
85
|
+
/**
|
|
86
|
+
* Whether the Svelte extractor should run a retry pass for components whose
|
|
87
|
+
* declared Props type couldn't be resolved on the first pass (cross-package
|
|
88
|
+
* extends, path-alias-only types, etc.). See svelte.ts for the policy.
|
|
89
|
+
*/
|
|
90
|
+
resolveUnreachable?: 'auto' | 'always' | 'never';
|
|
91
|
+
/** Absolute project root — used by the retry pass to locate tsconfig.json and node_modules. */
|
|
92
|
+
projectRoot?: string;
|
|
93
|
+
}
|
|
94
|
+
export interface ComponentExtractor {
|
|
95
|
+
name: string;
|
|
96
|
+
fileFilter: (filePath: string) => boolean;
|
|
97
|
+
extract(filePaths: string[], onProgress?: (p: ExtractorProgress) => void, opts?: ExtractorOptions): Promise<ComponentExtractionResult>;
|
|
98
|
+
}
|
|
79
99
|
/** Strip internal scoring fields before serialising a RawComponentDefinition for display or editing. */
|
|
80
100
|
export declare function stripScoringFields({ extractionConfidence: _c, reviewReasons: _r, needsReview: _n, ...rest }: RawComponentDefinition): Omit<RawComponentDefinition, 'extractionConfidence' | 'reviewReasons' | 'needsReview'>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentful/experience-design-system-extraction",
|
|
3
|
-
"version": "2.34.5-dev-build-
|
|
3
|
+
"version": "2.34.5-dev-build-9dff4380.0",
|
|
4
4
|
"description": "Component extraction engine for the Contentful Experience Design System SDK",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { Node, type ArrowFunction, type FunctionDeclaration, type FunctionExpression } from 'ts-morph';
|
|
2
|
-
export type FunctionLike = FunctionDeclaration | ArrowFunction | FunctionExpression;
|
|
3
|
-
export declare function resolveFunctionNode(decl: Node): FunctionLike | undefined;
|
|
4
|
-
export declare function resolveBestFunctionNode(declarations: Node[]): FunctionLike | undefined;
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import { Node, } from 'ts-morph';
|
|
2
|
-
import { getNodeDefinitions } from '../support/tsx-shared.js';
|
|
3
|
-
export function resolveFunctionNode(decl) {
|
|
4
|
-
if (Node.isFunctionDeclaration(decl))
|
|
5
|
-
return decl;
|
|
6
|
-
if (Node.isArrowFunction(decl))
|
|
7
|
-
return decl;
|
|
8
|
-
if (Node.isFunctionExpression(decl))
|
|
9
|
-
return decl;
|
|
10
|
-
if (Node.isVariableDeclaration(decl)) {
|
|
11
|
-
const init = decl.getInitializer();
|
|
12
|
-
if (init && Node.isArrowFunction(init))
|
|
13
|
-
return init;
|
|
14
|
-
if (init && Node.isFunctionExpression(init))
|
|
15
|
-
return init;
|
|
16
|
-
if (init && Node.isCallExpression(init))
|
|
17
|
-
return resolveFunctionFromCallExpression(init, new Set());
|
|
18
|
-
}
|
|
19
|
-
return undefined;
|
|
20
|
-
}
|
|
21
|
-
export function resolveBestFunctionNode(declarations) {
|
|
22
|
-
const candidates = declarations
|
|
23
|
-
.map((decl) => resolveFunctionNode(decl))
|
|
24
|
-
.filter((candidate) => candidate !== undefined);
|
|
25
|
-
const implementation = candidates.find((candidate) => !Node.isFunctionDeclaration(candidate) || candidate.getBody() !== undefined);
|
|
26
|
-
return implementation ?? candidates[0];
|
|
27
|
-
}
|
|
28
|
-
function resolveForwardRefFunction(callExpr) {
|
|
29
|
-
if (!Node.isCallExpression(callExpr))
|
|
30
|
-
return undefined;
|
|
31
|
-
const expressionText = callExpr.getExpression().getText();
|
|
32
|
-
if (!/(^|\.)forwardRef$/.test(expressionText))
|
|
33
|
-
return undefined;
|
|
34
|
-
const firstArg = callExpr.getArguments()[0];
|
|
35
|
-
if (!firstArg)
|
|
36
|
-
return undefined;
|
|
37
|
-
if (Node.isArrowFunction(firstArg))
|
|
38
|
-
return firstArg;
|
|
39
|
-
if (Node.isFunctionExpression(firstArg))
|
|
40
|
-
return firstArg;
|
|
41
|
-
if (Node.isIdentifier(firstArg)) {
|
|
42
|
-
const declarations = getNodeDefinitions(firstArg).flatMap((definition) => {
|
|
43
|
-
const declarationNode = definition.getDeclarationNode();
|
|
44
|
-
return declarationNode ? [declarationNode] : [];
|
|
45
|
-
});
|
|
46
|
-
for (const declaration of declarations) {
|
|
47
|
-
const resolved = resolveFunctionNode(declaration);
|
|
48
|
-
if (resolved)
|
|
49
|
-
return resolved;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
return undefined;
|
|
53
|
-
}
|
|
54
|
-
function resolveFunctionFromCallExpression(callExpr, seen) {
|
|
55
|
-
return resolveForwardRefFunction(callExpr) ?? resolveReturnedFunctionFromFactoryCall(callExpr, seen);
|
|
56
|
-
}
|
|
57
|
-
function resolveReturnedFunctionFromFactoryCall(callExpr, seen) {
|
|
58
|
-
const expression = callExpr.getExpression();
|
|
59
|
-
if (!Node.isIdentifier(expression))
|
|
60
|
-
return undefined;
|
|
61
|
-
for (const definition of getNodeDefinitions(expression)) {
|
|
62
|
-
const declaration = definition.getDeclarationNode();
|
|
63
|
-
if (!declaration)
|
|
64
|
-
continue;
|
|
65
|
-
const resolved = resolveReturnedFunctionFromDeclaration(declaration, seen);
|
|
66
|
-
if (resolved)
|
|
67
|
-
return resolved;
|
|
68
|
-
}
|
|
69
|
-
return undefined;
|
|
70
|
-
}
|
|
71
|
-
function resolveReturnedFunctionFromDeclaration(node, seen) {
|
|
72
|
-
if (seen.has(node))
|
|
73
|
-
return undefined;
|
|
74
|
-
seen.add(node);
|
|
75
|
-
if (Node.isVariableDeclaration(node)) {
|
|
76
|
-
const initializer = node.getInitializer();
|
|
77
|
-
if (!initializer)
|
|
78
|
-
return undefined;
|
|
79
|
-
if (Node.isArrowFunction(initializer) || Node.isFunctionExpression(initializer)) {
|
|
80
|
-
return resolveReturnedFunctionFromCallable(initializer, seen);
|
|
81
|
-
}
|
|
82
|
-
if (Node.isCallExpression(initializer)) {
|
|
83
|
-
return resolveFunctionFromCallExpression(initializer, seen);
|
|
84
|
-
}
|
|
85
|
-
return undefined;
|
|
86
|
-
}
|
|
87
|
-
if (Node.isFunctionDeclaration(node) || Node.isFunctionExpression(node) || Node.isArrowFunction(node)) {
|
|
88
|
-
return resolveReturnedFunctionFromCallable(node, seen);
|
|
89
|
-
}
|
|
90
|
-
return undefined;
|
|
91
|
-
}
|
|
92
|
-
function resolveReturnedFunctionFromCallable(fn, seen) {
|
|
93
|
-
const body = fn.getBody();
|
|
94
|
-
if (!body)
|
|
95
|
-
return undefined;
|
|
96
|
-
if (!Node.isBlock(body)) {
|
|
97
|
-
return resolveReturnedFunctionFromExpression(body, seen);
|
|
98
|
-
}
|
|
99
|
-
for (const statement of body.getStatements()) {
|
|
100
|
-
if (!Node.isReturnStatement(statement))
|
|
101
|
-
continue;
|
|
102
|
-
const expression = statement.getExpression();
|
|
103
|
-
if (!expression)
|
|
104
|
-
continue;
|
|
105
|
-
const resolved = resolveReturnedFunctionFromExpression(expression, seen);
|
|
106
|
-
if (resolved)
|
|
107
|
-
return resolved;
|
|
108
|
-
}
|
|
109
|
-
return undefined;
|
|
110
|
-
}
|
|
111
|
-
function resolveReturnedFunctionFromExpression(node, seen) {
|
|
112
|
-
if (Node.isArrowFunction(node) || Node.isFunctionExpression(node))
|
|
113
|
-
return node;
|
|
114
|
-
if (Node.isParenthesizedExpression(node)) {
|
|
115
|
-
return resolveReturnedFunctionFromExpression(node.getExpression(), seen);
|
|
116
|
-
}
|
|
117
|
-
if (Node.isCallExpression(node)) {
|
|
118
|
-
return resolveFunctionFromCallExpression(node, seen);
|
|
119
|
-
}
|
|
120
|
-
if (Node.isIdentifier(node)) {
|
|
121
|
-
for (const definition of getNodeDefinitions(node)) {
|
|
122
|
-
const declaration = definition.getDeclarationNode();
|
|
123
|
-
if (!declaration)
|
|
124
|
-
continue;
|
|
125
|
-
const resolved = resolveReturnedFunctionFromDeclaration(declaration, seen);
|
|
126
|
-
if (resolved)
|
|
127
|
-
return resolved;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
return undefined;
|
|
131
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { type ParameterDeclaration } from 'ts-morph';
|
|
2
|
-
import { type FunctionLike } from './function-resolution.js';
|
|
3
|
-
export type PropForwardingEdge = {
|
|
4
|
-
sourceProp: string;
|
|
5
|
-
targetComponentIdentity: string;
|
|
6
|
-
targetProp: string;
|
|
7
|
-
};
|
|
8
|
-
export type PropDataflow = {
|
|
9
|
-
intrinsicDomProps: Set<string>;
|
|
10
|
-
componentEdges: PropForwardingEdge[];
|
|
11
|
-
};
|
|
12
|
-
export declare function getComponentIdentity(func: FunctionLike): string;
|
|
13
|
-
/** Trace only statically resolvable, component-local prop dataflow into JSX. */
|
|
14
|
-
export declare function collectPropDataflow(func: FunctionLike, param: ParameterDeclaration, availablePropNames: Set<string>): PropDataflow;
|