@genesislcap/ts-builder 14.417.1-alpha-83eabbf.0 → 14.418.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -8
- package/package.json +3 -3
- package/src/index.ts +0 -8
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/react-jsx-generator.d.ts +0 -6
- package/dist/react-jsx-generator.d.ts.map +0 -1
- package/dist/react-jsx-generator.js +0 -806
- package/src/react-jsx-generator.ts +0 -994
|
@@ -1,994 +0,0 @@
|
|
|
1
|
-
import { mkdir, readFile, readdir, stat, writeFile } from 'node:fs/promises';
|
|
2
|
-
import { dirname, relative, resolve } from 'node:path';
|
|
3
|
-
|
|
4
|
-
type CEMType = { text?: string };
|
|
5
|
-
type CEMEvent = { name?: string; type?: CEMType };
|
|
6
|
-
type CEMSuperclass = {
|
|
7
|
-
name?: string;
|
|
8
|
-
package?: string;
|
|
9
|
-
};
|
|
10
|
-
type CEMMember = {
|
|
11
|
-
name?: string;
|
|
12
|
-
fieldName?: string;
|
|
13
|
-
attribute?: string | null;
|
|
14
|
-
kind?: string;
|
|
15
|
-
privacy?: string;
|
|
16
|
-
type?: CEMType;
|
|
17
|
-
};
|
|
18
|
-
type CEMDeclaration = {
|
|
19
|
-
name?: string;
|
|
20
|
-
customElement?: boolean;
|
|
21
|
-
tagName?: string;
|
|
22
|
-
superclass?: CEMSuperclass;
|
|
23
|
-
members?: CEMMember[];
|
|
24
|
-
attributes?: CEMMember[];
|
|
25
|
-
events?: CEMEvent[];
|
|
26
|
-
};
|
|
27
|
-
type CEMModule = {
|
|
28
|
-
declarations?: CEMDeclaration[];
|
|
29
|
-
};
|
|
30
|
-
type CEMManifest = {
|
|
31
|
-
modules?: CEMModule[];
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
type TypeImportState = {
|
|
35
|
-
importsByIdentifier: Map<string, string>;
|
|
36
|
-
ambiguousIdentifiers: Set<string>;
|
|
37
|
-
usedImports: Map<string, Set<string>>;
|
|
38
|
-
wildcardExportModules: Set<string>;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
function createTypeImportState(): TypeImportState {
|
|
42
|
-
return {
|
|
43
|
-
importsByIdentifier: new Map(),
|
|
44
|
-
ambiguousIdentifiers: new Set(),
|
|
45
|
-
usedImports: new Map(),
|
|
46
|
-
wildcardExportModules: new Set(),
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const GENERATED_FILE_NAME = 'react-jsx-runtime.d.ts';
|
|
51
|
-
|
|
52
|
-
const primitiveUnionRegex =
|
|
53
|
-
/^(?:\s*(?:string|number|boolean|bigint|null|undefined|unknown|any|void|'[^']*'|"[^"]*"|`[^`]*`|(?:\d+(?:\.\d+)?))\s*)(?:\|\s*(?:string|number|boolean|bigint|null|undefined|unknown|any|void|'[^']*'|"[^"]*"|`[^`]*`|(?:\d+(?:\.\d+)?))\s*)*$/;
|
|
54
|
-
|
|
55
|
-
const allowedTypeIdentifierRegex = /^[A-Za-z_$][A-Za-z0-9_$]*(?:\.[A-Za-z_$][A-Za-z0-9_$]*)*$/;
|
|
56
|
-
const allowedTypeNameSet = new Set([
|
|
57
|
-
'Array',
|
|
58
|
-
'ReadonlyArray',
|
|
59
|
-
'Promise',
|
|
60
|
-
'Record',
|
|
61
|
-
'Partial',
|
|
62
|
-
'Required',
|
|
63
|
-
'Pick',
|
|
64
|
-
'Omit',
|
|
65
|
-
'Map',
|
|
66
|
-
'Set',
|
|
67
|
-
'WeakMap',
|
|
68
|
-
'WeakSet',
|
|
69
|
-
'Date',
|
|
70
|
-
'RegExp',
|
|
71
|
-
'Error',
|
|
72
|
-
'Node',
|
|
73
|
-
'Element',
|
|
74
|
-
'HTMLElement',
|
|
75
|
-
'SVGElement',
|
|
76
|
-
'Event',
|
|
77
|
-
'CustomEvent',
|
|
78
|
-
'MouseEvent',
|
|
79
|
-
'KeyboardEvent',
|
|
80
|
-
'FocusEvent',
|
|
81
|
-
'InputEvent',
|
|
82
|
-
'PointerEvent',
|
|
83
|
-
'WheelEvent',
|
|
84
|
-
'DragEvent',
|
|
85
|
-
'SubmitEvent',
|
|
86
|
-
'AbortSignal',
|
|
87
|
-
'DOMRect',
|
|
88
|
-
'Document',
|
|
89
|
-
'Window',
|
|
90
|
-
'URL',
|
|
91
|
-
'URLSearchParams',
|
|
92
|
-
'CSSStyleDeclaration',
|
|
93
|
-
'Intl.Locale',
|
|
94
|
-
]);
|
|
95
|
-
|
|
96
|
-
const reactNativeEventHandlerNames = new Set([
|
|
97
|
-
'onCopy',
|
|
98
|
-
'onCut',
|
|
99
|
-
'onPaste',
|
|
100
|
-
'onCompositionEnd',
|
|
101
|
-
'onCompositionStart',
|
|
102
|
-
'onCompositionUpdate',
|
|
103
|
-
'onFocus',
|
|
104
|
-
'onBlur',
|
|
105
|
-
'onChange',
|
|
106
|
-
'onBeforeInput',
|
|
107
|
-
'onInput',
|
|
108
|
-
'onReset',
|
|
109
|
-
'onSubmit',
|
|
110
|
-
'onInvalid',
|
|
111
|
-
'onLoad',
|
|
112
|
-
'onError',
|
|
113
|
-
'onKeyDown',
|
|
114
|
-
'onKeyPress',
|
|
115
|
-
'onKeyUp',
|
|
116
|
-
'onAbort',
|
|
117
|
-
'onCanPlay',
|
|
118
|
-
'onCanPlayThrough',
|
|
119
|
-
'onDurationChange',
|
|
120
|
-
'onEmptied',
|
|
121
|
-
'onEncrypted',
|
|
122
|
-
'onEnded',
|
|
123
|
-
'onLoadedData',
|
|
124
|
-
'onLoadedMetadata',
|
|
125
|
-
'onLoadStart',
|
|
126
|
-
'onPause',
|
|
127
|
-
'onPlay',
|
|
128
|
-
'onPlaying',
|
|
129
|
-
'onProgress',
|
|
130
|
-
'onRateChange',
|
|
131
|
-
'onResize',
|
|
132
|
-
'onSeeked',
|
|
133
|
-
'onSeeking',
|
|
134
|
-
'onStalled',
|
|
135
|
-
'onSuspend',
|
|
136
|
-
'onTimeUpdate',
|
|
137
|
-
'onVolumeChange',
|
|
138
|
-
'onWaiting',
|
|
139
|
-
'onAuxClick',
|
|
140
|
-
'onClick',
|
|
141
|
-
'onContextMenu',
|
|
142
|
-
'onDoubleClick',
|
|
143
|
-
'onDrag',
|
|
144
|
-
'onDragEnd',
|
|
145
|
-
'onDragEnter',
|
|
146
|
-
'onDragExit',
|
|
147
|
-
'onDragLeave',
|
|
148
|
-
'onDragOver',
|
|
149
|
-
'onDragStart',
|
|
150
|
-
'onDrop',
|
|
151
|
-
'onMouseDown',
|
|
152
|
-
'onMouseEnter',
|
|
153
|
-
'onMouseLeave',
|
|
154
|
-
'onMouseMove',
|
|
155
|
-
'onMouseOut',
|
|
156
|
-
'onMouseOver',
|
|
157
|
-
'onMouseUp',
|
|
158
|
-
'onSelect',
|
|
159
|
-
'onTouchCancel',
|
|
160
|
-
'onTouchEnd',
|
|
161
|
-
'onTouchMove',
|
|
162
|
-
'onTouchStart',
|
|
163
|
-
'onPointerOver',
|
|
164
|
-
'onPointerEnter',
|
|
165
|
-
'onPointerDown',
|
|
166
|
-
'onPointerMove',
|
|
167
|
-
'onPointerUp',
|
|
168
|
-
'onPointerCancel',
|
|
169
|
-
'onPointerOut',
|
|
170
|
-
'onPointerLeave',
|
|
171
|
-
'onGotPointerCapture',
|
|
172
|
-
'onLostPointerCapture',
|
|
173
|
-
'onScroll',
|
|
174
|
-
'onWheel',
|
|
175
|
-
'onAnimationStart',
|
|
176
|
-
'onAnimationEnd',
|
|
177
|
-
'onAnimationIteration',
|
|
178
|
-
'onTransitionEnd',
|
|
179
|
-
'onToggle',
|
|
180
|
-
]);
|
|
181
|
-
|
|
182
|
-
function normalizeWhitespace(value: string): string {
|
|
183
|
-
return value.replace(/\s+/g, ' ').trim();
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
function toTypeNameSegment(value: string): string {
|
|
187
|
-
const pascal = toPascalCase(value);
|
|
188
|
-
if (!pascal) {
|
|
189
|
-
return 'Pkg';
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
if (/^[0-9]/.test(pascal)) {
|
|
193
|
-
return `Pkg${pascal}`;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
return pascal;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
function getPackageTypePrefix(packageName: string): string {
|
|
200
|
-
const withoutScope = packageName.replace(/^@/, '').replace(/\//g, '-');
|
|
201
|
-
const segment = toTypeNameSegment(withoutScope);
|
|
202
|
-
return `${segment}React`;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
function normalizePropertyName(name: string): string | null {
|
|
206
|
-
let normalized = name.trim();
|
|
207
|
-
if (!normalized) return null;
|
|
208
|
-
|
|
209
|
-
const bracketQuotedMatch = normalized.match(/^\[\s*['"](.+?)['"]\s*\]$/);
|
|
210
|
-
if (bracketQuotedMatch) {
|
|
211
|
-
normalized = bracketQuotedMatch[1];
|
|
212
|
-
} else {
|
|
213
|
-
const bracketMatch = normalized.match(/^\[\s*(.+?)\s*\]$/);
|
|
214
|
-
if (bracketMatch) {
|
|
215
|
-
normalized = bracketMatch[1];
|
|
216
|
-
}
|
|
217
|
-
const quotedMatch = normalized.match(/^['"](.+?)['"]$/);
|
|
218
|
-
if (quotedMatch) {
|
|
219
|
-
normalized = quotedMatch[1];
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
normalized = normalized.trim();
|
|
224
|
-
if (!normalized) return null;
|
|
225
|
-
if (normalized.includes('\n') || normalized.includes('\r')) return null;
|
|
226
|
-
return normalized;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
function escapeSingleQuotes(value: string): string {
|
|
230
|
-
return value.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
function isKnownTypeIdentifier(identifier: string): boolean {
|
|
234
|
-
if (allowedTypeNameSet.has(identifier)) return true;
|
|
235
|
-
if (allowedTypeIdentifierRegex.test(identifier) && identifier.startsWith('globalThis.')) return true;
|
|
236
|
-
return false;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
function getIdentifierTokens(typeText: string): string[] {
|
|
240
|
-
return typeText.match(/[A-Za-z_$][A-Za-z0-9_$]*(?:\.[A-Za-z_$][A-Za-z0-9_$]*)*/g) ?? [];
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
function isPrimitiveToken(match: string): boolean {
|
|
244
|
-
return (
|
|
245
|
-
match === 'true' ||
|
|
246
|
-
match === 'false' ||
|
|
247
|
-
match === 'null' ||
|
|
248
|
-
match === 'undefined' ||
|
|
249
|
-
match === 'string' ||
|
|
250
|
-
match === 'number' ||
|
|
251
|
-
match === 'boolean' ||
|
|
252
|
-
match === 'bigint' ||
|
|
253
|
-
match === 'symbol' ||
|
|
254
|
-
match === 'unknown' ||
|
|
255
|
-
match === 'any' ||
|
|
256
|
-
match === 'void' ||
|
|
257
|
-
match === 'never'
|
|
258
|
-
);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
function registerTypeImport(
|
|
262
|
-
state: TypeImportState,
|
|
263
|
-
identifier: string,
|
|
264
|
-
moduleSpecifier: string,
|
|
265
|
-
): void {
|
|
266
|
-
if (state.ambiguousIdentifiers.has(identifier)) {
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
const existing = state.importsByIdentifier.get(identifier);
|
|
271
|
-
if (existing && existing !== moduleSpecifier) {
|
|
272
|
-
state.importsByIdentifier.delete(identifier);
|
|
273
|
-
state.ambiguousIdentifiers.add(identifier);
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
if (!existing) {
|
|
278
|
-
state.importsByIdentifier.set(identifier, moduleSpecifier);
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
function trackImportedIdentifierUsage(
|
|
283
|
-
state: TypeImportState,
|
|
284
|
-
identifier: string,
|
|
285
|
-
moduleSpecifier: string,
|
|
286
|
-
): void {
|
|
287
|
-
if (!state.usedImports.has(moduleSpecifier)) {
|
|
288
|
-
state.usedImports.set(moduleSpecifier, new Set());
|
|
289
|
-
}
|
|
290
|
-
state.usedImports.get(moduleSpecifier)!.add(identifier);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
function isBareModuleSpecifier(moduleSpecifier: string): boolean {
|
|
294
|
-
return !!moduleSpecifier && !moduleSpecifier.startsWith('.') && !moduleSpecifier.startsWith('/');
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
function canUseComplexType(typeText: string, typeImportState?: TypeImportState): boolean {
|
|
298
|
-
if (!typeText) return false;
|
|
299
|
-
if (/[{};=]/.test(typeText)) return false;
|
|
300
|
-
if (/=>/.test(typeText)) return false;
|
|
301
|
-
if (!/^[A-Za-z0-9_$<>\[\]\(\)\|&,.?'"`\s:-]+$/.test(typeText)) return false;
|
|
302
|
-
|
|
303
|
-
const identifierMatches = getIdentifierTokens(typeText);
|
|
304
|
-
for (const match of identifierMatches) {
|
|
305
|
-
if (isPrimitiveToken(match)) {
|
|
306
|
-
continue;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
if (isKnownTypeIdentifier(match)) {
|
|
310
|
-
continue;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
const rootIdentifier = match.split('.')[0];
|
|
314
|
-
if (
|
|
315
|
-
typeImportState &&
|
|
316
|
-
!typeImportState.ambiguousIdentifiers.has(rootIdentifier) &&
|
|
317
|
-
typeImportState.importsByIdentifier.has(rootIdentifier)
|
|
318
|
-
) {
|
|
319
|
-
trackImportedIdentifierUsage(
|
|
320
|
-
typeImportState,
|
|
321
|
-
rootIdentifier,
|
|
322
|
-
typeImportState.importsByIdentifier.get(rootIdentifier)!,
|
|
323
|
-
);
|
|
324
|
-
continue;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
if (!isKnownTypeIdentifier(rootIdentifier)) {
|
|
328
|
-
return false;
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
return true;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
function toPascalCase(value: string): string {
|
|
336
|
-
return value
|
|
337
|
-
.split(/[^a-zA-Z0-9]+/)
|
|
338
|
-
.filter(Boolean)
|
|
339
|
-
.map((part) => `${part[0].toUpperCase()}${part.slice(1)}`)
|
|
340
|
-
.join('');
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
function toCamelCase(value: string): string {
|
|
344
|
-
const pascal = toPascalCase(value);
|
|
345
|
-
if (!pascal) return '';
|
|
346
|
-
return `${pascal[0].toLowerCase()}${pascal.slice(1)}`;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
function toSafeType(typeText?: string, typeImportState?: TypeImportState): string {
|
|
350
|
-
if (!typeText) return 'unknown';
|
|
351
|
-
const normalized = normalizeWhitespace(typeText);
|
|
352
|
-
if (!normalized) return 'unknown';
|
|
353
|
-
|
|
354
|
-
if (primitiveUnionRegex.test(normalized)) {
|
|
355
|
-
return normalized;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
if (normalized.endsWith('[]')) {
|
|
359
|
-
const itemType = normalized.slice(0, -2).trim();
|
|
360
|
-
if (primitiveUnionRegex.test(itemType)) {
|
|
361
|
-
return `${itemType}[]`;
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
if (canUseComplexType(normalized, typeImportState)) {
|
|
366
|
-
return normalized;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
return 'unknown';
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
function getCEMManifestPath(cwd: string, packageJson: Record<string, unknown>): string {
|
|
373
|
-
if (typeof packageJson.customElements === 'string' && packageJson.customElements.trim().length > 0) {
|
|
374
|
-
return resolve(cwd, packageJson.customElements);
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
return resolve(cwd, 'dist/custom-elements.json');
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
function collectCustomElements(manifest: CEMManifest): CEMDeclaration[] {
|
|
381
|
-
const elements: CEMDeclaration[] = [];
|
|
382
|
-
|
|
383
|
-
for (const moduleDefinition of manifest.modules ?? []) {
|
|
384
|
-
for (const declaration of moduleDefinition.declarations ?? []) {
|
|
385
|
-
if (declaration.customElement && declaration.tagName) {
|
|
386
|
-
elements.push(declaration);
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
return elements;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
function mergeUniqueByKey<T>(base: T[], extra: T[], getKey: (item: T) => string | null): T[] {
|
|
395
|
-
const merged = [...base];
|
|
396
|
-
const knownKeys = new Set(
|
|
397
|
-
base
|
|
398
|
-
.map((item) => getKey(item))
|
|
399
|
-
.filter((item): item is string => !!item),
|
|
400
|
-
);
|
|
401
|
-
|
|
402
|
-
for (const item of extra) {
|
|
403
|
-
const key = getKey(item);
|
|
404
|
-
if (!key || !knownKeys.has(key)) {
|
|
405
|
-
merged.push(item);
|
|
406
|
-
if (key) knownKeys.add(key);
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
return merged;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
function mergeDeclarationMetadata(
|
|
414
|
-
declaration: CEMDeclaration,
|
|
415
|
-
inheritedDeclaration: CEMDeclaration,
|
|
416
|
-
): CEMDeclaration {
|
|
417
|
-
const declarationAttributes = declaration.attributes ?? [];
|
|
418
|
-
const inheritedAttributes = inheritedDeclaration.attributes ?? [];
|
|
419
|
-
const attributes = mergeUniqueByKey(
|
|
420
|
-
declarationAttributes,
|
|
421
|
-
inheritedAttributes,
|
|
422
|
-
(attribute) => normalizePropertyName(attribute.fieldName ?? attribute.name ?? ''),
|
|
423
|
-
);
|
|
424
|
-
|
|
425
|
-
const declarationMembers = declaration.members ?? [];
|
|
426
|
-
const inheritedMembers = inheritedDeclaration.members ?? [];
|
|
427
|
-
const members = mergeUniqueByKey(
|
|
428
|
-
declarationMembers,
|
|
429
|
-
inheritedMembers,
|
|
430
|
-
(member) => normalizePropertyName(member.name ?? ''),
|
|
431
|
-
);
|
|
432
|
-
|
|
433
|
-
const declarationEvents = declaration.events ?? [];
|
|
434
|
-
const inheritedEvents = inheritedDeclaration.events ?? [];
|
|
435
|
-
const events = mergeUniqueByKey(
|
|
436
|
-
declarationEvents,
|
|
437
|
-
inheritedEvents,
|
|
438
|
-
(event) => normalizePropertyName(event.name ?? ''),
|
|
439
|
-
);
|
|
440
|
-
|
|
441
|
-
return {
|
|
442
|
-
...declaration,
|
|
443
|
-
attributes,
|
|
444
|
-
members,
|
|
445
|
-
events,
|
|
446
|
-
};
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
function createDeclarationLookup(manifest: CEMManifest): {
|
|
450
|
-
byTagAndName: Map<string, CEMDeclaration>;
|
|
451
|
-
byTag: Map<string, CEMDeclaration>;
|
|
452
|
-
} {
|
|
453
|
-
const byTagAndName = new Map<string, CEMDeclaration>();
|
|
454
|
-
const byTag = new Map<string, CEMDeclaration>();
|
|
455
|
-
|
|
456
|
-
for (const moduleDefinition of manifest.modules ?? []) {
|
|
457
|
-
for (const declaration of moduleDefinition.declarations ?? []) {
|
|
458
|
-
if (!declaration.customElement || !declaration.tagName) continue;
|
|
459
|
-
|
|
460
|
-
if (declaration.name) {
|
|
461
|
-
byTagAndName.set(`${declaration.tagName}::${declaration.name}`, declaration);
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
if (!byTag.has(declaration.tagName)) {
|
|
465
|
-
byTag.set(declaration.tagName, declaration);
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
return { byTagAndName, byTag };
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
async function mergeFastInheritanceFromManifest(
|
|
474
|
-
cwd: string,
|
|
475
|
-
declarations: CEMDeclaration[],
|
|
476
|
-
): Promise<CEMDeclaration[]> {
|
|
477
|
-
const fastManifestPath = resolve(cwd, 'ms-fast-components/custom-elements.json');
|
|
478
|
-
if (!(await fileExists(fastManifestPath))) {
|
|
479
|
-
return declarations;
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
const fastManifest = JSON.parse(await readFile(fastManifestPath, 'utf8')) as CEMManifest;
|
|
483
|
-
const { byTagAndName, byTag } = createDeclarationLookup(fastManifest);
|
|
484
|
-
|
|
485
|
-
return declarations.map((declaration) => {
|
|
486
|
-
if (!declaration.tagName || declaration.superclass?.package !== '@microsoft/fast-components') {
|
|
487
|
-
return declaration;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
const byTagAndNameKey = `${declaration.tagName}::${declaration.name ?? ''}`;
|
|
491
|
-
const inheritedDeclaration =
|
|
492
|
-
byTagAndName.get(byTagAndNameKey) ??
|
|
493
|
-
byTagAndName.get(`${declaration.tagName}::${declaration.superclass?.name ?? ''}`) ??
|
|
494
|
-
byTag.get(declaration.tagName);
|
|
495
|
-
|
|
496
|
-
if (!inheritedDeclaration) {
|
|
497
|
-
return declaration;
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
return mergeDeclarationMetadata(declaration, inheritedDeclaration);
|
|
501
|
-
});
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
function resolveTagPrefixes(packageName: string): string[] {
|
|
505
|
-
const normalized = packageName.toLowerCase();
|
|
506
|
-
|
|
507
|
-
if (normalized === '@genesislcap/foundation-ui') {
|
|
508
|
-
return ['foundation'];
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
if (normalized.startsWith('@genesislcap/rapid-') || normalized.includes('/rapid-')) {
|
|
512
|
-
return ['rapid'];
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
if (normalized.includes('foundation-zero') || normalized.startsWith('@genesislcap/zero-')) {
|
|
516
|
-
return ['zero'];
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
// MF and generic foundation packages can switch prefixes at runtime.
|
|
520
|
-
return ['foundation', 'rapid', 'zero'];
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
function normalizeTagNames(tagName: string, packageName: string): string[] {
|
|
524
|
-
const prefixToken = '%%prefix%%-';
|
|
525
|
-
if (!tagName.includes(prefixToken)) {
|
|
526
|
-
return [tagName];
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
const suffix = tagName.replace(prefixToken, '');
|
|
530
|
-
return resolveTagPrefixes(packageName).map((prefix) => `${prefix}-${suffix}`);
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
function toEventHandlerType(typeText?: string, typeImportState?: TypeImportState): string {
|
|
534
|
-
if (!typeText) {
|
|
535
|
-
return '(event: CustomEvent<unknown>) => void';
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
const normalized = typeText.trim();
|
|
539
|
-
if (!normalized) {
|
|
540
|
-
return '(event: CustomEvent<unknown>) => void';
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
if (normalized === 'Event') {
|
|
544
|
-
return '(event: Event) => void';
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
if (normalized.startsWith('CustomEvent<')) {
|
|
548
|
-
const match = normalized.match(/^CustomEvent<(.+)>$/);
|
|
549
|
-
if (!match) return '(event: CustomEvent<unknown>) => void';
|
|
550
|
-
const detailType = toSafeType(match[1]?.trim(), typeImportState);
|
|
551
|
-
return `(event: CustomEvent<${detailType}>) => void`;
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
if (normalized === 'CustomEvent') {
|
|
555
|
-
return '(event: CustomEvent<unknown>) => void';
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
return '(event: CustomEvent<unknown>) => void';
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
function buildElementProps(declaration: CEMDeclaration, typeImportState: TypeImportState): string[] {
|
|
562
|
-
const propertyMap = new Map<string, string>();
|
|
563
|
-
const eventMap = new Map<string, string>();
|
|
564
|
-
|
|
565
|
-
const addProperty = (name: string, typeText?: string) => {
|
|
566
|
-
if (!name) return;
|
|
567
|
-
const normalizedName = normalizePropertyName(name);
|
|
568
|
-
if (!normalizedName) return;
|
|
569
|
-
const safeType = toSafeType(typeText, typeImportState);
|
|
570
|
-
if (!propertyMap.has(normalizedName)) {
|
|
571
|
-
propertyMap.set(normalizedName, safeType);
|
|
572
|
-
}
|
|
573
|
-
};
|
|
574
|
-
|
|
575
|
-
for (const attribute of declaration.attributes ?? []) {
|
|
576
|
-
// Prefer React-friendly property casing when available.
|
|
577
|
-
if (attribute.fieldName) {
|
|
578
|
-
addProperty(attribute.fieldName, attribute.type?.text);
|
|
579
|
-
} else if (attribute.name) {
|
|
580
|
-
addProperty(attribute.name, attribute.type?.text);
|
|
581
|
-
if (attribute.name.includes('-')) {
|
|
582
|
-
const camelName = toCamelCase(attribute.name);
|
|
583
|
-
if (camelName) {
|
|
584
|
-
addProperty(camelName, attribute.type?.text);
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
// Only include public fields that are reflected as attributes.
|
|
591
|
-
for (const member of declaration.members ?? []) {
|
|
592
|
-
if (
|
|
593
|
-
member.kind === 'field' &&
|
|
594
|
-
member.privacy !== 'private' &&
|
|
595
|
-
member.privacy !== 'protected' &&
|
|
596
|
-
member.attribute &&
|
|
597
|
-
member.name &&
|
|
598
|
-
!member.name.startsWith('_') &&
|
|
599
|
-
!member.name.startsWith('$')
|
|
600
|
-
) {
|
|
601
|
-
// React canonical typing should expose property name (camelCase).
|
|
602
|
-
addProperty(member.name, member.type?.text);
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
for (const event of declaration.events ?? []) {
|
|
607
|
-
if (!event.name) continue;
|
|
608
|
-
const normalizedEventName = normalizePropertyName(event.name);
|
|
609
|
-
if (!normalizedEventName) continue;
|
|
610
|
-
const eventHandlerType = toEventHandlerType(event.type?.text, typeImportState);
|
|
611
|
-
const pascalName = toPascalCase(normalizedEventName);
|
|
612
|
-
if (pascalName) {
|
|
613
|
-
const handlerName = `on${pascalName}`;
|
|
614
|
-
if (!reactNativeEventHandlerNames.has(handlerName)) {
|
|
615
|
-
eventMap.set(handlerName, eventHandlerType);
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
const lines: string[] = [
|
|
621
|
-
'class?: string;',
|
|
622
|
-
'part?: string;',
|
|
623
|
-
'[key: `data-${string}`]: string | number | boolean | undefined;',
|
|
624
|
-
];
|
|
625
|
-
|
|
626
|
-
for (const [name, typeText] of propertyMap) {
|
|
627
|
-
lines.push(`'${escapeSingleQuotes(name)}'?: ${typeText};`);
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
for (const [name, handlerType] of eventMap) {
|
|
631
|
-
lines.push(`'${escapeSingleQuotes(name)}'?: ${handlerType};`);
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
return lines;
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
function generateDeclarations(
|
|
638
|
-
packageName: string,
|
|
639
|
-
declarations: CEMDeclaration[],
|
|
640
|
-
typeImportState: TypeImportState,
|
|
641
|
-
): string {
|
|
642
|
-
const packagePrefix = getPackageTypePrefix(packageName);
|
|
643
|
-
const interfaceEntries: { interfaceName: string; code: string }[] = [];
|
|
644
|
-
const interfacesByTag = new Map<string, string>();
|
|
645
|
-
let interfaceCounter = 0;
|
|
646
|
-
|
|
647
|
-
for (const declaration of declarations) {
|
|
648
|
-
const interfaceName = `${packagePrefix}ElementProps${interfaceCounter + 1}`;
|
|
649
|
-
interfaceCounter += 1;
|
|
650
|
-
const props = buildElementProps(declaration, typeImportState).map((line) => ` ${line}`);
|
|
651
|
-
const code = [` interface ${interfaceName} {`, ...props, ' }'].join('\n');
|
|
652
|
-
interfaceEntries.push({ interfaceName, code });
|
|
653
|
-
for (const tagName of normalizeTagNames(declaration.tagName!, packageName)) {
|
|
654
|
-
if (!interfacesByTag.has(tagName)) {
|
|
655
|
-
interfacesByTag.set(tagName, interfaceName);
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
const intrinsicEntries = [...interfacesByTag.entries()]
|
|
661
|
-
.sort((a, b) => a[0].localeCompare(b[0]))
|
|
662
|
-
.map(([tagName, interfaceName]) => ` '${tagName}': ${interfaceName};`);
|
|
663
|
-
|
|
664
|
-
const elementInterfaces = interfaceEntries.map((entry) =>
|
|
665
|
-
entry.code.replace(
|
|
666
|
-
`interface ${entry.interfaceName} {`,
|
|
667
|
-
`interface ${entry.interfaceName} extends HTMLAttributes<HTMLElement> {`,
|
|
668
|
-
),
|
|
669
|
-
);
|
|
670
|
-
|
|
671
|
-
const importLines = [...typeImportState.usedImports.entries()]
|
|
672
|
-
.sort((a, b) => a[0].localeCompare(b[0]))
|
|
673
|
-
.map(([moduleSpecifier, identifiers]) => {
|
|
674
|
-
const sortedIdentifiers = [...identifiers].sort((a, b) => a.localeCompare(b));
|
|
675
|
-
return `import type { ${sortedIdentifiers.join(', ')} } from '${moduleSpecifier}';`;
|
|
676
|
-
});
|
|
677
|
-
|
|
678
|
-
return [
|
|
679
|
-
'/**',
|
|
680
|
-
' * AUTO-GENERATED FILE - DO NOT EDIT.',
|
|
681
|
-
` * Source package: ${packageName}`,
|
|
682
|
-
' * Generated from custom-elements manifest.',
|
|
683
|
-
' */',
|
|
684
|
-
'',
|
|
685
|
-
"import type { HTMLAttributes } from 'react';",
|
|
686
|
-
...importLines,
|
|
687
|
-
'',
|
|
688
|
-
"declare module 'react/jsx-runtime' {",
|
|
689
|
-
' namespace JSX {',
|
|
690
|
-
...elementInterfaces,
|
|
691
|
-
' interface IntrinsicElements {',
|
|
692
|
-
...intrinsicEntries,
|
|
693
|
-
' }',
|
|
694
|
-
' }',
|
|
695
|
-
'}',
|
|
696
|
-
'',
|
|
697
|
-
'export {};',
|
|
698
|
-
'',
|
|
699
|
-
].join('\n');
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
async function fileExists(path: string): Promise<boolean> {
|
|
703
|
-
try {
|
|
704
|
-
await stat(path);
|
|
705
|
-
return true;
|
|
706
|
-
} catch {
|
|
707
|
-
return false;
|
|
708
|
-
}
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
function addCanonicalReferenceFromValue(value: unknown, state: TypeImportState): void {
|
|
712
|
-
if (!value || typeof value !== 'object') {
|
|
713
|
-
return;
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
if (Array.isArray(value)) {
|
|
717
|
-
for (const item of value) {
|
|
718
|
-
addCanonicalReferenceFromValue(item, state);
|
|
719
|
-
}
|
|
720
|
-
return;
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
const record = value as Record<string, unknown>;
|
|
724
|
-
const canonicalReference = record.canonicalReference;
|
|
725
|
-
if (typeof canonicalReference === 'string') {
|
|
726
|
-
const match = canonicalReference.match(/^(@[^!]+)!([^:]+):/);
|
|
727
|
-
if (match) {
|
|
728
|
-
const moduleSpecifier = match[1];
|
|
729
|
-
const identifier = match[2];
|
|
730
|
-
if (identifier && /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(identifier)) {
|
|
731
|
-
registerTypeImport(state, identifier, moduleSpecifier);
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
for (const nestedValue of Object.values(record)) {
|
|
737
|
-
if (nestedValue && typeof nestedValue === 'object') {
|
|
738
|
-
addCanonicalReferenceFromValue(nestedValue, state);
|
|
739
|
-
}
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
function parseImportsFromDtsContent(content: string, state: TypeImportState): void {
|
|
744
|
-
const importOrExportBlockRegex =
|
|
745
|
-
/(?:import|export)\s+(?:type\s+)?\{([^}]+)\}\s+from\s+['"]([^'"]+)['"]/g;
|
|
746
|
-
for (const match of content.matchAll(importOrExportBlockRegex)) {
|
|
747
|
-
const importList = match[1] ?? '';
|
|
748
|
-
const moduleSpecifier = match[2] ?? '';
|
|
749
|
-
if (!isBareModuleSpecifier(moduleSpecifier)) continue;
|
|
750
|
-
|
|
751
|
-
for (const entryRaw of importList.split(',')) {
|
|
752
|
-
const entry = entryRaw.trim();
|
|
753
|
-
if (!entry) continue;
|
|
754
|
-
const aliasMatch = entry.match(/^([A-Za-z_$][A-Za-z0-9_$]*)\s+as\s+([A-Za-z_$][A-Za-z0-9_$]*)$/);
|
|
755
|
-
if (aliasMatch) {
|
|
756
|
-
registerTypeImport(state, aliasMatch[2], moduleSpecifier);
|
|
757
|
-
continue;
|
|
758
|
-
}
|
|
759
|
-
if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(entry)) {
|
|
760
|
-
registerTypeImport(state, entry, moduleSpecifier);
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
const exportAllRegex = /export\s+\*\s+from\s+['"]([^'"]+)['"]/g;
|
|
766
|
-
for (const match of content.matchAll(exportAllRegex)) {
|
|
767
|
-
const moduleSpecifier = match[1] ?? '';
|
|
768
|
-
if (!isBareModuleSpecifier(moduleSpecifier)) continue;
|
|
769
|
-
state.wildcardExportModules.add(moduleSpecifier);
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
async function collectFilesRecursively(
|
|
774
|
-
rootDirectory: string,
|
|
775
|
-
isTargetFile: (fileName: string) => boolean,
|
|
776
|
-
): Promise<string[]> {
|
|
777
|
-
const files: string[] = [];
|
|
778
|
-
const queue: string[] = [rootDirectory];
|
|
779
|
-
|
|
780
|
-
while (queue.length) {
|
|
781
|
-
const currentDirectory = queue.pop()!;
|
|
782
|
-
const entries = await readdir(currentDirectory, { withFileTypes: true });
|
|
783
|
-
for (const entry of entries) {
|
|
784
|
-
const fullPath = resolve(currentDirectory, entry.name);
|
|
785
|
-
if (entry.isDirectory()) {
|
|
786
|
-
queue.push(fullPath);
|
|
787
|
-
} else if (entry.isFile() && isTargetFile(entry.name)) {
|
|
788
|
-
files.push(fullPath);
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
return files;
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
async function collectTypeMetadataFiles(
|
|
797
|
-
distDirectory: string,
|
|
798
|
-
): Promise<{ apiJsonFiles: string[]; dtsFiles: string[] }> {
|
|
799
|
-
const [apiJsonFiles, dtsFiles] = await Promise.all([
|
|
800
|
-
collectFilesRecursively(distDirectory, (fileName) => fileName.endsWith('.api.json')),
|
|
801
|
-
collectFilesRecursively(distDirectory, (fileName) => fileName.endsWith('.d.ts')),
|
|
802
|
-
]);
|
|
803
|
-
|
|
804
|
-
return { apiJsonFiles, dtsFiles };
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
async function parseApiJsonFiles(filePaths: string[], state: TypeImportState): Promise<void> {
|
|
808
|
-
for (const filePath of filePaths) {
|
|
809
|
-
const apiJson = JSON.parse(await readFile(filePath, 'utf8')) as unknown;
|
|
810
|
-
addCanonicalReferenceFromValue(apiJson, state);
|
|
811
|
-
}
|
|
812
|
-
}
|
|
813
|
-
|
|
814
|
-
async function parseDtsFiles(filePaths: string[], state: TypeImportState): Promise<void> {
|
|
815
|
-
for (const filePath of filePaths) {
|
|
816
|
-
const dtsContent = await readFile(filePath, 'utf8');
|
|
817
|
-
parseImportsFromDtsContent(dtsContent, state);
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
function mergeTypeImportStateInto(
|
|
822
|
-
targetState: TypeImportState,
|
|
823
|
-
sourceState: TypeImportState,
|
|
824
|
-
): void {
|
|
825
|
-
for (const ambiguousIdentifier of sourceState.ambiguousIdentifiers) {
|
|
826
|
-
targetState.importsByIdentifier.delete(ambiguousIdentifier);
|
|
827
|
-
targetState.ambiguousIdentifiers.add(ambiguousIdentifier);
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
for (const [identifier, moduleSpecifier] of sourceState.importsByIdentifier) {
|
|
831
|
-
registerTypeImport(targetState, identifier, moduleSpecifier);
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
async function findWorkspaceRoot(startDirectory: string): Promise<string> {
|
|
836
|
-
let currentDirectory = startDirectory;
|
|
837
|
-
while (true) {
|
|
838
|
-
const hasPackagesDirectory = await fileExists(resolve(currentDirectory, 'packages'));
|
|
839
|
-
const hasRootPackageJson = await fileExists(resolve(currentDirectory, 'package.json'));
|
|
840
|
-
if (hasPackagesDirectory && hasRootPackageJson) {
|
|
841
|
-
return currentDirectory;
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
const parentDirectory = dirname(currentDirectory);
|
|
845
|
-
if (parentDirectory === currentDirectory) {
|
|
846
|
-
return startDirectory;
|
|
847
|
-
}
|
|
848
|
-
currentDirectory = parentDirectory;
|
|
849
|
-
}
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
async function getWorkspacePackageDirectoryByName(
|
|
853
|
-
workspaceRoot: string,
|
|
854
|
-
packageName: string,
|
|
855
|
-
): Promise<string | undefined> {
|
|
856
|
-
const packagesDirectory = resolve(workspaceRoot, 'packages');
|
|
857
|
-
if (!(await fileExists(packagesDirectory))) {
|
|
858
|
-
return undefined;
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
const packageJsonFiles = await collectFilesRecursively(
|
|
862
|
-
packagesDirectory,
|
|
863
|
-
(fileName) => fileName === 'package.json',
|
|
864
|
-
);
|
|
865
|
-
for (const packageJsonPath of packageJsonFiles) {
|
|
866
|
-
const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8')) as Record<string, unknown>;
|
|
867
|
-
if (packageJson.name === packageName) {
|
|
868
|
-
return dirname(packageJsonPath);
|
|
869
|
-
}
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
return undefined;
|
|
873
|
-
}
|
|
874
|
-
|
|
875
|
-
async function enrichFromWorkspaceWildcardExports(
|
|
876
|
-
cwd: string,
|
|
877
|
-
state: TypeImportState,
|
|
878
|
-
): Promise<void> {
|
|
879
|
-
const workspaceRoot = await findWorkspaceRoot(cwd);
|
|
880
|
-
const processedModules = new Set<string>();
|
|
881
|
-
const modulesToProcess = [...state.wildcardExportModules].filter((moduleSpecifier) =>
|
|
882
|
-
moduleSpecifier.startsWith('@genesislcap/'),
|
|
883
|
-
);
|
|
884
|
-
|
|
885
|
-
while (modulesToProcess.length) {
|
|
886
|
-
const moduleSpecifier = modulesToProcess.pop()!;
|
|
887
|
-
if (processedModules.has(moduleSpecifier)) {
|
|
888
|
-
continue;
|
|
889
|
-
}
|
|
890
|
-
processedModules.add(moduleSpecifier);
|
|
891
|
-
|
|
892
|
-
const packageDirectory = await getWorkspacePackageDirectoryByName(workspaceRoot, moduleSpecifier);
|
|
893
|
-
if (!packageDirectory) {
|
|
894
|
-
continue;
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
const distDirectory = resolve(packageDirectory, 'dist');
|
|
898
|
-
if (!(await fileExists(distDirectory))) {
|
|
899
|
-
continue;
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
const referencedState = createTypeImportState();
|
|
903
|
-
const { apiJsonFiles, dtsFiles } = await collectTypeMetadataFiles(distDirectory);
|
|
904
|
-
await parseApiJsonFiles(apiJsonFiles, referencedState);
|
|
905
|
-
await parseDtsFiles(dtsFiles, referencedState);
|
|
906
|
-
mergeTypeImportStateInto(state, referencedState);
|
|
907
|
-
|
|
908
|
-
for (const exportedModule of referencedState.wildcardExportModules) {
|
|
909
|
-
if (exportedModule.startsWith('@genesislcap/') && !processedModules.has(exportedModule)) {
|
|
910
|
-
modulesToProcess.push(exportedModule);
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
}
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
async function buildTypeImportState(cwd: string): Promise<TypeImportState> {
|
|
917
|
-
const state = createTypeImportState();
|
|
918
|
-
|
|
919
|
-
const distDirectory = resolve(cwd, 'dist');
|
|
920
|
-
if (!(await fileExists(distDirectory))) {
|
|
921
|
-
return state;
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
const { apiJsonFiles, dtsFiles } = await collectTypeMetadataFiles(distDirectory);
|
|
925
|
-
await parseApiJsonFiles(apiJsonFiles, state);
|
|
926
|
-
await parseDtsFiles(dtsFiles, state);
|
|
927
|
-
await enrichFromWorkspaceWildcardExports(cwd, state);
|
|
928
|
-
|
|
929
|
-
return state;
|
|
930
|
-
}
|
|
931
|
-
|
|
932
|
-
async function ensureReferenceInTypesFile(
|
|
933
|
-
filePath: string,
|
|
934
|
-
reactJsxRuntimePath: string,
|
|
935
|
-
): Promise<void> {
|
|
936
|
-
if (!(await fileExists(filePath))) {
|
|
937
|
-
return;
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
const relativeReferencePath = relative(dirname(filePath), reactJsxRuntimePath).replace(/\\/g, '/');
|
|
941
|
-
const normalizedReferencePath = relativeReferencePath.startsWith('.')
|
|
942
|
-
? relativeReferencePath
|
|
943
|
-
: `./${relativeReferencePath}`;
|
|
944
|
-
const referenceLine = `/// <reference path="${normalizedReferencePath}" />`;
|
|
945
|
-
|
|
946
|
-
const existingContent = await readFile(filePath, 'utf8');
|
|
947
|
-
if (!existingContent.includes(referenceLine)) {
|
|
948
|
-
await writeFile(filePath, `${referenceLine}\n${existingContent}`, 'utf8');
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
export async function generateReactJsxTypes(
|
|
954
|
-
cwd: string,
|
|
955
|
-
): Promise<{ generated: boolean; path?: string; reason?: string }> {
|
|
956
|
-
const packageJsonPath = resolve(cwd, 'package.json');
|
|
957
|
-
if (!(await fileExists(packageJsonPath))) {
|
|
958
|
-
return { generated: false, reason: 'No package.json found.' };
|
|
959
|
-
}
|
|
960
|
-
|
|
961
|
-
const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8')) as Record<string, unknown>;
|
|
962
|
-
const manifestPath = getCEMManifestPath(cwd, packageJson);
|
|
963
|
-
if (!(await fileExists(manifestPath))) {
|
|
964
|
-
return { generated: false, reason: 'No custom elements manifest found.' };
|
|
965
|
-
}
|
|
966
|
-
|
|
967
|
-
const manifest = JSON.parse(await readFile(manifestPath, 'utf8')) as CEMManifest;
|
|
968
|
-
const declarations = collectCustomElements(manifest);
|
|
969
|
-
if (!declarations.length) {
|
|
970
|
-
return { generated: false, reason: 'No custom elements discovered in manifest.' };
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
const resolvedDeclarations = await mergeFastInheritanceFromManifest(cwd, declarations);
|
|
974
|
-
|
|
975
|
-
const dtsRoot = resolve(cwd, 'dist/dts');
|
|
976
|
-
const outputPath = resolve(dtsRoot, GENERATED_FILE_NAME);
|
|
977
|
-
await mkdir(dirname(outputPath), { recursive: true });
|
|
978
|
-
|
|
979
|
-
const packageName = typeof packageJson.name === 'string' ? packageJson.name : 'unknown-package';
|
|
980
|
-
const typeImportState = await buildTypeImportState(cwd);
|
|
981
|
-
const content = generateDeclarations(packageName, resolvedDeclarations, typeImportState);
|
|
982
|
-
await writeFile(outputPath, content, 'utf8');
|
|
983
|
-
|
|
984
|
-
const candidateTypesPaths = new Set<string>([resolve(cwd, 'dist/dts/index.d.ts')]);
|
|
985
|
-
if (typeof packageJson.types === 'string' && packageJson.types.endsWith('.d.ts')) {
|
|
986
|
-
candidateTypesPaths.add(resolve(cwd, packageJson.types));
|
|
987
|
-
}
|
|
988
|
-
|
|
989
|
-
for (const typesPath of candidateTypesPaths) {
|
|
990
|
-
await ensureReferenceInTypesFile(typesPath, outputPath);
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
return { generated: true, path: outputPath };
|
|
994
|
-
}
|