@wix/zero-config-implementation 1.31.0 → 1.32.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.
@@ -14,6 +14,7 @@ export interface ResolvedType {
14
14
  /**
15
15
  * Resolved default value with its type.
16
16
  * For literals (string, number, boolean, null), the value is the actual JavaScript value.
17
+ * For structured literals (object, array), the value is the parsed JavaScript value.
17
18
  * For unresolvable values (references, expressions), we store the raw source text.
18
19
  */
19
20
  export type DefaultValue = {
@@ -28,6 +29,12 @@ export type DefaultValue = {
28
29
  } | {
29
30
  kind: 'null';
30
31
  value: null;
32
+ } | {
33
+ kind: 'object';
34
+ value: Record<string, unknown>;
35
+ } | {
36
+ kind: 'array';
37
+ value: unknown[];
31
38
  } | {
32
39
  kind: 'unresolved';
33
40
  value: string;
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "registry": "https://registry.npmjs.org/",
5
5
  "access": "public"
6
6
  },
7
- "version": "1.31.0",
7
+ "version": "1.32.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": "47671a9f6b5bba6b6a6a93ccf874198731eefd39404baf528141978b"
86
+ "falconPackageHash": "459bf8c730865e0703e2a8248d887164542b0044ede2b6bcdae37271"
87
87
  }
@@ -74,20 +74,8 @@ function generateMockValue(propInfo: PropInfo, propName: string, path: string, r
74
74
  return generateValueFromResolvedType(propInfo.resolvedType, propName, path, registrar)
75
75
  }
76
76
 
77
- /**
78
- * Extract the actual value from a DefaultValue object
79
- */
80
77
  function extractDefaultValueValue(defaultValue: DefaultValue): unknown {
81
- switch (defaultValue.kind) {
82
- case 'string':
83
- case 'number':
84
- case 'boolean':
85
- case 'null':
86
- return defaultValue.value
87
- case 'unresolved':
88
- // For unresolved values, return the raw string (e.g., MY_CONST)
89
- return defaultValue.value
90
- }
78
+ return defaultValue.value
91
79
  }
92
80
 
93
81
  /**
@@ -372,6 +372,17 @@ function parseDefaultValueFromString(text: string, fallbackToString = false): De
372
372
  return { kind: 'string', value: trimmed.slice(1, -1) }
373
373
  }
374
374
 
375
+ // Object / array literals: parse via the TS compiler API so single-quoted
376
+ // strings and unquoted keys are handled correctly.
377
+ if (trimmed.startsWith('{') || trimmed.startsWith('[')) {
378
+ const parsed = tryParseStructuredLiteral(trimmed)
379
+ if (parsed !== undefined) {
380
+ return Array.isArray(parsed)
381
+ ? { kind: 'array', value: parsed }
382
+ : { kind: 'object', value: parsed as Record<string, unknown> }
383
+ }
384
+ }
385
+
375
386
  // react-docgen-typescript strips quotes from string defaults, so treat as string
376
387
  if (fallbackToString) {
377
388
  return { kind: 'string', value: trimmed }
@@ -381,6 +392,82 @@ function parseDefaultValueFromString(text: string, fallbackToString = false): De
381
392
  return { kind: 'unresolved', value: trimmed }
382
393
  }
383
394
 
395
+ /**
396
+ * Attempts to parse a string that looks like a TS object or array literal into
397
+ * an actual JavaScript value. Uses `ts.createSourceFile` so that single-quoted
398
+ * strings, unquoted keys, and nested structures are all handled natively.
399
+ *
400
+ * Returns `undefined` when any part of the expression cannot be statically
401
+ * evaluated (references, function calls, binary expressions, etc.).
402
+ */
403
+ function tryParseStructuredLiteral(text: string): Record<string, unknown> | unknown[] | undefined {
404
+ const sourceFile = ts.createSourceFile('__default__.ts', `const __v__ = ${text}`, ts.ScriptTarget.Latest, true)
405
+
406
+ const statement = sourceFile.statements[0]
407
+ if (!statement || !ts.isVariableStatement(statement)) return undefined
408
+
409
+ const initializer = statement.declarationList.declarations[0]?.initializer
410
+ if (!initializer) return undefined
411
+
412
+ return evaluateLiteralExpression(initializer) as Record<string, unknown> | unknown[] | undefined
413
+ }
414
+
415
+ /**
416
+ * Recursively evaluates a TS AST node into a plain JS value.
417
+ * Only pure literals are supported; returns `undefined` for anything dynamic.
418
+ *
419
+ * The sentinel `undefined` means "could not evaluate" -- this is unambiguous
420
+ * because `null` literals evaluate to `null`, and there is no `undefined`
421
+ * keyword in the TS AST (it is a global identifier, not a literal).
422
+ */
423
+ function evaluateLiteralExpression(node: ts.Expression): unknown {
424
+ if (ts.isObjectLiteralExpression(node)) {
425
+ const result: Record<string, unknown> = {}
426
+ for (const property of node.properties) {
427
+ if (!ts.isPropertyAssignment(property)) return undefined
428
+ const key = getStaticPropertyName(property.name)
429
+ if (key === undefined) return undefined
430
+
431
+ const value = evaluateLiteralExpression(property.initializer)
432
+ if (value === undefined) return undefined
433
+ result[key] = value
434
+ }
435
+ return result
436
+ }
437
+
438
+ if (ts.isArrayLiteralExpression(node)) {
439
+ const elements: unknown[] = []
440
+ for (const element of node.elements) {
441
+ const value = evaluateLiteralExpression(element)
442
+ if (value === undefined) return undefined
443
+ elements.push(value)
444
+ }
445
+ return elements
446
+ }
447
+
448
+ if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) return node.text
449
+ if (ts.isNumericLiteral(node)) return Number(node.text)
450
+ if (
451
+ ts.isPrefixUnaryExpression(node) &&
452
+ node.operator === ts.SyntaxKind.MinusToken &&
453
+ ts.isNumericLiteral(node.operand)
454
+ ) {
455
+ return -Number(node.operand.text)
456
+ }
457
+ if (node.kind === ts.SyntaxKind.TrueKeyword) return true
458
+ if (node.kind === ts.SyntaxKind.FalseKeyword) return false
459
+ if (node.kind === ts.SyntaxKind.NullKeyword) return null
460
+
461
+ return undefined
462
+ }
463
+
464
+ function getStaticPropertyName(name: ts.PropertyName): string | undefined {
465
+ if (ts.isIdentifier(name) || ts.isStringLiteral(name) || ts.isNumericLiteral(name)) {
466
+ return name.text
467
+ }
468
+ return undefined
469
+ }
470
+
384
471
  // ─────────────────────────────────────────────────────────────────────────────
385
472
  // Helpers
386
473
  // ─────────────────────────────────────────────────────────────────────────────
@@ -26,6 +26,7 @@ export interface ResolvedType {
26
26
  /**
27
27
  * Resolved default value with its type.
28
28
  * For literals (string, number, boolean, null), the value is the actual JavaScript value.
29
+ * For structured literals (object, array), the value is the parsed JavaScript value.
29
30
  * For unresolvable values (references, expressions), we store the raw source text.
30
31
  */
31
32
  export type DefaultValue =
@@ -33,7 +34,9 @@ export type DefaultValue =
33
34
  | { kind: 'number'; value: number }
34
35
  | { kind: 'boolean'; value: boolean }
35
36
  | { kind: 'null'; value: null }
36
- | { kind: 'unresolved'; value: string } // For references like MY_CONST or complex expressions
37
+ | { kind: 'object'; value: Record<string, unknown> }
38
+ | { kind: 'array'; value: unknown[] }
39
+ | { kind: 'unresolved'; value: string }
37
40
 
38
41
  export interface PropInfo {
39
42
  name: string