@master/css-mcp 2.0.0-rc.88 → 2.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/README.md +47 -22
- package/dist/bin/index.js +4 -5
- package/dist/classes.js +153 -168
- package/dist/compare.js +99 -83
- package/dist/context.d.ts +5 -10
- package/dist/context.js +28 -10
- package/dist/design-system-schema.js +97 -0
- package/dist/directives.js +59 -109
- package/dist/document.js +2 -10
- package/dist/format.js +67 -56
- package/dist/index.d.ts +2 -3
- package/dist/index.js +1 -3
- package/dist/internal/src/workspace.js +70 -0
- package/dist/language.js +27 -23
- package/dist/lint.js +86 -96
- package/dist/manifest-query.js +40 -100
- package/dist/manifest-summary.js +15 -35
- package/dist/output-schema.js +207 -0
- package/dist/preview-write-lock.js +90 -0
- package/dist/project-comparison-schema.js +59 -0
- package/dist/project.js +77 -18
- package/dist/result.js +67 -8
- package/dist/scan.js +93 -73
- package/dist/semantic-schema.js +286 -0
- package/dist/server.d.ts +10 -9
- package/dist/server.js +123 -111
- package/dist/setup.js +28 -29
- package/dist/source-schema.js +141 -0
- package/dist/suggest.js +22 -0
- package/dist/tooling-session.js +27 -0
- package/package.json +63 -73
- package/LICENSE +0 -21
- package/dist/classes.d.ts +0 -236
- package/dist/compare.d.ts +0 -70
- package/dist/contributor.d.ts +0 -149
- package/dist/contributor.js +0 -499
- package/dist/directives.d.ts +0 -132
- package/dist/document.d.ts +0 -24
- package/dist/format.d.ts +0 -56
- package/dist/language.d.ts +0 -24
- package/dist/lint.d.ts +0 -55
- package/dist/manifest-query.d.ts +0 -148
- package/dist/manifest-summary.d.ts +0 -47
- package/dist/project.d.ts +0 -31
- package/dist/result.d.ts +0 -8
- package/dist/scan.d.ts +0 -156
- package/dist/setup.d.ts +0 -67
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Master CSS MCP Server
|
|
2
2
|
|
|
3
|
-
Model Context Protocol server for Master CSS tooling. It lets AI clients inspect a Master CSS workspace, audit setup, read the active project manifest, inspect CSS-first directives, trace classes through extraction and generated CSS, render or compare CSS output, run lint diagnostics, request syntax suggestions, apply reviewed fix previews
|
|
3
|
+
Model Context Protocol server for Master CSS tooling. It lets AI clients inspect a Master CSS workspace, audit setup, read the active project manifest, inspect CSS-first directives, trace classes through extraction and generated CSS, render or compare CSS output, run lint diagnostics, request syntax suggestions, and apply reviewed fix previews.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -11,7 +11,7 @@ npm install -D @master/css-mcp
|
|
|
11
11
|
You can also run it directly:
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
npx -y @master/css-mcp@
|
|
14
|
+
npx -y @master/css-mcp@latest --root /absolute/path/to/project
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
## MCP client config
|
|
@@ -23,7 +23,7 @@ Most MCP clients accept a command and arguments for stdio servers:
|
|
|
23
23
|
"mcpServers": {
|
|
24
24
|
"master-css": {
|
|
25
25
|
"command": "npx",
|
|
26
|
-
"args": ["-y", "@master/css-mcp@
|
|
26
|
+
"args": ["-y", "@master/css-mcp@latest", "--root", "/absolute/path/to/project"]
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
}
|
|
@@ -35,6 +35,7 @@ Use an absolute `--root` path so the server resolves the intended workspace.
|
|
|
35
35
|
|
|
36
36
|
| Tool | Use |
|
|
37
37
|
| --- | --- |
|
|
38
|
+
| `mastercss_suggest_classes` | Suggest project-aware classes for an isolated CSS declaration block without writing files. Preserves the block when conversion needs review; checks declaration output, not surrounding cascade or browser rendering. |
|
|
38
39
|
| `mastercss_workspace_info` | Report workspace roots, resolved packages, and manifest status. |
|
|
39
40
|
| `mastercss_setup_audit` | Audit package, entry stylesheet, manifest, integration, and package-resolution setup. |
|
|
40
41
|
| `mastercss_inspect_class` | Inspect one class and return generated rules and CSS text. |
|
|
@@ -42,9 +43,9 @@ Use an absolute `--root` path so the server resolves the intended workspace.
|
|
|
42
43
|
| `mastercss_extract_classes` | Extract class positions and validation summaries from files or an in-memory source buffer. |
|
|
43
44
|
| `mastercss_inspect_directives` | Inspect CSS-first directives and report manifest, dependency, warning, and CSS effects. |
|
|
44
45
|
| `mastercss_render_css` | Generate CSS from HTML or a class list. |
|
|
45
|
-
| `mastercss_scan_project` | Scan sources, check optional classes, and report scanner state, stylesheet entries, generated CSS metadata, and missing CSS diagnostics. |
|
|
46
|
-
| `mastercss_manifest_query` | Query active manifest tokens, utilities,
|
|
47
|
-
| `mastercss_css_compare` | Compare
|
|
46
|
+
| `mastercss_scan_project` | Scan sources, check optional classes, and report scanner state, stylesheet entries, generated CSS metadata, and missing CSS diagnostics. Optionally inspect stylesheet token references and design policies. |
|
|
47
|
+
| `mastercss_manifest_query` | Query active manifest tokens, utilities, mixins, custom media, and token families. |
|
|
48
|
+
| `mastercss_css_compare` | Compare class/content output under one manifest, or two resolved project snapshots including definition changes and known consumers. |
|
|
48
49
|
| `mastercss_lint_project` | Run class-list diagnostics for workspace files without writing files. |
|
|
49
50
|
| `mastercss_lint_content` | Run class-list diagnostics on an in-memory source buffer without writing files. |
|
|
50
51
|
| `mastercss_suggest_syntax` | Return language-service completions and hover context. |
|
|
@@ -52,16 +53,33 @@ Use an absolute `--root` path so the server resolves the intended workspace.
|
|
|
52
53
|
| `mastercss_preview_directive_format` | Preview Master CSS directive formatting for files, or format in-memory content without writing. |
|
|
53
54
|
| `mastercss_apply_preview` | Apply a preview after token, hash, and workspace checks. |
|
|
54
55
|
|
|
55
|
-
|
|
56
|
+
`@theme` defines utility tokens with direct custom-property declarations and optional `static` / `inline` modifiers. Native CSS controls scoped overrides and does not add utility candidates. Directive inspection and manifest queries report the same Rust-backed contract as the compiler and language service.
|
|
56
57
|
|
|
57
|
-
|
|
58
|
+
## Inspect token use in stylesheets
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
Pass `designSystem` to `mastercss_scan_project` with the default project context to include a version 1 report in `result.data.designSystem`. This option cannot be combined with `context: "preset"`:
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"designSystem": {
|
|
65
|
+
"version": 1,
|
|
66
|
+
"metadata": {
|
|
67
|
+
"--color-brand-old": {
|
|
68
|
+
"description": "Previous brand color",
|
|
69
|
+
"deprecated": true,
|
|
70
|
+
"replacement": "--color-brand"
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"rawValuePolicy": {
|
|
74
|
+
"requireProperties": ["color", "background-color"]
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The report covers project-owned CSS reached from the project's Master CSS entries, plus any `routeStylesheets` globs for stylesheets imported from JavaScript. It includes authored `var()` reference ranges in UTF-16 offsets, selector and at-rule ancestry, source importers, token-family collisions, each component class's attribute vocabulary (`components`), and diagnostics for the supplied metadata and raw-value policy. Ordinary native CSS can reference the same `@theme` tokens as Master CSS classes. Unregistered custom properties may come from native CSS or inheritance and are not automatically missing-token errors.
|
|
81
|
+
|
|
82
|
+
Metadata and policies are analysis inputs: they do not change generated CSS, manifests, or runtime programs. Unrecognized option fields are rejected. Omit `rawValuePolicy` to skip native declaration raw-value checks. Read `project.excluded` and `coverage`: package sources and files outside the project root are excluded, importer links include reference-only context, and the report does not establish DOM usage, cascade winners, computed styles, or browser behavior. `includeSnapshot` remains available in the same call.
|
|
65
83
|
|
|
66
84
|
## Prompt templates
|
|
67
85
|
|
|
@@ -69,21 +87,28 @@ These read-only tools are for Master CSS repository contributors, AI coding agen
|
|
|
69
87
|
| --- | --- |
|
|
70
88
|
| `debug-missing-css` | Debug scanner coverage, manifest loading, invalid syntax, native CSS pruning, and stylesheet entry configuration. |
|
|
71
89
|
| `review-mastercss-classes` | Review class lists and propose only safe, scoped write previews. |
|
|
72
|
-
| `migrate-to-mastercss` |
|
|
73
|
-
|
|
74
|
-
Use `migrate-to-mastercss` when an MCP-capable AI client is helping migrate CSS, CSS Modules, Sass, Tailwind CSS, CSS-in-JS, component-library styling, or Master CSS v1. The prompt asks the agent to inspect the workspace first, identify stylesheet entries and source extraction coverage, recommend a rendering mode, choose the first reviewable migration batch, and list validation commands and visual review risks.
|
|
75
|
-
|
|
76
|
-
The migration prompt is a planning workflow, not a one-shot converter. Keep the previous styling system in place until each migrated slice builds, runs, and visually matches the old UI.
|
|
90
|
+
| `migrate-to-mastercss` | Plan a conversion from CSS, CSS Modules, Sass, Tailwind CSS, CSS-in-JS or component-library styling to current Master CSS. |
|
|
77
91
|
|
|
78
92
|
## Machine-readable results
|
|
79
93
|
|
|
80
|
-
|
|
94
|
+
Every tool returns a `version: 3` envelope with `metadata`, `diagnostics` and `result`. Success data lives in `result.data`; failures have `result.status: "error"` and an error code and message, and set MCP `isError`. JSON text matches `structuredContent`. Metadata identifies the actual context, manifest and package contracts; read the tool’s published output schema for its payload.
|
|
81
95
|
|
|
82
96
|
## Safety
|
|
83
97
|
|
|
84
98
|
Read-only tools do not write files. File writes use a two-step preview/apply flow, validate workspace containment, and verify original file hashes before writing. Lint fixes, generated CSS output writes, and directive formatting for files all use preview tokens before `mastercss_apply_preview` can write anything.
|
|
85
99
|
|
|
100
|
+
Concurrent applies coordinate across MCP processes for the same OS user through a local lock directory under `~/.cache/mastercss`. Hash validation and writes run one apply at a time across all workspace roots. A waiting apply times out after 30 seconds without taking over a live writer; its token can be retried until it expires. External editors do not participate in this lock, so edits made after hash validation can still race with apply. Multi-file writes are sequential and do not provide rollback or crash atomicity.
|
|
101
|
+
|
|
86
102
|
## Related docs
|
|
87
103
|
|
|
88
|
-
- [MCP Server guide](https://
|
|
89
|
-
- [AI Coding guide](https://
|
|
104
|
+
- [MCP Server guide](https://css.master.co/guide/ai-coding#connect-the-mcp-server)
|
|
105
|
+
- [AI Coding guide](https://css.master.co/guide/ai-coding)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
## Compare a project before and after editing
|
|
109
|
+
|
|
110
|
+
Call `mastercss_scan_project` with `includeSnapshot: true` before editing and save `result.data.snapshot`. Repeat after editing, then pass the two objects to `mastercss_css_compare` as `beforeSnapshot` and `afterSnapshot`. Both are required; snapshot inputs cannot be mixed with class/content, `filePath` or `context` inputs.
|
|
111
|
+
|
|
112
|
+
The project result is `{ version: 3, mode: 'project', comparison }` inside the usual version 3 envelope. `comparison.version` is 1. It reports changed definitions, known class consumers and files, before/after generated rules, native references, output assets and delivery order. Read `coverage` even when there are no differences: dynamic sources, remote content, binary assets and final browser behavior are not exhaustively checked. Native consumers are conservative at stylesheet granularity.
|
|
113
|
+
|
|
114
|
+
These tools use the installed compiler. Check workspace package versions, language/binding versions and manifest metadata before using documentation or examples; use the project-local, lockfile-pinned MCP package for reproducible sessions.
|
package/dist/bin/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { startMasterCSSMCPStdioServer } from "../server.js";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
3
4
|
import { dirname, resolve } from "node:path";
|
|
4
5
|
import { fileURLToPath } from "node:url";
|
|
5
|
-
|
|
6
|
-
//#region src/bin/index.ts
|
|
6
|
+
// src/bin/index.ts
|
|
7
7
|
function readPackageVersion() {
|
|
8
8
|
const directory = dirname(fileURLToPath(import.meta.url));
|
|
9
9
|
try {
|
|
@@ -51,10 +51,9 @@ function parseArgs(argv) {
|
|
|
51
51
|
return options;
|
|
52
52
|
}
|
|
53
53
|
try {
|
|
54
|
-
await
|
|
54
|
+
await startMasterCSSMCPStdioServer(parseArgs(process.argv.slice(2)));
|
|
55
55
|
} catch (error) {
|
|
56
56
|
console.error(error instanceof Error ? error.message : String(error));
|
|
57
57
|
process.exit(1);
|
|
58
58
|
}
|
|
59
|
-
//#endregion
|
|
60
59
|
export {};
|
package/dist/classes.js
CHANGED
|
@@ -1,52 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { loadWorkspaceManifest, manifestMetadata, requireWorkspaceManifest } from "./project.js";
|
|
2
|
+
import { compactClassInspection, createMCPToolingSession } from "./tooling-session.js";
|
|
3
3
|
import { resolveSourceFiles, scanProject } from "./scan.js";
|
|
4
|
-
import {
|
|
4
|
+
import { createMCPTextDocument, getLanguageId } from "./document.js";
|
|
5
5
|
import { readFile } from "node:fs/promises";
|
|
6
|
-
|
|
7
|
-
import { inspectMasterCSSClass } from "@master/css-engine/inspect";
|
|
8
|
-
import { createCSSWithNativeDeclarations } from "@master/css-validator/native-declaration";
|
|
9
|
-
//#region src/classes.ts
|
|
6
|
+
// src/classes.ts
|
|
10
7
|
const CLASS_EXTRACTION_VERSION = 1;
|
|
11
8
|
const CLASS_TRACE_VERSION = 1;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const
|
|
9
|
+
async function createClassInspectionState(context, options = {}) {
|
|
10
|
+
const manifest = await loadWorkspaceManifest(context, options.context);
|
|
11
|
+
const activeManifest = requireWorkspaceManifest(manifest);
|
|
15
12
|
return {
|
|
16
13
|
manifest,
|
|
17
|
-
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
function createLanguageService(manifest) {
|
|
21
|
-
return new CSSLanguageService(manifest.status === "loaded" ? { manifest: manifest.manifest } : void 0);
|
|
22
|
-
}
|
|
23
|
-
function compactInspection(css, className, mode, includeRules = false) {
|
|
24
|
-
const inspection = inspectMasterCSSClass(css, className, mode);
|
|
25
|
-
return {
|
|
26
|
-
valid: inspection.rules.length > 0,
|
|
27
|
-
base: inspection.base,
|
|
28
|
-
suffix: inspection.suffix,
|
|
29
|
-
key: inspection.key,
|
|
30
|
-
value: inspection.value,
|
|
31
|
-
keyToken: inspection.keyToken,
|
|
32
|
-
valueToken: inspection.valueToken,
|
|
33
|
-
stateToken: inspection.stateToken,
|
|
34
|
-
important: inspection.important,
|
|
35
|
-
matcherTypes: inspection.matcherTypes,
|
|
36
|
-
variables: inspection.variableEntries.map(({ key, variable }) => ({
|
|
37
|
-
key,
|
|
38
|
-
variable
|
|
39
|
-
})),
|
|
40
|
-
rules: includeRules ? inspection.rules.map((rule) => ({
|
|
41
|
-
className: rule.name,
|
|
42
|
-
layer: rule.layerName,
|
|
43
|
-
type: rule.type,
|
|
44
|
-
text: rule.text
|
|
45
|
-
})) : inspection.rules.map((rule) => ({
|
|
46
|
-
className: rule.name,
|
|
47
|
-
layer: rule.layerName,
|
|
48
|
-
type: rule.type
|
|
49
|
-
}))
|
|
14
|
+
session: await createMCPToolingSession(activeManifest, manifest.nativeClassNames)
|
|
50
15
|
};
|
|
51
16
|
}
|
|
52
17
|
function classifyExtractedClass(token, inspection, discovered) {
|
|
@@ -54,100 +19,118 @@ function classifyExtractedClass(token, inspection, discovered) {
|
|
|
54
19
|
if (discovered?.usedNative.includes(token)) return "native-css";
|
|
55
20
|
if (discovered?.invalid.includes(token)) return "invalid";
|
|
56
21
|
if (discovered?.latent.includes(token)) return "latent";
|
|
57
|
-
return inspection.
|
|
22
|
+
return inspection.matchStatus === "matched" ? "generated" : "unknown";
|
|
58
23
|
}
|
|
59
|
-
function extractFromContent(
|
|
24
|
+
function extractFromContent(session, filePath, content, includeRules, discovered) {
|
|
60
25
|
const document = createMCPTextDocument(filePath, content);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
start: document.positionAt(position.range.start),
|
|
69
|
-
end: document.positionAt(position.range.end)
|
|
70
|
-
},
|
|
71
|
-
contextRange: position.contextRange,
|
|
72
|
-
sourceKind: "class-position",
|
|
73
|
-
status: classifyExtractedClass(position.token, inspection, discovered),
|
|
74
|
-
valid: inspection.valid,
|
|
75
|
-
inspection
|
|
76
|
-
};
|
|
26
|
+
const extracted = session.extractSource({ files: [{
|
|
27
|
+
source: filePath,
|
|
28
|
+
content
|
|
29
|
+
}] }).files[0];
|
|
30
|
+
if (extracted.diagnostics.length) throw Object.assign(new Error(extracted.diagnostics[0].message), {
|
|
31
|
+
code: "SOURCE_PARSE_ERROR",
|
|
32
|
+
diagnostics: extracted.diagnostics
|
|
77
33
|
});
|
|
34
|
+
return {
|
|
35
|
+
classes: extracted.occurrences.filter((occurrence) => occurrence.included).map((occurrence) => {
|
|
36
|
+
const position = {
|
|
37
|
+
token: occurrence.candidate,
|
|
38
|
+
range: occurrence.range,
|
|
39
|
+
raw: content.slice(occurrence.range.start, occurrence.range.end),
|
|
40
|
+
contextRange: occurrence.contextRange
|
|
41
|
+
};
|
|
42
|
+
const inspection = compactClassInspection(session, position.token, includeRules);
|
|
43
|
+
return {
|
|
44
|
+
raw: position.raw,
|
|
45
|
+
token: position.token,
|
|
46
|
+
range: position.range,
|
|
47
|
+
loc: {
|
|
48
|
+
start: document.positionAt(position.range.start),
|
|
49
|
+
end: document.positionAt(position.range.end)
|
|
50
|
+
},
|
|
51
|
+
contextRange: position.contextRange,
|
|
52
|
+
sourceKind: occurrence.contentKind,
|
|
53
|
+
provenance: occurrence,
|
|
54
|
+
status: classifyExtractedClass(position.token, inspection, discovered),
|
|
55
|
+
matchStatus: inspection.matchStatus,
|
|
56
|
+
cssSyntaxStatus: inspection.cssSyntaxStatus,
|
|
57
|
+
cssValueStatus: inspection.cssValueStatus,
|
|
58
|
+
browserSupport: inspection.browserSupport,
|
|
59
|
+
inspection
|
|
60
|
+
};
|
|
61
|
+
}),
|
|
62
|
+
occurrences: extracted.occurrences
|
|
63
|
+
};
|
|
78
64
|
}
|
|
79
65
|
async function extractClasses(context, options = {}) {
|
|
80
|
-
const { manifest,
|
|
81
|
-
const service = createLanguageService(manifest);
|
|
66
|
+
const { manifest, session } = await createClassInspectionState(context, options);
|
|
82
67
|
const includeRules = Boolean(options.includeRules);
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
68
|
+
try {
|
|
69
|
+
if (options.content !== void 0) {
|
|
70
|
+
const filePath = context.resolveVirtualPath(options.filePath || "index.html");
|
|
71
|
+
const extracted = extractFromContent(session, filePath, options.content, includeRules);
|
|
72
|
+
const { classes } = extracted;
|
|
73
|
+
return {
|
|
74
|
+
version: CLASS_EXTRACTION_VERSION,
|
|
75
|
+
root: context.root,
|
|
76
|
+
manifest: manifestMetadata(manifest),
|
|
77
|
+
inputs: {
|
|
78
|
+
mode: "content",
|
|
79
|
+
filePath
|
|
80
|
+
},
|
|
81
|
+
files: [{
|
|
82
|
+
filePath,
|
|
83
|
+
languageId: getLanguageId(filePath),
|
|
84
|
+
...extracted
|
|
85
|
+
}],
|
|
86
|
+
summary: {
|
|
87
|
+
files: 1,
|
|
88
|
+
classes: classes.length,
|
|
89
|
+
matched: classes.filter((className) => className.matchStatus === "matched").length,
|
|
90
|
+
unmatched: classes.filter((className) => className.matchStatus !== "matched").length
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
const filePaths = await resolveSourceFiles(context, options.patterns);
|
|
95
|
+
const scan = await scanProject(context, {
|
|
96
|
+
context: options.context,
|
|
97
|
+
patterns: options.patterns,
|
|
98
|
+
includeCss: false
|
|
99
|
+
});
|
|
100
|
+
const scanFileByPath = new Map(scan.files.map((file) => [file.filePath, file]));
|
|
101
|
+
const files = await Promise.all(filePaths.map(async (filePath) => {
|
|
102
|
+
const content = await readFile(filePath, "utf8");
|
|
103
|
+
const discovered = scanFileByPath.get(filePath)?.discovered;
|
|
104
|
+
return {
|
|
105
|
+
filePath,
|
|
106
|
+
languageId: getLanguageId(filePath),
|
|
107
|
+
...extractFromContent(session, filePath, content, includeRules, discovered)
|
|
108
|
+
};
|
|
109
|
+
}));
|
|
110
|
+
const classes = files.flatMap((file) => file.classes);
|
|
86
111
|
return {
|
|
87
112
|
version: CLASS_EXTRACTION_VERSION,
|
|
88
113
|
root: context.root,
|
|
89
|
-
manifest:
|
|
90
|
-
status: manifest.status,
|
|
91
|
-
entries: manifest.entries,
|
|
92
|
-
...manifest.status === "error" ? { error: manifest.error } : {}
|
|
93
|
-
},
|
|
114
|
+
manifest: manifestMetadata(manifest),
|
|
94
115
|
inputs: {
|
|
95
|
-
mode: "
|
|
96
|
-
|
|
116
|
+
mode: "project",
|
|
117
|
+
patterns: options.patterns ?? scan.inputs.patterns,
|
|
118
|
+
files: filePaths
|
|
97
119
|
},
|
|
98
|
-
files
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
classes
|
|
102
|
-
}],
|
|
120
|
+
files,
|
|
121
|
+
scanner: { counts: scan.scanner.counts },
|
|
122
|
+
diagnostics: scan.diagnostics,
|
|
103
123
|
summary: {
|
|
104
|
-
files:
|
|
124
|
+
files: files.length,
|
|
105
125
|
classes: classes.length,
|
|
106
|
-
|
|
107
|
-
|
|
126
|
+
matched: classes.filter((className) => className.matchStatus === "matched").length,
|
|
127
|
+
unmatched: classes.filter((className) => className.matchStatus !== "matched").length,
|
|
128
|
+
diagnostics: scan.summary.diagnostics
|
|
108
129
|
}
|
|
109
130
|
};
|
|
131
|
+
} finally {
|
|
132
|
+
session.dispose?.();
|
|
110
133
|
}
|
|
111
|
-
const filePaths = await resolveSourceFiles(context, options.patterns);
|
|
112
|
-
const scan = await scanProject(context, {
|
|
113
|
-
patterns: options.patterns,
|
|
114
|
-
includeCss: false
|
|
115
|
-
});
|
|
116
|
-
const scanFileByPath = new Map(scan.files.map((file) => [file.filePath, file]));
|
|
117
|
-
const files = await Promise.all(filePaths.map(async (filePath) => {
|
|
118
|
-
const content = await readFile(filePath, "utf8");
|
|
119
|
-
const discovered = scanFileByPath.get(filePath)?.discovered;
|
|
120
|
-
return {
|
|
121
|
-
filePath,
|
|
122
|
-
languageId: getLanguageId(filePath),
|
|
123
|
-
classes: extractFromContent(service, css, filePath, content, includeRules, discovered)
|
|
124
|
-
};
|
|
125
|
-
}));
|
|
126
|
-
const classes = files.flatMap((file) => file.classes);
|
|
127
|
-
return {
|
|
128
|
-
version: CLASS_EXTRACTION_VERSION,
|
|
129
|
-
root: context.root,
|
|
130
|
-
manifest: {
|
|
131
|
-
status: manifest.status,
|
|
132
|
-
entries: manifest.entries,
|
|
133
|
-
...manifest.status === "error" ? { error: manifest.error } : {}
|
|
134
|
-
},
|
|
135
|
-
inputs: {
|
|
136
|
-
mode: "project",
|
|
137
|
-
patterns: options.patterns ?? scan.inputs.patterns,
|
|
138
|
-
files: filePaths
|
|
139
|
-
},
|
|
140
|
-
files,
|
|
141
|
-
scanner: { counts: scan.scanner.counts },
|
|
142
|
-
diagnostics: scan.diagnostics,
|
|
143
|
-
summary: {
|
|
144
|
-
files: files.length,
|
|
145
|
-
classes: classes.length,
|
|
146
|
-
valid: classes.filter((className) => className.valid).length,
|
|
147
|
-
invalid: classes.filter((className) => !className.valid).length,
|
|
148
|
-
diagnostics: scan.summary.diagnostics
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
134
|
}
|
|
152
135
|
function findClassOccurrences(report, className) {
|
|
153
136
|
return report.files.flatMap((file) => {
|
|
@@ -169,56 +152,58 @@ async function traceClass(context, options) {
|
|
|
169
152
|
const [scan, state] = await Promise.all([scanProject(context, {
|
|
170
153
|
patterns: options.patterns,
|
|
171
154
|
classes: [options.className],
|
|
172
|
-
includeCss: options.includeCss
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
155
|
+
includeCss: options.includeCss,
|
|
156
|
+
context: options.context
|
|
157
|
+
}), createClassInspectionState(context, options)]);
|
|
158
|
+
try {
|
|
159
|
+
const inspection = compactClassInspection(state.session, options.className, true);
|
|
160
|
+
const missingResult = [...scan.missingCSS.present, ...scan.missingCSS.missing].find((result) => result.className === options.className);
|
|
161
|
+
const occurrences = findClassOccurrences(scan, options.className);
|
|
162
|
+
const status = missingResult?.status ?? (inspection.matchStatus === "matched" ? "present" : "missing");
|
|
163
|
+
const reason = missingResult?.reason ?? (inspection.matchStatus === "matched" ? "generated" : "not-detected");
|
|
164
|
+
return {
|
|
165
|
+
version: CLASS_TRACE_VERSION,
|
|
166
|
+
root: context.root,
|
|
167
|
+
manifest: manifestMetadata(state.manifest),
|
|
168
|
+
inputs: {
|
|
169
|
+
className: options.className,
|
|
170
|
+
patterns: options.patterns ?? scan.inputs.patterns
|
|
171
|
+
},
|
|
188
172
|
className: options.className,
|
|
189
|
-
patterns: options.patterns ?? scan.inputs.patterns,
|
|
190
|
-
mode: options.mode
|
|
191
|
-
},
|
|
192
|
-
className: options.className,
|
|
193
|
-
status,
|
|
194
|
-
reason,
|
|
195
|
-
detected: occurrences.length > 0,
|
|
196
|
-
occurrences,
|
|
197
|
-
inspection,
|
|
198
|
-
scanner: {
|
|
199
|
-
counts: scan.scanner.counts,
|
|
200
|
-
safelist: scan.scanner.classes.safelist.includes(options.className),
|
|
201
|
-
blocklist: scan.scanner.classes.blocklist.includes(options.className)
|
|
202
|
-
},
|
|
203
|
-
css: {
|
|
204
|
-
included: scan.css.included,
|
|
205
|
-
bytes: scan.css.bytes,
|
|
206
|
-
emittedGlobals: scan.css.emittedGlobals,
|
|
207
|
-
...scan.css.text !== void 0 ? { text: scan.css.text } : {}
|
|
208
|
-
},
|
|
209
|
-
diagnostics: scan.diagnostics.filter((diagnostic) => {
|
|
210
|
-
if (diagnostic.sourceKind === "missing-css") return diagnostic.data?.className === options.className;
|
|
211
|
-
return diagnostic.message.includes(options.className);
|
|
212
|
-
}),
|
|
213
|
-
summary: {
|
|
214
173
|
status,
|
|
215
174
|
reason,
|
|
216
175
|
detected: occurrences.length > 0,
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
176
|
+
occurrences,
|
|
177
|
+
inspection,
|
|
178
|
+
scanner: {
|
|
179
|
+
counts: scan.scanner.counts,
|
|
180
|
+
safelist: scan.scanner.classes.safelist.includes(options.className),
|
|
181
|
+
blocklist: scan.scanner.classes.blocklist.includes(options.className)
|
|
182
|
+
},
|
|
183
|
+
css: {
|
|
184
|
+
included: scan.css.included,
|
|
185
|
+
bytes: scan.css.bytes,
|
|
186
|
+
emittedGlobals: scan.css.emittedGlobals,
|
|
187
|
+
...scan.css.text !== void 0 ? { text: scan.css.text } : {}
|
|
188
|
+
},
|
|
189
|
+
diagnostics: scan.diagnostics.filter((diagnostic) => {
|
|
190
|
+
if (diagnostic.sourceKind === "missing-css") return diagnostic.data?.className === options.className;
|
|
191
|
+
return diagnostic.message.includes(options.className);
|
|
192
|
+
}),
|
|
193
|
+
summary: {
|
|
194
|
+
status,
|
|
195
|
+
reason,
|
|
196
|
+
detected: occurrences.length > 0,
|
|
197
|
+
matchStatus: inspection.matchStatus,
|
|
198
|
+
cssSyntaxStatus: inspection.cssSyntaxStatus,
|
|
199
|
+
cssValueStatus: inspection.cssValueStatus,
|
|
200
|
+
browserSupport: inspection.browserSupport,
|
|
201
|
+
rules: inspection.rules.length,
|
|
202
|
+
diagnostics: scan.diagnostics.length
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
} finally {
|
|
206
|
+
state.session.dispose?.();
|
|
207
|
+
}
|
|
222
208
|
}
|
|
223
|
-
//#endregion
|
|
224
209
|
export { extractClasses, traceClass };
|