@effected/tsconfig-json 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/CompilerOptionsFromProgrammatic.js +52 -0
- package/README.md +2 -1
- package/index.d.ts +54 -1
- package/index.js +3 -2
- package/package.json +2 -2
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { CompilerOptions } from "./CompilerOptions.js";
|
|
2
|
+
import { TsEnumCodec } from "./TsEnumCodec.js";
|
|
3
|
+
import { Schema, SchemaTransformation } from "effect";
|
|
4
|
+
|
|
5
|
+
//#region src/CompilerOptionsFromProgrammatic.ts
|
|
6
|
+
const normalizeIn = (input) => TsEnumCodec.decodeCompilerOptions(input);
|
|
7
|
+
const encodeOut = (encoded) => TsEnumCodec.encodeCompilerOptions(encoded);
|
|
8
|
+
/**
|
|
9
|
+
* A codec between the **programmatic** `compilerOptions` shape TypeScript's own
|
|
10
|
+
* API uses and this package's decoded {@link (CompilerOptions:namespace).Type}.
|
|
11
|
+
*
|
|
12
|
+
* Decoding accepts the numeric-enum spelling (`{ target: ts.ScriptTarget.ES2025 }`),
|
|
13
|
+
* the canonical string spelling, case-varying strings (`"ESNext"`), any mixture of
|
|
14
|
+
* the three in one object, and `lib` entries in any of their three spellings
|
|
15
|
+
* (`"esnext"`, `"lib.esnext.d.ts"`, an absolute path to the lib file) — producing
|
|
16
|
+
* validated {@link (CompilerOptions:namespace).Type} with canonical lowercase enum
|
|
17
|
+
* strings and short-form `lib`. Unknown and dead keys pass through, exactly as
|
|
18
|
+
* {@link (CompilerOptions:variable)} itself allows. Decoding is idempotent on
|
|
19
|
+
* already-canonical input.
|
|
20
|
+
*
|
|
21
|
+
* Encoding is {@link TsEnumCodec.encodeCompilerOptions}: numeric enum values and
|
|
22
|
+
* `lib` in the file-name form (`lib.esnext.d.ts`).
|
|
23
|
+
*
|
|
24
|
+
* @remarks
|
|
25
|
+
* A numeric value with no table entry — a future TypeScript enum member — survives
|
|
26
|
+
* normalization as a number and then **fails decode** with a typed schema issue,
|
|
27
|
+
* rather than passing through. That is deliberate: this is the validating door
|
|
28
|
+
* {@link TsEnumCodec.decodeCompilerOptions} is not, which is why that function's
|
|
29
|
+
* return type stays the wider `Record<string, unknown>`.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* import { Schema } from "effect";
|
|
34
|
+
* import { CompilerOptionsFromProgrammatic } from "@effected/tsconfig-json";
|
|
35
|
+
*
|
|
36
|
+
* // { target: "es2025", strict: true, lib: ["esnext"] }
|
|
37
|
+
* Schema.decodeUnknownSync(CompilerOptionsFromProgrammatic)({
|
|
38
|
+
* target: 12,
|
|
39
|
+
* strict: true,
|
|
40
|
+
* lib: ["lib.esnext.d.ts"],
|
|
41
|
+
* });
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @public
|
|
45
|
+
*/
|
|
46
|
+
const CompilerOptionsFromProgrammatic = Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.decodeTo(CompilerOptions, SchemaTransformation.transform({
|
|
47
|
+
decode: normalizeIn,
|
|
48
|
+
encode: encodeOut
|
|
49
|
+
})));
|
|
50
|
+
|
|
51
|
+
//#endregion
|
|
52
|
+
export { CompilerOptionsFromProgrammatic };
|
package/README.md
CHANGED
|
@@ -114,7 +114,7 @@ const compilerOptions = TsconfigLoaderSync.compilerOptions("./tsconfig.json", op
|
|
|
114
114
|
TypeScript 7's native `tsc` ships a version-only stub as its `.` export — there is no JS compiler API behind it. A package that drives the typechecker as a library (`@typescript/vfs`, the language service, the Program API) can neither type against nor runtime-load a TypeScript 7 install, and the obvious fix of pinning the dev `typescript` back to 6 forfeits the native `tsc` and leaves toolchain peers on `^7` unmet. The recipe that keeps both starts here, because this package is what removes the compile-time half of the dependency.
|
|
115
115
|
|
|
116
116
|
1. Type against the tsconfig JSON form, not the compiler. Public option types use `CompilerOptions.Type` — `{ target: "es2022" }`, strings all the way down — so nothing in `src` or the tests imports `typescript`, not even as a type. The dev `typescript` stays on 7, native `tsc --noEmit` still runs the typecheck, and the toolchain's `^7` peer stays satisfied.
|
|
117
|
-
2. Convert at a single runtime seam. `TsEnumCodec.encodeCompilerOptions` maps the string form to the numeric enums a real compiler expects and returns `ProgrammaticCompilerOptions`, the shape a `ts.CompilerOptions`-typed API takes without a cast. Only that one call site knows a compiler exists.
|
|
117
|
+
2. Convert at a single runtime seam. `TsEnumCodec.encodeCompilerOptions` maps the string form to the numeric enums a real compiler expects and returns `ProgrammaticCompilerOptions`, the shape a `ts.CompilerOptions`-typed API takes without a cast. Only that one call site knows a compiler exists. The inbound direction is `CompilerOptionsFromProgrammatic`, a schema rather than a function: hand it a live `ts.CompilerOptions`, a numeric enum literal or the output of `encodeCompilerOptions` and validated `CompilerOptions.Type` comes back, with an unmappable numeric failing decode instead of leaking through.
|
|
118
118
|
3. Alias a classic install for the test runtime, where the JS API is genuinely needed: a dev-only `"typescript-classic": "npm:typescript@^6.0.3"` plus a vitest `resolve.alias` mapping `typescript` to it. The consumer-facing peer stays an optional `^6` — runtime-only, for callers of the compiler-touching module.
|
|
119
119
|
4. Pass `tsLibDirectory` explicitly when you drive `@typescript/vfs`. It locates `lib.*.d.ts` through `require.resolve("typescript")`, which under this setup resolves the TypeScript 7 install, and that install has no lib directory: the map comes back **empty**, silently, with no error to follow. Derive the directory from the module you actually loaded.
|
|
120
120
|
|
|
@@ -159,6 +159,7 @@ console.log(fsMap.size);
|
|
|
159
159
|
- `ResolvedTsconfig` — the pure merge engine behind `resolve`: per-field merge semantics, path-option absolutization against the declaring config's directory, final `${configDir}` substitution and `pathsBase` provenance, with no filesystem access at all.
|
|
160
160
|
- `TsconfigDiscovery.findNearest` — the nearest `tsconfig.json` (or any filename via `options.filename`) at or above a starting directory, over `@effected/walker`; one unreadable ancestor cannot hide a config above it.
|
|
161
161
|
- `TsEnumCodec` — the string↔numeric enum tables as plain data with zero `typescript` imports. `encodeCompilerOptions` returns the exported `ProgrammaticCompilerOptions` type — the numeric shape `ts.CompilerOptions` expects, so you hand it to a `ts.CompilerOptions`-shaped API without a cast — with `lib` entries in the file-name form the compiler resolves verbatim; `decodeCompilerOptions` reverses it.
|
|
162
|
+
- `CompilerOptionsFromProgrammatic` — the same tables as a validating codec, for callers holding TypeScript's programmatic spelling. Decode accepts numeric enums, canonical strings, case-varying strings, any mixture of the three and `lib` in any of its three spellings; encode returns the numeric form. A numeric with no table entry fails decode as a typed schema issue rather than passing through, which is the check `TsEnumCodec.decodeCompilerOptions` deliberately does not make.
|
|
162
163
|
- `PortableTsconfig.make` — an allow-list projection down to machine-independent type-semantics options, with `composite: false` and `noEmit: true` forced: the slice a virtual TypeScript environment (Twoslash, API Extractor, an in-memory language service) can safely inherit. An optional `{ includeTypes }` argument carries the source config's `types` package names onto the portable shape too, for a caller whose virtual environment can resolve `@types` packages itself; `typeRoots` stays dropped either way, since it names machine-specific, config-location-dependent directories.
|
|
163
164
|
- `JsxConfig.fromCompilerOptions` — the JSX transform a bundler can configure, projected from decoded options: `react-jsx` / `react-jsxdev` select the automatic runtime with its import source (defaulting to `react`, tsc's own default), `react` selects classic, and `preserve`, `react-native` or an absent `jsx` yield `Option.none()`.
|
|
164
165
|
- Typed failures everywhere: a malformed file is a `TsconfigParseError` carrying its path, a broken chain is a `TsconfigExtendsError` with a `not-found` / `cycle` / `depth` / `empty` reason and the full resolution chain, and IO errors flow through as `PlatformError`. Nothing fails as a defect.
|
package/index.d.ts
CHANGED
|
@@ -190,6 +190,59 @@ declare namespace CompilerOptions {
|
|
|
190
190
|
type Encoded = typeof CompilerOptions.Encoded;
|
|
191
191
|
}
|
|
192
192
|
//#endregion
|
|
193
|
+
//#region src/CompilerOptionsFromProgrammatic.d.ts
|
|
194
|
+
/**
|
|
195
|
+
* The untyped record this codec accepts on its encoded side. Exported because
|
|
196
|
+
* it names the codec's encoded type in the public signature; the values stay
|
|
197
|
+
* `unknown` rather than {@link ProgrammaticCompilerOptionsValue} because decode
|
|
198
|
+
* validates them and must be able to receive anything, including the
|
|
199
|
+
* unmappable numeric it exists to reject.
|
|
200
|
+
*
|
|
201
|
+
* @public
|
|
202
|
+
*/
|
|
203
|
+
interface ProgrammaticRecord {
|
|
204
|
+
readonly [key: string]: unknown;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* A codec between the **programmatic** `compilerOptions` shape TypeScript's own
|
|
208
|
+
* API uses and this package's decoded {@link (CompilerOptions:namespace).Type}.
|
|
209
|
+
*
|
|
210
|
+
* Decoding accepts the numeric-enum spelling (`{ target: ts.ScriptTarget.ES2025 }`),
|
|
211
|
+
* the canonical string spelling, case-varying strings (`"ESNext"`), any mixture of
|
|
212
|
+
* the three in one object, and `lib` entries in any of their three spellings
|
|
213
|
+
* (`"esnext"`, `"lib.esnext.d.ts"`, an absolute path to the lib file) — producing
|
|
214
|
+
* validated {@link (CompilerOptions:namespace).Type} with canonical lowercase enum
|
|
215
|
+
* strings and short-form `lib`. Unknown and dead keys pass through, exactly as
|
|
216
|
+
* {@link (CompilerOptions:variable)} itself allows. Decoding is idempotent on
|
|
217
|
+
* already-canonical input.
|
|
218
|
+
*
|
|
219
|
+
* Encoding is {@link TsEnumCodec.encodeCompilerOptions}: numeric enum values and
|
|
220
|
+
* `lib` in the file-name form (`lib.esnext.d.ts`).
|
|
221
|
+
*
|
|
222
|
+
* @remarks
|
|
223
|
+
* A numeric value with no table entry — a future TypeScript enum member — survives
|
|
224
|
+
* normalization as a number and then **fails decode** with a typed schema issue,
|
|
225
|
+
* rather than passing through. That is deliberate: this is the validating door
|
|
226
|
+
* {@link TsEnumCodec.decodeCompilerOptions} is not, which is why that function's
|
|
227
|
+
* return type stays the wider `Record<string, unknown>`.
|
|
228
|
+
*
|
|
229
|
+
* @example
|
|
230
|
+
* ```ts
|
|
231
|
+
* import { Schema } from "effect";
|
|
232
|
+
* import { CompilerOptionsFromProgrammatic } from "@effected/tsconfig-json";
|
|
233
|
+
*
|
|
234
|
+
* // { target: "es2025", strict: true, lib: ["esnext"] }
|
|
235
|
+
* Schema.decodeUnknownSync(CompilerOptionsFromProgrammatic)({
|
|
236
|
+
* target: 12,
|
|
237
|
+
* strict: true,
|
|
238
|
+
* lib: ["lib.esnext.d.ts"],
|
|
239
|
+
* });
|
|
240
|
+
* ```
|
|
241
|
+
*
|
|
242
|
+
* @public
|
|
243
|
+
*/
|
|
244
|
+
declare const CompilerOptionsFromProgrammatic: Schema.Codec<typeof CompilerOptions.Type, ProgrammaticRecord>;
|
|
245
|
+
//#endregion
|
|
193
246
|
//#region src/JsxConfig.d.ts
|
|
194
247
|
declare const JsxConfig_base: Schema.Class<JsxConfig, Schema.Struct<{
|
|
195
248
|
/** The JSX transform runtime: `"automatic"` (`react-jsx` / `react-jsxdev`) or `"classic"` (`react`). */
|
|
@@ -1299,5 +1352,5 @@ declare class TsEnumCodec {
|
|
|
1299
1352
|
static readonly decodeCompilerOptions: (numeric: Readonly<Record<string, unknown>>) => Record<string, unknown>;
|
|
1300
1353
|
}
|
|
1301
1354
|
//#endregion
|
|
1302
|
-
export { CompilerOptions, type EnumFamily, FallbackPolling, type FindNearestOptions, Jsx, JsxConfig, Lib, Module, ModuleDetection, ModuleResolution, NewLine, PortableTsconfig, type PortableTsconfigOptions, type ProgrammaticCompilerOptions, type ProgrammaticCompilerOptionsValue, Reference, ResolvedTsconfig, type SyncFileSystem, type SyncPath, Target, TsEnumCodec, TsconfigDiscovery, TsconfigExtendsError, TsconfigJson, TsconfigJsonFromString, TsconfigLoader, TsconfigLoaderSync, type TsconfigLoaderSyncOptions, TsconfigParseError, TypeAcquisition, WatchDirectory, WatchFile, WatchOptions };
|
|
1355
|
+
export { CompilerOptions, CompilerOptionsFromProgrammatic, type EnumFamily, FallbackPolling, type FindNearestOptions, Jsx, JsxConfig, Lib, Module, ModuleDetection, ModuleResolution, NewLine, PortableTsconfig, type PortableTsconfigOptions, type ProgrammaticCompilerOptions, type ProgrammaticCompilerOptionsValue, type ProgrammaticRecord, Reference, ResolvedTsconfig, type SyncFileSystem, type SyncPath, Target, TsEnumCodec, TsconfigDiscovery, TsconfigExtendsError, TsconfigJson, TsconfigJsonFromString, TsconfigLoader, TsconfigLoaderSync, type TsconfigLoaderSyncOptions, TsconfigParseError, TypeAcquisition, WatchDirectory, WatchFile, WatchOptions };
|
|
1303
1356
|
//# sourceMappingURL=index.d.ts.map
|
package/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { CompilerOptions, Jsx, Lib, Module, ModuleDetection, ModuleResolution, NewLine, Target } from "./CompilerOptions.js";
|
|
2
|
+
import { TsEnumCodec } from "./TsEnumCodec.js";
|
|
3
|
+
import { CompilerOptionsFromProgrammatic } from "./CompilerOptionsFromProgrammatic.js";
|
|
2
4
|
import { JsxConfig } from "./JsxConfig.js";
|
|
3
5
|
import { PortableTsconfig } from "./PortableTsconfig.js";
|
|
4
6
|
import { ResolvedTsconfig } from "./ResolvedTsconfig.js";
|
|
@@ -6,6 +8,5 @@ import { TsconfigDiscovery } from "./TsconfigDiscovery.js";
|
|
|
6
8
|
import { FallbackPolling, Reference, TsconfigJson, TsconfigJsonFromString, TsconfigParseError, TypeAcquisition, WatchDirectory, WatchFile, WatchOptions } from "./TsconfigJson.js";
|
|
7
9
|
import { TsconfigExtendsError, TsconfigLoader } from "./TsconfigLoader.js";
|
|
8
10
|
import { TsconfigLoaderSync } from "./TsconfigLoaderSync.js";
|
|
9
|
-
import { TsEnumCodec } from "./TsEnumCodec.js";
|
|
10
11
|
|
|
11
|
-
export { CompilerOptions, FallbackPolling, Jsx, JsxConfig, Lib, Module, ModuleDetection, ModuleResolution, NewLine, PortableTsconfig, Reference, ResolvedTsconfig, Target, TsEnumCodec, TsconfigDiscovery, TsconfigExtendsError, TsconfigJson, TsconfigJsonFromString, TsconfigLoader, TsconfigLoaderSync, TsconfigParseError, TypeAcquisition, WatchDirectory, WatchFile, WatchOptions };
|
|
12
|
+
export { CompilerOptions, CompilerOptionsFromProgrammatic, FallbackPolling, Jsx, JsxConfig, Lib, Module, ModuleDetection, ModuleResolution, NewLine, PortableTsconfig, Reference, ResolvedTsconfig, Target, TsEnumCodec, TsconfigDiscovery, TsconfigExtendsError, TsconfigJson, TsconfigJsonFromString, TsconfigLoader, TsconfigLoaderSync, TsconfigParseError, TypeAcquisition, WatchDirectory, WatchFile, WatchOptions };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effected/tsconfig-json",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.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,7 +39,7 @@
|
|
|
39
39
|
"./package.json": "./package.json"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"@effected/jsonc": "^0.8.
|
|
42
|
+
"@effected/jsonc": "^0.8.1",
|
|
43
43
|
"@effected/walker": "^0.5.0",
|
|
44
44
|
"effect": "4.0.0-rc.109"
|
|
45
45
|
},
|