@ttsc/unplugin 0.30.1 → 0.30.2
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/lib/core/projectRootFiles.d.cts +11 -0
- package/lib/core/projectRootFiles.d.mts +11 -0
- package/lib/core/projectRootFiles.d.ts +11 -0
- package/lib/core/projectRootFiles.js +136 -0
- package/lib/core/projectRootFiles.js.map +1 -0
- package/lib/core/projectRootFiles.mjs +134 -0
- package/lib/core/projectRootFiles.mjs.map +1 -0
- package/lib/core/transform.js +36 -21
- package/lib/core/transform.js.map +1 -1
- package/lib/core/transform.mjs +36 -21
- package/lib/core/transform.mjs.map +1 -1
- package/lib/core/tsconfigPaths.d.cts +14 -0
- package/lib/core/tsconfigPaths.d.mts +14 -0
- package/lib/core/tsconfigPaths.d.ts +14 -0
- package/lib/core/tsconfigPaths.js +41 -4
- package/lib/core/tsconfigPaths.js.map +1 -1
- package/lib/core/tsconfigPaths.mjs +41 -4
- package/lib/core/tsconfigPaths.mjs.map +1 -1
- package/package.json +3 -3
- package/src/core/projectRootFiles.ts +151 -0
- package/src/core/transform.ts +55 -21
- package/src/core/tsconfigPaths.ts +64 -4
package/src/core/transform.ts
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
findNearestProjectTsconfig,
|
|
22
22
|
isIgnoredProjectDirectory,
|
|
23
23
|
} from "./projectDiscovery";
|
|
24
|
+
import { matchesProjectRootFile } from "./projectRootFiles";
|
|
24
25
|
import {
|
|
25
26
|
CONFIG_DIR_TEMPLATE_LIST_OPTIONS,
|
|
26
27
|
CONFIG_DIR_TEMPLATE_SCALAR_OPTIONS,
|
|
@@ -2624,6 +2625,29 @@ function matchesCachedSource(
|
|
|
2624
2625
|
cached.sourceHashes?.[identity] ??
|
|
2625
2626
|
cached.inputHashes[currentKey] ??
|
|
2626
2627
|
cached.externalInputHashes?.[identity];
|
|
2628
|
+
if (
|
|
2629
|
+
expected === undefined &&
|
|
2630
|
+
cached.result.type === "success" &&
|
|
2631
|
+
!matchesProjectRootFile(file, cached.membershipPolicy, false)
|
|
2632
|
+
) {
|
|
2633
|
+
const state = envelopeDerivation(cached);
|
|
2634
|
+
const outputs = (state.outputIndex ??= createEnvelopeKeyIndex(
|
|
2635
|
+
state,
|
|
2636
|
+
cached.projectRoot,
|
|
2637
|
+
cached.result.typescript,
|
|
2638
|
+
));
|
|
2639
|
+
if (!outputs.has(identity)) {
|
|
2640
|
+
// Root discovery deliberately never hashed this unrelated module. Its
|
|
2641
|
+
// bytes cannot affect an output the compiler did not produce, but the
|
|
2642
|
+
// whole program must still be current before we reuse that absence: a
|
|
2643
|
+
// changed config or importer can bring this file into the next program.
|
|
2644
|
+
refreshFilesystemClockReference(
|
|
2645
|
+
TRANSFORM_CLOCK_REFERENCE_DIRECTORIES.get(cached),
|
|
2646
|
+
resultFilesystem(cached.result),
|
|
2647
|
+
);
|
|
2648
|
+
return matchesCompleteInputSnapshot(cached, currentKey, source);
|
|
2649
|
+
}
|
|
2650
|
+
}
|
|
2627
2651
|
if (expected !== hashText(source)) {
|
|
2628
2652
|
return false;
|
|
2629
2653
|
}
|
|
@@ -4442,7 +4466,10 @@ function walkProjectInputs(
|
|
|
4442
4466
|
continue;
|
|
4443
4467
|
}
|
|
4444
4468
|
const file = path.join(current, entry.name);
|
|
4445
|
-
if (
|
|
4469
|
+
if (
|
|
4470
|
+
(entry.isDirectory() && isExcludedProjectDirectory(file, policy)) ||
|
|
4471
|
+
!matchesProjectRootFile(file, policy, entry.isDirectory())
|
|
4472
|
+
) {
|
|
4446
4473
|
continue;
|
|
4447
4474
|
}
|
|
4448
4475
|
const possible = isPossibleProgramEntry(entry, policy);
|
|
@@ -4851,30 +4878,34 @@ function reportsProgramMembership(
|
|
|
4851
4878
|
policy: ITtscProjectMembershipPolicy,
|
|
4852
4879
|
filesystem: TtscTransformFilesystemOperations,
|
|
4853
4880
|
): boolean {
|
|
4854
|
-
if (
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
return
|
|
4881
|
+
if (
|
|
4882
|
+
!matchesProjectRootFile(location, policy, false) &&
|
|
4883
|
+
!matchesProjectRootFile(location, policy, true)
|
|
4884
|
+
) {
|
|
4885
|
+
return false;
|
|
4859
4886
|
}
|
|
4860
|
-
let directory: boolean;
|
|
4861
4887
|
try {
|
|
4862
|
-
|
|
4888
|
+
if (filesystem.lstat(location).isDirectory()) {
|
|
4889
|
+
return (
|
|
4890
|
+
matchesProjectRootFile(location, policy, true) &&
|
|
4891
|
+
!insideExcludedProjectDirectory(location, policy, false)
|
|
4892
|
+
);
|
|
4893
|
+
}
|
|
4863
4894
|
} catch {
|
|
4864
|
-
//
|
|
4865
|
-
// and a directory removed under this one reports its own contents leaving
|
|
4866
|
-
// through the watch that was opened on it.
|
|
4867
|
-
return false;
|
|
4895
|
+
// Deleted file names still need classification below.
|
|
4868
4896
|
}
|
|
4869
|
-
if (
|
|
4870
|
-
|
|
4897
|
+
if (isPossibleProgramFileName(filename, policy)) {
|
|
4898
|
+
// A name the program could admit. It still says nothing if it lies inside a
|
|
4899
|
+
// directory the walk never descends into, because the digest cannot see
|
|
4900
|
+
// there either and the tracker must not be the one side that reacts.
|
|
4901
|
+
return (
|
|
4902
|
+
matchesProjectRootFile(location, policy, false) &&
|
|
4903
|
+
!insideExcludedProjectDirectory(location, policy, true)
|
|
4904
|
+
);
|
|
4871
4905
|
}
|
|
4872
|
-
//
|
|
4873
|
-
//
|
|
4874
|
-
|
|
4875
|
-
// `output.clean` do on every build, would otherwise void the generation once
|
|
4876
|
-
// per build on every host that has no build boundary.
|
|
4877
|
-
return !insideExcludedProjectDirectory(location, policy, false);
|
|
4906
|
+
// Removed directories report their source removals through their own watch.
|
|
4907
|
+
// A non-source file name cannot introduce program membership.
|
|
4908
|
+
return false;
|
|
4878
4909
|
}
|
|
4879
4910
|
|
|
4880
4911
|
/** Record enough exact mutation evidence without retaining an event stream. */
|
|
@@ -5356,7 +5387,10 @@ export function isProjectWalkPath(
|
|
|
5356
5387
|
// a graph input the compiler really read in neither snapshot: absent from
|
|
5357
5388
|
// `inputHashes` because the walk skipped it, and absent from the out-of-walk
|
|
5358
5389
|
// snapshot because this predicate claimed the walk covered it.
|
|
5359
|
-
if (
|
|
5390
|
+
if (
|
|
5391
|
+
!isPossibleProgramFileName(path.basename(file), policy) ||
|
|
5392
|
+
!matchesProjectRootFile(file, policy, false)
|
|
5393
|
+
) {
|
|
5360
5394
|
return false;
|
|
5361
5395
|
}
|
|
5362
5396
|
let current = resolvedRoot;
|
|
@@ -116,6 +116,16 @@ export function readTsconfigSourceSnapshot(
|
|
|
116
116
|
* dropped from the walk entirely (samchon/ttsc#1307).
|
|
117
117
|
*/
|
|
118
118
|
export interface ITtscProjectMembershipPolicy {
|
|
119
|
+
/** Absolute root-file specifications; absent means conservative discovery. */
|
|
120
|
+
rootFileSpecs?: Readonly<{
|
|
121
|
+
files: readonly string[];
|
|
122
|
+
include: readonly string[];
|
|
123
|
+
/**
|
|
124
|
+
* The requested root and its regular/native realpath spellings, without
|
|
125
|
+
* following child links. Native realpath expands Windows short names.
|
|
126
|
+
*/
|
|
127
|
+
root?: Readonly<{ path: string; realpath: string; nativepath?: string }>;
|
|
128
|
+
}>;
|
|
119
129
|
/**
|
|
120
130
|
* Absolute directory exclusions separated by the configuration entry that
|
|
121
131
|
* contributed them.
|
|
@@ -210,6 +220,48 @@ export function readProjectMembershipPolicy(
|
|
|
210
220
|
// when it has gone stale. `findDeclaredValue` walks `extends` for each option
|
|
211
221
|
// independently, and each walk records what it read.
|
|
212
222
|
const sources = new Set<string>();
|
|
223
|
+
const fileSpec = (key: "files" | "include") =>
|
|
224
|
+
findDeclaredValue(
|
|
225
|
+
resolved,
|
|
226
|
+
(parsed) =>
|
|
227
|
+
Object.prototype.hasOwnProperty.call(parsed, key)
|
|
228
|
+
? { value: (parsed as Record<string, unknown>)[key] }
|
|
229
|
+
: undefined,
|
|
230
|
+
new Set(),
|
|
231
|
+
sources,
|
|
232
|
+
);
|
|
233
|
+
const files = fileSpec("files");
|
|
234
|
+
const include = fileSpec("include");
|
|
235
|
+
const resolveSpecs = (
|
|
236
|
+
declared: ReturnType<typeof fileSpec>,
|
|
237
|
+
): string[] | undefined => {
|
|
238
|
+
if (declared === null || declared.value.value == null) return undefined;
|
|
239
|
+
const value = declared.value.value;
|
|
240
|
+
if (
|
|
241
|
+
!Array.isArray(value) ||
|
|
242
|
+
!value.every((entry) => typeof entry === "string")
|
|
243
|
+
)
|
|
244
|
+
return undefined;
|
|
245
|
+
return value.map((entry) =>
|
|
246
|
+
absolutizePathsTarget(declared.baseDir, entry, path.dirname(resolved)),
|
|
247
|
+
);
|
|
248
|
+
};
|
|
249
|
+
const explicitFiles = resolveSpecs(files);
|
|
250
|
+
const includes = resolveSpecs(include);
|
|
251
|
+
const root = {
|
|
252
|
+
path: path.dirname(resolved),
|
|
253
|
+
realpath: resolveRealPath(path.dirname(resolved)),
|
|
254
|
+
nativepath: resolveNativeRootPath(path.dirname(resolved)),
|
|
255
|
+
};
|
|
256
|
+
// Missing/invalid specs keep the wide fallback. A files-only project has no
|
|
257
|
+
// implicit include, whereas include and files together form a union.
|
|
258
|
+
const rootFileSpecs =
|
|
259
|
+
includes !== undefined
|
|
260
|
+
? { files: explicitFiles ?? [], include: includes, root }
|
|
261
|
+
: explicitFiles !== undefined &&
|
|
262
|
+
(include === null || include.value.value == null)
|
|
263
|
+
? { files: explicitFiles, include: [], root }
|
|
264
|
+
: undefined;
|
|
213
265
|
const flag = (key: string): boolean =>
|
|
214
266
|
findDeclaredValue(
|
|
215
267
|
resolved,
|
|
@@ -302,6 +354,7 @@ export function readProjectMembershipPolicy(
|
|
|
302
354
|
}
|
|
303
355
|
}
|
|
304
356
|
return {
|
|
357
|
+
rootFileSpecs,
|
|
305
358
|
directoryExclusionOrigins,
|
|
306
359
|
excludedDirectories: flattenDirectoryExclusionOrigins(
|
|
307
360
|
directoryExclusionOrigins,
|
|
@@ -367,6 +420,7 @@ export function mergeMembershipPolicyOverlay(
|
|
|
367
420
|
}
|
|
368
421
|
}
|
|
369
422
|
return {
|
|
423
|
+
rootFileSpecs: policy.rootFileSpecs,
|
|
370
424
|
directoryExclusionOrigins,
|
|
371
425
|
excludedDirectories: flattenDirectoryExclusionOrigins(
|
|
372
426
|
directoryExclusionOrigins,
|
|
@@ -866,10 +920,16 @@ function isRelativeSpecifier(specifier: string): boolean {
|
|
|
866
920
|
);
|
|
867
921
|
}
|
|
868
922
|
|
|
869
|
-
/**
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
923
|
+
/** Native watchers expand Windows short names that regular realpath retains. */
|
|
924
|
+
function resolveNativeRootPath(location: string): string {
|
|
925
|
+
try {
|
|
926
|
+
return fs.realpathSync.native(location);
|
|
927
|
+
} catch {
|
|
928
|
+
return resolveRealPath(location);
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
/** Resolve symlinks, retaining the original spelling when the path is missing. */
|
|
873
933
|
function resolveRealPath(location: string): string {
|
|
874
934
|
try {
|
|
875
935
|
return fs.realpathSync(location);
|