@williamthorsen/tsconfig 0.6.1 → 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 +77 -2
- package/.readyup/manifest.json +12 -6
- package/README.md +6 -5
- package/package.json +2 -2
package/.readyup/kits/default.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
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) {
|
|
@@ -140,7 +180,7 @@ var cache = {
|
|
|
140
180
|
chains: /* @__PURE__ */ new Map()
|
|
141
181
|
};
|
|
142
182
|
var default_default = defineRdyKit({
|
|
143
|
-
description: `Adoption and
|
|
183
|
+
description: `Adoption, alignment, and hygiene checks for a project consuming ${PACKAGE_NAME}`,
|
|
144
184
|
defaultSeverity: "warn",
|
|
145
185
|
checklists: [
|
|
146
186
|
{
|
|
@@ -177,6 +217,17 @@ var default_default = defineRdyKit({
|
|
|
177
217
|
fix: "Raise engines.node to a major implementing the base's ES year: below it, code that typechecks fails at runtime"
|
|
178
218
|
}
|
|
179
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
|
+
]
|
|
180
231
|
}
|
|
181
232
|
]
|
|
182
233
|
});
|
|
@@ -193,6 +244,10 @@ function classifyTsconfig(path) {
|
|
|
193
244
|
function dedupe(values) {
|
|
194
245
|
return [...new Set(values)];
|
|
195
246
|
}
|
|
247
|
+
function describeEscape(configPath, escaping) {
|
|
248
|
+
const source = escaping.declaredIn === configPath ? "" : `, from ${escaping.declaredIn}`;
|
|
249
|
+
return `${escaping.field}: ${escaping.path}${source}`;
|
|
250
|
+
}
|
|
196
251
|
function everyEsYearMatchesTheBase() {
|
|
197
252
|
const baseEsYear = readBaseEsYear();
|
|
198
253
|
if (baseEsYear === void 0) return true;
|
|
@@ -267,6 +322,23 @@ function nodeFloorSupportsBaseEsYear() {
|
|
|
267
322
|
const verdict = judgeNodeFloor();
|
|
268
323
|
return verdict.kind === "skip" ? true : { ok: verdict.kind === "pass", detail: verdict.detail };
|
|
269
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
|
+
}
|
|
270
342
|
function noRedundantOptions() {
|
|
271
343
|
const offenders = listAdoptedTsconfigs().flatMap(
|
|
272
344
|
(adoption) => findRedundantOptions(adoption.chain.entries, adoption.baseIndex).map(
|
|
@@ -307,6 +379,9 @@ function skipUnlessSomeTsconfigIsAccountable() {
|
|
|
307
379
|
if (classified.length === 0) return "no workspace tsconfig was found";
|
|
308
380
|
return classified.some((adoption) => adoption.kind !== "external-base") ? false : "every workspace tsconfig extends a base belonging to another package";
|
|
309
381
|
}
|
|
382
|
+
function skipUnlessSomeTsconfigWasFound() {
|
|
383
|
+
return findTsconfigs().length === 0 ? "no workspace tsconfig was found" : false;
|
|
384
|
+
}
|
|
310
385
|
export {
|
|
311
386
|
default_default as default
|
|
312
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,6 +30,11 @@
|
|
|
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",
|
|
@@ -47,10 +53,10 @@
|
|
|
47
53
|
],
|
|
48
54
|
"name": "default",
|
|
49
55
|
"path": "kits/default.js",
|
|
50
|
-
"readyupVersion": "0.
|
|
56
|
+
"readyupVersion": "0.35.0",
|
|
51
57
|
"source": "kits/default.ts",
|
|
52
|
-
"sourceHash": "
|
|
53
|
-
"targetHash": "
|
|
58
|
+
"sourceHash": "f4ec4ffd",
|
|
59
|
+
"targetHash": "2bcc6e9b"
|
|
54
60
|
}
|
|
55
61
|
]
|
|
56
62
|
}
|
package/README.md
CHANGED
|
@@ -3,13 +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
|
-
|
|
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.
|
|
13
13
|
<!-- /section:release-notes -->
|
|
14
14
|
|
|
15
15
|
## Installation
|
|
@@ -100,10 +100,11 @@ export default defineRdyConfig({
|
|
|
100
100
|
|
|
101
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.
|
|
102
102
|
|
|
103
|
-
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:
|
|
104
104
|
|
|
105
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.
|
|
106
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.
|
|
107
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.
|
|
108
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.
|
|
109
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"
|