@contentful/experience-design-system-cli 2.12.4-dev-build-9c819d8.0 → 2.13.1-dev-build-847dead.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.
Files changed (51) hide show
  1. package/dist/package.json +3 -6
  2. package/dist/src/analyze/command.js +2 -22
  3. package/dist/src/analyze/select/command.js +1 -1
  4. package/dist/src/analyze/select/tui/components/FieldEditor.js +4 -1
  5. package/dist/src/analyze/select-agent/command.js +1 -1
  6. package/dist/src/apply/command.d.ts +1 -5
  7. package/dist/src/apply/command.js +0 -43
  8. package/dist/src/import/tui/steps/GenerateReviewStep.d.ts +1 -1
  9. package/dist/src/import/tui/steps/GenerateReviewStep.js +20 -102
  10. package/dist/src/import/tui/steps/WizardPreviewStep.d.ts +0 -10
  11. package/dist/src/import/tui/steps/WizardPreviewStep.js +51 -95
  12. package/dist/src/import/tui/steps/preview-diff.js +0 -48
  13. package/dist/src/session/db.d.ts +0 -9
  14. package/dist/src/session/db.js +0 -46
  15. package/dist/src/types.d.ts +2 -76
  16. package/dist/src/types.js +1 -4
  17. package/package.json +3 -6
  18. package/dist/src/analyze/cycle-detection.d.ts +0 -68
  19. package/dist/src/analyze/cycle-detection.js +0 -285
  20. package/dist/src/analyze/extract/astro.d.ts +0 -5
  21. package/dist/src/analyze/extract/astro.js +0 -289
  22. package/dist/src/analyze/extract/non-authorable-filter.d.ts +0 -16
  23. package/dist/src/analyze/extract/non-authorable-filter.js +0 -60
  24. package/dist/src/analyze/extract/pipeline.d.ts +0 -6
  25. package/dist/src/analyze/extract/pipeline.js +0 -314
  26. package/dist/src/analyze/extract/react.d.ts +0 -2
  27. package/dist/src/analyze/extract/react.js +0 -2041
  28. package/dist/src/analyze/extract/scoring.d.ts +0 -12
  29. package/dist/src/analyze/extract/scoring.js +0 -108
  30. package/dist/src/analyze/extract/slot-allowed-components.d.ts +0 -8
  31. package/dist/src/analyze/extract/slot-allowed-components.js +0 -40
  32. package/dist/src/analyze/extract/slot-detection.d.ts +0 -35
  33. package/dist/src/analyze/extract/slot-detection.js +0 -101
  34. package/dist/src/analyze/extract/source-inspection.d.ts +0 -13
  35. package/dist/src/analyze/extract/source-inspection.js +0 -189
  36. package/dist/src/analyze/extract/stencil.d.ts +0 -2
  37. package/dist/src/analyze/extract/stencil.js +0 -296
  38. package/dist/src/analyze/extract/svelte.d.ts +0 -5
  39. package/dist/src/analyze/extract/svelte.js +0 -1626
  40. package/dist/src/analyze/extract/tsx-shared.d.ts +0 -8
  41. package/dist/src/analyze/extract/tsx-shared.js +0 -263
  42. package/dist/src/analyze/extract/validate.d.ts +0 -16
  43. package/dist/src/analyze/extract/validate.js +0 -94
  44. package/dist/src/analyze/extract/vue-tsx.d.ts +0 -2
  45. package/dist/src/analyze/extract/vue-tsx.js +0 -498
  46. package/dist/src/analyze/extract/vue.d.ts +0 -5
  47. package/dist/src/analyze/extract/vue.js +0 -653
  48. package/dist/src/analyze/extract/web-components.d.ts +0 -2
  49. package/dist/src/analyze/extract/web-components.js +0 -876
  50. package/dist/src/analyze/pre-classify.d.ts +0 -17
  51. package/dist/src/analyze/pre-classify.js +0 -211
