@master/css-language-service 0.0.0-site.1793659883.g69c9aebcf628

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.
Files changed (44) hide show
  1. package/README.md +131 -0
  2. package/dist/common.d.ts +2 -0
  3. package/dist/common.js +1 -0
  4. package/dist/core.d.ts +34 -0
  5. package/dist/core.js +81 -0
  6. package/dist/document-analysis.d.ts +16 -0
  7. package/dist/document-analysis.js +34 -0
  8. package/dist/features/edit-syntax-colors.d.ts +5 -0
  9. package/dist/features/edit-syntax-colors.js +36 -0
  10. package/dist/features/format-directives.d.ts +5 -0
  11. package/dist/features/format-directives.js +60 -0
  12. package/dist/features/inspect-syntax.d.ts +5 -0
  13. package/dist/features/inspect-syntax.js +48 -0
  14. package/dist/features/render-semantic-tokens.d.ts +6 -0
  15. package/dist/features/render-semantic-tokens.js +36 -0
  16. package/dist/features/render-syntax-colors.d.ts +5 -0
  17. package/dist/features/render-syntax-colors.js +47 -0
  18. package/dist/features/suggest-syntax.d.ts +5 -0
  19. package/dist/features/suggest-syntax.js +165 -0
  20. package/dist/index.d.ts +8 -0
  21. package/dist/index.js +8 -0
  22. package/dist/settings.d.ts +21 -0
  23. package/dist/settings.js +64 -0
  24. package/dist/shiki/hast.d.ts +13 -0
  25. package/dist/shiki/hast.js +174 -0
  26. package/dist/shiki/languages.d.ts +8 -0
  27. package/dist/shiki/languages.js +69 -0
  28. package/dist/shiki.d.ts +159 -0
  29. package/dist/shiki.js +522 -0
  30. package/dist/utils/beautify-css.d.ts +2 -0
  31. package/dist/utils/beautify-css.js +12 -0
  32. package/dist/utils/convert-color-token.d.ts +4 -0
  33. package/dist/utils/convert-color-token.js +31 -0
  34. package/dist/utils/create-css-markdown-documentation.d.ts +6 -0
  35. package/dist/utils/create-css-markdown-documentation.js +12 -0
  36. package/dist/utils/create-doc.d.ts +17 -0
  37. package/dist/utils/create-doc.js +20 -0
  38. package/dist/utils/get-position.d.ts +2 -0
  39. package/dist/utils/get-position.js +8 -0
  40. package/dist/utils/get-range.d.ts +3 -0
  41. package/dist/utils/get-range.js +20 -0
  42. package/package.json +60 -0
  43. package/src/shiki.css +7 -0
  44. package/syntaxes/master-css.tmLanguage.json +881 -0
