codemeld 2.1.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/README.md +514 -0
- package/bin/cli.js +2 -0
- package/dist/ai/agent.d.ts +124 -0
- package/dist/ai/agent.d.ts.map +1 -0
- package/dist/ai/agent.js +289 -0
- package/dist/ai/agent.js.map +1 -0
- package/dist/ai/index.d.ts +10 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +10 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/prompts.d.ts +35 -0
- package/dist/ai/prompts.d.ts.map +1 -0
- package/dist/ai/prompts.js +166 -0
- package/dist/ai/prompts.js.map +1 -0
- package/dist/ai/refinement-loop.d.ts +29 -0
- package/dist/ai/refinement-loop.d.ts.map +1 -0
- package/dist/ai/refinement-loop.js +180 -0
- package/dist/ai/refinement-loop.js.map +1 -0
- package/dist/ai/tools.d.ts +17 -0
- package/dist/ai/tools.d.ts.map +1 -0
- package/dist/ai/tools.js +353 -0
- package/dist/ai/tools.js.map +1 -0
- package/dist/ai/visual-compare.d.ts +43 -0
- package/dist/ai/visual-compare.d.ts.map +1 -0
- package/dist/ai/visual-compare.js +176 -0
- package/dist/ai/visual-compare.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +179 -0
- package/dist/cli.js.map +1 -0
- package/dist/converter.d.ts +10 -0
- package/dist/converter.d.ts.map +1 -0
- package/dist/converter.js +836 -0
- package/dist/converter.js.map +1 -0
- package/dist/deconverter.d.ts +19 -0
- package/dist/deconverter.d.ts.map +1 -0
- package/dist/deconverter.js +188 -0
- package/dist/deconverter.js.map +1 -0
- package/dist/frameworks/angular-adapter.d.ts +27 -0
- package/dist/frameworks/angular-adapter.d.ts.map +1 -0
- package/dist/frameworks/angular-adapter.js +617 -0
- package/dist/frameworks/angular-adapter.js.map +1 -0
- package/dist/frameworks/index.d.ts +10 -0
- package/dist/frameworks/index.d.ts.map +1 -0
- package/dist/frameworks/index.js +21 -0
- package/dist/frameworks/index.js.map +1 -0
- package/dist/frameworks/nextjs-adapter.d.ts +22 -0
- package/dist/frameworks/nextjs-adapter.d.ts.map +1 -0
- package/dist/frameworks/nextjs-adapter.js +392 -0
- package/dist/frameworks/nextjs-adapter.js.map +1 -0
- package/dist/frameworks/react-adapter.d.ts +21 -0
- package/dist/frameworks/react-adapter.d.ts.map +1 -0
- package/dist/frameworks/react-adapter.js +71 -0
- package/dist/frameworks/react-adapter.js.map +1 -0
- package/dist/frameworks/svelte-adapter.d.ts +27 -0
- package/dist/frameworks/svelte-adapter.d.ts.map +1 -0
- package/dist/frameworks/svelte-adapter.js +519 -0
- package/dist/frameworks/svelte-adapter.js.map +1 -0
- package/dist/frameworks/types.d.ts +78 -0
- package/dist/frameworks/types.d.ts.map +1 -0
- package/dist/frameworks/types.js +2 -0
- package/dist/frameworks/types.js.map +1 -0
- package/dist/frameworks/vue-adapter.d.ts +34 -0
- package/dist/frameworks/vue-adapter.d.ts.map +1 -0
- package/dist/frameworks/vue-adapter.js +632 -0
- package/dist/frameworks/vue-adapter.js.map +1 -0
- package/dist/generators/accessibility-generator.d.ts +43 -0
- package/dist/generators/accessibility-generator.d.ts.map +1 -0
- package/dist/generators/accessibility-generator.js +507 -0
- package/dist/generators/accessibility-generator.js.map +1 -0
- package/dist/generators/asset-handler.d.ts +14 -0
- package/dist/generators/asset-handler.d.ts.map +1 -0
- package/dist/generators/asset-handler.js +79 -0
- package/dist/generators/asset-handler.js.map +1 -0
- package/dist/generators/build-verifier.d.ts +8 -0
- package/dist/generators/build-verifier.d.ts.map +1 -0
- package/dist/generators/build-verifier.js +64 -0
- package/dist/generators/build-verifier.js.map +1 -0
- package/dist/generators/component-extractor.d.ts +25 -0
- package/dist/generators/component-extractor.d.ts.map +1 -0
- package/dist/generators/component-extractor.js +146 -0
- package/dist/generators/component-extractor.js.map +1 -0
- package/dist/generators/component-generator.d.ts +12 -0
- package/dist/generators/component-generator.d.ts.map +1 -0
- package/dist/generators/component-generator.js +724 -0
- package/dist/generators/component-generator.js.map +1 -0
- package/dist/generators/deploy-generator.d.ts +9 -0
- package/dist/generators/deploy-generator.d.ts.map +1 -0
- package/dist/generators/deploy-generator.js +409 -0
- package/dist/generators/deploy-generator.js.map +1 -0
- package/dist/generators/error-boundary.d.ts +5 -0
- package/dist/generators/error-boundary.d.ts.map +1 -0
- package/dist/generators/error-boundary.js +59 -0
- package/dist/generators/error-boundary.js.map +1 -0
- package/dist/generators/form-generator.d.ts +42 -0
- package/dist/generators/form-generator.d.ts.map +1 -0
- package/dist/generators/form-generator.js +662 -0
- package/dist/generators/form-generator.js.map +1 -0
- package/dist/generators/hooks-generator.d.ts +40 -0
- package/dist/generators/hooks-generator.d.ts.map +1 -0
- package/dist/generators/hooks-generator.js +297 -0
- package/dist/generators/hooks-generator.js.map +1 -0
- package/dist/generators/html-generator.d.ts +27 -0
- package/dist/generators/html-generator.d.ts.map +1 -0
- package/dist/generators/html-generator.js +772 -0
- package/dist/generators/html-generator.js.map +1 -0
- package/dist/generators/jquery-converter.d.ts +41 -0
- package/dist/generators/jquery-converter.d.ts.map +1 -0
- package/dist/generators/jquery-converter.js +594 -0
- package/dist/generators/jquery-converter.js.map +1 -0
- package/dist/generators/pattern-implementer.d.ts +26 -0
- package/dist/generators/pattern-implementer.d.ts.map +1 -0
- package/dist/generators/pattern-implementer.js +336 -0
- package/dist/generators/pattern-implementer.js.map +1 -0
- package/dist/generators/performance-generator.d.ts +51 -0
- package/dist/generators/performance-generator.d.ts.map +1 -0
- package/dist/generators/performance-generator.js +428 -0
- package/dist/generators/performance-generator.js.map +1 -0
- package/dist/generators/router-generator.d.ts +21 -0
- package/dist/generators/router-generator.d.ts.map +1 -0
- package/dist/generators/router-generator.js +178 -0
- package/dist/generators/router-generator.js.map +1 -0
- package/dist/generators/scaffolder.d.ts +28 -0
- package/dist/generators/scaffolder.d.ts.map +1 -0
- package/dist/generators/scaffolder.js +266 -0
- package/dist/generators/scaffolder.js.map +1 -0
- package/dist/generators/seo-generator.d.ts +29 -0
- package/dist/generators/seo-generator.d.ts.map +1 -0
- package/dist/generators/seo-generator.js +223 -0
- package/dist/generators/seo-generator.js.map +1 -0
- package/dist/generators/test-generator.d.ts +19 -0
- package/dist/generators/test-generator.d.ts.map +1 -0
- package/dist/generators/test-generator.js +398 -0
- package/dist/generators/test-generator.js.map +1 -0
- package/dist/generators/type-generator.d.ts +33 -0
- package/dist/generators/type-generator.d.ts.map +1 -0
- package/dist/generators/type-generator.js +663 -0
- package/dist/generators/type-generator.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/parsers/css-processor.d.ts +23 -0
- package/dist/parsers/css-processor.d.ts.map +1 -0
- package/dist/parsers/css-processor.js +129 -0
- package/dist/parsers/css-processor.js.map +1 -0
- package/dist/parsers/framework-parser.d.ts +48 -0
- package/dist/parsers/framework-parser.d.ts.map +1 -0
- package/dist/parsers/framework-parser.js +770 -0
- package/dist/parsers/framework-parser.js.map +1 -0
- package/dist/parsers/html-parser.d.ts +12 -0
- package/dist/parsers/html-parser.d.ts.map +1 -0
- package/dist/parsers/html-parser.js +444 -0
- package/dist/parsers/html-parser.js.map +1 -0
- package/dist/parsers/js-analyzer.d.ts +199 -0
- package/dist/parsers/js-analyzer.d.ts.map +1 -0
- package/dist/parsers/js-analyzer.js +680 -0
- package/dist/parsers/js-analyzer.js.map +1 -0
- package/dist/parsers/js-resolver.d.ts +8 -0
- package/dist/parsers/js-resolver.d.ts.map +1 -0
- package/dist/parsers/js-resolver.js +45 -0
- package/dist/parsers/js-resolver.js.map +1 -0
- package/dist/parsers/tailwind-detector.d.ts +23 -0
- package/dist/parsers/tailwind-detector.d.ts.map +1 -0
- package/dist/parsers/tailwind-detector.js +104 -0
- package/dist/parsers/tailwind-detector.js.map +1 -0
- package/dist/tests/advanced-features.test.d.ts +2 -0
- package/dist/tests/advanced-features.test.d.ts.map +1 -0
- package/dist/tests/advanced-features.test.js +235 -0
- package/dist/tests/advanced-features.test.js.map +1 -0
- package/dist/tests/css-modules.test.d.ts +2 -0
- package/dist/tests/css-modules.test.d.ts.map +1 -0
- package/dist/tests/css-modules.test.js +61 -0
- package/dist/tests/css-modules.test.js.map +1 -0
- package/dist/tests/css-processor.test.d.ts +2 -0
- package/dist/tests/css-processor.test.d.ts.map +1 -0
- package/dist/tests/css-processor.test.js +48 -0
- package/dist/tests/css-processor.test.js.map +1 -0
- package/dist/tests/html-parser.test.d.ts +2 -0
- package/dist/tests/html-parser.test.d.ts.map +1 -0
- package/dist/tests/html-parser.test.js +78 -0
- package/dist/tests/html-parser.test.js.map +1 -0
- package/dist/tests/integration.test.d.ts +2 -0
- package/dist/tests/integration.test.d.ts.map +1 -0
- package/dist/tests/integration.test.js +65 -0
- package/dist/tests/integration.test.js.map +1 -0
- package/dist/tests/js-analyzer.test.d.ts +2 -0
- package/dist/tests/js-analyzer.test.d.ts.map +1 -0
- package/dist/tests/js-analyzer.test.js +58 -0
- package/dist/tests/js-analyzer.test.js.map +1 -0
- package/dist/tests/naming.test.d.ts +2 -0
- package/dist/tests/naming.test.d.ts.map +1 -0
- package/dist/tests/naming.test.js +43 -0
- package/dist/tests/naming.test.js.map +1 -0
- package/dist/tests/router-generator.test.d.ts +2 -0
- package/dist/tests/router-generator.test.d.ts.map +1 -0
- package/dist/tests/router-generator.test.js +60 -0
- package/dist/tests/router-generator.test.js.map +1 -0
- package/dist/tui/chat.d.ts +13 -0
- package/dist/tui/chat.d.ts.map +1 -0
- package/dist/tui/chat.js +499 -0
- package/dist/tui/chat.js.map +1 -0
- package/dist/tui/design-guide.d.ts +41 -0
- package/dist/tui/design-guide.d.ts.map +1 -0
- package/dist/tui/design-guide.js +184 -0
- package/dist/tui/design-guide.js.map +1 -0
- package/dist/tui/input.d.ts +30 -0
- package/dist/tui/input.d.ts.map +1 -0
- package/dist/tui/input.js +239 -0
- package/dist/tui/input.js.map +1 -0
- package/dist/tui/renderer.d.ts +48 -0
- package/dist/tui/renderer.d.ts.map +1 -0
- package/dist/tui/renderer.js +212 -0
- package/dist/tui/renderer.js.map +1 -0
- package/dist/tui/tools.d.ts +14 -0
- package/dist/tui/tools.d.ts.map +1 -0
- package/dist/tui/tools.js +1370 -0
- package/dist/tui/tools.js.map +1 -0
- package/dist/types.d.ts +93 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/config.d.ts +20 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +33 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/formatter.d.ts +5 -0
- package/dist/utils/formatter.d.ts.map +1 -0
- package/dist/utils/formatter.js +68 -0
- package/dist/utils/formatter.js.map +1 -0
- package/dist/utils/logger.d.ts +8 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +19 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/naming.d.ts +17 -0
- package/dist/utils/naming.d.ts.map +1 -0
- package/dist/utils/naming.js +48 -0
- package/dist/utils/naming.js.map +1 -0
- package/dist/utils/report.d.ts +56 -0
- package/dist/utils/report.d.ts.map +1 -0
- package/dist/utils/report.js +339 -0
- package/dist/utils/report.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,663 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analyzes component JSX for props usage and infers TypeScript types
|
|
3
|
+
* from usage context. Scans for `{props.x}` and destructured props patterns.
|
|
4
|
+
*/
|
|
5
|
+
export function inferPropTypes(component) {
|
|
6
|
+
const props = new Map();
|
|
7
|
+
const jsx = component.jsx;
|
|
8
|
+
// Match props.xxx patterns
|
|
9
|
+
const propsAccessRegex = /\bprops\.(\w+)/g;
|
|
10
|
+
let match;
|
|
11
|
+
while ((match = propsAccessRegex.exec(jsx)) !== null) {
|
|
12
|
+
const name = match[1];
|
|
13
|
+
if (!props.has(name)) {
|
|
14
|
+
props.set(name, {
|
|
15
|
+
name,
|
|
16
|
+
type: inferTypeFromName(name),
|
|
17
|
+
required: false,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
// Match destructured props: { foo, bar } = props or ({ foo, bar })
|
|
22
|
+
const destructuredRegex = /\{\s*([\w\s,]+)\s*\}\s*=\s*props/g;
|
|
23
|
+
while ((match = destructuredRegex.exec(jsx)) !== null) {
|
|
24
|
+
const names = match[1].split(',').map((s) => s.trim()).filter(Boolean);
|
|
25
|
+
for (const name of names) {
|
|
26
|
+
if (!props.has(name)) {
|
|
27
|
+
props.set(name, {
|
|
28
|
+
name,
|
|
29
|
+
type: inferTypeFromName(name),
|
|
30
|
+
required: false,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// Match function component parameter destructuring: function Comp({ foo, bar })
|
|
36
|
+
const paramDestructureRegex = /(?:function\s+\w+|const\s+\w+\s*=\s*)\s*\(\s*\{\s*([\w\s,='":\-.*]+)\s*\}\s*\)/g;
|
|
37
|
+
while ((match = paramDestructureRegex.exec(jsx)) !== null) {
|
|
38
|
+
const params = match[1].split(',');
|
|
39
|
+
for (const param of params) {
|
|
40
|
+
const trimmed = param.trim();
|
|
41
|
+
// Handle default values: name = 'default'
|
|
42
|
+
const defaultMatch = trimmed.match(/^(\w+)\s*=\s*(.+)$/);
|
|
43
|
+
const name = defaultMatch ? defaultMatch[1] : trimmed.split(':')[0].trim();
|
|
44
|
+
if (!name || name.startsWith('...'))
|
|
45
|
+
continue;
|
|
46
|
+
const cleanName = name.replace(/\.\.\./g, '');
|
|
47
|
+
if (!cleanName)
|
|
48
|
+
continue;
|
|
49
|
+
const propType = {
|
|
50
|
+
name: cleanName,
|
|
51
|
+
type: inferTypeFromName(cleanName),
|
|
52
|
+
required: !defaultMatch,
|
|
53
|
+
};
|
|
54
|
+
if (defaultMatch) {
|
|
55
|
+
propType.defaultValue = defaultMatch[2].trim();
|
|
56
|
+
// Refine type based on default value
|
|
57
|
+
const refined = inferTypeFromValue(propType.defaultValue);
|
|
58
|
+
if (refined !== 'unknown') {
|
|
59
|
+
propType.type = refined;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (!props.has(cleanName)) {
|
|
63
|
+
props.set(cleanName, propType);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Refine types by analyzing usage context in JSX
|
|
68
|
+
for (const [name, prop] of props) {
|
|
69
|
+
const contextType = inferTypeFromUsageContext(name, jsx);
|
|
70
|
+
if (contextType) {
|
|
71
|
+
prop.type = contextType;
|
|
72
|
+
}
|
|
73
|
+
prop.description = generatePropDescription(name, prop.type);
|
|
74
|
+
}
|
|
75
|
+
return Array.from(props.values());
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Infers a TypeScript type from a prop name using common naming conventions.
|
|
79
|
+
*/
|
|
80
|
+
function inferTypeFromName(name) {
|
|
81
|
+
// Event handlers
|
|
82
|
+
if (/^on[A-Z]/.test(name)) {
|
|
83
|
+
return inferEventHandlerType(name);
|
|
84
|
+
}
|
|
85
|
+
// Boolean patterns
|
|
86
|
+
if (/^(is|has|can|should|will|did|show|hide|enable|disable|visible|active|checked|disabled|loading|open|closed|selected|readonly|required)/.test(name)) {
|
|
87
|
+
return 'boolean';
|
|
88
|
+
}
|
|
89
|
+
// String patterns
|
|
90
|
+
if (/^(className|class|style|id|name|label|title|description|placeholder|alt|src|href|url|text|content|message|error|value|type|variant|size|color|icon|path|key|token|email|password|username)$/i.test(name)) {
|
|
91
|
+
return 'string';
|
|
92
|
+
}
|
|
93
|
+
// Number patterns
|
|
94
|
+
if (/^(count|index|length|size|width|height|min|max|step|limit|offset|page|total|amount|quantity|duration|delay|timeout|interval|priority|order|level|depth|columns|rows|tabIndex|zIndex|opacity|flex|span)$/i.test(name)) {
|
|
95
|
+
return 'number';
|
|
96
|
+
}
|
|
97
|
+
// Children
|
|
98
|
+
if (name === 'children') {
|
|
99
|
+
return 'React.ReactNode';
|
|
100
|
+
}
|
|
101
|
+
// Ref
|
|
102
|
+
if (/ref$/i.test(name)) {
|
|
103
|
+
return 'React.Ref<HTMLElement>';
|
|
104
|
+
}
|
|
105
|
+
// Arrays
|
|
106
|
+
if (/^(items|list|options|data|rows|columns|entries|results|tags|values|elements|records|children)$/i.test(name) && name !== 'children') {
|
|
107
|
+
return 'unknown[]';
|
|
108
|
+
}
|
|
109
|
+
return 'unknown';
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Infers event handler type from the handler name.
|
|
113
|
+
*/
|
|
114
|
+
function inferEventHandlerType(name) {
|
|
115
|
+
const eventMap = {
|
|
116
|
+
onClick: '(event: React.MouseEvent) => void',
|
|
117
|
+
onChange: '(event: React.ChangeEvent<HTMLInputElement>) => void',
|
|
118
|
+
onSubmit: '(event: React.FormEvent) => void',
|
|
119
|
+
onFocus: '(event: React.FocusEvent) => void',
|
|
120
|
+
onBlur: '(event: React.FocusEvent) => void',
|
|
121
|
+
onKeyDown: '(event: React.KeyboardEvent) => void',
|
|
122
|
+
onKeyUp: '(event: React.KeyboardEvent) => void',
|
|
123
|
+
onKeyPress: '(event: React.KeyboardEvent) => void',
|
|
124
|
+
onMouseEnter: '(event: React.MouseEvent) => void',
|
|
125
|
+
onMouseLeave: '(event: React.MouseEvent) => void',
|
|
126
|
+
onScroll: '(event: React.UIEvent) => void',
|
|
127
|
+
onDrag: '(event: React.DragEvent) => void',
|
|
128
|
+
onDrop: '(event: React.DragEvent) => void',
|
|
129
|
+
onInput: '(event: React.FormEvent<HTMLInputElement>) => void',
|
|
130
|
+
onLoad: '() => void',
|
|
131
|
+
onError: '(error: Error) => void',
|
|
132
|
+
};
|
|
133
|
+
if (eventMap[name]) {
|
|
134
|
+
return eventMap[name];
|
|
135
|
+
}
|
|
136
|
+
// Generic handler pattern: onItemClick → (id: string) => void
|
|
137
|
+
if (/^on\w+Click$/.test(name)) {
|
|
138
|
+
return '(id: string) => void';
|
|
139
|
+
}
|
|
140
|
+
if (/^on\w+Change$/.test(name)) {
|
|
141
|
+
return '(value: unknown) => void';
|
|
142
|
+
}
|
|
143
|
+
return '() => void';
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Infers type from a literal value string.
|
|
147
|
+
*/
|
|
148
|
+
function inferTypeFromValue(value) {
|
|
149
|
+
const trimmed = value.trim();
|
|
150
|
+
if (trimmed === 'true' || trimmed === 'false')
|
|
151
|
+
return 'boolean';
|
|
152
|
+
if (/^-?\d+(\.\d+)?$/.test(trimmed))
|
|
153
|
+
return 'number';
|
|
154
|
+
if (/^['"`]/.test(trimmed))
|
|
155
|
+
return 'string';
|
|
156
|
+
if (trimmed === 'null')
|
|
157
|
+
return 'null';
|
|
158
|
+
if (trimmed === 'undefined')
|
|
159
|
+
return 'undefined';
|
|
160
|
+
if (trimmed.startsWith('['))
|
|
161
|
+
return 'unknown[]';
|
|
162
|
+
if (trimmed.startsWith('{'))
|
|
163
|
+
return 'Record<string, unknown>';
|
|
164
|
+
return 'unknown';
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Analyzes how a prop is used in JSX to infer a more accurate type.
|
|
168
|
+
*/
|
|
169
|
+
function inferTypeFromUsageContext(name, jsx) {
|
|
170
|
+
// Used as event handler: onClick={props.x} or onSubmit={x}
|
|
171
|
+
const eventHandlerRegex = new RegExp(`on\\w+\\s*=\\s*\\{\\s*(?:props\\.)?${escapeRegex(name)}\\s*\\}`);
|
|
172
|
+
if (eventHandlerRegex.test(jsx)) {
|
|
173
|
+
return '(...args: unknown[]) => void';
|
|
174
|
+
}
|
|
175
|
+
// Used as src attribute
|
|
176
|
+
const srcRegex = new RegExp(`src\\s*=\\s*\\{\\s*(?:props\\.)?${escapeRegex(name)}\\s*\\}`);
|
|
177
|
+
if (srcRegex.test(jsx)) {
|
|
178
|
+
return 'string';
|
|
179
|
+
}
|
|
180
|
+
// Used as className
|
|
181
|
+
const classRegex = new RegExp(`className\\s*=\\s*\\{\\s*(?:props\\.)?${escapeRegex(name)}\\s*\\}`);
|
|
182
|
+
if (classRegex.test(jsx)) {
|
|
183
|
+
return 'string';
|
|
184
|
+
}
|
|
185
|
+
// Used in template literal or string concatenation
|
|
186
|
+
const backtick = '`';
|
|
187
|
+
const templateRegex = new RegExp(backtick + '[^' + backtick + ']*\\$\\{\\s*(?:props\\.)?' + escapeRegex(name) + '\\s*\\}[^' + backtick + ']*' + backtick);
|
|
188
|
+
if (templateRegex.test(jsx)) {
|
|
189
|
+
return 'string | number';
|
|
190
|
+
}
|
|
191
|
+
// Used in arithmetic
|
|
192
|
+
const arithmeticRegex = new RegExp(`(?:props\\.)?${escapeRegex(name)}\\s*[+\\-*/%]\\s*\\d|\\d\\s*[+\\-*/%]\\s*(?:props\\.)?${escapeRegex(name)}`);
|
|
193
|
+
if (arithmeticRegex.test(jsx)) {
|
|
194
|
+
return 'number';
|
|
195
|
+
}
|
|
196
|
+
// Used in .map() → array
|
|
197
|
+
const mapRegex = new RegExp(`(?:props\\.)?${escapeRegex(name)}\\.map\\s*\\(`);
|
|
198
|
+
if (mapRegex.test(jsx)) {
|
|
199
|
+
return 'unknown[]';
|
|
200
|
+
}
|
|
201
|
+
// Used in .length → string or array
|
|
202
|
+
const lengthRegex = new RegExp(`(?:props\\.)?${escapeRegex(name)}\\.length`);
|
|
203
|
+
if (lengthRegex.test(jsx)) {
|
|
204
|
+
return 'string | unknown[]';
|
|
205
|
+
}
|
|
206
|
+
// Used in conditional → boolean
|
|
207
|
+
const conditionalRegex = new RegExp(`\\{\\s*(?:props\\.)?${escapeRegex(name)}\\s*&&`);
|
|
208
|
+
if (conditionalRegex.test(jsx)) {
|
|
209
|
+
return 'boolean';
|
|
210
|
+
}
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
function escapeRegex(str) {
|
|
214
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Generates a JSDoc description for a prop based on its name and type.
|
|
218
|
+
*/
|
|
219
|
+
function generatePropDescription(name, type) {
|
|
220
|
+
if (name === 'children')
|
|
221
|
+
return 'Child elements';
|
|
222
|
+
if (name === 'className')
|
|
223
|
+
return 'CSS class name';
|
|
224
|
+
if (name === 'style')
|
|
225
|
+
return 'Inline styles';
|
|
226
|
+
// Event handlers
|
|
227
|
+
if (/^on[A-Z]/.test(name)) {
|
|
228
|
+
const event = name.replace(/^on/, '');
|
|
229
|
+
return `${event} handler`;
|
|
230
|
+
}
|
|
231
|
+
// Convert camelCase to readable text
|
|
232
|
+
const readable = name
|
|
233
|
+
.replace(/([A-Z])/g, ' $1')
|
|
234
|
+
.replace(/^./, (s) => s.toUpperCase())
|
|
235
|
+
.trim();
|
|
236
|
+
if (type === 'boolean') {
|
|
237
|
+
return `Whether ${readable.toLowerCase()}`;
|
|
238
|
+
}
|
|
239
|
+
if (type === 'number') {
|
|
240
|
+
return `Number of ${readable.toLowerCase()}`;
|
|
241
|
+
}
|
|
242
|
+
return readable;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Generates complete TypeScript interface definitions for a component's props and state.
|
|
246
|
+
*/
|
|
247
|
+
export function generateTypeDefinitions(component, analysis) {
|
|
248
|
+
const lines = [];
|
|
249
|
+
const propsName = `${component.name}Props`;
|
|
250
|
+
const propTypes = inferPropTypes(component);
|
|
251
|
+
// Check for children usage in JSX
|
|
252
|
+
const hasChildren = component.jsx.includes('{children}') ||
|
|
253
|
+
component.jsx.includes('{props.children}') ||
|
|
254
|
+
component.jsx.includes('children');
|
|
255
|
+
if (hasChildren && !propTypes.find((p) => p.name === 'children')) {
|
|
256
|
+
propTypes.push({
|
|
257
|
+
name: 'children',
|
|
258
|
+
type: 'React.ReactNode',
|
|
259
|
+
required: false,
|
|
260
|
+
description: 'Child elements',
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
// Generate Props interface
|
|
264
|
+
if (propTypes.length > 0) {
|
|
265
|
+
lines.push(`interface ${propsName} {`);
|
|
266
|
+
for (const prop of propTypes) {
|
|
267
|
+
if (prop.description) {
|
|
268
|
+
lines.push(` /** ${prop.description} */`);
|
|
269
|
+
}
|
|
270
|
+
const optional = prop.required ? '' : '?';
|
|
271
|
+
lines.push(` ${prop.name}${optional}: ${prop.type};`);
|
|
272
|
+
}
|
|
273
|
+
lines.push('}');
|
|
274
|
+
lines.push('');
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
lines.push(`interface ${propsName} {`);
|
|
278
|
+
lines.push(' children?: React.ReactNode;');
|
|
279
|
+
lines.push('}');
|
|
280
|
+
lines.push('');
|
|
281
|
+
}
|
|
282
|
+
// Generate State type from component stateVars
|
|
283
|
+
const stateVars = component.stateVars;
|
|
284
|
+
if (stateVars.length > 0) {
|
|
285
|
+
const stateTypes = inferStateTypes(stateVars);
|
|
286
|
+
const stateName = `${component.name}State`;
|
|
287
|
+
lines.push(`interface ${stateName} {`);
|
|
288
|
+
for (const stateVar of stateVars) {
|
|
289
|
+
const tsType = stateTypes.get(stateVar.name) ?? 'unknown';
|
|
290
|
+
const description = stateVar.name
|
|
291
|
+
.replace(/([A-Z])/g, ' $1')
|
|
292
|
+
.replace(/^./, (s) => s.toUpperCase())
|
|
293
|
+
.trim();
|
|
294
|
+
lines.push(` /** ${description} */`);
|
|
295
|
+
lines.push(` ${stateVar.name}: ${tsType};`);
|
|
296
|
+
}
|
|
297
|
+
lines.push('}');
|
|
298
|
+
lines.push('');
|
|
299
|
+
}
|
|
300
|
+
// Generate API response types if fetch calls exist
|
|
301
|
+
if (analysis?.fetchCalls && analysis.fetchCalls.length > 0) {
|
|
302
|
+
const apiTypes = inferApiResponseType(analysis.fetchCalls);
|
|
303
|
+
if (apiTypes) {
|
|
304
|
+
lines.push(apiTypes);
|
|
305
|
+
lines.push('');
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return lines.join('\n');
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Analyzes fetch call URLs and patterns to generate response type interfaces.
|
|
312
|
+
* Groups endpoints by path and generates typed response interfaces.
|
|
313
|
+
*/
|
|
314
|
+
export function inferApiResponseType(fetchCalls) {
|
|
315
|
+
if (fetchCalls.length === 0)
|
|
316
|
+
return '';
|
|
317
|
+
const lines = [];
|
|
318
|
+
// Generic API response wrapper
|
|
319
|
+
lines.push('interface ApiResponse<T> {');
|
|
320
|
+
lines.push(' data: T;');
|
|
321
|
+
lines.push(' status: number;');
|
|
322
|
+
lines.push(' message?: string;');
|
|
323
|
+
lines.push('}');
|
|
324
|
+
lines.push('');
|
|
325
|
+
// Group fetch calls by endpoint to generate specific types
|
|
326
|
+
const endpointTypes = new Map();
|
|
327
|
+
for (const call of fetchCalls) {
|
|
328
|
+
const resourceName = extractResourceName(call.url);
|
|
329
|
+
if (!endpointTypes.has(resourceName)) {
|
|
330
|
+
endpointTypes.set(resourceName, { methods: new Set(), hasBody: false });
|
|
331
|
+
}
|
|
332
|
+
const info = endpointTypes.get(resourceName);
|
|
333
|
+
info.methods.add(call.method);
|
|
334
|
+
if (call.hasBody)
|
|
335
|
+
info.hasBody = true;
|
|
336
|
+
}
|
|
337
|
+
for (const [resource, info] of endpointTypes) {
|
|
338
|
+
const typeName = toPascalCase(resource);
|
|
339
|
+
// Generate response type
|
|
340
|
+
lines.push(`interface ${typeName}Response {`);
|
|
341
|
+
lines.push(` id: string;`);
|
|
342
|
+
lines.push(` [key: string]: unknown;`);
|
|
343
|
+
lines.push('}');
|
|
344
|
+
lines.push('');
|
|
345
|
+
// Generate request type if there are POST/PUT/PATCH calls
|
|
346
|
+
const mutationMethods = ['POST', 'PUT', 'PATCH'];
|
|
347
|
+
const hasMutation = [...info.methods].some((m) => mutationMethods.includes(m.toUpperCase()));
|
|
348
|
+
if (hasMutation && info.hasBody) {
|
|
349
|
+
lines.push(`interface ${typeName}Request {`);
|
|
350
|
+
lines.push(` [key: string]: unknown;`);
|
|
351
|
+
lines.push('}');
|
|
352
|
+
lines.push('');
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
return lines.join('\n').trimEnd();
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Extracts a resource name from a URL path for type generation.
|
|
359
|
+
* E.g., `/api/users/123` → `User`, `/products` → `Product`
|
|
360
|
+
*/
|
|
361
|
+
function extractResourceName(url) {
|
|
362
|
+
// Remove protocol and domain
|
|
363
|
+
let path = url.replace(/^https?:\/\/[^/]+/, '');
|
|
364
|
+
// Remove query string and hash
|
|
365
|
+
path = path.replace(/[?#].*$/, '');
|
|
366
|
+
// Remove trailing slash
|
|
367
|
+
path = path.replace(/\/$/, '');
|
|
368
|
+
// Extract meaningful path segments
|
|
369
|
+
const segments = path.split('/').filter((s) => s && !s.startsWith(':') && !/^\d+$/.test(s) && s !== 'api' && s !== 'v1' && s !== 'v2' && s !== 'v3');
|
|
370
|
+
if (segments.length === 0) {
|
|
371
|
+
return 'Api';
|
|
372
|
+
}
|
|
373
|
+
// Use the last meaningful segment, singularize if needed
|
|
374
|
+
let resource = segments[segments.length - 1];
|
|
375
|
+
resource = singularize(resource);
|
|
376
|
+
return resource;
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Naive singularization of common English plurals.
|
|
380
|
+
*/
|
|
381
|
+
function singularize(word) {
|
|
382
|
+
if (word.endsWith('ies'))
|
|
383
|
+
return word.slice(0, -3) + 'y';
|
|
384
|
+
if (word.endsWith('ses') || word.endsWith('xes') || word.endsWith('zes'))
|
|
385
|
+
return word.slice(0, -2);
|
|
386
|
+
if (word.endsWith('s') && !word.endsWith('ss') && !word.endsWith('us'))
|
|
387
|
+
return word.slice(0, -1);
|
|
388
|
+
return word;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Converts a kebab-case or snake_case string to PascalCase.
|
|
392
|
+
*/
|
|
393
|
+
function toPascalCase(str) {
|
|
394
|
+
return str
|
|
395
|
+
.replace(/[-_]+(.)/g, (_, c) => c.toUpperCase())
|
|
396
|
+
.replace(/^./, (s) => s.toUpperCase());
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Generates global type definitions file content suitable for a `global.d.ts` file.
|
|
400
|
+
*/
|
|
401
|
+
export function generateGlobalTypes() {
|
|
402
|
+
return `// Global type definitions for the converted React application
|
|
403
|
+
|
|
404
|
+
// Utility type for components that accept children
|
|
405
|
+
type PropsWithChildren<P = {}> = P & { children?: React.ReactNode };
|
|
406
|
+
|
|
407
|
+
// Common event handler types
|
|
408
|
+
type ClickHandler = (event: React.MouseEvent<HTMLElement>) => void;
|
|
409
|
+
type ChangeHandler = (event: React.ChangeEvent<HTMLInputElement>) => void;
|
|
410
|
+
type SubmitHandler = (event: React.FormEvent<HTMLFormElement>) => void;
|
|
411
|
+
type KeyHandler = (event: React.KeyboardEvent<HTMLElement>) => void;
|
|
412
|
+
type FocusHandler = (event: React.FocusEvent<HTMLElement>) => void;
|
|
413
|
+
type DragHandler = (event: React.DragEvent<HTMLElement>) => void;
|
|
414
|
+
type ScrollHandler = (event: React.UIEvent<HTMLElement>) => void;
|
|
415
|
+
type InputHandler = (event: React.FormEvent<HTMLInputElement>) => void;
|
|
416
|
+
|
|
417
|
+
// CSS Modules
|
|
418
|
+
declare module '*.module.css' {
|
|
419
|
+
const classes: { readonly [key: string]: string };
|
|
420
|
+
export default classes;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
declare module '*.module.scss' {
|
|
424
|
+
const classes: { readonly [key: string]: string };
|
|
425
|
+
export default classes;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
declare module '*.module.less' {
|
|
429
|
+
const classes: { readonly [key: string]: string };
|
|
430
|
+
export default classes;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// SVG module declaration
|
|
434
|
+
declare module '*.svg' {
|
|
435
|
+
import * as React from 'react';
|
|
436
|
+
const ReactComponent: React.FunctionComponent<React.SVGProps<SVGSVGElement> & { title?: string }>;
|
|
437
|
+
export { ReactComponent };
|
|
438
|
+
const src: string;
|
|
439
|
+
export default src;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// Image module declarations
|
|
443
|
+
declare module '*.png' {
|
|
444
|
+
const src: string;
|
|
445
|
+
export default src;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
declare module '*.jpg' {
|
|
449
|
+
const src: string;
|
|
450
|
+
export default src;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
declare module '*.jpeg' {
|
|
454
|
+
const src: string;
|
|
455
|
+
export default src;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
declare module '*.gif' {
|
|
459
|
+
const src: string;
|
|
460
|
+
export default src;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
declare module '*.webp' {
|
|
464
|
+
const src: string;
|
|
465
|
+
export default src;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
declare module '*.avif' {
|
|
469
|
+
const src: string;
|
|
470
|
+
export default src;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
declare module '*.ico' {
|
|
474
|
+
const src: string;
|
|
475
|
+
export default src;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
declare module '*.bmp' {
|
|
479
|
+
const src: string;
|
|
480
|
+
export default src;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Font module declarations
|
|
484
|
+
declare module '*.woff' {
|
|
485
|
+
const src: string;
|
|
486
|
+
export default src;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
declare module '*.woff2' {
|
|
490
|
+
const src: string;
|
|
491
|
+
export default src;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Environment variables type
|
|
495
|
+
interface ImportMetaEnv {
|
|
496
|
+
readonly VITE_API_URL: string;
|
|
497
|
+
readonly VITE_APP_TITLE: string;
|
|
498
|
+
readonly VITE_PUBLIC_URL: string;
|
|
499
|
+
readonly MODE: string;
|
|
500
|
+
readonly BASE_URL: string;
|
|
501
|
+
readonly PROD: boolean;
|
|
502
|
+
readonly DEV: boolean;
|
|
503
|
+
readonly SSR: boolean;
|
|
504
|
+
readonly [key: string]: string | boolean | undefined;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
interface ImportMeta {
|
|
508
|
+
readonly env: ImportMetaEnv;
|
|
509
|
+
}
|
|
510
|
+
`;
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Maps state variable names and initial values to TypeScript types.
|
|
514
|
+
* Analyzes literal values and setter usage patterns to infer accurate types.
|
|
515
|
+
*/
|
|
516
|
+
export function inferStateTypes(stateVars) {
|
|
517
|
+
const typeMap = new Map();
|
|
518
|
+
for (const stateVar of stateVars) {
|
|
519
|
+
const type = inferStateType(stateVar);
|
|
520
|
+
typeMap.set(stateVar.name, type);
|
|
521
|
+
}
|
|
522
|
+
return typeMap;
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Infers the TypeScript type for a single state variable.
|
|
526
|
+
*/
|
|
527
|
+
function inferStateType(stateVar) {
|
|
528
|
+
const { name, initialValue, setter } = stateVar;
|
|
529
|
+
const trimmed = initialValue.trim();
|
|
530
|
+
// Direct literal types
|
|
531
|
+
if (trimmed === 'true' || trimmed === 'false')
|
|
532
|
+
return 'boolean';
|
|
533
|
+
if (/^-?\d+$/.test(trimmed))
|
|
534
|
+
return 'number';
|
|
535
|
+
if (/^-?\d+\.\d+$/.test(trimmed))
|
|
536
|
+
return 'number';
|
|
537
|
+
if (trimmed === '0' || trimmed === '1')
|
|
538
|
+
return 'number';
|
|
539
|
+
// String values
|
|
540
|
+
if (/^['"`]/.test(trimmed) && /['"`]$/.test(trimmed))
|
|
541
|
+
return 'string';
|
|
542
|
+
if (trimmed === "''" || trimmed === '""' || trimmed === '``')
|
|
543
|
+
return 'string';
|
|
544
|
+
// Array values
|
|
545
|
+
if (trimmed.startsWith('[')) {
|
|
546
|
+
return inferArrayType(trimmed);
|
|
547
|
+
}
|
|
548
|
+
// Object values
|
|
549
|
+
if (trimmed.startsWith('{')) {
|
|
550
|
+
return 'Record<string, unknown>';
|
|
551
|
+
}
|
|
552
|
+
// null - try to infer from name or setter usage
|
|
553
|
+
if (trimmed === 'null' || trimmed === 'undefined') {
|
|
554
|
+
return inferNullableType(name, setter);
|
|
555
|
+
}
|
|
556
|
+
// Named patterns
|
|
557
|
+
if (/^(is|has|show|can|should|enable|visible|active|loading|open|checked|disabled|selected)/.test(name)) {
|
|
558
|
+
return 'boolean';
|
|
559
|
+
}
|
|
560
|
+
if (/^(count|index|total|page|size|limit|offset|num|amount|quantity)/.test(name)) {
|
|
561
|
+
return 'number';
|
|
562
|
+
}
|
|
563
|
+
if (/^(name|title|text|message|error|label|description|email|password|query|search|input|value|content|url|path)/.test(name)) {
|
|
564
|
+
return 'string';
|
|
565
|
+
}
|
|
566
|
+
if (/^(items|list|options|data|results|entries|rows|tags|records|elements)/.test(name)) {
|
|
567
|
+
return 'unknown[]';
|
|
568
|
+
}
|
|
569
|
+
return 'unknown';
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Infers array element type from an initial array value.
|
|
573
|
+
*/
|
|
574
|
+
function inferArrayType(value) {
|
|
575
|
+
const trimmed = value.trim();
|
|
576
|
+
// Empty array
|
|
577
|
+
if (trimmed === '[]')
|
|
578
|
+
return 'unknown[]';
|
|
579
|
+
// Try to parse array contents
|
|
580
|
+
const inner = trimmed.slice(1, -1).trim();
|
|
581
|
+
if (!inner)
|
|
582
|
+
return 'unknown[]';
|
|
583
|
+
// Check first element
|
|
584
|
+
const elements = splitTopLevel(inner);
|
|
585
|
+
if (elements.length === 0)
|
|
586
|
+
return 'unknown[]';
|
|
587
|
+
const firstEl = elements[0].trim();
|
|
588
|
+
if (/^['"`]/.test(firstEl))
|
|
589
|
+
return 'string[]';
|
|
590
|
+
if (/^-?\d+(\.\d+)?$/.test(firstEl))
|
|
591
|
+
return 'number[]';
|
|
592
|
+
if (firstEl === 'true' || firstEl === 'false')
|
|
593
|
+
return 'boolean[]';
|
|
594
|
+
if (firstEl.startsWith('{'))
|
|
595
|
+
return 'Record<string, unknown>[]';
|
|
596
|
+
return 'unknown[]';
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Splits a string by top-level commas (ignoring commas inside brackets/braces/parens).
|
|
600
|
+
*/
|
|
601
|
+
function splitTopLevel(str) {
|
|
602
|
+
const result = [];
|
|
603
|
+
let depth = 0;
|
|
604
|
+
let current = '';
|
|
605
|
+
for (const char of str) {
|
|
606
|
+
if (char === '[' || char === '{' || char === '(') {
|
|
607
|
+
depth++;
|
|
608
|
+
current += char;
|
|
609
|
+
}
|
|
610
|
+
else if (char === ']' || char === '}' || char === ')') {
|
|
611
|
+
depth--;
|
|
612
|
+
current += char;
|
|
613
|
+
}
|
|
614
|
+
else if (char === ',' && depth === 0) {
|
|
615
|
+
result.push(current);
|
|
616
|
+
current = '';
|
|
617
|
+
}
|
|
618
|
+
else {
|
|
619
|
+
current += char;
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
if (current.trim()) {
|
|
623
|
+
result.push(current);
|
|
624
|
+
}
|
|
625
|
+
return result;
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* Infers a nullable type from the state variable name and setter usage patterns.
|
|
629
|
+
*/
|
|
630
|
+
function inferNullableType(name, setter) {
|
|
631
|
+
// Infer from naming conventions
|
|
632
|
+
if (/^(selected|current|active)/.test(name)) {
|
|
633
|
+
if (/item|element|row|record/i.test(name))
|
|
634
|
+
return 'Record<string, unknown> | null';
|
|
635
|
+
if (/index|id/i.test(name))
|
|
636
|
+
return 'number | null';
|
|
637
|
+
return 'string | null';
|
|
638
|
+
}
|
|
639
|
+
if (/^(error|message|notification)/.test(name))
|
|
640
|
+
return 'string | null';
|
|
641
|
+
if (/^(user|profile|account)$/i.test(name))
|
|
642
|
+
return 'Record<string, unknown> | null';
|
|
643
|
+
if (/^(data|response|result)$/i.test(name))
|
|
644
|
+
return 'unknown | null';
|
|
645
|
+
if (/^(timer|timeout|interval)/.test(name))
|
|
646
|
+
return 'ReturnType<typeof setTimeout> | null';
|
|
647
|
+
if (/^(ref|element|node)/.test(name))
|
|
648
|
+
return 'HTMLElement | null';
|
|
649
|
+
// Infer from setter name pattern
|
|
650
|
+
if (setter) {
|
|
651
|
+
const setterTarget = setter.replace(/^set/, '');
|
|
652
|
+
if (/^Is|^Has|^Show|^Can/.test(setterTarget))
|
|
653
|
+
return 'boolean | null';
|
|
654
|
+
if (/Count|Index|Total|Page/.test(setterTarget))
|
|
655
|
+
return 'number | null';
|
|
656
|
+
if (/Name|Title|Text|Message|Error/.test(setterTarget))
|
|
657
|
+
return 'string | null';
|
|
658
|
+
if (/Items|List|Options|Data/.test(setterTarget))
|
|
659
|
+
return 'unknown[] | null';
|
|
660
|
+
}
|
|
661
|
+
return 'unknown | null';
|
|
662
|
+
}
|
|
663
|
+
//# sourceMappingURL=type-generator.js.map
|