@ttsc/strip 0.27.0 → 0.28.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/config.go +104 -32
- package/driver/strip.go +5 -0
- package/package.json +1 -1
package/driver/config.go
CHANGED
|
@@ -77,7 +77,12 @@ func loadStripConfigMapWithReporters(pluginConfig map[string]any, cwd, tsconfigP
|
|
|
77
77
|
}
|
|
78
78
|
configFilePath = resolveStripConfigFilePath(cf, cwd, tsconfigPath)
|
|
79
79
|
} else {
|
|
80
|
-
discovered, err := findStripConfigFile(cwd, tsconfigPath)
|
|
80
|
+
discovered, probed, err := findStripConfigFile(cwd, tsconfigPath)
|
|
81
|
+
// Report the rejected candidates before the error check and before the
|
|
82
|
+
// defaults path below: a search that ended empty examined them just the
|
|
83
|
+
// same, and falling back to the built-in defaults is exactly the state a
|
|
84
|
+
// config appearing later would change.
|
|
85
|
+
driver.ReportRejectedConfigCandidates(probed, hashReporter, realpathReporter)
|
|
81
86
|
if err != nil {
|
|
82
87
|
return nil, err
|
|
83
88
|
}
|
|
@@ -106,36 +111,32 @@ func loadStripConfigMapWithReporters(pluginConfig map[string]any, cwd, tsconfigP
|
|
|
106
111
|
// tsconfig is set) and returns the first directory that contains exactly one
|
|
107
112
|
// strip.config.* file. Multiple candidates in the same directory is an error.
|
|
108
113
|
// Returns "" (no error) when the filesystem root is reached without a match.
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
return "", fmt.Errorf(
|
|
125
|
-
"@ttsc/strip: multiple strip config files found in %s (%s); "+
|
|
126
|
-
"set \"configFile\" explicitly in the tsconfig plugin entry",
|
|
127
|
-
dir, strings.Join(names, ", "),
|
|
128
|
-
)
|
|
129
|
-
}
|
|
130
|
-
if len(matches) == 1 {
|
|
131
|
-
return matches[0], nil
|
|
132
|
-
}
|
|
133
|
-
parent := filepath.Dir(dir)
|
|
134
|
-
if parent == dir {
|
|
135
|
-
return "", nil
|
|
114
|
+
//
|
|
115
|
+
// The second return value is every candidate the walk examined and rejected,
|
|
116
|
+
// each carrying whether it was absent or a directory wearing the name. Those
|
|
117
|
+
// decide the result as much as the file it returned: one created
|
|
118
|
+
// nearer the entry wins the next search, and one created beside the match makes
|
|
119
|
+
// that directory ambiguous. Without them a persistent consumer keeps applying
|
|
120
|
+
// the rules of a config a cold run would no longer choose — or keeps stripping
|
|
121
|
+
// under the built-in defaults after a real config appeared
|
|
122
|
+
// (samchon/ttsc#1271).
|
|
123
|
+
func findStripConfigFile(cwd, tsconfigPath string) (string, []driver.ConfigCandidate, error) {
|
|
124
|
+
discovery := driver.DiscoverConfigFile(stripDiscoveryBaseDir(cwd, tsconfigPath), stripConfigFilenames)
|
|
125
|
+
if len(discovery.Matches) > 1 {
|
|
126
|
+
names := make([]string, 0, len(discovery.Matches))
|
|
127
|
+
for _, match := range discovery.Matches {
|
|
128
|
+
names = append(names, filepath.Base(match))
|
|
136
129
|
}
|
|
137
|
-
|
|
130
|
+
return "", discovery.Probed, fmt.Errorf(
|
|
131
|
+
"@ttsc/strip: multiple strip config files found in %s (%s); "+
|
|
132
|
+
"set \"configFile\" explicitly in the tsconfig plugin entry",
|
|
133
|
+
discovery.Directory, strings.Join(names, ", "),
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
if len(discovery.Matches) == 1 {
|
|
137
|
+
return discovery.Matches[0], discovery.Probed, nil
|
|
138
138
|
}
|
|
139
|
+
return "", discovery.Probed, nil
|
|
139
140
|
}
|
|
140
141
|
|
|
141
142
|
// stripDiscoveryBaseDir returns the directory from which auto-discovery walks
|
|
@@ -305,7 +306,8 @@ func parseStripJSONConfigFile(location string, body []byte) (any, error) {
|
|
|
305
306
|
// loadStripScriptConfigFile to evaluate a .js/.cjs/.mjs strip config and
|
|
306
307
|
// serialize the result to stdout as JSON.
|
|
307
308
|
const stripScriptLoaderSource = `
|
|
308
|
-
const
|
|
309
|
+
const nodeModule = require("node:module");
|
|
310
|
+
const { createRequire, isBuiltin, registerHooks } = nodeModule;
|
|
309
311
|
const crypto = require("node:crypto");
|
|
310
312
|
const fs = require("node:fs");
|
|
311
313
|
const path = require("node:path");
|
|
@@ -501,6 +503,33 @@ registerHooks({
|
|
|
501
503
|
},
|
|
502
504
|
});
|
|
503
505
|
|
|
506
|
+
// The hook above never sees a require() made from inside a CommonJS module the
|
|
507
|
+
// ESM loader evaluated, which on Node 22 is every require the config makes:
|
|
508
|
+
// module.registerHooks observes the import() of that module and nothing within
|
|
509
|
+
// it. A config's own dependencies would then be reported without the candidates
|
|
510
|
+
// that decide them, so a spelling appearing later could change what the config
|
|
511
|
+
// resolves to with nothing in the envelope to notice it (samchon/ttsc#1280).
|
|
512
|
+
// Wrapping the CommonJS resolver records the same two observations the hook
|
|
513
|
+
// does, on the graph the hook cannot reach.
|
|
514
|
+
const nextResolveFilename = nodeModule._resolveFilename;
|
|
515
|
+
nodeModule._resolveFilename = function resolveFilename(request, parent, isMain, options) {
|
|
516
|
+
// _resolveFilename is an internal entry point anything may call, so a
|
|
517
|
+
// non-string request arrives here as readily as a specifier does. Reading it
|
|
518
|
+
// would replace Node's own argument error with a TypeError from this loader.
|
|
519
|
+
if (typeof request !== "string") {
|
|
520
|
+
return nextResolveFilename.call(this, request, parent, isMain, options);
|
|
521
|
+
}
|
|
522
|
+
const parentFile = parent && typeof parent.filename === "string" ? parent.filename : undefined;
|
|
523
|
+
const parentURL = parentFile === undefined ? undefined : pathToFileURL(parentFile).href;
|
|
524
|
+
recordResolutionCandidates(request, parentURL, undefined);
|
|
525
|
+
const resolved = nextResolveFilename.call(this, request, parent, isMain, options);
|
|
526
|
+
if (path.isAbsolute(resolved)) {
|
|
527
|
+
recordResolutionCandidates(request, parentURL, pathToFileURL(resolved).href);
|
|
528
|
+
recordFile(resolved);
|
|
529
|
+
}
|
|
530
|
+
return resolved;
|
|
531
|
+
};
|
|
532
|
+
|
|
504
533
|
(async () => {
|
|
505
534
|
const mod = await import(pathToFileURL(process.argv[1]).href);
|
|
506
535
|
let current = mod;
|
|
@@ -609,11 +638,11 @@ func decodeStripConfigLoaderOutput(output []byte) (stripLoadedConfig, error) {
|
|
|
609
638
|
// `"./strip.config.ts"`) produced by json.Marshal.
|
|
610
639
|
func stripTypeScriptLoaderSource(importLiteral string) string {
|
|
611
640
|
return fmt.Sprintf(`// @ts-nocheck
|
|
612
|
-
import { createRequire, isBuiltin, registerHooks } from "node:module";
|
|
641
|
+
import Module, { createRequire, isBuiltin, registerHooks } from "node:module";
|
|
613
642
|
import crypto from "node:crypto";
|
|
614
643
|
import fs from "node:fs";
|
|
615
644
|
import path from "node:path";
|
|
616
|
-
import { fileURLToPath } from "node:url";
|
|
645
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
617
646
|
|
|
618
647
|
const inputs = new Set<string>();
|
|
619
648
|
const hashes = new Map<string, string | null>();
|
|
@@ -820,6 +849,49 @@ registerHooks({
|
|
|
820
849
|
},
|
|
821
850
|
});
|
|
822
851
|
|
|
852
|
+
// The hook above never sees a require() made from inside a CommonJS module the
|
|
853
|
+
// ESM loader evaluated, which on Node 22 is every require the config makes:
|
|
854
|
+
// module.registerHooks observes the import() of that module and nothing within
|
|
855
|
+
// it. A config's own dependencies would then be reported without the candidates
|
|
856
|
+
// that decide them, so a spelling appearing later could change what the config
|
|
857
|
+
// resolves to with nothing in the envelope to notice it (samchon/ttsc#1280).
|
|
858
|
+
// Wrapping the CommonJS resolver records the same two observations the hook
|
|
859
|
+
// does, on the graph the hook cannot reach.
|
|
860
|
+
const moduleInternals = Module as unknown as {
|
|
861
|
+
_resolveFilename(
|
|
862
|
+
request: string,
|
|
863
|
+
parent: { filename?: string | null } | null | undefined,
|
|
864
|
+
isMain: boolean,
|
|
865
|
+
options?: unknown,
|
|
866
|
+
): string;
|
|
867
|
+
};
|
|
868
|
+
const nextResolveFilename = moduleInternals._resolveFilename;
|
|
869
|
+
moduleInternals._resolveFilename = function resolveFilename(
|
|
870
|
+
this: unknown,
|
|
871
|
+
request: string,
|
|
872
|
+
parent: { filename?: string | null } | null | undefined,
|
|
873
|
+
isMain: boolean,
|
|
874
|
+
options?: unknown,
|
|
875
|
+
): string {
|
|
876
|
+
// _resolveFilename is an internal entry point anything may call, so a
|
|
877
|
+
// non-string request arrives here as readily as a specifier does. Reading it
|
|
878
|
+
// would replace Node's own argument error with a TypeError from this loader.
|
|
879
|
+
if (typeof request !== "string") {
|
|
880
|
+
return nextResolveFilename.call(this, request, parent, isMain, options);
|
|
881
|
+
}
|
|
882
|
+
const parentURL =
|
|
883
|
+
typeof parent?.filename === "string"
|
|
884
|
+
? pathToFileURL(parent.filename).href
|
|
885
|
+
: undefined;
|
|
886
|
+
recordResolutionCandidates(request, parentURL, undefined);
|
|
887
|
+
const resolved = nextResolveFilename.call(this, request, parent, isMain, options);
|
|
888
|
+
if (path.isAbsolute(resolved)) {
|
|
889
|
+
recordResolutionCandidates(request, parentURL, pathToFileURL(resolved).href);
|
|
890
|
+
recordFile(resolved);
|
|
891
|
+
}
|
|
892
|
+
return resolved;
|
|
893
|
+
};
|
|
894
|
+
|
|
823
895
|
declare const process: {
|
|
824
896
|
exitCode?: number;
|
|
825
897
|
stdout: { write(value: string, callback?: () => void): void };
|
package/driver/strip.go
CHANGED
|
@@ -27,6 +27,11 @@ func (plugin) ApplyProgram(prog *driver.Program, ctx driver.PluginContext) error
|
|
|
27
27
|
if err != nil {
|
|
28
28
|
return err
|
|
29
29
|
}
|
|
30
|
+
// The rewrite reads the statements in front of it and the configured
|
|
31
|
+
// patterns, never the checker and never another file, so what a file's
|
|
32
|
+
// output depends on is that file's own text plus strip.config.*, which was
|
|
33
|
+
// reported above as a host input (samchon/ttsc#1263).
|
|
34
|
+
ctx.ReportDependenciesComplete()
|
|
30
35
|
for _, file := range prog.SourceFiles() {
|
|
31
36
|
rewriter.apply(file)
|
|
32
37
|
}
|
package/package.json
CHANGED