@williamthorsen/tsconfig 0.6.0 → 0.7.0
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/.readyup/kits/default.js +84 -4
- package/.readyup/manifest.json +17 -6
- package/README.md +6 -9
- package/package.json +2 -2
package/.readyup/kits/default.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
/** @noformat
|
|
1
|
+
/** @noformat -- @generated. Do not edit. Compiled by rdy. */
|
|
2
2
|
/* eslint-disable */
|
|
3
|
-
export const __readyupVersion = "0.
|
|
3
|
+
export const __readyupVersion = "0.35.0";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
// .readyup/kits/default.ts
|
|
@@ -71,6 +71,46 @@ function toStringArray(value) {
|
|
|
71
71
|
return value.filter((entry) => typeof entry === "string");
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
// src/readiness/findEscapingPaths.ts
|
|
75
|
+
import { dirname, join, relative } from "node:path/posix";
|
|
76
|
+
var CONFIG_DIR_TEMPLATE = "${configDir}";
|
|
77
|
+
var FIELDS = ["exclude", "files", "include"];
|
|
78
|
+
var ROOTED_PATH = /^(?:\/|[A-Za-z]:)/;
|
|
79
|
+
function findEscapingPaths(entries) {
|
|
80
|
+
const judged = entries[0];
|
|
81
|
+
if (judged === void 0) return [];
|
|
82
|
+
const judgedDir = dirname(judged.path);
|
|
83
|
+
return FIELDS.flatMap((field) => findEscapingPathsInField(entries, field, judgedDir));
|
|
84
|
+
}
|
|
85
|
+
function findDeclaringEntry(entries, field) {
|
|
86
|
+
for (const entry of entries) {
|
|
87
|
+
const declared = entry.config[field];
|
|
88
|
+
if (declared) return entry;
|
|
89
|
+
}
|
|
90
|
+
return void 0;
|
|
91
|
+
}
|
|
92
|
+
function findEscapingPathsInField(entries, field, judgedDir) {
|
|
93
|
+
const declaring = findDeclaringEntry(entries, field);
|
|
94
|
+
if (declaring === void 0) return [];
|
|
95
|
+
const declared = declaring.config[field];
|
|
96
|
+
if (!Array.isArray(declared)) return [];
|
|
97
|
+
const declaredDir = dirname(declaring.path);
|
|
98
|
+
return declared.filter((value) => typeof value === "string").flatMap((value) => {
|
|
99
|
+
const outward = findOutwardPath(value, declaredDir, judgedDir);
|
|
100
|
+
return outward === void 0 ? [] : [{ declaredIn: declaring.path, field, path: outward }];
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
function findOutwardPath(value, declaredDir, judgedDir) {
|
|
104
|
+
const normalized = value.split("\\").join("/");
|
|
105
|
+
if (ROOTED_PATH.test(normalized)) return normalized;
|
|
106
|
+
const resolved = startsWithConfigDir(normalized) ? join(judgedDir, normalized.slice(CONFIG_DIR_TEMPLATE.length)) : join(declaredDir, normalized);
|
|
107
|
+
const fromJudged = relative(judgedDir, resolved);
|
|
108
|
+
return fromJudged === ".." || fromJudged.startsWith("../") ? fromJudged : void 0;
|
|
109
|
+
}
|
|
110
|
+
function startsWithConfigDir(value) {
|
|
111
|
+
return value.slice(0, CONFIG_DIR_TEMPLATE.length).toLowerCase() === CONFIG_DIR_TEMPLATE.toLowerCase();
|
|
112
|
+
}
|
|
113
|
+
|
|
74
114
|
// src/readiness/findRedundantOptions.ts
|
|
75
115
|
import { isDeepStrictEqual } from "node:util";
|
|
76
116
|
function findRedundantOptions(entries, baseIndex) {
|
|
@@ -96,6 +136,11 @@ function collectDependencyDeclaredKeys(entries, baseIndex) {
|
|
|
96
136
|
return keys;
|
|
97
137
|
}
|
|
98
138
|
|
|
139
|
+
// src/readiness/listSearchDirs.ts
|
|
140
|
+
function listSearchDirs(workspaceDirs) {
|
|
141
|
+
return [.../* @__PURE__ */ new Set([".", ...workspaceDirs])];
|
|
142
|
+
}
|
|
143
|
+
|
|
99
144
|
// src/readiness/node-floor.ts
|
|
100
145
|
var NODE_MAJOR = /^v?(\d+)(?:[.\s]|$)/;
|
|
101
146
|
var NODE_MAJOR_CEILING = 99;
|
|
@@ -135,7 +180,7 @@ var cache = {
|
|
|
135
180
|
chains: /* @__PURE__ */ new Map()
|
|
136
181
|
};
|
|
137
182
|
var default_default = defineRdyKit({
|
|
138
|
-
description: `Adoption and
|
|
183
|
+
description: `Adoption, alignment, and hygiene checks for a project consuming ${PACKAGE_NAME}`,
|
|
139
184
|
defaultSeverity: "warn",
|
|
140
185
|
checklists: [
|
|
141
186
|
{
|
|
@@ -172,6 +217,17 @@ var default_default = defineRdyKit({
|
|
|
172
217
|
fix: "Raise engines.node to a major implementing the base's ES year: below it, code that typechecks fails at runtime"
|
|
173
218
|
}
|
|
174
219
|
]
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
name: "hygiene",
|
|
223
|
+
checks: [
|
|
224
|
+
{
|
|
225
|
+
name: "No tsconfig's include, exclude, or files names a path outside its own directory",
|
|
226
|
+
skip: skipUnlessSomeTsconfigWasFound,
|
|
227
|
+
check: noEscapingPaths,
|
|
228
|
+
fix: "Declare the field named above in the config that owns the directory, listing every path it needs, since a local declaration replaces the inherited one rather than merging and discards the default exclude of node_modules, bower_components, jspm_packages, and outDir; or prefix each path in the config being extended with ${configDir}, which resolves to the consuming config's directory"
|
|
229
|
+
}
|
|
230
|
+
]
|
|
175
231
|
}
|
|
176
232
|
]
|
|
177
233
|
});
|
|
@@ -188,6 +244,10 @@ function classifyTsconfig(path) {
|
|
|
188
244
|
function dedupe(values) {
|
|
189
245
|
return [...new Set(values)];
|
|
190
246
|
}
|
|
247
|
+
function describeEscape(configPath, escaping) {
|
|
248
|
+
const source = escaping.declaredIn === configPath ? "" : `, from ${escaping.declaredIn}`;
|
|
249
|
+
return `${escaping.field}: ${escaping.path}${source}`;
|
|
250
|
+
}
|
|
191
251
|
function everyEsYearMatchesTheBase() {
|
|
192
252
|
const baseEsYear = readBaseEsYear();
|
|
193
253
|
if (baseEsYear === void 0) return true;
|
|
@@ -256,12 +316,29 @@ function listPathsOfKind(classified, kind) {
|
|
|
256
316
|
return classified.filter((adoption) => adoption.kind === kind).map((adoption) => adoption.path);
|
|
257
317
|
}
|
|
258
318
|
function listTsconfigSearchDirs() {
|
|
259
|
-
return discoverWorkspaces().map((workspace) => workspace.dir);
|
|
319
|
+
return listSearchDirs(discoverWorkspaces().map((workspace) => workspace.dir));
|
|
260
320
|
}
|
|
261
321
|
function nodeFloorSupportsBaseEsYear() {
|
|
262
322
|
const verdict = judgeNodeFloor();
|
|
263
323
|
return verdict.kind === "skip" ? true : { ok: verdict.kind === "pass", detail: verdict.detail };
|
|
264
324
|
}
|
|
325
|
+
function noEscapingPaths() {
|
|
326
|
+
const judged = findTsconfigs().flatMap((path) => {
|
|
327
|
+
const chain = readChain(path);
|
|
328
|
+
return chain === void 0 ? [] : [{ escapes: findEscapingPaths(chain.entries), path }];
|
|
329
|
+
});
|
|
330
|
+
const offenders = judged.filter((judgedConfig) => judgedConfig.escapes.length > 0);
|
|
331
|
+
const progress = {
|
|
332
|
+
type: "fraction",
|
|
333
|
+
passedCount: judged.length - offenders.length,
|
|
334
|
+
count: judged.length
|
|
335
|
+
};
|
|
336
|
+
if (offenders.length === 0) return { ok: true, progress };
|
|
337
|
+
const details = offenders.flatMap(
|
|
338
|
+
(offender) => offender.escapes.map((escaping) => `${offender.path} (${describeEscape(offender.path, escaping)})`)
|
|
339
|
+
);
|
|
340
|
+
return { ok: false, detail: details.join(", "), progress };
|
|
341
|
+
}
|
|
265
342
|
function noRedundantOptions() {
|
|
266
343
|
const offenders = listAdoptedTsconfigs().flatMap(
|
|
267
344
|
(adoption) => findRedundantOptions(adoption.chain.entries, adoption.baseIndex).map(
|
|
@@ -302,6 +379,9 @@ function skipUnlessSomeTsconfigIsAccountable() {
|
|
|
302
379
|
if (classified.length === 0) return "no workspace tsconfig was found";
|
|
303
380
|
return classified.some((adoption) => adoption.kind !== "external-base") ? false : "every workspace tsconfig extends a base belonging to another package";
|
|
304
381
|
}
|
|
382
|
+
function skipUnlessSomeTsconfigWasFound() {
|
|
383
|
+
return findTsconfigs().length === 0 ? "no workspace tsconfig was found" : false;
|
|
384
|
+
}
|
|
305
385
|
export {
|
|
306
386
|
default_default as default
|
|
307
387
|
};
|
package/.readyup/manifest.json
CHANGED
|
@@ -4,13 +4,14 @@
|
|
|
4
4
|
{
|
|
5
5
|
"checklists": [
|
|
6
6
|
"adoption",
|
|
7
|
-
"alignment"
|
|
7
|
+
"alignment",
|
|
8
|
+
"hygiene"
|
|
8
9
|
],
|
|
9
|
-
"description": "Adoption and
|
|
10
|
+
"description": "Adoption, alignment, and hygiene checks for a project consuming @williamthorsen/tsconfig",
|
|
10
11
|
"esbuildVersion": "0.28.2",
|
|
11
12
|
"inputs": [
|
|
12
13
|
{
|
|
13
|
-
"hash": "
|
|
14
|
+
"hash": "f4ec4ffd",
|
|
14
15
|
"kind": "module",
|
|
15
16
|
"path": "kits/default.ts"
|
|
16
17
|
},
|
|
@@ -29,11 +30,21 @@
|
|
|
29
30
|
"kind": "module",
|
|
30
31
|
"path": "../src/readiness/es-year.ts"
|
|
31
32
|
},
|
|
33
|
+
{
|
|
34
|
+
"hash": "bfbb0002",
|
|
35
|
+
"kind": "module",
|
|
36
|
+
"path": "../src/readiness/findEscapingPaths.ts"
|
|
37
|
+
},
|
|
32
38
|
{
|
|
33
39
|
"hash": "acd6ba2b",
|
|
34
40
|
"kind": "module",
|
|
35
41
|
"path": "../src/readiness/findRedundantOptions.ts"
|
|
36
42
|
},
|
|
43
|
+
{
|
|
44
|
+
"hash": "30178e5c",
|
|
45
|
+
"kind": "module",
|
|
46
|
+
"path": "../src/readiness/listSearchDirs.ts"
|
|
47
|
+
},
|
|
37
48
|
{
|
|
38
49
|
"hash": "31b0fbf5",
|
|
39
50
|
"kind": "module",
|
|
@@ -42,10 +53,10 @@
|
|
|
42
53
|
],
|
|
43
54
|
"name": "default",
|
|
44
55
|
"path": "kits/default.js",
|
|
45
|
-
"readyupVersion": "0.
|
|
56
|
+
"readyupVersion": "0.35.0",
|
|
46
57
|
"source": "kits/default.ts",
|
|
47
|
-
"sourceHash": "
|
|
48
|
-
"targetHash": "
|
|
58
|
+
"sourceHash": "f4ec4ffd",
|
|
59
|
+
"targetHash": "2bcc6e9b"
|
|
49
60
|
}
|
|
50
61
|
]
|
|
51
62
|
}
|
package/README.md
CHANGED
|
@@ -3,17 +3,13 @@
|
|
|
3
3
|
Shared TypeScript base config for Node-only projects. Inlines the settings of [`@tsconfig/strictest`](https://www.npmjs.com/package/@tsconfig/strictest) and adds the Node and build options it leaves out, so a consuming repo declares only what is genuinely its own.
|
|
4
4
|
|
|
5
5
|
<!-- section:release-notes -->
|
|
6
|
-
## Release notes — v0.
|
|
6
|
+
## Release notes — v0.7.0 (2026-08-30)
|
|
7
7
|
|
|
8
8
|
### 🎉 Features
|
|
9
9
|
|
|
10
|
-
-
|
|
10
|
+
- Report an include, exclude, or files path outside a tsconfig's directory (#197)
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Both kits now take readyup's workspace list directly, dropping the root literal each carried to compensate for the older behavior.
|
|
15
|
-
|
|
16
|
-
Migration: A consumer running `rdy` against either kit upgrades `readyup` to 0.33.0 or later.
|
|
12
|
+
Adds a `hygiene` checklist to the `@williamthorsen/tsconfig` readiness kit, reporting at `warn` a workspace tsconfig whose effective `include`, `exclude`, or `files` names a path outside the directory holding it, whether that config declared the field itself or inherited it from a base.
|
|
17
13
|
<!-- /section:release-notes -->
|
|
18
14
|
|
|
19
15
|
## Installation
|
|
@@ -102,12 +98,13 @@ export default defineRdyConfig({
|
|
|
102
98
|
});
|
|
103
99
|
```
|
|
104
100
|
|
|
105
|
-
The
|
|
101
|
+
The `readyup >=0.33.0` optional peer names the version the kit is developed and tested against. Below 0.33.0, readyup does not report the repo root among a monorepo's workspaces, so the kit supplies the root itself and sweeps every member package alongside it.
|
|
106
102
|
|
|
107
|
-
The kit walks each workspace tsconfig's `extends` chain and reports
|
|
103
|
+
The kit walks each workspace tsconfig's `extends` chain and reports five things:
|
|
108
104
|
|
|
109
105
|
- **Adoption**: a tsconfig reaching neither this base nor a framework base. A tsconfig naming this base through a specifier that does not resolve is reported separately, as declared but not installed.
|
|
110
106
|
- **Re-declaration**: an option restated with the base's own value. A key that a framework base in the same chain also declares is exempt, since restating it is how a config wins against that base.
|
|
107
|
+
- **Escaping paths**: an `include`, `exclude`, or `files` path resolving outside the directory that holds the tsconfig. A config that is extended hands these fields down resolved against its own directory, so a package inheriting them is governed by paths pointing outside itself; the remedy is a complete local declaration, or `${configDir}` in the config being extended.
|
|
111
108
|
- **ES year**: a `target` or `lib` declaring a year other than the base's, read from the base you extend rather than from a constant compiled into the kit.
|
|
112
109
|
- **Node floor**: an `engines.node` below the major that implements that ES year. This is the one failure `tsc` cannot surface on its own, which is why it alone is an error.
|
|
113
110
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@williamthorsen/tsconfig",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Shared TypeScript base config for Node-only projects",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tsconfig",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@tsconfig/strictest": "2.0.8",
|
|
33
33
|
"esbuild": "0.28.2",
|
|
34
|
-
"readyup": "0.
|
|
34
|
+
"readyup": "0.35.0"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
37
|
"readyup": ">=0.33.0"
|