package/README.md ADDED
@@ -0,0 +1,131 @@
1
+ <br>
2
+ <div align="center">
3
+
4
+ <p align="center">
5
+ <a href="https://css.master.co">
6
+ <picture>
7
+ <source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/33840671/201701649-3bb7d698-abec-4d5f-ac30-ccc4d7bafcd4.svg">
8
+ <source media="(prefers-color-scheme: light)" srcset="https://user-images.githubusercontent.com/33840671/201703010-77bf2373-9899-40cc-98f5-30cf9b546941.svg">
9
+ <img alt="Master CSS" src="https://user-images.githubusercontent.com/33840671/201703010-77bf2373-9899-40cc-98f5-30cf9b546941.svg" width="100%">
10
+ </picture>
11
+ </a>
12
+ </p>
13
+ <p align="center">Language Service for Master CSS</p>
14
+
15
+ <p align="center">
16
+ <a aria-label="GitHub release (latest by date including pre-releases)" href="https://github.com/master-co/css/releases">
17
+ <picture>
18
+ <source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/github/v/release/master-co/css?include_prereleases&color=212022&label=&style=for-the-badge&logo=github&logoColor=fff">
19
+ <source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/github/v/release/master-co/css?include_prereleases&color=f6f7f8&label=&style=for-the-badge&logo=github&logoColor=%23000">
20
+ <img alt="NPM Version" src="https://img.shields.io/github/v/release/master-co/css?include_prereleases&color=f6f7f8&label=&style=for-the-badge&logo=github">
21
+ </picture>
22
+ </a>
23
+ <a aria-label="NPM Package" href="https://www.npmjs.com/package/@master/css-language-service">
24
+ <picture>
25
+ <source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/npm/dm/@master/css-language-service?color=212022&label=%20&logo=npm&style=for-the-badge">
26
+ <source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/npm/dm/@master/css-language-service?color=f6f7f8&label=%20&logo=npm&style=for-the-badge">
27
+ <img alt="NPM package ( download / month )" src="https://img.shields.io/npm/dm/@master/css-language-service?color=f6f7f8&label=%20&logo=npm&style=for-the-badge">
28
+ </picture>
29
+ </a>
30
+ <a aria-label="JSDelivr" href="https://www.jsdelivr.com/package/npm/@master/css-language-service">
31
+ <picture>
32
+ <source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/jsdelivr/npm/hm/@master/css-language-service?color=212022&label=%20&logo=jsdelivr&style=for-the-badge">
33
+ <source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/jsdelivr/npm/hm/@master/css-language-service?color=f6f7f8&label=%20&logo=jsdelivr&style=for-the-badge">
34
+ <img alt="JSDelivr hits (npm scoped)" src="https://img.shields.io/jsdelivr/npm/hm/@master/css-language-service?color=f6f7f8&label=%20&logo=jsdelivr&style=for-the-badge">
35
+ </picture>
36
+ </a>
37
+ <a aria-label="Discord Community" href="https://discord.gg/sZNKpAAAw6">
38
+ <picture>
39
+ <source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/discord/917780624314613760?color=212022&label=%20&logo=discord&style=for-the-badge">
40
+ <source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/discord/917780624314613760?color=f6f7f8&label=%20&logo=discord&style=for-the-badge">
41
+ <img alt="Discord online" src="https://img.shields.io/discord/917780624314613760?color=f6f7f8&label=%20&logo=discord&style=for-the-badge">
42
+ </picture>
43
+ </a>
44
+ <a aria-label="Follow @mastercorg" href="https://twitter.com/mastercorg">
45
+ <picture>
46
+ <source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/static/v1?label=%20&message=twitter&color=212022&logo=twitter&style=for-the-badge">
47
+ <source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/static/v1?label=%20&message=twitter&color=f6f7f8&logo=twitter&style=for-the-badge">
48
+ <img alt="Follow @mastercorg" src="https://img.shields.io/static/v1?label=%20&message=twitter&color=f6f7f8&logo=twitter&style=for-the-badge">
49
+ </picture>
50
+ </a>
51
+ <a aria-label="Github Actions" href="https://github.com/master-co/css/actions/workflows/ci-release.yml">
52
+ <picture>
53
+ <source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/github/actions/workflow/status/master-co/css/ci-release.yml?branch=rc&label=%20&message=twitter&color=212022&logo=githubactions&style=for-the-badge">
54
+ <source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/github/actions/workflow/status/master-co/css/ci-release.yml?branch=rc&label=%20&message=twitter&color=f6f7f8&logo=githubactions&style=for-the-badge&logoColor=%23000">
55
+ <img alt="Github release actions" src="https://img.shields.io/github/actions/workflow/status/master-co/css/ci-release.yml?branch=rc&label=%20&message=twitter&color=f6f7f8&logo=githubactions&style=for-the-badge&logoColor=%23000">
56
+ </picture>
57
+ </a>
58
+ </p>
59
+
60
+ </div>
61
+
62
+ ## Installation
63
+
64
+ ```bash
65
+ npm install @master/css-language-service
66
+ ```
67
+
68
+ ## Usage
69
+
70
+ ```js
71
+ import { MasterCSSLanguageService } from '@master/css-language-service'
72
+ import { createToolingSession } from '@master/css-tooling'
73
+
74
+ const session = await createToolingSession({ manifest })
75
+ const languageService = new MasterCSSLanguageService(customSettings, { session })
76
+ ```
77
+
78
+ `MasterCSSLanguageService` provides stateful completion, hover, color, color presentation, and semantic token features around one manifest-scoped tooling session. Dispose the service when the editor workspace closes.
79
+
80
+ ### Semantic tokens
81
+
82
+ ```ts
83
+ const semanticTokens = languageService.renderSemanticTokens(textDocument)
84
+ ```
85
+
86
+ Semantic tokens are generated with the project manifest, so project tokens, utility definitions, and other manifest-dependent syntax can be classified after the caller loads the manifest.
87
+
88
+ Use `renderSemanticTokensAtPosition()` when a client wants active-only highlighting for the embedded class context at the current editor position.
89
+
90
+ ```ts
91
+ const semanticTokens = languageService.renderSemanticTokensAtPosition(textDocument, position)
92
+ ```
93
+
94
+ CSS directive syntax in CSS-family documents is highlighted by the shared TextMate grammar. Semantic tokens are only added for directive class-list spans such as quoted `@safelist` strings.
95
+
96
+ ### Directive formatting
97
+
98
+ ```ts
99
+ const edits = languageService.formatDirectives(textDocument)
100
+ ```
101
+
102
+ Directive formatting returns LSP text edits for Master CSS directive source. It supports CSS, SCSS, and LESS documents, plus CSS-family `<style>` blocks in Vue, Svelte, and Astro documents. The formatter repairs directive class-list important markers such as `(background-color:transparent) !` to `(background-color:transparent)!` and does not change compiler semantics or generated CSS.
103
+
104
+ Pass an LSP range as the second argument for range formatting:
105
+
106
+ ```ts
107
+ const edits = languageService.formatDirectives(textDocument, range)
108
+ ```
109
+
110
+ ## Settings
111
+
112
+ ```js
113
+ import { defaultLanguageServiceSettings } from '@master/css-language-service'
114
+ ```
115
+
116
+ | Setting | Type | Default | Description |
117
+ | --- | --- | --- | --- |
118
+ | `includedLanguages` | `string[]` | Common web and template languages | Language IDs that receive language-service features. |
119
+ | `exclude` | `string[]` | `["**/.git/**", "**/node_modules/**", "**/.hg/**"]` | Glob patterns excluded from all features. |
120
+ | `classAttributes` | `string[]` | `["class", "className"]` | Quoted markup attributes that contain Master CSS class strings. |
121
+ | `classAttributeBindings` | `Record<string, [string, string] \| false>` | Framework binding defaults | Bound attributes such as `:class`, `[ngClass]`, and `class:list`. |
122
+ | `classFunctions` | `string[]` | Common class helpers | Functions and methods whose string arguments contain classes, such as `clsx()` and `classList.add()`. |
123
+ | `classDeclarations` | `string[]` | `[]` | Variable declarations or object properties whose string values contain classes. |
124
+ | `suggestSyntax` | `boolean` | `true` | Enables syntax suggestions. |
125
+ | `inspectSyntax` | `boolean` | `true` | Enables hover inspection and generated CSS previews. |
126
+ | `renderSyntaxColors` | `boolean` | `true` | Enables color rendering. |
127
+ | `editSyntaxColors` | `boolean` | `true` | Enables color editing. |
128
+ | `formatDirectives` | `boolean` | `true` | Enables Master CSS directive formatting. |
129
+ | `embeddedSyntaxHighlighting` | `'active' \| 'always' \| 'off'` | `'active'` | Controls embedded semantic token highlighting. |
130
+
131
+ Use `@master/css-tooling/language` directly for browser helpers, Shiki integration, TextMate grammar assets, and raw class-position scanning.
@@ -0,0 +1,2 @@
1
+ import { AT_TRIGGER_CHARACTER, INVOKED_TRIGGER_CHARACTERS, QUERY_TRIGGER_CHARACTERS, SELECTOR_TRIGGER_CHARACTERS, VALUE_TRIGGER_CHARACTERS } from "@master/css-tooling/language";
2
+ export { AT_TRIGGER_CHARACTER, INVOKED_TRIGGER_CHARACTERS, QUERY_TRIGGER_CHARACTERS, SELECTOR_TRIGGER_CHARACTERS, VALUE_TRIGGER_CHARACTERS };
package/dist/common.js ADDED
@@ -0,0 +1 @@
1
+ export { AT_TRIGGER_CHARACTER, INVOKED_TRIGGER_CHARACTERS, QUERY_TRIGGER_CHARACTERS, SELECTOR_TRIGGER_CHARACTERS, VALUE_TRIGGER_CHARACTERS } from "@master/css-tooling/language";
package/dist/core.d.ts ADDED
@@ -0,0 +1,34 @@
1
+ import { Position } from "vscode-languageserver-protocol";
2
+ import { TextDocument } from "vscode-languageserver-textdocument";
3
+ import { MasterCSSLanguageClassPosition, MasterCSSToolingSession } from "@master/css-tooling";
4
+ import { MasterCSSLanguageServiceSettings } from "./settings.js";
5
+ import inspectSyntax from "./features/inspect-syntax.js";
6
+ import renderSyntaxColors from "./features/render-syntax-colors.js";
7
+ import editSyntaxColors from "./features/edit-syntax-colors.js";
8
+ import formatDirectives from "./features/format-directives.js";
9
+ import renderSemanticTokens, { renderSemanticTokensAtPosition } from "./features/render-semantic-tokens.js";
10
+ import suggestSyntax from "./features/suggest-syntax.js";
11
+ interface MasterCSSLanguageServiceOptions {
12
+ session: MasterCSSToolingSession;
13
+ }
14
+ declare class MasterCSSLanguageService implements Disposable {
15
+ customSettings: MasterCSSLanguageServiceSettings | undefined;
16
+ readonly settings: MasterCSSLanguageServiceSettings;
17
+ readonly session: MasterCSSToolingSession;
18
+ constructor(customSettings: MasterCSSLanguageServiceSettings | undefined, options: MasterCSSLanguageServiceOptions);
19
+ dispose(): void;
20
+ [Symbol.dispose](): void;
21
+ inspectSyntax(...params: Parameters<typeof inspectSyntax>): import("vscode-languageserver-types").Hover | undefined;
22
+ renderSyntaxColors(...params: Parameters<typeof renderSyntaxColors>): Promise<import("vscode-languageserver-types").ColorInformation[]> | undefined;
23
+ editSyntaxColors(...params: Parameters<typeof editSyntaxColors>): import("vscode-languageserver-types").ColorPresentation[] | undefined;
24
+ formatDirectives(...params: Parameters<typeof formatDirectives>): import("vscode-languageserver-types").TextEdit[] | undefined;
25
+ renderSemanticTokens(...params: Parameters<typeof renderSemanticTokens>): import("vscode-languageserver-types").SemanticTokens | undefined;
26
+ renderSemanticTokensAtPosition(...params: Parameters<typeof renderSemanticTokensAtPosition>): import("vscode-languageserver-types").SemanticTokens | undefined;
27
+ suggestSyntax(...params: Parameters<typeof suggestSyntax>): import("vscode-languageserver-types").CompletionItem[] | undefined;
28
+ getClassPositions(document: TextDocument): MasterCSSLanguageClassPosition[];
29
+ getClassPosition(document: TextDocument, position: Position): MasterCSSLanguageClassPosition | undefined;
30
+ getClassContextPositions(document: TextDocument, position: Position): MasterCSSLanguageClassPosition[];
31
+ private analyzeDocumentClassPositions;
32
+ isDocumentAccepted(document: TextDocument): boolean;
33
+ }
34
+ export { MasterCSSLanguageService, MasterCSSLanguageServiceOptions };
package/dist/core.js ADDED
@@ -0,0 +1,81 @@
1
+ import { analyzeDocument, clearDocumentAnalyses } from "./document-analysis.js";
2
+ import { defaultLanguageServiceSettings } from "./settings.js";
3
+ import inspectSyntax from "./features/inspect-syntax.js";
4
+ import renderSyntaxColors from "./features/render-syntax-colors.js";
5
+ import editSyntaxColors from "./features/edit-syntax-colors.js";
6
+ import formatDirectives from "./features/format-directives.js";
7
+ import renderSemanticTokens, { renderSemanticTokensAtPosition } from "./features/render-semantic-tokens.js";
8
+ import suggestSyntax from "./features/suggest-syntax.js";
9
+ import { defu } from "defu";
10
+ import { minimatch } from "minimatch";
11
+ // src/core.ts
12
+ var MasterCSSLanguageService = class {
13
+ customSettings;
14
+ settings;
15
+ session;
16
+ constructor(customSettings, options) {
17
+ this.customSettings = customSettings;
18
+ if (!options?.session) throw new TypeError("MasterCSSLanguageService requires a MasterCSSToolingSession.");
19
+ this.settings = defu(customSettings, defaultLanguageServiceSettings);
20
+ this.session = options.session;
21
+ }
22
+ dispose() {
23
+ clearDocumentAnalyses(this);
24
+ this.session.dispose();
25
+ }
26
+ [Symbol.dispose]() {
27
+ this.dispose();
28
+ }
29
+ inspectSyntax(...params) {
30
+ if (this.settings.inspectSyntax && this.isDocumentAccepted(params[0])) return inspectSyntax.call(this, ...params);
31
+ }
32
+ renderSyntaxColors(...params) {
33
+ if (this.settings.renderSyntaxColors && this.isDocumentAccepted(params[0])) return renderSyntaxColors.call(this, ...params);
34
+ }
35
+ editSyntaxColors(...params) {
36
+ if (this.settings.editSyntaxColors && this.isDocumentAccepted(params[0])) return editSyntaxColors.call(this, ...params);
37
+ }
38
+ formatDirectives(...params) {
39
+ if (this.settings.formatDirectives && this.isDocumentAccepted(params[0])) return formatDirectives.call(this, ...params);
40
+ }
41
+ renderSemanticTokens(...params) {
42
+ if (this.isDocumentAccepted(params[0])) return renderSemanticTokens.call(this, ...params);
43
+ }
44
+ renderSemanticTokensAtPosition(...params) {
45
+ if (this.isDocumentAccepted(params[0])) return renderSemanticTokensAtPosition.call(this, ...params);
46
+ }
47
+ suggestSyntax(...params) {
48
+ if (this.settings.suggestSyntax && this.isDocumentAccepted(params[0])) return suggestSyntax.call(this, ...params);
49
+ }
50
+ getClassPositions(document) {
51
+ return this.analyzeDocumentClassPositions(document);
52
+ }
53
+ getClassPosition(document, position) {
54
+ const offset = document.offsetAt(position);
55
+ const classPositions = this.analyzeDocumentClassPositions(document);
56
+ const exact = classPositions.filter(({ range }) => offset >= range.start && offset <= range.end).sort((left, right) => left.range.end - left.range.start - (right.range.end - right.range.start))[0];
57
+ if (exact) return exact;
58
+ const context = classPositions.find(({ contextRange }) => offset >= contextRange.start && offset <= contextRange.end);
59
+ const source = document.getText();
60
+ if (context && (offset === context.contextRange.start || /\s/u.test(source[offset - 1] || ""))) return {
61
+ range: {
62
+ start: offset,
63
+ end: offset
64
+ },
65
+ contextRange: context.contextRange,
66
+ raw: "",
67
+ token: ""
68
+ };
69
+ }
70
+ getClassContextPositions(document, position) {
71
+ const offset = document.offsetAt(position);
72
+ return this.analyzeDocumentClassPositions(document).filter(({ contextRange }) => offset >= contextRange.start && offset <= contextRange.end);
73
+ }
74
+ analyzeDocumentClassPositions(document) {
75
+ return [...analyzeDocument(this, document).classPositions];
76
+ }
77
+ isDocumentAccepted(document) {
78
+ return !this.settings.exclude?.some((pattern) => minimatch(document.uri, pattern));
79
+ }
80
+ };
81
+ export { MasterCSSLanguageService };
@@ -0,0 +1,16 @@
1
+ import { MasterCSSDocumentAnalysis } from "@master/css-tooling/language";
2
+ import { TextDocument } from "vscode-languageserver-textdocument";
3
+ import { MasterCSSLanguageService } from "./core.js";
4
+ declare function clearDocumentAnalyses(service: MasterCSSLanguageService): void;
5
+ /** The Rust document request for a document under the service's class settings. */
6
+ declare function documentRequest(service: MasterCSSLanguageService, document: TextDocument): {
7
+ source: string;
8
+ languageId: string;
9
+ settings: {
10
+ classAttributes: string[] | undefined;
11
+ classFunctions: string[] | undefined;
12
+ classDeclarations: string[] | undefined;
13
+ };
14
+ };
15
+ declare function analyzeDocument(service: MasterCSSLanguageService, document: TextDocument): MasterCSSDocumentAnalysis;
16
+ export { analyzeDocument, clearDocumentAnalyses, documentRequest };
@@ -0,0 +1,34 @@
1
+ // src/document-analysis.ts
2
+ const documents = /* @__PURE__ */ new WeakMap();
3
+ function clearDocumentAnalyses(service) {
4
+ documents.delete(service);
5
+ }
6
+ /** The Rust document request for a document under the service's class settings. */
7
+ function documentRequest(service, document) {
8
+ return {
9
+ source: document.getText(),
10
+ languageId: document.languageId,
11
+ settings: {
12
+ classAttributes: service.settings.classAttributes,
13
+ classFunctions: service.settings.classFunctions,
14
+ classDeclarations: service.settings.classDeclarations
15
+ }
16
+ };
17
+ }
18
+ function analyzeDocument(service, document) {
19
+ const request = documentRequest(service, document);
20
+ const settingsKey = JSON.stringify(request.settings);
21
+ let cache = documents.get(service);
22
+ const cached = cache?.get(document);
23
+ if (cached && cached.version === document.version && cached.languageId === document.languageId && cached.settingsKey === settingsKey) return cached.result;
24
+ const result = service.session.analyzeDocument(request);
25
+ if (!cache) documents.set(service, cache = /* @__PURE__ */ new WeakMap());
26
+ cache.set(document, {
27
+ version: document.version,
28
+ languageId: document.languageId,
29
+ settingsKey,
30
+ result
31
+ });
32
+ return result;
33
+ }
34
+ export { analyzeDocument, clearDocumentAnalyses, documentRequest };
@@ -0,0 +1,5 @@
1
+ import { ColorPresentation, ColorPresentationParams } from "vscode-languageserver-protocol";
2
+ import { TextDocument } from "vscode-languageserver-textdocument";
3
+ import { MasterCSSLanguageService } from "../core.js";
4
+ declare function editSyntaxColors(this: MasterCSSLanguageService, document: TextDocument, color: ColorPresentationParams['color'], range: ColorPresentationParams['range']): ColorPresentation[];
5
+ export { editSyntaxColors as default };
@@ -0,0 +1,36 @@
1
+ import { convertColorInFormat } from "../utils/convert-color-token.js";
2
+ // src/features/edit-syntax-colors.ts
3
+ const commonFormats = [
4
+ { syntax: "hex" },
5
+ { syntax: "rgb" },
6
+ { syntax: "hsl" },
7
+ { syntax: "oklch" }
8
+ ];
9
+ function editSyntaxColors(document, color, range) {
10
+ const selectedColorToken = document.getText(range);
11
+ const rustPresentation = this.session.colorPresentation(selectedColorToken);
12
+ if (!rustPresentation.editable) return [];
13
+ const formats = rustPresentation.sourceFormat ? [rustPresentation.sourceFormat, ...commonFormats] : [...commonFormats];
14
+ const colorPresentations = [];
15
+ const formatKeys = /* @__PURE__ */ new Set();
16
+ const tokens = /* @__PURE__ */ new Set();
17
+ for (const format of formats) {
18
+ const formatKey = `${format.syntax}:${format.space || ""}`;
19
+ if (formatKeys.has(formatKey)) continue;
20
+ formatKeys.add(formatKey);
21
+ try {
22
+ const targetColorToken = convertColorInFormat(color, format);
23
+ if (tokens.has(targetColorToken)) continue;
24
+ tokens.add(targetColorToken);
25
+ colorPresentations.push({
26
+ label: targetColorToken,
27
+ textEdit: {
28
+ range,
29
+ newText: (rustPresentation.replacementPrefix || "") + targetColorToken + (rustPresentation.replacementSuffix || "")
30
+ }
31
+ });
32
+ } catch {}
33
+ }
34
+ return colorPresentations;
35
+ }
36
+ export { editSyntaxColors as default };
@@ -0,0 +1,5 @@
1
+ import { Range, TextEdit } from "vscode-languageserver-protocol";
2
+ import { TextDocument } from "vscode-languageserver-textdocument";
3
+ import { MasterCSSLanguageService } from "../core.js";
4
+ declare function formatDirectives(this: MasterCSSLanguageService, document: TextDocument, range?: Range): TextEdit[] | undefined;
5
+ export { formatDirectives as default };
@@ -0,0 +1,60 @@
1
+ // src/features/format-directives.ts
2
+ const CSS_FORMAT_LANGUAGE_IDS = /* @__PURE__ */ new Set([
3
+ "css",
4
+ "scss",
5
+ "less"
6
+ ]);
7
+ const SFC_FORMAT_LANGUAGE_IDS = /* @__PURE__ */ new Set([
8
+ "vue",
9
+ "svelte",
10
+ "astro"
11
+ ]);
12
+ const STYLE_BLOCK_RE = /<style\b([^>]*)>([\s\S]*?)<\/style>/gi;
13
+ function getSFCStyleLanguage(attributes) {
14
+ const match = /\blang\s*=\s*(?:"([^"]+)"|'([^']+)'|([^\s>]+))/i.exec(attributes);
15
+ return (match?.[1] || match?.[2] || match?.[3] || "css").toLowerCase();
16
+ }
17
+ function toOffsetRange(document, range) {
18
+ if (!range) return;
19
+ return {
20
+ start: document.offsetAt(range.start),
21
+ end: document.offsetAt(range.end)
22
+ };
23
+ }
24
+ function toTextEdit(document, edit) {
25
+ return {
26
+ range: {
27
+ start: document.positionAt(edit.range.start),
28
+ end: document.positionAt(edit.range.end)
29
+ },
30
+ newText: edit.text
31
+ };
32
+ }
33
+ function collectSFCStyleRanges(document) {
34
+ const source = document.getText();
35
+ const ranges = [];
36
+ STYLE_BLOCK_RE.lastIndex = 0;
37
+ for (const match of source.matchAll(STYLE_BLOCK_RE)) {
38
+ const styleLanguage = getSFCStyleLanguage(match[1]);
39
+ if (!CSS_FORMAT_LANGUAGE_IDS.has(styleLanguage)) continue;
40
+ const styleText = match[2];
41
+ const styleStart = (match.index || 0) + match[0].indexOf(">") + 1;
42
+ const styleEnd = styleStart + styleText.length;
43
+ ranges.push({
44
+ start: styleStart,
45
+ end: styleEnd
46
+ });
47
+ }
48
+ return ranges;
49
+ }
50
+ function formatDirectives(document, range) {
51
+ const isCSS = CSS_FORMAT_LANGUAGE_IDS.has(document.languageId);
52
+ const isSFC = SFC_FORMAT_LANGUAGE_IDS.has(document.languageId);
53
+ if (!isCSS && !isSFC) return;
54
+ return this.session.formatDirectives({
55
+ source: document.getText(),
56
+ range: toOffsetRange(document, range),
57
+ styleRanges: isSFC ? collectSFCStyleRanges(document) : void 0
58
+ }).edits.map(toTextEdit.bind(void 0, document));
59
+ }
60
+ export { formatDirectives as default };
@@ -0,0 +1,5 @@
1
+ import { Hover, HoverParams } from "vscode-languageserver-protocol";
2
+ import { TextDocument } from "vscode-languageserver-textdocument";
3
+ import { MasterCSSLanguageService } from "../core.js";
4
+ declare function inspectSyntax(this: MasterCSSLanguageService, document: TextDocument, position: HoverParams['position']): Hover | undefined;
5
+ export { inspectSyntax as default };
@@ -0,0 +1,48 @@
1
+ import { analyzeDocument } from "../document-analysis.js";
2
+ import createCSSMarkdownDocumentation from "../utils/create-css-markdown-documentation.js";
3
+ // src/features/inspect-syntax.ts
4
+ function inspectSyntax(document, position) {
5
+ const offset = document.offsetAt(position);
6
+ const keyframe = analyzeDocument(this, document).keyframePositions.find(({ range }) => offset >= range.start && offset <= range.end);
7
+ if (keyframe) {
8
+ const entry = this.session.completionIndex().keyframes.find((entry) => entry.name === keyframe.token);
9
+ if (!entry) return;
10
+ const origins = entry.sources.map((source) => `${source.file || "stylesheet"}${source.loc ? `:${source.loc.start.line}` : ""}`).join("\n");
11
+ return {
12
+ contents: {
13
+ kind: "markdown",
14
+ value: [createCSSMarkdownDocumentation(entry.text)?.value, origins].filter(Boolean).join("\n\n")
15
+ },
16
+ range: {
17
+ start: document.positionAt(keyframe.range.start),
18
+ end: document.positionAt(keyframe.range.end)
19
+ }
20
+ };
21
+ }
22
+ const classPosition = this.getClassPosition(document, position);
23
+ if (!classPosition) return;
24
+ const inspection = this.session.inspectClassName(classPosition.token);
25
+ const documentation = createCSSMarkdownDocumentation(inspection.text);
26
+ const range = {
27
+ start: document.positionAt(classPosition.range.start),
28
+ end: document.positionAt(classPosition.range.end)
29
+ };
30
+ const messages = (inspection.diagnostics ?? []).map((diagnostic) => `**${diagnostic.code}**: ${diagnostic.message}${diagnostic.notes?.length ? `\n\n${diagnostic.notes.join("\n\n")}` : ""}`);
31
+ if (!documentation && !messages.length) return;
32
+ const names = inspection.kind === "token" ? [...new Set(inspection.variables.map(({ variable }) => `\`--${variable.name}\``))] : [];
33
+ const origin = inspection.kind === "token" ? `Named token${names.length ? `: ${names.join(", ")}` : ""}` : inspection.kind === "component" ? "(components)" : "";
34
+ const status = inspection.cssValueStatus === "invalid" || inspection.cssValueStatus === "unknown" ? `CSS value check: **${inspection.cssValueStatus}**. Browser support: **${inspection.browserSupport}**.` : "";
35
+ return {
36
+ contents: {
37
+ kind: "markdown",
38
+ value: [
39
+ origin,
40
+ documentation?.value,
41
+ status,
42
+ ...messages
43
+ ].filter(Boolean).join("\n\n")
44
+ },
45
+ range
46
+ };
47
+ }
48
+ export { inspectSyntax as default };
@@ -0,0 +1,6 @@
1
+ import { SemanticTokens } from "vscode-languageserver-protocol";
2
+ import { TextDocument } from "vscode-languageserver-textdocument";
3
+ import { MasterCSSLanguageService } from "../core.js";
4
+ declare function renderSemanticTokensAtPosition(this: MasterCSSLanguageService, document: TextDocument, position: Parameters<MasterCSSLanguageService['getClassPosition']>[1]): SemanticTokens | undefined;
5
+ declare function renderSemanticTokens(this: MasterCSSLanguageService, document: TextDocument): SemanticTokens | undefined;
6
+ export { renderSemanticTokens as default, renderSemanticTokensAtPosition };
@@ -0,0 +1,36 @@
1
+ import { analyzeDocument } from "../document-analysis.js";
2
+ import { SEMANTIC_TOKEN_MODIFIERS, SEMANTIC_TOKEN_TYPES } from "@master/css-tooling/language";
3
+ // src/features/render-semantic-tokens.ts
4
+ const CSS_LANGUAGE_IDS = /* @__PURE__ */ new Set(["css", "scss"]);
5
+ function encodeSemanticTokens(document, tokens) {
6
+ const data = [];
7
+ let previousLine = 0;
8
+ let previousCharacter = 0;
9
+ for (const token of [...tokens].sort((left, right) => left.start - right.start || left.end - right.end)) {
10
+ const start = document.positionAt(token.start);
11
+ const deltaLine = start.line - previousLine;
12
+ const deltaCharacter = deltaLine === 0 ? start.character - previousCharacter : start.character;
13
+ const tokenType = SEMANTIC_TOKEN_TYPES.indexOf(token.type);
14
+ const modifiers = (token.modifiers || []).reduce((bits, modifier) => {
15
+ const index = SEMANTIC_TOKEN_MODIFIERS.indexOf(modifier);
16
+ return index < 0 ? bits : bits | 1 << index;
17
+ }, 0);
18
+ data.push(deltaLine, deltaCharacter, token.end - token.start, tokenType, modifiers);
19
+ previousLine = start.line;
20
+ previousCharacter = start.character;
21
+ }
22
+ return data;
23
+ }
24
+ function renderSemanticTokensAtPosition(document, position) {
25
+ if (this.settings.embeddedSyntaxHighlighting === "off") return;
26
+ const classPosition = this.getClassPosition(document, position);
27
+ if (!classPosition) return;
28
+ const data = encodeSemanticTokens(document, analyzeDocument(this, document).semanticTokens.filter(({ start, end }) => start >= classPosition.contextRange.start && end <= classPosition.contextRange.end));
29
+ return data.length ? { data } : void 0;
30
+ }
31
+ function renderSemanticTokens(document) {
32
+ if (this.settings.embeddedSyntaxHighlighting !== "always" && !CSS_LANGUAGE_IDS.has(document.languageId)) return;
33
+ const result = analyzeDocument(this, document);
34
+ return result.semanticTokenData.length ? { data: [...result.semanticTokenData] } : void 0;
35
+ }
36
+ export { renderSemanticTokens as default, renderSemanticTokensAtPosition };
@@ -0,0 +1,5 @@
1
+ import { ColorInformation } from "vscode-languageserver-protocol";
2
+ import { TextDocument } from "vscode-languageserver-textdocument";
3
+ import { MasterCSSLanguageService } from "../core.js";
4
+ declare function renderSyntaxColors(this: MasterCSSLanguageService, document: TextDocument): Promise<ColorInformation[]>;
5
+ export { renderSyntaxColors as default };
@@ -0,0 +1,47 @@
1
+ import Color from "colorjs.io";
2
+ // src/features/render-syntax-colors.ts
3
+ const colorJsSpaces = {
4
+ "display-p3": "p3",
5
+ "a98-rgb": "a98rgb",
6
+ "prophoto-rgb": "prophoto",
7
+ "xyz": "xyz-d65"
8
+ };
9
+ function evaluateColorExpression(expression) {
10
+ if (expression.kind === "literal") {
11
+ const color = new Color(expression.value);
12
+ if (expression.alpha !== void 0) color.alpha *= expression.alpha;
13
+ return color;
14
+ }
15
+ const color = Color.mix(evaluateColorExpression(expression.left), evaluateColorExpression(expression.right), expression.progress, {
16
+ space: colorJsSpaces[expression.space] || expression.space,
17
+ premultiplied: true,
18
+ hue: expression.hue
19
+ });
20
+ color.alpha *= expression.alphaMultiplier;
21
+ return color;
22
+ }
23
+ async function renderSyntaxColors(document) {
24
+ const candidates = this.getClassPositions(document).map(({ token, range }) => ({
25
+ className: token,
26
+ start: range.start
27
+ }));
28
+ const colors = [];
29
+ for (const token of this.session.colorTokens(candidates).tokens) try {
30
+ const srgb = evaluateColorExpression(token.expression).to("srgb");
31
+ const clamp = (value) => Number.isFinite(value) ? Math.min(1, Math.max(0, value)) : 0;
32
+ colors.push({
33
+ range: {
34
+ start: document.positionAt(token.range.start),
35
+ end: document.positionAt(token.range.end)
36
+ },
37
+ color: {
38
+ red: clamp(srgb.r ?? 0),
39
+ green: clamp(srgb.g ?? 0),
40
+ blue: clamp(srgb.b ?? 0),
41
+ alpha: clamp(Number(srgb.alpha))
42
+ }
43
+ });
44
+ } catch {}
45
+ return colors;
46
+ }
47
+ export { renderSyntaxColors as default };
@@ -0,0 +1,5 @@
1
+ import { CompletionItem, CompletionParams } from "vscode-languageserver-protocol";
2
+ import { TextDocument } from "vscode-languageserver-textdocument";
3
+ import { MasterCSSLanguageService } from "../core.js";
4
+ declare function suggestSyntax(this: MasterCSSLanguageService, document: TextDocument, position: CompletionParams['position'], context: CompletionParams['context']): CompletionItem[] | undefined;
5
+ export { suggestSyntax as default };