@projitect/blueprint-tsconfig 0.0.0-stage → 1.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kapil Easwar
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@projitect/blueprint-tsconfig",
3
+ "version": "1.0.1",
4
+ "description": "TypeScript tsconfig.json scaffolding blueprint for projitect — strict defaults, owned mode.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/projitect/projitect.git",
8
+ "directory": "packages/blueprint-tsconfig"
9
+ },
10
+ "license": "MIT",
11
+ "type": "module",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/src/index.d.ts",
15
+ "import": "./dist/src/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "src",
21
+ "!**/*.tsbuildinfo"
22
+ ],
23
+ "scripts": {
24
+ "build": "tsc --build",
25
+ "build:clean": "tsc --build --clean",
26
+ "tc": "tsc --build"
27
+ },
28
+ "devDependencies": {
29
+ "@projitect/blueprint": "workspace:*",
30
+ "@projitect/core": "workspace:*",
31
+ "@projitect/test-kit": "workspace:*",
32
+ "effect": "4.0.0-rc.111",
33
+ "typescript": "5.9.3"
34
+ },
35
+ "peerDependencies": {
36
+ "@projitect/blueprint": "workspace:*",
37
+ "@projitect/core": "workspace:*",
38
+ "effect": "4.0.0-rc.111"
39
+ },
40
+ "engines": {
41
+ "node": ">=22.12.0"
42
+ },
43
+ "projitect": {
44
+ "type": "blueprint",
45
+ "import": "import { tsconfig } from \"@projitect/blueprint-tsconfig\"",
46
+ "call": "tsconfig()"
47
+ }
48
+ }
@@ -0,0 +1,86 @@
1
+ /**
2
+ * @projitect/blueprint-tsconfig
3
+ *
4
+ * One owned-mode blueprint that scaffolds `tsconfig.json` with strict defaults. Designed for the
5
+ * common Node-library / Node-app shape; toggle `dom` for browser code and `jsx` for React/JSX.
6
+ *
7
+ * Owned mode means projitect rewrites `tsconfig.json` from scratch on every `pjt remodel` —
8
+ * the user can't accidentally drift it. If a project needs overrides projitect can't model
9
+ * (e.g. `compilerOptions.paths`), the answer is: configure projitect's options here, then
10
+ * compose a second TS config file (`tsconfig.local.json`) that extends this one and adds the
11
+ * overrides. Don't hand-edit the owned file. Project `references` are the exception: TypeScript
12
+ * never inherits them through `extends`, so declare them with the `references` option here.
13
+ */
14
+ import type { Blueprint } from "@projitect/core";
15
+ export interface TsconfigOptions {
16
+ /**
17
+ * Strict family of compiler flags. Defaults to `true` (`strict`, `noUncheckedIndexedAccess`,
18
+ * `noImplicitOverride`, `noFallthroughCasesInSwitch`, `noPropertyAccessFromIndexSignature`,
19
+ * `exactOptionalPropertyTypes`). Pass `false` to ship the loose defaults TS gives a new
20
+ * project — useful when adopting projitect on a legacy codebase where flipping strict mode
21
+ * at once isn't feasible.
22
+ */
23
+ readonly strict?: boolean;
24
+ /** ECMAScript target. Defaults to `"ES2023"`. */
25
+ readonly target?: string;
26
+ /** Module system. Defaults to `"NodeNext"` (with matching `moduleResolution`). */
27
+ readonly module?: "NodeNext" | "ESNext" | "Node16" | "CommonJS";
28
+ /**
29
+ * `lib` entries. Defaults to `["ES2023"]` (matches `target`). Use `dom: true` instead of
30
+ * adding `"DOM"` here — the helper handles the right pairing.
31
+ */
32
+ readonly lib?: readonly string[];
33
+ /**
34
+ * Include `"DOM"` + `"DOM.Iterable"` in `lib`. Defaults to `false` (Node-only). Flip to `true`
35
+ * for browser code.
36
+ */
37
+ readonly dom?: boolean;
38
+ /**
39
+ * JSX transform. `null` (default) emits no `jsx` field. `"react-jsx"` is the modern automatic
40
+ * runtime; `"react"` is the classic transform; `"preserve"` keeps JSX as-is for downstream
41
+ * tooling (Vite, etc.).
42
+ */
43
+ readonly jsx?: "react" | "react-jsx" | "preserve" | null;
44
+ /**
45
+ * Source root. Defaults to `"./src"`. The generated config derives `include` from this
46
+ * (`${rootDir}/...all files...`) and sets `exclude` to `["node_modules", outDir]`.
47
+ */
48
+ readonly rootDir?: string;
49
+ /**
50
+ * Output directory. Defaults to `"./dist"`.
51
+ */
52
+ readonly outDir?: string;
53
+ /**
54
+ * Paths to referenced projects (a directory or a tsconfig file), emitted in the given order as
55
+ * top-level `references: [{ path }]` entries. Paths are kept exactly as written. Each referenced
56
+ * project must set `composite: true` in its own tsconfig. Omitted or empty emits no
57
+ * `references` key.
58
+ */
59
+ readonly references?: readonly string[];
60
+ /**
61
+ * Type-check only. Defaults to `false`. When `true` the config emits `noEmit: true` and leaves
62
+ * out the emit settings (`rootDir`, `outDir`, `declaration`, `declarationMap`, `sourceMap`),
63
+ * for projects whose bundler or framework does the emitting.
64
+ */
65
+ readonly noEmit?: boolean;
66
+ /** Emit `allowJs: true`. Defaults to `false` (no `allowJs` field). */
67
+ readonly allowJs?: boolean;
68
+ /** Emit `incremental: true`. Defaults to `false` (no `incremental` field). */
69
+ readonly incremental?: boolean;
70
+ /**
71
+ * TypeScript language service plugin names, emitted as `compilerOptions.plugins: [{ name }]` in
72
+ * the given order. Omitted or empty emits no `plugins` key.
73
+ */
74
+ readonly plugins?: readonly string[];
75
+ /**
76
+ * Extra `include` entries, appended after the glob derived from `rootDir` and kept exactly as
77
+ * written (e.g. generated type directories).
78
+ */
79
+ readonly include?: readonly string[];
80
+ }
81
+ /**
82
+ * Build the tsconfig blueprint. Returns an owned-mode blueprint that emits a single operation
83
+ * writing `tsconfig.json` with the rendered content.
84
+ */
85
+ export declare const tsconfig: (options?: TsconfigOptions) => Blueprint.Blueprint;
86
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAQhD,MAAM,WAAW,eAAe;IAC9B;;;;;;OAMG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;IACzB,iDAAiD;IACjD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,kFAAkF;IAClF,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAA;IAC/D;;;OAGG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAChC;;;OAGG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAA;IACtB;;;;OAIG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,GAAG,WAAW,GAAG,UAAU,GAAG,IAAI,CAAA;IACxD;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB;;OAEG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACvC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;IACzB,sEAAsE;IACtE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;IAC1B,8EAA8E;IAC9E,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAA;IAC9B;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CACrC;AAED;;;GAGG;AACH,eAAO,MAAM,QAAQ,GAAI,UAAS,eAAoB,KAAG,SAAS,CAAC,SAO/D,CAAA"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * @projitect/blueprint-tsconfig
3
+ *
4
+ * One owned-mode blueprint that scaffolds `tsconfig.json` with strict defaults. Designed for the
5
+ * common Node-library / Node-app shape; toggle `dom` for browser code and `jsx` for React/JSX.
6
+ *
7
+ * Owned mode means projitect rewrites `tsconfig.json` from scratch on every `pjt remodel` —
8
+ * the user can't accidentally drift it. If a project needs overrides projitect can't model
9
+ * (e.g. `compilerOptions.paths`), the answer is: configure projitect's options here, then
10
+ * compose a second TS config file (`tsconfig.local.json`) that extends this one and adds the
11
+ * overrides. Don't hand-edit the owned file. Project `references` are the exception: TypeScript
12
+ * never inherits them through `extends`, so declare them with the `references` option here.
13
+ */
14
+ import { ownFile } from "@projitect/blueprint";
15
+ import { Array } from "effect";
16
+ import manifest from "../package.json" with { type: "json" };
17
+ // Read the version from the package manifest (emitted next to `dist/src`) so a release bump
18
+ // reaches `.pjt.lock` without a hand-edited constant. JSON import keeps this runtime-pure.
19
+ const PACKAGE_VERSION = manifest.version;
20
+ /**
21
+ * Build the tsconfig blueprint. Returns an owned-mode blueprint that emits a single operation
22
+ * writing `tsconfig.json` with the rendered content.
23
+ */
24
+ export const tsconfig = (options = {}) => ownFile({
25
+ id: "pjt:tsconfig",
26
+ version: PACKAGE_VERSION,
27
+ description: "TypeScript tsconfig.json with strict defaults",
28
+ path: "tsconfig.json",
29
+ content: renderTsconfig(options),
30
+ });
31
+ const renderTsconfig = (options) => {
32
+ const strict = options.strict ?? true;
33
+ const target = options.target ?? "ES2023";
34
+ const module_ = options.module ?? "NodeNext";
35
+ const baseLib = options.lib ?? [target];
36
+ const lib = options.dom === true ? [...baseLib, "DOM", "DOM.Iterable"] : baseLib;
37
+ const rootDir = options.rootDir ?? "./src";
38
+ const outDir = options.outDir ?? "./dist";
39
+ const jsx = options.jsx ?? null;
40
+ const references = options.references ?? [];
41
+ const noEmit = options.noEmit ?? false;
42
+ const plugins = options.plugins ?? [];
43
+ const config = {
44
+ compilerOptions: {
45
+ target,
46
+ module: module_,
47
+ moduleResolution: moduleResolutionFor(module_),
48
+ lib,
49
+ ...(jsx !== null && { jsx }),
50
+ ...(noEmit ? { noEmit } : { rootDir, outDir }),
51
+ ...(options.allowJs === true && { allowJs: true }),
52
+ ...(options.incremental === true && { incremental: true }),
53
+ ...(Array.isReadonlyArrayNonEmpty(plugins) && {
54
+ plugins: plugins.map((name) => ({ name })),
55
+ }),
56
+ // Always-on hygiene flags. These don't toggle with `strict` — they're the table stakes
57
+ // every modern TS project should have.
58
+ esModuleInterop: true,
59
+ forceConsistentCasingInFileNames: true,
60
+ skipLibCheck: true,
61
+ isolatedModules: true,
62
+ resolveJsonModule: true,
63
+ ...(!noEmit && { declaration: true, declarationMap: true, sourceMap: true }),
64
+ ...(strict && {
65
+ strict: true,
66
+ noImplicitOverride: true,
67
+ noFallthroughCasesInSwitch: true,
68
+ noUncheckedIndexedAccess: true,
69
+ noPropertyAccessFromIndexSignature: true,
70
+ exactOptionalPropertyTypes: true,
71
+ }),
72
+ },
73
+ include: [`${stripDot(rootDir)}/**/*`, ...(options.include ?? [])],
74
+ exclude: noEmit ? ["node_modules"] : ["node_modules", stripDot(outDir)],
75
+ ...(Array.isReadonlyArrayNonEmpty(references) && {
76
+ references: references.map((path) => ({ path })),
77
+ }),
78
+ };
79
+ return `${JSON.stringify(config, null, 2)}\n`;
80
+ };
81
+ const moduleResolutionFor = (m) => {
82
+ switch (m) {
83
+ case "NodeNext":
84
+ case "Node16": {
85
+ return m;
86
+ }
87
+ case "ESNext": {
88
+ return "Bundler";
89
+ }
90
+ case "CommonJS": {
91
+ return "Node";
92
+ }
93
+ default: {
94
+ return "NodeNext";
95
+ }
96
+ }
97
+ };
98
+ const stripDot = (p) => (p.startsWith("./") ? p.slice(2) : p);
99
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,48 @@
1
1
  {
2
2
  "name": "@projitect/blueprint-tsconfig",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "1.0.1",
4
+ "description": "TypeScript tsconfig.json scaffolding blueprint for projitect — strict defaults, owned mode.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/projitect/projitect.git",
8
+ "directory": "packages/blueprint-tsconfig"
9
+ },
10
+ "license": "MIT",
11
+ "type": "module",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/src/index.d.ts",
15
+ "import": "./dist/src/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "src",
21
+ "!**/*.tsbuildinfo"
22
+ ],
23
+ "devDependencies": {
24
+ "effect": "4.0.0-rc.111",
25
+ "typescript": "5.9.3",
26
+ "@projitect/blueprint": "1.0.1",
27
+ "@projitect/core": "1.0.1",
28
+ "@projitect/test-kit": "1.0.1"
29
+ },
30
+ "peerDependencies": {
31
+ "effect": "4.0.0-rc.111",
32
+ "@projitect/blueprint": "1.0.1",
33
+ "@projitect/core": "1.0.1"
34
+ },
35
+ "engines": {
36
+ "node": ">=22.12.0"
37
+ },
38
+ "projitect": {
39
+ "type": "blueprint",
40
+ "import": "import { tsconfig } from \"@projitect/blueprint-tsconfig\"",
41
+ "call": "tsconfig()"
42
+ },
43
+ "scripts": {
44
+ "build": "tsc --build",
45
+ "build:clean": "tsc --build --clean",
46
+ "tc": "tsc --build"
47
+ }
6
48
  }
