@effected/tsconfig-json 0.12.1 → 0.13.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/CompilerOptions.js +7 -7
- package/CompilerOptionsFromProgrammatic.js +1 -1
- package/README.md +5 -5
- package/ResolvedTsconfig.js +10 -10
- package/TsEnumCodec.js +7 -7
- package/TsconfigDiscovery.js +12 -0
- package/TsconfigJson.js +10 -11
- package/TsconfigLoader.js +16 -4
- package/index.d.ts +57 -35
- package/internal/extendsTarget.js +5 -5
- package/package.json +5 -4
package/CompilerOptions.js
CHANGED
|
@@ -3,7 +3,7 @@ import { Schema, SchemaTransformation } from "effect";
|
|
|
3
3
|
//#region src/CompilerOptions.ts
|
|
4
4
|
/**
|
|
5
5
|
* Case-insensitive literal-union decode; canonical lowercase encode. Module-
|
|
6
|
-
* internal
|
|
6
|
+
* internal — every exported enum schema below is built
|
|
7
7
|
* from it, but the helper itself is not part of the public surface.
|
|
8
8
|
*/
|
|
9
9
|
const caseInsensitiveLiterals = (literals) => Schema.String.pipe(Schema.decodeTo(Schema.Literals(literals), SchemaTransformation.transform({
|
|
@@ -12,7 +12,7 @@ const caseInsensitiveLiterals = (literals) => Schema.String.pipe(Schema.decodeTo
|
|
|
12
12
|
})));
|
|
13
13
|
/**
|
|
14
14
|
* `compilerOptions.target` — the ECMAScript target. `es5` is deprecated in TS
|
|
15
|
-
* 6.0; `es3` has no literal (
|
|
15
|
+
* 6.0; `es3` has no literal (a removed value — a `target: "es3"` value fails
|
|
16
16
|
* decode against this schema rather than silently passing through, since
|
|
17
17
|
* `target` itself is a live, typed field).
|
|
18
18
|
*
|
|
@@ -94,7 +94,7 @@ const ModuleDetection = caseInsensitiveLiterals([
|
|
|
94
94
|
]);
|
|
95
95
|
/**
|
|
96
96
|
* `compilerOptions.lib` member values — the complete TS 6.0.3 set, lowercase
|
|
97
|
-
* canonical
|
|
97
|
+
* canonical.
|
|
98
98
|
*
|
|
99
99
|
* @public
|
|
100
100
|
*/
|
|
@@ -215,10 +215,10 @@ const IgnoreDeprecations = Schema.Literals(["5.0", "6.0"]);
|
|
|
215
215
|
*/
|
|
216
216
|
const PluginEntry = Schema.StructWithRest(Schema.Struct({ name: Schema.String }), [Schema.Record(Schema.String, Schema.Unknown)]);
|
|
217
217
|
/**
|
|
218
|
-
* `compilerOptions`, decoded as every
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
218
|
+
* `compilerOptions`, decoded as every live boolean, string, path, array,
|
|
219
|
+
* record, number and enum field — each `optionalKey` — intersected with a
|
|
220
|
+
* passthrough record so unknown and removed keys survive decode and re-encode
|
|
221
|
+
* untouched, which keeps the schema tolerant of newer compiler options.
|
|
222
222
|
*
|
|
223
223
|
* @public
|
|
224
224
|
*/
|
|
@@ -14,7 +14,7 @@ const encodeOut = (encoded) => TsEnumCodec.encodeCompilerOptions(encoded);
|
|
|
14
14
|
* the three in one object, and `lib` entries in any of their three spellings
|
|
15
15
|
* (`"esnext"`, `"lib.esnext.d.ts"`, an absolute path to the lib file) — producing
|
|
16
16
|
* validated {@link (CompilerOptions:namespace).Type} with canonical lowercase enum
|
|
17
|
-
* strings and short-form `lib`. Unknown and
|
|
17
|
+
* strings and short-form `lib`. Unknown and removed keys pass through, exactly as
|
|
18
18
|
* {@link (CompilerOptions:variable)} itself allows. Decoding is idempotent on
|
|
19
19
|
* already-canonical input.
|
|
20
20
|
*
|
package/README.md
CHANGED
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
|
|
8
8
|
Composable tsconfig.json handling for Effect: document and compiler-option schemas, `extends`-chain resolution with tsc's own merge semantics, nearest-config discovery and a portable-config filter for virtual TypeScript environments. Every parse is JSONC — comments and trailing commas are legal everywhere, exactly as tsc treats them — and options the schemas do not know pass through decode and encode untouched instead of being dropped.
|
|
9
9
|
|
|
10
|
-
> **Pre
|
|
11
|
-
>
|
|
12
|
-
> `1.0.0`
|
|
13
|
-
>
|
|
10
|
+
> **Pre-`1.0.0`.** This package is part of the `@effected/*` kit, built on stable
|
|
11
|
+
> Effect v4 (`effect` `^4.0.0`) and still in `0.x` development. Stable Effect
|
|
12
|
+
> makes a kit `1.0.0` possible, not automatic. To keep your `effect` and
|
|
13
|
+
> `@effect/*` versions on the line the kit is built and tested against, install
|
|
14
14
|
> [`@effected/pnpm-plugin-effect`](https://www.npmjs.com/package/@effected/pnpm-plugin-effect).
|
|
15
15
|
>
|
|
16
16
|
> **Stability: unstable.** This package's API surface is not yet considered
|
|
@@ -39,7 +39,7 @@ Requires Node.js >=24.11.0. `effect` v4, `@effected/jsonc` and `@effected/walker
|
|
|
39
39
|
|
|
40
40
|
All `@effected/*` packages are ESM-only: the exports maps publish only `import` conditions, so `require()` — including tools that resolve in CJS mode — fails with Node's `ERR_PACKAGE_PATH_NOT_EXPORTED` rather than loading a CJS build that does not exist. Import from an ES module.
|
|
41
41
|
|
|
42
|
-
All IO goes through `FileSystem` and `Path` from `effect` core, not a platform package, so a consumer provides them once at the edge (`@effect/platform-node` on Node, `@effect/platform-bun` on Bun) and a test provides `Path.layer`
|
|
42
|
+
All IO goes through `FileSystem` and `Path` from `effect` core, not a platform package, so a consumer provides them once at the edge (`@effect/platform-node` on Node, `@effect/platform-bun` on Bun) and a test provides core's `Path.layer` plus an in-memory volume from `@effected/memfs` — no platform package installed.
|
|
43
43
|
|
|
44
44
|
## Quick start
|
|
45
45
|
|
package/ResolvedTsconfig.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//#region src/ResolvedTsconfig.ts
|
|
2
2
|
const CONFIG_DIR_TEMPLATE = `\${configDir}`;
|
|
3
3
|
const CONFIG_DIR_TEMPLATE_LOWER = CONFIG_DIR_TEMPLATE.toLowerCase();
|
|
4
|
-
/** A value is `${configDir}`-prefixed if its leading token matches case-insensitively
|
|
4
|
+
/** A value is `${configDir}`-prefixed if its leading token matches case-insensitively. */
|
|
5
5
|
const startsWithConfigDir = (value) => value.slice(0, CONFIG_DIR_TEMPLATE.length).toLowerCase() === CONFIG_DIR_TEMPLATE_LOWER;
|
|
6
6
|
const normalizeSlashes = (p) => p.replace(/\\/g, "/");
|
|
7
7
|
/** POSIX `dirname` over the normalized path; a rootless path yields `"."`. */
|
|
@@ -51,10 +51,10 @@ const PATH_STRING_KEYS = [
|
|
|
51
51
|
];
|
|
52
52
|
const PATH_LIST_KEYS = ["typeRoots", "rootDirs"];
|
|
53
53
|
/**
|
|
54
|
-
* Apply `transform` to every path-typed compilerOptions surface: the
|
|
54
|
+
* Apply `transform` to every path-typed compilerOptions surface: the path
|
|
55
55
|
* strings and path lists, and — when `includePathsValues` — the `paths` record's
|
|
56
|
-
* values (
|
|
57
|
-
* verbatim). Non-string values pass through untouched (forward tolerance).
|
|
56
|
+
* values (the final `${configDir}` phase substitutes those; the parse phase
|
|
57
|
+
* leaves them verbatim). Non-string values pass through untouched (forward tolerance).
|
|
58
58
|
*/
|
|
59
59
|
const transformCompilerOptionPaths = (co, transform, includePathsValues) => {
|
|
60
60
|
const out = { ...co };
|
|
@@ -119,7 +119,7 @@ const extractPassthrough = (source, consumed) => {
|
|
|
119
119
|
}
|
|
120
120
|
return out;
|
|
121
121
|
};
|
|
122
|
-
/** Re-root one inherited `files`/`include`/`exclude` entry, exempting absolute and `${configDir}` entries
|
|
122
|
+
/** Re-root one inherited `files`/`include`/`exclude` entry, exempting absolute and `${configDir}` entries. */
|
|
123
123
|
const rerootEntry = (prefix, entry) => {
|
|
124
124
|
if (startsWithConfigDir(entry) || isAbsolutePath(entry)) return entry;
|
|
125
125
|
return prefix === "" ? entry : `${prefix}/${entry}`;
|
|
@@ -211,25 +211,25 @@ const substituteConfigDir = (resolved, finalDir) => {
|
|
|
211
211
|
var ResolvedTsconfig = class {
|
|
212
212
|
constructor() {}
|
|
213
213
|
/**
|
|
214
|
-
* Absolutize a config's path-typed options
|
|
214
|
+
* Absolutize a config's path-typed options against its own
|
|
215
215
|
* `configDir`, using the injected `join` (`Path.Path.resolve` at the call
|
|
216
216
|
* site — so an already-absolute value is preserved). `${configDir}`-prefixed
|
|
217
217
|
* values are exempt (resolved later, in
|
|
218
218
|
* {@link (ResolvedTsconfig:class).substituteConfigDir}), and `paths`
|
|
219
219
|
* VALUES stay verbatim. Only `compilerOptions` path surfaces are touched;
|
|
220
|
-
* `files`/`include`/`exclude` are re-rooted at merge time instead
|
|
220
|
+
* `files`/`include`/`exclude` are re-rooted at merge time instead.
|
|
221
221
|
*/
|
|
222
222
|
static absolutize = absolutize;
|
|
223
223
|
/**
|
|
224
|
-
* Fold one more-derived config onto the accumulated base
|
|
225
|
-
* winning. The loader
|
|
224
|
+
* Fold one more-derived config onto the accumulated base, derived
|
|
225
|
+
* winning. The loader applies this across the resolution chain,
|
|
226
226
|
* own config last. `derivedPath` is the derived config's absolute
|
|
227
227
|
* normalized path, from which the re-rooting frame and `pathsBase` are
|
|
228
228
|
* computed.
|
|
229
229
|
*/
|
|
230
230
|
static merge = merge;
|
|
231
231
|
/**
|
|
232
|
-
* The
|
|
232
|
+
* The final phase: replace a leading `${configDir}` token
|
|
233
233
|
* (case-insensitive, leading position only) with `finalDir` — the
|
|
234
234
|
* top-level extending config's directory — across every eligible
|
|
235
235
|
* surface: compilerOptions path options, `paths` values,
|
package/TsEnumCodec.js
CHANGED
|
@@ -2,9 +2,9 @@ import { Option } from "effect";
|
|
|
2
2
|
|
|
3
3
|
//#region src/TsEnumCodec.ts
|
|
4
4
|
/**
|
|
5
|
-
* Builds a family's forward/reverse maps from its
|
|
5
|
+
* Builds a family's forward/reverse maps from its row order. The
|
|
6
6
|
* reverse map overwrites on every duplicate value, so the last-listed name
|
|
7
|
-
* for a value is canonical
|
|
7
|
+
* for a value is canonical.
|
|
8
8
|
*/
|
|
9
9
|
const buildTable = (rows) => {
|
|
10
10
|
const forward = /* @__PURE__ */ new Map();
|
|
@@ -101,7 +101,7 @@ const normalizeLibReference = (lib) => {
|
|
|
101
101
|
const withoutPrefix = base.startsWith("lib.") ? base.slice(4) : base;
|
|
102
102
|
return withoutPrefix.endsWith(".d.ts") ? withoutPrefix.slice(0, -5) : withoutPrefix;
|
|
103
103
|
};
|
|
104
|
-
/** `compilerOptions` keys whose values are one of the
|
|
104
|
+
/** `compilerOptions` keys whose values are one of the enum families. */
|
|
105
105
|
const COMPILER_OPTION_ENUM_KEYS = [
|
|
106
106
|
["target", "target"],
|
|
107
107
|
["module", "module"],
|
|
@@ -139,7 +139,7 @@ const decodeCompilerOptions = (numeric) => {
|
|
|
139
139
|
};
|
|
140
140
|
/**
|
|
141
141
|
* The string↔numeric enum codec for `compilerOptions` / `watchOptions`
|
|
142
|
-
* families
|
|
142
|
+
* families. Plain data: every lookup is a synchronous map read
|
|
143
143
|
* returning `Option.Option`, never a thrown error.
|
|
144
144
|
*
|
|
145
145
|
* @public
|
|
@@ -169,8 +169,8 @@ var TsEnumCodec = class {
|
|
|
169
169
|
/**
|
|
170
170
|
* Encodes a decoded `compilerOptions` object into the
|
|
171
171
|
* numeric-enum-shaped {@link ProgrammaticCompilerOptions} form
|
|
172
|
-
* `ts.CompilerOptions` (and `@typescript/vfs`'s
|
|
173
|
-
* every
|
|
172
|
+
* `ts.CompilerOptions` (and `@typescript/vfs`'s virtual environment) expect:
|
|
173
|
+
* every enum family becomes its numeric value, and `lib` entries
|
|
174
174
|
* become the file-name form (`lib.esnext.d.ts`) — see the module banner
|
|
175
175
|
* for the evidence. Every other key (booleans, strings, arrays, unknown
|
|
176
176
|
* passthrough keys) is copied through untouched.
|
|
@@ -189,7 +189,7 @@ var TsEnumCodec = class {
|
|
|
189
189
|
* Decodes a numeric-enum-shaped `compilerOptions` object (as produced by
|
|
190
190
|
* {@link TsEnumCodec.encodeCompilerOptions} or read off a live
|
|
191
191
|
* `ts.CompilerOptions`) back into the string-enum shape this package's
|
|
192
|
-
* schemas use: every
|
|
192
|
+
* schemas use: every enum family becomes its canonical string, and
|
|
193
193
|
* `lib` entries become the short form. A numeric value with no table
|
|
194
194
|
* entry — a future TS enum member — is left as-is (passthrough, never an
|
|
195
195
|
* error) — which is why the return type stays the wider
|
package/TsconfigDiscovery.js
CHANGED
|
@@ -11,6 +11,18 @@ const findNearest = (start, options) => Effect.gen(function* () {
|
|
|
11
11
|
/**
|
|
12
12
|
* Nearest-config upward discovery for `tsconfig.json`.
|
|
13
13
|
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { TsconfigDiscovery } from "@effected/tsconfig-json";
|
|
17
|
+
* import { Effect, Option } from "effect";
|
|
18
|
+
*
|
|
19
|
+
* // Requires `FileSystem` and `Path` in `R`; provide them from a platform layer.
|
|
20
|
+
* const program = Effect.gen(function* () {
|
|
21
|
+
* const found = yield* TsconfigDiscovery.findNearest(process.cwd());
|
|
22
|
+
* return Option.getOrUndefined(found);
|
|
23
|
+
* });
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
14
26
|
* @public
|
|
15
27
|
*/
|
|
16
28
|
var TsconfigDiscovery = class {
|
package/TsconfigJson.js
CHANGED
|
@@ -38,14 +38,14 @@ const FallbackPolling = caseInsensitiveLiterals([
|
|
|
38
38
|
]);
|
|
39
39
|
/**
|
|
40
40
|
* One `references[]` entry: `path` is required and non-empty; every other key
|
|
41
|
-
* is preserved verbatim
|
|
41
|
+
* is preserved verbatim.
|
|
42
42
|
*
|
|
43
43
|
* @public
|
|
44
44
|
*/
|
|
45
45
|
const Reference = Schema.StructWithRest(Schema.Struct({ path: Schema.String.check(Schema.isMinLength(1)) }), [Schema.Record(Schema.String, Schema.Unknown)]);
|
|
46
46
|
/**
|
|
47
|
-
* `watchOptions` — the three enum fields
|
|
48
|
-
*
|
|
47
|
+
* `watchOptions` — the three enum fields, the two live booleans/arrays,
|
|
48
|
+
* and a passthrough record (schemastore's `force` is phantom).
|
|
49
49
|
*
|
|
50
50
|
* @public
|
|
51
51
|
*/
|
|
@@ -58,7 +58,7 @@ const WatchOptions = Schema.StructWithRest(Schema.Struct({
|
|
|
58
58
|
excludeFiles: Schema.optionalKey(Schema.Array(Schema.String))
|
|
59
59
|
}), [Schema.Record(Schema.String, Schema.Unknown)]);
|
|
60
60
|
/**
|
|
61
|
-
* `typeAcquisition` —
|
|
61
|
+
* `typeAcquisition` — the automatic type-acquisition settings, with unknown keys preserved.
|
|
62
62
|
*
|
|
63
63
|
* @public
|
|
64
64
|
*/
|
|
@@ -69,7 +69,7 @@ const TypeAcquisition = Schema.StructWithRest(Schema.Struct({
|
|
|
69
69
|
disableFilenameBasedTypeAcquisition: Schema.optionalKey(Schema.Boolean)
|
|
70
70
|
}), [Schema.Record(Schema.String, Schema.Unknown)]);
|
|
71
71
|
/**
|
|
72
|
-
* The tsconfig.json document: every typed top-level field
|
|
72
|
+
* The tsconfig.json document: every typed top-level field optional,
|
|
73
73
|
* plus a passthrough record so unrecognized keys (`buildOptions`, `ts-node`,
|
|
74
74
|
* …) survive decode and re-encode untouched — tsc itself silently ignores
|
|
75
75
|
* unknown top-level keys, and this schema follows suit.
|
|
@@ -91,10 +91,9 @@ const TsconfigJson = Schema.StructWithRest(Schema.Struct({
|
|
|
91
91
|
/**
|
|
92
92
|
* Decodes a JSONC-encoded tsconfig.json document straight into
|
|
93
93
|
* {@link (TsconfigJson:variable)}. Bound once at module top level —
|
|
94
|
-
* `Jsonc.schema` is schema-producing, and this is the shared instance
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
* static).
|
|
94
|
+
* `Jsonc.schema` is schema-producing, and this is the shared instance
|
|
95
|
+
* (`TsconfigJson` is a `Schema.StructWithRest` value rather than a
|
|
96
|
+
* `Schema.Class`, so the codec is a sibling export, not a static).
|
|
98
97
|
*
|
|
99
98
|
* @public
|
|
100
99
|
*/
|
|
@@ -102,8 +101,8 @@ const TsconfigJsonFromString = Jsonc.schema(TsconfigJson);
|
|
|
102
101
|
/**
|
|
103
102
|
* Raised when a tsconfig.json document fails to parse or decode. `path` is
|
|
104
103
|
* the file path when the failure is file-bound, and the empty string
|
|
105
|
-
* otherwise (e.g. decoding an in-memory string).
|
|
106
|
-
* file-bound decode failures in this error
|
|
104
|
+
* otherwise (e.g. decoding an in-memory string). `TsconfigLoader` wraps
|
|
105
|
+
* file-bound decode failures in this error.
|
|
107
106
|
*
|
|
108
107
|
* @public
|
|
109
108
|
*/
|
package/TsconfigLoader.js
CHANGED
|
@@ -132,6 +132,18 @@ const compilerOptions = Effect.fn("TsconfigLoader.compilerOptions")(function* (c
|
|
|
132
132
|
* merge -\> `${configDir}` pipeline, and {@link TsconfigLoader.compilerOptions}
|
|
133
133
|
* projects the resolved result down to its merged `compilerOptions`.
|
|
134
134
|
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```ts
|
|
137
|
+
* import { TsconfigLoader } from "@effected/tsconfig-json";
|
|
138
|
+
* import { Effect } from "effect";
|
|
139
|
+
*
|
|
140
|
+
* // Requires `FileSystem` and `Path` in `R`; provide them from a platform layer.
|
|
141
|
+
* const program = Effect.gen(function* () {
|
|
142
|
+
* const resolved = yield* TsconfigLoader.resolve("./tsconfig.json");
|
|
143
|
+
* return resolved.compilerOptions.target;
|
|
144
|
+
* });
|
|
145
|
+
* ```
|
|
146
|
+
*
|
|
135
147
|
* @public
|
|
136
148
|
*/
|
|
137
149
|
var TsconfigLoader = class {
|
|
@@ -147,10 +159,10 @@ var TsconfigLoader = class {
|
|
|
147
159
|
/**
|
|
148
160
|
* Resolve a tsconfig.json and its full `extends` chain into a
|
|
149
161
|
* {@link (ResolvedTsconfig:interface)}: load and decode each config,
|
|
150
|
-
* absolutize its path options
|
|
151
|
-
* per-branch cycle and depth guards
|
|
152
|
-
* own-config-last
|
|
153
|
-
* against the top config's directory
|
|
162
|
+
* absolutize its path options, resolve `extends` depth-first with
|
|
163
|
+
* per-branch cycle and depth guards, fold the chain
|
|
164
|
+
* own-config-last, then substitute a leading `${configDir}` once
|
|
165
|
+
* against the top config's directory. `configPath` +
|
|
154
166
|
* `extendedPaths` come back base-most first, own config last. Every
|
|
155
167
|
* failure is a typed error — `TsconfigParseError` (a malformed file,
|
|
156
168
|
* carrying that file's path), `TsconfigExtendsError` (a broken chain), or
|
package/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Effect, FileSystem, Option, Path, PlatformError, Schema } from "effect"
|
|
|
2
2
|
//#region src/CompilerOptions.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* `compilerOptions.target` — the ECMAScript target. `es5` is deprecated in TS
|
|
5
|
-
* 6.0; `es3` has no literal (
|
|
5
|
+
* 6.0; `es3` has no literal (a removed value — a `target: "es3"` value fails
|
|
6
6
|
* decode against this schema rather than silently passing through, since
|
|
7
7
|
* `target` itself is a live, typed field).
|
|
8
8
|
*
|
|
@@ -36,16 +36,16 @@ export declare const NewLine: Schema.decodeTo<Schema.Literals<readonly ["crlf",
|
|
|
36
36
|
export declare const ModuleDetection: Schema.decodeTo<Schema.Literals<readonly ["auto", "legacy", "force"]>, Schema.String, never, never>;
|
|
37
37
|
/**
|
|
38
38
|
* `compilerOptions.lib` member values — the complete TS 6.0.3 set, lowercase
|
|
39
|
-
* canonical
|
|
39
|
+
* canonical.
|
|
40
40
|
*
|
|
41
41
|
* @public
|
|
42
42
|
*/
|
|
43
43
|
export declare const Lib: Schema.decodeTo<Schema.Literals<readonly ["es5", "es6", "es7", "es2015", "es2016", "es2017", "es2018", "es2019", "es2020", "es2021", "es2022", "es2023", "es2024", "es2025", "esnext", "dom", "dom.iterable", "dom.asynciterable", "webworker", "webworker.importscripts", "webworker.iterable", "webworker.asynciterable", "scripthost", "es2015.core", "es2015.collection", "es2015.generator", "es2015.iterable", "es2015.promise", "es2015.proxy", "es2015.reflect", "es2015.symbol", "es2015.symbol.wellknown", "es2016.array.include", "es2016.intl", "es2017.arraybuffer", "es2017.date", "es2017.object", "es2017.sharedmemory", "es2017.string", "es2017.intl", "es2017.typedarrays", "es2018.asyncgenerator", "es2018.asynciterable", "es2018.intl", "es2018.promise", "es2018.regexp", "es2019.array", "es2019.object", "es2019.string", "es2019.symbol", "es2019.intl", "es2020.bigint", "es2020.date", "es2020.promise", "es2020.sharedmemory", "es2020.string", "es2020.symbol.wellknown", "es2020.intl", "es2020.number", "es2021.promise", "es2021.string", "es2021.weakref", "es2021.intl", "es2022.array", "es2022.error", "es2022.intl", "es2022.object", "es2022.string", "es2022.regexp", "es2023.array", "es2023.collection", "es2023.intl", "es2024.arraybuffer", "es2024.collection", "es2024.object", "es2024.promise", "es2024.regexp", "es2024.sharedmemory", "es2024.string", "es2025.collection", "es2025.float16", "es2025.intl", "es2025.iterator", "es2025.promise", "es2025.regexp", "esnext.asynciterable", "esnext.symbol", "esnext.bigint", "esnext.weakref", "esnext.object", "esnext.regexp", "esnext.string", "esnext.float16", "esnext.iterator", "esnext.promise", "esnext.array", "esnext.collection", "esnext.date", "esnext.decorators", "esnext.disposable", "esnext.error", "esnext.intl", "esnext.sharedmemory", "esnext.temporal", "esnext.typedarrays", "decorators", "decorators.legacy"]>, Schema.String, never, never>;
|
|
44
44
|
/**
|
|
45
|
-
* `compilerOptions`, decoded as every
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
45
|
+
* `compilerOptions`, decoded as every live boolean, string, path, array,
|
|
46
|
+
* record, number and enum field — each `optionalKey` — intersected with a
|
|
47
|
+
* passthrough record so unknown and removed keys survive decode and re-encode
|
|
48
|
+
* untouched, which keeps the schema tolerant of newer compiler options.
|
|
49
49
|
*
|
|
50
50
|
* @public
|
|
51
51
|
*/
|
|
@@ -212,7 +212,7 @@ interface ProgrammaticRecord {
|
|
|
212
212
|
* the three in one object, and `lib` entries in any of their three spellings
|
|
213
213
|
* (`"esnext"`, `"lib.esnext.d.ts"`, an absolute path to the lib file) — producing
|
|
214
214
|
* validated {@link (CompilerOptions:namespace).Type} with canonical lowercase enum
|
|
215
|
-
* strings and short-form `lib`. Unknown and
|
|
215
|
+
* strings and short-form `lib`. Unknown and removed keys pass through, exactly as
|
|
216
216
|
* {@link (CompilerOptions:variable)} itself allows. Decoding is idempotent on
|
|
217
217
|
* already-canonical input.
|
|
218
218
|
*
|
|
@@ -280,7 +280,7 @@ export declare const WatchDirectory: Schema.decodeTo<Schema.Literals<readonly ["
|
|
|
280
280
|
export declare const FallbackPolling: Schema.decodeTo<Schema.Literals<readonly ["fixedinterval", "priorityinterval", "dynamicpriority", "fixedchunksize"]>, Schema.String, never, never>;
|
|
281
281
|
/**
|
|
282
282
|
* One `references[]` entry: `path` is required and non-empty; every other key
|
|
283
|
-
* is preserved verbatim
|
|
283
|
+
* is preserved verbatim.
|
|
284
284
|
*
|
|
285
285
|
* @public
|
|
286
286
|
*/
|
|
@@ -307,8 +307,8 @@ export declare namespace Reference {
|
|
|
307
307
|
type Encoded = typeof Reference.Encoded;
|
|
308
308
|
}
|
|
309
309
|
/**
|
|
310
|
-
* `watchOptions` — the three enum fields
|
|
311
|
-
*
|
|
310
|
+
* `watchOptions` — the three enum fields, the two live booleans/arrays,
|
|
311
|
+
* and a passthrough record (schemastore's `force` is phantom).
|
|
312
312
|
*
|
|
313
313
|
* @public
|
|
314
314
|
*/
|
|
@@ -340,7 +340,7 @@ export declare namespace WatchOptions {
|
|
|
340
340
|
type Encoded = typeof WatchOptions.Encoded;
|
|
341
341
|
}
|
|
342
342
|
/**
|
|
343
|
-
* `typeAcquisition` —
|
|
343
|
+
* `typeAcquisition` — the automatic type-acquisition settings, with unknown keys preserved.
|
|
344
344
|
*
|
|
345
345
|
* @public
|
|
346
346
|
*/
|
|
@@ -370,7 +370,7 @@ export declare namespace TypeAcquisition {
|
|
|
370
370
|
type Encoded = typeof TypeAcquisition.Encoded;
|
|
371
371
|
}
|
|
372
372
|
/**
|
|
373
|
-
* The tsconfig.json document: every typed top-level field
|
|
373
|
+
* The tsconfig.json document: every typed top-level field optional,
|
|
374
374
|
* plus a passthrough record so unrecognized keys (`buildOptions`, `ts-node`,
|
|
375
375
|
* …) survive decode and re-encode untouched — tsc itself silently ignores
|
|
376
376
|
* unknown top-level keys, and this schema follows suit.
|
|
@@ -539,10 +539,9 @@ export declare namespace TsconfigJson {
|
|
|
539
539
|
/**
|
|
540
540
|
* Decodes a JSONC-encoded tsconfig.json document straight into
|
|
541
541
|
* {@link (TsconfigJson:variable)}. Bound once at module top level —
|
|
542
|
-
* `Jsonc.schema` is schema-producing, and this is the shared instance
|
|
543
|
-
*
|
|
544
|
-
*
|
|
545
|
-
* static).
|
|
542
|
+
* `Jsonc.schema` is schema-producing, and this is the shared instance
|
|
543
|
+
* (`TsconfigJson` is a `Schema.StructWithRest` value rather than a
|
|
544
|
+
* `Schema.Class`, so the codec is a sibling export, not a static).
|
|
546
545
|
*
|
|
547
546
|
* @public
|
|
548
547
|
*/
|
|
@@ -556,8 +555,8 @@ declare const TsconfigParseError_base: Schema.Class<TsconfigParseError, Schema.T
|
|
|
556
555
|
/**
|
|
557
556
|
* Raised when a tsconfig.json document fails to parse or decode. `path` is
|
|
558
557
|
* the file path when the failure is file-bound, and the empty string
|
|
559
|
-
* otherwise (e.g. decoding an in-memory string).
|
|
560
|
-
* file-bound decode failures in this error
|
|
558
|
+
* otherwise (e.g. decoding an in-memory string). `TsconfigLoader` wraps
|
|
559
|
+
* file-bound decode failures in this error.
|
|
561
560
|
*
|
|
562
561
|
* @public
|
|
563
562
|
*/
|
|
@@ -568,7 +567,7 @@ export declare class TsconfigParseError extends TsconfigParseError_base {
|
|
|
568
567
|
//#region src/ResolvedTsconfig.d.ts
|
|
569
568
|
/**
|
|
570
569
|
* The result of resolving a tsconfig.json's full `extends` chain: the merged
|
|
571
|
-
* compiler options and inherited settings, flattened
|
|
570
|
+
* compiler options and inherited settings, flattened the way tsc does, with enough
|
|
572
571
|
* provenance for the consumer (`configPath`, `extendedPaths`, and `pathsBase`,
|
|
573
572
|
* the directory of the config that declared `paths`). Unknown top-level keys
|
|
574
573
|
* survive as passthrough via the index signature.
|
|
@@ -596,7 +595,7 @@ export interface ResolvedTsconfig {
|
|
|
596
595
|
readonly typeAcquisition?: TypeAcquisition.Type;
|
|
597
596
|
/** `compileOnSave`, inherited only when own is undefined and the inherited value is truthy. */
|
|
598
597
|
readonly compileOnSave?: boolean;
|
|
599
|
-
/** The directory of the config that declared `paths
|
|
598
|
+
/** The directory of the config that declared `paths`, against which `paths` values resolve. */
|
|
600
599
|
readonly pathsBase?: string;
|
|
601
600
|
/** Unknown top-level keys, preserved through the merge (forward tolerance). */
|
|
602
601
|
readonly [key: string]: unknown;
|
|
@@ -612,25 +611,25 @@ export interface ResolvedTsconfig {
|
|
|
612
611
|
export declare class ResolvedTsconfig {
|
|
613
612
|
private constructor();
|
|
614
613
|
/**
|
|
615
|
-
* Absolutize a config's path-typed options
|
|
614
|
+
* Absolutize a config's path-typed options against its own
|
|
616
615
|
* `configDir`, using the injected `join` (`Path.Path.resolve` at the call
|
|
617
616
|
* site — so an already-absolute value is preserved). `${configDir}`-prefixed
|
|
618
617
|
* values are exempt (resolved later, in
|
|
619
618
|
* {@link (ResolvedTsconfig:class).substituteConfigDir}), and `paths`
|
|
620
619
|
* VALUES stay verbatim. Only `compilerOptions` path surfaces are touched;
|
|
621
|
-
* `files`/`include`/`exclude` are re-rooted at merge time instead
|
|
620
|
+
* `files`/`include`/`exclude` are re-rooted at merge time instead.
|
|
622
621
|
*/
|
|
623
622
|
static readonly absolutize: (doc: TsconfigJson.Type, configDir: string, join: (a: string, b: string) => string) => TsconfigJson.Type;
|
|
624
623
|
/**
|
|
625
|
-
* Fold one more-derived config onto the accumulated base
|
|
626
|
-
* winning. The loader
|
|
624
|
+
* Fold one more-derived config onto the accumulated base, derived
|
|
625
|
+
* winning. The loader applies this across the resolution chain,
|
|
627
626
|
* own config last. `derivedPath` is the derived config's absolute
|
|
628
627
|
* normalized path, from which the re-rooting frame and `pathsBase` are
|
|
629
628
|
* computed.
|
|
630
629
|
*/
|
|
631
630
|
static readonly merge: (base: ResolvedTsconfig, derived: TsconfigJson.Type, derivedPath: string) => ResolvedTsconfig;
|
|
632
631
|
/**
|
|
633
|
-
* The
|
|
632
|
+
* The final phase: replace a leading `${configDir}` token
|
|
634
633
|
* (case-insensitive, leading position only) with `finalDir` — the
|
|
635
634
|
* top-level extending config's directory — across every eligible
|
|
636
635
|
* surface: compilerOptions path options, `paths` values,
|
|
@@ -729,6 +728,18 @@ interface FindNearestOptions {
|
|
|
729
728
|
/**
|
|
730
729
|
* Nearest-config upward discovery for `tsconfig.json`.
|
|
731
730
|
*
|
|
731
|
+
* @example
|
|
732
|
+
* ```ts
|
|
733
|
+
* import { TsconfigDiscovery } from "@effected/tsconfig-json";
|
|
734
|
+
* import { Effect, Option } from "effect";
|
|
735
|
+
*
|
|
736
|
+
* // Requires `FileSystem` and `Path` in `R`; provide them from a platform layer.
|
|
737
|
+
* const program = Effect.gen(function* () {
|
|
738
|
+
* const found = yield* TsconfigDiscovery.findNearest(process.cwd());
|
|
739
|
+
* return Option.getOrUndefined(found);
|
|
740
|
+
* });
|
|
741
|
+
* ```
|
|
742
|
+
*
|
|
732
743
|
* @public
|
|
733
744
|
*/
|
|
734
745
|
export declare class TsconfigDiscovery {
|
|
@@ -775,6 +786,18 @@ export declare class TsconfigExtendsError extends TsconfigExtendsError_base {
|
|
|
775
786
|
* merge -\> `${configDir}` pipeline, and {@link TsconfigLoader.compilerOptions}
|
|
776
787
|
* projects the resolved result down to its merged `compilerOptions`.
|
|
777
788
|
*
|
|
789
|
+
* @example
|
|
790
|
+
* ```ts
|
|
791
|
+
* import { TsconfigLoader } from "@effected/tsconfig-json";
|
|
792
|
+
* import { Effect } from "effect";
|
|
793
|
+
*
|
|
794
|
+
* // Requires `FileSystem` and `Path` in `R`; provide them from a platform layer.
|
|
795
|
+
* const program = Effect.gen(function* () {
|
|
796
|
+
* const resolved = yield* TsconfigLoader.resolve("./tsconfig.json");
|
|
797
|
+
* return resolved.compilerOptions.target;
|
|
798
|
+
* });
|
|
799
|
+
* ```
|
|
800
|
+
*
|
|
778
801
|
* @public
|
|
779
802
|
*/
|
|
780
803
|
export declare class TsconfigLoader {
|
|
@@ -936,10 +959,10 @@ export declare class TsconfigLoader {
|
|
|
936
959
|
/**
|
|
937
960
|
* Resolve a tsconfig.json and its full `extends` chain into a
|
|
938
961
|
* {@link (ResolvedTsconfig:interface)}: load and decode each config,
|
|
939
|
-
* absolutize its path options
|
|
940
|
-
* per-branch cycle and depth guards
|
|
941
|
-
* own-config-last
|
|
942
|
-
* against the top config's directory
|
|
962
|
+
* absolutize its path options, resolve `extends` depth-first with
|
|
963
|
+
* per-branch cycle and depth guards, fold the chain
|
|
964
|
+
* own-config-last, then substitute a leading `${configDir}` once
|
|
965
|
+
* against the top config's directory. `configPath` +
|
|
943
966
|
* `extendedPaths` come back base-most first, own config last. Every
|
|
944
967
|
* failure is a typed error — `TsconfigParseError` (a malformed file,
|
|
945
968
|
* carrying that file's path), `TsconfigExtendsError` (a broken chain), or
|
|
@@ -1200,8 +1223,7 @@ export declare class TsconfigLoaderSync {
|
|
|
1200
1223
|
//#endregion
|
|
1201
1224
|
//#region src/TsEnumCodec.d.ts
|
|
1202
1225
|
/**
|
|
1203
|
-
* The nine `compilerOptions` / `watchOptions` enum families this codec knows
|
|
1204
|
-
* per R1.6.
|
|
1226
|
+
* The nine `compilerOptions` / `watchOptions` enum families this codec knows.
|
|
1205
1227
|
*
|
|
1206
1228
|
* @public
|
|
1207
1229
|
*/
|
|
@@ -1290,7 +1312,7 @@ interface ProgrammaticCompilerOptions {
|
|
|
1290
1312
|
}
|
|
1291
1313
|
/**
|
|
1292
1314
|
* The string↔numeric enum codec for `compilerOptions` / `watchOptions`
|
|
1293
|
-
* families
|
|
1315
|
+
* families. Plain data: every lookup is a synchronous map read
|
|
1294
1316
|
* returning `Option.Option`, never a thrown error.
|
|
1295
1317
|
*
|
|
1296
1318
|
* @public
|
|
@@ -1320,8 +1342,8 @@ export declare class TsEnumCodec {
|
|
|
1320
1342
|
/**
|
|
1321
1343
|
* Encodes a decoded `compilerOptions` object into the
|
|
1322
1344
|
* numeric-enum-shaped {@link ProgrammaticCompilerOptions} form
|
|
1323
|
-
* `ts.CompilerOptions` (and `@typescript/vfs`'s
|
|
1324
|
-
* every
|
|
1345
|
+
* `ts.CompilerOptions` (and `@typescript/vfs`'s virtual environment) expect:
|
|
1346
|
+
* every enum family becomes its numeric value, and `lib` entries
|
|
1325
1347
|
* become the file-name form (`lib.esnext.d.ts`) — see the module banner
|
|
1326
1348
|
* for the evidence. Every other key (booleans, strings, arrays, unknown
|
|
1327
1349
|
* passthrough keys) is copied through untouched.
|
|
@@ -1340,7 +1362,7 @@ export declare class TsEnumCodec {
|
|
|
1340
1362
|
* Decodes a numeric-enum-shaped `compilerOptions` object (as produced by
|
|
1341
1363
|
* {@link TsEnumCodec.encodeCompilerOptions} or read off a live
|
|
1342
1364
|
* `ts.CompilerOptions`) back into the string-enum shape this package's
|
|
1343
|
-
* schemas use: every
|
|
1365
|
+
* schemas use: every enum family becomes its canonical string, and
|
|
1344
1366
|
* `lib` entries become the short form. A numeric value with no table
|
|
1345
1367
|
* entry — a future TS enum member — is left as-is (passthrough, never an
|
|
1346
1368
|
* error) — which is why the return type stays the wider
|
|
@@ -4,8 +4,8 @@ import { Jsonc } from "@effected/jsonc";
|
|
|
4
4
|
|
|
5
5
|
//#region src/internal/extendsTarget.ts
|
|
6
6
|
/**
|
|
7
|
-
* The `extends` target-resolution engine (
|
|
8
|
-
* node_modules lookup). Every input reaching {@link resolveExports} is an
|
|
7
|
+
* The `extends` target-resolution engine (relative/rooted specifiers and the bare-specifier
|
|
8
|
+
* `node_modules` lookup). Every input reaching {@link resolveExports} is an
|
|
9
9
|
* untrusted `package.json` `exports` map, so every recursive surface carries a
|
|
10
10
|
* depth guard, every untrusted map read goes through `Object.hasOwn`, dunder
|
|
11
11
|
* keys are skipped, and substituted maps are built with `Object.create(null)` —
|
|
@@ -155,7 +155,7 @@ const readManifest = (fs, manifestPath) => Effect.gen(function* () {
|
|
|
155
155
|
/** Read an own property of an untrusted record, guarding dunder keys and inherited members. */
|
|
156
156
|
const ownProp = (record, key) => !DUNDER_KEYS.has(key) && Object.hasOwn(record, key) ? record[key] : void 0;
|
|
157
157
|
/**
|
|
158
|
-
* Resolve
|
|
158
|
+
* Resolve relative/rooted targets: the exact file wins verbatim (even
|
|
159
159
|
* extensionless); otherwise, if the target does not already end in `.json`, the
|
|
160
160
|
* `.json`-appended path is tried. There is no directory fallback.
|
|
161
161
|
*/
|
|
@@ -206,8 +206,8 @@ const tryCandidate = (fs, path, dir, pkg, subpath) => Effect.gen(function* () {
|
|
|
206
206
|
});
|
|
207
207
|
/**
|
|
208
208
|
* Resolve an `extends` target to an absolute config path. Relative and rooted
|
|
209
|
-
* specifiers
|
|
210
|
-
* specifiers
|
|
209
|
+
* specifiers resolve against the extending config's directory; bare
|
|
210
|
+
* specifiers walk up the ancestor `node_modules` chain, skipping ancestors
|
|
211
211
|
* named `node_modules`, and resolve against the first package found.
|
|
212
212
|
*
|
|
213
213
|
* Absence is `Option.none()`; a malformed manifest is coerced to an empty one
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effected/tsconfig-json",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Composable tsconfig.json handling for Effect: schemas, extends-chain resolution, and config discovery.",
|
|
6
6
|
"keywords": [
|
|
@@ -39,9 +39,10 @@
|
|
|
39
39
|
"./package.json": "./package.json"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"@effected/
|
|
43
|
-
"@effected/
|
|
44
|
-
"
|
|
42
|
+
"@effected/glob": "^0.10.0",
|
|
43
|
+
"@effected/jsonc": "^0.15.0",
|
|
44
|
+
"@effected/walker": "^0.15.0",
|
|
45
|
+
"effect": "^4.0.0"
|
|
45
46
|
},
|
|
46
47
|
"engines": {
|
|
47
48
|
"node": ">=24.11.0"
|