@doikayt/typescript-build-config 0.1.15 → 0.1.16

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/README.md CHANGED
@@ -111,33 +111,41 @@ small single-purpose scripts, and the check side mirrors the write side:
111
111
  | --- | --- |
112
112
  | `ci` | The release gate: `check-all-format` then `test` (plus `test:e2e` for UI). |
113
113
  | `build` | Compile TypeScript to `dist/` (`tsc`). |
114
- | `prepack` | Runs `build` before packing, so `changeset publish` ships compiled `dist/`. |
115
114
  | `test` | Unit / integration tests (`vitest run`). |
116
115
  | `test:e2e` | End-to-end tests (`playwright test`) — UI projects only. |
116
+ | `prepack` | Runs `build` before packing, so `changeset publish` ships compiled `dist/` — **libraries only**. |
117
117
  | `update-all-format` | Reformat everything: code + markdown docs (write). |
118
118
  | `check-all-format` | Verify formatting: code + markdown docs (used by `ci`). |
119
119
  | `update-code-formatting` / `check-code-formatting` | Prettier write / check. |
120
120
  | `update-markdown-docs` / `check-markdown-docs` | Regenerate / verify generated markdown (TOC, UML, …). |
121
121
 
122
- Alongside the scripts, `init` sets the publish config a fresh package needs —
123
- `type: "module"`, `main` / `types` / `exports` pointing at `dist/index.js`, and
124
- `files: ["dist"]` — each only if you have not already set it. Combined with
125
- `prepack`, a brand-new project builds and publishes a compiled, typed ESM
126
- package on push with no extra wiring.
122
+ `init` also asks whether the project is a **publishable library**, which sets the
123
+ publish config accordingly (non-destructively):
124
+
125
+ - **Library** — `main` / `types` / `exports` → `dist/index.js`, `files: ["dist"]`,
126
+ and `prepack`, so it publishes a compiled, typed ESM package on push.
127
+ - **App / CLI** (the default) — marked `private: true`, so a release versions and
128
+ tags it but never publishes to npm.
129
+
130
+ `type: "module"` and `build` are set either way. New to these terms (compiled
131
+ `dist/`, publish fields, library vs app)? See
132
+ [Packaging concepts](docs/packaging-concepts.md) for the background.
127
133
 
128
134
  ### Console / CLI project
129
135
 
130
136
  ```bash
131
137
  npm init -y # if starting fresh
132
138
  npm install --save-dev @doikayt/typescript-build-config
133
- npx @doikayt/typescript-build-config init # answer "n" to the Playwright prompt
139
+ npx @doikayt/typescript-build-config init # answer "n" to Playwright; "n" (app) or "y" (library)
134
140
  npm install # fetch the declared devDependencies
135
141
  ```
136
142
 
