logicstamp-context 0.5.5 → 0.7.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 (90) hide show
  1. package/LLM_CONTEXT.md +67 -20
  2. package/README.md +50 -36
  3. package/dist/cli/commands/clean.d.ts +2 -2
  4. package/dist/cli/commands/clean.js +2 -2
  5. package/dist/cli/commands/compare.js +1 -1
  6. package/dist/cli/commands/compare.js.map +1 -1
  7. package/dist/cli/commands/context/configManager.js +2 -2
  8. package/dist/cli/commands/context/configManager.js.map +1 -1
  9. package/dist/cli/commands/context/contractBuilder.d.ts +1 -0
  10. package/dist/cli/commands/context/contractBuilder.d.ts.map +1 -1
  11. package/dist/cli/commands/context/contractBuilder.js +1 -1
  12. package/dist/cli/commands/context/contractBuilder.js.map +1 -1
  13. package/dist/cli/commands/context/incrementalWatch.d.ts +2 -2
  14. package/dist/cli/commands/context/incrementalWatch.d.ts.map +1 -1
  15. package/dist/cli/commands/context/incrementalWatch.js +100 -38
  16. package/dist/cli/commands/context/incrementalWatch.js.map +1 -1
  17. package/dist/cli/commands/context/index.d.ts +22 -2
  18. package/dist/cli/commands/context/index.d.ts.map +1 -1
  19. package/dist/cli/commands/context/index.js +24 -2
  20. package/dist/cli/commands/context/index.js.map +1 -1
  21. package/dist/cli/commands/context/statsCalculator.d.ts +1 -1
  22. package/dist/cli/commands/context/statsCalculator.js +4 -4
  23. package/dist/cli/commands/context/statsCalculator.js.map +1 -1
  24. package/dist/cli/commands/context/tokenEstimator.d.ts.map +1 -1
  25. package/dist/cli/commands/context/tokenEstimator.js +10 -7
  26. package/dist/cli/commands/context/tokenEstimator.js.map +1 -1
  27. package/dist/cli/commands/context/watchMode.d.ts +2 -2
  28. package/dist/cli/commands/context/watchMode.d.ts.map +1 -1
  29. package/dist/cli/commands/context/watchMode.js +8 -6
  30. package/dist/cli/commands/context/watchMode.js.map +1 -1
  31. package/dist/cli/commands/context.d.ts +2 -1
  32. package/dist/cli/commands/context.d.ts.map +1 -1
  33. package/dist/cli/commands/context.js +12 -7
  34. package/dist/cli/commands/context.js.map +1 -1
  35. package/dist/cli/commands/init.js +7 -7
  36. package/dist/cli/commands/init.js.map +1 -1
  37. package/dist/cli/commands/security.d.ts +1 -1
  38. package/dist/cli/commands/security.js +1 -1
  39. package/dist/cli/commands/style.d.ts +2 -2
  40. package/dist/cli/commands/style.js +2 -2
  41. package/dist/cli/commands/validate.d.ts +1 -1
  42. package/dist/cli/commands/validate.js +2 -2
  43. package/dist/cli/commands/validate.js.map +1 -1
  44. package/dist/cli/handlers/compareHandler.d.ts +1 -1
  45. package/dist/cli/handlers/compareHandler.js +5 -5
  46. package/dist/cli/handlers/compareHandler.js.map +1 -1
  47. package/dist/cli/handlers/contextHandler.d.ts +1 -1
  48. package/dist/cli/handlers/contextHandler.js +2 -2
  49. package/dist/cli/handlers/contextHandler.js.map +1 -1
  50. package/dist/cli/handlers/styleHandler.js +1 -1
  51. package/dist/cli/handlers/styleHandler.js.map +1 -1
  52. package/dist/cli/index.d.ts +2 -2
  53. package/dist/cli/index.js +10 -10
  54. package/dist/cli/index.js.map +1 -1
  55. package/dist/cli/parser/argumentParser.d.ts +1 -1
  56. package/dist/cli/parser/argumentParser.d.ts.map +1 -1
  57. package/dist/cli/parser/argumentParser.js +6 -1
  58. package/dist/cli/parser/argumentParser.js.map +1 -1
  59. package/dist/cli/parser/helpText.d.ts.map +1 -1
  60. package/dist/cli/parser/helpText.js +37 -30
  61. package/dist/cli/parser/helpText.js.map +1 -1
  62. package/dist/cli/stamp.d.ts +2 -2
  63. package/dist/cli/stamp.js +3 -3
  64. package/dist/cli/stamp.js.map +1 -1
  65. package/dist/core/pack/loader.d.ts +2 -0
  66. package/dist/core/pack/loader.d.ts.map +1 -1
  67. package/dist/core/pack/loader.js +106 -5
  68. package/dist/core/pack/loader.js.map +1 -1
  69. package/dist/extractors/react/propExtractor.d.ts.map +1 -1
  70. package/dist/extractors/react/propExtractor.js +164 -217
  71. package/dist/extractors/react/propExtractor.js.map +1 -1
  72. package/dist/extractors/styling/styleExtractor.d.ts +5 -2
  73. package/dist/extractors/styling/styleExtractor.d.ts.map +1 -1
  74. package/dist/extractors/styling/styleExtractor.js +177 -5
  75. package/dist/extractors/styling/styleExtractor.js.map +1 -1
  76. package/dist/types/UIFContract.d.ts +27 -4
  77. package/dist/types/UIFContract.d.ts.map +1 -1
  78. package/dist/types/UIFContract.js.map +1 -1
  79. package/dist/utils/config.d.ts +2 -0
  80. package/dist/utils/config.d.ts.map +1 -1
  81. package/dist/utils/config.js.map +1 -1
  82. package/dist/utils/fileLock.d.ts.map +1 -1
  83. package/dist/utils/fileLock.js +23 -4
  84. package/dist/utils/fileLock.js.map +1 -1
  85. package/dist/utils/schemaValidator.d.ts +24 -0
  86. package/dist/utils/schemaValidator.d.ts.map +1 -0
  87. package/dist/utils/schemaValidator.js +137 -0
  88. package/dist/utils/schemaValidator.js.map +1 -0
  89. package/package.json +6 -5
  90. package/schema/logicstamp.context.schema.json +70 -9
