@techninja/clearstack 0.3.5 → 0.3.7

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
@@ -10,6 +10,13 @@ import { checkFileLines, runCmd, countFiles } from './spec-utils.js';
10
10
 
11
11
  export { checkFileLines, runCmd, countFiles, findFiles, elapsed } from './spec-utils.js';
12
12
 
13
+ /** Detect the project's package manager runner (npx, pnpm exec, yarn). */
14
+ function detectRunner(projectDir) {
15
+ if (existsSync(resolve(projectDir, 'pnpm-lock.yaml'))) return 'pnpm exec';
16
+ if (existsSync(resolve(projectDir, 'yarn.lock'))) return 'yarn';
17
+ return 'npx';
18
+ }
19
+
13
20
  /** @param {string} src */
14
21
  function parseEnv(src) {
15
22
  const env = {};
@@ -36,15 +43,24 @@ export function loadConfig(projectDir) {
36
43
  };
37
44
  }
38
45
 
39
- /** Standard check commands used by both CLI and POC. */
40
- export const CMDS = {
41
- lint: 'npx eslint --config .configs/eslint.config.js . --fix',
42
- stylelint: 'npx stylelint --config .configs/.stylelintrc.json "src/**/*.css" --fix',
43
- prettier: 'npx prettier --config .configs/.prettierrc --write src scripts',
44
- mdlint: 'npx markdownlint-cli2 --config .configs/.markdownlint.jsonc --fix "docs/**/*.md" "*.md"',
45
- types: 'npx tsc --project .configs/jsconfig.json',
46
- audit: 'npm audit --omit=dev',
47
- };
46
+ /**
47
+ * Build check commands for the detected package manager.
48
+ * @param {string} runner
49
+ */
50
+ function buildCmds(runner) {
51
+ const audit = runner === 'pnpm exec' ? 'pnpm audit --prod' : 'npm audit --omit=dev';
52
+ return {
53
+ lint: `${runner} eslint --config .configs/eslint.config.js . --fix`,
54
+ stylelint: `${runner} stylelint --config .configs/.stylelintrc.json "src/**/*.css" --fix`,
55
+ prettier: `${runner} prettier --config .configs/.prettierrc --write src scripts`,
56
+ mdlint: `${runner} markdownlint-cli2 --config .configs/.markdownlint.jsonc --fix "docs/**/*.md" "*.md"`,
57
+ types: `${runner} tsc --project .configs/jsconfig.json`,
58
+ audit,
59
+ };
60
+ }
61
+
62
+ /** @deprecated Use buildCmds() instead — kept for backward compat. */
63
+ export const CMDS = buildCmds('npx');
48
64
 
49
65
  /**
50
66
  * Run the full spec compliance check (used by clearstack CLI).
@@ -53,6 +69,7 @@ export const CMDS = {
53
69
  */