137
143
  `init` writes the canonical scripts (`ci`, `build`, `test`, `update-all-format`,
138
- `check-all-format`, `prepack`, and their sub-tasks), sets the `dist/`-based
139
- publish config, declares `vitest` + `@doikayt/autogen-markdown-doc` +
140
- `typescript`, and seeds a commented `vitest.config.ts`.
144
+ `check-all-format`, and their sub-tasks), declares `vitest` +
145
+ `@doikayt/autogen-markdown-doc` + `typescript`, and seeds a commented
146
+ `vitest.config.ts`. Answering the "publishable library?" prompt sets the publish
147
+ config — `private` for an app, or `prepack` + the `dist/`-based fields for a
148
+ library (see [The canonical script set](#the-canonical-script-set)).
141
149
 
142
150
  ### UI / web project (with Playwright e2e)
143
151
 
@@ -496,6 +504,10 @@ To auto-fix formatting before verifying:
496
504
  npm run update-all-format && npm run ci
497
505
  ```
498
506
 
507
+ To verify end-to-end that `init` scaffolds and ships both a library and an app —
508
+ by hand, with what to look for at each step — follow
509
+ [docs/e2e-verification.md](docs/e2e-verification.md).
510
+
499
511
  ## License
500
512
 
501
513
  MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doikayt/typescript-build-config",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "description": "Shared build configuration for TypeScript projects — ESLint, Prettier, tsconfig, and Playwright presets",
5
5
  "_comments": {
6
6
  "exports": "This block lists the config files that will be extended by files in in src/toplevel - which are copied to consuming project root folder. An example: eslint.config.js imports from '@doikayt/typescript-build-config/eslint'.",
@@ -1,10 +1,11 @@
1
1
  // The canonical npm-script set init writes into every consumer. package.json is
2
2
  // the single source of truth (it is always present); NX projects, if any, add
3
- // thin targets that delegate to `npm run <x>` — never the reverse. So this set
4
- // is identical regardless of orchestrator; only the UI/console distinction
5
- // changes it (Playwright e2e).
3
+ // thin targets that delegate to `npm run <x>` — never the reverse. Two axes vary
4
+ // the set: UI/console (Playwright e2e) and library/app. `build` is universal
5
+ // (both archetypes compile); only a publishable library adds `prepack`, which
6
+ // builds dist/ at publish time so `changeset publish` ships compiled output.
6
7
 
7
- export function canonicalScripts({ ui = false } = {}) {
8
+ export function canonicalScripts({ ui = false, library = false } = {}) {
8
9
  const ci = ui
9
10
  ? "npm run check-all-format && npm run test && npm run test:e2e"
10
11
  : "npm run check-all-format && npm run test";
@@ -21,12 +22,10 @@ export function canonicalScripts({ ui = false } = {}) {
21
22
  "npm run check-code-formatting && npm run check-markdown-docs",
22
23
  "check-code-formatting": "prettier --check src/",
23
24
  "check-markdown-docs": "autogen-markdown-doc check",
24
- // Build at publish time so `changeset publish` ships compiled dist/ without
25
- // the release workflow needing a build step.
26
- prepack: "npm run build",
27
25
  };
28
26
 
29
27
  if (ui) scripts["test:e2e"] = "doikayt-playwright-install && playwright test";
28
+ if (library) scripts.prepack = "npm run build";
30
29
 
31
30
  return scripts;
32
31
  }
@@ -37,21 +36,26 @@ export function devDependencyNames({ ui = false } = {}) {
37
36
  return names;
38
37
  }
39
38
 
40
- // Top-level package.json fields init sets (non-destructively) so a fresh project
41
- // builds to dist/ and publishes a compiled, importable ESM package. Assumes the
42
- // canonical src/index.ts entry point; a consumer that wants a different shape
43
- // sets these first and init leaves them untouched.
44
- export function packageFields() {
45
- return {
46
- type: "module",
47
- main: "dist/index.js",
48
- types: "dist/index.d.ts",
49
- exports: {
39
+ // Top-level package.json fields init sets (non-destructively). `type: "module"`
40
+ // is universal. A publishable **library** also gets the dist/-based entry points
41
+ // (main/types/exports) and the tarball allow-list (files), assuming the canonical
42
+ // src/index.ts entry. An **app** is instead marked `private` so `changeset
43
+ // publish` never publishes it — its release is a version bump + tag only. Either
44
+ // way, fields a consumer already set are left untouched by the caller.
45
+ export function packageFields({ library = false } = {}) {
46
+ const fields = { type: "module" };
47
+ if (library) {
48
+ fields.main = "dist/index.js";
49
+ fields.types = "dist/index.d.ts";
50
+ fields.exports = {
50
51
  ".": {
51
52
  types: "./dist/index.d.ts",
52
53
  default: "./dist/index.js",
53
54
  },
54
- },
55
- files: ["dist"],
56
- };
55
+ };
56
+ fields.files = ["dist"];
57
+ } else {
58
+ fields.private = true;
59
+ }
60
+ return fields;
57
61
  }
package/src/init.js CHANGED
@@ -66,13 +66,18 @@ export async function runInit({
66
66
  "Is this a UI project that needs Playwright (e2e)? [y/N] ",
67
67
  );
68
68
 
69
- const scripts = canonicalScripts({ ui });
69
+ const library = await prompt(
70
+ "Is this a publishable library (published to npm)? Apps/CLIs answer No and\n" +
71
+ "are marked private so they are never published. [y/N] ",
72
+ );
73
+
74
+ const scripts = canonicalScripts({ ui, library });
70
75
  const devDependencies = resolveDevVersions(devDependencyNames({ ui }));
71
76
 
72
77
  const { text, added, skipped } = applyToPackageJson(raw, {
73
78
  scripts,
74
79
  devDependencies,
75
- fields: packageFields(),
80
+ fields: packageFields({ library }),
76
81
  });
77
82
  writeFileSync(pkgPath, text);
78
83
 
@@ -111,7 +116,7 @@ export async function runInit({
111
116
  async function maybeScaffoldDemo({ cwd, prompt, log }) {
112
117
  const wantDemo = await prompt(
113
118
  "Scaffold a starter demo (minimal src module + README + project.json) so you\n" +
114
- "can build, test, and publish immediately? Existing files are never\n" +
119
+ "can build, test, and release immediately? Existing files are never\n" +
115
120
  "overwritten. [y/N] ",
116
121
  );
117
122
  if (!wantDemo) {
@@ -38,5 +38,5 @@ Mermaid diagrams inline from the fenced blocks.
38
38
  npm install # fetch the dev deps init declared
39
39
  npm test # the seeded vitest test passes
40
40
  npm run update-all-format # fills the doc blocks above
41
- git commit -am "feat: initial version" && git push # feat:/fix: trigger a publish
41
+ git commit -am "feat: initial version" && git push # feat:/fix: cut a release (npm publish if a library)
42
42
  ```