@master/css-mcp 2.0.0-rc.76 → 2.0.0-rc.78

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.
@@ -0,0 +1,158 @@
1
+ import { createMCPTextDocument } from "./document.js";
2
+ import { getErrorMessage } from "./result.js";
3
+ import { summarizeManifest } from "./manifest-summary.js";
4
+ import { readFile } from "node:fs/promises";
5
+ import { basename } from "node:path";
6
+ import { collectCSSDirectiveRanges } from "@master/css-lexer";
7
+ import { compileCSSManifest, compileCSSManifestFile } from "@master/css-compiler";
8
+ //#region src/directives.ts
9
+ const DIRECTIVE_INSPECTION_VERSION = 1;
10
+ function createDirectiveEntries(content, filePath) {
11
+ const document = createMCPTextDocument(filePath, content);
12
+ return collectCSSDirectiveRanges(content).map((directive) => ({
13
+ name: directive.name,
14
+ range: {
15
+ start: directive.start,
16
+ end: directive.end
17
+ },
18
+ loc: {
19
+ start: document.positionAt(directive.start),
20
+ end: document.positionAt(directive.end)
21
+ },
22
+ prelude: content.slice(directive.preludeRange.start, directive.preludeRange.end).trim(),
23
+ hasBlock: Boolean(directive.blockRange),
24
+ quotedStrings: directive.quotedStringRanges.length
25
+ }));
26
+ }
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
+ atRules: countObjectKeys(manifestInput.atRules),
40
+ selectors: countObjectKeys(manifestInput.selectors),
41
+ animations: countObjectKeys(manifestInput.animations)
42
+ }
43
+ };
44
+ }
45
+ function summarizeCompileResult(result) {
46
+ const styleDefinitions = result.directives.styleDefinitions ?? [];
47
+ return {
48
+ manifest: summarizeManifest(result.manifest),
49
+ directives: {
50
+ manifestInput: summarizeManifestInput(result.directives.manifestInput),
51
+ classNames: result.classNames,
52
+ nativeClassNames: result.nativeClassNames,
53
+ styleDefinitions: styleDefinitions.length,
54
+ extractionPolicy: result.extractionPolicy
55
+ },
56
+ css: {
57
+ bytes: result.css.length,
58
+ nativeBytes: result.nativeCSS.length,
59
+ generatedBytes: result.generatedCSS.length
60
+ },
61
+ dependencies: result.dependencies,
62
+ warnings: result.warnings
63
+ };
64
+ }
65
+ async function compileDirectives(context, options) {
66
+ if (options.entryPath) {
67
+ const filePath = await context.resolveExistingFile(options.entryPath);
68
+ const [content, result] = await Promise.all([readFile(filePath, "utf8"), Promise.resolve(compileCSSManifestFile(filePath, {
69
+ root: context.root,
70
+ preserveNativeCSS: options.preserveNativeCSS
71
+ }))]);
72
+ return {
73
+ filePath,
74
+ content,
75
+ result
76
+ };
77
+ }
78
+ if (options.content === void 0) throw new Error("Either entryPath or content is required.");
79
+ const filePath = context.resolveVirtualPath(options.filePath || "master.css");
80
+ const result = compileCSSManifest(options.content, {
81
+ root: context.root,
82
+ from: filePath,
83
+ preserveNativeCSS: options.preserveNativeCSS
84
+ });
85
+ return {
86
+ filePath,
87
+ content: options.content,
88
+ result
89
+ };
90
+ }
91
+ async function inspectDirectives(context, options) {
92
+ try {
93
+ const compiled = await compileDirectives(context, options);
94
+ const inspection = summarizeCompileResult(compiled.result);
95
+ const directiveEntries = createDirectiveEntries(compiled.content, compiled.filePath);
96
+ return {
97
+ version: DIRECTIVE_INSPECTION_VERSION,
98
+ root: context.root,
99
+ status: inspection.warnings.length ? "warning" : "ok",
100
+ input: {
101
+ filePath: compiled.filePath,
102
+ name: basename(compiled.filePath),
103
+ mode: options.entryPath ? "entry" : "content"
104
+ },
105
+ directiveEntries,
106
+ ...inspection,
107
+ diagnostics: inspection.warnings.map((warning) => ({
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
+ }
156
+ }
157
+ //#endregion
158
+ export { inspectDirectives };
@@ -0,0 +1,25 @@
1
+ import { TextDocument } from "vscode-languageserver-textdocument";
2
+
3
+ //#region src/document.d.ts
4
+ interface Position {
5
+ line: number;
6
+ character: number;
7
+ }
8
+ interface Range {
9
+ start: Position;
10
+ end: Position;
11
+ }
12
+ interface TextEdit {
13
+ range: Range;
14
+ newText: string;
15
+ }
16
+ declare const languageByExtension: Record<string, string>;
17
+ declare function getLanguageId(filePath: string): string;
18
+ declare function createMCPTextDocument(filePath: string, content: string): TextDocument;
19
+ declare function toOffsetRange(document: TextDocument, range?: Range): {
20
+ start: number;
21
+ end: number;
22
+ } | undefined;
23
+ declare function applyTextEdits(content: string, document: TextDocument, edits: TextEdit[]): string;
24
+ //#endregion
25
+ export { Position, Range, TextEdit, applyTextEdits, createMCPTextDocument, getLanguageId, languageByExtension, toOffsetRange };
@@ -0,0 +1,51 @@
1
+ import { extname } from "node:path";
2
+ import { pathToFileURL } from "node:url";
3
+ import { TextDocument } from "vscode-languageserver-textdocument";
4
+ //#region src/document.ts
5
+ const languageByExtension = {
6
+ ".astro": "astro",
7
+ ".css": "css",
8
+ ".htm": "html",
9
+ ".html": "html",
10
+ ".js": "javascript",
11
+ ".jsx": "javascriptreact",
12
+ ".less": "less",
13
+ ".md": "markdown",
14
+ ".mdx": "mdx",
15
+ ".mjs": "javascript",
16
+ ".cjs": "javascript",
17
+ ".mts": "typescript",
18
+ ".cts": "typescript",
19
+ ".php": "php",
20
+ ".pug": "pug",
21
+ ".scss": "scss",
22
+ ".svelte": "svelte",
23
+ ".ts": "typescript",
24
+ ".tsx": "typescriptreact",
25
+ ".vue": "vue"
26
+ };
27
+ function getLanguageId(filePath) {
28
+ return languageByExtension[extname(filePath).toLowerCase()] || "html";
29
+ }
30
+ function createMCPTextDocument(filePath, content) {
31
+ return TextDocument.create(pathToFileURL(filePath).href, getLanguageId(filePath), 0, content);
32
+ }
33
+ function toOffsetRange(document, range) {
34
+ if (!range) return;
35
+ return {
36
+ start: document.offsetAt(range.start),
37
+ end: document.offsetAt(range.end)
38
+ };
39
+ }
40
+ function applyTextEdits(content, document, edits) {
41
+ let result = content;
42
+ const offsetEdits = edits.map((edit) => ({
43
+ start: document.offsetAt(edit.range.start),
44
+ end: document.offsetAt(edit.range.end),
45
+ newText: edit.newText
46
+ }));
47
+ for (const edit of offsetEdits.sort((a, b) => b.start - a.start || b.end - a.end)) result = result.slice(0, edit.start) + edit.newText + result.slice(edit.end);
48
+ return result;
49
+ }
50
+ //#endregion
51
+ export { applyTextEdits, createMCPTextDocument, getLanguageId, languageByExtension, toOffsetRange };
@@ -0,0 +1,57 @@
1
+ import MasterCSSMCPContext from "./context.js";
2
+ import { Range, TextEdit } from "./document.js";
3
+
4
+ //#region src/format.d.ts
5
+ interface PreviewDirectiveFormatOptions {
6
+ content?: string;
7
+ filePath?: string;
8
+ patterns?: string[];
9
+ range?: Range;
10
+ ttlMs?: number;
11
+ }
12
+ declare function previewDirectiveFormat(context: MasterCSSMCPContext, options?: PreviewDirectiveFormatOptions): Promise<{
13
+ version: number;
14
+ root: string;
15
+ mode: string;
16
+ files: {
17
+ filePath: string;
18
+ languageId: string;
19
+ edits: TextEdit[];
20
+ changed: boolean;
21
+ beforeBytes: number;
22
+ afterBytes: number;
23
+ }[];
24
+ formatted: string;
25
+ summary: {
26
+ files: number;
27
+ changed: number;
28
+ edits: number;
29
+ };
30
+ inputs?: undefined;
31
+ preview?: undefined;
32
+ } | {
33
+ version: number;
34
+ root: string;
35
+ mode: string;
36
+ inputs: {
37
+ patterns: string[];
38
+ files: string[];
39
+ };
40
+ preview: import("./context.js").PreviewResult;
41
+ files: {
42
+ filePath: string;
43
+ languageId: string;
44
+ edits: TextEdit[];
45
+ changed: boolean;
46
+ beforeBytes: number;
47
+ afterBytes: number;
48
+ }[];
49
+ summary: {
50
+ files: number;
51
+ changed: number;
52
+ edits: number;
53
+ };
54
+ formatted?: undefined;
55
+ }>;
56
+ //#endregion
57
+ export { PreviewDirectiveFormatOptions, previewDirectiveFormat };
package/dist/format.js ADDED
@@ -0,0 +1,81 @@
1
+ import { applyTextEdits, createMCPTextDocument, getLanguageId } from "./document.js";
2
+ import { resolveSourceFiles } from "./scan.js";
3
+ import { readFile } from "node:fs/promises";
4
+ import CSSLanguageService from "@master/css-language-service";
5
+ //#region src/format.ts
6
+ const DIRECTIVE_FORMAT_PREVIEW_VERSION = 1;
7
+ const DEFAULT_DIRECTIVE_FORMAT_PATTERNS = ["**/*.{css,scss,less,vue,svelte,astro}"];
8
+ function formatContent(service, filePath, content, range) {
9
+ const document = createMCPTextDocument(filePath, content);
10
+ const edits = service.formatDirectives(document, range) ?? [];
11
+ const formatted = applyTextEdits(content, document, edits);
12
+ return {
13
+ filePath,
14
+ languageId: getLanguageId(filePath),
15
+ edits,
16
+ changed: formatted !== content,
17
+ beforeBytes: content.length,
18
+ afterBytes: formatted.length,
19
+ formatted
20
+ };
21
+ }
22
+ async function previewDirectiveFormat(context, options = {}) {
23
+ const service = new CSSLanguageService();
24
+ if (options.content !== void 0) {
25
+ const filePath = context.resolveVirtualPath(options.filePath || "master.css");
26
+ const formatted = formatContent(service, filePath, options.content, options.range);
27
+ return {
28
+ version: DIRECTIVE_FORMAT_PREVIEW_VERSION,
29
+ root: context.root,
30
+ mode: "content",
31
+ files: [{
32
+ filePath,
33
+ languageId: formatted.languageId,
34
+ edits: formatted.edits,
35
+ changed: formatted.changed,
36
+ beforeBytes: formatted.beforeBytes,
37
+ afterBytes: formatted.afterBytes
38
+ }],
39
+ formatted: formatted.formatted,
40
+ summary: {
41
+ files: 1,
42
+ changed: formatted.changed ? 1 : 0,
43
+ edits: formatted.edits.length
44
+ }
45
+ };
46
+ }
47
+ const files = await resolveSourceFiles(context, options.patterns ?? DEFAULT_DIRECTIVE_FORMAT_PATTERNS);
48
+ const formattedFiles = await Promise.all(files.map(async (filePath) => {
49
+ return formatContent(service, filePath, await readFile(filePath, "utf8"), options.range);
50
+ }));
51
+ const preview = await context.createPreview(formattedFiles.filter((file) => file.changed).map((file) => ({
52
+ filePath: file.filePath,
53
+ beforeText: void 0,
54
+ afterText: file.formatted
55
+ })), options.ttlMs);
56
+ return {
57
+ version: DIRECTIVE_FORMAT_PREVIEW_VERSION,
58
+ root: context.root,
59
+ mode: "files",
60
+ inputs: {
61
+ patterns: options.patterns ?? DEFAULT_DIRECTIVE_FORMAT_PATTERNS,
62
+ files
63
+ },
64
+ preview,
65
+ files: formattedFiles.map((file) => ({
66
+ filePath: file.filePath,
67
+ languageId: file.languageId,
68
+ edits: file.edits,
69
+ changed: file.changed,
70
+ beforeBytes: file.beforeBytes,
71
+ afterBytes: file.afterBytes
72
+ })),
73
+ summary: {
74
+ files: formattedFiles.length,
75
+ changed: formattedFiles.filter((file) => file.changed).length,
76
+ edits: formattedFiles.reduce((count, file) => count + file.edits.length, 0)
77
+ }
78
+ };
79
+ }
80
+ //#endregion
81
+ export { previewDirectiveFormat };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import { MasterCSSMCPServerInstance, createMasterCSSMCPServer, startStdioServer } from "./server.js";
2
1
  import MasterCSSMCPContext, { MasterCSSMCPContextOptions } from "./context.js";
2
+ import { MasterCSSMCPServerInstance, createMasterCSSMCPServer, startStdioServer } from "./server.js";
3
3
  export { MasterCSSMCPContext, type MasterCSSMCPContextOptions, type MasterCSSMCPServerInstance, createMasterCSSMCPServer, startStdioServer };
package/dist/language.js CHANGED
@@ -1,30 +1,12 @@
1
+ import { createMCPTextDocument } from "./document.js";
1
2
  import { loadWorkspaceManifest } from "./project.js";
2
- import { extname } from "node:path";
3
- import { pathToFileURL } from "node:url";
4
3
  import CSSLanguageService from "@master/css-language-service";
5
- import { TextDocument } from "vscode-languageserver-textdocument";
6
4
  //#region src/language.ts
7
- const languageByExtension = {
8
- ".astro": "astro",
9
- ".css": "css",
10
- ".htm": "html",
11
- ".html": "html",
12
- ".js": "javascript",
13
- ".jsx": "javascriptreact",
14
- ".less": "less",
15
- ".md": "markdown",
16
- ".mdx": "mdx",
17
- ".scss": "scss",
18
- ".svelte": "svelte",
19
- ".ts": "typescript",
20
- ".tsx": "typescriptreact",
21
- ".vue": "vue"
22
- };
23
5
  async function suggestSyntax(context, options) {
24
6
  const filePath = context.resolveVirtualPath(options.filePath);
25
7
  const manifest = await loadWorkspaceManifest(context);
26
8
  const service = new CSSLanguageService(manifest.status === "loaded" ? { manifest: manifest.manifest } : void 0);
27
- const document = TextDocument.create(pathToFileURL(filePath).href, languageByExtension[extname(filePath).toLowerCase()] || "html", 0, options.content);
9
+ const document = createMCPTextDocument(filePath, options.content);
28
10
  const completions = service.suggestSyntax(document, options.position, {
29
11
  triggerKind: options.triggerCharacter ? 2 : 1,
30
12
  ...options.triggerCharacter ? { triggerCharacter: options.triggerCharacter } : {}
@@ -0,0 +1,149 @@
1
+ import MasterCSSMCPContext from "./context.js";
2
+
3
+ //#region src/manifest-query.d.ts
4
+ type ManifestQueryKind = 'all' | 'token' | 'utility' | 'variant' | 'mode' | 'at-rule' | 'alias';
5
+ interface ManifestQueryOptions {
6
+ query?: string;
7
+ kind?: ManifestQueryKind;
8
+ namespace?: string;
9
+ limit?: number;
10
+ }
11
+ declare function queryManifest(context: MasterCSSMCPContext, options?: ManifestQueryOptions): Promise<{
12
+ version: number;
13
+ root: string;
14
+ manifest: {
15
+ status: "error";
16
+ entries: string[];
17
+ error: string;
18
+ summary?: undefined;
19
+ };
20
+ inputs: {
21
+ query: string | undefined;
22
+ kind: ManifestQueryKind;
23
+ namespace: string | undefined;
24
+ limit: number;
25
+ };
26
+ results: {
27
+ tokens: never[];
28
+ utilities: never[];
29
+ variants: never[];
30
+ modes: never[];
31
+ atRules: never[];
32
+ aliases: never[];
33
+ };
34
+ diagnostics: {
35
+ code: string;
36
+ severity: "error";
37
+ message: string;
38
+ source: string;
39
+ sourceKind: string;
40
+ }[];
41
+ summary: {
42
+ total: number;
43
+ returned: number;
44
+ status: string;
45
+ tokens?: undefined;
46
+ utilities?: undefined;
47
+ variants?: undefined;
48
+ modes?: undefined;
49
+ atRules?: undefined;
50
+ aliases?: undefined;
51
+ };
52
+ } | {
53
+ version: number;
54
+ root: string;
55
+ manifest: {
56
+ status: "loaded";
57
+ entries: string[];
58
+ summary: {
59
+ settings: import("@master/css-engine").MasterCSSManifestSettings;
60
+ counts: {
61
+ variables: number;
62
+ variableNamespaces: number;
63
+ utilities: number;
64
+ variants: number;
65
+ atRules: number;
66
+ breakpointAtRules: number;
67
+ containerAtRules: number;
68
+ selectors: number;
69
+ animations: number;
70
+ };
71
+ };
72
+ error?: undefined;
73
+ };
74
+ inputs: {
75
+ query: string | undefined;
76
+ kind: ManifestQueryKind;
77
+ namespace: string | undefined;
78
+ limit: number;
79
+ };
80
+ results: {
81
+ tokens: {
82
+ static?: boolean | undefined;
83
+ inline?: boolean | undefined;
84
+ modes?: string[] | undefined;
85
+ numeric?: import("@master/css-engine").MasterCSSManifestVariableNumericValue | undefined;
86
+ name: string;
87
+ key: string;
88
+ namespace: string;
89
+ type: "string" | "number";
90
+ value: import("@master/css-engine").MasterCSSManifestVariableValue | undefined;
91
+ }[];
92
+ utilities: {
93
+ variableAliasRefs?: string[] | undefined;
94
+ aliasGroups?: string[] | undefined;
95
+ layer: import("@master/css-engine").MasterCSSManifestUtilityLayerName | undefined;
96
+ matcherTypes: ("static" | "pattern" | "key" | "variable" | "value")[];
97
+ emitType: "static" | "declarations" | "template" | "property";
98
+ namespaces?: string[] | undefined;
99
+ keys?: string[] | undefined;
100
+ subkey?: string | undefined;
101
+ key?: string | undefined;
102
+ name?: string | undefined;
103
+ id: string;
104
+ }[];
105
+ variants: {
106
+ token: import("@master/css-engine").MasterCSSManifestVariantToken;
107
+ branches: number;
108
+ layers: (import("@master/css-engine").MasterCSSManifestUtilityLayerName | undefined)[];
109
+ }[];
110
+ modes: {
111
+ name: string;
112
+ default: boolean;
113
+ trigger: import("@master/css-engine").MasterCSSManifestModeTrigger | undefined;
114
+ }[];
115
+ atRules: {
116
+ name: string;
117
+ id: import("@master/css-engine").MasterCSSManifestAtIdentifier;
118
+ nodes: number;
119
+ }[];
120
+ aliases: ({
121
+ utility: string;
122
+ key: string;
123
+ name: string;
124
+ type: "variable-alias";
125
+ } | {
126
+ utility: string;
127
+ ref: string;
128
+ type: "variable-alias-ref";
129
+ } | {
130
+ utility: string;
131
+ group: string;
132
+ type: "alias-group";
133
+ })[];
134
+ };
135
+ summary: {
136
+ total: number;
137
+ returned: number;
138
+ tokens: number;
139
+ utilities: number;
140
+ variants: number;
141
+ modes: number;
142
+ atRules: number;
143
+ aliases: number;
144
+ status: string;
145
+ };
146
+ diagnostics?: undefined;
147
+ }>;
148
+ //#endregion
149
+ export { ManifestQueryKind, ManifestQueryOptions, queryManifest };