@techninja/clearstack 0.3.14 → 0.3.15

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/lib/check.js CHANGED
@@ -42,11 +42,9 @@ export function loadConfig(projectDir) {
42
42
  };
43
43
  }
44
44
 
45
- /**
46
- * Build check commands for the detected package manager.
47
- * @param {string} runner
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(detectRunner(projectDir));
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('Running spec compliance check...\n');
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)}`);
@@ -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: 'clearstack',
24
+ spec: 'node scripts/spec.js',
25
25
  };
26
26
 
27
27
  const specDeps = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@techninja/clearstack",
3
- "version": "0.3.14",
3
+ "version": "0.3.15",
4
4
  "type": "module",
5
5
  "description": "A no-build web component framework specification — scaffold, validate, and evolve spec-compliant projects",
6
6
  "bin": {
@@ -24,20 +24,8 @@ jobs:
24
24
  - name: Install Playwright Chromium
25
25
  run: npx playwright install chromium --with-deps
26
26
 
27
- - name: Code line counts (≤150)
28
- run: node scripts/spec.js code
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
@@ -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
+ }