@osdlc/tsconfig 0.0.0-stage → 0.0.1-stage

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/CHANGELOG.md ADDED
@@ -0,0 +1,57 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/), and this project adheres to
6
+ [Semantic Versioning](https://semver.org/).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.3.3] - 2026-10-16
11
+
12
+ ### Changed
13
+
14
+ - Renamed from `@sksizer/tsconfig`. No other changes.
15
+ - To move, replace `@sksizer/tsconfig` with `@osdlc/tsconfig` in `devDependencies` and in every
16
+ `extends`.
17
+
18
+ ## [0.3.2] - 2026-10-15
19
+
20
+ ### Changed
21
+
22
+ - First release made from [sksizer/sdlc](https://github.com/sksizer/sdlc) CI, through npm trusted
23
+ publishing, so the package now carries provenance. The package contents are unchanged.
24
+
25
+ ## [0.3.1] - 2026-10-15
26
+
27
+ ### Changed
28
+
29
+ - Published to npm from [sksizer/sdlc](https://github.com/sksizer/sdlc), with a LICENSE file
30
+ and a README written for outside readers. The resolution probe runs as `npm run typecheck`.
31
+
32
+ ## [0.3.0] - 2026-09-06
33
+
34
+ ### Changed
35
+
36
+ - **BREAKING:** `exactOptionalPropertyTypes` moves into the shared `base` preset, so every consumer
37
+ now compiles under it.
38
+
39
+ ## [0.2.0] - 2026-09-04
40
+
41
+ ### Changed
42
+
43
+ - **BREAKING:** Shipping-model options split out of the shared bar into the `source-shipped` preset;
44
+ `base` no longer carries them.
45
+
46
+ ### Fixed
47
+
48
+ - Presets no longer resolve a sibling package to a `dist/` nothing builds.
49
+ - Presets stop naming internal packages and counts in their docs.
50
+
51
+ ## [0.1.0] - 2026-09-01
52
+
53
+ ### Added
54
+
55
+ - Initial `@sksizer/tsconfig` workspace package: the shared compiler bar as `base`, plus `node-lib`,
56
+ `bun-lib`, `build` and `vue` presets.
57
+ - A `bun` resolution condition.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SK Sizer
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.
package/README.md CHANGED
@@ -1,3 +1,84 @@
1
- # Temporary Holding Version
1
+ # @osdlc/tsconfig
2
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.
3
+ Strict TypeScript compiler presets: one shared bar, plus the package shapes
4
+ that recur on top of it. Consumed through `extends`; ships no code.
5
+
6
+ ```sh
7
+ npm install --save-dev @osdlc/tsconfig typescript
8
+ ```
9
+
10
+ Requires TypeScript 5.7 or later (`build` uses `rewriteRelativeImportExtensions`
11
+ and the `${configDir}` template).
12
+
13
+ ## Presets
14
+
15
+ | Preset | What it is |
16
+ |---|---|
17
+ | `base` | The shared bar, carrying nothing specific to how a package ships. |
18
+ | `source-shipped` | `base` + `allowImportingTsExtensions` and `noEmit`, for a package consumed as TypeScript source rather than as built `dist/`. |
19
+ | `node-lib` | `source-shipped` + the ES2022 runtime and node globals. |
20
+ | `bun-lib` | `node-lib` + bun's globals, for a package whose tests or runtime are Bun. |
21
+ | `vue` | `source-shipped` + the modern browser, the DOM, `jsx: preserve`, and no ambient types. |
22
+ | `build` | The emit block, as a mixin. Not a standalone config — see below. |
23
+
24
+ ## Use
25
+
26
+ `base` and `source-shipped` differ by two options, and TypeScript couples them:
27
+ `allowImportingTsExtensions` is rejected unless `noEmit`, `emitDeclarationOnly`
28
+ or `rewriteRelativeImportExtensions` is set (TS5096). A package consumed as
29
+ TypeScript source, importing `./x.ts`, wants `source-shipped` (directly or
30
+ through `node-lib`, `bun-lib` or `vue`). A package that builds with tsc and
31
+ imports `./x.js` wants `base`.
32
+
33
+ ```jsonc
34
+ // tsconfig.json — the family preset, then your own per-package facts
35
+ {
36
+ "extends": "@osdlc/tsconfig/node-lib",
37
+ "include": ["index.ts", "sync.ts"]
38
+ }
39
+ ```
40
+
41
+ `lib`, `types`, `jsx` and `include` are genuine per-package facts, so a package
42
+ still states the ones where it really differs from its preset. What it should
43
+ not restate is anything the preset already says.
44
+
45
+ The emit mixin goes **last in an array**, on top of the package's own config:
46
+
47
+ ```jsonc
48
+ // tsconfig.build.json
49
+ {
50
+ "extends": ["./tsconfig.json", "@osdlc/tsconfig/build"],
51
+ "compilerOptions": { "rootDir": "." }
52
+ }
53
+ ```
54
+
55
+ TypeScript applies array entries left to right, and the extending file's own
56
+ `compilerOptions` last — so `build`'s `noEmit: false` lands on top of the dev
57
+ config's `noEmit: true`, while `rootDir` and `include` stay where they belong.
58
+ `build` deliberately declares no `extends` and no `include`; `presets/build.json`
59
+ explains why each of those would break silently.
60
+
61
+ ## Adding a preset
62
+
63
+ Add the file under `presets/`, **and add both its `exports` keys** (the
64
+ extensionless and `.json` spellings) to `package.json`. Then add it to
65
+ `tests/resolve.json`. Skipping the `exports` entry still resolves from inside
66
+ this package and breaks every consumer; `npm run typecheck` (tsc over
67
+ `tests/resolve.json`) is what catches that.
68
+
69
+ ## Not for framework-generated configs
70
+
71
+ A config that extends `./.nuxt/tsconfig.json` or `astro/tsconfigs/*` must stay
72
+ that way. Layering this bar on top would clobber the `paths`, `types`,
73
+ `moduleResolution` and `jsx` the generator computed.
74
+
75
+ ## Source and releases
76
+
77
+ Developed and released in
78
+ [osdlc/osdlc](https://github.com/osdlc/osdlc/tree/main/packages/tsconfig),
79
+ under `packages/tsconfig`. Report issues at
80
+ [osdlc/osdlc/issues](https://github.com/osdlc/osdlc/issues).
81
+
82
+ ## License
83
+
84
+ [MIT](https://github.com/osdlc/osdlc/blob/main/packages/tsconfig/LICENSE)
package/package.json CHANGED
@@ -1,6 +1,56 @@
1
1
  {
2
2
  "name": "@osdlc/tsconfig",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.0.1-stage",
4
+ "description": "Strict TypeScript compiler presets: a shared bar plus node, bun, vue and build shapes. Consumed through `extends`; ships no code.",
5
+ "license": "MIT",
6
+ "author": "SK Sizer",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/osdlc/osdlc.git",
10
+ "directory": "packages/tsconfig"
11
+ },
12
+ "homepage": "https://github.com/osdlc/osdlc/tree/main/packages/tsconfig#readme",
13
+ "bugs": "https://github.com/osdlc/osdlc/issues",
14
+ "keywords": [
15
+ "tsconfig",
16
+ "typescript",
17
+ "preset",
18
+ "strict"
19
+ ],
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "files": [
24
+ "presets/",
25
+ "README.md",
26
+ "CHANGELOG.md",
27
+ "LICENSE"
28
+ ],
29
+ "exports": {
30
+ "./base": "./presets/base.json",
31
+ "./base.json": "./presets/base.json",
32
+ "./source-shipped": "./presets/source-shipped.json",
33
+ "./source-shipped.json": "./presets/source-shipped.json",
34
+ "./node-lib": "./presets/node-lib.json",
35
+ "./node-lib.json": "./presets/node-lib.json",
36
+ "./bun-lib": "./presets/bun-lib.json",
37
+ "./bun-lib.json": "./presets/bun-lib.json",
38
+ "./vue": "./presets/vue.json",
39
+ "./vue.json": "./presets/vue.json",
40
+ "./build": "./presets/build.json",
41
+ "./build.json": "./presets/build.json",
42
+ "./package.json": "./package.json"
43
+ },
44
+ "devDependencies": {
45
+ "oxlint": "^1.65.0",
46
+ "prettier": "3.9.6",
47
+ "typescript": "~6.0.3",
48
+ "@osdlc/prettier-config": "^0.2.3"
49
+ },
50
+ "scripts": {
51
+ "typecheck": "tsc --noEmit -p tests/resolve.json",
52
+ "format": "prettier --write .",
53
+ "format:check": "prettier --check .",
54
+ "lint": "oxlint ."
55
+ }
6
56
  }
@@ -0,0 +1,61 @@
1
+ {
2
+ // The one TypeScript bar every package on these presets meets — and the only
3
+ // preset that assumes nothing about how a package is shipped.
4
+ //
5
+ // It exists so that "how strictly is this checked" is not a per-package
6
+ // accident. A package cannot be laxer than the app that consumes it, and a
7
+ // new package inherits the bar instead of choosing one.
8
+ //
9
+ // Nothing here assumes a workspace, a bundler, or source-shipped siblings, so
10
+ // this is the preset an outside consumer extends. The two options that DO
11
+ // assume all three — `allowImportingTsExtensions` and `noEmit` — live one
12
+ // level down in ./source-shipped.json, which the sibling presets reach
13
+ // through. Nothing extends this file for the bar alone; the resolution probe
14
+ // in this package's tests is what keeps it honest with no local consumer.
15
+ //
16
+ // What is NOT here is otherwise deliberate. `lib`, `types`, `jsx` and
17
+ // `include` are genuine per-package facts — a DOM library and a node CLI
18
+ // legitimately differ — so packages still set those themselves. The
19
+ // combinations that recur anyway are the sibling presets: ./node-lib.json,
20
+ // ./bun-lib.json and ./vue.json. A package not covered by one extends
21
+ // ./source-shipped.json and states its own facts; a preset with two consumers
22
+ // would hide one self-documenting line behind an indirection, which is worse
23
+ // than the line.
24
+ //
25
+ // NOT reachable from here: a config that extends a framework-generated one
26
+ // (./.nuxt/tsconfig.json, astro/tsconfigs/*). Applying this bar on top of
27
+ // those would clobber the `paths`, `types`, `moduleResolution` and `jsx` the
28
+ // generator computed.
29
+ //
30
+ // `exactOptionalPropertyTypes` was the last option to arrive, in 2026-09, and
31
+ // it came in the long way: per package, cheapest first, each setting it
32
+ // locally until the last holdout fell and the line could move here. It cost
33
+ // 59 fixes across 8 packages, nearly all of one shape — an optional property
34
+ // handed a `T | undefined` — and nearly all resolved by omitting the key
35
+ // rather than widening the type, which is the distinction the flag exists to
36
+ // preserve.
37
+ "compilerOptions": {
38
+ "target": "ES2022",
39
+ "module": "ESNext",
40
+ // Capitalised. TypeScript accepts either spelling, which is exactly how the
41
+ // two drift apart across a set of packages.
42
+ "moduleResolution": "Bundler",
43
+
44
+ "strict": true,
45
+ // `arr[i]` is `T | undefined`, which is true. Pretending otherwise is how an
46
+ // index out of range becomes a runtime error rather than a compile one.
47
+ "noUncheckedIndexedAccess": true,
48
+ "noImplicitOverride": true,
49
+ "noFallthroughCasesInSwitch": true,
50
+ "noUnusedLocals": true,
51
+
52
+ "verbatimModuleSyntax": true,
53
+ "isolatedModules": true,
54
+ "esModuleInterop": true,
55
+ "skipLibCheck": true,
56
+
57
+ // An optional property is absent or it holds a value; it is not "present
58
+ // and undefined". See the note above for how this one arrived.
59
+ "exactOptionalPropertyTypes": true
60
+ }
61
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ // The emit block, as a MIXIN. Use it as the LAST element of an extends array,
3
+ // never on its own:
4
+ //
5
+ // "extends": ["./tsconfig.json", "@osdlc/tsconfig/build"]
6
+ //
7
+ // Two things here are deliberate, and both fail silently if changed.
8
+ //
9
+ // 1. `${configDir}` on outDir. A file-path option in an extended config is
10
+ // normalized against THAT CONFIG'S directory, not the consumer's — a plain
11
+ // "dist" here emits into this package's own directory, so every consumer's
12
+ // build produces nothing and the npm tarballs ship empty. The template is
13
+ // exempted from that normalization and substitutes against the consuming
14
+ // project. (typescript 6.0.3, normalizeNonListOptionValue.)
15
+ //
16
+ // 2. No `extends`, and no `include`/`exclude`/`files`. Extending a preset here
17
+ // would re-apply it over the consumer's own config and revert what the
18
+ // consumer overrode — a NodeNext package would silently become
19
+ // ESNext/Bundler. An `include` here would replace the consumer's, rebased
20
+ // onto a directory inside node_modules.
21
+ //
22
+ // `rootDir` is not here either: it differs between consumers ("." or "src"),
23
+ // and guessing wrong quietly changes the dist/ layout.
24
+ "compilerOptions": {
25
+ "noEmit": false,
26
+ "outDir": "${configDir}/dist",
27
+ "declaration": true,
28
+ "declarationMap": true,
29
+ // What makes an emitting build legal alongside source-shipped.json's
30
+ // `allowImportingTsExtensions`, which TS otherwise rejects (TS5096); also
31
+ // what lets a source-shipped dependency whose own imports carry .ts
32
+ // extensions typecheck through (TS5097).
33
+ "rewriteRelativeImportExtensions": true
34
+ }
35
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ // A node library whose tests (or runtime) are Bun: node globals plus bun's.
3
+ //
4
+ // Adds nothing but `types`. `customConditions: ["bun"]` is deliberately NOT
5
+ // folded in, because it is a per-package fact rather than a property of this
6
+ // shape — packages in this shape legitimately differ on it.
7
+ //
8
+ // What that setting decides: whether a workspace sibling resolves to its
9
+ // TypeScript source or to its published `dist/`. Getting it wrong is not a
10
+ // style choice. A package that imports a source-shipped sibling typechecks
11
+ // THAT sibling's source under ITS OWN options, so if the sibling in turn
12
+ // reaches a package whose `types` point at a `dist/` no typecheck builds, the
13
+ // import is unresolvable — TS2307 — even though the sibling's own check is
14
+ // green. Nothing reports it until the importing package is next checked, so a
15
+ // package can sit red for as long as nothing touches it.
16
+ //
17
+ // So: a package importing a source-shipped sibling must match that sibling's
18
+ // condition. The alternative is to build the dependency first, which requires
19
+ // it to have a build task — a source-shipped package may not.
20
+ "extends": "./node-lib.json",
21
+ "compilerOptions": {
22
+ "types": ["node", "bun"]
23
+ }
24
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ // A node library: the ES2022 runtime, node globals, no DOM.
3
+ //
4
+ // `customConditions: ["bun"]` is deliberately not here — it is a per-package
5
+ // decision rather than a property of this shape, so it stays a stated line in
6
+ // the packages that need it. See ./bun-lib.json for what the setting decides
7
+ // and how getting it wrong turns into a TS2307 nothing reports until the
8
+ // importing package is next checked.
9
+ "extends": "./source-shipped.json",
10
+ "compilerOptions": {
11
+ "lib": ["ES2022"],
12
+ "types": ["node"]
13
+ }
14
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ // The shared bar plus the two options that assume packages are consumed as
3
+ // SOURCE — resolved through a `bun` export condition to TypeScript rather
4
+ // than to a built `dist/` — so an import may name its `.ts` extension.
5
+ //
6
+ // Split out of ./base.json rather than left in it because these two are the
7
+ // only part of the bar an outside consumer would not want. A package that
8
+ // builds with tsc and imports `./x.js` wants base; a package consumed as
9
+ // source wants this file, directly or through ./node-lib.json and ./vue.json.
10
+ //
11
+ // The two travel together by force, not by preference: TypeScript rejects
12
+ // `allowImportingTsExtensions` unless one of `noEmit`, `emitDeclarationOnly`
13
+ // or `rewriteRelativeImportExtensions` is set (TS5096). That is why they moved
14
+ // as a pair and why neither belongs in base alone. ./build.json sets
15
+ // `rewriteRelativeImportExtensions`, which is what lets an emitting build
16
+ // override this file's `noEmit` without tripping the same rule.
17
+ "extends": "./base.json",
18
+ "compilerOptions": {
19
+ "allowImportingTsExtensions": true,
20
+ "noEmit": true
21
+ }
22
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ // A Vue 3 component package: the modern browser, the DOM and the iterable form
3
+ // of its collections, SFC/JSX left for the bundler, and NO ambient @types at
4
+ // all — a browser component must not silently pick up node globals, which is
5
+ // what an omitted `types` gets you once anything hoists them into reach.
6
+ //
7
+ // A Vue package that targets ES2022, or sets no `jsx`, is a different shape
8
+ // rather than a drifted copy of this one; it extends ./source-shipped.json
9
+ // directly and states its own facts.
10
+ "extends": "./source-shipped.json",
11
+ "compilerOptions": {
12
+ "target": "ESNext",
13
+ "lib": ["ESNext", "DOM", "DOM.Iterable"],
14
+ "jsx": "preserve",
15
+ "types": []
16
+ }
17
+ }