@doikayt/typescript-build-config 0.1.17 → 0.1.19
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 +3 -2
- package/package.json +1 -1
- package/src/canonical-scripts.js +10 -1
- package/src/init.js +47 -14
package/README.md
CHANGED
|
@@ -142,8 +142,9 @@ npm install # fetch the declared devD
|
|
|
142
142
|
|
|
143
143
|
`init` writes the canonical scripts (`ci`, `build`, `test`, `update-all-format`,
|
|
144
144
|
`check-all-format`, and their sub-tasks), declares `vitest` +
|
|
145
|
-
`@doikayt/autogen-markdown-doc` + `typescript
|
|
146
|
-
`vitest.config.ts`. Answering the
|
|
145
|
+
`@doikayt/autogen-markdown-doc` + `typescript` + `@changesets/cli` (the release
|
|
146
|
+
pipeline needs it), and seeds a commented `vitest.config.ts`. Answering the
|
|
147
|
+
"publishable library?" prompt sets the publish
|
|
147
148
|
config — `private` for an app, or `prepack` + the `dist/`-based fields for a
|
|
148
149
|
library (see [The canonical script set](#the-canonical-script-set)).
|
|
149
150
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@doikayt/typescript-build-config",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.19",
|
|
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'.",
|
package/src/canonical-scripts.js
CHANGED
|
@@ -31,7 +31,16 @@ export function canonicalScripts({ ui = false, library = false } = {}) {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
export function devDependencyNames({ ui = false } = {}) {
|
|
34
|
-
|
|
34
|
+
// @changesets/cli is required by the release pipeline (release.yml runs
|
|
35
|
+
// `npx changeset version` / `publish`), so every consumer needs it installed —
|
|
36
|
+
// otherwise `npx changeset` can't resolve the `changeset` bin and the release
|
|
37
|
+
// job fails with "could not determine executable to run".
|
|
38
|
+
const names = [
|
|
39
|
+
"vitest",
|
|
40
|
+
"@doikayt/autogen-markdown-doc",
|
|
41
|
+
"typescript",
|
|
42
|
+
"@changesets/cli",
|
|
43
|
+
];
|
|
35
44
|
if (ui) names.push("@playwright/test");
|
|
36
45
|
return names;
|
|
37
46
|
}
|
package/src/init.js
CHANGED
|
@@ -42,38 +42,71 @@ function dirIsEmpty(dir) {
|
|
|
42
42
|
return !existsSync(dir) || readdirSync(dir).length === 0;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
// Default interactive prompt.
|
|
46
|
-
|
|
45
|
+
// Default interactive prompt. Buffers input lines as they arrive and lets each
|
|
46
|
+
// question pull the next one, so it works with both a live terminal and piped /
|
|
47
|
+
// non-interactive stdin (scripts, CI). `rl.question` alone drops lines that
|
|
48
|
+
// arrive before the next call — with a pipe every line lands at once, which made
|
|
49
|
+
// init silently no-op. On EOF, unanswered prompts default to No. Injectable, so
|
|
50
|
+
// runInit stays testable without stdin.
|
|
51
|
+
function createAskYesNo() {
|
|
47
52
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
const lines = []; // input lines not yet consumed by a prompt
|
|
54
|
+
const waiters = []; // prompt resolvers waiting for the next line
|
|
55
|
+
let closed = false;
|
|
56
|
+
rl.on("line", (line) => {
|
|
57
|
+
const waiter = waiters.shift();
|
|
58
|
+
if (waiter) waiter(line);
|
|
59
|
+
else lines.push(line);
|
|
60
|
+
});
|
|
61
|
+
rl.on("close", () => {
|
|
62
|
+
closed = true;
|
|
63
|
+
while (waiters.length) waiters.shift()("");
|
|
64
|
+
});
|
|
65
|
+
const ask = (question) =>
|
|
66
|
+
new Promise((res) => {
|
|
67
|
+
process.stdout.write(question);
|
|
68
|
+
const answer = (line) => res(/^y(es)?$/i.test(line.trim()));
|
|
69
|
+
if (lines.length) answer(lines.shift());
|
|
70
|
+
else if (closed) answer("");
|
|
71
|
+
else waiters.push(answer);
|
|
72
|
+
});
|
|
73
|
+
ask.close = () => rl.close();
|
|
74
|
+
return ask;
|
|
54
75
|
}
|
|
55
76
|
|
|
56
77
|
export async function runInit({
|
|
57
78
|
cwd = process.cwd(),
|
|
58
|
-
prompt
|
|
79
|
+
prompt,
|
|
59
80
|
resolveDevVersions = resolveVersions,
|
|
60
81
|
log = console.log,
|
|
61
82
|
} = {}) {
|
|
83
|
+
// One readline interface for all prompts (see createAskYesNo); close it even
|
|
84
|
+
// on error so a leftover interface never keeps the process alive.
|
|
85
|
+
const ownAsk = prompt ? null : createAskYesNo();
|
|
86
|
+
const ask = prompt ?? ownAsk;
|
|
87
|
+
try {
|
|
88
|
+
return await collectAndScaffold({ cwd, ask, resolveDevVersions, log });
|
|
89
|
+
} finally {
|
|
90
|
+
ownAsk?.close();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function collectAndScaffold({ cwd, ask, resolveDevVersions, log }) {
|
|
62
95
|
const pkgPath = resolve(cwd, "package.json");
|
|
63
96
|
const raw = readFileSync(pkgPath, "utf8");
|
|
64
97
|
|
|
65
98
|
// Collect every answer up front, before doing any work or printing next
|
|
66
99
|
// steps, so the flow reads: ask everything → act → report.
|
|
67
|
-
const ui = await
|
|
100
|
+
const ui = await ask(
|
|
68
101
|
"Is this a UI project that needs Playwright (e2e)? Default is No. [y/N] ",
|
|
69
102
|
);
|
|
70
103
|
|
|
71
|
-
const library = await
|
|
72
|
-
"Is this a publishable library (published to npm)? Default is No
|
|
73
|
-
"app/CLI
|
|
104
|
+
const library = await ask(
|
|
105
|
+
"Is this a publishable library (published to npm)? Default is No\n" +
|
|
106
|
+
" — a non-library (an app/CLI) is marked private so it is never published. [y/N] ",
|
|
74
107
|
);
|
|
75
108
|
|
|
76
|
-
const wantDemo = await
|
|
109
|
+
const wantDemo = await ask(
|
|
77
110
|
"Scaffold a starter demo (minimal src module + README + project.json) so\n" +
|
|
78
111
|
"you can build, test, and release immediately? Default is No; existing\n" +
|
|
79
112
|
"files are never overwritten. [y/N] ",
|