@canonical/terrazzo-lsp 0.0.1

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 (250) hide show
  1. package/README.md +68 -0
  2. package/dist/esm/cli.js +340 -0
  3. package/dist/esm/cli.js.map +1 -0
  4. package/dist/esm/css/buildSelectorContext.js +9 -0
  5. package/dist/esm/css/buildSelectorContext.js.map +1 -0
  6. package/dist/esm/css/classifySelectorScope.js +32 -0
  7. package/dist/esm/css/classifySelectorScope.js.map +1 -0
  8. package/dist/esm/css/compareFallbackStaleness.js +61 -0
  9. package/dist/esm/css/compareFallbackStaleness.js.map +1 -0
  10. package/dist/esm/css/constants.js +35 -0
  11. package/dist/esm/css/constants.js.map +1 -0
  12. package/dist/esm/css/expectedTypeForProperty.js +124 -0
  13. package/dist/esm/css/expectedTypeForProperty.js.map +1 -0
  14. package/dist/esm/css/extractCssImports.js +20 -0
  15. package/dist/esm/css/extractCssImports.js.map +1 -0
  16. package/dist/esm/css/extractJsImports.js +17 -0
  17. package/dist/esm/css/extractJsImports.js.map +1 -0
  18. package/dist/esm/css/extractPackageName.js +20 -0
  19. package/dist/esm/css/extractPackageName.js.map +1 -0
  20. package/dist/esm/css/extractPropertyAtPosition.js +30 -0
  21. package/dist/esm/css/extractPropertyAtPosition.js.map +1 -0
  22. package/dist/esm/css/extractUnit.js +9 -0
  23. package/dist/esm/css/extractUnit.js.map +1 -0
  24. package/dist/esm/css/formatFileUri.js +5 -0
  25. package/dist/esm/css/formatFileUri.js.map +1 -0
  26. package/dist/esm/css/index.js +25 -0
  27. package/dist/esm/css/index.js.map +1 -0
  28. package/dist/esm/css/isAssignable.js +14 -0
  29. package/dist/esm/css/isAssignable.js.map +1 -0
  30. package/dist/esm/css/isBareSpecifier.js +13 -0
  31. package/dist/esm/css/isBareSpecifier.js.map +1 -0
  32. package/dist/esm/css/isExternalPath.js +5 -0
  33. package/dist/esm/css/isExternalPath.js.map +1 -0
  34. package/dist/esm/css/isSuppressed.js +49 -0
  35. package/dist/esm/css/isSuppressed.js.map +1 -0
  36. package/dist/esm/css/mapDtcgType.js +21 -0
  37. package/dist/esm/css/mapDtcgType.js.map +1 -0
  38. package/dist/esm/css/parseFileUri.js +5 -0
  39. package/dist/esm/css/parseFileUri.js.map +1 -0
  40. package/dist/esm/css/parseSuppressionDirectives.js +57 -0
  41. package/dist/esm/css/parseSuppressionDirectives.js.map +1 -0
  42. package/dist/esm/css/parseSyntaxType.js +27 -0
  43. package/dist/esm/css/parseSyntaxType.js.map +1 -0
  44. package/dist/esm/css/resolveDimensionValue.js +63 -0
  45. package/dist/esm/css/resolveDimensionValue.js.map +1 -0
  46. package/dist/esm/css/resolveImportSpecifier.js +30 -0
  47. package/dist/esm/css/resolveImportSpecifier.js.map +1 -0
  48. package/dist/esm/css/scanDeclarations.js +107 -0
  49. package/dist/esm/css/scanDeclarations.js.map +1 -0
  50. package/dist/esm/css/scanProperties.js +40 -0
  51. package/dist/esm/css/scanProperties.js.map +1 -0
  52. package/dist/esm/css/scanUsages.js +81 -0
  53. package/dist/esm/css/scanUsages.js.map +1 -0
  54. package/dist/esm/graph/ReachabilityCache.js +75 -0
  55. package/dist/esm/graph/ReachabilityCache.js.map +1 -0
  56. package/dist/esm/graph/TokenGraph.js +120 -0
  57. package/dist/esm/graph/TokenGraph.js.map +1 -0
  58. package/dist/esm/graph/index.js +5 -0
  59. package/dist/esm/graph/index.js.map +1 -0
  60. package/dist/esm/graph/loadArtifact.js +159 -0
  61. package/dist/esm/graph/loadArtifact.js.map +1 -0
  62. package/dist/esm/graph/parseArtifactToken.js +112 -0
  63. package/dist/esm/graph/parseArtifactToken.js.map +1 -0
  64. package/dist/esm/index.js +16 -0
  65. package/dist/esm/index.js.map +1 -0
  66. package/dist/esm/protocol/createRequest.js +7 -0
  67. package/dist/esm/protocol/createRequest.js.map +1 -0
  68. package/dist/esm/protocol/index.js +9 -0
  69. package/dist/esm/protocol/index.js.map +1 -0
  70. package/dist/esm/protocol/isCompletionRequest.js +4 -0
  71. package/dist/esm/protocol/isCompletionRequest.js.map +1 -0
  72. package/dist/esm/protocol/isDefinitionRequest.js +4 -0
  73. package/dist/esm/protocol/isDefinitionRequest.js.map +1 -0
  74. package/dist/esm/protocol/isDiagnosticsRequest.js +4 -0
  75. package/dist/esm/protocol/isDiagnosticsRequest.js.map +1 -0
  76. package/dist/esm/protocol/isHoverRequest.js +4 -0
  77. package/dist/esm/protocol/isHoverRequest.js.map +1 -0
  78. package/dist/esm/protocol/isReferencesRequest.js +4 -0
  79. package/dist/esm/protocol/isReferencesRequest.js.map +1 -0
  80. package/dist/esm/protocol/matchResponse.js +5 -0
  81. package/dist/esm/protocol/matchResponse.js.map +1 -0
  82. package/dist/esm/protocol/resolveConfig.js +206 -0
  83. package/dist/esm/protocol/resolveConfig.js.map +1 -0
  84. package/dist/esm/providers/buildTokenTooltip.js +448 -0
  85. package/dist/esm/providers/buildTokenTooltip.js.map +1 -0
  86. package/dist/esm/providers/classifyProvenance.js +19 -0
  87. package/dist/esm/providers/classifyProvenance.js.map +1 -0
  88. package/dist/esm/providers/formatCheckReport.js +90 -0
  89. package/dist/esm/providers/formatCheckReport.js.map +1 -0
  90. package/dist/esm/providers/index.js +12 -0
  91. package/dist/esm/providers/index.js.map +1 -0
  92. package/dist/esm/providers/produceArtifactDiagnostics.js +101 -0
  93. package/dist/esm/providers/produceArtifactDiagnostics.js.map +1 -0
  94. package/dist/esm/providers/produceDiagnostics.js +245 -0
  95. package/dist/esm/providers/produceDiagnostics.js.map +1 -0
  96. package/dist/esm/providers/provideCompletions.js +286 -0
  97. package/dist/esm/providers/provideCompletions.js.map +1 -0
  98. package/dist/esm/providers/provideDocumentColors.js +90 -0
  99. package/dist/esm/providers/provideDocumentColors.js.map +1 -0
  100. package/dist/esm/providers/provideHover.js +23 -0
  101. package/dist/esm/providers/provideHover.js.map +1 -0
  102. package/dist/esm/providers/provideRename.js +63 -0
  103. package/dist/esm/providers/provideRename.js.map +1 -0
  104. package/dist/esm/providers/provideSemanticTokens.js +81 -0
  105. package/dist/esm/providers/provideSemanticTokens.js.map +1 -0
  106. package/dist/esm/providers/provideWorkspaceSymbols.js +149 -0
  107. package/dist/esm/providers/provideWorkspaceSymbols.js.map +1 -0
  108. package/dist/esm/providers/resolveDefinition.js +42 -0
  109. package/dist/esm/providers/resolveDefinition.js.map +1 -0
  110. package/dist/esm/providers/tooltipOptions.js +15 -0
  111. package/dist/esm/providers/tooltipOptions.js.map +1 -0
  112. package/dist/esm/runtime/buildImportGraph.js +91 -0
  113. package/dist/esm/runtime/buildImportGraph.js.map +1 -0
  114. package/dist/esm/runtime/createGraphWorker.js +329 -0
  115. package/dist/esm/runtime/createGraphWorker.js.map +1 -0
  116. package/dist/esm/runtime/index.js +5 -0
  117. package/dist/esm/runtime/index.js.map +1 -0
  118. package/dist/esm/runtime/scheduleBufferUpdate.js +57 -0
  119. package/dist/esm/runtime/scheduleBufferUpdate.js.map +1 -0
  120. package/dist/esm/runtime/startLspServer.js +365 -0
  121. package/dist/esm/runtime/startLspServer.js.map +1 -0
  122. package/dist/esm/runtime/types.js +8 -0
  123. package/dist/esm/runtime/types.js.map +1 -0
  124. package/dist/esm/types.js +74 -0
  125. package/dist/esm/types.js.map +1 -0
  126. package/dist/types/cli.d.ts +3 -0
  127. package/dist/types/cli.d.ts.map +1 -0
  128. package/dist/types/css/buildSelectorContext.d.ts +4 -0
  129. package/dist/types/css/buildSelectorContext.d.ts.map +1 -0
  130. package/dist/types/css/classifySelectorScope.d.ts +7 -0
  131. package/dist/types/css/classifySelectorScope.d.ts.map +1 -0
  132. package/dist/types/css/compareFallbackStaleness.d.ts +8 -0
  133. package/dist/types/css/compareFallbackStaleness.d.ts.map +1 -0
  134. package/dist/types/css/constants.d.ts +11 -0
  135. package/dist/types/css/constants.d.ts.map +1 -0
  136. package/dist/types/css/expectedTypeForProperty.d.ts +22 -0
  137. package/dist/types/css/expectedTypeForProperty.d.ts.map +1 -0
  138. package/dist/types/css/extractCssImports.d.ts +6 -0
  139. package/dist/types/css/extractCssImports.d.ts.map +1 -0
  140. package/dist/types/css/extractJsImports.d.ts +6 -0
  141. package/dist/types/css/extractJsImports.d.ts.map +1 -0
  142. package/dist/types/css/extractPackageName.d.ts +6 -0
  143. package/dist/types/css/extractPackageName.d.ts.map +1 -0
  144. package/dist/types/css/extractPropertyAtPosition.d.ts +22 -0
  145. package/dist/types/css/extractPropertyAtPosition.d.ts.map +1 -0
  146. package/dist/types/css/extractUnit.d.ts +6 -0
  147. package/dist/types/css/extractUnit.d.ts.map +1 -0
  148. package/dist/types/css/formatFileUri.d.ts +3 -0
  149. package/dist/types/css/formatFileUri.d.ts.map +1 -0
  150. package/dist/types/css/index.d.ts +25 -0
  151. package/dist/types/css/index.d.ts.map +1 -0
  152. package/dist/types/css/isAssignable.d.ts +7 -0
  153. package/dist/types/css/isAssignable.d.ts.map +1 -0
  154. package/dist/types/css/isBareSpecifier.d.ts +3 -0
  155. package/dist/types/css/isBareSpecifier.d.ts.map +1 -0
  156. package/dist/types/css/isExternalPath.d.ts +3 -0
  157. package/dist/types/css/isExternalPath.d.ts.map +1 -0
  158. package/dist/types/css/isSuppressed.d.ts +7 -0
  159. package/dist/types/css/isSuppressed.d.ts.map +1 -0
  160. package/dist/types/css/mapDtcgType.d.ts +7 -0
  161. package/dist/types/css/mapDtcgType.d.ts.map +1 -0
  162. package/dist/types/css/parseFileUri.d.ts +3 -0
  163. package/dist/types/css/parseFileUri.d.ts.map +1 -0
  164. package/dist/types/css/parseSuppressionDirectives.d.ts +13 -0
  165. package/dist/types/css/parseSuppressionDirectives.d.ts.map +1 -0
  166. package/dist/types/css/parseSyntaxType.d.ts +4 -0
  167. package/dist/types/css/parseSyntaxType.d.ts.map +1 -0
  168. package/dist/types/css/resolveDimensionValue.d.ts +7 -0
  169. package/dist/types/css/resolveDimensionValue.d.ts.map +1 -0
  170. package/dist/types/css/resolveImportSpecifier.d.ts +3 -0
  171. package/dist/types/css/resolveImportSpecifier.d.ts.map +1 -0
  172. package/dist/types/css/scanDeclarations.d.ts +8 -0
  173. package/dist/types/css/scanDeclarations.d.ts.map +1 -0
  174. package/dist/types/css/scanProperties.d.ts +7 -0
  175. package/dist/types/css/scanProperties.d.ts.map +1 -0
  176. package/dist/types/css/scanUsages.d.ts +7 -0
  177. package/dist/types/css/scanUsages.d.ts.map +1 -0
  178. package/dist/types/graph/ReachabilityCache.d.ts +13 -0
  179. package/dist/types/graph/ReachabilityCache.d.ts.map +1 -0
  180. package/dist/types/graph/TokenGraph.d.ts +19 -0
  181. package/dist/types/graph/TokenGraph.d.ts.map +1 -0
  182. package/dist/types/graph/index.d.ts +5 -0
  183. package/dist/types/graph/index.d.ts.map +1 -0
  184. package/dist/types/graph/loadArtifact.d.ts +13 -0
  185. package/dist/types/graph/loadArtifact.d.ts.map +1 -0
  186. package/dist/types/graph/parseArtifactToken.d.ts +13 -0
  187. package/dist/types/graph/parseArtifactToken.d.ts.map +1 -0
  188. package/dist/types/index.d.ts +13 -0
  189. package/dist/types/index.d.ts.map +1 -0
  190. package/dist/types/protocol/createRequest.d.ts +51 -0
  191. package/dist/types/protocol/createRequest.d.ts.map +1 -0
  192. package/dist/types/protocol/index.d.ts +9 -0
  193. package/dist/types/protocol/index.d.ts.map +1 -0
  194. package/dist/types/protocol/isCompletionRequest.d.ts +5 -0
  195. package/dist/types/protocol/isCompletionRequest.d.ts.map +1 -0
  196. package/dist/types/protocol/isDefinitionRequest.d.ts +5 -0
  197. package/dist/types/protocol/isDefinitionRequest.d.ts.map +1 -0
  198. package/dist/types/protocol/isDiagnosticsRequest.d.ts +5 -0
  199. package/dist/types/protocol/isDiagnosticsRequest.d.ts.map +1 -0
  200. package/dist/types/protocol/isHoverRequest.d.ts +5 -0
  201. package/dist/types/protocol/isHoverRequest.d.ts.map +1 -0
  202. package/dist/types/protocol/isReferencesRequest.d.ts +5 -0
  203. package/dist/types/protocol/isReferencesRequest.d.ts.map +1 -0
  204. package/dist/types/protocol/matchResponse.d.ts +4 -0
  205. package/dist/types/protocol/matchResponse.d.ts.map +1 -0
  206. package/dist/types/protocol/resolveConfig.d.ts +16 -0
  207. package/dist/types/protocol/resolveConfig.d.ts.map +1 -0
  208. package/dist/types/providers/buildTokenTooltip.d.ts +33 -0
  209. package/dist/types/providers/buildTokenTooltip.d.ts.map +1 -0
  210. package/dist/types/providers/classifyProvenance.d.ts +8 -0
  211. package/dist/types/providers/classifyProvenance.d.ts.map +1 -0
  212. package/dist/types/providers/formatCheckReport.d.ts +14 -0
  213. package/dist/types/providers/formatCheckReport.d.ts.map +1 -0
  214. package/dist/types/providers/index.d.ts +12 -0
  215. package/dist/types/providers/index.d.ts.map +1 -0
  216. package/dist/types/providers/produceArtifactDiagnostics.d.ts +14 -0
  217. package/dist/types/providers/produceArtifactDiagnostics.d.ts.map +1 -0
  218. package/dist/types/providers/produceDiagnostics.d.ts +5 -0
  219. package/dist/types/providers/produceDiagnostics.d.ts.map +1 -0
  220. package/dist/types/providers/provideCompletions.d.ts +18 -0
  221. package/dist/types/providers/provideCompletions.d.ts.map +1 -0
  222. package/dist/types/providers/provideDocumentColors.d.ts +35 -0
  223. package/dist/types/providers/provideDocumentColors.d.ts.map +1 -0
  224. package/dist/types/providers/provideHover.d.ts +13 -0
  225. package/dist/types/providers/provideHover.d.ts.map +1 -0
  226. package/dist/types/providers/provideRename.d.ts +18 -0
  227. package/dist/types/providers/provideRename.d.ts.map +1 -0
  228. package/dist/types/providers/provideSemanticTokens.d.ts +12 -0
  229. package/dist/types/providers/provideSemanticTokens.d.ts.map +1 -0
  230. package/dist/types/providers/provideWorkspaceSymbols.d.ts +17 -0
  231. package/dist/types/providers/provideWorkspaceSymbols.d.ts.map +1 -0
  232. package/dist/types/providers/resolveDefinition.d.ts +8 -0
  233. package/dist/types/providers/resolveDefinition.d.ts.map +1 -0
  234. package/dist/types/providers/tooltipOptions.d.ts +12 -0
  235. package/dist/types/providers/tooltipOptions.d.ts.map +1 -0
  236. package/dist/types/runtime/buildImportGraph.d.ts +10 -0
  237. package/dist/types/runtime/buildImportGraph.d.ts.map +1 -0
  238. package/dist/types/runtime/createGraphWorker.d.ts +30 -0
  239. package/dist/types/runtime/createGraphWorker.d.ts.map +1 -0
  240. package/dist/types/runtime/index.d.ts +7 -0
  241. package/dist/types/runtime/index.d.ts.map +1 -0
  242. package/dist/types/runtime/scheduleBufferUpdate.d.ts +17 -0
  243. package/dist/types/runtime/scheduleBufferUpdate.d.ts.map +1 -0
  244. package/dist/types/runtime/startLspServer.d.ts +26 -0
  245. package/dist/types/runtime/startLspServer.d.ts.map +1 -0
  246. package/dist/types/runtime/types.d.ts +21 -0
  247. package/dist/types/runtime/types.d.ts.map +1 -0
  248. package/dist/types/types.d.ts +920 -0
  249. package/dist/types/types.d.ts.map +1 -0
  250. package/package.json +35 -0