@@ -2,8 +2,9 @@
2
2
  * Loader module - Load contracts, manifests, and source code
3
3
  */
4
4
  import { readFile } from 'node:fs/promises';
5
- import { join, resolve, isAbsolute } from 'node:path';
5
+ import { join, resolve, isAbsolute, relative } from 'node:path';
6
6
  import { debugError } from '../../utils/debug.js';
7
+ import { validateUIFContract } from '../../utils/schemaValidator.js';
7
8
  import { loadSecurityReport, sanitizeCode } from '../../utils/codeSanitizer.js';
8
9
  // Cache expiration time (5 minutes) - balances performance vs memory for long-running processes
9
10
  const CACHE_MAX_AGE_MS = 5 * 60 * 1000;
@@ -37,7 +38,10 @@ let sanitizeStats = {
37
38
  filesWithSecrets: 0,
38
39
  totalSecretsReplaced: 0,
39
40
  filesProcessed: [],
41
+ securityReportLoaded: false,
40
42
  };
43
+ // Track whether security report was loaded during this context generation
44
+ let securityReportWasLoaded = false;
41
45
  /**
42
46
  * Record sanitization info into the module-level accumulator
43
47
  * Thread-safe: callers aggregate results and call this once after processing
@@ -66,12 +70,17 @@ export function recordSanitizationBatch(infos) {
66
70
  * Get and reset sanitization statistics
67
71
  */
