@ontrails/adapter-kit 1.0.0-beta.39 → 1.0.0-beta.41
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/package.json +3 -2
- package/src/catalog.ts +14 -520
- package/src/check.ts +658 -237
- package/src/index.ts +10 -0
- package/src/source.ts +684 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ontrails/adapter-kit",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.41",
|
|
4
4
|
"description": "Internal adapter authoring kit for Trails metadata, scaffolding, and checks.",
|
|
5
5
|
"files": [
|
|
6
6
|
"src/**/*.ts",
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"clean": "rm -rf dist *.tsbuildinfo"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@ontrails/core": "^1.0.0-beta.
|
|
24
|
+
"@ontrails/core": "^1.0.0-beta.41",
|
|
25
|
+
"@ontrails/source": "^1.0.0-beta.41"
|
|
25
26
|
},
|
|
26
27
|
"peerDependencies": {
|
|
27
28
|
"zod": "^4.3.5"
|
package/src/catalog.ts
CHANGED
|
@@ -6,11 +6,17 @@
|
|
|
6
6
|
* internal tooling package.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { existsSync,
|
|
10
|
-
import {
|
|
9
|
+
import { existsSync, realpathSync, statSync } from 'node:fs';
|
|
10
|
+
import { join, resolve } from 'node:path';
|
|
11
11
|
|
|
12
12
|
import { listWorkspacePackages } from '@ontrails/core';
|
|
13
13
|
|
|
14
|
+
import {
|
|
15
|
+
adapterSourceExportKind,
|
|
16
|
+
adapterSourceExportKindHasType,
|
|
17
|
+
adapterSourceExportKindHasValue,
|
|
18
|
+
} from './source.js';
|
|
19
|
+
|
|
14
20
|
export const adapterTargetPlacements = ['extracted', 'subpath'] as const;
|
|
15
21
|
|
|
16
22
|
export type AdapterTargetPlacementValue =
|
|
@@ -85,47 +91,12 @@ interface ParsedCatalogTarget {
|
|
|
85
91
|
readonly targetEntry?: AdapterTargetCatalogEntry | undefined;
|
|
86
92
|
}
|
|
87
93
|
|
|
88
|
-
type ExportKind = 'type' | 'type-value' | 'value';
|
|
89
|
-
|
|
90
|
-
interface StarExportSpecifier {
|
|
91
|
-
readonly specifier: string;
|
|
92
|
-
readonly typeOnly: boolean;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
interface NamedExportSpecifier {
|
|
96
|
-
readonly identifier: string;
|
|
97
|
-
readonly specifier: string;
|
|
98
|
-
readonly typeOnly: boolean;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
interface NamedImportSpecifier {
|
|
102
|
-
readonly identifier: string;
|
|
103
|
-
readonly specifier: string;
|
|
104
|
-
readonly typeOnly: boolean;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
interface ExportListSpecifier {
|
|
108
|
-
readonly exported: string;
|
|
109
|
-
readonly local: string;
|
|
110
|
-
readonly typeOnly: boolean;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
type ImportKindResolver = (
|
|
114
|
-
importSpecifier: NamedImportSpecifier
|
|
115
|
-
) => ExportKind | undefined;
|
|
116
|
-
|
|
117
94
|
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
118
95
|
Boolean(value && typeof value === 'object' && !Array.isArray(value));
|
|
119
96
|
|
|
120
97
|
const targetIdPattern = /^[a-z][a-z0-9-]*$/u;
|
|
121
98
|
const exportIdentifierPattern = /^[A-Za-z_$][\w$]*$/u;
|
|
122
99
|
|
|
123
|
-
const exportKindHasType = (kind: ExportKind | undefined): boolean =>
|
|
124
|
-
kind === 'type' || kind === 'type-value';
|
|
125
|
-
|
|
126
|
-
const exportKindHasValue = (kind: ExportKind | undefined): boolean =>
|
|
127
|
-
kind === 'value' || kind === 'type-value';
|
|
128
|
-
|
|
129
100
|
const normalizePath = (path: string): string => path.replaceAll('\\', '/');
|
|
130
101
|
|
|
131
102
|
const normalizeRealPath = (path: string): string => {
|
|
@@ -144,264 +115,6 @@ const pathIsFile = (path: string): boolean => {
|
|
|
144
115
|
}
|
|
145
116
|
};
|
|
146
117
|
|
|
147
|
-
const localDeclarationKind = (
|
|
148
|
-
code: string,
|
|
149
|
-
identifier: string,
|
|
150
|
-
exportedOnly = false
|
|
151
|
-
): ExportKind | undefined => {
|
|
152
|
-
const escapedIdentifier = identifier.replaceAll(
|
|
153
|
-
/[.*+?^${}()|[\]\\]/gu,
|
|
154
|
-
'\\$&'
|
|
155
|
-
);
|
|
156
|
-
const exportPrefix = exportedOnly ? '\\bexport\\s+' : '\\b(?:export\\s+)?';
|
|
157
|
-
const valueDeclarationPattern = new RegExp(
|
|
158
|
-
`${exportPrefix}(?!declare\\s+)(?:(?:async\\s+)?function|const|let|var)\\s+${escapedIdentifier}\\b`,
|
|
159
|
-
'u'
|
|
160
|
-
);
|
|
161
|
-
if (valueDeclarationPattern.test(code)) {
|
|
162
|
-
return 'value';
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const typeValueDeclarationPattern = new RegExp(
|
|
166
|
-
`${exportPrefix}(?!declare\\s+)(?:abstract\\s+)?(?:class|enum)\\s+${escapedIdentifier}\\b`,
|
|
167
|
-
'u'
|
|
168
|
-
);
|
|
169
|
-
if (typeValueDeclarationPattern.test(code)) {
|
|
170
|
-
return 'type-value';
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const typeDeclarationPattern = new RegExp(
|
|
174
|
-
`${exportPrefix}(?:declare\\s+)?(?:interface|type)\\s+${escapedIdentifier}\\b`,
|
|
175
|
-
'u'
|
|
176
|
-
);
|
|
177
|
-
return typeDeclarationPattern.test(code) ? 'type' : undefined;
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
const maskDeadSourceText = (
|
|
181
|
-
source: string,
|
|
182
|
-
options: { strings: boolean }
|
|
183
|
-
): string => {
|
|
184
|
-
const output = [...source];
|
|
185
|
-
let index = 0;
|
|
186
|
-
|
|
187
|
-
const maskRange = (start: number, end: number): void => {
|
|
188
|
-
for (let cursor = start; cursor < end; cursor += 1) {
|
|
189
|
-
if (output[cursor] !== '\n') {
|
|
190
|
-
output[cursor] = ' ';
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
const skipQuoted = (quote: '"' | "'" | '`'): void => {
|
|
196
|
-
const start = index;
|
|
197
|
-
index += 1;
|
|
198
|
-
while (index < source.length) {
|
|
199
|
-
if (source[index] === '\\') {
|
|
200
|
-
index += 2;
|
|
201
|
-
continue;
|
|
202
|
-
}
|
|
203
|
-
if (source[index] === quote) {
|
|
204
|
-
index += 1;
|
|
205
|
-
break;
|
|
206
|
-
}
|
|
207
|
-
index += 1;
|
|
208
|
-
}
|
|
209
|
-
if (options.strings) {
|
|
210
|
-
maskRange(start, index);
|
|
211
|
-
}
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
while (index < source.length) {
|
|
215
|
-
if (source.startsWith('//', index)) {
|
|
216
|
-
const end = source.indexOf('\n', index + 2);
|
|
217
|
-
const stop = end === -1 ? source.length : end;
|
|
218
|
-
maskRange(index, stop);
|
|
219
|
-
index = stop;
|
|
220
|
-
continue;
|
|
221
|
-
}
|
|
222
|
-
if (source.startsWith('/*', index)) {
|
|
223
|
-
const end = source.indexOf('*/', index + 2);
|
|
224
|
-
const stop = end === -1 ? source.length : end + 2;
|
|
225
|
-
maskRange(index, stop);
|
|
226
|
-
index = stop;
|
|
227
|
-
continue;
|
|
228
|
-
}
|
|
229
|
-
const char = source[index];
|
|
230
|
-
if (char === '"' || char === "'" || char === '`') {
|
|
231
|
-
skipQuoted(char);
|
|
232
|
-
continue;
|
|
233
|
-
}
|
|
234
|
-
index += 1;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
return output.join('');
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
const defaultExportKind = (source: string): ExportKind | undefined => {
|
|
241
|
-
const code = maskDeadSourceText(source, { strings: true });
|
|
242
|
-
if (/\bexport\s+default\s+(?:async\s+)?function\*?\b/u.test(code)) {
|
|
243
|
-
return 'value';
|
|
244
|
-
}
|
|
245
|
-
if (/\bexport\s+default\s+(?:abstract\s+)?(?:class|enum)\b/u.test(code)) {
|
|
246
|
-
return 'type-value';
|
|
247
|
-
}
|
|
248
|
-
if (/\bexport\s+default\s+(?:interface|type)\b/u.test(code)) {
|
|
249
|
-
return 'type';
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
const expressionIdentifier =
|
|
253
|
-
/\bexport\s+default\s+(?<identifier>[A-Za-z_$][\w$]*)\b/u.exec(code)
|
|
254
|
-
?.groups?.['identifier'];
|
|
255
|
-
if (expressionIdentifier) {
|
|
256
|
-
return localDeclarationKind(code, expressionIdentifier) ?? 'value';
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
return /\bexport\s+default\b/u.test(code) ? 'value' : undefined;
|
|
260
|
-
};
|
|
261
|
-
|
|
262
|
-
const localDefaultImportSpecifier = (
|
|
263
|
-
code: string,
|
|
264
|
-
stringsMaskedCode: string,
|
|
265
|
-
identifier: string
|
|
266
|
-
): NamedImportSpecifier | undefined => {
|
|
267
|
-
const pattern =
|
|
268
|
-
/\bimport\s+(?<importTypeOnly>type\s+)?(?<local>[A-Za-z_$][\w$]*)(?:\s*,\s*(?:\{[\s\S]*?\}|\*\s+as\s+[A-Za-z_$][\w$]*))?\s+from\s+['"](?<specifier>[^'"]+)['"]/gu;
|
|
269
|
-
|
|
270
|
-
for (const match of code.matchAll(pattern)) {
|
|
271
|
-
if (!stringsMaskedCode.startsWith('import', match.index ?? 0)) {
|
|
272
|
-
continue;
|
|
273
|
-
}
|
|
274
|
-
if (match.groups?.['local'] !== identifier) {
|
|
275
|
-
continue;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
return {
|
|
279
|
-
identifier: 'default',
|
|
280
|
-
specifier: match.groups?.['specifier'] ?? '',
|
|
281
|
-
typeOnly: Boolean(match.groups?.['importTypeOnly']),
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
return undefined;
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
const parseNamedImportSpecifier = (
|
|
289
|
-
item: string,
|
|
290
|
-
declarationTypeOnly: boolean,
|
|
291
|
-
specifier: string,
|
|
292
|
-
identifier: string
|
|
293
|
-
): NamedImportSpecifier | undefined => {
|
|
294
|
-
const trimmedItem = item.trim();
|
|
295
|
-
if (!trimmedItem) {
|
|
296
|
-
return undefined;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
const itemTypeOnly = declarationTypeOnly || trimmedItem.startsWith('type ');
|
|
300
|
-
const specifierText = trimmedItem.replace(/^type\s+/u, '');
|
|
301
|
-
const imported =
|
|
302
|
-
/^(?<imported>[A-Za-z_$][\w$]*)(?:\s+as\s+(?<local>[A-Za-z_$][\w$]*))?$/u.exec(
|
|
303
|
-
specifierText
|
|
304
|
-
)?.groups;
|
|
305
|
-
const local = imported?.['local'] ?? imported?.['imported'];
|
|
306
|
-
const importedName = imported?.['imported'];
|
|
307
|
-
if (local !== identifier || !importedName) {
|
|
308
|
-
return undefined;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
return {
|
|
312
|
-
identifier: importedName,
|
|
313
|
-
specifier,
|
|
314
|
-
typeOnly: itemTypeOnly,
|
|
315
|
-
};
|
|
316
|
-
};
|
|
317
|
-
|
|
318
|
-
const localNamedImportSpecifier = (
|
|
319
|
-
source: string,
|
|
320
|
-
identifier: string
|
|
321
|
-
): NamedImportSpecifier | undefined => {
|
|
322
|
-
const code = maskDeadSourceText(source, { strings: false });
|
|
323
|
-
const stringsMaskedCode = maskDeadSourceText(source, { strings: true });
|
|
324
|
-
const defaultSpecifier = localDefaultImportSpecifier(
|
|
325
|
-
code,
|
|
326
|
-
stringsMaskedCode,
|
|
327
|
-
identifier
|
|
328
|
-
);
|
|
329
|
-
if (defaultSpecifier) {
|
|
330
|
-
return defaultSpecifier;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
const pattern =
|
|
334
|
-
/\bimport\s+(?<importTypeOnly>type\s+)?\{(?<imports>[\s\S]*?)\}\s+from\s+['"](?<specifier>[^'"]+)['"]/gu;
|
|
335
|
-
|
|
336
|
-
for (const match of code.matchAll(pattern)) {
|
|
337
|
-
if (!stringsMaskedCode.startsWith('import', match.index ?? 0)) {
|
|
338
|
-
continue;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
const declarationTypeOnly = Boolean(match.groups?.['importTypeOnly']);
|
|
342
|
-
const namedImports = match.groups?.['imports'] ?? '';
|
|
343
|
-
const specifier = match.groups?.['specifier'] ?? '';
|
|
344
|
-
for (const item of namedImports.split(',')) {
|
|
345
|
-
const namedSpecifier = parseNamedImportSpecifier(
|
|
346
|
-
item,
|
|
347
|
-
declarationTypeOnly,
|
|
348
|
-
specifier,
|
|
349
|
-
identifier
|
|
350
|
-
);
|
|
351
|
-
if (namedSpecifier) {
|
|
352
|
-
return namedSpecifier;
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
return undefined;
|
|
358
|
-
};
|
|
359
|
-
|
|
360
|
-
const parseExportListSpecifier = (
|
|
361
|
-
item: string,
|
|
362
|
-
declarationTypeOnly: boolean
|
|
363
|
-
): ExportListSpecifier | undefined => {
|
|
364
|
-
const trimmedItem = item.trim();
|
|
365
|
-
if (!trimmedItem) {
|
|
366
|
-
return undefined;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
const typeOnly = declarationTypeOnly || trimmedItem.startsWith('type ');
|
|
370
|
-
const specifierText = trimmedItem.replace(/^type\s+/u, '');
|
|
371
|
-
const exported =
|
|
372
|
-
/^(?<local>[A-Za-z_$][\w$]*)(?:\s+as\s+(?<name>[A-Za-z_$][\w$]*))?$/u.exec(
|
|
373
|
-
specifierText
|
|
374
|
-
)?.groups;
|
|
375
|
-
const local = exported?.['local'];
|
|
376
|
-
if (!local) {
|
|
377
|
-
return undefined;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
return {
|
|
381
|
-
exported: exported?.['name'] ?? local,
|
|
382
|
-
local,
|
|
383
|
-
typeOnly,
|
|
384
|
-
};
|
|
385
|
-
};
|
|
386
|
-
|
|
387
|
-
const exportedLocalBindingKind = (
|
|
388
|
-
source: string,
|
|
389
|
-
code: string,
|
|
390
|
-
local: string,
|
|
391
|
-
resolveImportKind: ImportKindResolver
|
|
392
|
-
): ExportKind | undefined => {
|
|
393
|
-
const localKind = localDeclarationKind(code, local);
|
|
394
|
-
if (localKind) {
|
|
395
|
-
return localKind;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
const importSpecifier = localNamedImportSpecifier(source, local);
|
|
399
|
-
if (importSpecifier?.typeOnly) {
|
|
400
|
-
return 'type';
|
|
401
|
-
}
|
|
402
|
-
return importSpecifier ? resolveImportKind(importSpecifier) : undefined;
|
|
403
|
-
};
|
|
404
|
-
|
|
405
118
|
const exportConditions = new Set([
|
|
406
119
|
'bun',
|
|
407
120
|
'node',
|
|
@@ -870,228 +583,6 @@ const normalizeConformance = (
|
|
|
870
583
|
};
|
|
871
584
|
};
|
|
872
585
|
|
|
873
|
-
const namedExportKind = (
|
|
874
|
-
source: string,
|
|
875
|
-
identifier: string,
|
|
876
|
-
resolveImportKind: ImportKindResolver
|
|
877
|
-
): ExportKind | undefined => {
|
|
878
|
-
if (identifier === 'default') {
|
|
879
|
-
const defaultKind = defaultExportKind(source);
|
|
880
|
-
if (defaultKind) {
|
|
881
|
-
return defaultKind;
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
const code = maskDeadSourceText(source, { strings: true });
|
|
886
|
-
const directKind = localDeclarationKind(code, identifier, true);
|
|
887
|
-
if (directKind) {
|
|
888
|
-
return directKind;
|
|
889
|
-
}
|
|
890
|
-
|
|
891
|
-
const exportListPattern =
|
|
892
|
-
/\bexport\s+(?<typeOnly>type\s+)?\{(?<exports>[\s\S]*?)\}(?!\s+from\b)/gu;
|
|
893
|
-
|
|
894
|
-
for (const match of code.matchAll(exportListPattern)) {
|
|
895
|
-
const declarationTypeOnly = Boolean(match.groups?.['typeOnly']);
|
|
896
|
-
const namedExports = match.groups?.['exports'] ?? '';
|
|
897
|
-
for (const item of namedExports.split(',')) {
|
|
898
|
-
const exported = parseExportListSpecifier(item, declarationTypeOnly);
|
|
899
|
-
if (exported?.exported !== identifier) {
|
|
900
|
-
continue;
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
const localKind = exportedLocalBindingKind(
|
|
904
|
-
source,
|
|
905
|
-
code,
|
|
906
|
-
exported.local,
|
|
907
|
-
resolveImportKind
|
|
908
|
-
);
|
|
909
|
-
if (!localKind) {
|
|
910
|
-
return undefined;
|
|
911
|
-
}
|
|
912
|
-
return exported.typeOnly ? 'type' : localKind;
|
|
913
|
-
}
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
return undefined;
|
|
917
|
-
};
|
|
918
|
-
|
|
919
|
-
const starExportSpecifiers = (
|
|
920
|
-
source: string
|
|
921
|
-
): readonly StarExportSpecifier[] => {
|
|
922
|
-
const code = maskDeadSourceText(source, { strings: false });
|
|
923
|
-
const stringsMaskedCode = maskDeadSourceText(source, { strings: true });
|
|
924
|
-
return [
|
|
925
|
-
...code.matchAll(
|
|
926
|
-
/\bexport\s+(?<typeOnly>type\s+)?\*\s+from\s+['"](?<specifier>[^'"]+)['"]/gu
|
|
927
|
-
),
|
|
928
|
-
]
|
|
929
|
-
.filter((match) => stringsMaskedCode.startsWith('export', match.index ?? 0))
|
|
930
|
-
.map((match) => ({
|
|
931
|
-
specifier: match.groups?.['specifier'] ?? '',
|
|
932
|
-
typeOnly: Boolean(match.groups?.['typeOnly']),
|
|
933
|
-
}));
|
|
934
|
-
};
|
|
935
|
-
|
|
936
|
-
const namedExportSpecifiers = (
|
|
937
|
-
source: string,
|
|
938
|
-
identifier: string
|
|
939
|
-
): readonly NamedExportSpecifier[] => {
|
|
940
|
-
const code = maskDeadSourceText(source, { strings: false });
|
|
941
|
-
const stringsMaskedCode = maskDeadSourceText(source, { strings: true });
|
|
942
|
-
const exports: NamedExportSpecifier[] = [];
|
|
943
|
-
const pattern =
|
|
944
|
-
/\bexport\s+(?<typeOnly>type\s+)?\{(?<exports>[\s\S]*?)\}\s+from\s+['"](?<specifier>[^'"]+)['"]/gu;
|
|
945
|
-
|
|
946
|
-
for (const match of code.matchAll(pattern)) {
|
|
947
|
-
if (!stringsMaskedCode.startsWith('export', match.index ?? 0)) {
|
|
948
|
-
continue;
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
const specifier = match.groups?.['specifier'];
|
|
952
|
-
if (!specifier?.startsWith('.')) {
|
|
953
|
-
continue;
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
const declarationTypeOnly = Boolean(match.groups?.['typeOnly']);
|
|
957
|
-
const namedExports = match.groups?.['exports'] ?? '';
|
|
958
|
-
for (const item of namedExports.split(',')) {
|
|
959
|
-
const trimmedItem = item.trim();
|
|
960
|
-
if (!trimmedItem) {
|
|
961
|
-
continue;
|
|
962
|
-
}
|
|
963
|
-
|
|
964
|
-
const itemTypeOnly =
|
|
965
|
-
declarationTypeOnly || trimmedItem.startsWith('type ');
|
|
966
|
-
const specifierText = trimmedItem.replace(/^type\s+/u, '');
|
|
967
|
-
const exported =
|
|
968
|
-
/^(?<local>[A-Za-z_$][\w$]*)(?:\s+as\s+(?<name>[A-Za-z_$][\w$]*))?$/u.exec(
|
|
969
|
-
specifierText
|
|
970
|
-
)?.groups;
|
|
971
|
-
const local = exported?.['local'];
|
|
972
|
-
if (!local || (exported?.['name'] ?? local) !== identifier) {
|
|
973
|
-
continue;
|
|
974
|
-
}
|
|
975
|
-
|
|
976
|
-
exports.push({
|
|
977
|
-
identifier: local,
|
|
978
|
-
specifier,
|
|
979
|
-
typeOnly: itemTypeOnly,
|
|
980
|
-
});
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
|
|
984
|
-
return exports;
|
|
985
|
-
};
|
|
986
|
-
|
|
987
|
-
const resolveLocalModuleSpecifier = (
|
|
988
|
-
sourcePath: string,
|
|
989
|
-
specifier: string
|
|
990
|
-
): string | undefined => {
|
|
991
|
-
if (!specifier.startsWith('.')) {
|
|
992
|
-
return undefined;
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
const basePath = resolve(dirname(sourcePath), specifier);
|
|
996
|
-
const candidates = [
|
|
997
|
-
basePath,
|
|
998
|
-
basePath.endsWith('.js') ? `${basePath.slice(0, -3)}.ts` : undefined,
|
|
999
|
-
basePath.endsWith('.js') ? `${basePath.slice(0, -3)}.tsx` : undefined,
|
|
1000
|
-
basePath.endsWith('.mjs') ? `${basePath.slice(0, -4)}.mts` : undefined,
|
|
1001
|
-
`${basePath}.ts`,
|
|
1002
|
-
`${basePath}.tsx`,
|
|
1003
|
-
join(basePath, 'index.ts'),
|
|
1004
|
-
join(basePath, 'index.tsx'),
|
|
1005
|
-
].filter((candidate): candidate is string => candidate !== undefined);
|
|
1006
|
-
|
|
1007
|
-
return candidates.find((candidate) => existsSync(candidate));
|
|
1008
|
-
};
|
|
1009
|
-
|
|
1010
|
-
const namedExportKindFromFile = (
|
|
1011
|
-
sourcePath: string,
|
|
1012
|
-
identifier: string,
|
|
1013
|
-
visited = new Set<string>()
|
|
1014
|
-
): ExportKind | undefined => {
|
|
1015
|
-
const normalizedSourcePath = normalizeRealPath(sourcePath);
|
|
1016
|
-
const visitKey = `${normalizedSourcePath}:${identifier}`;
|
|
1017
|
-
if (visited.has(visitKey)) {
|
|
1018
|
-
return undefined;
|
|
1019
|
-
}
|
|
1020
|
-
visited.add(visitKey);
|
|
1021
|
-
|
|
1022
|
-
let source: string;
|
|
1023
|
-
try {
|
|
1024
|
-
source = readFileSync(normalizedSourcePath, 'utf8');
|
|
1025
|
-
} catch {
|
|
1026
|
-
return undefined;
|
|
1027
|
-
}
|
|
1028
|
-
|
|
1029
|
-
const directKind = namedExportKind(source, identifier, (importSpecifier) => {
|
|
1030
|
-
const importTarget = resolveLocalModuleSpecifier(
|
|
1031
|
-
normalizedSourcePath,
|
|
1032
|
-
importSpecifier.specifier
|
|
1033
|
-
);
|
|
1034
|
-
if (!importTarget) {
|
|
1035
|
-
return;
|
|
1036
|
-
}
|
|
1037
|
-
return namedExportKindFromFile(
|
|
1038
|
-
importTarget,
|
|
1039
|
-
importSpecifier.identifier,
|
|
1040
|
-
new Set(visited)
|
|
1041
|
-
);
|
|
1042
|
-
});
|
|
1043
|
-
if (directKind) {
|
|
1044
|
-
return directKind;
|
|
1045
|
-
}
|
|
1046
|
-
|
|
1047
|
-
let sawTypeExport = false;
|
|
1048
|
-
for (const exportSpecifier of namedExportSpecifiers(source, identifier)) {
|
|
1049
|
-
const exportTarget = resolveLocalModuleSpecifier(
|
|
1050
|
-
normalizedSourcePath,
|
|
1051
|
-
exportSpecifier.specifier
|
|
1052
|
-
);
|
|
1053
|
-
if (!exportTarget) {
|
|
1054
|
-
continue;
|
|
1055
|
-
}
|
|
1056
|
-
|
|
1057
|
-
const reexportedKind = namedExportKindFromFile(
|
|
1058
|
-
exportTarget,
|
|
1059
|
-
exportSpecifier.identifier,
|
|
1060
|
-
new Set(visited)
|
|
1061
|
-
);
|
|
1062
|
-
if (exportKindHasValue(reexportedKind) && !exportSpecifier.typeOnly) {
|
|
1063
|
-
return reexportedKind;
|
|
1064
|
-
}
|
|
1065
|
-
if (exportKindHasType(reexportedKind)) {
|
|
1066
|
-
sawTypeExport = true;
|
|
1067
|
-
}
|
|
1068
|
-
}
|
|
1069
|
-
|
|
1070
|
-
for (const exportSpecifier of starExportSpecifiers(source)) {
|
|
1071
|
-
const exportTarget = resolveLocalModuleSpecifier(
|
|
1072
|
-
normalizedSourcePath,
|
|
1073
|
-
exportSpecifier.specifier
|
|
1074
|
-
);
|
|
1075
|
-
if (!exportTarget) {
|
|
1076
|
-
continue;
|
|
1077
|
-
}
|
|
1078
|
-
|
|
1079
|
-
const reexportedKind = namedExportKindFromFile(
|
|
1080
|
-
exportTarget,
|
|
1081
|
-
identifier,
|
|
1082
|
-
new Set(visited)
|
|
1083
|
-
);
|
|
1084
|
-
if (exportKindHasValue(reexportedKind) && !exportSpecifier.typeOnly) {
|
|
1085
|
-
return reexportedKind;
|
|
1086
|
-
}
|
|
1087
|
-
if (exportKindHasType(reexportedKind)) {
|
|
1088
|
-
sawTypeExport = true;
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
|
-
|
|
1092
|
-
return sawTypeExport ? 'type' : undefined;
|
|
1093
|
-
};
|
|
1094
|
-
|
|
1095
586
|
const conformanceExportDiagnostics = (
|
|
1096
587
|
context: AdapterTargetParseContext,
|
|
1097
588
|
target: string,
|
|
@@ -1114,11 +605,14 @@ const conformanceExportDiagnostics = (
|
|
|
1114
605
|
keyof AdapterTargetConformanceManifest,
|
|
1115
606
|
string,
|
|
1116
607
|
][]) {
|
|
1117
|
-
const exportKind =
|
|
1118
|
-
if (field === 'adapterType' &&
|
|
608
|
+
const exportKind = adapterSourceExportKind(testingExportTarget, identifier);
|
|
609
|
+
if (field === 'adapterType' && adapterSourceExportKindHasType(exportKind)) {
|
|
1119
610
|
continue;
|
|
1120
611
|
}
|
|
1121
|
-
if (
|
|
612
|
+
if (
|
|
613
|
+
field !== 'adapterType' &&
|
|
614
|
+
adapterSourceExportKindHasValue(exportKind)
|
|
615
|
+
) {
|
|
1122
616
|
continue;
|
|
1123
617
|
}
|
|
1124
618
|
const expectedExport =
|