blotdev 1.0.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/LICENSE +21 -0
- package/README.md +74 -0
- package/blot.config.example.json +5 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +64 -0
- package/dist/config.js.map +1 -0
- package/dist/detectors.d.ts +3 -0
- package/dist/detectors.d.ts.map +1 -0
- package/dist/detectors.js +113 -0
- package/dist/detectors.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +65 -0
- package/dist/index.js.map +1 -0
- package/dist/output.d.ts +5 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +107 -0
- package/dist/output.js.map +1 -0
- package/dist/scanner.d.ts +4 -0
- package/dist/scanner.d.ts.map +1 -0
- package/dist/scanner.js +76 -0
- package/dist/scanner.js.map +1 -0
- package/dist/types.d.ts +17 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +53 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Blot Studios, LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# blotdev
|
|
2
|
+
|
|
3
|
+
Scan codebases for brand consistency issues. Catches hardcoded colors, fonts, and styles that should use design tokens.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install blotdev
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx blotdev # full scan, outputs brand-issues.md
|
|
15
|
+
npx blotdev --staged # staged files only (for pre-commit)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Config
|
|
19
|
+
|
|
20
|
+
Create `blot.config.json` in your project root:
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"colors": ["#1a1a1a", "#ffffff", "#FF6B35"],
|
|
25
|
+
"fonts": ["Inter", "Space Grotesk"],
|
|
26
|
+
"allowInlineStyles": false
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
| Option | Description |
|
|
31
|
+
|--------|-------------|
|
|
32
|
+
| `colors` | Allowed hex colors |
|
|
33
|
+
| `fonts` | Allowed font families |
|
|
34
|
+
| `allowInlineStyles` | Allow `style={{}}` in JSX |
|
|
35
|
+
|
|
36
|
+
## Output
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
Scanned 42 files
|
|
40
|
+
|
|
41
|
+
Colors (2):
|
|
42
|
+
src/components/Button.tsx:14 #3b82f6
|
|
43
|
+
src/components/Card.tsx:8 #ef4444
|
|
44
|
+
|
|
45
|
+
Fonts (1):
|
|
46
|
+
src/styles/globals.css:22 Helvetica
|
|
47
|
+
|
|
48
|
+
3 issues found.
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Full scans also write `brand-issues.md` with a checklist format.
|
|
52
|
+
|
|
53
|
+
## Pre-commit
|
|
54
|
+
|
|
55
|
+
With lint-staged:
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"lint-staged": {
|
|
60
|
+
"*.{ts,tsx,css,scss}": "blotdev --staged"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Options
|
|
66
|
+
|
|
67
|
+
| Flag | Description |
|
|
68
|
+
|------|-------------|
|
|
69
|
+
| `-s, --staged` | Scan staged files only |
|
|
70
|
+
| `-h, --help` | Show help |
|
|
71
|
+
|
|
72
|
+
## License
|
|
73
|
+
|
|
74
|
+
MIT - [Blot Studios, LLC](https://blot.dev)
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAQjC,wBAAgB,UAAU,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM,CAqB9D"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.loadConfig = loadConfig;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const DEFAULT_CONFIG = {
|
|
40
|
+
colors: [],
|
|
41
|
+
fonts: [],
|
|
42
|
+
allowInlineStyles: true,
|
|
43
|
+
};
|
|
44
|
+
function loadConfig(cwd = process.cwd()) {
|
|
45
|
+
const configPath = path.join(cwd, "blot.config.json");
|
|
46
|
+
if (!fs.existsSync(configPath)) {
|
|
47
|
+
console.error("Warning: No blot.config.json found, using defaults");
|
|
48
|
+
return DEFAULT_CONFIG;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
const raw = fs.readFileSync(configPath, "utf-8");
|
|
52
|
+
const parsed = JSON.parse(raw);
|
|
53
|
+
return {
|
|
54
|
+
colors: Array.isArray(parsed.colors) ? parsed.colors : [],
|
|
55
|
+
fonts: Array.isArray(parsed.fonts) ? parsed.fonts : [],
|
|
56
|
+
allowInlineStyles: parsed.allowInlineStyles ?? true,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
console.error("Warning: Failed to parse blot.config.json, using defaults");
|
|
61
|
+
return DEFAULT_CONFIG;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAUA,gCAqBC;AA/BD,uCAAyB;AACzB,2CAA6B;AAG7B,MAAM,cAAc,GAAW;IAC7B,MAAM,EAAE,EAAE;IACV,KAAK,EAAE,EAAE;IACT,iBAAiB,EAAE,IAAI;CACxB,CAAC;AAEF,SAAgB,UAAU,CAAC,MAAc,OAAO,CAAC,GAAG,EAAE;IACpD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC;IAEtD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,OAAO,CAAC,KAAK,CAAC,oDAAoD,CAAC,CAAC;QACpE,OAAO,cAAc,CAAC;IACxB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACjD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAE/B,OAAO;YACL,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;YACzD,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;YACtD,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,IAAI,IAAI;SACpD,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,KAAK,CAAC,2DAA2D,CAAC,CAAC;QAC3E,OAAO,cAAc,CAAC;IACxB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detectors.d.ts","sourceRoot":"","sources":["../src/detectors.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAiF5C,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,CAS9E"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.detectViolations = detectViolations;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const scanner_1 = require("./scanner");
|
|
39
|
+
const HEX_COLOR = /#([0-9a-fA-F]{3}){1,2}\b/g;
|
|
40
|
+
const FONT_FAMILY = /font-family\s*:\s*['"]?([^'";,}]+)/gi;
|
|
41
|
+
const INLINE_STYLE = /style\s*=\s*\{\s*\{/g;
|
|
42
|
+
function detectColors(lines, file, config) {
|
|
43
|
+
const violations = [];
|
|
44
|
+
const allowedColors = config.colors.map((c) => c.toLowerCase());
|
|
45
|
+
lines.forEach((line, index) => {
|
|
46
|
+
const matches = line.matchAll(HEX_COLOR);
|
|
47
|
+
for (const match of matches) {
|
|
48
|
+
const color = match[0].toLowerCase();
|
|
49
|
+
if (!allowedColors.includes(color)) {
|
|
50
|
+
violations.push({
|
|
51
|
+
file,
|
|
52
|
+
line: index + 1,
|
|
53
|
+
type: "color",
|
|
54
|
+
found: match[0],
|
|
55
|
+
suggestion: "var(--brand-color)",
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
return violations;
|
|
61
|
+
}
|
|
62
|
+
function detectFonts(lines, file, config) {
|
|
63
|
+
const violations = [];
|
|
64
|
+
const brandFonts = config.fonts.map((f) => f.toLowerCase());
|
|
65
|
+
lines.forEach((line, index) => {
|
|
66
|
+
const matches = line.matchAll(FONT_FAMILY);
|
|
67
|
+
for (const match of matches) {
|
|
68
|
+
const font = match[1].trim();
|
|
69
|
+
const isAllowed = brandFonts.some((bf) => font.toLowerCase().includes(bf) || bf.includes(font.toLowerCase()));
|
|
70
|
+
if (!isAllowed && font) {
|
|
71
|
+
violations.push({
|
|
72
|
+
file,
|
|
73
|
+
line: index + 1,
|
|
74
|
+
type: "font",
|
|
75
|
+
found: font,
|
|
76
|
+
suggestion: config.fonts[0] || "brand font",
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
return violations;
|
|
82
|
+
}
|
|
83
|
+
function detectInlineStyles(lines, file, config) {
|
|
84
|
+
if (config.allowInlineStyles)
|
|
85
|
+
return [];
|
|
86
|
+
const violations = [];
|
|
87
|
+
const isTsxFile = file.endsWith(".tsx") || file.endsWith(".jsx");
|
|
88
|
+
if (!isTsxFile)
|
|
89
|
+
return violations;
|
|
90
|
+
lines.forEach((line, index) => {
|
|
91
|
+
if (INLINE_STYLE.test(line)) {
|
|
92
|
+
violations.push({
|
|
93
|
+
file,
|
|
94
|
+
line: index + 1,
|
|
95
|
+
type: "inline-style",
|
|
96
|
+
found: "inline style object",
|
|
97
|
+
suggestion: "Tailwind class or CSS module",
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
INLINE_STYLE.lastIndex = 0;
|
|
101
|
+
});
|
|
102
|
+
return violations;
|
|
103
|
+
}
|
|
104
|
+
function detectViolations(filePath, config) {
|
|
105
|
+
const lines = (0, scanner_1.readFileLines)(filePath);
|
|
106
|
+
const relativePath = path.relative(process.cwd(), filePath);
|
|
107
|
+
return [
|
|
108
|
+
...detectColors(lines, relativePath, config),
|
|
109
|
+
...detectFonts(lines, relativePath, config),
|
|
110
|
+
...detectInlineStyles(lines, relativePath, config),
|
|
111
|
+
];
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=detectors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detectors.js","sourceRoot":"","sources":["../src/detectors.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const config_1 = require("./config");
|
|
5
|
+
const scanner_1 = require("./scanner");
|
|
6
|
+
const detectors_1 = require("./detectors");
|
|
7
|
+
const output_1 = require("./output");
|
|
8
|
+
function parseArgs(args) {
|
|
9
|
+
return {
|
|
10
|
+
staged: args.includes("--staged") || args.includes("-s"),
|
|
11
|
+
help: args.includes("--help") || args.includes("-h"),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function printHelp() {
|
|
15
|
+
console.log(`
|
|
16
|
+
blotdev - Scan for brand consistency issues
|
|
17
|
+
|
|
18
|
+
Usage:
|
|
19
|
+
blotdev Scan codebase, output brand-issues.md
|
|
20
|
+
blotdev --staged Scan staged files only (pre-commit)
|
|
21
|
+
|
|
22
|
+
Options:
|
|
23
|
+
-s, --staged Only scan git staged files
|
|
24
|
+
-h, --help Show this help
|
|
25
|
+
|
|
26
|
+
Config:
|
|
27
|
+
Create blot.config.json in project root:
|
|
28
|
+
|
|
29
|
+
{
|
|
30
|
+
"colors": ["#1a1a1a", "#ffffff"],
|
|
31
|
+
"fonts": ["Inter", "Space Grotesk"],
|
|
32
|
+
"allowInlineStyles": false
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
https://blot.dev
|
|
36
|
+
`);
|
|
37
|
+
}
|
|
38
|
+
async function main() {
|
|
39
|
+
const options = parseArgs(process.argv.slice(2));
|
|
40
|
+
if (options.help) {
|
|
41
|
+
printHelp();
|
|
42
|
+
process.exit(0);
|
|
43
|
+
}
|
|
44
|
+
const cwd = process.cwd();
|
|
45
|
+
const config = (0, config_1.loadConfig)(cwd);
|
|
46
|
+
const files = options.staged ? (0, scanner_1.getStagedFiles)(cwd) : await (0, scanner_1.getAllFiles)(cwd);
|
|
47
|
+
if (files.length === 0) {
|
|
48
|
+
console.log("No files to scan.");
|
|
49
|
+
process.exit(0);
|
|
50
|
+
}
|
|
51
|
+
const violations = [];
|
|
52
|
+
for (const file of files) {
|
|
53
|
+
violations.push(...(0, detectors_1.detectViolations)(file, config));
|
|
54
|
+
}
|
|
55
|
+
(0, output_1.printToConsole)(violations, files.length);
|
|
56
|
+
if (!options.staged) {
|
|
57
|
+
(0, output_1.writeMarkdownReport)(violations);
|
|
58
|
+
}
|
|
59
|
+
process.exit(violations.length > 0 ? 1 : 0);
|
|
60
|
+
}
|
|
61
|
+
main().catch((err) => {
|
|
62
|
+
console.error("Error:", err.message || err);
|
|
63
|
+
process.exit(1);
|
|
64
|
+
});
|
|
65
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAEA,qCAAsC;AACtC,uCAAwD;AACxD,2CAA+C;AAC/C,qCAA+D;AAG/D,SAAS,SAAS,CAAC,IAAc;IAC/B,OAAO;QACL,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QACxD,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;KACrD,CAAC;AACJ,CAAC;AAED,SAAS,SAAS;IAChB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;CAqBb,CAAC,CAAC;AACH,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAEjD,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,SAAS,EAAE,CAAC;QACZ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,MAAM,GAAG,IAAA,mBAAU,EAAC,GAAG,CAAC,CAAC;IAE/B,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,IAAA,wBAAc,EAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,IAAA,qBAAW,EAAC,GAAG,CAAC,CAAC;IAE5E,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QACjC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,UAAU,GAAgB,EAAE,CAAC;IACnC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,UAAU,CAAC,IAAI,CAAC,GAAG,IAAA,4BAAgB,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IACrD,CAAC;IAED,IAAA,uBAAc,EAAC,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAEzC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QACpB,IAAA,4BAAmB,EAAC,UAAU,CAAC,CAAC;IAClC,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9C,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,CAAC;IAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/output.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Violation } from "./types";
|
|
2
|
+
export declare function generateMarkdown(violations: Violation[]): string;
|
|
3
|
+
export declare function writeMarkdownReport(violations: Violation[]): void;
|
|
4
|
+
export declare function printToConsole(violations: Violation[], fileCount: number): void;
|
|
5
|
+
//# sourceMappingURL=output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAkBpC,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,MAAM,CA2BhE;AAED,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,IAAI,CAIjE;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAgC/E"}
|
package/dist/output.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.generateMarkdown = generateMarkdown;
|
|
37
|
+
exports.writeMarkdownReport = writeMarkdownReport;
|
|
38
|
+
exports.printToConsole = printToConsole;
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
function groupByType(violations) {
|
|
41
|
+
return violations.reduce((acc, v) => {
|
|
42
|
+
if (!acc[v.type])
|
|
43
|
+
acc[v.type] = [];
|
|
44
|
+
acc[v.type].push(v);
|
|
45
|
+
return acc;
|
|
46
|
+
}, {});
|
|
47
|
+
}
|
|
48
|
+
function formatViolation(v) {
|
|
49
|
+
const suggestion = v.suggestion ? ` -> \`${v.suggestion}\`` : "";
|
|
50
|
+
return `- [ ] \`${v.file}:${v.line}\` - \`${v.found}\`${suggestion}`;
|
|
51
|
+
}
|
|
52
|
+
function generateMarkdown(violations) {
|
|
53
|
+
if (violations.length === 0) {
|
|
54
|
+
return "# Brand Issues\n\nNo issues found.";
|
|
55
|
+
}
|
|
56
|
+
const grouped = groupByType(violations);
|
|
57
|
+
const sections = ["# Brand Issues\n"];
|
|
58
|
+
if (grouped["color"]?.length) {
|
|
59
|
+
sections.push("## Hardcoded Colors\n");
|
|
60
|
+
sections.push(grouped["color"].map(formatViolation).join("\n"));
|
|
61
|
+
sections.push("");
|
|
62
|
+
}
|
|
63
|
+
if (grouped["font"]?.length) {
|
|
64
|
+
sections.push("## Font Issues\n");
|
|
65
|
+
sections.push(grouped["font"].map(formatViolation).join("\n"));
|
|
66
|
+
sections.push("");
|
|
67
|
+
}
|
|
68
|
+
if (grouped["inline-style"]?.length) {
|
|
69
|
+
sections.push("## Inline Styles\n");
|
|
70
|
+
sections.push(grouped["inline-style"].map(formatViolation).join("\n"));
|
|
71
|
+
sections.push("");
|
|
72
|
+
}
|
|
73
|
+
return sections.join("\n");
|
|
74
|
+
}
|
|
75
|
+
function writeMarkdownReport(violations) {
|
|
76
|
+
const content = generateMarkdown(violations);
|
|
77
|
+
fs.writeFileSync("brand-issues.md", content);
|
|
78
|
+
console.log("\nWrote brand-issues.md");
|
|
79
|
+
}
|
|
80
|
+
function printToConsole(violations, fileCount) {
|
|
81
|
+
console.log(`Scanned ${fileCount} files\n`);
|
|
82
|
+
if (violations.length === 0) {
|
|
83
|
+
console.log("No issues found.");
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const grouped = groupByType(violations);
|
|
87
|
+
if (grouped["color"]?.length) {
|
|
88
|
+
console.log(`Colors (${grouped["color"].length}):`);
|
|
89
|
+
grouped["color"].forEach((v) => {
|
|
90
|
+
console.log(` ${v.file}:${v.line} ${v.found}`);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
if (grouped["font"]?.length) {
|
|
94
|
+
console.log(`Fonts (${grouped["font"].length}):`);
|
|
95
|
+
grouped["font"].forEach((v) => {
|
|
96
|
+
console.log(` ${v.file}:${v.line} ${v.found}`);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
if (grouped["inline-style"]?.length) {
|
|
100
|
+
console.log(`Inline styles (${grouped["inline-style"].length}):`);
|
|
101
|
+
grouped["inline-style"].forEach((v) => {
|
|
102
|
+
console.log(` ${v.file}:${v.line}`);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
console.log(`\n${violations.length} issues found.`);
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAOA,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAOhE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAepD;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAMxD"}
|
package/dist/scanner.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.getAllFiles = getAllFiles;
|
|
37
|
+
exports.getStagedFiles = getStagedFiles;
|
|
38
|
+
exports.readFileLines = readFileLines;
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const child_process_1 = require("child_process");
|
|
42
|
+
const glob_1 = require("glob");
|
|
43
|
+
const EXTENSIONS = ["ts", "tsx", "css", "scss"];
|
|
44
|
+
async function getAllFiles(cwd) {
|
|
45
|
+
const pattern = `**/*.{${EXTENSIONS.join(",")}}`;
|
|
46
|
+
return (0, glob_1.glob)(pattern, {
|
|
47
|
+
cwd,
|
|
48
|
+
ignore: ["**/node_modules/**", "**/dist/**", "**/build/**", "**/.next/**"],
|
|
49
|
+
absolute: true,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
function getStagedFiles(cwd) {
|
|
53
|
+
try {
|
|
54
|
+
const output = (0, child_process_1.execSync)("git diff --cached --name-only --diff-filter=ACM", {
|
|
55
|
+
cwd,
|
|
56
|
+
encoding: "utf-8",
|
|
57
|
+
});
|
|
58
|
+
return output
|
|
59
|
+
.split("\n")
|
|
60
|
+
.filter((f) => f.trim())
|
|
61
|
+
.filter((f) => EXTENSIONS.some((ext) => f.endsWith(`.${ext}`)))
|
|
62
|
+
.map((f) => path.join(cwd, f));
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function readFileLines(filePath) {
|
|
69
|
+
try {
|
|
70
|
+
return fs.readFileSync(filePath, "utf-8").split("\n");
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return [];
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAOA,kCAOC;AAED,wCAeC;AAED,sCAMC;AAvCD,uCAAyB;AACzB,2CAA6B;AAC7B,iDAAyC;AACzC,+BAA4B;AAE5B,MAAM,UAAU,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AAEzC,KAAK,UAAU,WAAW,CAAC,GAAW;IAC3C,MAAM,OAAO,GAAG,SAAS,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IACjD,OAAO,IAAA,WAAI,EAAC,OAAO,EAAE;QACnB,GAAG;QACH,MAAM,EAAE,CAAC,oBAAoB,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,CAAC;QAC1E,QAAQ,EAAE,IAAI;KACf,CAAC,CAAC;AACL,CAAC;AAED,SAAgB,cAAc,CAAC,GAAW;IACxC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAA,wBAAQ,EAAC,iDAAiD,EAAE;YACzE,GAAG;YACH,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC;QAEH,OAAO,MAAM;aACV,KAAK,CAAC,IAAI,CAAC;aACX,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACvB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC;aAC9D,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAgB,aAAa,CAAC,QAAgB;IAC5C,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface Config {
|
|
2
|
+
colors: string[];
|
|
3
|
+
fonts: string[];
|
|
4
|
+
allowInlineStyles: boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface Violation {
|
|
7
|
+
file: string;
|
|
8
|
+
line: number;
|
|
9
|
+
type: "color" | "font" | "inline-style";
|
|
10
|
+
found: string;
|
|
11
|
+
suggestion?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface Options {
|
|
14
|
+
staged: boolean;
|
|
15
|
+
help: boolean;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,cAAc,CAAC;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;CACf"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "blotdev",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CLI tool to scan codebases for brand consistency issues - catches hardcoded colors, fonts, and styles that should use design tokens.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"blotdev": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"dev": "tsc --watch",
|
|
13
|
+
"start": "node dist/index.js",
|
|
14
|
+
"prepublishOnly": "npm run build"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"lint",
|
|
18
|
+
"linter",
|
|
19
|
+
"brand",
|
|
20
|
+
"design-system",
|
|
21
|
+
"design-tokens",
|
|
22
|
+
"css",
|
|
23
|
+
"colors",
|
|
24
|
+
"fonts",
|
|
25
|
+
"cli"
|
|
26
|
+
],
|
|
27
|
+
"author": "Blot Studios, LLC",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"homepage": "https://blot.dev",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "git+https://github.com/blot-studios/blotdev.git"
|
|
33
|
+
},
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/blot-studios/blotdev/issues"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/node": "^20.10.0",
|
|
39
|
+
"typescript": "^5.3.0"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"glob": "^10.3.0"
|
|
43
|
+
},
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=16.0.0"
|
|
46
|
+
},
|
|
47
|
+
"files": [
|
|
48
|
+
"dist",
|
|
49
|
+
"README.md",
|
|
50
|
+
"LICENSE",
|
|
51
|
+
"blot.config.example.json"
|
|
52
|
+
]
|
|
53
|
+
}
|