@ttsc/banner 0.13.1 → 0.14.0-dev.20260528.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/driver/banner.go +66 -9
- package/lib/index.js.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +5 -8
package/driver/banner.go
CHANGED
|
@@ -2,16 +2,24 @@ package banner
|
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
4
|
"bytes"
|
|
5
|
+
"context"
|
|
5
6
|
"encoding/json"
|
|
6
7
|
"fmt"
|
|
7
8
|
"os"
|
|
8
9
|
"os/exec"
|
|
9
10
|
"path/filepath"
|
|
11
|
+
"runtime"
|
|
10
12
|
"strings"
|
|
13
|
+
"time"
|
|
11
14
|
|
|
12
15
|
"github.com/samchon/ttsc/packages/ttsc/driver"
|
|
13
16
|
)
|
|
14
17
|
|
|
18
|
+
// configLoaderTimeout caps subprocesses that evaluate user-supplied banner
|
|
19
|
+
// config files. This matches the strip/lint loaders so a hanging config does
|
|
20
|
+
// not block the compiler indefinitely.
|
|
21
|
+
const configLoaderTimeout = 60 * time.Second
|
|
22
|
+
|
|
15
23
|
func init() {
|
|
16
24
|
driver.RegisterPlugin(plugin{})
|
|
17
25
|
}
|
|
@@ -296,8 +304,18 @@ const { pathToFileURL } = require("node:url");
|
|
|
296
304
|
|
|
297
305
|
(async () => {
|
|
298
306
|
const mod = await import(pathToFileURL(process.argv[1]).href);
|
|
299
|
-
|
|
300
|
-
|
|
307
|
+
let current = Object.prototype.hasOwnProperty.call(mod, "default") ? mod.default : mod;
|
|
308
|
+
for (let i = 0; i < 8; i++) {
|
|
309
|
+
if (current !== null && typeof current === "object" && typeof current.text === "string") {
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
312
|
+
if (current !== null && typeof current === "object" && Object.prototype.hasOwnProperty.call(current, "default")) {
|
|
313
|
+
current = current.default;
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
break;
|
|
317
|
+
}
|
|
318
|
+
const value = typeof current === "function" ? await current() : current;
|
|
301
319
|
process.stdout.write(JSON.stringify(toSerializableBanner(value)));
|
|
302
320
|
})().catch((error) => {
|
|
303
321
|
process.stderr.write(error && error.stack ? error.stack : String(error));
|
|
@@ -315,10 +333,15 @@ function toSerializableBanner(value) {
|
|
|
315
333
|
if node == "" {
|
|
316
334
|
node = "node"
|
|
317
335
|
}
|
|
318
|
-
|
|
336
|
+
ctx, cancel := context.WithTimeout(context.Background(), configLoaderTimeout)
|
|
337
|
+
defer cancel()
|
|
338
|
+
cmd := exec.CommandContext(ctx, node, "-e", script, location)
|
|
319
339
|
cmd.Env = nodeConfigLoaderEnv(location)
|
|
320
340
|
output, err := cmd.Output()
|
|
321
341
|
if err != nil {
|
|
342
|
+
if ctx.Err() == context.DeadlineExceeded {
|
|
343
|
+
return nil, fmt.Errorf("@ttsc/banner: load config file %s: timed out after %s", location, configLoaderTimeout)
|
|
344
|
+
}
|
|
322
345
|
stderr := ""
|
|
323
346
|
if exit, ok := err.(*exec.ExitError); ok {
|
|
324
347
|
stderr = strings.TrimSpace(string(exit.Stderr))
|
|
@@ -376,10 +399,15 @@ func loadBannerTypeScriptConfigFile(location string) (any, error) {
|
|
|
376
399
|
}
|
|
377
400
|
args = append(args, loader)
|
|
378
401
|
|
|
379
|
-
|
|
402
|
+
ctx, cancel := context.WithTimeout(context.Background(), configLoaderTimeout)
|
|
403
|
+
defer cancel()
|
|
404
|
+
cmd := ttsxCommandContext(ctx, args...)
|
|
380
405
|
cmd.Env = nodeConfigLoaderEnv(location)
|
|
381
406
|
output, err := cmd.Output()
|
|
382
407
|
if err != nil {
|
|
408
|
+
if ctx.Err() == context.DeadlineExceeded {
|
|
409
|
+
return nil, fmt.Errorf("@ttsc/banner: load TypeScript config file %s: timed out after %s", location, configLoaderTimeout)
|
|
410
|
+
}
|
|
383
411
|
stderr := ""
|
|
384
412
|
if exit, ok := err.(*exec.ExitError); ok {
|
|
385
413
|
stderr = strings.TrimSpace(string(exit.Stderr))
|
|
@@ -431,8 +459,11 @@ try {
|
|
|
431
459
|
}
|
|
432
460
|
|
|
433
461
|
async function resolveConfig(value: unknown): Promise<unknown> {
|
|
434
|
-
let current = value;
|
|
462
|
+
let current = isObject(value) && hasOwn(value, "default") ? value.default : value;
|
|
435
463
|
for (let i = 0; i < 8; i++) {
|
|
464
|
+
if (isBannerObject(current)) {
|
|
465
|
+
break;
|
|
466
|
+
}
|
|
436
467
|
if (isObject(current) && hasOwn(current, "default")) {
|
|
437
468
|
current = current.default;
|
|
438
469
|
continue;
|
|
@@ -449,6 +480,10 @@ function isObject(value: unknown): value is Record<string, unknown> {
|
|
|
449
480
|
return value !== null && typeof value === "object";
|
|
450
481
|
}
|
|
451
482
|
|
|
483
|
+
function isBannerObject(value: unknown): value is { text: string } {
|
|
484
|
+
return isObject(value) && typeof value.text === "string";
|
|
485
|
+
}
|
|
486
|
+
|
|
452
487
|
function hasOwn(value: Record<string, unknown>, key: string): boolean {
|
|
453
488
|
return Object.prototype.hasOwnProperty.call(value, key);
|
|
454
489
|
}
|
|
@@ -490,6 +525,11 @@ func typeScriptConfigLoaderTsconfig(loader, location, outDir string) string {
|
|
|
490
525
|
// When TTSC_TTSX_BINARY has a script extension (.js, .ts, …) the binary is
|
|
491
526
|
// invoked via the Node runtime so it is executed correctly on all platforms.
|
|
492
527
|
func ttsxCommand(args ...string) *exec.Cmd {
|
|
528
|
+
return ttsxCommandContext(context.Background(), args...)
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// ttsxCommandContext is the timeout-aware variant used by config loaders.
|
|
532
|
+
func ttsxCommandContext(ctx context.Context, args ...string) *exec.Cmd {
|
|
493
533
|
ttsx := os.Getenv("TTSC_TTSX_BINARY")
|
|
494
534
|
if ttsx == "" {
|
|
495
535
|
ttsx = "ttsx"
|
|
@@ -499,9 +539,9 @@ func ttsxCommand(args ...string) *exec.Cmd {
|
|
|
499
539
|
if node == "" {
|
|
500
540
|
node = "node"
|
|
501
541
|
}
|
|
502
|
-
return exec.
|
|
542
|
+
return exec.CommandContext(ctx, node, append([]string{ttsx}, args...)...)
|
|
503
543
|
}
|
|
504
|
-
return exec.
|
|
544
|
+
return exec.CommandContext(ctx, ttsx, args...)
|
|
505
545
|
}
|
|
506
546
|
|
|
507
547
|
// shouldRunTtsxThroughNode reports whether binary has a script file extension
|
|
@@ -541,8 +581,25 @@ func linkNearestNodeModules(tempDir, sourceDir string) error {
|
|
|
541
581
|
return nil
|
|
542
582
|
}
|
|
543
583
|
link := filepath.Join(tempDir, "node_modules")
|
|
544
|
-
|
|
545
|
-
|
|
584
|
+
err := os.Symlink(nodeModules, link)
|
|
585
|
+
if err == nil {
|
|
586
|
+
return nil
|
|
587
|
+
}
|
|
588
|
+
if runtime.GOOS == "windows" {
|
|
589
|
+
jerr := createWindowsJunction(link, nodeModules)
|
|
590
|
+
if jerr == nil {
|
|
591
|
+
return nil
|
|
592
|
+
}
|
|
593
|
+
err = fmt.Errorf("%w (junction fallback: %v)", err, jerr)
|
|
594
|
+
}
|
|
595
|
+
return fmt.Errorf("@ttsc/banner: link config node_modules %s: %w", nodeModules, err)
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// createWindowsJunction creates a directory junction on Windows.
|
|
599
|
+
func createWindowsJunction(link, target string) error {
|
|
600
|
+
cmd := exec.Command("cmd", "/c", "mklink", "/J", link, target)
|
|
601
|
+
if out, err := cmd.CombinedOutput(); err != nil {
|
|
602
|
+
return fmt.Errorf("mklink /J failed: %v: %s", err, strings.TrimSpace(string(out)))
|
|
546
603
|
}
|
|
547
604
|
return nil
|
|
548
605
|
}
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA,0DAA6B;AAI7B,qDAAmC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA,0DAA6B;AAI7B,qDAAmC;AAyCnC;;;;GAIG;AACH,MAAM,cAAc,GAAG,IAAI,GAAG,CAAS;IACrC,SAAS;IACT,MAAM;IACN,OAAO;IACP,WAAW;CACZ,CAAC,CAAC;AAEH;;;;;;;;;;GAUG;AACH,0BACE,OAA0D;IAE1D,MAAM,KAAK,GAAG,OAAO,CAAC,MAAiC,CAAC;IACxD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACrC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,GAAG,KAAK,YAAY,EAAE,CAAC;YACrD,MAAM,IAAI,KAAK,CACb,gEAAgE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI;gBACrF,sFAAsF;gBACtF,iGAAiG,CACpG,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO;QACL,IAAI,EAAE,cAAc;QACpB,iEAAiE;QACjE,sDAAsD;QACtD,MAAM,EAAE,mBAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,QAAQ,CAAC;QAC/C,KAAK,EAAE,WAAW;KACnB,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttsc/banner",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0-dev.20260528.1",
|
|
4
4
|
"description": "First-party ttsc plugin that adds package-documentation JSDoc banners during emit.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -33,9 +33,9 @@
|
|
|
33
33
|
],
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@types/node": "^25.3.0",
|
|
36
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
36
|
+
"@typescript/native-preview": "7.0.0-dev.20260527.2",
|
|
37
37
|
"rimraf": "^6.1.2",
|
|
38
|
-
"ttsc": "0.
|
|
38
|
+
"ttsc": "0.14.0-dev.20260528.1"
|
|
39
39
|
},
|
|
40
40
|
"repository": {
|
|
41
41
|
"type": "git",
|
package/src/index.ts
CHANGED
|
@@ -7,9 +7,9 @@ export * from "./structures/index";
|
|
|
7
7
|
/**
|
|
8
8
|
* The shape returned by a ttsc plugin factory function.
|
|
9
9
|
*
|
|
10
|
-
* Mirrors the
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* Mirrors the ttsc plugin descriptor contract. The `source` field points to the
|
|
11
|
+
* Go source directory that the host will compile and cache as either an
|
|
12
|
+
* executable sidecar or linked native source.
|
|
13
13
|
*/
|
|
14
14
|
type TtscPluginDescriptor = {
|
|
15
15
|
/** Human-readable plugin name used in logs and error messages. */
|
|
@@ -18,7 +18,7 @@ type TtscPluginDescriptor = {
|
|
|
18
18
|
source: string;
|
|
19
19
|
/**
|
|
20
20
|
* Pipeline stage. `"transform"` plugins may rewrite source files; `"check"`
|
|
21
|
-
* plugins only produce diagnostics.
|
|
21
|
+
* plugins only produce diagnostics. The framework default is `"transform"`.
|
|
22
22
|
*/
|
|
23
23
|
stage?: "check" | "transform";
|
|
24
24
|
};
|
|
@@ -31,10 +31,7 @@ type TtscPluginDescriptor = {
|
|
|
31
31
|
* factories ignore it.
|
|
32
32
|
*/
|
|
33
33
|
type TtscPluginFactoryContext<TConfig> = {
|
|
34
|
-
/**
|
|
35
|
-
* Absolute path to the compiled plugin binary (not yet built at factory
|
|
36
|
-
* time).
|
|
37
|
-
*/
|
|
34
|
+
/** Absolute path to the selected ttsc native helper, not a plugin binary. */
|
|
38
35
|
binary: string;
|
|
39
36
|
/** Working directory of the ttsc invocation. */
|
|
40
37
|
cwd: string;
|