tsrx-typegen 0.2.0 → 0.2.1
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 +9 -9
- package/package.json +8 -8
- package/src/cli.mjs +193 -62
- package/src/pack-check.mjs +6 -3
package/README.md
CHANGED
|
@@ -56,7 +56,7 @@ select a named target directly. A target can look like this:
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
-
|
|
59
|
+
}
|
|
60
60
|
}
|
|
61
61
|
```
|
|
62
62
|
|
|
@@ -65,9 +65,9 @@ generated directory, then map their generated output path explicitly:
|
|
|
65
65
|
|
|
66
66
|
```json
|
|
67
67
|
{
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
"overrides": {
|
|
69
|
+
"Button.d.ts": "types/overrides/Button.d.ts"
|
|
70
|
+
}
|
|
71
71
|
}
|
|
72
72
|
```
|
|
73
73
|
|
|
@@ -113,11 +113,11 @@ Run the same gate from `prepack` so `pnpm pack` and publication share it:
|
|
|
113
113
|
|
|
114
114
|
```json
|
|
115
115
|
{
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
116
|
+
"scripts": {
|
|
117
|
+
"typegen": "tsrx-typegen --target octane",
|
|
118
|
+
"build": "vite build && pnpm typegen",
|
|
119
|
+
"prepack": "pnpm build && tsrx-typegen --pack-check"
|
|
120
|
+
}
|
|
121
121
|
}
|
|
122
122
|
```
|
|
123
123
|
|
package/package.json
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tsrx-typegen",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Generate consumer-ready TypeScript declarations for TSRX libraries",
|
|
5
5
|
"keywords": [
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"typescript",
|
|
6
|
+
"build-tool",
|
|
7
|
+
"codegen",
|
|
9
8
|
"declarations",
|
|
10
9
|
"dts",
|
|
11
|
-
"
|
|
12
|
-
"
|
|
10
|
+
"tsrx",
|
|
11
|
+
"typegen",
|
|
12
|
+
"typescript"
|
|
13
13
|
],
|
|
14
|
-
"license": "MIT",
|
|
15
14
|
"homepage": "https://github.com/octane-xplat/octane-xplat/tree/main/packages/tsrx-typegen",
|
|
15
|
+
"license": "MIT",
|
|
16
16
|
"repository": {
|
|
17
17
|
"type": "git",
|
|
18
|
-
"url": "
|
|
18
|
+
"url": "https://github.com/octane-xplat/octane-xplat",
|
|
19
19
|
"directory": "packages/tsrx-typegen"
|
|
20
20
|
},
|
|
21
21
|
"bin": {
|
package/src/cli.mjs
CHANGED
|
@@ -92,7 +92,12 @@ function configuredTargetNames(projectRoot, selectedTarget) {
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
const targets = config?.targets
|
|
95
|
-
if (
|
|
95
|
+
if (
|
|
96
|
+
!targets ||
|
|
97
|
+
typeof targets !== 'object' ||
|
|
98
|
+
Array.isArray(targets) ||
|
|
99
|
+
!Object.keys(targets).length
|
|
100
|
+
) {
|
|
96
101
|
throw new Error(`${path}: --pack-check requires at least one configured target`)
|
|
97
102
|
}
|
|
98
103
|
|
|
@@ -124,16 +129,24 @@ function readProjectConfig(ts, configPath, projectRoot, target) {
|
|
|
124
129
|
[{ extension: '.tsrx', isMixedContent: true, scriptKind: ts.ScriptKind.Deferred }],
|
|
125
130
|
)
|
|
126
131
|
|
|
127
|
-
if (!parsed) {
|
|
132
|
+
if (!parsed) {
|
|
133
|
+
throw new Error(`Could not read ${configPath}`)
|
|
134
|
+
}
|
|
135
|
+
|
|
128
136
|
const errors = parsed.errors.map((diagnostic) =>
|
|
129
137
|
ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'),
|
|
130
138
|
)
|
|
131
139
|
|
|
132
|
-
if (errors.length) {
|
|
140
|
+
if (errors.length) {
|
|
141
|
+
throw new Error(errors.join('\n'))
|
|
142
|
+
}
|
|
143
|
+
|
|
133
144
|
const options = parsed.options
|
|
134
145
|
const jsxRenderer =
|
|
135
146
|
options.jsxImportSource ??
|
|
136
|
-
(options.jsx === ts.JsxEmit.ReactJSX || options.jsx === ts.JsxEmit.ReactJSXDev
|
|
147
|
+
(options.jsx === ts.JsxEmit.ReactJSX || options.jsx === ts.JsxEmit.ReactJSXDev
|
|
148
|
+
? 'react'
|
|
149
|
+
: undefined)
|
|
137
150
|
|
|
138
151
|
if (target?.renderer && jsxRenderer && target.renderer !== jsxRenderer) {
|
|
139
152
|
throw new Error(
|
|
@@ -149,7 +162,9 @@ function readProjectConfig(ts, configPath, projectRoot, target) {
|
|
|
149
162
|
|
|
150
163
|
const outputDirectory = target?.outDir ?? options.declarationDir ?? options.outDir
|
|
151
164
|
if (!outputDirectory) {
|
|
152
|
-
throw new Error(
|
|
165
|
+
throw new Error(
|
|
166
|
+
`${configPath} must set target outDir, compilerOptions.outDir, or declarationDir.`,
|
|
167
|
+
)
|
|
153
168
|
}
|
|
154
169
|
|
|
155
170
|
return {
|
|
@@ -163,7 +178,10 @@ function readProjectConfig(ts, configPath, projectRoot, target) {
|
|
|
163
178
|
}
|
|
164
179
|
|
|
165
180
|
function commonDirectory(paths) {
|
|
166
|
-
if (!paths.length) {
|
|
181
|
+
if (!paths.length) {
|
|
182
|
+
throw new Error('TypeScript project has no root files.')
|
|
183
|
+
}
|
|
184
|
+
|
|
167
185
|
const segments = paths.map((path) => resolve(dirname(path)).split(sep))
|
|
168
186
|
const common = []
|
|
169
187
|
for (let index = 0; segments.every((parts) => parts[index] === segments[0][index]); index += 1) {
|
|
@@ -178,7 +196,10 @@ function sourceDeclarationMap(rootDir, fileNames, extensions, overrides) {
|
|
|
178
196
|
const runtimeByDeclaration = new Map()
|
|
179
197
|
for (const source of fileNames) {
|
|
180
198
|
const sourceExtension = extname(source).toLowerCase()
|
|
181
|
-
if (!Object.hasOwn(extensions, sourceExtension) || /\.d\.[cm]?ts$/i.test(source)) {
|
|
199
|
+
if (!Object.hasOwn(extensions, sourceExtension) || /\.d\.[cm]?ts$/i.test(source)) {
|
|
200
|
+
continue
|
|
201
|
+
}
|
|
202
|
+
|
|
182
203
|
const sourcePath = relative(rootDir, source)
|
|
183
204
|
if (!sourcePath || sourcePath.startsWith(`..${sep}`) || isAbsolute(sourcePath)) {
|
|
184
205
|
throw new Error(`Source file is outside compilerOptions.rootDir: ${source}`)
|
|
@@ -187,7 +208,10 @@ function sourceDeclarationMap(rootDir, fileNames, extensions, overrides) {
|
|
|
187
208
|
const declarationExtension =
|
|
188
209
|
sourceExtension === '.mts' ? '.d.mts' : sourceExtension === '.cts' ? '.d.cts' : '.d.ts'
|
|
189
210
|
|
|
190
|
-
const declaration = normalize(
|
|
211
|
+
const declaration = normalize(
|
|
212
|
+
sourcePath.slice(0, -sourceExtension.length) + declarationExtension,
|
|
213
|
+
)
|
|
214
|
+
|
|
191
215
|
const prior = sourceOutputs.get(declaration)
|
|
192
216
|
if (prior && !overrides.has(declaration)) {
|
|
193
217
|
throw new Error(
|
|
@@ -211,7 +235,10 @@ function configOptions(projectRoot, projectArgument, targetArgument) {
|
|
|
211
235
|
config = JSON.parse(readFileSync(path, 'utf8'))
|
|
212
236
|
} catch (error) {
|
|
213
237
|
if (error.code === 'ENOENT') {
|
|
214
|
-
if (targetArgument) {
|
|
238
|
+
if (targetArgument) {
|
|
239
|
+
throw new Error(`No tsrx-typegen.json defines target ${targetArgument}.`)
|
|
240
|
+
}
|
|
241
|
+
|
|
215
242
|
return {
|
|
216
243
|
project: projectArgument,
|
|
217
244
|
target: null,
|
|
@@ -235,7 +262,10 @@ function configOptions(projectRoot, projectArgument, targetArgument) {
|
|
|
235
262
|
const resolveProject = (value) => resolve(projectRoot, value)
|
|
236
263
|
let selectedName = targetArgument
|
|
237
264
|
let selected = selectedName ? targets[selectedName] : undefined
|
|
238
|
-
if (selectedName && !selected) {
|
|
265
|
+
if (selectedName && !selected) {
|
|
266
|
+
throw new Error(`${path}: unknown target ${selectedName}`)
|
|
267
|
+
}
|
|
268
|
+
|
|
239
269
|
if (!selected && projectArgument) {
|
|
240
270
|
const matches = Object.entries(targets).filter(
|
|
241
271
|
([, target]) => target?.project && resolveProject(target.project) === projectArgument,
|
|
@@ -245,15 +275,18 @@ function configOptions(projectRoot, projectArgument, targetArgument) {
|
|
|
245
275
|
throw new Error(`${path}: project matches multiple targets; pass --target <name>`)
|
|
246
276
|
}
|
|
247
277
|
|
|
248
|
-
if (matches.length === 1) {
|
|
249
|
-
|
|
278
|
+
if (matches.length === 1) {
|
|
279
|
+
;[selectedName, selected] = matches[0]
|
|
280
|
+
} else if (Object.keys(targets).length) {
|
|
250
281
|
throw new Error(`${path}: ${projectArgument} is not declared by a target`)
|
|
251
282
|
}
|
|
252
283
|
}
|
|
253
284
|
|
|
254
285
|
if (selected) {
|
|
255
286
|
if (selected.emit === false) {
|
|
256
|
-
throw new Error(
|
|
287
|
+
throw new Error(
|
|
288
|
+
`${path}: target ${selectedName} has emit: false — it configures --pack-check only`,
|
|
289
|
+
)
|
|
257
290
|
}
|
|
258
291
|
|
|
259
292
|
if (typeof selected.project !== 'string' || !selected.project) {
|
|
@@ -282,10 +315,12 @@ function configOptions(projectRoot, projectArgument, targetArgument) {
|
|
|
282
315
|
!entry ||
|
|
283
316
|
typeof entry !== 'object' ||
|
|
284
317
|
typeof entry.source !== 'string' ||
|
|
285
|
-
|
|
318
|
+
!stringsIn(entry.runtime).length ||
|
|
286
319
|
!stringsIn(entry.types).length
|
|
287
320
|
) {
|
|
288
|
-
throw new Error(
|
|
321
|
+
throw new Error(
|
|
322
|
+
`${path}: target ${selectedName} entrypoint ${subpath} needs source, runtime, and types`,
|
|
323
|
+
)
|
|
289
324
|
}
|
|
290
325
|
|
|
291
326
|
for (const publishedPath of [...stringsIn(entry.runtime), ...stringsIn(entry.types)]) {
|
|
@@ -304,7 +339,9 @@ function configOptions(projectRoot, projectArgument, targetArgument) {
|
|
|
304
339
|
} catch {}
|
|
305
340
|
|
|
306
341
|
if (!pathInside(projectRoot, source) || !isFile) {
|
|
307
|
-
throw new Error(
|
|
342
|
+
throw new Error(
|
|
343
|
+
`${path}: target ${selectedName} entrypoint source is missing: ${entry.source}`,
|
|
344
|
+
)
|
|
308
345
|
}
|
|
309
346
|
}
|
|
310
347
|
|
|
@@ -325,10 +362,17 @@ function configOptions(projectRoot, projectArgument, targetArgument) {
|
|
|
325
362
|
}
|
|
326
363
|
|
|
327
364
|
const project = projectArgument ?? resolveProject(selected.project)
|
|
328
|
-
const sourceExtensions = {
|
|
365
|
+
const sourceExtensions = {
|
|
366
|
+
...defaultExtensions,
|
|
367
|
+
...config.sourceExtensions,
|
|
368
|
+
...selected?.sourceExtensions,
|
|
369
|
+
}
|
|
370
|
+
|
|
329
371
|
for (const [source, runtime] of Object.entries(sourceExtensions)) {
|
|
330
372
|
if (!source.startsWith('.') || typeof runtime !== 'string' || !runtime.startsWith('.')) {
|
|
331
|
-
throw new Error(
|
|
373
|
+
throw new Error(
|
|
374
|
+
`${path}: sourceExtensions must map dot-prefixed extensions to dot-prefixed runtime extensions`,
|
|
375
|
+
)
|
|
332
376
|
}
|
|
333
377
|
}
|
|
334
378
|
|
|
@@ -378,7 +422,10 @@ function applyOverrides(ts, projectRoot, outputDir, generated, overrides) {
|
|
|
378
422
|
normalized.set(outputFile, content)
|
|
379
423
|
}
|
|
380
424
|
|
|
381
|
-
for (const [outputPath, content] of normalized) {
|
|
425
|
+
for (const [outputPath, content] of normalized) {
|
|
426
|
+
generated.set(outputPath, content)
|
|
427
|
+
}
|
|
428
|
+
|
|
382
429
|
return new Set(normalized.keys())
|
|
383
430
|
}
|
|
384
431
|
|
|
@@ -390,8 +437,11 @@ function collectFiles(root, output = []) {
|
|
|
390
437
|
|
|
391
438
|
for (const entry of readdirSync(root, { withFileTypes: true })) {
|
|
392
439
|
const path = join(root, entry.name)
|
|
393
|
-
if (entry.isDirectory()) {
|
|
394
|
-
|
|
440
|
+
if (entry.isDirectory()) {
|
|
441
|
+
collectFiles(path, output)
|
|
442
|
+
} else if (entry.isFile()) {
|
|
443
|
+
output.push(path)
|
|
444
|
+
}
|
|
395
445
|
}
|
|
396
446
|
|
|
397
447
|
return output
|
|
@@ -428,7 +478,10 @@ function moduleSpecifierNodes(ts, sourceFile) {
|
|
|
428
478
|
|
|
429
479
|
function assertNoTsrxModuleReferences(ts, path, text) {
|
|
430
480
|
const source = ts.createSourceFile(path, text, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS)
|
|
431
|
-
const unresolved = moduleSpecifierNodes(ts, source).find((node) =>
|
|
481
|
+
const unresolved = moduleSpecifierNodes(ts, source).find((node) =>
|
|
482
|
+
/\.tsrx(?:$|[?#])/.test(node.text),
|
|
483
|
+
)
|
|
484
|
+
|
|
432
485
|
if (unresolved) {
|
|
433
486
|
throw new Error(`${path}: unresolved .tsrx module specifier ${unresolved.text}`)
|
|
434
487
|
}
|
|
@@ -440,8 +493,14 @@ function rewriteDeclaration(ts, path, outputDir, extensions, generatedFiles, run
|
|
|
440
493
|
const edits = []
|
|
441
494
|
for (const node of moduleSpecifierNodes(ts, source)) {
|
|
442
495
|
const specifier = node.text
|
|
443
|
-
if (!specifier.startsWith('.')) {
|
|
444
|
-
|
|
496
|
+
if (!specifier.startsWith('.')) {
|
|
497
|
+
continue
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
if (/\.d\.[cm]?ts$/i.test(specifier)) {
|
|
501
|
+
continue
|
|
502
|
+
}
|
|
503
|
+
|
|
445
504
|
const extension = Object.keys(extensions).find(
|
|
446
505
|
(candidate) => !candidate.startsWith('.d.') && specifier.endsWith(candidate),
|
|
447
506
|
)
|
|
@@ -464,7 +523,10 @@ function rewriteDeclaration(ts, path, outputDir, extensions, generatedFiles, run
|
|
|
464
523
|
generatedFiles.has(relative(outputDir, candidate)),
|
|
465
524
|
)
|
|
466
525
|
|
|
467
|
-
if (!target) {
|
|
526
|
+
if (!target) {
|
|
527
|
+
continue
|
|
528
|
+
}
|
|
529
|
+
|
|
468
530
|
const declaration = relative(outputDir, target)
|
|
469
531
|
const runtimeExtension = runtimeByDeclaration.get(declaration) ?? '.js'
|
|
470
532
|
const isIndex = /[\\/]index\.d\.[cm]?ts$/.test(target)
|
|
@@ -498,19 +560,15 @@ function normalizeOutput(ts, outputDir, extensions, runtimeByDeclaration) {
|
|
|
498
560
|
.filter((path) => /\.d\.[cm]?ts$/.test(path))
|
|
499
561
|
.sort()
|
|
500
562
|
|
|
501
|
-
if (!files.length) {
|
|
563
|
+
if (!files.length) {
|
|
564
|
+
throw new Error('TypeScript emitted no declaration files.')
|
|
565
|
+
}
|
|
566
|
+
|
|
502
567
|
const generatedFiles = new Set(files.map((path) => relative(outputDir, path)))
|
|
503
568
|
return new Map(
|
|
504
569
|
files.map((path) => [
|
|
505
570
|
relative(outputDir, path),
|
|
506
|
-
rewriteDeclaration(
|
|
507
|
-
ts,
|
|
508
|
-
path,
|
|
509
|
-
outputDir,
|
|
510
|
-
extensions,
|
|
511
|
-
generatedFiles,
|
|
512
|
-
runtimeByDeclaration,
|
|
513
|
-
),
|
|
571
|
+
rewriteDeclaration(ts, path, outputDir, extensions, generatedFiles, runtimeByDeclaration),
|
|
514
572
|
]),
|
|
515
573
|
)
|
|
516
574
|
}
|
|
@@ -532,7 +590,10 @@ function previousManifest(outputDir) {
|
|
|
532
590
|
|
|
533
591
|
return new Set(manifest.files)
|
|
534
592
|
} catch (error) {
|
|
535
|
-
if (error.code === 'ENOENT') {
|
|
593
|
+
if (error.code === 'ENOENT') {
|
|
594
|
+
return null
|
|
595
|
+
}
|
|
596
|
+
|
|
536
597
|
throw new Error(`${path}: ${error.message}`)
|
|
537
598
|
}
|
|
538
599
|
}
|
|
@@ -549,19 +610,29 @@ function pathInside(root, file) {
|
|
|
549
610
|
|
|
550
611
|
function writeOutput(outputDir, generated, oldFiles, overrideFiles) {
|
|
551
612
|
for (const file of generated.keys()) {
|
|
552
|
-
if (oldFiles?.has(file) || overrideFiles.has(file)) {
|
|
613
|
+
if (oldFiles?.has(file) || overrideFiles.has(file)) {
|
|
614
|
+
continue
|
|
615
|
+
}
|
|
616
|
+
|
|
553
617
|
try {
|
|
554
618
|
statSync(join(outputDir, file))
|
|
555
619
|
throw new Error(`refusing to overwrite unmanaged declaration: ${file}`)
|
|
556
620
|
} catch (error) {
|
|
557
|
-
if (error.code !== 'ENOENT') {
|
|
621
|
+
if (error.code !== 'ENOENT') {
|
|
622
|
+
throw error
|
|
623
|
+
}
|
|
558
624
|
}
|
|
559
625
|
}
|
|
560
626
|
|
|
561
627
|
for (const file of oldFiles ?? []) {
|
|
562
628
|
const path = resolve(outputDir, file)
|
|
563
|
-
if (!pathInside(outputDir, path)) {
|
|
564
|
-
|
|
629
|
+
if (!pathInside(outputDir, path)) {
|
|
630
|
+
throw new Error(`Invalid generated path in manifest: ${file}`)
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
if (!generated.has(file)) {
|
|
634
|
+
rmSync(path, { force: true })
|
|
635
|
+
}
|
|
565
636
|
}
|
|
566
637
|
|
|
567
638
|
for (const [file, content] of generated) {
|
|
@@ -579,40 +650,57 @@ function writeOutput(outputDir, generated, oldFiles, overrideFiles) {
|
|
|
579
650
|
|
|
580
651
|
function compareOutput(outputDir, generated, oldFiles, overrideFiles) {
|
|
581
652
|
const errors = []
|
|
582
|
-
if (!oldFiles) {
|
|
653
|
+
if (!oldFiles) {
|
|
654
|
+
errors.push(`missing ${manifestName}; run tsrx-typegen --project <tsconfig> first`)
|
|
655
|
+
}
|
|
656
|
+
|
|
583
657
|
for (const file of generated.keys()) {
|
|
584
658
|
if (!oldFiles?.has(file) && !overrideFiles.has(file)) {
|
|
585
659
|
try {
|
|
586
660
|
statSync(join(outputDir, file))
|
|
587
661
|
errors.push(`${file} conflicts with unmanaged output`)
|
|
588
662
|
} catch (error) {
|
|
589
|
-
if (error.code !== 'ENOENT') {
|
|
663
|
+
if (error.code !== 'ENOENT') {
|
|
664
|
+
throw error
|
|
665
|
+
}
|
|
590
666
|
}
|
|
591
667
|
}
|
|
592
668
|
|
|
593
669
|
try {
|
|
594
|
-
if (readFileSync(join(outputDir, file), 'utf8') !== generated.get(file))
|
|
595
|
-
|
|
670
|
+
if (readFileSync(join(outputDir, file), 'utf8') !== generated.get(file)) {
|
|
671
|
+
errors.push(`${file} is stale`)
|
|
672
|
+
}
|
|
596
673
|
} catch {
|
|
597
674
|
errors.push(`${file} is missing`)
|
|
598
675
|
}
|
|
599
676
|
}
|
|
600
677
|
|
|
601
678
|
for (const file of oldFiles ?? []) {
|
|
602
|
-
if (!generated.has(file)) {
|
|
679
|
+
if (!generated.has(file)) {
|
|
680
|
+
errors.push(`${file} is stale`)
|
|
681
|
+
}
|
|
603
682
|
}
|
|
604
683
|
|
|
605
684
|
return errors
|
|
606
685
|
}
|
|
607
686
|
|
|
608
687
|
function stringsIn(value) {
|
|
609
|
-
if (typeof value === 'string') {
|
|
610
|
-
|
|
688
|
+
if (typeof value === 'string') {
|
|
689
|
+
return [value]
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
if (!value || typeof value !== 'object') {
|
|
693
|
+
return []
|
|
694
|
+
}
|
|
695
|
+
|
|
611
696
|
return Object.values(value).flatMap(stringsIn)
|
|
612
697
|
}
|
|
613
698
|
|
|
614
699
|
function typeTargets(value) {
|
|
615
|
-
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
700
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
701
|
+
return []
|
|
702
|
+
}
|
|
703
|
+
|
|
616
704
|
return [
|
|
617
705
|
...(Object.hasOwn(value, 'types') ? stringsIn(value.types) : []),
|
|
618
706
|
...Object.entries(value)
|
|
@@ -647,13 +735,18 @@ function verifyPublicTypes(projectRoot, generated, outDir, target, sourceOutputs
|
|
|
647
735
|
for (const [subpath, entry] of Object.entries(target.entrypoints)) {
|
|
648
736
|
const mapping = exportsMap[subpath]
|
|
649
737
|
if (!mapping) {
|
|
650
|
-
failures.push(
|
|
738
|
+
failures.push(
|
|
739
|
+
`${subpath} is configured for ${target.name} but missing from effective package exports`,
|
|
740
|
+
)
|
|
741
|
+
|
|
651
742
|
continue
|
|
652
743
|
}
|
|
653
744
|
|
|
654
745
|
const source = resolve(projectRoot, entry.source)
|
|
655
746
|
if (![...sourceOutputs.values()].includes(source)) {
|
|
656
|
-
failures.push(
|
|
747
|
+
failures.push(
|
|
748
|
+
`${subpath} source is not included by its TypeScript project: ${entry.source}`,
|
|
749
|
+
)
|
|
657
750
|
}
|
|
658
751
|
|
|
659
752
|
const declaredRuntime = stringsIn(entry.runtime)
|
|
@@ -680,7 +773,10 @@ function verifyPublicTypes(projectRoot, generated, outDir, target, sourceOutputs
|
|
|
680
773
|
/\.(?:[cm]?[jt]sx?|tsrx)$/.test(target),
|
|
681
774
|
)
|
|
682
775
|
|
|
683
|
-
if (!runtimeTargets.length) {
|
|
776
|
+
if (!runtimeTargets.length) {
|
|
777
|
+
continue
|
|
778
|
+
}
|
|
779
|
+
|
|
684
780
|
const targets = typeTargets(mapping)
|
|
685
781
|
if (!targets.length) {
|
|
686
782
|
failures.push(`${subpath} has code exports but no types condition`)
|
|
@@ -688,7 +784,10 @@ function verifyPublicTypes(projectRoot, generated, outDir, target, sourceOutputs
|
|
|
688
784
|
}
|
|
689
785
|
|
|
690
786
|
for (const target of targets) {
|
|
691
|
-
if (!target.startsWith('./') || target.includes('*')) {
|
|
787
|
+
if (!target.startsWith('./') || target.includes('*')) {
|
|
788
|
+
continue
|
|
789
|
+
}
|
|
790
|
+
|
|
692
791
|
const absolute = resolve(projectRoot, target)
|
|
693
792
|
if (!pathInside(projectRoot, absolute)) {
|
|
694
793
|
failures.push(`${subpath} types target escapes the package: ${target}`)
|
|
@@ -696,10 +795,14 @@ function verifyPublicTypes(projectRoot, generated, outDir, target, sourceOutputs
|
|
|
696
795
|
}
|
|
697
796
|
|
|
698
797
|
const generatedPath = relative(outDir, absolute)
|
|
699
|
-
if (pathInside(outDir, absolute) && generated.has(generatedPath)) {
|
|
798
|
+
if (pathInside(outDir, absolute) && generated.has(generatedPath)) {
|
|
799
|
+
continue
|
|
800
|
+
}
|
|
801
|
+
|
|
700
802
|
try {
|
|
701
|
-
if (!statSync(absolute).isFile())
|
|
702
|
-
|
|
803
|
+
if (!statSync(absolute).isFile()) {
|
|
804
|
+
failures.push(`${subpath} types target is not a file: ${target}`)
|
|
805
|
+
}
|
|
703
806
|
} catch {
|
|
704
807
|
failures.push(`${subpath} types target is missing: ${target}`)
|
|
705
808
|
}
|
|
@@ -712,14 +815,18 @@ function verifyPublicTypes(projectRoot, generated, outDir, target, sourceOutputs
|
|
|
712
815
|
failures.push(`package types target escapes the package: ${targetPath}`)
|
|
713
816
|
} else if (!(pathInside(outDir, target) && generated.has(relative(outDir, target)))) {
|
|
714
817
|
try {
|
|
715
|
-
if (!statSync(target).isFile()) {
|
|
818
|
+
if (!statSync(target).isFile()) {
|
|
819
|
+
failures.push(`package types target is not a file: ${targetPath}`)
|
|
820
|
+
}
|
|
716
821
|
} catch {
|
|
717
822
|
failures.push(`package types target is missing: ${targetPath}`)
|
|
718
823
|
}
|
|
719
824
|
}
|
|
720
825
|
}
|
|
721
826
|
|
|
722
|
-
if (failures.length) {
|
|
827
|
+
if (failures.length) {
|
|
828
|
+
throw new Error(failures.join('\n'))
|
|
829
|
+
}
|
|
723
830
|
}
|
|
724
831
|
|
|
725
832
|
function runTarget(projectRoot, args) {
|
|
@@ -751,16 +858,34 @@ function runTarget(projectRoot, args) {
|
|
|
751
858
|
const temporaryOut = join(temporaryRoot, 'types')
|
|
752
859
|
const outputDir = temporaryOut
|
|
753
860
|
try {
|
|
754
|
-
const compilerArgs = [
|
|
861
|
+
const compilerArgs = [
|
|
862
|
+
compilerPath,
|
|
863
|
+
'--pretty',
|
|
864
|
+
'false',
|
|
865
|
+
'--project',
|
|
866
|
+
project,
|
|
867
|
+
outputFlag,
|
|
868
|
+
temporaryOut,
|
|
869
|
+
]
|
|
870
|
+
|
|
755
871
|
const result = spawnSync(process.execPath, compilerArgs, {
|
|
756
872
|
cwd: projectRoot,
|
|
757
873
|
encoding: 'utf8',
|
|
758
874
|
maxBuffer: 32 * 1024 * 1024,
|
|
759
875
|
})
|
|
760
876
|
|
|
761
|
-
if (result.stdout) {
|
|
762
|
-
|
|
763
|
-
|
|
877
|
+
if (result.stdout) {
|
|
878
|
+
process.stdout.write(result.stdout)
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
if (result.stderr) {
|
|
882
|
+
process.stderr.write(result.stderr)
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
if (result.error) {
|
|
886
|
+
throw result.error
|
|
887
|
+
}
|
|
888
|
+
|
|
764
889
|
if (/\[tsrx-tsc\]/.test(result.stderr ?? '')) {
|
|
765
890
|
throw new Error(
|
|
766
891
|
'tsrx compiler reported transform diagnostics; declarations were not written. Fix the source or configure an explicit declaration override.',
|
|
@@ -783,7 +908,10 @@ function runTarget(projectRoot, args) {
|
|
|
783
908
|
if (args.check) {
|
|
784
909
|
const errors = compareOutput(outDir, generated, oldFiles, managedOverrides)
|
|
785
910
|
if (errors.length) {
|
|
786
|
-
for (const error of errors) {
|
|
911
|
+
for (const error of errors) {
|
|
912
|
+
console.error(`tsrx-typegen: ${error}`)
|
|
913
|
+
}
|
|
914
|
+
|
|
787
915
|
return false
|
|
788
916
|
}
|
|
789
917
|
|
|
@@ -805,7 +933,10 @@ function run() {
|
|
|
805
933
|
const args = parseArgs(process.argv.slice(2))
|
|
806
934
|
const projectRoot = process.cwd()
|
|
807
935
|
if (!args.packCheck) {
|
|
808
|
-
if (!runTarget(projectRoot, args)) {
|
|
936
|
+
if (!runTarget(projectRoot, args)) {
|
|
937
|
+
process.exitCode = 1
|
|
938
|
+
}
|
|
939
|
+
|
|
809
940
|
return
|
|
810
941
|
}
|
|
811
942
|
|
package/src/pack-check.mjs
CHANGED
|
@@ -262,7 +262,11 @@ function staticRuntimeExports(ts, file, seen = new Set()) {
|
|
|
262
262
|
}
|
|
263
263
|
|
|
264
264
|
if (ts.isExportDeclaration(statement) && !statement.isTypeOnly) {
|
|
265
|
-
if (
|
|
265
|
+
if (
|
|
266
|
+
!statement.exportClause &&
|
|
267
|
+
statement.moduleSpecifier &&
|
|
268
|
+
ts.isStringLiteralLike(statement.moduleSpecifier)
|
|
269
|
+
) {
|
|
266
270
|
const target = localSourceModule(absolute, statement.moduleSpecifier.text)
|
|
267
271
|
if (target) {
|
|
268
272
|
for (const name of staticRuntimeExports(ts, target, seen)) {
|
|
@@ -350,8 +354,7 @@ function compilerExports(ts, program, file, cache = new Map(), pending = new Set
|
|
|
350
354
|
ts.sys,
|
|
351
355
|
).resolvedModule?.resolvedFileName
|
|
352
356
|
|
|
353
|
-
const targetExports =
|
|
354
|
-
target && compilerExports(ts, program, target, cache, pending)
|
|
357
|
+
const targetExports = target && compilerExports(ts, program, target, cache, pending)
|
|
355
358
|
|
|
356
359
|
pending.delete(absolute)
|
|
357
360
|
for (const name of targetExports?.all ?? []) {
|