@techninja/clearstack 0.3.14 → 0.3.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 +8 -6
- package/bin/cli.js +2 -2
- package/docs/CONVENTIONS.md +1 -1
- package/docs/QUICKSTART.md +30 -24
- package/lib/check.js +6 -10
- package/lib/package-gen.js +1 -1
- package/lib/update.js +16 -8
- package/package.json +1 -1
- package/templates/shared/.github/workflows/spec.yml +2 -14
- package/templates/shared/docs/clearstack/CONVENTIONS.md +1 -1
- package/templates/shared/docs/clearstack/QUICKSTART.md +30 -24
- package/templates/shared/scripts/spec.js +63 -0
package/README.md
CHANGED
|
@@ -50,8 +50,9 @@ npm install -D @techninja/clearstack # add to your project
|
|
|
50
50
|
npx clearstack init # scaffold (interactive)
|
|
51
51
|
npx clearstack init -y # scaffold (fullstack defaults)
|
|
52
52
|
npx clearstack init --static # scaffold (static, no server)
|
|
53
|
+
npx clearstack update # sync docs (skip existing configs)
|
|
54
|
+
npx clearstack update --force # sync docs + overwrite configs
|
|
53
55
|
npm run spec # check compliance
|
|
54
|
-
npm run spec:update # sync docs + configs on upgrade
|
|
55
56
|
```
|
|
56
57
|
|
|
57
58
|
Two modes: **fullstack** (Express + WebSocket + JSON DB + SSE) or **static** (localStorage, no server).
|
|
@@ -65,7 +66,7 @@ See [QUICKSTART.md](./docs/QUICKSTART.md) for the full walkthrough.
|
|
|
65
66
|
- **Light DOM by default.** Shared styles just work.
|
|
66
67
|
- **JSDoc over TypeScript.** Types without a compile step — validated by `tsc --checkJs`.
|
|
67
68
|
- **Test at the boundary.** Each phase passes before the next begins.
|
|
68
|
-
- **The spec checks itself.** `npm run spec
|
|
69
|
+
- **The spec checks itself.** `npm run spec code` and `npm run spec docs`.
|
|
69
70
|
- **Lint and format.** ESLint + Prettier, semicolons, 2-space indent.
|
|
70
71
|
|
|
71
72
|
## Scripts
|
|
@@ -78,10 +79,11 @@ npm run lint # ESLint check
|
|
|
78
79
|
npm run lint:fix # ESLint auto-fix
|
|
79
80
|
npm run format # Prettier auto-format
|
|
80
81
|
npm run typecheck # JSDoc type validation via tsc
|
|
81
|
-
npm run spec # Spec compliance
|
|
82
|
-
npm run spec
|
|
83
|
-
npm run spec
|
|
84
|
-
npm run spec
|
|
82
|
+
npm run spec # Spec compliance (interactive)
|
|
83
|
+
npm run spec all # Full spec check
|
|
84
|
+
npm run spec code # Check code files ≤150 lines
|
|
85
|
+
npm run spec docs # Check doc files ≤500 lines
|
|
86
|
+
npm run spec update # Sync docs from upstream
|
|
85
87
|
```
|
|
86
88
|
|
|
87
89
|
## License
|
package/bin/cli.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* clearstack CLI — scaffold, update, and check spec-compliant projects.
|
|
5
5
|
* Usage:
|
|
6
6
|
* clearstack init [-y] [--static|--fullstack] [--port 3000]
|
|
7
|
-
* clearstack update
|
|
7
|
+
* clearstack update [--force]
|
|
8
8
|
* clearstack check [code|docs|imports|lint|lint es|format|types|audit|all]
|
|
9
9
|
* clearstack → interactive menu
|
|
10
10
|
*/
|
|
@@ -54,7 +54,7 @@ async function run(action) {
|
|
|
54
54
|
await init(PKG_ROOT, { yes, ...flags });
|
|
55
55
|
} else if (action === 'update') {
|
|
56
56
|
const { update } = await import('../lib/update.js');
|
|
57
|
-
await update(PKG_ROOT);
|
|
57
|
+
await update(PKG_ROOT, { force: !!flags.force });
|
|
58
58
|
} else if (action === 'check') {
|
|
59
59
|
const subs = args.filter((a) => a !== cmd && !a.startsWith('-'));
|
|
60
60
|
const { check } = await import('../lib/check.js');
|
package/docs/CONVENTIONS.md
CHANGED
|
@@ -298,7 +298,7 @@ multiple keys.
|
|
|
298
298
|
|
|
299
299
|
- **One script per domain.** `test`, `spec`, `lint` — not `test:node`,
|
|
300
300
|
`test:browser`, `lint:fix`, `spec:code`, `spec:docs`.
|
|
301
|
-
- **Arguments over aliases.** `pnpm spec
|
|
301
|
+
- **Arguments over aliases.** `pnpm spec code` instead of
|
|
302
302
|
`pnpm spec:code`. The CLI handles routing.
|
|
303
303
|
- **Interactive by default.** Running `pnpm spec` with no arguments shows
|
|
304
304
|
a menu of available actions. Users discover commands by using the tool.
|
package/docs/QUICKSTART.md
CHANGED
|
@@ -43,7 +43,7 @@ If a `package.json` already exists, Clearstack merges into it — your existing
|
|
|
43
43
|
|
|
44
44
|
```
|
|
45
45
|
your-project/
|
|
46
|
-
├── .configs/ #
|
|
46
|
+
├── .configs/ # ✏️ Scaffolded once — yours to customize
|
|
47
47
|
├── .github/ # CI workflow, PR + issue templates
|
|
48
48
|
├── docs/
|
|
49
49
|
│ ├── clearstack/ # ⟳ Managed — spec docs, synced on update
|
|
@@ -108,14 +108,16 @@ When Clearstack releases a new version:
|
|
|
108
108
|
|
|
109
109
|
```bash
|
|
110
110
|
npm update @techninja/clearstack # bump the package
|
|
111
|
-
npm run spec
|
|
111
|
+
npm run spec update # sync docs, skip existing configs
|
|
112
|
+
npm run spec update --force # sync docs + overwrite configs
|
|
112
113
|
git diff docs/ .configs/ # review what changed
|
|
113
114
|
```
|
|
114
115
|
|
|
115
116
|
This updates:
|
|
116
117
|
|
|
117
|
-
- `docs/clearstack/*.md` — spec documentation
|
|
118
|
-
- `.configs/*` —
|
|
118
|
+
- `docs/clearstack/*.md` — spec documentation (always overwritten)
|
|
119
|
+
- `.configs/*` — skipped if already exists (your customizations are safe)
|
|
120
|
+
- `.configs/*` with `--force` — overwritten with latest defaults
|
|
119
121
|
|
|
120
122
|
This never touches:
|
|
121
123
|
|
|
@@ -127,12 +129,16 @@ This never touches:
|
|
|
127
129
|
## 8. Spec Compliance
|
|
128
130
|
|
|
129
131
|
```bash
|
|
130
|
-
npm run spec #
|
|
131
|
-
npm run spec
|
|
132
|
-
npm run spec
|
|
133
|
-
npm run
|
|
134
|
-
npm run
|
|
135
|
-
npm run
|
|
132
|
+
npm run spec # interactive menu
|
|
133
|
+
npm run spec all # full check
|
|
134
|
+
npm run spec code # code files ≤150 lines
|
|
135
|
+
npm run spec docs # doc files ≤500 lines
|
|
136
|
+
npm run spec lint # ESLint + Stylelint + Markdown
|
|
137
|
+
npm run spec lint es # ESLint only
|
|
138
|
+
npm run spec format # Prettier
|
|
139
|
+
npm run spec imports # import map aliases
|
|
140
|
+
npm run spec types # JSDoc type validation
|
|
141
|
+
npm run spec audit # security audit
|
|
136
142
|
npm test # Node + browser tests
|
|
137
143
|
```
|
|
138
144
|
|
|
@@ -153,21 +159,21 @@ SPEC_IGNORE_DIRS=node_modules,src/vendor,.git,.configs
|
|
|
153
159
|
The scaffolded `.github/workflows/spec.yml` runs all checks on every PR:
|
|
154
160
|
|
|
155
161
|
```
|
|
156
|
-
spec
|
|
162
|
+
spec all → lint + format + code + docs + imports + types + audit
|
|
157
163
|
```
|
|
158
164
|
|
|
159
165
|
## Summary
|
|
160
166
|
|
|
161
|
-
| Task | Command
|
|
162
|
-
| --------------------- |
|
|
163
|
-
| Install Clearstack | `npm install -D @techninja/clearstack`
|
|
164
|
-
| Scaffold (fullstack) | `npx clearstack init`
|
|
165
|
-
| Scaffold (static) | `npx clearstack init --static`
|
|
166
|
-
| Install dependencies | `npm install`
|
|
167
|
-
| Start dev server | `npm run dev`
|
|
168
|
-
| Lint + format | `npm run lint
|
|
169
|
-
| Type check | `npm run typecheck`
|
|
170
|
-
| Run tests | `npm test`
|
|
171
|
-
| Full spec check | `npm run spec`
|
|
172
|
-
| Update spec + configs | `npm run spec
|
|
173
|
-
| Review spec changes | `git diff docs/ .configs/`
|
|
167
|
+
| Task | Command |
|
|
168
|
+
| --------------------- | ------------------------------------------ |
|
|
169
|
+
| Install Clearstack | `npm install -D @techninja/clearstack` |
|
|
170
|
+
| Scaffold (fullstack) | `npx clearstack init` |
|
|
171
|
+
| Scaffold (static) | `npx clearstack init --static` |
|
|
172
|
+
| Install dependencies | `npm install` |
|
|
173
|
+
| Start dev server | `npm run dev` |
|
|
174
|
+
| Lint + format | `npm run spec lint && npm run spec format` |
|
|
175
|
+
| Type check | `npm run typecheck` |
|
|
176
|
+
| Run tests | `npm test` |
|
|
177
|
+
| Full spec check | `npm run spec` |
|
|
178
|
+
| Update spec + configs | `npm run spec update` |
|
|
179
|
+
| Review spec changes | `git diff docs/ .configs/` |
|
package/lib/check.js
CHANGED
|
@@ -42,11 +42,9 @@ export function loadConfig(projectDir) {
|
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
/**
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
*/
|
|
49
|
-
function buildCmds(runner) {
|
|
45
|
+
/** Build check commands for the detected package manager. */
|
|
46
|
+
export function buildCmds(projectDir) {
|
|
47
|
+
const runner = detectRunner(projectDir);
|
|
50
48
|
const audit = runner === 'pnpm exec' ? 'pnpm audit --prod' : 'npm audit --omit=dev';
|
|
51
49
|
return {
|
|
52
50
|
lint: `${runner} eslint --config .configs/eslint.config.js . --fix`,
|
|
@@ -58,8 +56,6 @@ function buildCmds(runner) {
|
|
|
58
56
|
};
|
|
59
57
|
}
|
|
60
58
|
|
|
61
|
-
/** @deprecated Use buildCmds() instead — kept for backward compat. */
|
|
62
|
-
export const CMDS = buildCmds('npx');
|
|
63
59
|
|
|
64
60
|
/** @typedef {{ key: string, name: string, parent?: string, run: () => boolean }} Check */
|
|
65
61
|
|
|
@@ -108,10 +104,10 @@ export function parentKeys(checks) {
|
|
|
108
104
|
return [...new Set(checks.filter((c) => c.parent).map((c) => c.parent))];
|
|
109
105
|
}
|
|
110
106
|
|
|
111
|
-
/** Run the full spec compliance check (used by clearstack CLI). */
|
|
107
|
+
/** Run the full spec compliance check (used by clearstack CLI and scripts/spec.js). */
|
|
112
108
|
export async function check(projectDir, scope) {
|
|
113
109
|
const cfg = loadConfig(projectDir);
|
|
114
|
-
const cmds = buildCmds(
|
|
110
|
+
const cmds = buildCmds(projectDir);
|
|
115
111
|
const checks = buildChecks(projectDir, cfg, cmds);
|
|
116
112
|
|
|
117
113
|
if (scope && scope !== 'all') {
|
|
@@ -127,7 +123,7 @@ export async function check(projectDir, scope) {
|
|
|
127
123
|
return;
|
|
128
124
|
}
|
|
129
125
|
|
|
130
|
-
console.log('
|
|
126
|
+
console.log('🔍 Clearstack compliance checking now... 💙\n');
|
|
131
127
|
const results = checks.map((c) => c.run());
|
|
132
128
|
const passed = results.filter(Boolean).length;
|
|
133
129
|
console.log(`\n${'='.repeat(40)}`);
|
package/lib/package-gen.js
CHANGED
|
@@ -21,7 +21,7 @@ export async function writePackageJson(dest, vars, existing) {
|
|
|
21
21
|
dev: 'node --watch --env-file=.env --env-file=.env.local src/server.js',
|
|
22
22
|
postinstall: 'node scripts/setup.js',
|
|
23
23
|
test: 'node scripts/test.js',
|
|
24
|
-
spec: '
|
|
24
|
+
spec: 'node scripts/spec.js',
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
const specDeps = {
|
package/lib/update.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Spec updater — syncs docs and configs from the clearstack package.
|
|
3
|
-
*
|
|
3
|
+
* Docs are overwritten (clearstack-owned). Configs skip existing files
|
|
4
|
+
* to preserve project customizations — use --force to overwrite.
|
|
4
5
|
* @module lib/update
|
|
5
6
|
*/
|
|
6
7
|
|
|
@@ -8,24 +9,27 @@ import { readdirSync, readFileSync, writeFileSync, existsSync, mkdirSync } from
|
|
|
8
9
|
import { resolve, join } from 'node:path';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
|
-
* Sync a source directory to a destination
|
|
12
|
+
* Sync a source directory to a destination.
|
|
12
13
|
* @param {string} src
|
|
13
14
|
* @param {string} dest
|
|
14
15
|
* @param {string} label
|
|
16
|
+
* @param {{ skipExisting?: boolean }} [opts]
|
|
15
17
|
* @returns {number} count of updated files
|
|
16
18
|
*/
|
|
17
|
-
function syncDir(src, dest, label) {
|
|
19
|
+
function syncDir(src, dest, label, opts = {}) {
|
|
18
20
|
if (!existsSync(src)) return 0;
|
|
19
21
|
mkdirSync(dest, { recursive: true });
|
|
20
|
-
|
|
21
22
|
const files = readdirSync(src).filter((f) => !f.startsWith('.spec'));
|
|
22
23
|
let updated = 0;
|
|
23
24
|
|
|
24
25
|
for (const file of files) {
|
|
25
|
-
const srcContent = readFileSync(join(src, file), 'utf-8');
|
|
26
26
|
const destPath = join(dest, file);
|
|
27
|
+
if (opts.skipExisting && existsSync(destPath)) {
|
|
28
|
+
console.log(` ⏭ Skipped: ${label}/${file} (exists, use --force to overwrite)`);
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const srcContent = readFileSync(join(src, file), 'utf-8');
|
|
27
32
|
const destContent = existsSync(destPath) ? readFileSync(destPath, 'utf-8') : '';
|
|
28
|
-
|
|
29
33
|
if (srcContent !== destContent) {
|
|
30
34
|
writeFileSync(destPath, srcContent);
|
|
31
35
|
console.log(` ✓ Updated: ${label}/${file}`);
|
|
@@ -36,25 +40,29 @@ function syncDir(src, dest, label) {
|
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
/**
|
|
39
|
-
* Update spec docs and configs from the clearstack package
|
|
43
|
+
* Update spec docs and configs from the clearstack package.
|
|
40
44
|
* @param {string} pkgRoot - Root of the clearstack package
|
|
45
|
+
* @param {{ force?: boolean }} [opts]
|
|
41
46
|
*/
|
|
42
|
-
export async function update(pkgRoot) {
|
|
47
|
+
export async function update(pkgRoot, opts = {}) {
|
|
43
48
|
const templateShared = resolve(pkgRoot, 'templates/shared');
|
|
44
49
|
let total = 0;
|
|
45
50
|
|
|
46
51
|
console.log('');
|
|
47
52
|
|
|
53
|
+
// Docs: always overwrite (clearstack-owned content)
|
|
48
54
|
total += syncDir(
|
|
49
55
|
resolve(templateShared, 'docs/clearstack'),
|
|
50
56
|
resolve(process.cwd(), 'docs/clearstack'),
|
|
51
57
|
'docs/clearstack',
|
|
52
58
|
);
|
|
53
59
|
|
|
60
|
+
// Configs: skip existing unless --force (project may have customized)
|
|
54
61
|
total += syncDir(
|
|
55
62
|
resolve(templateShared, '.configs'),
|
|
56
63
|
resolve(process.cwd(), '.configs'),
|
|
57
64
|
'.configs',
|
|
65
|
+
{ skipExisting: !opts.force },
|
|
58
66
|
);
|
|
59
67
|
|
|
60
68
|
// Merge .gitignore (append missing lines, never remove user entries)
|
package/package.json
CHANGED
|
@@ -24,20 +24,8 @@ jobs:
|
|
|
24
24
|
- name: Install Playwright Chromium
|
|
25
25
|
run: npx playwright install chromium --with-deps
|
|
26
26
|
|
|
27
|
-
- name:
|
|
28
|
-
run: node scripts/spec.js
|
|
29
|
-
|
|
30
|
-
- name: Doc line counts (≤500)
|
|
31
|
-
run: node scripts/spec.js docs
|
|
32
|
-
|
|
33
|
-
- name: ESLint
|
|
34
|
-
run: npx eslint --config .configs/eslint.config.js .
|
|
35
|
-
|
|
36
|
-
- name: Prettier
|
|
37
|
-
run: npx prettier --config .configs/.prettierrc --check src scripts server.js tests
|
|
38
|
-
|
|
39
|
-
- name: JSDoc types (tsc --checkJs)
|
|
40
|
-
run: npx tsc --project .configs/jsconfig.json
|
|
27
|
+
- name: Spec compliance
|
|
28
|
+
run: node scripts/spec.js all
|
|
41
29
|
|
|
42
30
|
- name: Node tests
|
|
43
31
|
run: node --test tests/*.test.js src/utils/*.test.js src/store/*.test.js
|
|
@@ -298,7 +298,7 @@ multiple keys.
|
|
|
298
298
|
|
|
299
299
|
- **One script per domain.** `test`, `spec`, `lint` — not `test:node`,
|
|
300
300
|
`test:browser`, `lint:fix`, `spec:code`, `spec:docs`.
|
|
301
|
-
- **Arguments over aliases.** `pnpm spec
|
|
301
|
+
- **Arguments over aliases.** `pnpm spec code` instead of
|
|
302
302
|
`pnpm spec:code`. The CLI handles routing.
|
|
303
303
|
- **Interactive by default.** Running `pnpm spec` with no arguments shows
|
|
304
304
|
a menu of available actions. Users discover commands by using the tool.
|
|
@@ -43,7 +43,7 @@ If a `package.json` already exists, Clearstack merges into it — your existing
|
|
|
43
43
|
|
|
44
44
|
```
|
|
45
45
|
your-project/
|
|
46
|
-
├── .configs/ #
|
|
46
|
+
├── .configs/ # ✏️ Scaffolded once — yours to customize
|
|
47
47
|
├── .github/ # CI workflow, PR + issue templates
|
|
48
48
|
├── docs/
|
|
49
49
|
│ ├── clearstack/ # ⟳ Managed — spec docs, synced on update
|
|
@@ -108,14 +108,16 @@ When Clearstack releases a new version:
|
|
|
108
108
|
|
|
109
109
|
```bash
|
|
110
110
|
npm update @techninja/clearstack # bump the package
|
|
111
|
-
npm run spec
|
|
111
|
+
npm run spec update # sync docs, skip existing configs
|
|
112
|
+
npm run spec update --force # sync docs + overwrite configs
|
|
112
113
|
git diff docs/ .configs/ # review what changed
|
|
113
114
|
```
|
|
114
115
|
|
|
115
116
|
This updates:
|
|
116
117
|
|
|
117
|
-
- `docs/clearstack/*.md` — spec documentation
|
|
118
|
-
- `.configs/*` —
|
|
118
|
+
- `docs/clearstack/*.md` — spec documentation (always overwritten)
|
|
119
|
+
- `.configs/*` — skipped if already exists (your customizations are safe)
|
|
120
|
+
- `.configs/*` with `--force` — overwritten with latest defaults
|
|
119
121
|
|
|
120
122
|
This never touches:
|
|
121
123
|
|
|
@@ -127,12 +129,16 @@ This never touches:
|
|
|
127
129
|
## 8. Spec Compliance
|
|
128
130
|
|
|
129
131
|
```bash
|
|
130
|
-
npm run spec #
|
|
131
|
-
npm run spec
|
|
132
|
-
npm run spec
|
|
133
|
-
npm run
|
|
134
|
-
npm run
|
|
135
|
-
npm run
|
|
132
|
+
npm run spec # interactive menu
|
|
133
|
+
npm run spec all # full check
|
|
134
|
+
npm run spec code # code files ≤150 lines
|
|
135
|
+
npm run spec docs # doc files ≤500 lines
|
|
136
|
+
npm run spec lint # ESLint + Stylelint + Markdown
|
|
137
|
+
npm run spec lint es # ESLint only
|
|
138
|
+
npm run spec format # Prettier
|
|
139
|
+
npm run spec imports # import map aliases
|
|
140
|
+
npm run spec types # JSDoc type validation
|
|
141
|
+
npm run spec audit # security audit
|
|
136
142
|
npm test # Node + browser tests
|
|
137
143
|
```
|
|
138
144
|
|
|
@@ -153,21 +159,21 @@ SPEC_IGNORE_DIRS=node_modules,src/vendor,.git,.configs
|
|
|
153
159
|
The scaffolded `.github/workflows/spec.yml` runs all checks on every PR:
|
|
154
160
|
|
|
155
161
|
```
|
|
156
|
-
spec
|
|
162
|
+
spec all → lint + format + code + docs + imports + types + audit
|
|
157
163
|
```
|
|
158
164
|
|
|
159
165
|
## Summary
|
|
160
166
|
|
|
161
|
-
| Task | Command
|
|
162
|
-
| --------------------- |
|
|
163
|
-
| Install Clearstack | `npm install -D @techninja/clearstack`
|
|
164
|
-
| Scaffold (fullstack) | `npx clearstack init`
|
|
165
|
-
| Scaffold (static) | `npx clearstack init --static`
|
|
166
|
-
| Install dependencies | `npm install`
|
|
167
|
-
| Start dev server | `npm run dev`
|
|
168
|
-
| Lint + format | `npm run lint
|
|
169
|
-
| Type check | `npm run typecheck`
|
|
170
|
-
| Run tests | `npm test`
|
|
171
|
-
| Full spec check | `npm run spec`
|
|
172
|
-
| Update spec + configs | `npm run spec
|
|
173
|
-
| Review spec changes | `git diff docs/ .configs/`
|
|
167
|
+
| Task | Command |
|
|
168
|
+
| --------------------- | ------------------------------------------ |
|
|
169
|
+
| Install Clearstack | `npm install -D @techninja/clearstack` |
|
|
170
|
+
| Scaffold (fullstack) | `npx clearstack init` |
|
|
171
|
+
| Scaffold (static) | `npx clearstack init --static` |
|
|
172
|
+
| Install dependencies | `npm install` |
|
|
173
|
+
| Start dev server | `npm run dev` |
|
|
174
|
+
| Lint + format | `npm run spec lint && npm run spec format` |
|
|
175
|
+
| Type check | `npm run typecheck` |
|
|
176
|
+
| Run tests | `npm test` |
|
|
177
|
+
| Full spec check | `npm run spec` |
|
|
178
|
+
| Update spec + configs | `npm run spec update` |
|
|
179
|
+
| Review spec changes | `git diff docs/ .configs/` |
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Spec enforcement — interactive menu + CLI shortcuts.
|
|
5
|
+
* Delegates all check logic to @techninja/clearstack.
|
|
6
|
+
* @module scripts/spec
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
loadConfig,
|
|
11
|
+
buildChecks,
|
|
12
|
+
buildCmds,
|
|
13
|
+
resolveChecks,
|
|
14
|
+
parentKeys,
|
|
15
|
+
check,
|
|
16
|
+
} from '@techninja/clearstack/lib/check.js';
|
|
17
|
+
|
|
18
|
+
const ROOT = new URL('..', import.meta.url).pathname.replace(/\/$/, '');
|
|
19
|
+
const [sub, subsub] = process.argv.slice(2);
|
|
20
|
+
const scope = subsub ? `${sub} ${subsub}` : sub;
|
|
21
|
+
|
|
22
|
+
if (scope) {
|
|
23
|
+
await check(ROOT, scope);
|
|
24
|
+
} else {
|
|
25
|
+
await interactive(ROOT);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Show interactive menu, then run the selected check. */
|
|
29
|
+
async function interactive(dir) {
|
|
30
|
+
const cfg = loadConfig(dir);
|
|
31
|
+
const checks = buildChecks(dir, cfg, buildCmds(dir));
|
|
32
|
+
try {
|
|
33
|
+
const { select } = await import('@inquirer/prompts');
|
|
34
|
+
const action = await select({
|
|
35
|
+
message: 'Spec checker — what do you want to validate?',
|
|
36
|
+
choices: menuChoices(checks),
|
|
37
|
+
});
|
|
38
|
+
await check(dir, action);
|
|
39
|
+
} catch (e) {
|
|
40
|
+
if (e?.name === 'ExitPromptError') process.exit(0);
|
|
41
|
+
throw e;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Build interactive menu choices with hierarchy. */
|
|
46
|
+
function menuChoices(checks) {
|
|
47
|
+
const choices = [];
|
|
48
|
+
const seen = new Set();
|
|
49
|
+
for (const c of checks) {
|
|
50
|
+
if (c.parent && !seen.has(c.parent)) {
|
|
51
|
+
seen.add(c.parent);
|
|
52
|
+
const kids = checks.filter((k) => k.parent === c.parent);
|
|
53
|
+
const label = kids.map((k) => k.name).join(' + ');
|
|
54
|
+
choices.push({ name: `${label} [${c.parent}]`, value: c.parent });
|
|
55
|
+
for (const k of kids)
|
|
56
|
+
choices.push({ name: ` ${k.name} [${c.parent} ${k.key}]`, value: `${c.parent} ${k.key}` });
|
|
57
|
+
} else if (!c.parent) {
|
|
58
|
+
choices.push({ name: `${c.name} [${c.key}]`, value: c.key });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
choices.push({ name: 'All (full spec check)', value: 'all' });
|
|
62
|
+
return choices;
|
|
63
|
+
}
|