@doikayt/typescript-build-config 0.1.20 → 0.1.22

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
@@ -5,6 +5,7 @@ Shared build configuration presets for TypeScript-based projects.
5
5
  <!-- TOC:START -->
6
6
  - [@doikayt/typescript-build-config](#doikayttypescript-build-config)
7
7
  - [Purpose](#purpose)
8
+ - [Quick start](#quick-start)
8
9
  - [Design Goals](#design-goals)
9
10
  - [What each component is for](#what-each-component-is-for)
10
11
  - [Installation](#installation)
@@ -13,6 +14,7 @@ Shared build configuration presets for TypeScript-based projects.
13
14
  - [Console / CLI project](#console--cli-project)
14
15
  - [UI / web project (with Playwright e2e)](#ui--web-project-with-playwright-e2e)
15
16
  - [Existing project](#existing-project)
17
+ - [Trying it out (demo + scratch repo)](#trying-it-out-demo--scratch-repo)
16
18
  - [Dependency Strategy](#dependency-strategy)
17
19
  - [Current Contents](#current-contents)
18
20
  - [Delivery Model](#delivery-model)
@@ -23,6 +25,7 @@ Shared build configuration presets for TypeScript-based projects.
23
25
  - [NX projects](#nx-projects)
24
26
  - [The `update-all-format` target](#the-update-all-format-target)
25
27
  - [Publishing](#publishing)
28
+ - [Team shell aliases](#team-shell-aliases)
26
29
  - [For Maintainers](#for-maintainers)
27
30
  - [Clone and install](#clone-and-install)
28
31
  - [Run the full CI suite](#run-the-full-ci-suite)
@@ -39,6 +42,40 @@ The plugin encapsulates common build **policy** and release **workflow logic**
39
42
  via the pipeline files it installs into each consumer repo and the canonical release process in
40
43
  [docs/RELEASE-PROCESS.md](docs/RELEASE-PROCESS.md).
41
44
 
45
+ ## Quick start
46
+
47
+ From a fresh machine to a pushed, scaffolded repo. Steps are minimal here — each
48
+ links to the section that explains _what_ and _why_.
49
+
50
+ **1. One-time machine setup.** Clone this base repo and install the shared team
51
+ [shell aliases](#team-shell-aliases):
52
+
53
+ ```bash
54
+ git clone git@github.com:doikayt/typescript-build-config.git
55
+ cd typescript-build-config
56
+ ./shell-assets/install.sh # adds `source shell-assets/aliases.sh` to your rc (idempotent)
57
+ exec $SHELL # reload
58
+ ```
59
+
60
+ **2. Create a new project.** One command creates the GitHub repo, scaffolds it
61
+ (build config + a runnable demo), and pushes it — choose `lib` (published) or
62
+ `app` (private, the default); see [library vs app](#usage) and
63
+ [Packaging concepts](docs/packaging-concepts.md):
64
+
65
+ ```bash
66
+ dk-scaffold my-project lib
67
+ ```
68
+
69
+ Or do it by hand / in an **existing** project — the same steps `dk-scaffold`
70
+ runs ([Installation](#installation) and [Usage](#usage) explain each):
71
+
72
+ ```bash
73
+ npx @doikayt/typescript-build-config new # npm init -y + @doikayt scope
74
+ npm install --save-dev @doikayt/typescript-build-config # postinstall seeds configs + pipeline
75
+ npx @doikayt/typescript-build-config init # scripts, deps, publish config, demo
76
+ npm install # fetch declared devDependencies
77
+ ```
78
+
42
79
  ## Design Goals
43
80
 
44
81
  The package housed in this repo is designed to be 'upstream-most' -- i.e., all other
@@ -78,11 +115,13 @@ is _why_.)
78
115
  | **Convention checks** — postinstall warns on missing `ci` / `update-all-format` | An install-time nudge toward the shared command surface | Consistency |
79
116
  | **`ci` gate** — `release.yml` runs `npm run ci` | Fail-closed enforcement: a repo that ignores the convention cannot release | Consistency (hard teeth) |
80
117
  | **Policy doc** — `docs/RELEASE-PROCESS.md`, linked never copied | One canonical release policy, impossible to drift | Consistency |
81
- | **Assets** — `assets/*` seeded into `docs/assets/` | Shared brand logos with no per-repo copies to maintain | Minimal setup |
118
+ | **Assets** — `image-assets/*` seeded into `docs/assets/` | Shared brand logos with no per-repo copies to maintain | Minimal setup |
119
+ | **Shell aliases** — `shell-assets/aliases.sh`, cloned + sourced (never shipped to npm) | One standard way for the team to create and scaffold repos (`mkrepo`, `dk-*`) | Consistency |
82
120
 
83
- The two goals map onto two lifecycle phases — **delivery** (getting canonical
84
- artifacts into a consuming repo) and **enforcement** (keeping that repo conformant over
85
- time). Each has its own top-level section below.
121
+ The two goals map onto two lifecycle phases — **[delivery](#delivery-model)**
122
+ (getting canonical artifacts into a consuming repo) and
123
+ **[enforcement](#enforcement-model)** (keeping that repo conformant over time).
124
+ Each has its own top-level section below.
86
125
 
87
126
  ## Installation
88
127
 
@@ -136,7 +175,7 @@ publish config accordingly (non-destructively):
136
175
  ### Console / CLI project
137
176
 
138
177
  ```bash
139
- npm init -y # if starting fresh
178
+ npx @doikayt/typescript-build-config new # npm init -y + @doikayt scope
140
179
  npm install --save-dev @doikayt/typescript-build-config
141
180
  npx @doikayt/typescript-build-config init # answer "n" to Playwright; "n" (app) or "y" (library)
142
181
  npm install # fetch the declared devDependencies
@@ -153,7 +192,7 @@ library (see [The canonical script set](#the-canonical-script-set)).
153
192
  ### UI / web project (with Playwright e2e)
154
193
 
155
194
  ```bash
156
- npm init -y
195
+ npx @doikayt/typescript-build-config new # npm init -y + @doikayt scope
157
196
  npm install --save-dev @doikayt/typescript-build-config
158
197
  npx @doikayt/typescript-build-config init # answer "y" to the Playwright prompt
159
198
  npm install
@@ -173,6 +212,22 @@ required targets (`ci`, `update-all-format`) until you add them — either by
173
212
  running `init` to adopt the full canonical set, or by defining the two scripts
174
213
  by hand (see [Conventions](#conventions-every-project-must-adhere-to)).
175
214
 
215
+ ### Trying it out (demo + scratch repo)
216
+
217
+ Answer **yes** to the demo prompt and `init` seeds a minimal starter — a `src/`
218
+ module, a `README` with doc-generator markers, and a `project.json` — so a
219
+ brand-new project builds, tests, and (for a library) publishes on push.
220
+
221
+ To exercise a scaffold end-to-end without standing up a repo, push it to the
222
+ shared throwaway repo
223
+ **[`doikayt/scratch-pad`](https://github.com/doikayt/scratch-pad)** (force-overwrite
224
+ each run). The full procedure — for both a library and an app, with what to look
225
+ for at each step — is in [docs/verification-runbook.md](docs/verification-runbook.md):
226
+
227
+ - [Pushing to the scratch repo](docs/verification-runbook.md#pushing-to-a-reusable-scratch-repo)
228
+ - [Testing publish without cluttering npm](docs/verification-runbook.md#testing-publish-without-cluttering-npm)
229
+ — dry-run / verdaccio, and deleting a real test publish afterward.
230
+
176
231
  ## Dependency Strategy
177
232
 
178
233
  `eslint` and `prettier` are listed as `dependencies` and are pulled in
@@ -185,6 +240,8 @@ versions of these tools may produce peer dependency conflicts.
185
240
 
186
241
  ## Current Contents
187
242
 
243
+ - `new` command (`npx @doikayt/typescript-build-config new`) — runs `npm init -y`
244
+ then scopes the package name to `@doikayt` (an existing scope is kept)
188
245
  - `init` scaffolder CLI (`npx @doikayt/typescript-build-config init`) — writes
189
246
  the canonical npm-script set, declares dev dependencies, and seeds config
190
247
  templates (see [Usage](#usage))
@@ -220,7 +277,7 @@ versions of these tools may produce peer dependency conflicts.
220
277
  });
221
278
  ```
222
279
 
223
- - Brand assets (`assets/doikayt-logo.png`, `assets/doikayt-logo.svg`) — shared logos for use
280
+ - Brand assets (`image-assets/doikayt-logo.png`, `image-assets/doikayt-logo.svg`) — shared logos for use
224
281
  across all `@doikayt` project READMEs and documentation
225
282
 
226
283
  ## Delivery Model
@@ -248,7 +305,7 @@ components.
248
305
  │ presets eslint prettier tsconfig playwright│
249
306
  │ stubs src/top-level/* │
250
307
  │ pipeline src/pipeline/* │
251
- │ assets assets/* │
308
+ │ assets image-assets/* │
252
309
  │ policy docs/RELEASE-PROCESS.md │
253
310
  └─────────┬───────────────┬───────────────┬───────┘
254
311
  │ │ │
@@ -300,6 +357,16 @@ components.
300
357
  their own contributor docs (as the consumer box shows) — never copied, so it cannot
301
358
  drift.
302
359
 
360
+ **Beyond consumer repos — the shell aliases.** The five components above all reach
361
+ a _consuming repo_ through npm (channels 1–3). The team
362
+ [shell aliases](#team-shell-aliases) are the exception: they target the
363
+ _developer's machine_, not a repo, through a fourth channel — **cloned and
364
+ sourced** (`git clone` this repo + `source shell-assets/aliases.sh`, via
365
+ `shell-assets/install.sh`). npm never touches them and they never land in a consumer's
366
+ `package.json` or tree. Same goal (a standard way to create repos), different
367
+ destination — which is why they sit outside the five-components / three-channels
368
+ model rather than as a sixth row in it.
369
+
303
370
  ## Enforcement Model
304
371
 
305
372
  _Phase 2 of 2: keeping a repo **conformant** over time, once delivery has seeded
@@ -473,6 +540,19 @@ release job until one is committed.
473
540
  **Manual publish (emergency):** trigger the workflow manually via
474
541
  **GitHub Actions → CI / Release → Run workflow** on the `main` branch.
475
542
 
543
+ ## Team shell aliases
544
+
545
+ Installed by [Quick start](#quick-start) step 1 (or manually: add
546
+ `source <clone-path>/shell-assets/aliases.sh` to your shell rc). They require `gh`
547
+ (authenticated) and `node`/`npm`.
548
+
549
+ | Alias | What it does |
550
+ | --- | --- |
551
+ | `mkrepo <name>` | Create a public repo in the `doikayt` org (guards against duplicates). |
552
+ | `dk-new` | `npm init -y` + `@doikayt` scope. |
553
+ | `dk-init` | Scaffold the build config into the current project. |
554
+ | `dk-scaffold <name> [lib\|app]` | Create the repo, scaffold, and push — one command (defaults to app). |
555
+
476
556
  ## For Maintainers
477
557
 
478
558
  ### Clone and install
@@ -509,7 +589,7 @@ npm run update-all-format && npm run ci
509
589
 
510
590
  To verify end-to-end that `init` scaffolds and ships both a library and an app —
511
591
  by hand, with what to look for at each step — follow
512
- [docs/e2e-verification.md](docs/e2e-verification.md).
592
+ [docs/verification-runbook.md](docs/verification-runbook.md).
513
593
 
514
594
  ## License
515
595
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doikayt/typescript-build-config",
3
- "version": "0.1.20",
3
+ "version": "0.1.22",
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'.",
@@ -21,7 +21,7 @@
21
21
  "files": [
22
22
  "src/",
23
23
  "src/top-level/.gitignore",
24
- "assets/"
24
+ "image-assets/"
25
25
  ],
26
26
  "scripts": {
27
27
  "prepack": "echo no build step required",
package/src/cli.js CHANGED
@@ -2,9 +2,10 @@
2
2
  // Main CLI entry for this package, registered as the `typescript-build-config`
3
3
  // bin. Invoked as `npx @doikayt/typescript-build-config <subcommand>` — npx
4
4
  // resolves the bin whose name matches the package. argv[2] is the subcommand
5
- // (argv[0]=node, argv[1]=this file). Today the only subcommand is `init`; this
6
- // dispatcher is the seam where future ones (e.g. `check-conventions`) plug in.
5
+ // (argv[0]=node, argv[1]=this file). This dispatcher is the seam where future
6
+ // subcommands (e.g. `check-conventions`) plug in.
7
7
  import { runInit } from "./init.js";
8
+ import { runNew } from "./new-package.js";
8
9
 
9
10
  const sub = process.argv[2];
10
11
 
@@ -18,9 +19,19 @@ if (sub === "init") {
18
19
  process.exit(1);
19
20
  },
20
21
  );
22
+ } else if (sub === "new") {
23
+ // `npm init -y` + @doikayt scope. Synchronous (spawnSync).
24
+ try {
25
+ runNew();
26
+ process.exit(0);
27
+ } catch (err) {
28
+ console.error(err?.message ?? err);
29
+ process.exit(1);
30
+ }
21
31
  } else {
22
32
  console.error(
23
- `Unknown command: ${sub ?? "(none)"}\nUsage: typescript-build-config init`,
33
+ `Unknown command: ${sub ?? "(none)"}\n` +
34
+ `Usage: typescript-build-config <new|init>`,
24
35
  );
25
36
  process.exit(1);
26
37
  }
package/src/init.js CHANGED
@@ -16,6 +16,7 @@ import {
16
16
  } from "./canonical-scripts.js";
17
17
  import { applyToPackageJson } from "./package-json.js";
18
18
  import { resolveVersions } from "./dep-versions.js";
19
+ import { scopeName } from "./scope-name.js";
19
20
 
20
21
  const templatesDir = fileURLToPath(new URL("templates/", import.meta.url));
21
22
 
@@ -76,11 +77,6 @@ function createAskYesNo() {
76
77
  return ask;
77
78
  }
78
79
 
79
- // Prepend the @doikayt scope unless the name is already scoped.
80
- function scopeName(name) {
81
- return name.startsWith("@") ? name : `@doikayt/${name}`;
82
- }
83
-
84
80
  export async function runInit({
85
81
  cwd = process.cwd(),
86
82
  prompt,
@@ -0,0 +1,38 @@
1
+ import { readFileSync, writeFileSync } from "fs";
2
+ import { resolve } from "path";
3
+ import { spawnSync } from "child_process";
4
+ import { scopeName } from "./scope-name.js";
5
+
6
+ // Default `npm init -y` runner. Injectable so runNew is testable without npm.
7
+ function npmInitY(cwd) {
8
+ const res = spawnSync("npm", ["init", "-y"], { cwd, stdio: "inherit" });
9
+ if (res.error) throw res.error;
10
+ if (res.status !== 0)
11
+ throw new Error(`npm init -y exited with ${res.status}`);
12
+ }
13
+
14
+ // Run `npm init -y`, then scope the generated package name to @doikayt unless it
15
+ // is already scoped (any @scope/ is left alone). Writes package.json back and
16
+ // returns the final name plus whether it changed.
17
+ export function runNew({
18
+ cwd = process.cwd(),
19
+ npmInit = npmInitY,
20
+ log = console.log,
21
+ } = {}) {
22
+ npmInit(cwd);
23
+
24
+ const pkgPath = resolve(cwd, "package.json");
25
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
26
+ const before = pkg.name || "package";
27
+ const scoped = scopeName(before);
28
+
29
+ if (scoped !== pkg.name) {
30
+ pkg.name = scoped;
31
+ writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
32
+ log(`Scoped package name: ${before} → ${scoped}`);
33
+ } else {
34
+ log(`Package name already scoped: ${scoped}`);
35
+ }
36
+
37
+ return { name: scoped, changed: scoped !== before };
38
+ }
@@ -15,9 +15,19 @@ const PREFIX = "[@doikayt/typescript-build-config]";
15
15
  console.log(`${PREFIX} Running postinstall...`);
16
16
 
17
17
  const projectRoot = process.env.INIT_CWD ?? process.cwd();
18
- const projectPkg = JSON.parse(
19
- readFileSync(resolve(projectRoot, "package.json"), "utf8"),
20
- );
18
+ const projectPkgPath = resolve(projectRoot, "package.json");
19
+
20
+ // Installed via `npx @doikayt/... new` into a bare dir (or otherwise before a
21
+ // consuming project has a package.json) — nothing to configure. Postinstall is
22
+ // warn-only, so no-op instead of crashing.
23
+ if (!existsSync(projectPkgPath)) {
24
+ console.log(
25
+ `${PREFIX} No package.json in ${projectRoot} — nothing to configure. Skipping.`,
26
+ );
27
+ process.exit(0);
28
+ }
29
+
30
+ const projectPkg = JSON.parse(readFileSync(projectPkgPath, "utf8"));
21
31
 
22
32
  if (projectPkg.name === "@doikayt/typescript-build-config") {
23
33
  console.log(`${PREFIX} Self-install detected — postinstall is a no-op.`);
@@ -101,7 +111,7 @@ for (const { src, dest } of pipelineFiles) {
101
111
 
102
112
  // --- Asset files: seeded into docs/assets/, same per-file copy/warn as pipeline ---
103
113
 
104
- const assetDir = new URL("../assets", import.meta.url).pathname;
114
+ const assetDir = new URL("../image-assets", import.meta.url).pathname;
105
115
 
106
116
  const assetFiles = [
107
117
  { src: "doikayt-logo.png", dest: "docs/assets/doikayt-logo.png" },
@@ -125,7 +135,7 @@ for (const { src, dest } of assetFiles) {
125
135
 
126
136
  console.warn(
127
137
  `${PREFIX} WARNING: ${dest} differs from canonical version — skipping. ` +
128
- `To resync: cp node_modules/@doikayt/typescript-build-config/assets/${src} ${dest}`,
138
+ `To resync: cp node_modules/@doikayt/typescript-build-config/image-assets/${src} ${dest}`,
129
139
  );
130
140
  }
131
141
 
@@ -0,0 +1,6 @@
1
+ // Prepend the @doikayt scope unless the name is already scoped — any existing
2
+ // @scope/ is left as-is. Shared by `init` (library name prompt) and the `new`
3
+ // command (scoped `npm init`).
4
+ export function scopeName(name) {
5
+ return name.startsWith("@") ? name : `@doikayt/${name}`;
6
+ }
File without changes
File without changes
File without changes