package/README.md ADDED
@@ -0,0 +1,68 @@
1
+ # @canonical/terrazzo-lsp
2
+
3
+ Language server providing CSS custom property intelligence for design token workflows. Reads `tokens.json` build artifacts and provides editor features for CSS and SCSS files.
4
+
5
+ ## Features
6
+
7
+ | Feature | Description |
8
+ |---------|-------------|
9
+ | Completions | Context-aware suggestions for `var(--...)` references, prioritised by type assignability, semantic tier, and provenance. |
10
+ | Hover | Token metadata including resolved value, colour swatch, alias chain, tier badge, selector context, and source location. |
11
+ | Diagnostics | Type mismatch detection, missing/stale fallback warnings, unreachable token analysis, primitive usage warnings, and more. |
12
+ | Go to Definition | Jump from a `var()` reference to the token declaration. |
13
+ | Rename | Rename a CSS custom property across all files in the import graph. |
14
+ | Document Colours | Inline colour swatches and colour picker for token-backed colour values. |
15
+ | Semantic Tokens | Syntax highlighting distinguishing artifact tokens, local properties, and external references. |
16
+ | Workspace Symbols | Search tokens across the workspace by name or type. |
17
+
18
+ ## Editor Setup
19
+
20
+ **VS Code** (recommended):
21
+
22
+ ```bash
23
+ bun run build:ext
24
+ code --install-extension extension/terrazzo-lsp-0.1.0.vsix
25
+ ```
26
+
27
+ **Neovim** (via nvim-lspconfig):
28
+
29
+ ```bash
30
+ bun dist/esm/cli.js install neovim
31
+ ```
32
+
33
+ **Helix:**
34
+
35
+ ```bash
36
+ bun dist/esm/cli.js install helix
37
+ ```
38
+
39
+ ## CLI
40
+
41
+ ```bash
42
+ bun dist/esm/cli.js --stdio # Start LSP server on stdio
43
+ bun dist/esm/cli.js check [globs] # Run diagnostics on CSS files
44
+ bun dist/esm/cli.js status # Show config and artifact status
45
+ bun dist/esm/cli.js inspect <var> # Inspect a CSS custom property
46
+ ```
47
+
48
+ ## Configuration
49
+
50
+ Create a `terrazzo-lsp.config.json` in your workspace root:
51
+
52
+ ```json
53
+ {
54
+ "artifacts": ["@canonical/design-tokens/dist/tokens.json"],
55
+ "globalStylesheets": [".storybook/styles.css"]
56
+ }
57
+ ```
58
+
59
+ See the root repository README for the full configuration reference.
60
+
61
+ ## Development
62
+
63
+ ```bash
64
+ bun run build # Compile LSP server (tsc)
65
+ bun run build:ext # Build + package VS Code extension
66
+ bun run test # Run tests
67
+ bun run check # Lint + type check
68
+ ```
@@ -0,0 +1,340 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * terrazzo-lsp CLI entry point.
4
+ *
5
+ * Commands:
6
+ * - (no args / --stdio) Start the LSP server on stdio
7
+ * - check [globs...] Run diagnostics on CSS files and report
8
+ * - status Show current config and artifact status
9
+ * - inspect <var> Inspect a CSS custom property
10
+ * - resolve <specifier> Resolve an import specifier
11
+ * - graph <file> Show the import graph from a file
12
+ *
13
+ * @note This function is impure — it reads process.argv, accesses the
14
+ * file system, and writes to stdout/stderr.
15
+ *
16
+ * @see session/G.TOKEN_LSP.md §14 — CLI Tooling
17
+ */
18
+ import * as fs from "node:fs/promises";
19
+ import { homedir } from "node:os";
20
+ import { join, resolve } from "node:path";
21
+ import { loadArtifact, ReachabilityCache, TokenGraph } from "./graph/index.js";
22
+ import { loadConfigFile, resolveConfig } from "./protocol/index.js";
23
+ import { produceDiagnostics } from "./providers/index.js";
24
+ import { buildImportGraph } from "./runtime/buildImportGraph.js";
25
+ import { startLspServer } from "./runtime/startLspServer.js";
26
+ import { DiagnosticSeverity } from "./types.js";
27
+ const args = process.argv.slice(2);
28
+ const command = args[0] ?? "--stdio";
29
+ const rootDir = process.cwd();
30
+ /**
31
+ * Run the CLI.
32
+ *
33
+ * @note This function is impure — it reads files, writes to stdout,
34
+ * and may exit the process.
35
+ */
36
+ async function run() {
37
+ switch (command) {
38
+ case "--stdio":
39
+ case "serve":
40
+ startLspServer(rootDir);
41
+ break;
42
+ case "check":
43
+ await runCheck(args.slice(1));
44
+ break;
45
+ case "status":
46
+ await runStatus();
47
+ break;
48
+ case "inspect":
49
+ await runInspect(args[1]);
50
+ break;
51
+ case "resolve":
52
+ await runResolve(args[1]);
53
+ break;
54
+ case "graph":
55
+ await runGraph(args[1]);
56
+ break;
57
+ case "install":
58
+ await runInstall(args[1]);
59
+ break;
60
+ case "--help":
61
+ case "-h":
62
+ printHelp();
63
+ break;
64
+ case "--version":
65
+ case "-v":
66
+ console.log("terrazzo-lsp 0.1.0");
67
+ break;
68
+ default:
69
+ console.error(`Unknown command: ${command}`);
70
+ printHelp();
71
+ process.exit(1);
72
+ }
73
+ }
74
+ function printHelp() {
75
+ console.log(`terrazzo-lsp — CSS custom property intelligence for design tokens
76
+
77
+ Usage:
78
+ terrazzo-lsp Start LSP server (stdio)
79
+ terrazzo-lsp check [globs] Run diagnostics on CSS files
80
+ terrazzo-lsp status Show config and artifact status
81
+ terrazzo-lsp inspect <var> Inspect a CSS custom property
82
+ terrazzo-lsp resolve <spec> Resolve an import specifier
83
+ terrazzo-lsp graph <file> Show import graph from a file
84
+ terrazzo-lsp install <editor> Install LSP config (neovim, helix, vscode)
85
+
86
+ Options:
87
+ --stdio Start LSP server on stdio (default)
88
+ -h, --help Show this help
89
+ -v, --version Show version`);
90
+ }
91
+ async function runCheck(globs) {
92
+ const { raw, configDir } = await loadConfigFile(rootDir);
93
+ const config = resolveConfig(raw, configDir ?? rootDir);
94
+ const graph = new TokenGraph();
95
+ const cache = new ReachabilityCache();
96
+ await loadArtifactFiles(config.artifactPaths, graph);
97
+ const patterns = globs.length > 0 ? globs : config.scanGlobs;
98
+ const files = await expandGlobs(patterns);
99
+ let errorCount = 0;
100
+ let warningCount = 0;
101
+ for (const file of files) {
102
+ const absPath = resolve(rootDir, file);
103
+ const source = await fs.readFile(absPath, "utf-8");
104
+ const uri = `file://${absPath}`;
105
+ const diagnostics = produceDiagnostics(uri, source, graph, cache, config);
106
+ for (const diag of diagnostics) {
107
+ const severity = diag.severity === DiagnosticSeverity.Error
108
+ ? "error"
109
+ : diag.severity === DiagnosticSeverity.Warning
110
+ ? "warning"
111
+ : "info";
112
+ if (diag.severity === DiagnosticSeverity.Error)
113
+ errorCount++;
114
+ if (diag.severity === DiagnosticSeverity.Warning)
115
+ warningCount++;
116
+ const loc = `${file}:${diag.range.start.line + 1}:${diag.range.start.character + 1}`;
117
+ console.log(`${loc} ${severity} ${diag.code} ${diag.message}`);
118
+ }
119
+ }
120
+ const total = errorCount + warningCount;
121
+ if (total > 0) {
122
+ console.log(`\n${errorCount} errors, ${warningCount} warnings`);
123
+ process.exit(errorCount > 0 ? 1 : 0);
124
+ }
125
+ else {
126
+ console.log("No issues found.");
127
+ }
128
+ }
129
+ async function runStatus() {
130
+ const { raw, configDir } = await loadConfigFile(rootDir);
131
+ const config = resolveConfig(raw, configDir ?? rootDir);
132
+ console.log("terrazzo-lsp status");
133
+ console.log("---");
134
+ console.log(`Root: ${rootDir}`);
135
+ console.log(`Dist: ${config.distDir}`);
136
+ console.log(`Artifacts: ${config.artifactPaths.length > 0 ? config.artifactPaths.join(", ") : "(none)"}`);
137
+ console.log(`Scan globs: ${config.scanGlobs.join(", ")}`);
138
+ console.log(`Global CSS: ${config.globalStylesheets === null ? "(auto)" : config.globalStylesheets.join(", ") || "(none)"}`);
139
+ }
140
+ async function runInspect(cssVar) {
141
+ if (!cssVar) {
142
+ console.error("Usage: terrazzo-lsp inspect <--custom-property>");
143
+ process.exit(1);
144
+ }
145
+ const { raw, configDir } = await loadConfigFile(rootDir);
146
+ const config = resolveConfig(raw, configDir ?? rootDir);
147
+ const graph = new TokenGraph();
148
+ await loadArtifactFiles(config.artifactPaths, graph);
149
+ const token = graph.resolveToken(cssVar);
150
+ if (token) {
151
+ console.log(JSON.stringify(token, null, 2));
152
+ }
153
+ else {
154
+ console.log(`Token "${cssVar}" not found in loaded artifacts.`);
155
+ }
156
+ }
157
+ async function runResolve(specifier) {
158
+ if (!specifier) {
159
+ console.error("Usage: terrazzo-lsp resolve <import-specifier>");
160
+ process.exit(1);
161
+ return;
162
+ }
163
+ const { resolveImportSpecifier } = await import("./css/index.js");
164
+ const resolved = resolveImportSpecifier(specifier, rootDir, rootDir);
165
+ console.log(resolved ?? "(unresolvable)");
166
+ }
167
+ async function runGraph(file) {
168
+ if (!file) {
169
+ console.error("Usage: terrazzo-lsp graph <file>");
170
+ process.exit(1);
171
+ }
172
+ const graph = new TokenGraph();
173
+ const absPath = resolve(rootDir, file);
174
+ const uri = `file://${absPath}`;
175
+ const nodeFs = {
176
+ rootDir,
177
+ async readFile(fileUri) {
178
+ const fsPath = fileUri.startsWith("file://") ? fileUri.slice(7) : fileUri;
179
+ try {
180
+ return await fs.readFile(fsPath, "utf-8");
181
+ }
182
+ catch {
183
+ return null;
184
+ }
185
+ },
186
+ };
187
+ await buildImportGraph(uri, graph, nodeFs);
188
+ console.log(`Import graph from ${file}:`);
189
+ for (const [importer, imported] of graph.data.imports) {
190
+ for (const dep of imported) {
191
+ const short = (s) => s.startsWith("file://") ? s.slice(7).replace(rootDir, ".") : s;
192
+ console.log(` ${short(importer)} → ${short(dep)}`);
193
+ }
194
+ }
195
+ console.log(`\nFiles: ${graph.data.files.size}`);
196
+ console.log(`Declarations: ${graph.data.allVars.size}`);
197
+ }
198
+ // ---------------------------------------------------------------------------
199
+ // install command
200
+ // ---------------------------------------------------------------------------
201
+ const NEOVIM_CONFIG = `-- terrazzo-lsp configuration for Neovim
202
+ -- Add this to your init.lua or lspconfig setup
203
+ --
204
+ -- Requires: bun (recommended) or node >= 22
205
+ -- Update the cmd path to point to your project's dist/esm/cli.js
206
+ require('lspconfig').terrazzo_lsp.setup({
207
+ cmd = { 'bun', 'run', '<path-to-repo>/dist/esm/cli.js', '--stdio' },
208
+ filetypes = { 'css', 'scss', 'json' },
209
+ root_dir = require('lspconfig').util.root_pattern(
210
+ 'terrazzo-lsp.config.json', 'package.json', '.git'
211
+ ),
212
+ on_attach = function(client, bufnr)
213
+ local o = { buffer = bufnr, noremap = true, silent = true }
214
+ vim.keymap.set('n', 'gd', vim.lsp.buf.definition, o)
215
+ vim.keymap.set('n', 'gr', vim.lsp.buf.references, o)
216
+ vim.keymap.set('n', 'K', vim.lsp.buf.hover, o)
217
+ vim.keymap.set('n', '<leader>ca', vim.lsp.buf.code_action, o)
218
+ vim.keymap.set('n', '<leader>rn', vim.lsp.buf.rename, o)
219
+ end,
220
+ })
221
+ `;
222
+ const HELIX_CONFIG = `# terrazzo-lsp configuration for Helix
223
+ # Add this to your ~/.config/helix/languages.toml
224
+ #
225
+ # Requires: bun (recommended) or node >= 22
226
+ # Update the command path to point to your project's dist/esm/cli.js
227
+
228
+ [language-server.terrazzo]
229
+ command = "bun"
230
+ args = ["run", "<path-to-repo>/dist/esm/cli.js", "--stdio"]
231
+
232
+ [[language]]
233
+ name = "css"
234
+ language-servers = ["terrazzo", "vscode-css-language-server"]
235
+
236
+ [[language]]
237
+ name = "scss"
238
+ language-servers = ["terrazzo", "vscode-css-language-server"]
239
+ `;
240
+ /**
241
+ * Install LSP configuration for the specified editor.
242
+ *
243
+ * @note This function is impure — it writes config files.
244
+ */
245
+ async function runInstall(editor) {
246
+ if (!editor) {
247
+ console.error("Usage: terrazzo-lsp install <editor>\nEditors: neovim, helix, vscode");
248
+ process.exit(1);
249
+ return;
250
+ }
251
+ switch (editor) {
252
+ case "neovim": {
253
+ const configDir = join(homedir(), ".config", "nvim", "lsp");
254
+ await fs.mkdir(configDir, { recursive: true });
255
+ const configPath = join(configDir, "terrazzo_lsp.lua");
256
+ await fs.writeFile(configPath, NEOVIM_CONFIG, "utf-8");
257
+ console.log(`Wrote Neovim LSP config to ${configPath}`);
258
+ console.log("Ensure nvim-lspconfig is installed. Update the cmd path in the config.");
259
+ break;
260
+ }
261
+ case "helix": {
262
+ const configDir = join(homedir(), ".config", "helix");
263
+ const configPath = join(configDir, "languages.toml");
264
+ let existing = "";
265
+ try {
266
+ existing = await fs.readFile(configPath, "utf-8");
267
+ }
268
+ catch {
269
+ // File doesn't exist yet
270
+ }
271
+ if (existing.includes("terrazzo")) {
272
+ console.log(`Helix config at ${configPath} already contains terrazzo configuration.`);
273
+ }
274
+ else {
275
+ await fs.mkdir(configDir, { recursive: true });
276
+ const updated = existing
277
+ ? `${existing}\n${HELIX_CONFIG}`
278
+ : HELIX_CONFIG;
279
+ await fs.writeFile(configPath, updated, "utf-8");
280
+ console.log(`Appended terrazzo-lsp config to ${configPath}`);
281
+ }
282
+ break;
283
+ }
284
+ case "vscode": {
285
+ const extDir = join(rootDir, ".vscode");
286
+ await fs.mkdir(extDir, { recursive: true });
287
+ const settingsPath = join(extDir, "settings.json");
288
+ let settings = {};
289
+ try {
290
+ const raw = await fs.readFile(settingsPath, "utf-8");
291
+ settings = JSON.parse(raw);
292
+ }
293
+ catch {
294
+ // New file
295
+ }
296
+ settings["terrazzo-lsp.enable"] = true;
297
+ await fs.writeFile(settingsPath, JSON.stringify(settings, null, 2), "utf-8");
298
+ console.log(`Updated VS Code settings at ${settingsPath}`);
299
+ console.log('Install the "Terrazzo Tokens" extension from the Extensions panel.');
300
+ break;
301
+ }
302
+ default:
303
+ console.error(`Unknown editor: ${editor}`);
304
+ console.error("Supported editors: neovim, helix, vscode");
305
+ process.exit(1);
306
+ }
307
+ }
308
+ // ---------------------------------------------------------------------------
309
+ // Artifact loading
310
+ // ---------------------------------------------------------------------------
311
+ async function loadArtifactFiles(paths, graph) {
312
+ for (const p of paths) {
313
+ try {
314
+ const raw = await fs.readFile(p, "utf-8");
315
+ const artifact = JSON.parse(raw);
316
+ const { dirname } = await import("node:path");
317
+ loadArtifact(artifact, graph, "", dirname(p));
318
+ }
319
+ catch {
320
+ // Skip missing artifacts
321
+ }
322
+ }
323
+ }
324
+ async function expandGlobs(patterns) {
325
+ const { glob } = await import("node:fs/promises");
326
+ const results = [];
327
+ for (const pattern of patterns) {
328
+ try {
329
+ for await (const entry of glob(pattern, { cwd: rootDir })) {
330
+ results.push(entry);
331
+ }
332
+ }
333
+ catch {
334
+ // Pattern didn't match — skip
335
+ }
336
+ }
337
+ return [...new Set(results)];
338
+ }
339
+ void run();
340
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { classifySelectorScope } from "./classifySelectorScope.js";
2
+ /** Build a full SelectorContext from a selector and its at-rule context. */
3
+ export function buildSelectorContext(selector, atRules) {
4
+ const scopeType = classifySelectorScope(selector, atRules);
5
+ const isGlobal = scopeType === "global" || scopeType === "universal";
6
+ const isScoped = !isGlobal;
7
+ return { selector, atRules, scopeType, isGlobal, isScoped };
8
+ }
9
+ //# sourceMappingURL=buildSelectorContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildSelectorContext.js","sourceRoot":"","sources":["../../../src/css/buildSelectorContext.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,4EAA4E;AAC5E,MAAM,UAAU,oBAAoB,CAClC,QAAgB,EAChB,OAAwB;IAExB,MAAM,SAAS,GAAG,qBAAqB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC3D,MAAM,QAAQ,GAAG,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,WAAW,CAAC;IACrE,MAAM,QAAQ,GAAG,CAAC,QAAQ,CAAC;IAC3B,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AAC9D,CAAC"}
@@ -0,0 +1,32 @@
1
+ const GLOBAL_SELECTORS = new Set([
2
+ ":root",
3
+ "html",
4
+ "body",
5
+ ":host",
6
+ ":host(*)",
7
+ ]);
8
+ /** Classify a CSS selector + at-rule context into a scope type. */
9
+ export function classifySelectorScope(selector, atRules) {
10
+ const trimmed = selector.trim();
11
+ if (trimmed === "*")
12
+ return "universal";
13
+ for (const at of atRules) {
14
+ if (at.name === "media")
15
+ return "media";
16
+ if (at.name === "layer")
17
+ return "layer";
18
+ if (at.name === "supports")
19
+ return "supports";
20
+ }
21
+ if (GLOBAL_SELECTORS.has(trimmed))
22
+ return "global";
23
+ if (trimmed.startsWith(".") ||
24
+ trimmed.startsWith("#") ||
25
+ trimmed.includes("[") ||
26
+ trimmed.includes(">") ||
27
+ trimmed.includes("+") ||
28
+ trimmed.includes("~"))
29
+ return "class";
30
+ return "other";
31
+ }
32
+ //# sourceMappingURL=classifySelectorScope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classifySelectorScope.js","sourceRoot":"","sources":["../../../src/css/classifySelectorScope.ts"],"names":[],"mappings":"AAKA,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;IAC/B,OAAO;IACP,MAAM;IACN,MAAM;IACN,OAAO;IACP,UAAU;CACX,CAAC,CAAC;AAEH,mEAAmE;AACnE,MAAM,UAAU,qBAAqB,CACnC,QAAgB,EAChB,OAAwB;IAExB,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;IAChC,IAAI,OAAO,KAAK,GAAG;QAAE,OAAO,WAAW,CAAC;IACxC,KAAK,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;QACzB,IAAI,EAAE,CAAC,IAAI,KAAK,OAAO;YAAE,OAAO,OAAO,CAAC;QACxC,IAAI,EAAE,CAAC,IAAI,KAAK,OAAO;YAAE,OAAO,OAAO,CAAC;QACxC,IAAI,EAAE,CAAC,IAAI,KAAK,UAAU;YAAE,OAAO,UAAU,CAAC;IAChD,CAAC;IACD,IAAI,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC;QAAE,OAAO,QAAQ,CAAC;IACnD,IACE,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;QACvB,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;QACvB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;QACrB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;QACrB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;QACrB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;QAErB,OAAO,OAAO,CAAC;IACjB,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Compare a fallback value against the current token value to detect staleness.
3
+ *
4
+ * For colour tokens, uses ΔE (oklch euclidean) with a threshold of 1.0 —
5
+ * equivalent colour representations do not count as stale.
6
+ *
7
+ * @see session/G.TOKEN_LSP.md §9.3 — css/stale-fallback
8
+ * @see session/G.TOKEN_LSP.md §11.5 — ΔE ≤ 1 colour comparison
9
+ */
10
+ import { differenceEuclidean, oklch, parse } from "culori";
11
+ /**
12
+ * ΔE threshold for colour equivalence in oklch space.
13
+ *
14
+ * culori's `differenceEuclidean("oklch")` returns values in [0, ~1.4].
15
+ * A threshold of 0.02 suppresses rounding differences between
16
+ * equivalent colour representations while catching meaningful changes.
17
+ *
18
+ * @see session/G.TOKEN_LSP.md §11.5 — ΔE ≤ 1 (CIEDE2000 scale;
19
+ * 0.02 oklch euclidean maps to approximately ΔE2000 ≤ 1)
20
+ */
21
+ const DELTA_E_THRESHOLD = 0.02;
22
+ const diffOklch = differenceEuclidean("oklch");
23
+ /**
24
+ * Compare a fallback CSS value against the current token value.
25
+ *
26
+ * @returns `true` when the fallback is stale (differs meaningfully from the
27
+ * current value), `false` when they are equivalent.
28
+ */
29
+ export function compareFallbackStaleness(fallback, currentValue, isColour) {
30
+ if (!currentValue)
31
+ return false;
32
+ const normFallback = fallback.trim();
33
+ const normCurrent = currentValue.trim();
34
+ if (normFallback === normCurrent)
35
+ return false;
36
+ if (isColour) {
37
+ return compareColourStaleness(normFallback, normCurrent);
38
+ }
39
+ // Non-colour: string inequality is stale
40
+ return true;
41
+ }
42
+ /** Compare two colour values using ΔE in oklch colour space. */
43
+ function compareColourStaleness(a, b) {
44
+ try {
45
+ const parsedA = parse(a);
46
+ const parsedB = parse(b);
47
+ if (!parsedA || !parsedB)
48
+ return true;
49
+ const okA = oklch(parsedA);
50
+ const okB = oklch(parsedB);
51
+ if (!okA || !okB)
52
+ return true;
53
+ const deltaE = diffOklch(okA, okB);
54
+ return deltaE > DELTA_E_THRESHOLD;
55
+ }
56
+ catch {
57
+ // Cannot parse — treat as stale (conservative)
58
+ return true;
59
+ }
60
+ }
61
+ //# sourceMappingURL=compareFallbackStaleness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compareFallbackStaleness.js","sourceRoot":"","sources":["../../../src/css/compareFallbackStaleness.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,mBAAmB,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAE3D;;;;;;;;;GASG;AACH,MAAM,iBAAiB,GAAG,IAAI,CAAC;AAC/B,MAAM,SAAS,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAE/C;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CACtC,QAAgB,EAChB,YAA2B,EAC3B,QAAiB;IAEjB,IAAI,CAAC,YAAY;QAAE,OAAO,KAAK,CAAC;IAChC,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;IACrC,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC;IACxC,IAAI,YAAY,KAAK,WAAW;QAAE,OAAO,KAAK,CAAC;IAE/C,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,sBAAsB,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;IAC3D,CAAC;IAED,yCAAyC;IACzC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,gEAAgE;AAChE,SAAS,sBAAsB,CAAC,CAAS,EAAE,CAAS;IAClD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACzB,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QACtC,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;QAC3B,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;QAC3B,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QAC9B,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACnC,OAAO,MAAM,GAAG,iBAAiB,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,+CAA+C;QAC/C,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,35 @@
1
+ /** Subtype pairs: [subtype, supertype]. @see session/G.TOKEN_LSP.md §11.3 */
2
+ export const SUBTYPE_RELATIONS = [
3
+ ["<length>", "<length-percentage>"],
4
+ ["<percentage>", "<length-percentage>"],
5
+ ["<integer>", "<number>"],
6
+ ["<number>", "<alpha-value>"],
7
+ ["<percentage>", "<alpha-value>"],
8
+ ["<gradient>", "<image>"],
9
+ ["<url>", "<image>"],
10
+ ];
11
+ /** CSS math functions — type checking is suppressed inside these. @see session/G.TOKEN_LSP.md §11.5 */
12
+ export const MATH_FUNCTIONS = new Set([
13
+ "calc",
14
+ "min",
15
+ "max",
16
+ "clamp",
17
+ "round",
18
+ "mod",
19
+ "rem",
20
+ "sin",
21
+ "cos",
22
+ "tan",
23
+ "asin",
24
+ "acos",
25
+ "atan",
26
+ "atan2",
27
+ "pow",
28
+ "sqrt",
29
+ "hypot",
30
+ "log",
31
+ "exp",
32
+ "abs",
33
+ "sign",
34
+ ]);
35
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/css/constants.ts"],"names":[],"mappings":"AAOA,6EAA6E;AAC7E,MAAM,CAAC,MAAM,iBAAiB,GAE1B;IACF,CAAC,UAAU,EAAE,qBAAqB,CAAC;IACnC,CAAC,cAAc,EAAE,qBAAqB,CAAC;IACvC,CAAC,WAAW,EAAE,UAAU,CAAC;IACzB,CAAC,UAAU,EAAE,eAAe,CAAC;IAC7B,CAAC,cAAc,EAAE,eAAe,CAAC;IACjC,CAAC,YAAY,EAAE,SAAS,CAAC;IACzB,CAAC,OAAO,EAAE,SAAS,CAAC;CACZ,CAAC;AAEX,uGAAuG;AACvG,MAAM,CAAC,MAAM,cAAc,GAAwB,IAAI,GAAG,CAAC;IACzD,MAAM;IACN,KAAK;IACL,KAAK;IACL,OAAO;IACP,OAAO;IACP,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,MAAM;IACN,MAAM;IACN,MAAM;IACN,OAAO;IACP,KAAK;IACL,MAAM;IACN,OAAO;IACP,KAAK;IACL,KAAK;IACL,KAAK;IACL,MAAM;CACP,CAAC,CAAC"}