stay-gold 1.0.3 → 1.1.0
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/dist/bang.js +5 -22
- package/dist/css-named-colors.d.ts +1 -0
- package/dist/css-named-colors.js +8 -9
- package/dist/css-vars.d.ts +1 -0
- package/dist/css-vars.js +10 -15
- package/dist/index.d.ts +2 -4
- package/dist/index.js +52 -4
- package/dist/stay-gold.test.d.ts +1 -0
- package/dist/stay-gold.test.js +305 -0
- package/dist/todos.d.ts +1 -0
- package/dist/todos.js +9 -25
- package/dist/vitest.config.d.ts +2 -0
- package/dist/vitest.config.js +9 -0
- package/dist/walk.d.ts +2 -0
- package/dist/walk.js +18 -0
- package/package.json +8 -3
package/dist/bang.js
CHANGED
|
@@ -1,29 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// check-for-bang.js
|
|
3
3
|
// Script to check for the string "// !" in project files and exit with error if found
|
|
4
|
-
import {
|
|
5
|
-
import { resolve
|
|
6
|
-
import {
|
|
7
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
-
const __dirname = dirname(__filename);
|
|
4
|
+
import { readFileSync } from "node:fs";
|
|
5
|
+
import { resolve } from "node:path";
|
|
6
|
+
import { walk } from "./walk.js";
|
|
9
7
|
const exts = [".js", ".ts", ".astro", ".css", ".tsx"];
|
|
10
8
|
const rootDir = resolve(process.cwd(), "src");
|
|
11
9
|
const publicDir = resolve(process.cwd(), "public");
|
|
12
|
-
function walk(dir) {
|
|
13
|
-
let results = [];
|
|
14
|
-
const list = readdirSync(dir);
|
|
15
|
-
list.forEach((file) => {
|
|
16
|
-
const filePath = join(dir, file);
|
|
17
|
-
const stat = statSync(filePath);
|
|
18
|
-
if (stat === null || stat === void 0 ? void 0 : stat.isDirectory()) {
|
|
19
|
-
results = results.concat(walk(filePath));
|
|
20
|
-
}
|
|
21
|
-
else if (exts.includes(extname(file))) {
|
|
22
|
-
results.push(filePath);
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
return results;
|
|
26
|
-
}
|
|
27
10
|
function checkFiles(files) {
|
|
28
11
|
let found = false;
|
|
29
12
|
files.forEach((file) => {
|
|
@@ -37,8 +20,8 @@ function checkFiles(files) {
|
|
|
37
20
|
});
|
|
38
21
|
return found;
|
|
39
22
|
}
|
|
40
|
-
const srcFiles = walk(rootDir);
|
|
41
|
-
const publicFiles = walk(publicDir);
|
|
23
|
+
const srcFiles = walk(rootDir, exts);
|
|
24
|
+
const publicFiles = walk(publicDir, exts);
|
|
42
25
|
const allFiles = srcFiles.concat(publicFiles);
|
|
43
26
|
if (checkFiles(allFiles)) {
|
|
44
27
|
process.exit(1);
|
package/dist/css-named-colors.js
CHANGED
|
@@ -1,21 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
1
2
|
// check-css-named-colors.ts
|
|
2
3
|
// Script to check for usage of named CSS colors in styles folder
|
|
3
|
-
import
|
|
4
|
-
import
|
|
4
|
+
import { readFileSync, readdirSync } from "node:fs";
|
|
5
|
+
import { resolve, join, extname } from "node:path";
|
|
5
6
|
import { namedColors } from "./named-colors.js";
|
|
6
|
-
const
|
|
7
|
-
const stylesDir = path.resolve(__dirname, "src/styles");
|
|
7
|
+
const stylesDir = resolve(process.cwd(), "src/styles");
|
|
8
8
|
const exts = [".css"];
|
|
9
|
-
// List of named CSS colors (partial, can be expanded)
|
|
10
9
|
function walkCssFiles(dir) {
|
|
11
|
-
return
|
|
12
|
-
.filter((f) => exts.includes(
|
|
13
|
-
.map((f) =>
|
|
10
|
+
return readdirSync(dir)
|
|
11
|
+
.filter((f) => exts.includes(extname(f)))
|
|
12
|
+
.map((f) => join(dir, f));
|
|
14
13
|
}
|
|
15
14
|
function checkNamedColors(files) {
|
|
16
15
|
let totalCount = 0;
|
|
17
16
|
files.forEach((file) => {
|
|
18
|
-
const content =
|
|
17
|
+
const content = readFileSync(file, "utf8");
|
|
19
18
|
namedColors.forEach((color) => {
|
|
20
19
|
const regex = new RegExp(`\\b${color}\\b`, "gi");
|
|
21
20
|
const matches = content.match(regex);
|
package/dist/css-vars.d.ts
CHANGED
package/dist/css-vars.js
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
1
2
|
// check-css-vars.ts
|
|
2
3
|
// Script to check for usage of undefined CSS variables in styles folder
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
throw new Error("Cannot determine __dirname: require.main or require.main.filename is undefined.");
|
|
8
|
-
}
|
|
9
|
-
const __dirname = path.dirname(require.main.filename);
|
|
10
|
-
const stylesDir = path.resolve(__dirname, "src/styles");
|
|
11
|
-
const variablesFile = path.join(stylesDir, "variables.css");
|
|
4
|
+
import { readFileSync, readdirSync } from "node:fs";
|
|
5
|
+
import { resolve, join, basename } from "node:path";
|
|
6
|
+
const stylesDir = resolve(process.cwd(), "src/styles");
|
|
7
|
+
const variablesFile = join(stylesDir, "variables.css");
|
|
12
8
|
function getDefinedVars(file) {
|
|
13
|
-
const content =
|
|
9
|
+
const content = readFileSync(file, "utf8");
|
|
14
10
|
const varRegex = /--([\w-]+):/g;
|
|
15
11
|
const vars = new Set();
|
|
16
12
|
let match = varRegex.exec(content);
|
|
@@ -21,7 +17,7 @@ function getDefinedVars(file) {
|
|
|
21
17
|
return vars;
|
|
22
18
|
}
|
|
23
19
|
function getUsedVars(file) {
|
|
24
|
-
const content =
|
|
20
|
+
const content = readFileSync(file, "utf8");
|
|
25
21
|
const useRegex = /var\(--([\w-]+)\)/g;
|
|
26
22
|
const used = new Set();
|
|
27
23
|
let match = useRegex.exec(content);
|
|
@@ -32,10 +28,9 @@ function getUsedVars(file) {
|
|
|
32
28
|
return used;
|
|
33
29
|
}
|
|
34
30
|
function walkCssFiles(dir) {
|
|
35
|
-
return
|
|
36
|
-
.readdirSync(dir)
|
|
31
|
+
return readdirSync(dir)
|
|
37
32
|
.filter((f) => f.endsWith(".css") && f !== "variables.css")
|
|
38
|
-
.map((f) =>
|
|
33
|
+
.map((f) => join(dir, f));
|
|
39
34
|
}
|
|
40
35
|
const definedVars = getDefinedVars(variablesFile);
|
|
41
36
|
const cssFiles = walkCssFiles(stylesDir);
|
|
@@ -44,7 +39,7 @@ cssFiles.forEach((file) => {
|
|
|
44
39
|
const usedVars = getUsedVars(file);
|
|
45
40
|
usedVars.forEach((v) => {
|
|
46
41
|
if (!definedVars.has(v)) {
|
|
47
|
-
console.error(`Undefined CSS variable --${v} used in ${
|
|
42
|
+
console.error(`Undefined CSS variable --${v} used in ${basename(file)}`);
|
|
48
43
|
hasError = true;
|
|
49
44
|
}
|
|
50
45
|
});
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,4 +1,52 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// index.ts
|
|
3
|
+
// Main script to run all stay-gold checks in sequence
|
|
4
|
+
import { spawn } from "node:child_process";
|
|
5
|
+
const checks = [
|
|
6
|
+
{ name: "Bang Check", script: "./dist/bang.js" },
|
|
7
|
+
{ name: "TODO Check", script: "./dist/todos.js" },
|
|
8
|
+
{ name: "CSS Variables Check", script: "./dist/css-vars.js" },
|
|
9
|
+
{ name: "CSS Named Colors Check", script: "./dist/css-named-colors.js" }
|
|
10
|
+
];
|
|
11
|
+
async function runCheck(script, name) {
|
|
12
|
+
return new Promise((resolve) => {
|
|
13
|
+
console.log(`\n--- Running ${name} ---`);
|
|
14
|
+
const child = spawn("node", [script], {
|
|
15
|
+
stdio: "inherit",
|
|
16
|
+
cwd: process.cwd()
|
|
17
|
+
});
|
|
18
|
+
child.on("close", (code) => {
|
|
19
|
+
if (code === 0) {
|
|
20
|
+
console.log(`✅ ${name} passed`);
|
|
21
|
+
resolve(true);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
console.log(`❌ ${name} failed`);
|
|
25
|
+
resolve(false);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
async function runAllChecks() {
|
|
31
|
+
console.log("🚀 Running all Stay Gold checks...\n");
|
|
32
|
+
let allPassed = true;
|
|
33
|
+
for (const check of checks) {
|
|
34
|
+
const passed = await runCheck(check.script, check.name);
|
|
35
|
+
if (!passed) {
|
|
36
|
+
allPassed = false;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
console.log("\n" + "=".repeat(50));
|
|
40
|
+
if (allPassed) {
|
|
41
|
+
console.log("🎉 All checks passed! Your code stays gold! ✨");
|
|
42
|
+
process.exit(0);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
console.log("💥 Some checks failed. Please fix the issues above.");
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
runAllChecks().catch((error) => {
|
|
50
|
+
console.error("Error running checks:", error);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll, afterAll } from "vitest";
|
|
2
|
+
import { execSync } from "node:child_process";
|
|
3
|
+
import { mkdirSync, writeFileSync, rmSync, existsSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
describe("stay-gold command", () => {
|
|
6
|
+
const testDir = join(process.cwd(), "test-project");
|
|
7
|
+
const srcDir = join(testDir, "src");
|
|
8
|
+
const publicDir = join(testDir, "public");
|
|
9
|
+
const stylesDir = join(srcDir, "styles");
|
|
10
|
+
beforeAll(() => {
|
|
11
|
+
// Create test project structure
|
|
12
|
+
if (existsSync(testDir)) {
|
|
13
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
14
|
+
}
|
|
15
|
+
mkdirSync(srcDir, { recursive: true });
|
|
16
|
+
mkdirSync(publicDir, { recursive: true });
|
|
17
|
+
mkdirSync(stylesDir, { recursive: true });
|
|
18
|
+
// Create clean test files
|
|
19
|
+
writeFileSync(join(srcDir, "clean.ts"), "// This is a clean file\nconst x = 1;\n");
|
|
20
|
+
writeFileSync(join(stylesDir, "variables.css"), ":root {\n --primary: #000;\n --secondary: #fff;\n}\n");
|
|
21
|
+
writeFileSync(join(stylesDir, "styles.css"), ".test { color: var(--primary); }\n");
|
|
22
|
+
// Build the project to ensure dist exists
|
|
23
|
+
try {
|
|
24
|
+
execSync("npm run build", { cwd: process.cwd(), stdio: "pipe" });
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
console.error("Build failed:", error);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
afterAll(() => {
|
|
31
|
+
// Cleanup test directory
|
|
32
|
+
if (existsSync(testDir)) {
|
|
33
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
describe("1. Command runs successfully without errors", () => {
|
|
37
|
+
it("should execute without throwing errors on clean project", () => {
|
|
38
|
+
expect(() => {
|
|
39
|
+
execSync("npm run find", {
|
|
40
|
+
cwd: testDir,
|
|
41
|
+
stdio: "pipe",
|
|
42
|
+
encoding: "utf-8",
|
|
43
|
+
});
|
|
44
|
+
}).not.toThrow();
|
|
45
|
+
});
|
|
46
|
+
it("should execute todos checker without errors", () => {
|
|
47
|
+
expect(() => {
|
|
48
|
+
execSync("npm run todos", {
|
|
49
|
+
cwd: testDir,
|
|
50
|
+
stdio: "pipe",
|
|
51
|
+
encoding: "utf-8",
|
|
52
|
+
});
|
|
53
|
+
}).not.toThrow();
|
|
54
|
+
});
|
|
55
|
+
it("should execute variables checker without errors on valid CSS", () => {
|
|
56
|
+
expect(() => {
|
|
57
|
+
execSync("npm run variables", {
|
|
58
|
+
cwd: testDir,
|
|
59
|
+
stdio: "pipe",
|
|
60
|
+
encoding: "utf-8",
|
|
61
|
+
});
|
|
62
|
+
}).not.toThrow();
|
|
63
|
+
});
|
|
64
|
+
it("should execute named-colors checker without errors", () => {
|
|
65
|
+
expect(() => {
|
|
66
|
+
execSync("npm run named-colors", {
|
|
67
|
+
cwd: testDir,
|
|
68
|
+
stdio: "pipe",
|
|
69
|
+
encoding: "utf-8",
|
|
70
|
+
});
|
|
71
|
+
}).not.toThrow();
|
|
72
|
+
});
|
|
73
|
+
it("should run all checks via gold command on clean project", () => {
|
|
74
|
+
const result = execSync("npm run gold", {
|
|
75
|
+
cwd: testDir,
|
|
76
|
+
stdio: "pipe",
|
|
77
|
+
encoding: "utf-8",
|
|
78
|
+
});
|
|
79
|
+
expect(result).toBeDefined();
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
describe("2. Command correctly executes all sub-commands", () => {
|
|
83
|
+
it("should detect forbidden bang comments", () => {
|
|
84
|
+
var _a, _b;
|
|
85
|
+
writeFileSync(join(srcDir, "with-bang.ts"), "// ! This should be detected\n");
|
|
86
|
+
try {
|
|
87
|
+
execSync(`node ${join(process.cwd(), "dist/bang.js")}`, {
|
|
88
|
+
cwd: testDir,
|
|
89
|
+
stdio: "pipe",
|
|
90
|
+
encoding: "utf-8",
|
|
91
|
+
});
|
|
92
|
+
expect.fail("Should have exited with error code 1");
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
expect(error.status).toBe(1);
|
|
96
|
+
const stderr = ((_a = error.stderr) === null || _a === void 0 ? void 0 : _a.toString()) || "";
|
|
97
|
+
const stdout = ((_b = error.stdout) === null || _b === void 0 ? void 0 : _b.toString()) || "";
|
|
98
|
+
const output = stderr + stdout;
|
|
99
|
+
expect(output).toContain("Forbidden string found");
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
// Cleanup
|
|
103
|
+
rmSync(join(srcDir, "with-bang.ts"), { force: true });
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
it("should detect and count TODO comments", () => {
|
|
107
|
+
writeFileSync(join(srcDir, "with-todo.ts"), "// TODO: Fix this later\nconst x = 1;\n");
|
|
108
|
+
try {
|
|
109
|
+
execSync(`node ${join(process.cwd(), "dist/todos.js")}`, {
|
|
110
|
+
cwd: testDir,
|
|
111
|
+
stdio: "pipe",
|
|
112
|
+
encoding: "utf-8",
|
|
113
|
+
});
|
|
114
|
+
expect.fail("Should have exited with error code 1");
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
expect(error.status).toBe(1);
|
|
118
|
+
expect(error.stdout.toString()).toContain("TODO(s) in");
|
|
119
|
+
expect(error.stderr.toString()).toContain("Total TODOs found: 1");
|
|
120
|
+
}
|
|
121
|
+
finally {
|
|
122
|
+
// Cleanup
|
|
123
|
+
rmSync(join(srcDir, "with-todo.ts"), { force: true });
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
it("should detect undefined CSS variables", () => {
|
|
127
|
+
writeFileSync(join(stylesDir, "bad-vars.css"), ".test { color: var(--undefined-var); }\n");
|
|
128
|
+
try {
|
|
129
|
+
execSync(`node ${join(process.cwd(), "dist/css-vars.js")}`, {
|
|
130
|
+
cwd: testDir,
|
|
131
|
+
stdio: "pipe",
|
|
132
|
+
encoding: "utf-8",
|
|
133
|
+
});
|
|
134
|
+
expect.fail("Should have exited with error code 1");
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
expect(error.status).toBe(1);
|
|
138
|
+
expect(error.stderr.toString()).toContain("Undefined CSS variable");
|
|
139
|
+
expect(error.stderr.toString()).toContain("undefined-var");
|
|
140
|
+
}
|
|
141
|
+
finally {
|
|
142
|
+
// Cleanup
|
|
143
|
+
rmSync(join(stylesDir, "bad-vars.css"), { force: true });
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
it("should detect named CSS colors", () => {
|
|
147
|
+
writeFileSync(join(stylesDir, "named-colors.css"), ".test { color: red; background: blue; }\n");
|
|
148
|
+
try {
|
|
149
|
+
execSync(`node ${join(process.cwd(), "dist/css-named-colors.js")}`, {
|
|
150
|
+
cwd: testDir,
|
|
151
|
+
stdio: "pipe",
|
|
152
|
+
encoding: "utf-8",
|
|
153
|
+
});
|
|
154
|
+
expect.fail("Should have exited with error code 1");
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
expect(error.status).toBe(1);
|
|
158
|
+
expect(error.stdout.toString()).toContain("named color");
|
|
159
|
+
expect(error.stderr.toString()).toContain("Total named CSS colors");
|
|
160
|
+
}
|
|
161
|
+
finally {
|
|
162
|
+
// Cleanup
|
|
163
|
+
rmSync(join(stylesDir, "named-colors.css"), { force: true });
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
it("should pass all checks when project is clean", () => {
|
|
167
|
+
const output = execSync(`node ${join(process.cwd(), "dist/bang.js")}`, {
|
|
168
|
+
cwd: testDir,
|
|
169
|
+
stdio: "pipe",
|
|
170
|
+
encoding: "utf-8",
|
|
171
|
+
});
|
|
172
|
+
expect(output).toContain("No forbidden string found");
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
describe("3. Command handles various input arguments or flags", () => {
|
|
176
|
+
it("should handle execution from different working directories", () => {
|
|
177
|
+
const output = execSync(`node ${join(process.cwd(), "dist/bang.js")}`, {
|
|
178
|
+
cwd: testDir,
|
|
179
|
+
stdio: "pipe",
|
|
180
|
+
encoding: "utf-8",
|
|
181
|
+
});
|
|
182
|
+
expect(output).toBeDefined();
|
|
183
|
+
});
|
|
184
|
+
it("should work when called via npm bin script", () => {
|
|
185
|
+
const output = execSync(`node ${join(process.cwd(), "dist/bang.js")}`, {
|
|
186
|
+
cwd: testDir,
|
|
187
|
+
stdio: "pipe",
|
|
188
|
+
encoding: "utf-8",
|
|
189
|
+
});
|
|
190
|
+
expect(output).toContain("No forbidden string found");
|
|
191
|
+
});
|
|
192
|
+
it("should handle projects with no src directory gracefully", () => {
|
|
193
|
+
const emptyTestDir = join(process.cwd(), "test-empty");
|
|
194
|
+
mkdirSync(emptyTestDir, { recursive: true });
|
|
195
|
+
try {
|
|
196
|
+
execSync(`node ${join(process.cwd(), "dist/bang.js")}`, {
|
|
197
|
+
cwd: emptyTestDir,
|
|
198
|
+
stdio: "pipe",
|
|
199
|
+
encoding: "utf-8",
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
// Should handle missing directories
|
|
204
|
+
expect(error).toBeDefined();
|
|
205
|
+
}
|
|
206
|
+
finally {
|
|
207
|
+
rmSync(emptyTestDir, { recursive: true, force: true });
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
it("should process multiple file types correctly", () => {
|
|
211
|
+
// Create files with different extensions
|
|
212
|
+
writeFileSync(join(srcDir, "test.js"), "const x = 1;\n");
|
|
213
|
+
writeFileSync(join(srcDir, "test.ts"), "const x: number = 1;\n");
|
|
214
|
+
writeFileSync(join(srcDir, "test.tsx"), "const x = <div />;\n");
|
|
215
|
+
writeFileSync(join(srcDir, "test.astro"), "---\nconst x = 1;\n---\n");
|
|
216
|
+
const output = execSync(`node ${join(process.cwd(), "dist/bang.js")}`, {
|
|
217
|
+
cwd: testDir,
|
|
218
|
+
stdio: "pipe",
|
|
219
|
+
encoding: "utf-8",
|
|
220
|
+
});
|
|
221
|
+
expect(output).toContain("No forbidden string found");
|
|
222
|
+
// Cleanup
|
|
223
|
+
rmSync(join(srcDir, "test.js"), { force: true });
|
|
224
|
+
rmSync(join(srcDir, "test.ts"), { force: true });
|
|
225
|
+
rmSync(join(srcDir, "test.tsx"), { force: true });
|
|
226
|
+
rmSync(join(srcDir, "test.astro"), { force: true });
|
|
227
|
+
});
|
|
228
|
+
it("should handle all comment styles for bang detection", () => {
|
|
229
|
+
// Test JavaScript style
|
|
230
|
+
writeFileSync(join(srcDir, "js-bang.js"), "// ! Error\n");
|
|
231
|
+
try {
|
|
232
|
+
execSync(`node ${join(process.cwd(), "dist/bang.js")}`, {
|
|
233
|
+
cwd: testDir,
|
|
234
|
+
stdio: "pipe",
|
|
235
|
+
});
|
|
236
|
+
expect.fail("Should detect // ! style");
|
|
237
|
+
}
|
|
238
|
+
catch (error) {
|
|
239
|
+
expect(error.status).toBe(1);
|
|
240
|
+
}
|
|
241
|
+
finally {
|
|
242
|
+
rmSync(join(srcDir, "js-bang.js"), { force: true });
|
|
243
|
+
}
|
|
244
|
+
// Test HTML style
|
|
245
|
+
writeFileSync(join(srcDir, "html-bang.astro"), "<!-- ! Error -->\n");
|
|
246
|
+
try {
|
|
247
|
+
execSync(`node ${join(process.cwd(), "dist/bang.js")}`, {
|
|
248
|
+
cwd: testDir,
|
|
249
|
+
stdio: "pipe",
|
|
250
|
+
});
|
|
251
|
+
expect.fail("Should detect <!-- ! style");
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
expect(error.status).toBe(1);
|
|
255
|
+
}
|
|
256
|
+
finally {
|
|
257
|
+
rmSync(join(srcDir, "html-bang.astro"), { force: true });
|
|
258
|
+
}
|
|
259
|
+
// Test JSX style
|
|
260
|
+
writeFileSync(join(srcDir, "jsx-bang.tsx"), "{/* ! Error */}\n");
|
|
261
|
+
try {
|
|
262
|
+
execSync(`node ${join(process.cwd(), "dist/bang.js")}`, {
|
|
263
|
+
cwd: testDir,
|
|
264
|
+
stdio: "pipe",
|
|
265
|
+
});
|
|
266
|
+
expect.fail("Should detect {/* ! style");
|
|
267
|
+
}
|
|
268
|
+
catch (error) {
|
|
269
|
+
expect(error.status).toBe(1);
|
|
270
|
+
}
|
|
271
|
+
finally {
|
|
272
|
+
rmSync(join(srcDir, "jsx-bang.tsx"), { force: true });
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
it("should exit with proper exit codes", () => {
|
|
276
|
+
// Test success exit code
|
|
277
|
+
try {
|
|
278
|
+
execSync(`node ${join(process.cwd(), "dist/bang.js")}`, {
|
|
279
|
+
cwd: testDir,
|
|
280
|
+
stdio: "pipe",
|
|
281
|
+
});
|
|
282
|
+
// If no error thrown, exit code was 0 (success)
|
|
283
|
+
expect(true).toBe(true);
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
expect.fail("Should exit with code 0 on clean project");
|
|
287
|
+
}
|
|
288
|
+
// Test failure exit code
|
|
289
|
+
writeFileSync(join(srcDir, "fail.ts"), "// ! Error\n");
|
|
290
|
+
try {
|
|
291
|
+
execSync(`node ${join(process.cwd(), "dist/bang.js")}`, {
|
|
292
|
+
cwd: testDir,
|
|
293
|
+
stdio: "pipe",
|
|
294
|
+
});
|
|
295
|
+
expect.fail("Should exit with code 1 on violations");
|
|
296
|
+
}
|
|
297
|
+
catch (error) {
|
|
298
|
+
expect(error.status).toBe(1);
|
|
299
|
+
}
|
|
300
|
+
finally {
|
|
301
|
+
rmSync(join(srcDir, "fail.ts"), { force: true });
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
});
|
package/dist/todos.d.ts
CHANGED
package/dist/todos.js
CHANGED
|
@@ -1,32 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
1
2
|
// check-todo.ts
|
|
2
3
|
// Script to check for the string "TODO:" in project files and count occurrences
|
|
3
|
-
|
|
4
|
-
import
|
|
5
|
-
import
|
|
4
|
+
import { readFileSync } from "node:fs";
|
|
5
|
+
import { resolve } from "node:path";
|
|
6
|
+
import { walk } from "./walk.js";
|
|
6
7
|
const exts = [".js", ".ts", ".astro", ".css", ".tsx"];
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const rootDir = path.resolve(__dirname, "src");
|
|
10
|
-
const publicDir = path.resolve(__dirname, "public");
|
|
11
|
-
function walk(dir) {
|
|
12
|
-
let results = [];
|
|
13
|
-
const list = fs.readdirSync(dir);
|
|
14
|
-
list.forEach((file) => {
|
|
15
|
-
const filePath = path.join(dir, file);
|
|
16
|
-
const stat = fs.statSync(filePath);
|
|
17
|
-
if (stat === null || stat === void 0 ? void 0 : stat.isDirectory()) {
|
|
18
|
-
results = results.concat(walk(filePath));
|
|
19
|
-
}
|
|
20
|
-
else if (exts.includes(path.extname(file))) {
|
|
21
|
-
results.push(filePath);
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
return results;
|
|
25
|
-
}
|
|
8
|
+
const rootDir = resolve(process.cwd(), "src");
|
|
9
|
+
const publicDir = resolve(process.cwd(), "public");
|
|
26
10
|
function checkTodos(files) {
|
|
27
11
|
let totalCount = 0;
|
|
28
12
|
files.forEach((file) => {
|
|
29
|
-
const content =
|
|
13
|
+
const content = readFileSync(file, "utf8");
|
|
30
14
|
const matches = content.match(/TODO:/g);
|
|
31
15
|
if (matches && matches.length > 0) {
|
|
32
16
|
console.log(`Found ${matches.length} TODO(s) in: ${file}`);
|
|
@@ -35,8 +19,8 @@ function checkTodos(files) {
|
|
|
35
19
|
});
|
|
36
20
|
return totalCount;
|
|
37
21
|
}
|
|
38
|
-
const srcFiles = walk(rootDir);
|
|
39
|
-
const publicFiles = walk(publicDir);
|
|
22
|
+
const srcFiles = walk(rootDir, exts);
|
|
23
|
+
const publicFiles = walk(publicDir, exts);
|
|
40
24
|
const allFiles = srcFiles.concat(publicFiles);
|
|
41
25
|
const todoCount = checkTodos(allFiles);
|
|
42
26
|
if (todoCount > 0) {
|
package/dist/walk.d.ts
ADDED
package/dist/walk.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { readdirSync, statSync } from "node:fs";
|
|
2
|
+
import { extname, join } from "node:path";
|
|
3
|
+
function walk(dir, exts) {
|
|
4
|
+
let results = [];
|
|
5
|
+
const list = readdirSync(dir);
|
|
6
|
+
list.forEach((file) => {
|
|
7
|
+
const filePath = join(dir, file);
|
|
8
|
+
const stat = statSync(filePath);
|
|
9
|
+
if (stat === null || stat === void 0 ? void 0 : stat.isDirectory()) {
|
|
10
|
+
results = results.concat(walk(filePath, exts));
|
|
11
|
+
}
|
|
12
|
+
else if (exts.includes(extname(file))) {
|
|
13
|
+
results.push(filePath);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
return results;
|
|
17
|
+
}
|
|
18
|
+
export { walk };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stay-gold",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Checks and balances for code quality. Run as a dev dependency in any project.",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -14,10 +14,13 @@
|
|
|
14
14
|
"stay-gold-find": "dist/bang.js",
|
|
15
15
|
"stay-gold-todos": "dist/todos.js",
|
|
16
16
|
"stay-gold-css-vars": "dist/css-vars.js",
|
|
17
|
-
"stay-gold-css-named-colors": "dist/css-named-colors.js"
|
|
17
|
+
"stay-gold-css-named-colors": "dist/css-named-colors.js",
|
|
18
|
+
"stay-gold": "dist/index.js"
|
|
18
19
|
},
|
|
19
20
|
"scripts": {
|
|
20
21
|
"build": "tsc",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"test:watch": "vitest",
|
|
21
24
|
"find": "node dist/bang.js",
|
|
22
25
|
"todos": "node dist/todos.js",
|
|
23
26
|
"variables": "node dist/css-vars.js",
|
|
@@ -37,7 +40,9 @@
|
|
|
37
40
|
"license": "ISC",
|
|
38
41
|
"devDependencies": {
|
|
39
42
|
"@types/node": "^24.3.1",
|
|
43
|
+
"@vitest/ui": "^4.0.5",
|
|
44
|
+
"string-checker": "latest",
|
|
40
45
|
"typescript": "^5.9.2",
|
|
41
|
-
"
|
|
46
|
+
"vitest": "^4.0.5"
|
|
42
47
|
}
|
|
43
48
|
}
|