@mp3wizard/figma-console-mcp 1.23.1 → 1.27.2
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 +49 -33
- package/dist/cloudflare/core/config.js +0 -8
- package/dist/cloudflare/core/console-monitor.js +3 -3
- package/dist/cloudflare/core/diagnose-tool.js +96 -0
- package/dist/cloudflare/core/figma-tools.js +69 -229
- package/dist/cloudflare/core/identity.js +96 -0
- package/dist/cloudflare/core/tokens/alias-resolver.js +98 -0
- package/dist/cloudflare/core/tokens/config.js +284 -0
- package/dist/cloudflare/core/tokens/figma-converter.js +195 -0
- package/dist/cloudflare/core/tokens/formatters/css-vars.js +329 -0
- package/dist/cloudflare/core/tokens/formatters/dtcg.js +300 -0
- package/dist/cloudflare/core/tokens/formatters/index.js +45 -0
- package/dist/cloudflare/core/tokens/formatters/json.js +7 -0
- package/dist/cloudflare/core/tokens/formatters/less.js +4 -0
- package/dist/cloudflare/core/tokens/formatters/scss.js +4 -0
- package/dist/cloudflare/core/tokens/formatters/stubs.js +11 -0
- package/dist/cloudflare/core/tokens/formatters/style-dictionary-v3.js +4 -0
- package/dist/cloudflare/core/tokens/formatters/tailwind-v3.js +4 -0
- package/dist/cloudflare/core/tokens/formatters/tailwind-v4.js +4 -0
- package/dist/cloudflare/core/tokens/formatters/tokens-studio.js +4 -0
- package/dist/cloudflare/core/tokens/formatters/ts-module.js +4 -0
- package/dist/cloudflare/core/tokens/index.js +15 -0
- package/dist/cloudflare/core/tokens/parsers/css-vars.js +4 -0
- package/dist/cloudflare/core/tokens/parsers/dtcg.js +253 -0
- package/dist/cloudflare/core/tokens/parsers/index.js +138 -0
- package/dist/cloudflare/core/tokens/parsers/json.js +7 -0
- package/dist/cloudflare/core/tokens/parsers/scss.js +4 -0
- package/dist/cloudflare/core/tokens/parsers/stubs.js +13 -0
- package/dist/cloudflare/core/tokens/parsers/style-dictionary-v3.js +4 -0
- package/dist/cloudflare/core/tokens/parsers/tailwind-v3.js +4 -0
- package/dist/cloudflare/core/tokens/parsers/tailwind-v4.js +4 -0
- package/dist/cloudflare/core/tokens/parsers/tokens-studio.js +4 -0
- package/dist/cloudflare/core/tokens/schemas.js +148 -0
- package/dist/cloudflare/core/tokens/transforms/color.js +12 -0
- package/dist/cloudflare/core/tokens/transforms/index.js +29 -0
- package/dist/cloudflare/core/tokens/transforms/size.js +7 -0
- package/dist/cloudflare/core/tokens/types.js +18 -0
- package/dist/cloudflare/core/tokens-tools.js +849 -0
- package/dist/cloudflare/core/version-tools.js +151 -7
- package/dist/cloudflare/core/websocket-server.js +77 -55
- package/dist/cloudflare/index.js +37 -26
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +0 -8
- package/dist/core/config.js.map +1 -1
- package/dist/core/console-monitor.d.ts +2 -2
- package/dist/core/console-monitor.d.ts.map +1 -1
- package/dist/core/console-monitor.js +3 -3
- package/dist/core/console-monitor.js.map +1 -1
- package/dist/core/diagnose-tool.d.ts +33 -0
- package/dist/core/diagnose-tool.d.ts.map +1 -0
- package/dist/core/diagnose-tool.js +97 -0
- package/dist/core/diagnose-tool.js.map +1 -0
- package/dist/core/diff/diff-engine.d.ts +14 -0
- package/dist/core/diff/diff-engine.d.ts.map +1 -1
- package/dist/core/diff/diff-engine.js.map +1 -1
- package/dist/core/figma-connector.d.ts +1 -1
- package/dist/core/figma-connector.d.ts.map +1 -1
- package/dist/core/figma-tools.d.ts +1 -2
- package/dist/core/figma-tools.d.ts.map +1 -1
- package/dist/core/figma-tools.js +69 -229
- package/dist/core/figma-tools.js.map +1 -1
- package/dist/core/identity.d.ts +41 -0
- package/dist/core/identity.d.ts.map +1 -0
- package/dist/core/identity.js +97 -0
- package/dist/core/identity.js.map +1 -0
- package/dist/core/tokens/alias-resolver.d.ts +40 -0
- package/dist/core/tokens/alias-resolver.d.ts.map +1 -0
- package/dist/core/tokens/alias-resolver.js +99 -0
- package/dist/core/tokens/alias-resolver.js.map +1 -0
- package/dist/core/tokens/config.d.ts +352 -0
- package/dist/core/tokens/config.d.ts.map +1 -0
- package/dist/core/tokens/config.js +285 -0
- package/dist/core/tokens/config.js.map +1 -0
- package/dist/core/tokens/figma-converter.d.ts +81 -0
- package/dist/core/tokens/figma-converter.d.ts.map +1 -0
- package/dist/core/tokens/figma-converter.js +196 -0
- package/dist/core/tokens/figma-converter.js.map +1 -0
- package/dist/core/tokens/formatters/css-vars.d.ts +24 -0
- package/dist/core/tokens/formatters/css-vars.d.ts.map +1 -0
- package/dist/core/tokens/formatters/css-vars.js +330 -0
- package/dist/core/tokens/formatters/css-vars.js.map +1 -0
- package/dist/core/tokens/formatters/dtcg.d.ts +28 -0
- package/dist/core/tokens/formatters/dtcg.d.ts.map +1 -0
- package/dist/core/tokens/formatters/dtcg.js +301 -0
- package/dist/core/tokens/formatters/dtcg.js.map +1 -0
- package/dist/core/tokens/formatters/index.d.ts +30 -0
- package/dist/core/tokens/formatters/index.d.ts.map +1 -0
- package/dist/core/tokens/formatters/index.js +46 -0
- package/dist/core/tokens/formatters/index.js.map +1 -0
- package/dist/core/tokens/formatters/json.d.ts +5 -0
- package/dist/core/tokens/formatters/json.d.ts.map +1 -0
- package/dist/core/tokens/formatters/json.js +8 -0
- package/dist/core/tokens/formatters/json.js.map +1 -0
- package/dist/core/tokens/formatters/less.d.ts +4 -0
- package/dist/core/tokens/formatters/less.d.ts.map +1 -0
- package/dist/core/tokens/formatters/less.js +5 -0
- package/dist/core/tokens/formatters/less.js.map +1 -0
- package/dist/core/tokens/formatters/scss.d.ts +4 -0
- package/dist/core/tokens/formatters/scss.d.ts.map +1 -0
- package/dist/core/tokens/formatters/scss.js +5 -0
- package/dist/core/tokens/formatters/scss.js.map +1 -0
- package/dist/core/tokens/formatters/stubs.d.ts +9 -0
- package/dist/core/tokens/formatters/stubs.d.ts.map +1 -0
- package/dist/core/tokens/formatters/stubs.js +12 -0
- package/dist/core/tokens/formatters/stubs.js.map +1 -0
- package/dist/core/tokens/formatters/style-dictionary-v3.d.ts +4 -0
- package/dist/core/tokens/formatters/style-dictionary-v3.d.ts.map +1 -0
- package/dist/core/tokens/formatters/style-dictionary-v3.js +5 -0
- package/dist/core/tokens/formatters/style-dictionary-v3.js.map +1 -0
- package/dist/core/tokens/formatters/tailwind-v3.d.ts +4 -0
- package/dist/core/tokens/formatters/tailwind-v3.d.ts.map +1 -0
- package/dist/core/tokens/formatters/tailwind-v3.js +5 -0
- package/dist/core/tokens/formatters/tailwind-v3.js.map +1 -0
- package/dist/core/tokens/formatters/tailwind-v4.d.ts +4 -0
- package/dist/core/tokens/formatters/tailwind-v4.d.ts.map +1 -0
- package/dist/core/tokens/formatters/tailwind-v4.js +5 -0
- package/dist/core/tokens/formatters/tailwind-v4.js.map +1 -0
- package/dist/core/tokens/formatters/tokens-studio.d.ts +4 -0
- package/dist/core/tokens/formatters/tokens-studio.d.ts.map +1 -0
- package/dist/core/tokens/formatters/tokens-studio.js +5 -0
- package/dist/core/tokens/formatters/tokens-studio.js.map +1 -0
- package/dist/core/tokens/formatters/ts-module.d.ts +4 -0
- package/dist/core/tokens/formatters/ts-module.d.ts.map +1 -0
- package/dist/core/tokens/formatters/ts-module.js +5 -0
- package/dist/core/tokens/formatters/ts-module.js.map +1 -0
- package/dist/core/tokens/index.d.ts +17 -0
- package/dist/core/tokens/index.d.ts.map +1 -0
- package/dist/core/tokens/index.js +16 -0
- package/dist/core/tokens/index.js.map +1 -0
- package/dist/core/tokens/parsers/css-vars.d.ts +3 -0
- package/dist/core/tokens/parsers/css-vars.d.ts.map +1 -0
- package/dist/core/tokens/parsers/css-vars.js +5 -0
- package/dist/core/tokens/parsers/css-vars.js.map +1 -0
- package/dist/core/tokens/parsers/dtcg.d.ts +21 -0
- package/dist/core/tokens/parsers/dtcg.d.ts.map +1 -0
- package/dist/core/tokens/parsers/dtcg.js +254 -0
- package/dist/core/tokens/parsers/dtcg.js.map +1 -0
- package/dist/core/tokens/parsers/index.d.ts +37 -0
- package/dist/core/tokens/parsers/index.d.ts.map +1 -0
- package/dist/core/tokens/parsers/index.js +139 -0
- package/dist/core/tokens/parsers/index.js.map +1 -0
- package/dist/core/tokens/parsers/json.d.ts +4 -0
- package/dist/core/tokens/parsers/json.d.ts.map +1 -0
- package/dist/core/tokens/parsers/json.js +8 -0
- package/dist/core/tokens/parsers/json.js.map +1 -0
- package/dist/core/tokens/parsers/scss.d.ts +3 -0
- package/dist/core/tokens/parsers/scss.d.ts.map +1 -0
- package/dist/core/tokens/parsers/scss.js +5 -0
- package/dist/core/tokens/parsers/scss.js.map +1 -0
- package/dist/core/tokens/parsers/stubs.d.ts +11 -0
- package/dist/core/tokens/parsers/stubs.d.ts.map +1 -0
- package/dist/core/tokens/parsers/stubs.js +14 -0
- package/dist/core/tokens/parsers/stubs.js.map +1 -0
- package/dist/core/tokens/parsers/style-dictionary-v3.d.ts +3 -0
- package/dist/core/tokens/parsers/style-dictionary-v3.d.ts.map +1 -0
- package/dist/core/tokens/parsers/style-dictionary-v3.js +5 -0
- package/dist/core/tokens/parsers/style-dictionary-v3.js.map +1 -0
- package/dist/core/tokens/parsers/tailwind-v3.d.ts +3 -0
- package/dist/core/tokens/parsers/tailwind-v3.d.ts.map +1 -0
- package/dist/core/tokens/parsers/tailwind-v3.js +5 -0
- package/dist/core/tokens/parsers/tailwind-v3.js.map +1 -0
- package/dist/core/tokens/parsers/tailwind-v4.d.ts +3 -0
- package/dist/core/tokens/parsers/tailwind-v4.d.ts.map +1 -0
- package/dist/core/tokens/parsers/tailwind-v4.js +5 -0
- package/dist/core/tokens/parsers/tailwind-v4.js.map +1 -0
- package/dist/core/tokens/parsers/tokens-studio.d.ts +3 -0
- package/dist/core/tokens/parsers/tokens-studio.d.ts.map +1 -0
- package/dist/core/tokens/parsers/tokens-studio.js +5 -0
- package/dist/core/tokens/parsers/tokens-studio.js.map +1 -0
- package/dist/core/tokens/schemas.d.ts +152 -0
- package/dist/core/tokens/schemas.d.ts.map +1 -0
- package/dist/core/tokens/schemas.js +149 -0
- package/dist/core/tokens/schemas.js.map +1 -0
- package/dist/core/tokens/transforms/color.d.ts +9 -0
- package/dist/core/tokens/transforms/color.d.ts.map +1 -0
- package/dist/core/tokens/transforms/color.js +13 -0
- package/dist/core/tokens/transforms/color.js.map +1 -0
- package/dist/core/tokens/transforms/index.d.ts +36 -0
- package/dist/core/tokens/transforms/index.d.ts.map +1 -0
- package/dist/core/tokens/transforms/index.js +30 -0
- package/dist/core/tokens/transforms/index.js.map +1 -0
- package/dist/core/tokens/transforms/size.d.ts +7 -0
- package/dist/core/tokens/transforms/size.d.ts.map +1 -0
- package/dist/core/tokens/transforms/size.js +8 -0
- package/dist/core/tokens/transforms/size.js.map +1 -0
- package/dist/core/tokens/types.d.ts +228 -0
- package/dist/core/tokens/types.d.ts.map +1 -0
- package/dist/core/tokens/types.js +19 -0
- package/dist/core/tokens/types.js.map +1 -0
- package/dist/core/tokens-tools.d.ts +42 -0
- package/dist/core/tokens-tools.d.ts.map +1 -0
- package/dist/core/tokens-tools.js +850 -0
- package/dist/core/tokens-tools.js.map +1 -0
- package/dist/core/types/index.d.ts +0 -8
- package/dist/core/types/index.d.ts.map +1 -1
- package/dist/core/version-tools.d.ts +30 -1
- package/dist/core/version-tools.d.ts.map +1 -1
- package/dist/core/version-tools.js +151 -7
- package/dist/core/version-tools.js.map +1 -1
- package/dist/core/websocket-connector.d.ts +1 -1
- package/dist/core/websocket-connector.d.ts.map +1 -1
- package/dist/core/websocket-server.d.ts +47 -3
- package/dist/core/websocket-server.d.ts.map +1 -1
- package/dist/core/websocket-server.js +77 -55
- package/dist/core/websocket-server.js.map +1 -1
- package/dist/local.d.ts +0 -12
- package/dist/local.d.ts.map +1 -1
- package/dist/local.js +967 -3406
- package/dist/local.js.map +1 -1
- package/figma-desktop-bridge/code.js +59 -63
- package/figma-desktop-bridge/ui.html +85 -11
- package/package.json +12 -30
- package/figma-desktop-bridge/ui-full.html +0 -1353
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tokens.config.json schema, loader, and autodiscovery for the figma-console-mcp
|
|
3
|
+
* token sync engine.
|
|
4
|
+
*
|
|
5
|
+
* Both figma_export_tokens and figma_import_tokens read this single config so
|
|
6
|
+
* follow-up calls in a project are zero-arg. Autodiscovery walks up from the
|
|
7
|
+
* current working directory looking for `tokens.config.json` at each level
|
|
8
|
+
* — same convention as `tsconfig.json`, `package.json`, `.eslintrc`, etc.
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
11
|
+
import { dirname, join, resolve } from "node:path";
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
/**
|
|
14
|
+
* Schema for a single output target in `tokens.config.json`. Each entry
|
|
15
|
+
* produces one or more files when figma_export_tokens runs.
|
|
16
|
+
*/
|
|
17
|
+
const OutputTargetSchema = z.object({
|
|
18
|
+
format: z.enum([
|
|
19
|
+
"dtcg",
|
|
20
|
+
"tokens-studio",
|
|
21
|
+
"css-vars",
|
|
22
|
+
"tailwind-v4",
|
|
23
|
+
"tailwind-v3",
|
|
24
|
+
"scss",
|
|
25
|
+
"less",
|
|
26
|
+
"ts-module",
|
|
27
|
+
"json-flat",
|
|
28
|
+
"json-nested",
|
|
29
|
+
"style-dictionary-v3",
|
|
30
|
+
]),
|
|
31
|
+
/** Optional filename override. Default is derived from format + scope. */
|
|
32
|
+
filename: z.string().optional(),
|
|
33
|
+
/** Output prefix applied to every token name (e.g. "ds-", "al-"). */
|
|
34
|
+
prefix: z.string().optional(),
|
|
35
|
+
/** Emit one file per mode (e.g. tokens-light.css, tokens-dark.css). */
|
|
36
|
+
splitByMode: z.boolean().optional(),
|
|
37
|
+
/** Emit one file per token set / Figma collection. */
|
|
38
|
+
splitByCollection: z.boolean().optional(),
|
|
39
|
+
/**
|
|
40
|
+
* If true, alias references are resolved to literal values in the output.
|
|
41
|
+
* If false, aliases are preserved (default for JSON formats, forced true
|
|
42
|
+
* for CSS/SCSS/Tailwind/etc. since they can't natively express aliases).
|
|
43
|
+
*/
|
|
44
|
+
resolveAliases: z.boolean().optional(),
|
|
45
|
+
/** Per-target transform options. Override the global defaults. */
|
|
46
|
+
transforms: z
|
|
47
|
+
.object({
|
|
48
|
+
colorFormat: z.enum(["hex", "hex8", "rgba", "oklch", "hsl"]).optional(),
|
|
49
|
+
sizeUnit: z.enum(["px", "rem", "pt", "dp"]).optional(),
|
|
50
|
+
remBase: z.number().positive().optional(),
|
|
51
|
+
})
|
|
52
|
+
.optional(),
|
|
53
|
+
});
|
|
54
|
+
/**
|
|
55
|
+
* Full schema for `tokens.config.json`. Every field is optional so the
|
|
56
|
+
* minimum-viable config is `{ "figmaFile": "..." }` — the rest gets sensible
|
|
57
|
+
* defaults.
|
|
58
|
+
*/
|
|
59
|
+
export const TokensConfigSchema = z
|
|
60
|
+
.object({
|
|
61
|
+
/** Optional JSON Schema URL for editor autocompletion. */
|
|
62
|
+
$schema: z.string().optional(),
|
|
63
|
+
/**
|
|
64
|
+
* Figma file URL or fileKey. When omitted, tools fall back to the
|
|
65
|
+
* currently-connected Desktop Bridge plugin's file (Local Mode) or the
|
|
66
|
+
* file context bound by figma_pair_plugin (Cloud Mode).
|
|
67
|
+
*/
|
|
68
|
+
figmaFile: z.string().optional(),
|
|
69
|
+
/** Where the canonical (committed) token sources live. */
|
|
70
|
+
source: z
|
|
71
|
+
.object({
|
|
72
|
+
/** Directory holding the canonical token files. */
|
|
73
|
+
dir: z.string(),
|
|
74
|
+
/** Glob pattern within dir. Default: "*.tokens.json" */
|
|
75
|
+
pattern: z.string().optional(),
|
|
76
|
+
/**
|
|
77
|
+
* Canonical format for source files. DTCG is the recommended default;
|
|
78
|
+
* Tokens Studio is supported for users who already have a `$themes.json`
|
|
79
|
+
* setup (e.g. Altitude).
|
|
80
|
+
*/
|
|
81
|
+
canonical: z.enum(["dtcg", "tokens-studio"]).default("dtcg"),
|
|
82
|
+
})
|
|
83
|
+
.default({ dir: "src/styles/tokens", canonical: "dtcg" }),
|
|
84
|
+
/** Where build outputs (CSS, Tailwind, etc.) get written. */
|
|
85
|
+
generated: z
|
|
86
|
+
.object({
|
|
87
|
+
dir: z.string().default("src/styles/generated"),
|
|
88
|
+
formats: z.array(OutputTargetSchema).default([]),
|
|
89
|
+
})
|
|
90
|
+
.optional(),
|
|
91
|
+
/** Mode name mappings (Figma mode name → output mode name). */
|
|
92
|
+
modes: z
|
|
93
|
+
.object({
|
|
94
|
+
/** e.g. { "Light": "light", "Dark": "dark" } */
|
|
95
|
+
map: z.record(z.string()).optional(),
|
|
96
|
+
/** Default mode if a token has no explicit mode (e.g. "Light"). */
|
|
97
|
+
default: z.string().optional(),
|
|
98
|
+
})
|
|
99
|
+
.optional(),
|
|
100
|
+
/** Default conflict-resolution strategy when not specified per-call. */
|
|
101
|
+
conflictResolution: z
|
|
102
|
+
.enum(["ask", "figma-wins", "code-wins", "skip"])
|
|
103
|
+
.default("ask"),
|
|
104
|
+
/** Behavior for tokens that exist on one side but not the other. */
|
|
105
|
+
sync: z
|
|
106
|
+
.object({
|
|
107
|
+
onMissingInCode: z
|
|
108
|
+
.enum(["preserve", "delete", "warn"])
|
|
109
|
+
.default("preserve"),
|
|
110
|
+
onMissingInFigma: z
|
|
111
|
+
.enum(["preserve", "delete", "warn"])
|
|
112
|
+
.default("preserve"),
|
|
113
|
+
})
|
|
114
|
+
.optional(),
|
|
115
|
+
})
|
|
116
|
+
.strict();
|
|
117
|
+
/**
|
|
118
|
+
* Walk up from `startDir` looking for `tokens.config.json`. Returns the first
|
|
119
|
+
* match, or `null` if none found by the filesystem root.
|
|
120
|
+
*/
|
|
121
|
+
export function findTokensConfig(startDir) {
|
|
122
|
+
let dir = resolve(startDir);
|
|
123
|
+
// Hard cap on directory traversal so a misconfigured startDir can't loop
|
|
124
|
+
// forever (defense against symlinks/weird filesystems).
|
|
125
|
+
const maxDepth = 32;
|
|
126
|
+
for (let i = 0; i < maxDepth; i++) {
|
|
127
|
+
const candidate = join(dir, "tokens.config.json");
|
|
128
|
+
if (existsSync(candidate)) {
|
|
129
|
+
return candidate;
|
|
130
|
+
}
|
|
131
|
+
const parent = dirname(dir);
|
|
132
|
+
if (parent === dir) {
|
|
133
|
+
// Hit filesystem root, no config found.
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
dir = parent;
|
|
137
|
+
}
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Load and validate `tokens.config.json`. If `explicitPath` is provided, uses
|
|
142
|
+
* that; otherwise autodiscovers by walking up from `cwd` (default
|
|
143
|
+
* `process.cwd()`).
|
|
144
|
+
*
|
|
145
|
+
* Returns `null` if no config is found AND no explicit path was given. Throws
|
|
146
|
+
* if an explicit path doesn't exist, or if the discovered file fails schema
|
|
147
|
+
* validation.
|
|
148
|
+
*/
|
|
149
|
+
export function loadTokensConfig(opts = {}) {
|
|
150
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
151
|
+
const configPath = opts.explicitPath
|
|
152
|
+
? resolve(opts.explicitPath)
|
|
153
|
+
: findTokensConfig(cwd);
|
|
154
|
+
if (!configPath)
|
|
155
|
+
return null;
|
|
156
|
+
if (!existsSync(configPath)) {
|
|
157
|
+
throw new Error(`[figma-console-mcp] tokens.config.json not found at ${configPath}`);
|
|
158
|
+
}
|
|
159
|
+
const raw = readFileSync(configPath, "utf-8");
|
|
160
|
+
let parsed;
|
|
161
|
+
try {
|
|
162
|
+
parsed = JSON.parse(raw);
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
throw new Error(`[figma-console-mcp] tokens.config.json at ${configPath} is not valid JSON: ${err instanceof Error ? err.message : String(err)}`);
|
|
166
|
+
}
|
|
167
|
+
const result = TokensConfigSchema.safeParse(parsed);
|
|
168
|
+
if (!result.success) {
|
|
169
|
+
const issues = result.error.issues
|
|
170
|
+
.map((i) => ` • ${i.path.join(".")}: ${i.message}`)
|
|
171
|
+
.join("\n");
|
|
172
|
+
throw new Error(`[figma-console-mcp] tokens.config.json at ${configPath} failed validation:\n${issues}`);
|
|
173
|
+
}
|
|
174
|
+
return {
|
|
175
|
+
config: result.data,
|
|
176
|
+
configPath,
|
|
177
|
+
projectRoot: dirname(configPath),
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Default config used when none is found. Drives the "no-config detected"
|
|
182
|
+
* response shape from figma_export_tokens — the AI uses this to propose a
|
|
183
|
+
* scaffold to the user.
|
|
184
|
+
*/
|
|
185
|
+
export const DEFAULT_TOKENS_CONFIG = {
|
|
186
|
+
source: { dir: "src/styles/tokens", canonical: "dtcg" },
|
|
187
|
+
generated: {
|
|
188
|
+
dir: "src/styles/generated",
|
|
189
|
+
formats: [
|
|
190
|
+
{ format: "css-vars", splitByMode: true },
|
|
191
|
+
],
|
|
192
|
+
},
|
|
193
|
+
conflictResolution: "ask",
|
|
194
|
+
};
|
|
195
|
+
/**
|
|
196
|
+
* Build a `suggestedScaffold` payload returned when a tool is called and no
|
|
197
|
+
* `tokens.config.json` exists. The AI presents this scaffold to the user,
|
|
198
|
+
* writes the files via its native edit/write tools, then calls the original
|
|
199
|
+
* tool again.
|
|
200
|
+
*/
|
|
201
|
+
export function buildSuggestedScaffold(opts) {
|
|
202
|
+
const config = {
|
|
203
|
+
$schema: "https://figma-console-mcp.southleft.com/schemas/tokens.config.v1.json",
|
|
204
|
+
source: { dir: "src/styles/tokens", canonical: "dtcg" },
|
|
205
|
+
generated: {
|
|
206
|
+
dir: "src/styles/generated",
|
|
207
|
+
formats: pickStartingFormats(opts.detectedFramework),
|
|
208
|
+
},
|
|
209
|
+
conflictResolution: "ask",
|
|
210
|
+
};
|
|
211
|
+
const stylesheetImport = pickStylesheetImport(opts.detectedFramework);
|
|
212
|
+
return {
|
|
213
|
+
configContent: JSON.stringify(config, null, 2),
|
|
214
|
+
directories: [config.source.dir, config.generated?.dir ?? "src/styles/generated"],
|
|
215
|
+
stylesheetImport,
|
|
216
|
+
nextSteps: [
|
|
217
|
+
"1. Write `tokens.config.json` at the project root using `configContent`.",
|
|
218
|
+
`2. Create the directories: ${config.source.dir} and ${config.generated?.dir}.`,
|
|
219
|
+
`3. Add this line to your main stylesheet:\n ${stylesheetImport}`,
|
|
220
|
+
"4. Run `figma_export_tokens` again — it'll pick up the new config and populate the source dir.",
|
|
221
|
+
].join("\n"),
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
function pickStartingFormats(framework) {
|
|
225
|
+
// Always emit DTCG as the canonical committed source; layer the
|
|
226
|
+
// framework-appropriate runtime format on top.
|
|
227
|
+
const base = [];
|
|
228
|
+
switch (framework) {
|
|
229
|
+
case "tailwind-v4":
|
|
230
|
+
base.push({ format: "tailwind-v4", splitByMode: true });
|
|
231
|
+
break;
|
|
232
|
+
case "tailwind-v3":
|
|
233
|
+
base.push({ format: "tailwind-v3" });
|
|
234
|
+
break;
|
|
235
|
+
case "scss":
|
|
236
|
+
base.push({ format: "scss", splitByMode: true });
|
|
237
|
+
break;
|
|
238
|
+
case "ts":
|
|
239
|
+
base.push({ format: "ts-module" });
|
|
240
|
+
base.push({ format: "css-vars", splitByMode: true });
|
|
241
|
+
break;
|
|
242
|
+
case "css":
|
|
243
|
+
default:
|
|
244
|
+
base.push({ format: "css-vars", splitByMode: true });
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
return base;
|
|
248
|
+
}
|
|
249
|
+
function pickStylesheetImport(framework) {
|
|
250
|
+
switch (framework) {
|
|
251
|
+
case "tailwind-v4":
|
|
252
|
+
return "@import './styles/generated/tailwind.theme.css';";
|
|
253
|
+
case "scss":
|
|
254
|
+
return "@use './styles/generated/tokens.scss' as *;";
|
|
255
|
+
case "ts":
|
|
256
|
+
case "css":
|
|
257
|
+
default:
|
|
258
|
+
return "@import './styles/generated/tokens.css';";
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Pick the export formats from a loaded config that map to a given runtime
|
|
263
|
+
* format. Used by figma_export_tokens to decide which generated files to
|
|
264
|
+
* write. Returns the list verbatim if the caller passed an explicit format.
|
|
265
|
+
*/
|
|
266
|
+
export function resolveOutputTargets(config, explicitFormat) {
|
|
267
|
+
if (explicitFormat) {
|
|
268
|
+
// Caller specified a format directly; ignore config's generated list.
|
|
269
|
+
return [{ format: explicitFormat }];
|
|
270
|
+
}
|
|
271
|
+
if (!config?.generated?.formats?.length) {
|
|
272
|
+
// No formats configured. Default to DTCG only — produces the canonical
|
|
273
|
+
// source files but no derived runtime outputs.
|
|
274
|
+
return [{ format: "dtcg" }];
|
|
275
|
+
}
|
|
276
|
+
return config.generated.formats;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Resolve the conflict-resolution strategy. Per-call argument wins over config
|
|
280
|
+
* default, which wins over the global default ("ask").
|
|
281
|
+
*/
|
|
282
|
+
export function resolveConflictStrategy(config, perCall) {
|
|
283
|
+
return perCall ?? config?.conflictResolution ?? "ask";
|
|
284
|
+
}
|
|
285
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/core/tokens/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert Figma's variables API response into our canonical TokenDocument.
|
|
3
|
+
*
|
|
4
|
+
* Input: the shape produced by `formatVariables()` in src/core/figma-api.ts
|
|
5
|
+
* (an object with `collections` and `variables` arrays, matching either the
|
|
6
|
+
* REST API's response or the Desktop Bridge plugin's `getLocalVariablesAsync`
|
|
7
|
+
* normalized payload).
|
|
8
|
+
*
|
|
9
|
+
* Output: a TokenDocument with one TokenSet per collection, paths derived
|
|
10
|
+
* from Figma variable names (slash-separated → path arrays), values
|
|
11
|
+
* normalized to our TokenValue shape, and Figma IDs preserved in
|
|
12
|
+
* $extensions["figma-console-mcp"] for round-trip non-destructiveness.
|
|
13
|
+
*/
|
|
14
|
+
import type { TokenDocument } from "./types.js";
|
|
15
|
+
/**
|
|
16
|
+
* Shape of Figma's variable collection as returned by formatVariables(). We
|
|
17
|
+
* use a narrow structural type rather than importing the existing `any`
|
|
18
|
+
* shape from figma-api.ts.
|
|
19
|
+
*/
|
|
20
|
+
interface FigmaCollection {
|
|
21
|
+
id: string;
|
|
22
|
+
name: string;
|
|
23
|
+
key?: string;
|
|
24
|
+
modes: Array<{
|
|
25
|
+
modeId: string;
|
|
26
|
+
name: string;
|
|
27
|
+
}>;
|
|
28
|
+
variableIds: string[];
|
|
29
|
+
}
|
|
30
|
+
interface FigmaVariable {
|
|
31
|
+
id: string;
|
|
32
|
+
name: string;
|
|
33
|
+
key?: string;
|
|
34
|
+
resolvedType: "COLOR" | "FLOAT" | "STRING" | "BOOLEAN";
|
|
35
|
+
variableCollectionId: string;
|
|
36
|
+
description?: string;
|
|
37
|
+
scopes?: string[];
|
|
38
|
+
/**
|
|
39
|
+
* Per-mode values. Each value is either a literal or a `{ type: "VARIABLE_ALIAS", id }`
|
|
40
|
+
* pointing at another variable.
|
|
41
|
+
*/
|
|
42
|
+
valuesByMode: Record<string, FigmaValue>;
|
|
43
|
+
}
|
|
44
|
+
type FigmaValue = {
|
|
45
|
+
r: number;
|
|
46
|
+
g: number;
|
|
47
|
+
b: number;
|
|
48
|
+
a?: number;
|
|
49
|
+
} | number | string | boolean | VariableAlias;
|
|
50
|
+
interface VariableAlias {
|
|
51
|
+
type: "VARIABLE_ALIAS";
|
|
52
|
+
id: string;
|
|
53
|
+
}
|
|
54
|
+
export interface FigmaVariablesPayload {
|
|
55
|
+
collections: FigmaCollection[];
|
|
56
|
+
variables: FigmaVariable[];
|
|
57
|
+
}
|
|
58
|
+
export interface ConvertOptions {
|
|
59
|
+
/** Figma file key. Stored in document metadata. */
|
|
60
|
+
figmaFileKey?: string;
|
|
61
|
+
/** ISO timestamp to stamp the exportedAt field. Defaults to now. */
|
|
62
|
+
exportedAt?: string;
|
|
63
|
+
/** MCP version string. */
|
|
64
|
+
mcpVersion?: string;
|
|
65
|
+
/** Filter to specific collection IDs. Undefined or empty means all. */
|
|
66
|
+
collectionIds?: string[];
|
|
67
|
+
/** Filter to specific mode names. Undefined means all. */
|
|
68
|
+
modes?: string[] | "all";
|
|
69
|
+
/** Optional prefix that gets stripped from variable names on conversion. */
|
|
70
|
+
stripPrefix?: string;
|
|
71
|
+
}
|
|
72
|
+
export interface ConvertResult {
|
|
73
|
+
document: TokenDocument;
|
|
74
|
+
warnings: string[];
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Convert a Figma variables payload to our canonical TokenDocument.
|
|
78
|
+
*/
|
|
79
|
+
export declare function convertFigmaVariablesToDocument(payload: FigmaVariablesPayload, opts?: ConvertOptions): ConvertResult;
|
|
80
|
+
export {};
|
|
81
|
+
//# sourceMappingURL=figma-converter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"figma-converter.d.ts","sourceRoot":"","sources":["../../../src/core/tokens/figma-converter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAEV,aAAa,EAId,MAAM,YAAY,CAAC;AAEpB;;;;GAIG;AACH,UAAU,eAAe;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,UAAU,aAAa;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;IACvD,oBAAoB,EAAE,MAAM,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CAC1C;AAED,KAAK,UAAU,GACX;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/C,MAAM,GACN,MAAM,GACN,OAAO,GACP,aAAa,CAAC;AAElB,UAAU,aAAa;IACrB,IAAI,EAAE,gBAAgB,CAAC;IACvB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,SAAS,EAAE,aAAa,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAC7B,mDAAmD;IACnD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,0DAA0D;IAC1D,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;IACzB,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,aAAa,CAAC;IACxB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,qBAAqB,EAC9B,IAAI,GAAE,cAAmB,GACxB,aAAa,CA6Bf"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert Figma's variables API response into our canonical TokenDocument.
|
|
3
|
+
*
|
|
4
|
+
* Input: the shape produced by `formatVariables()` in src/core/figma-api.ts
|
|
5
|
+
* (an object with `collections` and `variables` arrays, matching either the
|
|
6
|
+
* REST API's response or the Desktop Bridge plugin's `getLocalVariablesAsync`
|
|
7
|
+
* normalized payload).
|
|
8
|
+
*
|
|
9
|
+
* Output: a TokenDocument with one TokenSet per collection, paths derived
|
|
10
|
+
* from Figma variable names (slash-separated → path arrays), values
|
|
11
|
+
* normalized to our TokenValue shape, and Figma IDs preserved in
|
|
12
|
+
* $extensions["figma-console-mcp"] for round-trip non-destructiveness.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Convert a Figma variables payload to our canonical TokenDocument.
|
|
16
|
+
*/
|
|
17
|
+
export function convertFigmaVariablesToDocument(payload, opts = {}) {
|
|
18
|
+
const warnings = [];
|
|
19
|
+
// Build a variable index for alias resolution: variableId → variable
|
|
20
|
+
const variableById = new Map();
|
|
21
|
+
for (const v of payload.variables)
|
|
22
|
+
variableById.set(v.id, v);
|
|
23
|
+
// Filter collections per scope.
|
|
24
|
+
const wantedCollections = opts.collectionIds?.length
|
|
25
|
+
? payload.collections.filter((c) => opts.collectionIds.includes(c.id))
|
|
26
|
+
: payload.collections;
|
|
27
|
+
const sets = wantedCollections.map((collection) => convertCollection(collection, payload.variables, variableById, opts, warnings));
|
|
28
|
+
return {
|
|
29
|
+
document: {
|
|
30
|
+
$schema: "https://figma-console-mcp.southleft.com/schemas/dtcg-extended-v1.json",
|
|
31
|
+
sets,
|
|
32
|
+
meta: {
|
|
33
|
+
figmaFileKey: opts.figmaFileKey,
|
|
34
|
+
exportedAt: opts.exportedAt ?? new Date().toISOString(),
|
|
35
|
+
mcpVersion: opts.mcpVersion,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
warnings,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function convertCollection(collection, allVariables, variableById, opts, warnings) {
|
|
42
|
+
// Mode filter: keep only modes the caller wants, intersected with what
|
|
43
|
+
// the collection actually has.
|
|
44
|
+
const wantedModes = !opts.modes || opts.modes === "all"
|
|
45
|
+
? collection.modes
|
|
46
|
+
: collection.modes.filter((m) => opts.modes.includes(m.name));
|
|
47
|
+
// Variables in this collection.
|
|
48
|
+
const collectionVars = allVariables.filter((v) => v.variableCollectionId === collection.id);
|
|
49
|
+
const tokens = collectionVars.map((variable) => convertVariable(variable, wantedModes, variableById, opts, warnings));
|
|
50
|
+
return {
|
|
51
|
+
name: collection.name,
|
|
52
|
+
modes: wantedModes.map((m) => m.name),
|
|
53
|
+
tokens,
|
|
54
|
+
meta: {
|
|
55
|
+
figmaCollectionId: collection.id,
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function convertVariable(variable, wantedModes, variableById, opts, warnings) {
|
|
60
|
+
// Derive the hierarchical path from the Figma variable name. Figma uses
|
|
61
|
+
// slashes to indicate grouping: "color/brand/primary" → ["color", "brand", "primary"].
|
|
62
|
+
let name = variable.name;
|
|
63
|
+
if (opts.stripPrefix && name.startsWith(opts.stripPrefix)) {
|
|
64
|
+
name = name.slice(opts.stripPrefix.length);
|
|
65
|
+
}
|
|
66
|
+
const path = name.split("/").filter(Boolean);
|
|
67
|
+
// Map resolvedType to TokenType.
|
|
68
|
+
const type = mapResolvedType(variable.resolvedType, variable.name, warnings);
|
|
69
|
+
// Convert each (mode → value) pair to our TokenValue shape, filtered by
|
|
70
|
+
// the wanted modes.
|
|
71
|
+
const values = {};
|
|
72
|
+
for (const mode of wantedModes) {
|
|
73
|
+
const rawValue = variable.valuesByMode[mode.modeId];
|
|
74
|
+
if (rawValue === undefined) {
|
|
75
|
+
warnings.push(`Variable "${variable.name}" has no value for mode "${mode.name}" (${mode.modeId}); skipping that mode.`);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
values[mode.name] = convertValue(rawValue, variable.resolvedType, variableById, warnings);
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
path,
|
|
82
|
+
type,
|
|
83
|
+
description: variable.description || undefined,
|
|
84
|
+
values,
|
|
85
|
+
extensions: {
|
|
86
|
+
"figma-console-mcp": {
|
|
87
|
+
variableId: variable.id,
|
|
88
|
+
collectionId: variable.variableCollectionId,
|
|
89
|
+
lastSyncedAt: new Date().toISOString(),
|
|
90
|
+
// We snapshot the synced value so future merge calls can detect
|
|
91
|
+
// two-sided conflicts.
|
|
92
|
+
lastSyncedValue: { ...values },
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function mapResolvedType(resolvedType, variableName, warnings) {
|
|
98
|
+
switch (resolvedType) {
|
|
99
|
+
case "COLOR":
|
|
100
|
+
return "color";
|
|
101
|
+
case "FLOAT":
|
|
102
|
+
// Figma FLOAT covers both pure numbers and dimensions. We default to
|
|
103
|
+
// "dimension" because the typical FLOAT variable represents spacing,
|
|
104
|
+
// sizing, or radius — all dimensions. A future enhancement could
|
|
105
|
+
// sniff the variable name (e.g. "opacity/*" → "number") for better
|
|
106
|
+
// type fidelity.
|
|
107
|
+
return inferFloatType(variableName);
|
|
108
|
+
case "STRING":
|
|
109
|
+
return inferStringType(variableName);
|
|
110
|
+
case "BOOLEAN":
|
|
111
|
+
return "boolean";
|
|
112
|
+
default: {
|
|
113
|
+
const _exhaustive = resolvedType;
|
|
114
|
+
warnings.push(`Unknown resolvedType "${_exhaustive}" for variable "${variableName}"; treating as string.`);
|
|
115
|
+
return "string";
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function inferFloatType(variableName) {
|
|
120
|
+
const lower = variableName.toLowerCase();
|
|
121
|
+
if (lower.includes("opacity") || lower.includes("alpha"))
|
|
122
|
+
return "number";
|
|
123
|
+
if (lower.includes("font-weight") || lower.includes("weight"))
|
|
124
|
+
return "fontWeight";
|
|
125
|
+
if (lower.includes("duration") || lower.includes("delay"))
|
|
126
|
+
return "duration";
|
|
127
|
+
// Default: treat numeric variables as dimensions (px values).
|
|
128
|
+
return "dimension";
|
|
129
|
+
}
|
|
130
|
+
function inferStringType(variableName) {
|
|
131
|
+
const lower = variableName.toLowerCase();
|
|
132
|
+
if (lower.includes("font-family") || lower.includes("font/family"))
|
|
133
|
+
return "fontFamily";
|
|
134
|
+
return "string";
|
|
135
|
+
}
|
|
136
|
+
function convertValue(rawValue, resolvedType, variableById, warnings) {
|
|
137
|
+
// Alias references: convert variable ID → path-based reference for DTCG.
|
|
138
|
+
if (isVariableAlias(rawValue)) {
|
|
139
|
+
const target = variableById.get(rawValue.id);
|
|
140
|
+
if (!target) {
|
|
141
|
+
// Cross-library alias — target is in a published library this file
|
|
142
|
+
// consumes, not in the local variable set. Preserve the original
|
|
143
|
+
// Figma variable ID in the reference syntax so round-trip can
|
|
144
|
+
// recover it AND formatters can detect this is unresolvable (vs a
|
|
145
|
+
// genuine local-path alias).
|
|
146
|
+
warnings.push(`Alias to unknown variable ID ${rawValue.id} (likely a cross-library reference). Original ID preserved in reference for round-trip.`);
|
|
147
|
+
return { reference: `{__library:${rawValue.id}}` };
|
|
148
|
+
}
|
|
149
|
+
// The DTCG alias path uses dots: "color.brand.primary".
|
|
150
|
+
const dotPath = target.name.replace(/\//g, ".");
|
|
151
|
+
return { reference: `{${dotPath}}` };
|
|
152
|
+
}
|
|
153
|
+
// Literal values per type.
|
|
154
|
+
if (resolvedType === "COLOR") {
|
|
155
|
+
if (typeof rawValue === "object" && rawValue !== null && "r" in rawValue) {
|
|
156
|
+
return { literal: rgbaToHex(rawValue) };
|
|
157
|
+
}
|
|
158
|
+
warnings.push(`COLOR value isn't an RGB object: ${JSON.stringify(rawValue)}`);
|
|
159
|
+
return { literal: String(rawValue) };
|
|
160
|
+
}
|
|
161
|
+
if (resolvedType === "FLOAT") {
|
|
162
|
+
return { literal: typeof rawValue === "number" ? rawValue : Number(rawValue) };
|
|
163
|
+
}
|
|
164
|
+
if (resolvedType === "BOOLEAN") {
|
|
165
|
+
return { literal: Boolean(rawValue) };
|
|
166
|
+
}
|
|
167
|
+
// STRING and fallthrough.
|
|
168
|
+
return { literal: typeof rawValue === "string" ? rawValue : String(rawValue) };
|
|
169
|
+
}
|
|
170
|
+
function isVariableAlias(value) {
|
|
171
|
+
return (typeof value === "object" &&
|
|
172
|
+
value !== null &&
|
|
173
|
+
"type" in value &&
|
|
174
|
+
value.type === "VARIABLE_ALIAS");
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Convert Figma's `{r, g, b, a}` floats (0–1 range) to a hex string. Returns
|
|
178
|
+
* `#RRGGBB` when alpha is 1 (or absent), `#RRGGBBAA` when alpha < 1.
|
|
179
|
+
*/
|
|
180
|
+
function rgbaToHex(rgba) {
|
|
181
|
+
const r = clampByte(rgba.r);
|
|
182
|
+
const g = clampByte(rgba.g);
|
|
183
|
+
const b = clampByte(rgba.b);
|
|
184
|
+
const a = rgba.a ?? 1;
|
|
185
|
+
const hex = `#${byteToHex(r)}${byteToHex(g)}${byteToHex(b)}`;
|
|
186
|
+
if (a >= 1)
|
|
187
|
+
return hex;
|
|
188
|
+
return `${hex}${byteToHex(clampByte(a))}`;
|
|
189
|
+
}
|
|
190
|
+
function clampByte(f) {
|
|
191
|
+
return Math.max(0, Math.min(255, Math.round(f * 255)));
|
|
192
|
+
}
|
|
193
|
+
function byteToHex(byte) {
|
|
194
|
+
return byte.toString(16).padStart(2, "0").toUpperCase();
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=figma-converter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"figma-converter.js","sourceRoot":"","sources":["../../../src/core/tokens/figma-converter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSS custom properties formatter.
|
|
3
|
+
*
|
|
4
|
+
* Converts a TokenDocument to one or more CSS files containing `:root { ... }`
|
|
5
|
+
* (and optionally per-mode selectors like `.dark { ... }`). The first
|
|
6
|
+
* "real" non-DTCG output, completing the canonical-to-runtime pipeline.
|
|
7
|
+
*
|
|
8
|
+
* Behavior:
|
|
9
|
+
* - Each token becomes a CSS custom property. Path joined with `-`,
|
|
10
|
+
* optionally prefixed. `color/primary` → `--color-primary`.
|
|
11
|
+
* - Aliases resolve to `var(--target-token)` so CSS cascading still works.
|
|
12
|
+
* - Composite tokens (typography, shadow) expand into multiple primitive
|
|
13
|
+
* custom properties since CSS doesn't natively express composites.
|
|
14
|
+
* - Single-mode tokens go in `:root`.
|
|
15
|
+
* - Multi-mode tokens emit per-mode selectors. Heuristic: a mode named
|
|
16
|
+
* `Light`/`Default` becomes `:root`; `Dark` becomes `.dark` (Tailwind
|
|
17
|
+
* convention); other modes become `[data-theme="<name>"]`.
|
|
18
|
+
* - splitByMode emits one file per mode with just that mode's values.
|
|
19
|
+
* - splitByCollection emits one file per set.
|
|
20
|
+
*/
|
|
21
|
+
import type { TokenDocument } from "../types.js";
|
|
22
|
+
import type { FormatOptions, FormatResult } from "./index.js";
|
|
23
|
+
export declare function formatCssVars(doc: TokenDocument, opts: FormatOptions): FormatResult;
|
|
24
|
+
//# sourceMappingURL=css-vars.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"css-vars.d.ts","sourceRoot":"","sources":["../../../../src/core/tokens/formatters/css-vars.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAS,aAAa,EAAwB,MAAM,aAAa,CAAC;AAC9E,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE9D,wBAAgB,aAAa,CAC3B,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,aAAa,GAClB,YAAY,CA0Dd"}
|