@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.
@@ -0,0 +1,11 @@
1
+ import type { ITtscProjectMembershipPolicy } from "./tsconfigPaths.cjs";
2
+ /**
3
+ * Match configured root files or a directory that can contain one.
4
+ *
5
+ * This is discovery, not dependency membership: imports outside these specs
6
+ * remain compiler inputs and are proven by the external-input snapshot.
7
+ * TypeScript's include grammar has only *, ?, ** and implicit directory globs.
8
+ * Unknown policies stay permissive; no filesystem existence probe is needed, so
9
+ * a newly created directory receives the same answer as an existing one.
10
+ */
11
+ export declare function matchesProjectRootFile(location: string, policy: ITtscProjectMembershipPolicy, directory: boolean): boolean;
@@ -0,0 +1,11 @@
1
+ import type { ITtscProjectMembershipPolicy } from "./tsconfigPaths.mjs";
2
+ /**
3
+ * Match configured root files or a directory that can contain one.
4
+ *
5
+ * This is discovery, not dependency membership: imports outside these specs
6
+ * remain compiler inputs and are proven by the external-input snapshot.
7
+ * TypeScript's include grammar has only *, ?, ** and implicit directory globs.
8
+ * Unknown policies stay permissive; no filesystem existence probe is needed, so
9
+ * a newly created directory receives the same answer as an existing one.
10
+ */
11
+ export declare function matchesProjectRootFile(location: string, policy: ITtscProjectMembershipPolicy, directory: boolean): boolean;
@@ -0,0 +1,11 @@
1
+ import type { ITtscProjectMembershipPolicy } from "./tsconfigPaths";
2
+ /**
3
+ * Match configured root files or a directory that can contain one.
4
+ *
5
+ * This is discovery, not dependency membership: imports outside these specs
6
+ * remain compiler inputs and are proven by the external-input snapshot.
7
+ * TypeScript's include grammar has only *, ?, ** and implicit directory globs.
8
+ * Unknown policies stay permissive; no filesystem existence probe is needed, so
9
+ * a newly created directory receives the same answer as an existing one.
10
+ */
11
+ export declare function matchesProjectRootFile(location: string, policy: ITtscProjectMembershipPolicy, directory: boolean): boolean;
@@ -0,0 +1,136 @@
1
+ 'use strict';
2
+
3
+ var path = require('node:path');
4
+
5
+ const compiled = new WeakMap();
6
+ /**
7
+ * Match configured root files or a directory that can contain one.
8
+ *
9
+ * This is discovery, not dependency membership: imports outside these specs
10
+ * remain compiler inputs and are proven by the external-input snapshot.
11
+ * TypeScript's include grammar has only *, ?, ** and implicit directory globs.
12
+ * Unknown policies stay permissive; no filesystem existence probe is needed, so
13
+ * a newly created directory receives the same answer as an existing one.
14
+ */
15
+ function matchesProjectRootFile(location, policy, directory) {
16
+ if (policy.rootFileSpecs === undefined)
17
+ return true;
18
+ let patterns = compiled.get(policy);
19
+ if (patterns === undefined) {
20
+ patterns = [
21
+ ...policy.rootFileSpecs.files.map((spec) => compile(spec, true)),
22
+ ...policy.rootFileSpecs.include.map((spec) => compile(spec, false)),
23
+ ].filter((pattern) => pattern !== undefined);
24
+ compiled.set(policy, patterns);
25
+ }
26
+ return rootSpellings(location, policy).some((spelling) => {
27
+ const parts = spelling.replace(/\\/g, "/").split("/");
28
+ return patterns.some((pattern) => matches(parts, pattern, directory));
29
+ });
30
+ }
31
+ /**
32
+ * Config ancestry is anchored physically, but the walk retains lexical paths.
33
+ * Match each equivalent project-root spelling without following child links.
34
+ * Native Windows watchers expand short names even when regular realpath keeps
35
+ * them. Keep patterns intact: a glob can begin above the root, and configDir
36
+ * can retain the requested spelling even when ancestry uses the physical one.
37
+ */
38
+ function rootSpellings(location, policy) {
39
+ const resolved = path.resolve(location);
40
+ const root = policy.rootFileSpecs?.root;
41
+ if (root === undefined)
42
+ return [resolved];
43
+ const spellings = [
44
+ ...new Set([root.path, root.realpath, root.nativepath ?? root.realpath]),
45
+ ];
46
+ for (const spelling of spellings) {
47
+ const relative = path.relative(spelling, resolved);
48
+ if (relative !== ".." &&
49
+ !relative.startsWith(`..${path.sep}`) &&
50
+ !path.isAbsolute(relative))
51
+ return spellings.map((candidate) => path.resolve(candidate, relative));
52
+ }
53
+ return [resolved];
54
+ }
55
+ function compile(spec, literal) {
56
+ const parts = path.resolve(spec).replace(/\\/g, "/").split("/");
57
+ if (!literal) {
58
+ const last = parts.at(-1);
59
+ if (last === "**")
60
+ return undefined;
61
+ if (!/[.*?]/.test(last))
62
+ parts.push("**", "*");
63
+ }
64
+ return {
65
+ literal,
66
+ components: parts.map((part) => {
67
+ if (!literal && part === "**")
68
+ return part;
69
+ const wildcard = !literal && /[*?]/.test(part);
70
+ if (!wildcard && process.platform === "linux")
71
+ return part;
72
+ const expression = [...part]
73
+ .map((char) => wildcard && char === "*"
74
+ ? "[^/]*"
75
+ : wildcard && char === "?"
76
+ ? "[^/]"
77
+ : char.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&"))
78
+ .join("");
79
+ // Case folding on macOS is conservative on case-sensitive volumes.
80
+ // Unicode simple folding also belongs to literal components: lowercasing
81
+ // alone misses equivalences such as Greek sigma/final sigma in Go.
82
+ return {
83
+ expression: new RegExp(`^${wildcard && (part.startsWith("*") || part.startsWith("?")) ? "(?!\\.)" : ""}${expression}$`, process.platform === "linux" ? "u" : "iu"),
84
+ wildcard,
85
+ };
86
+ }),
87
+ };
88
+ }
89
+ /** Iterative glob-state traversal avoids recursion on deep directory trees. */
90
+ function matches(parts, pattern, directory) {
91
+ const { components } = pattern;
92
+ let states = new Set([0]);
93
+ const expand = () => {
94
+ for (const state of states) {
95
+ if (!pattern.literal && components[state] === "**")
96
+ states.add(state + 1);
97
+ }
98
+ };
99
+ for (const part of parts) {
100
+ expand();
101
+ const next = new Set();
102
+ for (const state of states) {
103
+ const component = components[state];
104
+ if (component === undefined)
105
+ continue;
106
+ if (!pattern.literal && component === "**") {
107
+ if (!part.startsWith(".") && !isPackageDirectory(part))
108
+ next.add(state);
109
+ }
110
+ else if (typeof component !== "string") {
111
+ if ((!component.wildcard || !isPackageDirectory(part)) &&
112
+ component.expression.test(part))
113
+ next.add(state + 1);
114
+ }
115
+ else if (component === part) {
116
+ next.add(state + 1);
117
+ }
118
+ }
119
+ if (next.size === 0)
120
+ return false;
121
+ states = next;
122
+ }
123
+ expand();
124
+ // A directory needs a remaining filename component, not just a completed
125
+ // exact-file match; otherwise `include: ["*.ts"]` would descend into a
126
+ // directory named `artifact.ts` and watch its unrelated children.
127
+ return directory
128
+ ? [...states].some((state) => state < components.length)
129
+ : states.has(components.length);
130
+ }
131
+ function isPackageDirectory(name) {
132
+ return /^(node_modules|bower_components|jspm_packages)$/i.test(name);
133
+ }
134
+
135
+ exports.matchesProjectRootFile = matchesProjectRootFile;
136
+ //# sourceMappingURL=projectRootFiles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectRootFiles.js","sources":["../../src/core/projectRootFiles.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
@@ -0,0 +1,134 @@
1
+ import path from 'node:path';
2
+
3
+ const compiled = new WeakMap();
4
+ /**
5
+ * Match configured root files or a directory that can contain one.
6
+ *
7
+ * This is discovery, not dependency membership: imports outside these specs
8
+ * remain compiler inputs and are proven by the external-input snapshot.
9
+ * TypeScript's include grammar has only *, ?, ** and implicit directory globs.
10
+ * Unknown policies stay permissive; no filesystem existence probe is needed, so
11
+ * a newly created directory receives the same answer as an existing one.
12
+ */
13
+ function matchesProjectRootFile(location, policy, directory) {
14
+ if (policy.rootFileSpecs === undefined)
15
+ return true;
16
+ let patterns = compiled.get(policy);
17
+ if (patterns === undefined) {
18
+ patterns = [
19
+ ...policy.rootFileSpecs.files.map((spec) => compile(spec, true)),
20
+ ...policy.rootFileSpecs.include.map((spec) => compile(spec, false)),
21
+ ].filter((pattern) => pattern !== undefined);
22
+ compiled.set(policy, patterns);
23
+ }
24
+ return rootSpellings(location, policy).some((spelling) => {
25
+ const parts = spelling.replace(/\\/g, "/").split("/");
26
+ return patterns.some((pattern) => matches(parts, pattern, directory));
27
+ });
28
+ }
29
+ /**
30
+ * Config ancestry is anchored physically, but the walk retains lexical paths.
31
+ * Match each equivalent project-root spelling without following child links.
32
+ * Native Windows watchers expand short names even when regular realpath keeps
33
+ * them. Keep patterns intact: a glob can begin above the root, and configDir
34
+ * can retain the requested spelling even when ancestry uses the physical one.
35
+ */
36
+ function rootSpellings(location, policy) {
37
+ const resolved = path.resolve(location);
38
+ const root = policy.rootFileSpecs?.root;
39
+ if (root === undefined)
40
+ return [resolved];
41
+ const spellings = [
42
+ ...new Set([root.path, root.realpath, root.nativepath ?? root.realpath]),
43
+ ];
44
+ for (const spelling of spellings) {
45
+ const relative = path.relative(spelling, resolved);
46
+ if (relative !== ".." &&
47
+ !relative.startsWith(`..${path.sep}`) &&
48
+ !path.isAbsolute(relative))
49
+ return spellings.map((candidate) => path.resolve(candidate, relative));
50
+ }
51
+ return [resolved];
52
+ }
53
+ function compile(spec, literal) {
54
+ const parts = path.resolve(spec).replace(/\\/g, "/").split("/");
55
+ if (!literal) {
56
+ const last = parts.at(-1);
57
+ if (last === "**")
58
+ return undefined;
59
+ if (!/[.*?]/.test(last))
60
+ parts.push("**", "*");
61
+ }
62
+ return {
63
+ literal,
64
+ components: parts.map((part) => {
65
+ if (!literal && part === "**")
66
+ return part;
67
+ const wildcard = !literal && /[*?]/.test(part);
68
+ if (!wildcard && process.platform === "linux")
69
+ return part;
70
+ const expression = [...part]
71
+ .map((char) => wildcard && char === "*"
72
+ ? "[^/]*"
73
+ : wildcard && char === "?"
74
+ ? "[^/]"
75
+ : char.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&"))
76
+ .join("");
77
+ // Case folding on macOS is conservative on case-sensitive volumes.
78
+ // Unicode simple folding also belongs to literal components: lowercasing
79
+ // alone misses equivalences such as Greek sigma/final sigma in Go.
80
+ return {
81
+ expression: new RegExp(`^${wildcard && (part.startsWith("*") || part.startsWith("?")) ? "(?!\\.)" : ""}${expression}$`, process.platform === "linux" ? "u" : "iu"),
82
+ wildcard,
83
+ };
84
+ }),
85
+ };
86
+ }
87
+ /** Iterative glob-state traversal avoids recursion on deep directory trees. */
88
+ function matches(parts, pattern, directory) {
89
+ const { components } = pattern;
90
+ let states = new Set([0]);
91
+ const expand = () => {
92
+ for (const state of states) {
93
+ if (!pattern.literal && components[state] === "**")
94
+ states.add(state + 1);
95
+ }
96
+ };
97
+ for (const part of parts) {
98
+ expand();
99
+ const next = new Set();
100
+ for (const state of states) {
101
+ const component = components[state];
102
+ if (component === undefined)
103
+ continue;
104
+ if (!pattern.literal && component === "**") {
105
+ if (!part.startsWith(".") && !isPackageDirectory(part))
106
+ next.add(state);
107
+ }
108
+ else if (typeof component !== "string") {
109
+ if ((!component.wildcard || !isPackageDirectory(part)) &&
110
+ component.expression.test(part))
111
+ next.add(state + 1);
112
+ }
113
+ else if (component === part) {
114
+ next.add(state + 1);
115
+ }
116
+ }
117
+ if (next.size === 0)
118
+ return false;
119
+ states = next;
120
+ }
121
+ expand();
122
+ // A directory needs a remaining filename component, not just a completed
123
+ // exact-file match; otherwise `include: ["*.ts"]` would descend into a
124
+ // directory named `artifact.ts` and watch its unrelated children.
125
+ return directory
126
+ ? [...states].some((state) => state < components.length)
127
+ : states.has(components.length);
128
+ }
129
+ function isPackageDirectory(name) {
130
+ return /^(node_modules|bower_components|jspm_packages)$/i.test(name);
131
+ }
132
+
133
+ export { matchesProjectRootFile };
134
+ //# sourceMappingURL=projectRootFiles.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectRootFiles.mjs","sources":["../../src/core/projectRootFiles.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
@@ -8,6 +8,7 @@ var path = require('node:path');
8
8
  var ttsc = require('ttsc');
9
9
  var pathIdentity = require('ttsc/path-identity');
10
10
  var projectDiscovery = require('./projectDiscovery.js');
11
+ var projectRootFiles = require('./projectRootFiles.js');
11
12
  var tsconfigPaths = require('./tsconfigPaths.js');
12
13
 
13
14
  const TTSC_SEMANTIC_CONFIG_PATH = "TTSC_SEMANTIC_CONFIG_PATH";
@@ -1577,6 +1578,20 @@ function matchesCachedSource(cached, file, source, epoch) {
1577
1578
  const expected = cached.sourceHashes?.[identity] ??
1578
1579
  cached.inputHashes[currentKey] ??
1579
1580
  cached.externalInputHashes?.[identity];
1581
+ if (expected === undefined &&
1582
+ cached.result.type === "success" &&
1583
+ !projectRootFiles.matchesProjectRootFile(file, cached.membershipPolicy, false)) {
1584
+ const state = envelopeDerivation(cached);
1585
+ const outputs = (state.outputIndex ??= createEnvelopeKeyIndex(state, cached.projectRoot, cached.result.typescript));
1586
+ if (!outputs.has(identity)) {
1587
+ // Root discovery deliberately never hashed this unrelated module. Its
1588
+ // bytes cannot affect an output the compiler did not produce, but the
1589
+ // whole program must still be current before we reuse that absence: a
1590
+ // changed config or importer can bring this file into the next program.
1591
+ refreshFilesystemClockReference(TRANSFORM_CLOCK_REFERENCE_DIRECTORIES.get(cached), resultFilesystem(cached.result));
1592
+ return matchesCompleteInputSnapshot(cached, currentKey, source);
1593
+ }
1594
+ }
1580
1595
  if (expected !== hashText(source)) {
1581
1596
  return false;
1582
1597
  }
@@ -3012,7 +3027,8 @@ function walkProjectInputs(root, filesystem = DEFAULT_FILESYSTEM_OPERATIONS, pol
3012
3027
  continue;
3013
3028
  }
3014
3029
  const file = path.join(current, entry.name);
3015
- if (entry.isDirectory() && isExcludedProjectDirectory(file, policy)) {
3030
+ if ((entry.isDirectory() && isExcludedProjectDirectory(file, policy)) ||
3031
+ !projectRootFiles.matchesProjectRootFile(file, policy, entry.isDirectory())) {
3016
3032
  continue;
3017
3033
  }
3018
3034
  const possible = isPossibleProgramEntry(entry, policy);
@@ -3317,31 +3333,29 @@ function insideExcludedProjectDirectory(location, policy, strictly) {
3317
3333
  * name the host did not report is unattributable and always counts.
3318
3334
  */
3319
3335
  function reportsProgramMembership(location, filename, policy, filesystem) {
3320
- if (isPossibleProgramFileName(filename, policy)) {
3321
- // A name the program could admit. It still says nothing if it lies inside a
3322
- // directory the walk never descends into, because the digest cannot see
3323
- // there either and the tracker must not be the one side that reacts.
3324
- return !insideExcludedProjectDirectory(location, policy, true);
3336
+ if (!projectRootFiles.matchesProjectRootFile(location, policy, false) &&
3337
+ !projectRootFiles.matchesProjectRootFile(location, policy, true)) {
3338
+ return false;
3325
3339
  }
3326
- let directory;
3327
3340
  try {
3328
- directory = filesystem.lstat(location).isDirectory();
3341
+ if (filesystem.lstat(location).isDirectory()) {
3342
+ return (projectRootFiles.matchesProjectRootFile(location, policy, true) &&
3343
+ !insideExcludedProjectDirectory(location, policy, false));
3344
+ }
3329
3345
  }
3330
3346
  catch {
3331
- // Gone again, or unreadable. Its name could not have been a program input,
3332
- // and a directory removed under this one reports its own contents leaving
3333
- // through the watch that was opened on it.
3334
- return false;
3347
+ // Deleted file names still need classification below.
3335
3348
  }
3336
- if (!directory) {
3337
- return false;
3349
+ if (isPossibleProgramFileName(filename, policy)) {
3350
+ // A name the program could admit. It still says nothing if it lies inside a
3351
+ // directory the walk never descends into, because the digest cannot see
3352
+ // there either and the tracker must not be the one side that reacts.
3353
+ return (projectRootFiles.matchesProjectRootFile(location, policy, false) &&
3354
+ !insideExcludedProjectDirectory(location, policy, true));
3338
3355
  }
3339
- // A directory counts, because it can hold sources and the tracker is not
3340
- // watching it yet, unless the configuration says the program does not contain
3341
- // it. Emptying and recreating an `outDir`, which is what `emptyOutDir` and
3342
- // `output.clean` do on every build, would otherwise void the generation once
3343
- // per build on every host that has no build boundary.
3344
- return !insideExcludedProjectDirectory(location, policy, false);
3356
+ // Removed directories report their source removals through their own watch.
3357
+ // A non-source file name cannot introduce program membership.
3358
+ return false;
3345
3359
  }
3346
3360
  /** Record enough exact mutation evidence without retaining an event stream. */
3347
3361
  function recordProjectMutation(tracker, changed) {
@@ -3742,7 +3756,8 @@ function isProjectWalkPath(root, file, _identities = createHostPathIdentityConte
3742
3756
  // a graph input the compiler really read in neither snapshot: absent from
3743
3757
  // `inputHashes` because the walk skipped it, and absent from the out-of-walk
3744
3758
  // snapshot because this predicate claimed the walk covered it.
3745
- if (!isPossibleProgramFileName(path.basename(file), policy)) {
3759
+ if (!isPossibleProgramFileName(path.basename(file), policy) ||
3760
+ !projectRootFiles.matchesProjectRootFile(file, policy, false)) {
3746
3761
  return false;
3747
3762
  }
3748
3763
  let current = resolvedRoot;