@master/css-cli 2.0.0-rc.75 → 2.0.0-rc.77
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 +65 -0
- package/dist/core.js +8 -0
- package/dist/inspect.js +38 -0
- package/dist/lint.js +160 -0
- package/package.json +11 -7
package/README.md
CHANGED
|
@@ -84,6 +84,71 @@ Options:
|
|
|
84
84
|
| `-v, --verbose <level>` | `number` | `1` | Logging level. Use `0` to silence terminal output. |
|
|
85
85
|
| `-w, --watch` | `boolean` | `false` | Watch files and rebuild continuously. |
|
|
86
86
|
|
|
87
|
+
### `npx @master/css-cli lint [source paths]`
|
|
88
|
+
|
|
89
|
+
Run machine-readable Master CSS diagnostics for agents, MCP servers, editor tools, and native CI checks. JavaScript and VS Code projects should still use ESLint as the main human lint workflow; this command is a native preflight surface that shares the same class policy engine.
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
npx @master/css-cli lint index.html main.js
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Use JSON output for tools:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
cat src/App.tsx | npx @master/css-cli lint --exit-code never --stdin --stdin-filepath src/App.tsx
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Options:
|
|
102
|
+
|
|
103
|
+
| Option | Type | Default | Description |
|
|
104
|
+
| --- | --- | --- | --- |
|
|
105
|
+
| `--stdin` | `boolean` | `false` | Read one source buffer from stdin. |
|
|
106
|
+
| `--stdin-filepath <path>` | `string` | `stdin.html` | File path used to infer the stdin language. |
|
|
107
|
+
| `--fix` | `boolean` | `false` | Apply safe class-list fixes to files. |
|
|
108
|
+
| `--fix-dry-run` | `boolean` | `false` | Return fix proposals without writing files. |
|
|
109
|
+
| `--fix-directives` | `boolean` | `false` | Allow structural directive fixes when `--fix` writes files. |
|
|
110
|
+
| `--format <format>` | `json` or `stylish` | `json` | Print machine-readable diagnostics or human-readable output. |
|
|
111
|
+
| `--rules <rules>` | comma list | recommended | Select lint rules, `recommended`, or `all`. |
|
|
112
|
+
| `--exit-code <mode>` | `diagnostics` or `never` | `diagnostics` | Control whether diagnostics set a non-zero exit code. |
|
|
113
|
+
| `--max-warnings <number>` | `number` | none | Exit with a non-zero status when warnings exceed this count. |
|
|
114
|
+
|
|
115
|
+
The JSON report uses `version: 1`. Tooling can rely on the top-level `version`, `cwd`, `manifest`, `files`, and `summary` fields. Diagnostic `data` objects may gain additional fields as Master CSS reports become more precise.
|
|
116
|
+
|
|
117
|
+
### `npx @master/css-cli inspect [source paths]`
|
|
118
|
+
|
|
119
|
+
Inspect scanner state, managed stylesheet entries, generated CSS size, and explicit missing CSS checks. This command is for MCP servers, AI agents, build diagnostics, and support tooling that need machine-readable extraction state, not class policy linting.
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
npx @master/css-cli inspect --classes "btn card" --format json --exit-code never
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Use `--classes` to ask whether specific class names are present in the generated CSS path. The report explains each checked class as `generated`, `native-css`, `safelist`, `invalid`, `blocklisted`, or `not-detected`.
|
|
126
|
+
|
|
127
|
+
The JSON report includes:
|
|
128
|
+
|
|
129
|
+
| Field | Description |
|
|
130
|
+
| --- | --- |
|
|
131
|
+
| `inputs` | Source patterns, resolved files, and explicit classes checked by this run. |
|
|
132
|
+
| `scanner` | Global scanner class sets, counts, safelist/blocklist counts, and reset dependencies. |
|
|
133
|
+
| `stylesheets` | Managed CSS entries, dependency metadata, warnings, and entry loading errors. |
|
|
134
|
+
| `css` | Generated CSS byte size, emitted global counts, and optional CSS text. |
|
|
135
|
+
| `missingCSS` | Present and missing results for `--classes`. |
|
|
136
|
+
| `files` | Per-file scanner discoveries for latent, valid, invalid, and native CSS classes. |
|
|
137
|
+
| `diagnostics` | Machine-readable `scanner`, `stylesheet`, and `missing-css` diagnostics. |
|
|
138
|
+
| `summary` | File, stylesheet, diagnostic, error, warning, missing CSS, and invalid class totals. |
|
|
139
|
+
|
|
140
|
+
The JSON report uses `version: 1`. Tooling can rely on the top-level `version`, `cwd`, `inputs`, `scanner`, `stylesheets`, `css`, `missingCSS`, `files`, `diagnostics`, and `summary` fields. Nested diagnostic `data` and stylesheet details may evolve unless documented for a specific diagnostic code.
|
|
141
|
+
|
|
142
|
+
Options:
|
|
143
|
+
|
|
144
|
+
| Option | Type | Default | Description |
|
|
145
|
+
| --- | --- | --- | --- |
|
|
146
|
+
| `--classes <classes>` | whitespace list | none | Class names to verify against scanner state and generated CSS. |
|
|
147
|
+
| `--include-css` | `boolean` | `false` | Include generated CSS text in the JSON report. |
|
|
148
|
+
| `--format <format>` | `json` or `stylish` | `json` | Print machine-readable diagnostics or human-readable output. |
|
|
149
|
+
| `--exit-code <mode>` | `diagnostics` or `never` | `diagnostics` | Control whether diagnostics set a non-zero exit code. |
|
|
150
|
+
| `--max-warnings <number>` | `number` | none | Exit with a non-zero status when warnings exceed this count. |
|
|
151
|
+
|
|
87
152
|
## Related docs
|
|
88
153
|
|
|
89
154
|
- [Static rendering guide](https://rc.css.master.co/guide/installation)
|
package/dist/core.js
CHANGED
|
@@ -22,6 +22,14 @@ async function runProgram(argv = process.argv) {
|
|
|
22
22
|
const { default: runScan } = await import("./scan.js");
|
|
23
23
|
return runScan(sourcePaths, options);
|
|
24
24
|
});
|
|
25
|
+
program.command("lint").description("Run machine-readable Master CSS diagnostics for source files.").argument("[source paths...]", "The glob pattern paths to lint sources").option("--stdin", "Read source content from stdin.").option("--stdin-filepath <path>", "File path used to infer the stdin source language.").option("--fix", "Apply safe class-list fixes to files.").option("--fix-dry-run", "Return fix proposals without writing files.").option("--fix-directives", "Allow structural directive fixes when --fix writes files.").option("--format <format>", "Diagnostic output format: json or stylish.", "json").option("--rules <rules>", "Comma-separated lint rules, \"recommended\", or \"all\".").option("--exit-code <mode>", "Exit code behavior: diagnostics or never.", "diagnostics").option("--max-warnings <number>", "Exit with a non-zero status if warnings exceed this count.").action(async (sourcePaths, options) => {
|
|
26
|
+
const { default: runLint } = await import("./lint.js");
|
|
27
|
+
await runLint(sourcePaths, options);
|
|
28
|
+
});
|
|
29
|
+
program.command("inspect").description("Inspect scanner state, stylesheet entries, generated CSS, and missing CSS.").argument("[source paths...]", "The glob pattern paths to inspect").option("--classes <classes>", "Whitespace-separated class names to verify in generated CSS.").option("--include-css", "Include generated CSS text in the JSON report.").option("--format <format>", "Diagnostic output format: json or stylish.", "json").option("--exit-code <mode>", "Exit code behavior: diagnostics or never.", "diagnostics").option("--max-warnings <number>", "Exit with a non-zero status if warnings exceed this count.").action(async (sourcePaths, options) => {
|
|
30
|
+
const { default: runInspect } = await import("./inspect.js");
|
|
31
|
+
await runInspect(sourcePaths, options);
|
|
32
|
+
});
|
|
25
33
|
const firstArgument = argv[2];
|
|
26
34
|
if (firstArgument && removedCommands.has(firstArgument)) errorRemovedCommand(program, firstArgument);
|
|
27
35
|
await program.parseAsync(argv);
|
package/dist/inspect.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { createMasterCSSInspectionReport } from "@master/css-diagnostics";
|
|
3
|
+
//#region src/inspect.ts
|
|
4
|
+
function parseMaxWarnings(value) {
|
|
5
|
+
if (value === void 0) return Number.POSITIVE_INFINITY;
|
|
6
|
+
const maxWarnings = Number(value);
|
|
7
|
+
return Number.isFinite(maxWarnings) && maxWarnings >= 0 ? maxWarnings : 0;
|
|
8
|
+
}
|
|
9
|
+
function formatStylish(report) {
|
|
10
|
+
const lines = [
|
|
11
|
+
`Scanned ${report.summary.files} files, ${report.summary.stylesheets} stylesheet entries.`,
|
|
12
|
+
`Classes: ${report.scanner.counts.valid} valid, ${report.scanner.counts.invalid} invalid, ${report.scanner.counts.usedNative} native.`,
|
|
13
|
+
`CSS: ${report.css.bytes} bytes.`
|
|
14
|
+
];
|
|
15
|
+
if (report.missingCSS.checked.length) lines.push(`Missing CSS: ${report.missingCSS.missing.length}/${report.missingCSS.checked.length}`);
|
|
16
|
+
for (const diagnostic of report.diagnostics) lines.push(`${diagnostic.severity.toUpperCase()} ${diagnostic.code}: ${diagnostic.message}`);
|
|
17
|
+
return `${lines.join("\n")}\n`;
|
|
18
|
+
}
|
|
19
|
+
function outputReport(report, format) {
|
|
20
|
+
if (format === "stylish") process.stdout.write(formatStylish(report));
|
|
21
|
+
else console.log(JSON.stringify(report, null, 2));
|
|
22
|
+
}
|
|
23
|
+
async function runInspect(specifiedSourcePaths = [], options = {}) {
|
|
24
|
+
const cwd = path.resolve(options.cwd || process.cwd());
|
|
25
|
+
const format = options.format || "json";
|
|
26
|
+
const exitCode = options.exitCode || "diagnostics";
|
|
27
|
+
const report = await createMasterCSSInspectionReport({
|
|
28
|
+
cwd,
|
|
29
|
+
patterns: specifiedSourcePaths.length ? specifiedSourcePaths : void 0,
|
|
30
|
+
classes: options.classes,
|
|
31
|
+
includeCss: Boolean(options.includeCss)
|
|
32
|
+
});
|
|
33
|
+
outputReport(report, format);
|
|
34
|
+
if (exitCode !== "never" && (report.summary.errors || report.summary.warnings > parseMaxWarnings(options.maxWarnings))) process.exitCode = 1;
|
|
35
|
+
return report;
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
export { runInspect as default };
|
package/dist/lint.js
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { createCSSWithNativeDeclarations } from "@master/css-validator";
|
|
4
|
+
import { fixMasterCSSContent, lintMasterCSSContent, resolveMasterCSSLintRules, summarizeMasterCSSLintFiles } from "@master/css-lint";
|
|
5
|
+
import { loadProjectManifest } from "@master/css-project/manifest";
|
|
6
|
+
import fg from "fast-glob";
|
|
7
|
+
//#region src/lint.ts
|
|
8
|
+
const REPORT_VERSION = 1;
|
|
9
|
+
const DEFAULT_SOURCE_PATTERNS = ["**/*.{html,htm,js,jsx,cjs,ts,tsx,mts,cts,svelte,astro,vue,md,mdx,pug,php,css,scss,less}"];
|
|
10
|
+
const DEFAULT_IGNORE_PATTERNS = ["**/node_modules/**", "node_modules"];
|
|
11
|
+
function normalizeSourcePatterns(specifiedSourcePaths) {
|
|
12
|
+
return specifiedSourcePaths?.length ? specifiedSourcePaths : DEFAULT_SOURCE_PATTERNS;
|
|
13
|
+
}
|
|
14
|
+
function normalizeGlobPatterns(patterns) {
|
|
15
|
+
return patterns.map((pattern) => pattern.replace(/\\/g, "/"));
|
|
16
|
+
}
|
|
17
|
+
function resolveSourcePaths(cwd, sourcePatterns, ignore = []) {
|
|
18
|
+
return fg.sync(normalizeGlobPatterns(sourcePatterns), {
|
|
19
|
+
cwd,
|
|
20
|
+
ignore: normalizeGlobPatterns(ignore),
|
|
21
|
+
onlyFiles: true
|
|
22
|
+
}).filter(Boolean);
|
|
23
|
+
}
|
|
24
|
+
function parseMaxWarnings(value) {
|
|
25
|
+
if (value === void 0) return Number.POSITIVE_INFINITY;
|
|
26
|
+
const maxWarnings = Number(value);
|
|
27
|
+
return Number.isFinite(maxWarnings) && maxWarnings >= 0 ? maxWarnings : 0;
|
|
28
|
+
}
|
|
29
|
+
function createManifestDiagnostic(cwd, error) {
|
|
30
|
+
return {
|
|
31
|
+
ruleId: "manifest",
|
|
32
|
+
code: "manifest-loading-error",
|
|
33
|
+
severity: "error",
|
|
34
|
+
message: `Failed to load Master CSS manifest: ${error instanceof Error ? error.message : String(error)}`,
|
|
35
|
+
range: {
|
|
36
|
+
start: 0,
|
|
37
|
+
end: 0
|
|
38
|
+
},
|
|
39
|
+
loc: {
|
|
40
|
+
start: {
|
|
41
|
+
line: 1,
|
|
42
|
+
column: 1
|
|
43
|
+
},
|
|
44
|
+
end: {
|
|
45
|
+
line: 1,
|
|
46
|
+
column: 1
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
source: "Master CSS",
|
|
50
|
+
sourceKind: "manifest",
|
|
51
|
+
data: { cwd }
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function createManifestFileResult(cwd, diagnostics) {
|
|
55
|
+
return {
|
|
56
|
+
filePath: cwd,
|
|
57
|
+
languageId: "manifest",
|
|
58
|
+
sourceKind: "manifest",
|
|
59
|
+
diagnostics
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function createReport(cwd, manifest, files) {
|
|
63
|
+
return {
|
|
64
|
+
version: REPORT_VERSION,
|
|
65
|
+
cwd,
|
|
66
|
+
manifest,
|
|
67
|
+
files,
|
|
68
|
+
summary: summarizeMasterCSSLintFiles(files)
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function formatStylish(report) {
|
|
72
|
+
const lines = [];
|
|
73
|
+
for (const result of report.files) {
|
|
74
|
+
if (!result.diagnostics.length) continue;
|
|
75
|
+
lines.push(result.filePath);
|
|
76
|
+
for (const diagnostic of result.diagnostics) lines.push(` ${diagnostic.loc.start.line}:${diagnostic.loc.start.column} ${diagnostic.severity} ${diagnostic.message} ${diagnostic.ruleId ? `@master/css/${diagnostic.ruleId}` : diagnostic.code}`);
|
|
77
|
+
}
|
|
78
|
+
return lines.length ? `${lines.join("\n")}\n` : "";
|
|
79
|
+
}
|
|
80
|
+
function outputReport(report, format) {
|
|
81
|
+
if (format === "stylish") {
|
|
82
|
+
const output = formatStylish(report);
|
|
83
|
+
if (output) process.stdout.write(output);
|
|
84
|
+
} else console.log(JSON.stringify(report, null, 2));
|
|
85
|
+
}
|
|
86
|
+
function resolveSourceInputs(cwd, specifiedSourcePaths, options) {
|
|
87
|
+
if (options.stdin) return [{
|
|
88
|
+
filePath: path.resolve(cwd, options.stdinFilepath || "stdin.html"),
|
|
89
|
+
content: fs.readFileSync(0, "utf8"),
|
|
90
|
+
stdin: true
|
|
91
|
+
}];
|
|
92
|
+
return resolveSourcePaths(cwd, normalizeSourcePatterns(specifiedSourcePaths), specifiedSourcePaths.length ? [] : DEFAULT_IGNORE_PATTERNS).map((source) => {
|
|
93
|
+
const filePath = path.resolve(cwd, source);
|
|
94
|
+
return {
|
|
95
|
+
filePath,
|
|
96
|
+
content: fs.readFileSync(filePath, "utf8")
|
|
97
|
+
};
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
function lintInputs(inputs, css, rules) {
|
|
101
|
+
return inputs.map((input) => lintMasterCSSContent({
|
|
102
|
+
content: input.content,
|
|
103
|
+
filePath: input.filePath,
|
|
104
|
+
css,
|
|
105
|
+
rules
|
|
106
|
+
})).filter((result) => result.diagnostics.length);
|
|
107
|
+
}
|
|
108
|
+
function applyFileFixes(inputs, css, rules, includeDirectiveFixes) {
|
|
109
|
+
for (const input of inputs) {
|
|
110
|
+
if (input.stdin) continue;
|
|
111
|
+
const fixed = fixMasterCSSContent({
|
|
112
|
+
content: input.content,
|
|
113
|
+
filePath: input.filePath,
|
|
114
|
+
css,
|
|
115
|
+
rules,
|
|
116
|
+
includeDirectiveFixes
|
|
117
|
+
});
|
|
118
|
+
if (fixed !== input.content) {
|
|
119
|
+
fs.writeFileSync(input.filePath, fixed);
|
|
120
|
+
input.content = fixed;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
async function runLint(specifiedSourcePaths = [], options = {}) {
|
|
125
|
+
const cwd = path.resolve(options.cwd || process.cwd());
|
|
126
|
+
const format = options.format || "json";
|
|
127
|
+
const exitCode = options.exitCode || "diagnostics";
|
|
128
|
+
const rules = resolveMasterCSSLintRules(options.rules);
|
|
129
|
+
const inputs = resolveSourceInputs(cwd, specifiedSourcePaths, options);
|
|
130
|
+
let manifest;
|
|
131
|
+
let files;
|
|
132
|
+
try {
|
|
133
|
+
const manifestResult = await loadProjectManifest(cwd);
|
|
134
|
+
const css = createCSSWithNativeDeclarations(manifestResult.manifest);
|
|
135
|
+
manifest = {
|
|
136
|
+
status: "loaded",
|
|
137
|
+
entries: manifestResult.entries,
|
|
138
|
+
diagnostics: []
|
|
139
|
+
};
|
|
140
|
+
files = lintInputs(inputs, css, rules);
|
|
141
|
+
if (options.fix && !options.fixDryRun) {
|
|
142
|
+
applyFileFixes(inputs, css, rules, Boolean(options.fixDirectives));
|
|
143
|
+
files = lintInputs(inputs, css, rules);
|
|
144
|
+
}
|
|
145
|
+
} catch (error) {
|
|
146
|
+
const diagnostic = createManifestDiagnostic(cwd, error);
|
|
147
|
+
manifest = {
|
|
148
|
+
status: "error",
|
|
149
|
+
entries: [],
|
|
150
|
+
diagnostics: [diagnostic]
|
|
151
|
+
};
|
|
152
|
+
files = [createManifestFileResult(cwd, [diagnostic])];
|
|
153
|
+
}
|
|
154
|
+
const report = createReport(cwd, manifest, files);
|
|
155
|
+
outputReport(report, format);
|
|
156
|
+
if (exitCode !== "never" && (report.summary.errors || report.summary.warnings > parseMaxWarnings(options.maxWarnings))) process.exitCode = 1;
|
|
157
|
+
return report;
|
|
158
|
+
}
|
|
159
|
+
//#endregion
|
|
160
|
+
export { runLint as default };
|
package/package.json
CHANGED
|
@@ -32,17 +32,21 @@
|
|
|
32
32
|
"commander": "^14.0.3",
|
|
33
33
|
"consola": "^3.4.2",
|
|
34
34
|
"fast-glob": "^3.3.3",
|
|
35
|
-
"@master/css": "^2.0.0-rc.
|
|
36
|
-
"@master/css-
|
|
37
|
-
"@master/css-
|
|
38
|
-
"@master/css-
|
|
35
|
+
"@master/css": "^2.0.0-rc.77",
|
|
36
|
+
"@master/css-diagnostics": "^2.0.0-rc.77",
|
|
37
|
+
"@master/css-lint": "^2.0.0-rc.77",
|
|
38
|
+
"@master/css-lexer": "^2.0.0-rc.77",
|
|
39
|
+
"@master/css-project": "^2.0.0-rc.77",
|
|
40
|
+
"@master/css-scanner": "^2.0.0-rc.77",
|
|
41
|
+
"@master/css-language": "^2.0.0-rc.77",
|
|
42
|
+
"@master/css-stylesheet": "^2.0.0-rc.77",
|
|
43
|
+
"@master/css-validator": "^2.0.0-rc.77"
|
|
39
44
|
},
|
|
40
45
|
"devDependencies": {
|
|
41
46
|
"@types/bytes": "^3.1.5",
|
|
42
|
-
"upath": "^2.0.1"
|
|
43
|
-
"@master/css-lexer": "^2.0.0-rc.75"
|
|
47
|
+
"upath": "^2.0.1"
|
|
44
48
|
},
|
|
45
|
-
"version": "2.0.0-rc.
|
|
49
|
+
"version": "2.0.0-rc.77",
|
|
46
50
|
"scripts": {
|
|
47
51
|
"build": "tsdown --config ../../shared/tsdown-package.config.ts",
|
|
48
52
|
"dev": "tsdown --config ../../shared/tsdown-package.config.ts --watch",
|