68
72
  export function getAndResetSanitizeStats() {
69
- const stats = { ...sanitizeStats };
73
+ const stats = {
74
+ ...sanitizeStats,
75
+ securityReportLoaded: securityReportWasLoaded,
76
+ };
70
77
  sanitizeStats = {
71
78
  filesWithSecrets: 0,
72
79
  totalSecretsReplaced: 0,
73
80
  filesProcessed: [],
81
+ securityReportLoaded: false,
74
82
  };
83
+ securityReportWasLoaded = false;
75
84
  return stats;
76
85
  }
77
86
  /**
@@ -111,17 +120,83 @@ export async function loadManifest(basePath) {
111
120
  * Sidecar path is computed from the manifest key (project-relative): resolved from projectRoot + key + '.uif.json'
112
121
  */
113
122
  export async function loadContract(entryId, projectRoot) {
123
+ // Validate path stays within project root (prevents path traversal attacks)
124
+ if (!isPathWithinRoot(entryId, projectRoot)) {
125
+ debugError('loader', 'loadContract', {
126
+ entryId,
127
+ projectRoot,
128
+ message: 'Path traversal attempt detected - path outside project root',
129
+ });
130
+ return null;
131
+ }
114
132
  // Resolve relative path from project root
115
133
  const absolutePath = isAbsolute(entryId) ? entryId : resolve(projectRoot, entryId);
116
134
  const sidecarPath = `${absolutePath}.uif.json`;
135
+ // 1. Read file
136
+ let content;
117
137
  try {
118
- const content = await readFile(sidecarPath, 'utf8');
119
- return JSON.parse(content);
138
+ content = await readFile(sidecarPath, 'utf8');
120
139
  }
121
140
  catch (error) {
122
- // Sidecar file doesn't exist or can't be read
141
+ const err = error;
142
+ // File not found is normal (sidecar doesn't exist yet) - silent return
143
+ if (err.code === 'ENOENT') {
144
+ return null;
145
+ }
146
+ // Other read errors (permissions, etc.) - log and return
147
+ debugError('loader', 'loadContract', {
148
+ sidecarPath,
149
+ entryId,
150
+ message: 'Failed to read sidecar file',
151
+ errorCode: err.code,
152
+ errorMessage: err.message,
153
+ });
154
+ return null;
155
+ }
156
+ // 2. Parse JSON
157
+ let parsed;
158
+ try {
159
+ parsed = JSON.parse(content);
160
+ }
161
+ catch (error) {
162
+ const err = error;
163
+ debugError('loader', 'loadContract', {
164
+ sidecarPath,
165
+ entryId,
166
+ message: 'Invalid JSON in sidecar file',
167
+ parseError: err.message,
168
+ });
169
+ return null;
170
+ }
171
+ // 3. Validate against UIFContract schema
172
+ const { valid, errors, data } = validateUIFContract(parsed);
173
+ if (!valid) {
174
+ // Cap errors to prevent log spam (AJV can output dozens of lines)
175
+ const MAX_ERRORS = 20;
176
+ const shownErrors = errors.slice(0, MAX_ERRORS);
177
+ const extraCount = errors.length - shownErrors.length;
178
+ debugError('loader', 'loadContract', {
179
+ sidecarPath,
180
+ entryId,
181
+ message: 'Invalid contract schema',
182
+ validationErrors: shownErrors,
183
+ ...(extraCount > 0 && { additionalErrors: `+${extraCount} more` }),
184
+ hint: 'This file may have been generated by an older LogicStamp version; rerun `stamp context`',
185
+ });
123
186
  return null;
124
187
  }
188
+ return data;
189
+ }
190
+ /**
191
+ * Check if a file path is within the project root directory
192
+ * Prevents path traversal attacks (e.g., `../../../sensitive.json`)
193
+ */
194
+ function isPathWithinRoot(filePath, rootPath) {
195
+ const resolvedPath = resolve(rootPath, filePath);
196
+ const relativePath = relative(rootPath, resolvedPath);
197
+ // Path is outside root if relative path starts with '..' or is absolute
198
+ // On Windows, also check for drive letter changes (e.g., C: to D:)
199
+ return !relativePath.startsWith('..') && !isAbsolute(relativePath);
125
200
  }