package/src/index.ts ADDED
@@ -0,0 +1,175 @@
1
+ /**
2
+ * @projitect/blueprint-tsconfig
3
+ *
4
+ * One owned-mode blueprint that scaffolds `tsconfig.json` with strict defaults. Designed for the
5
+ * common Node-library / Node-app shape; toggle `dom` for browser code and `jsx` for React/JSX.
6
+ *
7
+ * Owned mode means projitect rewrites `tsconfig.json` from scratch on every `pjt remodel` —
8
+ * the user can't accidentally drift it. If a project needs overrides projitect can't model
9
+ * (e.g. `compilerOptions.paths`), the answer is: configure projitect's options here, then
10
+ * compose a second TS config file (`tsconfig.local.json`) that extends this one and adds the
11
+ * overrides. Don't hand-edit the owned file. Project `references` are the exception: TypeScript
12
+ * never inherits them through `extends`, so declare them with the `references` option here.
13
+ */
14
+
15
+ import { ownFile } from "@projitect/blueprint"
16
+ import type { Blueprint } from "@projitect/core"
17
+ import { Array } from "effect"
18
+ import manifest from "../package.json" with { type: "json" }
19
+
20
+ // Read the version from the package manifest (emitted next to `dist/src`) so a release bump
21
+ // reaches `.pjt.lock` without a hand-edited constant. JSON import keeps this runtime-pure.
22
+ const PACKAGE_VERSION = manifest.version
23
+
24
+ export interface TsconfigOptions {
25
+ /**
26
+ * Strict family of compiler flags. Defaults to `true` (`strict`, `noUncheckedIndexedAccess`,
27
+ * `noImplicitOverride`, `noFallthroughCasesInSwitch`, `noPropertyAccessFromIndexSignature`,
28
+ * `exactOptionalPropertyTypes`). Pass `false` to ship the loose defaults TS gives a new
29
+ * project — useful when adopting projitect on a legacy codebase where flipping strict mode
30
+ * at once isn't feasible.
31
+ */
32
+ readonly strict?: boolean
33
+ /** ECMAScript target. Defaults to `"ES2023"`. */
34
+ readonly target?: string
35
+ /** Module system. Defaults to `"NodeNext"` (with matching `moduleResolution`). */
36
+ readonly module?: "NodeNext" | "ESNext" | "Node16" | "CommonJS"
37
+ /**
38
+ * `lib` entries. Defaults to `["ES2023"]` (matches `target`). Use `dom: true` instead of
39
+ * adding `"DOM"` here — the helper handles the right pairing.
40
+ */
41
+ readonly lib?: readonly string[]
42
+ /**
43
+ * Include `"DOM"` + `"DOM.Iterable"` in `lib`. Defaults to `false` (Node-only). Flip to `true`
44
+ * for browser code.
45
+ */
46
+ readonly dom?: boolean
47
+ /**
48
+ * JSX transform. `null` (default) emits no `jsx` field. `"react-jsx"` is the modern automatic
49
+ * runtime; `"react"` is the classic transform; `"preserve"` keeps JSX as-is for downstream
50
+ * tooling (Vite, etc.).
51
+ */
52
+ readonly jsx?: "react" | "react-jsx" | "preserve" | null
53
+ /**
54
+ * Source root. Defaults to `"./src"`. The generated config derives `include` from this
55
+ * (`${rootDir}/...all files...`) and sets `exclude` to `["node_modules", outDir]`.
56
+ */
57
+ readonly rootDir?: string
58
+ /**
59
+ * Output directory. Defaults to `"./dist"`.
60
+ */
61
+ readonly outDir?: string
62
+ /**
63
+ * Paths to referenced projects (a directory or a tsconfig file), emitted in the given order as
64
+ * top-level `references: [{ path }]` entries. Paths are kept exactly as written. Each referenced
65
+ * project must set `composite: true` in its own tsconfig. Omitted or empty emits no
66
+ * `references` key.
67
+ */
68
+ readonly references?: readonly string[]
69
+ /**
70
+ * Type-check only. Defaults to `false`. When `true` the config emits `noEmit: true` and leaves
71
+ * out the emit settings (`rootDir`, `outDir`, `declaration`, `declarationMap`, `sourceMap`),
72
+ * for projects whose bundler or framework does the emitting.
73
+ */
74
+ readonly noEmit?: boolean
75
+ /** Emit `allowJs: true`. Defaults to `false` (no `allowJs` field). */
76
+ readonly allowJs?: boolean
77
+ /** Emit `incremental: true`. Defaults to `false` (no `incremental` field). */
78
+ readonly incremental?: boolean
79
+ /**
80
+ * TypeScript language service plugin names, emitted as `compilerOptions.plugins: [{ name }]` in
81
+ * the given order. Omitted or empty emits no `plugins` key.
82
+ */
83
+ readonly plugins?: readonly string[]
84
+ /**
85
+ * Extra `include` entries, appended after the glob derived from `rootDir` and kept exactly as
86
+ * written (e.g. generated type directories).
87
+ */
88
+ readonly include?: readonly string[]
89
+ }
90
+
91
+ /**
92
+ * Build the tsconfig blueprint. Returns an owned-mode blueprint that emits a single operation
93
+ * writing `tsconfig.json` with the rendered content.
94
+ */
95
+ export const tsconfig = (options: TsconfigOptions = {}): Blueprint.Blueprint =>
96
+ ownFile({
97
+ id: "pjt:tsconfig",
98
+ version: PACKAGE_VERSION,
99
+ description: "TypeScript tsconfig.json with strict defaults",
100
+ path: "tsconfig.json",
101
+ content: renderTsconfig(options),
102
+ })
103
+
104
+ const renderTsconfig = (options: TsconfigOptions): string => {
105
+ const strict = options.strict ?? true
106
+ const target = options.target ?? "ES2023"
107
+ const module_ = options.module ?? "NodeNext"
108
+ const baseLib = options.lib ?? [target]
109
+ const lib = options.dom === true ? [...baseLib, "DOM", "DOM.Iterable"] : baseLib
110
+ const rootDir = options.rootDir ?? "./src"
111
+ const outDir = options.outDir ?? "./dist"
112
+ const jsx = options.jsx ?? null
113
+ const references = options.references ?? []
114
+ const noEmit = options.noEmit ?? false
115
+ const plugins = options.plugins ?? []
116
+
117
+ const config: Record<string, unknown> = {
118
+ compilerOptions: {
119
+ target,
120
+ module: module_,
121
+ moduleResolution: moduleResolutionFor(module_),
122
+ lib,
123
+ ...(jsx !== null && { jsx }),
124
+ ...(noEmit ? { noEmit } : { rootDir, outDir }),
125
+ ...(options.allowJs === true && { allowJs: true }),
126
+ ...(options.incremental === true && { incremental: true }),
127
+ ...(Array.isReadonlyArrayNonEmpty(plugins) && {
128
+ plugins: plugins.map((name) => ({ name })),
129
+ }),
130
+ // Always-on hygiene flags. These don't toggle with `strict` — they're the table stakes
131
+ // every modern TS project should have.
132
+ esModuleInterop: true,
133
+ forceConsistentCasingInFileNames: true,
134
+ skipLibCheck: true,
135
+ isolatedModules: true,
136
+ resolveJsonModule: true,
137
+ ...(!noEmit && { declaration: true, declarationMap: true, sourceMap: true }),
138
+ ...(strict && {
139
+ strict: true,
140
+ noImplicitOverride: true,
141
+ noFallthroughCasesInSwitch: true,
142
+ noUncheckedIndexedAccess: true,
143
+ noPropertyAccessFromIndexSignature: true,
144
+ exactOptionalPropertyTypes: true,
145
+ }),
146
+ },
147
+ include: [`${stripDot(rootDir)}/**/*`, ...(options.include ?? [])],
148
+ exclude: noEmit ? ["node_modules"] : ["node_modules", stripDot(outDir)],
149
+ ...(Array.isReadonlyArrayNonEmpty(references) && {
150
+ references: references.map((path) => ({ path })),
151
+ }),
152
+ }
153
+
154
+ return `${JSON.stringify(config, null, 2)}\n`
155
+ }
156
+
157
+ const moduleResolutionFor = (m: TsconfigOptions["module"]): string => {
158
+ switch (m) {
159
+ case "NodeNext":
160
+ case "Node16": {
161
+ return m
162
+ }
163
+ case "ESNext": {
164
+ return "Bundler"
165
+ }
166
+ case "CommonJS": {
167
+ return "Node"
168
+ }
169
+ default: {
170
+ return "NodeNext"
171
+ }
172
+ }
173
+ }
174
+
175
+ const stripDot = (p: string): string => (p.startsWith("./") ? p.slice(2) : p)
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.