@@ -1,8 +0,0 @@
1
- import { Node, type Type } from 'ts-morph';
2
- export declare function extractAllowedValues(type: Type): string[] | undefined;
3
- export declare function getNodeDefinitions(node: Node): {
4
- getDeclarationNode(): Node | undefined;
5
- }[];
6
- export declare function getTypeTargetDeclarations(targetNode: Node, allowWorkspaceImportFallback?: boolean): Node[];
7
- export declare function getValueTargetDeclarations(targetNode: Node): Node[];
8
- export declare function getTypeReferenceName(typeNode: Node): string | undefined;
@@ -1,263 +0,0 @@
1
- import { existsSync, readFileSync } from 'node:fs';
2
- import { dirname, join, resolve } from 'node:path';
3
- import { Node } from 'ts-morph';
4
- import ts from 'typescript';
5
- const packageRootByFilePathCache = new Map();
6
- const workspacePackageManifestCache = new Map();
7
- const nearestTsConfigPathCache = new Map();
8
- const tsConfigPathsCache = new Map();
9
- export function extractAllowedValues(type) {
10
- if (!type.isUnion())
11
- return undefined;
12
- const literals = type
13
- .getUnionTypes()
14
- .filter((t) => t.isStringLiteral())
15
- .map((t) => t.getLiteralValueOrThrow());
16
- return literals.length >= 2 ? literals.sort() : undefined;
17
- }
18
- export function getNodeDefinitions(node) {
19
- const anyNode = node;
20
- return anyNode.getDefinitions?.() ?? [];
21
- }
22
- export function getTypeTargetDeclarations(targetNode, allowWorkspaceImportFallback = false) {
23
- return getNodeDefinitions(targetNode).flatMap((definition) => {
24
- const declaration = definition.getDeclarationNode();
25
- if (!declaration)
26
- return [];
27
- if (!allowWorkspaceImportFallback || !Node.isImportSpecifier(declaration)) {
28
- return [declaration];
29
- }
30
- const resolvedDeclarations = resolveWorkspaceImportSpecifierDeclarations(declaration, targetNode);
31
- return resolvedDeclarations.length > 0 ? resolvedDeclarations : [declaration];
32
- });
33
- }
34
- export function getValueTargetDeclarations(targetNode) {
35
- return getNodeDefinitions(targetNode).flatMap((definition) => {
36
- const declaration = definition.getDeclarationNode();
37
- if (!declaration)
38
- return [];
39
- if (!Node.isImportSpecifier(declaration)) {
40
- return [declaration];
41
- }
42
- const resolvedDeclarations = resolveWorkspaceImportSpecifierDeclarations(declaration, targetNode);
43
- return resolvedDeclarations.length > 0 ? resolvedDeclarations : [declaration];
44
- });
45
- }
46
- export function getTypeReferenceName(typeNode) {
47
- if (Node.isTypeReference(typeNode)) {
48
- return typeNode.getTypeName().getText().split('.').pop();
49
- }
50
- if (Node.isExpressionWithTypeArguments(typeNode)) {
51
- return typeNode.getExpression().getText().split('.').pop();
52
- }
53
- return undefined;
54
- }
55
- function resolveWorkspaceImportSpecifierDeclarations(importSpecifier, referenceNode) {
56
- if (!Node.isImportSpecifier(importSpecifier))
57
- return [];
58
- const importDeclaration = importSpecifier.getImportDeclaration();
59
- const moduleSpecifierSourceFile = importDeclaration.getModuleSpecifierSourceFile();
60
- if (moduleSpecifierSourceFile) {
61
- return getExportedDeclarationsForImportSpecifier(importSpecifier, moduleSpecifierSourceFile);
62
- }
63
- const moduleSpecifier = importDeclaration.getModuleSpecifierValue();
64
- if (!isBareModuleSpecifier(moduleSpecifier))
65
- return [];
66
- const workspaceEntrySourceFile = findWorkspacePackageEntrySourceFile(referenceNode.getSourceFile(), moduleSpecifier);
67
- if (workspaceEntrySourceFile) {
68
- return getExportedDeclarationsForImportSpecifier(importSpecifier, workspaceEntrySourceFile);
69
- }
70
- const aliasedSourceFile = findRepoLocalAliasSourceFile(referenceNode.getSourceFile(), moduleSpecifier);
71
- if (!aliasedSourceFile)
72
- return [];
73
- return getExportedDeclarationsForImportSpecifier(importSpecifier, aliasedSourceFile);
74
- }
75
- function getExportedDeclarationsForImportSpecifier(importSpecifier, sourceFile) {
76
- if (!Node.isImportSpecifier(importSpecifier))
77
- return [];
78
- const exportedName = importSpecifier.getNameNode().getText();
79
- return sourceFile.getExportedDeclarations().get(exportedName) ?? [];
80
- }
81
- function isBareModuleSpecifier(moduleSpecifier) {
82
- return !moduleSpecifier.startsWith('.') && !moduleSpecifier.startsWith('/');
83
- }
84
- function findRepoLocalAliasSourceFile(originSourceFile, moduleSpecifier) {
85
- const resolvedPath = resolveRepoLocalAliasImportPath(originSourceFile.getFilePath(), moduleSpecifier);
86
- if (!resolvedPath)
87
- return undefined;
88
- const project = originSourceFile.getProject();
89
- return findProjectSourceFileByImportPath(project, resolvedPath);
90
- }
91
- function resolveRepoLocalAliasImportPath(importingFilePath, moduleSpecifier) {
92
- const nearestTsConfigPath = findNearestTsConfigPath(importingFilePath);
93
- if (!nearestTsConfigPath)
94
- return undefined;
95
- const tsConfigPaths = getTsConfigPaths(nearestTsConfigPath);
96
- if (!tsConfigPaths)
97
- return undefined;
98
- for (const [pattern, targets] of Object.entries(tsConfigPaths.paths)) {
99
- const match = matchTsConfigPathPattern(pattern, moduleSpecifier);
100
- if (!match.matched)
101
- continue;
102
- for (const targetPattern of targets) {
103
- const substitutedTarget = substituteTsConfigPathTarget(targetPattern, match.wildcard);
104
- const resolvedPath = resolve(tsConfigPaths.baseUrl, substitutedTarget);
105
- const sourceFilePath = resolveImportSourcePath(resolvedPath);
106
- if (sourceFilePath)
107
- return sourceFilePath;
108
- }
109
- }
110
- return undefined;
111
- }
112
- function findNearestTsConfigPath(filePath) {
113
- if (nearestTsConfigPathCache.has(filePath)) {
114
- return nearestTsConfigPathCache.get(filePath) ?? undefined;
115
- }
116
- let currentDir = dirname(filePath);
117
- while (true) {
118
- for (const candidateName of ['tsconfig.json', 'jsconfig.json']) {
119
- const candidatePath = join(currentDir, candidateName);
120
- if (existsSync(candidatePath)) {
121
- nearestTsConfigPathCache.set(filePath, candidatePath);
122
- return candidatePath;
123
- }
124
- }
125
- const parentDir = dirname(currentDir);
126
- if (parentDir === currentDir) {
127
- nearestTsConfigPathCache.set(filePath, null);
128
- return undefined;
129
- }
130
- currentDir = parentDir;
131
- }
132
- }
133
- function getTsConfigPaths(tsConfigPath) {
134
- if (tsConfigPathsCache.has(tsConfigPath)) {
135
- return tsConfigPathsCache.get(tsConfigPath) ?? undefined;
136
- }
137
- const configFile = ts.readConfigFile(tsConfigPath, ts.sys.readFile);
138
- if (configFile.error || !configFile.config) {
139
- tsConfigPathsCache.set(tsConfigPath, null);
140
- return undefined;
141
- }
142
- const parsedConfig = ts.parseJsonConfigFileContent(configFile.config, ts.sys, dirname(tsConfigPath));
143
- const paths = parsedConfig.options.paths;
144
- if (!paths || Object.keys(paths).length === 0) {
145
- tsConfigPathsCache.set(tsConfigPath, null);
146
- return undefined;
147
- }
148
- const baseUrl = parsedConfig.options.baseUrl ?? dirname(tsConfigPath);
149
- const result = { baseUrl, paths };
150
- tsConfigPathsCache.set(tsConfigPath, result);
151
- return result;
152
- }
153
- function matchTsConfigPathPattern(pattern, specifier) {
154
- if (!pattern.includes('*')) {
155
- return { matched: pattern === specifier };
156
- }
157
- const [prefix, suffix] = pattern.split('*');
158
- if (!specifier.startsWith(prefix) || !specifier.endsWith(suffix)) {
159
- return { matched: false };
160
- }
161
- return {
162
- matched: true,
163
- wildcard: specifier.slice(prefix.length, specifier.length - suffix.length),
164
- };
165
- }
166
- function substituteTsConfigPathTarget(targetPattern, wildcard) {
167
- return wildcard === undefined ? targetPattern : targetPattern.replace('*', wildcard);
168
- }
169
- function resolveImportSourcePath(basePath) {
170
- const candidates = [
171
- basePath,
172
- `${basePath}.ts`,
173
- `${basePath}.tsx`,
174
- `${basePath}.js`,
175
- `${basePath}.jsx`,
176
- join(basePath, 'index.ts'),
177
- join(basePath, 'index.tsx'),
178
- join(basePath, 'index.js'),
179
- join(basePath, 'index.jsx'),
180
- ];
181
- return candidates.find((candidatePath) => existsSync(candidatePath));
182
- }
183
- function findProjectSourceFileByImportPath(project, resolvedPath) {
184
- const candidatePaths = [
185
- resolvedPath,
186
- `${resolvedPath}.ts`,
187
- `${resolvedPath}.tsx`,
188
- `${resolvedPath}.js`,
189
- `${resolvedPath}.jsx`,
190
- join(resolvedPath, 'index.ts'),
191
- join(resolvedPath, 'index.tsx'),
192
- join(resolvedPath, 'index.js'),
193
- join(resolvedPath, 'index.jsx'),
194
- ];
195
- for (const candidatePath of candidatePaths) {
196
- const sourceFile = project.getSourceFile(candidatePath);
197
- if (sourceFile)
198
- return sourceFile;
199
- }
200
- return undefined;
201
- }
202
- function findWorkspacePackageEntrySourceFile(originSourceFile, moduleSpecifier) {
203
- const project = originSourceFile.getProject();
204
- const candidateSourceFiles = project.getSourceFiles().filter((sourceFile) => {
205
- const manifest = getWorkspacePackageManifestForSourceFile(sourceFile);
206
- return manifest?.name === moduleSpecifier;
207
- });
208
- if (candidateSourceFiles.length === 0)
209
- return undefined;
210
- const packageRootDir = getWorkspacePackageManifestForSourceFile(candidateSourceFiles[0])?.rootDir;
211
- if (!packageRootDir)
212
- return undefined;
213
- const preferredEntryPaths = [
214
- join(packageRootDir, 'src/index.ts'),
215
- join(packageRootDir, 'src/index.tsx'),
216
- join(packageRootDir, 'index.ts'),
217
- join(packageRootDir, 'index.tsx'),
218
- ];
219
- for (const entryPath of preferredEntryPaths) {
220
- const entrySourceFile = project.getSourceFile(entryPath);
221
- if (entrySourceFile) {
222
- return entrySourceFile;
223
- }
224
- }
225
- return candidateSourceFiles.find((sourceFile) => sourceFile.getDirectoryPath() === join(packageRootDir, 'src'));
226
- }
227
- function getWorkspacePackageManifestForSourceFile(sourceFile) {
228
- const packageRootDir = findNearestPackageRootDir(sourceFile.getFilePath());
229
- if (!packageRootDir)
230
- return undefined;
231
- if (workspacePackageManifestCache.has(packageRootDir)) {
232
- return workspacePackageManifestCache.get(packageRootDir) ?? undefined;
233
- }
234
- const packageJsonPath = join(packageRootDir, 'package.json');
235
- try {
236
- const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
237
- const manifest = typeof packageJson.name === 'string' ? { name: packageJson.name, rootDir: packageRootDir } : null;
238
- workspacePackageManifestCache.set(packageRootDir, manifest);
239
- return manifest ?? undefined;
240
- }
241
- catch {
242
- workspacePackageManifestCache.set(packageRootDir, null);
243
- return undefined;
244
- }
245
- }
246
- function findNearestPackageRootDir(filePath) {
247
- if (packageRootByFilePathCache.has(filePath)) {
248
- return packageRootByFilePathCache.get(filePath) ?? undefined;
249
- }
250
- let currentDir = dirname(filePath);
251
- while (true) {
252
- if (existsSync(join(currentDir, 'package.json'))) {
253
- packageRootByFilePathCache.set(filePath, currentDir);
254
- return currentDir;
255
- }
256
- const parentDir = dirname(currentDir);
257
- if (parentDir === currentDir) {
258
- packageRootByFilePathCache.set(filePath, null);
259
- return undefined;
260
- }
261
- currentDir = parentDir;
262
- }
263
- }
@@ -1,16 +0,0 @@
1
- import type { RawComponentDefinition, ExtractionValidationIssue } from '../../types.js';
2
- export type { ExtractionValidationIssue } from '../../types.js';
3
- export declare function validateExtractedComponents(components: RawComponentDefinition[]): RawComponentDefinition[];
4
- export declare function shouldExcludeDueToValidation(component: RawComponentDefinition): boolean;
5
- /**
6
- * Format a stderr-ready warning describing components auto-rejected by the
7
- * extraction gate. Used by `analyze select --select-all --exclude-invalid`
8
- * and `analyze select-agent --exclude-invalid` so both opt-in paths emit a
9
- * consistent message — non-interactive callers (CI, orchestrator, scripted
10
- * pipeline) need to see WHICH components were excluded and WHY, not just
11
- * the bare counts.
12
- */
13
- export declare function formatExclusionWarning(rejected: Array<{
14
- name: string;
15
- validationIssues?: ExtractionValidationIssue[];
16
- }>): string;
@@ -1,94 +0,0 @@
1
- export function validateExtractedComponents(components) {
2
- const nameCounts = new Map();
3
- for (const component of components) {
4
- const key = component.name.trim();
5
- nameCounts.set(key, (nameCounts.get(key) ?? 0) + 1);
6
- }
7
- return components.map((component) => {
8
- const issues = [];
9
- if (!component.name.trim()) {
10
- issues.push({
11
- severity: 'error',
12
- code: 'EMPTY_COMPONENT_NAME',
13
- message: 'Component name must not be empty',
14
- });
15
- }
16
- for (let i = 0; i < component.props.length; i++) {
17
- if (!component.props[i].name.trim()) {
18
- issues.push({
19
- severity: 'error',
20
- code: 'EMPTY_PROP_NAME',
21
- message: `Prop at index ${i} has an empty name`,
22
- field: `props[${i}].name`,
23
- });
24
- }
25
- }
26
- for (let i = 0; i < component.slots.length; i++) {
27
- if (!component.slots[i].name.trim()) {
28
- // Warning, not error: SP-2's renameEmptySlots auto-recovers empty slot
29
- // names to children/slot_<n> before the LLM prompt, so the component
30
- // can still be generated. Asymmetric with EMPTY_PROP_NAME (still error)
31
- // because that path silently drops empty-named props in
32
- // loadCDFComponents — real data loss — instead of recovering them.
33
- issues.push({
34
- severity: 'warning',
35
- code: 'EMPTY_SLOT_NAME',
36
- message: `Slot at index ${i} has an empty name`,
37
- field: `slots[${i}].name`,
38
- });
39
- }
40
- }
41
- const propNames = new Set(component.props.map((p) => p.name.trim()).filter(Boolean));
42
- for (let i = 0; i < component.slots.length; i++) {
43
- const slotName = component.slots[i].name.trim();
44
- if (slotName && propNames.has(slotName)) {
45
- issues.push({
46
- severity: 'error',
47
- code: 'PROP_SLOT_NAME_COLLISION',
48
- message: `"${slotName}" is used as both a prop name and a slot name`,
49
- field: `slots[${i}].name`,
50
- });
51
- }
52
- }
53
- const nameKey = component.name.trim();
54
- if (nameKey && (nameCounts.get(nameKey) ?? 0) > 1) {
55
- issues.push({
56
- severity: 'error',
57
- code: 'DUPLICATE_COMPONENT_NAME',
58
- message: `Component name "${component.name}" appears more than once in the extracted set`,
59
- });
60
- }
61
- if (component.props.length === 0 && component.slots.length === 0) {
62
- issues.push({
63
- severity: 'warning',
64
- code: 'EMPTY_COMPONENT',
65
- message: 'Component has no props or slots and will be filtered out during generation',
66
- });
67
- }
68
- return { ...component, validationIssues: issues };
69
- });
70
- }
71
- export function shouldExcludeDueToValidation(component) {
72
- return (component.validationIssues ?? []).some((i) => i.severity === 'error');
73
- }
74
- /**
75
- * Format a stderr-ready warning describing components auto-rejected by the
76
- * extraction gate. Used by `analyze select --select-all --exclude-invalid`
77
- * and `analyze select-agent --exclude-invalid` so both opt-in paths emit a
78
- * consistent message — non-interactive callers (CI, orchestrator, scripted
79
- * pipeline) need to see WHICH components were excluded and WHY, not just
80
- * the bare counts.
81
- */
82
- export function formatExclusionWarning(rejected) {
83
- if (rejected.length === 0)
84
- return '';
85
- const lines = [`Warning: ${rejected.length} component(s) excluded due to validation errors:`];
86
- for (const comp of rejected) {
87
- const codes = (comp.validationIssues ?? [])
88
- .filter((i) => i.severity === 'error')
89
- .map((i) => i.code)
90
- .join(', ');
91
- lines.push(` ✗ ${comp.name} ${codes}`);
92
- }
93
- return lines.join('\n') + '\n';
94
- }
@@ -1,2 +0,0 @@
1
- import type { ComponentExtractionResult } from '../../types.js';
2
- export declare function extractVueTsxComponents(filePaths: string[]): Promise<ComponentExtractionResult>;