@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/dist/compare.js
CHANGED
|
@@ -1,44 +1,42 @@
|
|
|
1
|
+
import { loadWorkspaceManifest, manifestMetadata, requireWorkspaceManifest } from "./project.js";
|
|
2
|
+
import { compactClassInspection, createMCPToolingSession } from "./tooling-session.js";
|
|
1
3
|
import { createMCPTextDocument } from "./document.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import { parseHTML } from "@master/css-server";
|
|
7
|
-
//#region src/compare.ts
|
|
8
|
-
const CSS_COMPARE_VERSION = 1;
|
|
9
|
-
const defaultManifest = createRequire(import.meta.url)("@master/css-preset/default-manifest.json");
|
|
4
|
+
import { renderClassNamesSync } from "@master/css/node";
|
|
5
|
+
import { compareProjectSnapshots } from "@master/css-compiler/diagnostics";
|
|
6
|
+
// src/compare.ts
|
|
7
|
+
const CSS_COMPARE_VERSION = 2;
|
|
10
8
|
function unique(values) {
|
|
11
9
|
return [...new Set(values)];
|
|
12
10
|
}
|
|
13
11
|
function splitClassList(value) {
|
|
14
12
|
return unique((value ?? "").split(/\s+/).map((className) => className.trim()).filter(Boolean));
|
|
15
13
|
}
|
|
16
|
-
function extractContentClasses(content, filePath) {
|
|
14
|
+
function extractContentClasses(content, filePath, session) {
|
|
17
15
|
if (content === void 0) return [];
|
|
18
|
-
const service = new CSSLanguageService();
|
|
19
16
|
const document = createMCPTextDocument(filePath, content);
|
|
20
|
-
return unique(
|
|
17
|
+
return unique(session.analyzeDocument({
|
|
18
|
+
source: content,
|
|
19
|
+
languageId: document.languageId
|
|
20
|
+
}).classPositions.map((position) => position.token));
|
|
21
21
|
}
|
|
22
|
-
function resolveClasses(options, side, filePath) {
|
|
22
|
+
function resolveClasses(options, side, filePath, session) {
|
|
23
23
|
const classList = side === "before" ? options.beforeClassList : options.afterClassList;
|
|
24
24
|
const html = side === "before" ? options.beforeHtml : options.afterHtml;
|
|
25
25
|
const content = side === "before" ? options.beforeContent : options.afterContent;
|
|
26
26
|
if (classList !== void 0) return splitClassList(classList);
|
|
27
|
-
if (html !== void 0) return unique(
|
|
28
|
-
|
|
27
|
+
if (html !== void 0) return unique(session.extractSource({ files: [{
|
|
28
|
+
source: filePath,
|
|
29
|
+
content: html,
|
|
30
|
+
kind: "html"
|
|
31
|
+
}] }).files[0]?.candidates ?? []);
|
|
32
|
+
return extractContentClasses(content, filePath, session);
|
|
29
33
|
}
|
|
30
34
|
function renderClasses(manifest, classes) {
|
|
31
|
-
const
|
|
32
|
-
const invalid = [];
|
|
33
|
-
for (const className of classes) {
|
|
34
|
-
const rules = css.generate(className);
|
|
35
|
-
if (rules.length) for (const rule of rules) rule.layer.insert(rule);
|
|
36
|
-
else invalid.push(className);
|
|
37
|
-
}
|
|
35
|
+
const rendered = renderClassNamesSync(classes, { manifest });
|
|
38
36
|
return {
|
|
39
|
-
text:
|
|
40
|
-
bytes:
|
|
41
|
-
invalid
|
|
37
|
+
text: rendered.cssText,
|
|
38
|
+
bytes: Buffer.byteLength(rendered.cssText, "utf8"),
|
|
39
|
+
invalid: [...rendered.invalidClassNames]
|
|
42
40
|
};
|
|
43
41
|
}
|
|
44
42
|
function diffValues(before, after) {
|
|
@@ -64,68 +62,86 @@ function createTextDiff(before, after) {
|
|
|
64
62
|
].join("\n");
|
|
65
63
|
}
|
|
66
64
|
async function compareCSS(context, options) {
|
|
67
|
-
|
|
65
|
+
if (options.beforeSnapshot || options.afterSnapshot) {
|
|
66
|
+
if (!options.beforeSnapshot || !options.afterSnapshot) throw new Error("Project comparison requires both beforeSnapshot and afterSnapshot.");
|
|
67
|
+
if (Object.entries(options).some(([key, value]) => key !== "beforeSnapshot" && key !== "afterSnapshot" && value !== void 0)) throw new Error("Project snapshots cannot be combined with class, content, filePath or context inputs.");
|
|
68
|
+
return {
|
|
69
|
+
version: 3,
|
|
70
|
+
mode: "project",
|
|
71
|
+
comparison: await compareProjectSnapshots({
|
|
72
|
+
before: options.beforeSnapshot,
|
|
73
|
+
after: options.afterSnapshot
|
|
74
|
+
})
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
const manifest = await loadWorkspaceManifest(context, options.context);
|
|
68
78
|
const filePath = context.resolveVirtualPath(options.filePath || "index.html");
|
|
69
|
-
const activeManifest = manifest
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
79
|
+
const activeManifest = requireWorkspaceManifest(manifest);
|
|
80
|
+
const session = createMCPToolingSession(activeManifest, manifest.nativeClassNames);
|
|
81
|
+
try {
|
|
82
|
+
const beforeClasses = resolveClasses(options, "before", filePath, session);
|
|
83
|
+
const afterClasses = resolveClasses(options, "after", filePath, session);
|
|
84
|
+
const before = renderClasses(activeManifest, beforeClasses);
|
|
85
|
+
const after = renderClasses(activeManifest, afterClasses);
|
|
86
|
+
const inspections = {
|
|
87
|
+
before: beforeClasses.map((name) => compactClassInspection(session, name, true)),
|
|
88
|
+
after: afterClasses.map((name) => compactClassInspection(session, name, true))
|
|
89
|
+
};
|
|
90
|
+
const classDiff = diffValues(beforeClasses, afterClasses);
|
|
91
|
+
const ruleDiff = diffValues(splitRules(before.text), splitRules(after.text));
|
|
92
|
+
return {
|
|
93
|
+
version: CSS_COMPARE_VERSION,
|
|
94
|
+
root: context.root,
|
|
95
|
+
manifest: manifestMetadata(manifest),
|
|
96
|
+
inspections,
|
|
97
|
+
diagnostics: [...inspections.before, ...inspections.after].flatMap((inspection) => inspection.diagnostics ?? []),
|
|
98
|
+
inputs: {
|
|
99
|
+
filePath,
|
|
100
|
+
before: {
|
|
101
|
+
classes: beforeClasses.length,
|
|
102
|
+
invalid: before.invalid.length
|
|
103
|
+
},
|
|
104
|
+
after: {
|
|
105
|
+
classes: afterClasses.length,
|
|
106
|
+
invalid: after.invalid.length
|
|
107
|
+
}
|
|
89
108
|
},
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
invalid: {
|
|
97
|
-
before: before.invalid,
|
|
98
|
-
after: after.invalid,
|
|
99
|
-
added: after.invalid.filter((className) => !before.invalid.includes(className)),
|
|
100
|
-
removed: before.invalid.filter((className) => !after.invalid.includes(className))
|
|
101
|
-
},
|
|
102
|
-
css: {
|
|
103
|
-
changed: before.text !== after.text,
|
|
104
|
-
before: {
|
|
105
|
-
bytes: before.bytes,
|
|
106
|
-
text: before.text
|
|
109
|
+
classes: classDiff,
|
|
110
|
+
invalid: {
|
|
111
|
+
before: before.invalid,
|
|
112
|
+
after: after.invalid,
|
|
113
|
+
added: after.invalid.filter((className) => !before.invalid.includes(className)),
|
|
114
|
+
removed: before.invalid.filter((className) => !after.invalid.includes(className))
|
|
107
115
|
},
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
116
|
+
css: {
|
|
117
|
+
changed: before.text !== after.text,
|
|
118
|
+
before: {
|
|
119
|
+
bytes: before.bytes,
|
|
120
|
+
text: before.text
|
|
121
|
+
},
|
|
122
|
+
after: {
|
|
123
|
+
bytes: after.bytes,
|
|
124
|
+
text: after.text
|
|
125
|
+
},
|
|
126
|
+
bytesDelta: after.bytes - before.bytes,
|
|
127
|
+
diff: createTextDiff(before.text, after.text)
|
|
111
128
|
},
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
+
rules: {
|
|
130
|
+
added: ruleDiff.added,
|
|
131
|
+
removed: ruleDiff.removed,
|
|
132
|
+
unchanged: ruleDiff.unchanged.length
|
|
133
|
+
},
|
|
134
|
+
summary: {
|
|
135
|
+
changed: before.text !== after.text,
|
|
136
|
+
addedClasses: classDiff.added.length,
|
|
137
|
+
removedClasses: classDiff.removed.length,
|
|
138
|
+
addedRules: ruleDiff.added.length,
|
|
139
|
+
removedRules: ruleDiff.removed.length,
|
|
140
|
+
bytesDelta: after.bytes - before.bytes
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
} finally {
|
|
144
|
+
session.dispose?.();
|
|
145
|
+
}
|
|
129
146
|
}
|
|
130
|
-
//#endregion
|
|
131
147
|
export { compareCSS };
|
package/dist/context.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
//#region src/context.d.ts
|
|
2
1
|
interface MasterCSSMCPContextOptions {
|
|
3
2
|
root?: string;
|
|
4
3
|
roots?: string[];
|
|
@@ -19,12 +18,6 @@ interface StoredPreviewChange {
|
|
|
19
18
|
afterText: string;
|
|
20
19
|
diff: string;
|
|
21
20
|
}
|
|
22
|
-
interface StoredPreview {
|
|
23
|
-
confirmToken: string;
|
|
24
|
-
createdAt: number;
|
|
25
|
-
expiresAt: number;
|
|
26
|
-
changes: StoredPreviewChange[];
|
|
27
|
-
}
|
|
28
21
|
interface PreviewResult {
|
|
29
22
|
confirmToken?: string;
|
|
30
23
|
expiresAt?: number;
|
|
@@ -41,12 +34,13 @@ declare class MasterCSSMCPContext {
|
|
|
41
34
|
readonly previewTTL: number;
|
|
42
35
|
private readonly containmentRoots;
|
|
43
36
|
private previews;
|
|
37
|
+
private applying;
|
|
44
38
|
constructor(options?: MasterCSSMCPContextOptions);
|
|
45
39
|
assertContained(filePath: string): string;
|
|
46
40
|
resolveVirtualPath(filePath: string): string;
|
|
47
41
|
resolveExistingFile(filePath: string): Promise<string>;
|
|
48
42
|
resolveWritableFile(filePath: string): Promise<string>;
|
|
49
|
-
validateGlobPatterns(patterns: string[]): void;
|
|
43
|
+
validateGlobPatterns(patterns: readonly string[]): void;
|
|
50
44
|
createPreview(changes: PreviewChange[], ttl?: number): Promise<PreviewResult>;
|
|
51
45
|
applyPreview(confirmToken: string): Promise<{
|
|
52
46
|
applied: boolean;
|
|
@@ -55,6 +49,7 @@ declare class MasterCSSMCPContext {
|
|
|
55
49
|
afterHash: string;
|
|
56
50
|
}[];
|
|
57
51
|
}>;
|
|
52
|
+
private applyStoredPreview;
|
|
53
|
+
dispose(): void;
|
|
58
54
|
}
|
|
59
|
-
|
|
60
|
-
export { MasterCSSMCPContextOptions, PreviewChange, PreviewResult, StoredPreview, StoredPreviewChange, MasterCSSMCPContext as default };
|
|
55
|
+
export { MasterCSSMCPContextOptions, PreviewChange, PreviewResult, StoredPreviewChange, MasterCSSMCPContext as default };
|
package/dist/context.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { dirname, isAbsolute, relative, resolve } from "node:path";
|
|
3
|
-
import { createHash, randomBytes } from "node:crypto";
|
|
1
|
+
import { withPreviewWriteLock } from "./preview-write-lock.js";
|
|
4
2
|
import { existsSync, realpathSync, statSync } from "node:fs";
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
4
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
5
|
+
import { lstat, mkdir, readFile, realpath, stat, writeFile } from "node:fs/promises";
|
|
6
|
+
// src/context.ts
|
|
7
|
+
const DEFAULT_PREVIEW_TTL = 3e5;
|
|
7
8
|
function sha256(text) {
|
|
8
9
|
return createHash("sha256").update(text).digest("hex");
|
|
9
10
|
}
|
|
@@ -48,6 +49,7 @@ var MasterCSSMCPContext = class {
|
|
|
48
49
|
previewTTL;
|
|
49
50
|
containmentRoots;
|
|
50
51
|
previews = /* @__PURE__ */ new Map();
|
|
52
|
+
applying = /* @__PURE__ */ new Set();
|
|
51
53
|
constructor(options = {}) {
|
|
52
54
|
const configuredRoots = options.roots?.length ? options.roots : [options.root || process.cwd()];
|
|
53
55
|
const roots = [];
|
|
@@ -90,9 +92,10 @@ var MasterCSSMCPContext = class {
|
|
|
90
92
|
return realPath;
|
|
91
93
|
}
|
|
92
94
|
this.assertContained(resolved);
|
|
95
|
+
if ((await lstat(resolved).catch(() => void 0))?.isSymbolicLink()) throw new Error(`Path is a dangling symbolic link: ${resolved}`);
|
|
93
96
|
const parent = await realpath$1(dirname(resolved));
|
|
94
97
|
this.assertContained(parent);
|
|
95
|
-
return resolved;
|
|
98
|
+
return join(parent, basename(resolved));
|
|
96
99
|
}
|
|
97
100
|
validateGlobPatterns(patterns) {
|
|
98
101
|
for (const pattern of patterns) assertFilePattern(pattern);
|
|
@@ -109,8 +112,8 @@ var MasterCSSMCPContext = class {
|
|
|
109
112
|
beforeHash: beforeExists ? sha256(beforeText) : null,
|
|
110
113
|
afterHash: sha256(change.afterText),
|
|
111
114
|
beforeExists,
|
|
112
|
-
beforeBytes: beforeText
|
|
113
|
-
afterBytes: change.afterText
|
|
115
|
+
beforeBytes: Buffer.byteLength(beforeText, "utf8"),
|
|
116
|
+
afterBytes: Buffer.byteLength(change.afterText, "utf8"),
|
|
114
117
|
afterText: change.afterText,
|
|
115
118
|
diff: formatDiff(filePath, beforeText, change.afterText)
|
|
116
119
|
});
|
|
@@ -143,6 +146,19 @@ var MasterCSSMCPContext = class {
|
|
|
143
146
|
async applyPreview(confirmToken) {
|
|
144
147
|
const preview = this.previews.get(confirmToken);
|
|
145
148
|
if (!preview) throw new Error("Unknown or already applied preview token.");
|
|
149
|
+
if (this.applying.has(confirmToken)) throw new Error("Preview token is already being applied.");
|
|
150
|
+
this.applying.add(confirmToken);
|
|
151
|
+
try {
|
|
152
|
+
return await withPreviewWriteLock(async () => {
|
|
153
|
+
if (this.previews.get(confirmToken) !== preview) throw new Error("Unknown or already applied preview token.");
|
|
154
|
+
return await this.applyStoredPreview(preview);
|
|
155
|
+
});
|
|
156
|
+
} finally {
|
|
157
|
+
this.applying.delete(confirmToken);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
async applyStoredPreview(preview) {
|
|
161
|
+
const { confirmToken } = preview;
|
|
146
162
|
if (preview.expiresAt < Date.now()) {
|
|
147
163
|
this.previews.delete(confirmToken);
|
|
148
164
|
throw new Error("Preview token has expired.");
|
|
@@ -158,7 +174,7 @@ var MasterCSSMCPContext = class {
|
|
|
158
174
|
}
|
|
159
175
|
for (const change of preview.changes) {
|
|
160
176
|
await mkdir(dirname(change.filePath), { recursive: true });
|
|
161
|
-
await writeFile(change.filePath, change.afterText);
|
|
177
|
+
await writeFile(change.filePath, change.afterText, { flag: change.beforeExists ? "w" : "wx" });
|
|
162
178
|
}
|
|
163
179
|
this.previews.delete(confirmToken);
|
|
164
180
|
return {
|
|
@@ -169,6 +185,9 @@ var MasterCSSMCPContext = class {
|
|
|
169
185
|
}))
|
|
170
186
|
};
|
|
171
187
|
}
|
|
188
|
+
dispose() {
|
|
189
|
+
this.previews.clear();
|
|
190
|
+
}
|
|
172
191
|
};
|
|
173
192
|
async function realpath$1(filePath) {
|
|
174
193
|
try {
|
|
@@ -185,5 +204,4 @@ async function readFileIfExists(filePath) {
|
|
|
185
204
|
throw error;
|
|
186
205
|
}
|
|
187
206
|
}
|
|
188
|
-
//#endregion
|
|
189
207
|
export { MasterCSSMCPContext as default };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { range, strings } from "./semantic-schema.js";
|
|
2
|
+
import * as z from "zod/v4";
|
|
3
|
+
// src/design-system-schema.ts
|
|
4
|
+
const tokenMetadata = z.object({
|
|
5
|
+
description: z.string().optional(),
|
|
6
|
+
deprecated: z.boolean().optional(),
|
|
7
|
+
replacement: z.string().optional()
|
|
8
|
+
}).strict();
|
|
9
|
+
const designSystemOptions = z.object({
|
|
10
|
+
version: z.literal(1),
|
|
11
|
+
metadata: z.record(z.string(), tokenMetadata).optional(),
|
|
12
|
+
rawValuePolicy: z.object({
|
|
13
|
+
allowRawValues: z.boolean().optional(),
|
|
14
|
+
allowProperties: strings.optional(),
|
|
15
|
+
requireProperties: strings.optional(),
|
|
16
|
+
allowedPatterns: strings.optional()
|
|
17
|
+
}).strict().optional()
|
|
18
|
+
}).strict();
|
|
19
|
+
const designSystemReport = z.object({
|
|
20
|
+
version: z.literal(1),
|
|
21
|
+
tokens: z.array(z.object({
|
|
22
|
+
name: z.string(),
|
|
23
|
+
metadata: tokenMetadata.optional()
|
|
24
|
+
})),
|
|
25
|
+
references: z.array(z.object({
|
|
26
|
+
source: z.string(),
|
|
27
|
+
token: z.string(),
|
|
28
|
+
registered: z.boolean(),
|
|
29
|
+
range,
|
|
30
|
+
property: z.string(),
|
|
31
|
+
declarationRange: range,
|
|
32
|
+
ancestry: z.array(z.object({
|
|
33
|
+
kind: z.enum(["selector", "at-rule"]),
|
|
34
|
+
name: z.string().optional(),
|
|
35
|
+
prelude: z.string(),
|
|
36
|
+
range
|
|
37
|
+
})),
|
|
38
|
+
hasFallback: z.boolean(),
|
|
39
|
+
inFallback: z.boolean(),
|
|
40
|
+
importers: strings
|
|
41
|
+
})),
|
|
42
|
+
collisions: z.array(z.object({
|
|
43
|
+
prefix: z.string(),
|
|
44
|
+
key: z.string(),
|
|
45
|
+
className: z.string(),
|
|
46
|
+
namespaces: strings,
|
|
47
|
+
properties: strings
|
|
48
|
+
})),
|
|
49
|
+
components: z.array(z.object({
|
|
50
|
+
className: z.string(),
|
|
51
|
+
attributes: z.array(z.object({
|
|
52
|
+
name: z.string(),
|
|
53
|
+
values: strings,
|
|
54
|
+
presence: z.boolean()
|
|
55
|
+
})),
|
|
56
|
+
sources: strings
|
|
57
|
+
})),
|
|
58
|
+
diagnostics: z.array(z.object({
|
|
59
|
+
code: z.string(),
|
|
60
|
+
severity: z.enum([
|
|
61
|
+
"error",
|
|
62
|
+
"warning",
|
|
63
|
+
"information"
|
|
64
|
+
]),
|
|
65
|
+
message: z.string(),
|
|
66
|
+
source: z.string().optional(),
|
|
67
|
+
range: range.optional(),
|
|
68
|
+
token: z.string().optional(),
|
|
69
|
+
data: z.record(z.string(), z.json()).optional()
|
|
70
|
+
})),
|
|
71
|
+
coverage: z.object({
|
|
72
|
+
scope: z.literal("provided-stylesheets"),
|
|
73
|
+
browser: z.literal("not-checked"),
|
|
74
|
+
notes: strings
|
|
75
|
+
}),
|
|
76
|
+
summary: z.object({
|
|
77
|
+
stylesheets: z.number(),
|
|
78
|
+
tokens: z.number(),
|
|
79
|
+
references: z.number(),
|
|
80
|
+
collisions: z.number(),
|
|
81
|
+
errors: z.number(),
|
|
82
|
+
warnings: z.number()
|
|
83
|
+
}),
|
|
84
|
+
project: z.object({
|
|
85
|
+
cwd: z.string(),
|
|
86
|
+
entries: strings,
|
|
87
|
+
files: strings,
|
|
88
|
+
routeStylesheets: strings,
|
|
89
|
+
excluded: strings,
|
|
90
|
+
edges: z.array(z.object({
|
|
91
|
+
from: z.string(),
|
|
92
|
+
specifier: z.string(),
|
|
93
|
+
resolved: z.string()
|
|
94
|
+
}))
|
|
95
|
+
})
|
|
96
|
+
});
|
|
97
|
+
export { designSystemOptions, designSystemReport };
|
package/dist/directives.js
CHANGED
|
@@ -1,158 +1,108 @@
|
|
|
1
|
+
import { loadWorkspaceManifest, manifestFingerprint, manifestMetadata, requireWorkspaceManifest } from "./project.js";
|
|
1
2
|
import { createMCPTextDocument } from "./document.js";
|
|
2
|
-
import { getErrorMessage } from "./result.js";
|
|
3
3
|
import { summarizeManifest } from "./manifest-summary.js";
|
|
4
|
-
import { readFile } from "node:fs/promises";
|
|
5
4
|
import { basename } from "node:path";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
const DIRECTIVE_INSPECTION_VERSION =
|
|
5
|
+
import { readFile } from "node:fs/promises";
|
|
6
|
+
import { compileManifestFileSync, compileManifestSync, inspectCSSSync } from "@master/css-compiler/node";
|
|
7
|
+
// src/directives.ts
|
|
8
|
+
const DIRECTIVE_INSPECTION_VERSION = 2;
|
|
10
9
|
function createDirectiveEntries(content, filePath) {
|
|
11
10
|
const document = createMCPTextDocument(filePath, content);
|
|
12
|
-
return
|
|
11
|
+
return inspectCSSSync(content).directives.map((directive) => ({
|
|
13
12
|
name: directive.name,
|
|
14
|
-
range:
|
|
15
|
-
start: directive.start,
|
|
16
|
-
end: directive.end
|
|
17
|
-
},
|
|
13
|
+
range: directive.range,
|
|
18
14
|
loc: {
|
|
19
|
-
start: document.positionAt(directive.start),
|
|
20
|
-
end: document.positionAt(directive.end)
|
|
15
|
+
start: document.positionAt(directive.range.start),
|
|
16
|
+
end: document.positionAt(directive.range.end)
|
|
21
17
|
},
|
|
22
18
|
prelude: content.slice(directive.preludeRange.start, directive.preludeRange.end).trim(),
|
|
23
|
-
hasBlock:
|
|
24
|
-
quotedStrings: directive.
|
|
19
|
+
hasBlock: directive.hasBlock,
|
|
20
|
+
quotedStrings: directive.quotedStrings
|
|
25
21
|
}));
|
|
26
22
|
}
|
|
27
|
-
function countObjectKeys(value) {
|
|
28
|
-
return value && typeof value === "object" ? Object.keys(value).length : 0;
|
|
29
|
-
}
|
|
30
|
-
function summarizeManifestInput(input) {
|
|
31
|
-
const manifestInput = input && typeof input === "object" ? input : {};
|
|
32
|
-
return {
|
|
33
|
-
keys: Object.keys(manifestInput),
|
|
34
|
-
counts: {
|
|
35
|
-
settings: countObjectKeys(manifestInput.settings),
|
|
36
|
-
variables: countObjectKeys(manifestInput.variables),
|
|
37
|
-
utilities: Array.isArray(manifestInput.utilities) ? manifestInput.utilities.length : countObjectKeys(manifestInput.utilities),
|
|
38
|
-
variants: Array.isArray(manifestInput.variants) ? manifestInput.variants.length : countObjectKeys(manifestInput.variants),
|
|
39
|
-
conditions: countObjectKeys(manifestInput.conditions),
|
|
40
|
-
selectors: countObjectKeys(manifestInput.selectors),
|
|
41
|
-
animations: countObjectKeys(manifestInput.animations)
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
23
|
function summarizeCompileResult(result) {
|
|
46
|
-
const
|
|
24
|
+
const warnings = result.diagnostics.filter((diagnostic) => diagnostic.severity === "warning").map((diagnostic) => diagnostic.message);
|
|
47
25
|
return {
|
|
48
26
|
manifest: summarizeManifest(result.manifest),
|
|
49
27
|
directives: {
|
|
50
|
-
manifestInput:
|
|
28
|
+
manifestInput: result.directiveSummary.manifestInput,
|
|
51
29
|
classNames: result.classNames,
|
|
52
30
|
nativeClassNames: result.nativeClassNames,
|
|
53
|
-
styleDefinitions: styleDefinitions
|
|
54
|
-
extractionPolicy: result.extractionPolicy
|
|
31
|
+
styleDefinitions: result.directiveSummary.styleDefinitions,
|
|
32
|
+
extractionPolicy: result.directiveSummary.extractionPolicy
|
|
55
33
|
},
|
|
56
34
|
css: {
|
|
57
|
-
bytes: result.css
|
|
58
|
-
nativeBytes: result.nativeCSS
|
|
59
|
-
generatedBytes: result.generatedCSS
|
|
35
|
+
bytes: Buffer.byteLength(result.css, "utf8"),
|
|
36
|
+
nativeBytes: Buffer.byteLength(result.nativeCSS, "utf8"),
|
|
37
|
+
generatedBytes: Buffer.byteLength(result.generatedCSS, "utf8")
|
|
60
38
|
},
|
|
61
39
|
dependencies: result.dependencies,
|
|
62
|
-
warnings
|
|
40
|
+
warnings,
|
|
41
|
+
diagnostics: result.diagnostics
|
|
63
42
|
};
|
|
64
43
|
}
|
|
65
44
|
async function compileDirectives(context, options) {
|
|
45
|
+
const manifest = await loadWorkspaceManifest(context, options.context, options.entryPath ? [await context.resolveExistingFile(options.entryPath)] : void 0);
|
|
46
|
+
const baseManifest = requireWorkspaceManifest(manifest);
|
|
66
47
|
if (options.entryPath) {
|
|
67
48
|
const filePath = await context.resolveExistingFile(options.entryPath);
|
|
68
|
-
const [content, result] = await Promise.all([readFile(filePath, "utf8"), Promise.resolve(
|
|
49
|
+
const [content, result] = await Promise.all([readFile(filePath, "utf8"), Promise.resolve(compileManifestFileSync(filePath, {
|
|
69
50
|
root: context.root,
|
|
51
|
+
baseManifest,
|
|
70
52
|
preserveNativeCSS: options.preserveNativeCSS
|
|
71
53
|
}))]);
|
|
72
54
|
return {
|
|
73
55
|
filePath,
|
|
74
56
|
content,
|
|
75
|
-
result
|
|
57
|
+
result,
|
|
58
|
+
context: manifestMetadata(manifest)
|
|
76
59
|
};
|
|
77
60
|
}
|
|
78
61
|
if (options.content === void 0) throw new Error("Either entryPath or content is required.");
|
|
79
62
|
const filePath = context.resolveVirtualPath(options.filePath || "master.css");
|
|
80
|
-
const result =
|
|
81
|
-
|
|
63
|
+
const result = compileManifestSync(options.content, {
|
|
64
|
+
baseManifest,
|
|
82
65
|
from: filePath,
|
|
83
66
|
preserveNativeCSS: options.preserveNativeCSS
|
|
84
67
|
});
|
|
85
68
|
return {
|
|
86
69
|
filePath,
|
|
87
70
|
content: options.content,
|
|
71
|
+
context: manifestMetadata(manifest),
|
|
88
72
|
result
|
|
89
73
|
};
|
|
90
74
|
}
|
|
91
75
|
async function inspectDirectives(context, options) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
76
|
+
const compiled = await compileDirectives(context, options);
|
|
77
|
+
const inspection = summarizeCompileResult(compiled.result);
|
|
78
|
+
const directiveEntries = createDirectiveEntries(compiled.content, compiled.filePath);
|
|
79
|
+
return {
|
|
80
|
+
version: DIRECTIVE_INSPECTION_VERSION,
|
|
81
|
+
root: context.root,
|
|
82
|
+
context: compiled.context,
|
|
83
|
+
status: inspection.warnings.length ? "warning" : "ok",
|
|
84
|
+
input: {
|
|
85
|
+
filePath: compiled.filePath,
|
|
86
|
+
name: basename(compiled.filePath),
|
|
87
|
+
mode: options.entryPath ? "entry" : "content"
|
|
88
|
+
},
|
|
89
|
+
directiveEntries,
|
|
90
|
+
...inspection,
|
|
91
|
+
manifest: {
|
|
92
|
+
...inspection.manifest,
|
|
93
|
+
fingerprint: manifestFingerprint(compiled.result.manifest),
|
|
94
|
+
languageVersion: compiled.result.manifest.languageVersion
|
|
95
|
+
},
|
|
96
|
+
diagnostics: inspection.diagnostics,
|
|
97
|
+
summary: {
|
|
99
98
|
status: inspection.warnings.length ? "warning" : "ok",
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
code: "compiler-warning",
|
|
109
|
-
severity: "warning",
|
|
110
|
-
message: warning,
|
|
111
|
-
source: "Master CSS",
|
|
112
|
-
sourceKind: "directive",
|
|
113
|
-
filePath: compiled.filePath
|
|
114
|
-
})),
|
|
115
|
-
summary: {
|
|
116
|
-
status: inspection.warnings.length ? "warning" : "ok",
|
|
117
|
-
directives: directiveEntries.length,
|
|
118
|
-
classNames: inspection.directives.classNames.length,
|
|
119
|
-
nativeClassNames: inspection.directives.nativeClassNames.length,
|
|
120
|
-
dependencies: inspection.dependencies.length,
|
|
121
|
-
warnings: inspection.warnings.length,
|
|
122
|
-
cssBytes: inspection.css.bytes
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
} catch (error) {
|
|
126
|
-
const filePath = options.entryPath || options.filePath || "master.css";
|
|
127
|
-
return {
|
|
128
|
-
version: DIRECTIVE_INSPECTION_VERSION,
|
|
129
|
-
root: context.root,
|
|
130
|
-
status: "error",
|
|
131
|
-
input: {
|
|
132
|
-
filePath,
|
|
133
|
-
mode: options.entryPath ? "entry" : "content"
|
|
134
|
-
},
|
|
135
|
-
directiveEntries: options.content ? createDirectiveEntries(options.content, context.resolveVirtualPath(options.filePath || "master.css")) : [],
|
|
136
|
-
diagnostics: [{
|
|
137
|
-
code: "directive-inspection-error",
|
|
138
|
-
severity: "error",
|
|
139
|
-
message: getErrorMessage(error),
|
|
140
|
-
source: "Master CSS",
|
|
141
|
-
sourceKind: "directive",
|
|
142
|
-
filePath
|
|
143
|
-
}],
|
|
144
|
-
summary: {
|
|
145
|
-
status: "error",
|
|
146
|
-
directives: 0,
|
|
147
|
-
classNames: 0,
|
|
148
|
-
nativeClassNames: 0,
|
|
149
|
-
dependencies: 0,
|
|
150
|
-
warnings: 0,
|
|
151
|
-
errors: 1,
|
|
152
|
-
cssBytes: 0
|
|
153
|
-
}
|
|
154
|
-
};
|
|
155
|
-
}
|
|
99
|
+
directives: directiveEntries.length,
|
|
100
|
+
classNames: inspection.directives.classNames.length,
|
|
101
|
+
nativeClassNames: inspection.directives.nativeClassNames.length,
|
|
102
|
+
dependencies: inspection.dependencies.length,
|
|
103
|
+
warnings: inspection.warnings.length,
|
|
104
|
+
cssBytes: inspection.css.bytes
|
|
105
|
+
}
|
|
106
|
+
};
|
|
156
107
|
}
|
|
157
|
-
//#endregion
|
|
158
108
|
export { inspectDirectives };
|