126
201
  /**
127
202
  * Normalize project root for comparison (handles Windows case-insensitivity and path variations)
@@ -141,6 +216,10 @@ function normalizeProjectRoot(path) {
141
216
  async function getSecurityReport(projectRoot) {
142
217
  // Check if we have a valid cached report
143
218
  if (isCacheValid(securityReportCache, projectRoot)) {
219
+ // Track that we have a security report available
220
+ if (securityReportCache.report !== null) {
221
+ securityReportWasLoaded = true;
222
+ }
144
223
  return securityReportCache.report;
145
224
  }
146
225
  // Load and cache the report with timestamp
@@ -150,6 +229,10 @@ async function getSecurityReport(projectRoot) {
150
229
  projectRoot,
151
230
  timestamp: Date.now(),
152
231
  };
232
+ // Track that we have a security report available
233
+ if (report !== null) {
234
+ securityReportWasLoaded = true;
235
+ }
153
236
  return report;
154
237
  }
155
238
  /**
@@ -161,6 +244,15 @@ async function getSecurityReport(projectRoot) {
161
244
  * Callers should aggregate sanitization info and record it once after batch processing.
162
245
  */
163
246
  export async function extractCodeHeader(entryId, projectRoot) {
247
+ // Validate path stays within project root (prevents path traversal attacks)
248
+ if (!isPathWithinRoot(entryId, projectRoot)) {
249
+ debugError('loader', 'extractCodeHeader', {
250
+ entryId,
251
+ projectRoot,
252
+ message: 'Path traversal attempt detected - path outside project root',
253
+ });
254
+ return { header: null };
255
+ }
164
256
  try {
165
257
  const absolutePath = isAbsolute(entryId) ? entryId : resolve(projectRoot, entryId);
166
258
  // Read file content (source file is never modified)
@@ -201,6 +293,15 @@ export async function extractCodeHeader(entryId, projectRoot) {
201
293
  * Callers should aggregate sanitization info and record it once after batch processing.
202
294
  */
203
295
  export async function readSourceCode(entryId, projectRoot) {
296
+ // Validate path stays within project root (prevents path traversal attacks)
297
+ if (!isPathWithinRoot(entryId, projectRoot)) {
298
+ debugError('loader', 'readSourceCode', {
299
+ entryId,
300
+ projectRoot,
301
+ message: 'Path traversal attempt detected - path outside project root',
302
+ });
303
+ return { code: null };
304
+ }
204
305
  try {
205
306
  const absolutePath = isAbsolute(entryId) ? entryId : resolve(projectRoot, entryId);
206
307
  // Read file content (source file is never modified)
@@ -1 +1 @@
1
- {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/core/pack/loader.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/core/pack/loader.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"propExtractor.d.ts","sourceRoot":"","sources":["../../../src/extractors/react/propExtractor.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAA0B,MAAM,UAAU,CAAC;AAC9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AA0B3D;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CA4NzE;AAID,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC"}
1
+ {"version":3,"file":"propExtractor.d.ts","sourceRoot":"","sources":["../../../src/extractors/react/propExtractor.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAsG,MAAM,UAAU,CAAC;AAC1I,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAiN3D;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAiDzE;AAID,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC"}
@@ -8,22 +8,157 @@ import { hasExportedHooks, extractHookParameters } from './hookParameterExtracto
8
8
  // TypeScript TypeFlags.Undefined constant (0x4000 = 16384)
9
9
  // Used for checking if a union type includes undefined
10
10
  const TYPEFLAG_UNDEFINED = 16384; // ts.TypeFlags.Undefined
11
+ /**
12
+ * Wraps a function call in a try-catch, returning a default value on error.
13
+ * Use this to simplify error handling for operations that may fail but shouldn't
14
+ * stop processing of other items.
15
+ */
16
+ function safeExtract(fn, defaultValue, errorContext) {
17
+ try {
18
+ return fn();
19
+ }
20
+ catch (error) {
21
+ if (errorContext) {
22
+ debugError('propExtractor', 'extractProps', {
23
+ filePath: errorContext.filePath,
24
+ error: error instanceof Error ? error.message : String(error),
25
+ context: errorContext.context,
26
+ });
27
+ }
28
+ return defaultValue;
29
+ }
30
+ }
11
31
  /**
12
32
  * Safely get TypeScript type flags from a ts-morph Type
13
33
  * Accesses the underlying TypeScript compiler type to get flags
14
34
  */
15
35
  function getTypeFlags(type) {
16
- try {
17
- // Access the underlying TypeScript compiler type
18
- const compilerType = type.compilerType;
19
- if (compilerType && typeof compilerType.flags === 'number') {
20
- return compilerType.flags;
36
+ const compilerType = type.compilerType;
37
+ if (compilerType && typeof compilerType.flags === 'number') {
38
+ return compilerType.flags;
39
+ }
40
+ return 0;
41
+ }
42
+ /**
43
+ * Check if a union type includes undefined
44
+ */
45
+ function isUndefinedType(type) {
46
+ const flags = getTypeFlags(type);
47
+ if ((flags & TYPEFLAG_UNDEFINED) !== 0) {
48
+ return true;
49
+ }
50
+ return type.getText() === 'undefined';
51
+ }
52
+ /**
53
+ * Check if a union type contains undefined and extract the non-undefined type text
54
+ * Returns { hasUndefined, typeText } where typeText excludes undefined
55
+ */
56
+ function analyzeUnionForUndefined(propType) {
57
+ if (!propType.isUnion()) {
58
+ return { hasUndefined: false, typeText: propType.getText() };
59
+ }
60
+ const unionTypes = propType.getUnionTypes();
61
+ const hasUndefined = unionTypes.some(isUndefinedType);
62
+ if (!hasUndefined) {
63
+ return { hasUndefined: false, typeText: propType.getText() };
64
+ }
65
+ const typeText = unionTypes
66
+ .filter(ut => !isUndefinedType(ut))
67
+ .map(ut => ut.getText())
68
+ .join(' | ');
69
+ return { hasUndefined: true, typeText };
70
+ }
71
+ /**
72
+ * Extract a single prop from an interface property
73
+ */
74
+ function extractInterfaceProp(prop) {
75
+ const name = prop.getName();
76
+ let isOptional = prop.hasQuestionToken();
77
+ let type = prop.getType().getText();
78
+ let didRebuildFromUnion = false;
79
+ // Check for union-with-undefined (some people write foo: string | undefined without ?)
80
+ if (!isOptional) {
81
+ const analysis = analyzeUnionForUndefined(prop.getType());
82
+ if (analysis.hasUndefined) {
83
+ isOptional = true;
84
+ type = analysis.typeText;
85
+ didRebuildFromUnion = true;
21
86
  }
22
87
  }
23
- catch {
24
- // Fallback if compiler type not accessible
88
+ // If optional but we didn't rebuild from union types, strip undefined from type text
89
+ if (isOptional && !didRebuildFromUnion) {
90
+ type = stripUndefinedFromUnionText(type);
25
91
  }
26
- return 0;
92
+ return { name, propType: normalizePropType(type, isOptional) };
93
+ }
94
+ /**
95
+ * Extract props from a single interface declaration
96
+ */
97
+ function extractPropsFromInterface(iface, filePath) {
98
+ const props = {};
99
+ if (!/Props$/i.test(iface.getName())) {
100
+ return props;
101
+ }
102
+ for (const prop of iface.getProperties()) {
103
+ const result = safeExtract(() => extractInterfaceProp(prop), null, { filePath, context: 'props-interface-property' });
104
+ if (result) {
105
+ props[result.name] = result.propType;
106
+ }
107
+ }
108
+ return props;
109
+ }
110
+ /**
111
+ * Extract a single prop from a type alias property symbol
112
+ */
113
+ function extractTypeAliasProp(prop, typeAlias) {
114
+ const name = prop.getName();
115
+ let isOptional = false;
116
+ let propType = prop.getTypeAtLocation(typeAlias).getText();
117
+ let didRebuildFromUnion = false;
118
+ // Method 1: Check if type is a union that includes undefined
119
+ const propTypeObj = prop.getTypeAtLocation(typeAlias);
120
+ const analysis = analyzeUnionForUndefined(propTypeObj);
121
+ if (analysis.hasUndefined) {
122
+ isOptional = true;
123
+ propType = analysis.typeText;
124
+ didRebuildFromUnion = true;
125
+ }
126
+ // Method 2: Check declarations for question token (AST method)
127
+ if (!isOptional) {
128
+ const declarations = prop.getDeclarations();
129
+ isOptional = declarations.some((decl) => {
130
+ if (Node.isPropertySignature(decl)) {
131
+ return decl.hasQuestionToken();
132
+ }
133
+ if (Node.isPropertyDeclaration(decl)) {
134
+ return decl.hasQuestionToken();
135
+ }
136
+ return false;
137
+ });
138
+ }
139
+ // If optional but we didn't rebuild from union types, strip undefined from type text
140
+ if (isOptional && !didRebuildFromUnion) {
141
+ propType = stripUndefinedFromUnionText(propType);
142
+ }
143
+ return { name, propType: normalizePropType(propType, isOptional) };
144
+ }
145
+ /**
146
+ * Extract props from a single type alias declaration
147
+ */
148
+ function extractPropsFromTypeAlias(typeAlias, filePath) {
149
+ const props = {};
150
+ if (!/Props$/i.test(typeAlias.getName())) {
151
+ return props;
152
+ }
153
+ const type = typeAlias.getType();
154
+ const properties = type.getProperties();
155
+ for (const prop of properties) {
156
+ const result = safeExtract(() => extractTypeAliasProp(prop, typeAlias), null, { filePath, context: 'props-typealias-property' });
157
+ if (result) {
158
+ props[result.name] = result.propType;
159
+ }
160
+ }
161
+ return props;
27
162
  }
28
163
  /**
29
164
  * Extract component props from TypeScript interfaces/types
@@ -32,216 +167,28 @@ function getTypeFlags(type) {
32
167
  export function extractProps(source) {
33
168
  const props = {};
34
169
  const filePath = source.getFilePath?.() ?? 'unknown';
35
- try {
36
- // Look for interfaces ending with Props
37
- try {
38
- source.getInterfaces().forEach((iface) => {
39
- try {
40
- if (/Props$/i.test(iface.getName())) {
41
- iface.getProperties().forEach((prop) => {
42
- try {
43
- const name = prop.getName();
44
- let isOptional = prop.hasQuestionToken();
45
- let type = prop.getType().getText();
46
- let didRebuildFromUnion = false;
47
- // Also check for union-with-undefined (some people write foo: string | undefined without ?)
48
- if (!isOptional) {
49
- try {
50
- const propType = prop.getType();
51
- if (propType.isUnion()) {
52
- const unionTypes = propType.getUnionTypes();
53
- const hasUndefined = unionTypes.some(ut => {
54
- try {
55
- const flags = getTypeFlags(ut);
56
- if ((flags & TYPEFLAG_UNDEFINED) !== 0) {
57
- return true;
58
- }
59
- }
60
- catch {
61
- // Fallback to string check if flags not available
62
- }
63
- const text = ut.getText();
64
- return text === 'undefined';
65
- });
66
- if (hasUndefined) {
67
- isOptional = true;
68
- // Normalize type text by removing undefined from union (handles any position)
69
- type = unionTypes
70
- .filter(ut => {
71
- const flags = getTypeFlags(ut);
72
- if ((flags & TYPEFLAG_UNDEFINED) !== 0) {
73
- return false;
74
- }
75
- return ut.getText() !== 'undefined';
76
- })
77
- .map(ut => ut.getText())
78
- .join(' | ');
79
- didRebuildFromUnion = true;
80
- }
81
- }
82
- }
83
- catch {
84
- // Fallback if union check fails
85
- }
86
- }
87
- // If optional but we didn't rebuild from union types, strip undefined from type text
88
- // This handles cases like "foo?: undefined | string" where ? token made us skip union logic
89
- if (isOptional && !didRebuildFromUnion) {
90
- type = stripUndefinedFromUnionText(type);
91
- }
92
- props[name] = normalizePropType(type, isOptional);
93
- }
94
- catch (error) {
95
- debugError('propExtractor', 'extractProps', {
96
- filePath,
97
- error: error instanceof Error ? error.message : String(error),
98
- context: 'props-interface-property',
99
- });
100
- // Continue with next property
101
- }
102
- });
103
- }
104
- }
105
- catch (error) {
106
- debugError('propExtractor', 'extractProps', {
107
- filePath,
108
- error: error instanceof Error ? error.message : String(error),
109
- context: 'props-interface',
110
- });
111
- // Continue with next interface
112
- }
113
- });
114
- }
115
- catch (error) {
116
- debugError('propExtractor', 'extractProps', {
117
- filePath,
118
- error: error instanceof Error ? error.message : String(error),
119
- context: 'props-interfaces-batch',
120
- });
121
- }
122
- // Look for type aliases ending with Props
123
- try {
124
- source.getTypeAliases().forEach((typeAlias) => {
125
- try {
126
- if (/Props$/i.test(typeAlias.getName())) {
127
- const type = typeAlias.getType();
128
- const properties = type.getProperties();
129
- properties.forEach((prop) => {
130
- try {
131
- const name = prop.getName();
132
- // Check if optional using TypeScript's type system
133
- let isOptional = false;
134
- let propType = prop.getTypeAtLocation(typeAlias).getText();
135
- let didRebuildFromUnion = false;
136
- // Method 1: Check if type is a union that includes undefined
137
- // Use type flags instead of string matching to avoid false positives
138
- try {
139
- const propTypeObj = prop.getTypeAtLocation(typeAlias);
140
- if (propTypeObj.isUnion()) {
141
- const unionTypes = propTypeObj.getUnionTypes();
142
- const hasUndefined = unionTypes.some(ut => {
143
- // Check type flags for undefined (more robust than string matching)
144
- const flags = getTypeFlags(ut);
145
- if ((flags & TYPEFLAG_UNDEFINED) !== 0) {
146
- return true;
147
- }
148
- // Fallback: exact string match only (avoid false positives like SomeUndefinedType)
149
- const text = ut.getText();
150
- return text === 'undefined';
151
- });
152
- if (hasUndefined) {
153
- isOptional = true;
154
- // Normalize type text by removing undefined from union (handles any position)
155
- // This ensures consistent output: undefined | string and string | undefined both become string
156
- propType = unionTypes
157
- .filter(ut => {
158
- const flags = getTypeFlags(ut);
159
- if ((flags & TYPEFLAG_UNDEFINED) !== 0) {
160
- return false;
161
- }
162
- return ut.getText() !== 'undefined';
163
- })
164
- .map(ut => ut.getText())
165
- .join(' | ');
166
- didRebuildFromUnion = true;
167
- }
168
- }
169
- }
170
- catch {
171
- // Fallback if union check fails
172
- }
173
- // Method 2: Check declarations for question token (AST method)
174
- if (!isOptional) {
175
- const declarations = prop.getDeclarations();
176
- isOptional = declarations.some((decl) => {
177
- // Use AST method to check for question token
178
- // PropertySignature and PropertyDeclaration both have hasQuestionToken()
179
- if (Node.isPropertySignature(decl)) {
180
- return decl.hasQuestionToken();
181
- }
182
- if (Node.isPropertyDeclaration(decl)) {
183
- return decl.hasQuestionToken();
184
- }
185
- return false;
186
- });
187
- }
188
- // If optional but we didn't rebuild from union types, strip undefined from type text
189
- // This handles cases like "foo?: undefined | string" where ? token made us skip union logic
190
- // Also handles "foo?: string | number" where union exists but doesn't contain undefined
191
- if (isOptional && !didRebuildFromUnion) {
192
- propType = stripUndefinedFromUnionText(propType);
193
- }
194
- props[name] = normalizePropType(propType, isOptional);
195
- }
196
- catch (error) {
197
- debugError('propExtractor', 'extractProps', {
198
- filePath,
199
- error: error instanceof Error ? error.message : String(error),
200
- context: 'props-typealias-property',
201
- });
202
- // Continue with next property
203
- }
204
- });
205
- }
206
- }
207
- catch (error) {
208
- debugError('propExtractor', 'extractProps', {
209
- filePath,
210
- error: error instanceof Error ? error.message : String(error),
211
- context: 'props-typealias',
212
- });
213
- // Continue with next type alias
214
- }
215
- });
216
- }
217
- catch (error) {
218
- debugError('propExtractor', 'extractProps', {
219
- filePath,
220
- error: error instanceof Error ? error.message : String(error),
221
- context: 'props-typealiases-batch',
222
- });
223
- }
224
- // Always try to extract hook parameters if there are exported hooks
225
- // This ensures hook parameters are captured even if there's a Props interface
226
- // Props take priority on conflicts (if a prop exists in both, Props value is kept)
227
- // Quick check: only extract if there might be exported hooks (performance optimization)
228
- if (hasExportedHooks(source)) {
229
- const hookParams = extractHookParameters(source);
230
- if (Object.keys(hookParams).length > 0) {
231
- // Merge hook parameters with Props, with Props taking priority on conflicts
232
- // Save original props to preserve Props values, then merge hookParams, then restore Props
233
- const originalProps = { ...props };
234
- Object.assign(props, hookParams);
235
- Object.assign(props, originalProps); // Props override any conflicting hook parameters
236
- }
237
- }
170
+ // Extract props from interfaces ending with Props
171
+ const interfaces = safeExtract(() => source.getInterfaces(), [], { filePath, context: 'props-interfaces-batch' });
172
+ for (const iface of interfaces) {
173
+ const ifaceProps = safeExtract(() => extractPropsFromInterface(iface, filePath), {}, { filePath, context: 'props-interface' });
174
+ Object.assign(props, ifaceProps);
238
175
  }
239
- catch (error) {
240
- debugError('propExtractor', 'extractProps', {
241
- filePath,
242
- error: error instanceof Error ? error.message : String(error),
243
- });
244
- return {};
176
+ // Extract props from type aliases ending with Props
177
+ const typeAliases = safeExtract(() => source.getTypeAliases(), [], { filePath, context: 'props-typealiases-batch' });
178
+ for (const typeAlias of typeAliases) {
179
+ const typeAliasProps = safeExtract(() => extractPropsFromTypeAlias(typeAlias, filePath), {}, { filePath, context: 'props-typealias' });
180
+ Object.assign(props, typeAliasProps);
181
+ }
182
+ // Extract hook parameters if there are exported hooks
183
+ // Props take priority on conflicts (if a prop exists in both, Props value is kept)
184
+ if (hasExportedHooks(source)) {
185
+ const hookParams = extractHookParameters(source);
186
+ if (Object.keys(hookParams).length > 0) {
187
+ // Merge hook parameters with Props, with Props taking priority on conflicts
188
+ const originalProps = { ...props };
189
+ Object.assign(props, hookParams);
190
+ Object.assign(props, originalProps); // Props override any conflicting hook parameters
191
+ }
245
192
  }
246
193
  return props;
247
194
  }