54
70
  export async function check(projectDir, scope) {
55
71
  const cfg = loadConfig(projectDir);
72
+ const cmds = buildCmds(detectRunner(projectDir));
56
73
 
57
74
  if (scope === 'code') {
58
75
  if (!checkFileLines(projectDir, cfg.codeExt, cfg.codeMax, cfg.ignore, `Code (max ${cfg.codeMax} lines)`))
@@ -73,12 +90,12 @@ export async function check(projectDir, scope) {
73
90
  const results = [
74
91
  checkFileLines(projectDir, cfg.codeExt, cfg.codeMax, cfg.ignore, `Code (max ${cfg.codeMax} lines)`),
75
92
  checkFileLines(projectDir, cfg.docsExt, cfg.docsMax, cfg.ignore, `Docs (max ${cfg.docsMax} lines)`),
76
- runCmd('ESLint', CMDS.lint, projectDir, `${jsFiles} files`),
77
- runCmd('Stylelint', CMDS.stylelint, projectDir, `${cssFiles} files`),
78
- runCmd('Prettier', CMDS.prettier, projectDir, `${jsFiles} files`),
79
- runCmd('Markdown', CMDS.mdlint, projectDir, `${mdFiles} files`),
80
- runCmd('JSDoc types', CMDS.types, projectDir, `${jsFiles} files`),
81
- runCmd('Security audit', CMDS.audit, projectDir),
93
+ runCmd('ESLint', cmds.lint, projectDir, `${jsFiles} files`),
94
+ runCmd('Stylelint', cmds.stylelint, projectDir, `${cssFiles} files`),
95
+ runCmd('Prettier', cmds.prettier, projectDir, `${jsFiles} files`),
96
+ runCmd('Markdown', cmds.mdlint, projectDir, `${mdFiles} files`),
97
+ runCmd('JSDoc types', cmds.types, projectDir, `${jsFiles} files`),
98
+ runCmd('Security audit', cmds.audit, projectDir),
82
99
  ];
83
100
 
84
101
  const passed = results.filter(Boolean).length;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@techninja/clearstack",
3
- "version": "0.3.5",
3
+ "version": "0.3.7",
4
4
  "type": "module",
5
5
  "description": "A no-build web component framework specification — scaffold, validate, and evolve spec-compliant projects",
6
6
  "bin": {
@@ -20,7 +20,7 @@
20
20
  "start": "node src/server.js",
21
21
  "dev": "node --watch --env-file=.env --env-file=.env.local src/server.js",
22
22
  "setup": "node scripts/vendor-deps.js && node scripts/build-icons.js",
23
- "test": "node --test tests/*.test.js src/utils/*.test.js src/store/*.test.js",
23
+ "test": "node scripts/test.js",
24
24
  "spec": "node --env-file=.env scripts/spec.js",
25
25
  "lint": "eslint --config .configs/eslint.config.js . --fix",
26
26
  "format": "prettier --config .configs/.prettierrc --write src scripts tests templates/**/*.md templates/**/*.html templates/**/*.css templates/**/*.json",
@@ -1,37 +1,57 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * Test runner — finds and executes all .test.js files.
4
+ * Test runner — runs node tests directly, browser tests via web-test-runner.
5
+ * Browser tests live in src/components/. Everything else runs in Node.
5
6
  * @module scripts/test
6
7
  */
7
8
 
8
9
  import { execSync } from 'node:child_process';
9
10
  import { dirname, resolve } from 'node:path';
10
11
  import { fileURLToPath } from 'node:url';
11
- import { readdirSync, statSync } from 'node:fs';
12
+ import { readdirSync, existsSync } from 'node:fs';
12
13
 
13
14
  const ROOT = dirname(dirname(fileURLToPath(import.meta.url)));
14
15
 
15
16
  /** @param {string} dir @returns {string[]} */
16
17
  function findTests(dir) {
17
18
  const results = [];
19
+ if (!existsSync(dir)) return results;
18
20
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
19
21
  const full = resolve(dir, entry.name);
20
- if (entry.name === 'node_modules' || entry.name === 'public') continue;
22
+ if (entry.name === 'node_modules' || entry.name === 'vendor') continue;
21
23
  if (entry.isDirectory()) results.push(...findTests(full));
22
24
  else if (entry.name.endsWith('.test.js')) results.push(full);
23
25
  }
24
26
  return results;
25
27
  }
26
28
 
27
- const files = findTests(ROOT);
28
- if (files.length === 0) {
29
- console.log('No test files found.');
30
- process.exit(0);
29
+ const componentDir = resolve(ROOT, 'src/components');
30
+ const allTests = findTests(ROOT);
31
+ const nodeTests = allTests.filter((f) => !f.startsWith(componentDir));
32
+ const browserTests = allTests.filter((f) => f.startsWith(componentDir));
33
+ let failed = false;
34
+
35
+ if (nodeTests.length > 0) {
36
+ console.log(`Running ${nodeTests.length} node test(s)...\n`);
37
+ try {
38
+ execSync(`node --test ${nodeTests.join(' ')}`, { cwd: ROOT, stdio: 'inherit' });
39
+ } catch {
40
+ failed = true;
41
+ }
31
42
  }
32
43
 
33
- try {
34
- execSync(`node --test ${files.join(' ')}`, { cwd: ROOT, stdio: 'inherit' });
35
- } catch {
36
- process.exit(1);
44
+ if (browserTests.length > 0) {
45
+ console.log(`\nRunning ${browserTests.length} browser test(s)...\n`);
46
+ try {
47
+ execSync('npx web-test-runner --config .configs/web-test-runner.config.js', {
48
+ cwd: ROOT,
49
+ stdio: 'inherit',
50
+ });
51
+ } catch {
52
+ failed = true;
53
+ }
37
54
  }
55
+
56
+ if (allTests.length === 0) console.log('No test files found.');
57
+ if (failed) process.exit(1);