@pantoken/cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # @pantoken/cli
2
+
3
+ `pantoken generate <target>` — emit native and other non-npm design-token source into a consumer
4
+ repo. Covers targets that don't fit the npm-package model: native platforms, static-site assets,
5
+ design-tool swatches, and CMS themes.
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ npm i @pantoken/cli
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```sh
16
+ pantoken generate swift --out ./ios/DesignTokens --theme rebrand --class PanTokens
17
+ ```
18
+
19
+ Writes:
20
+
21
+ - `Sources/PanTokens/Tokens.swift` — the generated Swift tokens.
22
+ - `Package.swift` — a SwiftPM manifest stub, so registry publishing is later a config flip.
23
+
24
+ Run it programmatically:
25
+
26
+ ```ts
27
+ import { run } from "@pantoken/cli";
28
+
29
+ await run(["generate", "swift", "--out", "./ios/DesignTokens"]);
30
+ ```
31
+
32
+ ## Targets
33
+
34
+ Supported now: `swift`, `android`, `compose`, `flutter`, `wordpress`, `vanilla`, `drupal`,
35
+ `swatches`, `rust`, `icon-font`, `pendo`, `jekyll`, and `hugo`. Each writes to `--out` and logs the
36
+ files it wrote.
37
+
38
+ ## Flags
39
+
40
+ - `--out <dir>` — output directory (default `./pantoken-out`).
41
+ - `--theme <theme>` — `rebrand` (default), `canvas`, or `canvasHighContrast`.
42
+ - `--class <Name>` — class or font name for targets that generate one (default `PanTokens`).
43
+ - `--icons <a,b,c>` — icon names to emit as native assets, for targets that support icons.
44
+ - `--format <fmt>` — output format for multi-format targets (`swatches`: `ase` / `gpl` / `sketch`;
45
+ `rust`: `egui` / `iced`).
46
+ - `--no-scope`, `--no-important`, `--no-prune` — Pendo target: skip `@scope` wrapping,
47
+ `!important`, or token pruning.
48
+
49
+ ## API
50
+
51
+ - **`run(argv): Promise<void>`** — parse `argv` and generate the target, writing files to disk.
52
+ - **`parseArgs(argv): CliArgs`** — parse `generate <target> [flags]` into a `CliArgs` object.
53
+ - **`CliArgs`** — the parsed invocation shape.
54
+
55
+ ## Related
56
+
57
+ - `@pantoken/core` builds the IR every target emitter consumes.
58
+ - npm-installable targets (React, SCSS, Tailwind, and so on) ship as their own `@pantoken/*`
59
+ packages and don't go through this CLI.
60
+
61
+ ## License
62
+
63
+ MIT
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import { run } from "../dist/index.mjs";
3
+
4
+ run(process.argv.slice(2)).catch((error) => {
5
+ console.error(error instanceof Error ? error.message : error);
6
+ process.exit(1);
7
+ });
@@ -0,0 +1,64 @@
1
+ import { Theme } from "@pantoken/model";
2
+
3
+ //#region src/index.d.ts
4
+ /** The parsed CLI invocation. */
5
+ interface CliArgs {
6
+ command: string;
7
+ target: string;
8
+ out: string;
9
+ theme: Theme;
10
+ className: string;
11
+ /** Icon names to emit as native assets (from `--icons a,b,c`). */
12
+ icons?: string[];
13
+ /** Output format, for targets that support several (e.g. `swatches --format ase`). */
14
+ format?: string;
15
+ /** Pendo: skip `@scope` wrapping (`--no-scope`). */
16
+ noScope?: boolean;
17
+ /** Pendo: skip `!important` (`--no-important`). */
18
+ noImportant?: boolean;
19
+ /** Pendo: skip token pruning (`--no-prune`). */
20
+ noPrune?: boolean;
21
+ }
22
+ /**
23
+ * Parse `generate <target> [--out dir] [--theme t] [--class Name]`.
24
+ *
25
+ * @example Positional target plus value flags
26
+ * ```ts
27
+ * import { parseArgs } from "@pantoken/cli";
28
+ *
29
+ * parseArgs(["generate", "swift", "--out", "./ios", "--theme", "canvas"]);
30
+ * // → { command: "generate", target: "swift", out: "./ios", theme: "canvas",
31
+ * // className: "PanTokens", … }
32
+ * ```
33
+ *
34
+ * @example Boolean flags and a comma-separated --icons list
35
+ * ```ts
36
+ * import { parseArgs } from "@pantoken/cli";
37
+ *
38
+ * const args = parseArgs(["generate", "pendo", "--no-scope", "--icons", "arrow-left,check-mark"]);
39
+ * args.noScope; // → true
40
+ * args.icons; // → ["arrow-left", "check-mark"]
41
+ * ```
42
+ */
43
+ declare function parseArgs(argv: readonly string[]): CliArgs;
44
+ /**
45
+ * Run the CLI.
46
+ *
47
+ * @example Generate Swift tokens into a consumer repo
48
+ * ```ts
49
+ * import { run } from "@pantoken/cli";
50
+ *
51
+ * // Writes Sources/PanTokens/Tokens.swift + Package.swift under ./ios/DesignTokens.
52
+ * await run(["generate", "swift", "--out", "./ios/DesignTokens"]);
53
+ * ```
54
+ *
55
+ * @example Generate a themed swatch palette in a specific format
56
+ * ```ts
57
+ * import { run } from "@pantoken/cli";
58
+ *
59
+ * await run(["generate", "swatches", "--format", "gpl", "--theme", "canvas", "--out", "./out"]);
60
+ * ```
61
+ */
62
+ declare function run(argv: readonly string[]): Promise<void>;
63
+ //#endregion
64
+ export { CliArgs, parseArgs, run };
package/dist/index.mjs ADDED
@@ -0,0 +1,270 @@
1
+ import { mkdirSync, writeFileSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { generateAndroid } from "@pantoken/android";
4
+ import { generateCompose } from "@pantoken/compose";
5
+ import { generateFlutter } from "@pantoken/flutter";
6
+ import { buildIconFont } from "@pantoken/icon-font";
7
+ import { buildPendoCss } from "@pantoken/pendo";
8
+ import { toDrupalTheme } from "@pantoken/drupal";
9
+ import { toHugoAssets } from "@pantoken/hugo";
10
+ import { toJekyllAssets } from "@pantoken/jekyll";
11
+ import { toMintlifyConfig } from "@pantoken/mintlify";
12
+ import { generateRust } from "@pantoken/rust";
13
+ import { toAse, toGpl, toSketchPalette, toSvg, toSwatches } from "@pantoken/swatches";
14
+ import { generateSwift } from "@pantoken/swift";
15
+ import { byTheme } from "@pantoken/tokens";
16
+ import { toVanillaVariables } from "@pantoken/vanilla";
17
+ import { toThemeJson } from "@pantoken/wordpress";
18
+ //#region src/index.ts
19
+ /**
20
+ * `@pantoken/cli` — `pantoken generate <target>`.
21
+ *
22
+ * Emits native and other non-npm design-token source into a consumer repo — the targets that don't
23
+ * fit the npm-package model. Supported now: `swift` (with an SPM `Package.swift` manifest stub, so
24
+ * registry publishing is later a config flip), `android`, `compose`, `flutter`, `wordpress`,
25
+ * `vanilla`, `drupal`, `swatches`, `rust`, `icon-font`, `pendo`, `jekyll`, `hugo`, and `mintlify`.
26
+ *
27
+ * @module
28
+ * @beta
29
+ */
30
+ const SUPPORTED = /* @__PURE__ */ new Set([
31
+ "swift",
32
+ "android",
33
+ "compose",
34
+ "flutter",
35
+ "wordpress",
36
+ "vanilla",
37
+ "drupal",
38
+ "swatches",
39
+ "rust",
40
+ "icon-font",
41
+ "pendo",
42
+ "jekyll",
43
+ "hugo",
44
+ "mintlify"
45
+ ]);
46
+ const PLANNED = /* @__PURE__ */ new Set();
47
+ /**
48
+ * Parse `generate <target> [--out dir] [--theme t] [--class Name]`.
49
+ *
50
+ * @example Positional target plus value flags
51
+ * ```ts
52
+ * import { parseArgs } from "@pantoken/cli";
53
+ *
54
+ * parseArgs(["generate", "swift", "--out", "./ios", "--theme", "canvas"]);
55
+ * // → { command: "generate", target: "swift", out: "./ios", theme: "canvas",
56
+ * // className: "PanTokens", … }
57
+ * ```
58
+ *
59
+ * @example Boolean flags and a comma-separated --icons list
60
+ * ```ts
61
+ * import { parseArgs } from "@pantoken/cli";
62
+ *
63
+ * const args = parseArgs(["generate", "pendo", "--no-scope", "--icons", "arrow-left,check-mark"]);
64
+ * args.noScope; // → true
65
+ * args.icons; // → ["arrow-left", "check-mark"]
66
+ * ```
67
+ */
68
+ function parseArgs(argv) {
69
+ const positionals = [];
70
+ const flags = {};
71
+ for (let i = 0; i < argv.length; i++) {
72
+ const arg = argv[i];
73
+ if (arg.startsWith("--")) {
74
+ const next = argv[i + 1];
75
+ if (next === void 0 || next.startsWith("--")) flags[arg.slice(2)] = "true";
76
+ else flags[arg.slice(2)] = argv[++i];
77
+ } else positionals.push(arg);
78
+ }
79
+ return {
80
+ command: positionals[0] ?? "",
81
+ target: positionals[1] ?? "",
82
+ out: flags.out ?? "./pantoken-out",
83
+ theme: flags.theme ?? "rebrand",
84
+ className: flags.class ?? "PanTokens",
85
+ icons: flags.icons ? flags.icons.split(",").filter(Boolean) : void 0,
86
+ format: flags.format,
87
+ noScope: "no-scope" in flags,
88
+ noImportant: "no-important" in flags,
89
+ noPrune: "no-prune" in flags
90
+ };
91
+ }
92
+ const SWIFT_PACKAGE_MANIFEST = (name) => `// swift-tools-version:5.9
93
+ // Generated by @pantoken/cli — publish to SwiftPM by pushing this package.
94
+ import PackageDescription
95
+
96
+ let package = Package(
97
+ name: "${name}",
98
+ platforms: [.iOS(.v15), .macOS(.v12)],
99
+ products: [.library(name: "${name}", targets: ["${name}"])],
100
+ targets: [.target(name: "${name}", path: "Sources/${name}")]
101
+ )
102
+ `;
103
+ /**
104
+ * Run the CLI.
105
+ *
106
+ * @example Generate Swift tokens into a consumer repo
107
+ * ```ts
108
+ * import { run } from "@pantoken/cli";
109
+ *
110
+ * // Writes Sources/PanTokens/Tokens.swift + Package.swift under ./ios/DesignTokens.
111
+ * await run(["generate", "swift", "--out", "./ios/DesignTokens"]);
112
+ * ```
113
+ *
114
+ * @example Generate a themed swatch palette in a specific format
115
+ * ```ts
116
+ * import { run } from "@pantoken/cli";
117
+ *
118
+ * await run(["generate", "swatches", "--format", "gpl", "--theme", "canvas", "--out", "./out"]);
119
+ * ```
120
+ */
121
+ async function run(argv) {
122
+ const args = parseArgs(argv);
123
+ if (args.command !== "generate") throw new Error(`Unknown command "${args.command}". Usage: pantoken generate <target> [--out dir] [--theme t]`);
124
+ if (PLANNED.has(args.target)) throw new Error(`Target "${args.target}" is planned but not implemented yet. Available now: ${[...SUPPORTED].join(", ")}.`);
125
+ if (!SUPPORTED.has(args.target)) throw new Error(`Unknown target "${args.target}". Available: ${[...SUPPORTED].join(", ")}.`);
126
+ if (args.target === "swift") {
127
+ const file = await generateSwift({
128
+ outDir: join(args.out, "Sources", args.className),
129
+ theme: args.theme,
130
+ className: args.className,
131
+ icons: args.icons
132
+ });
133
+ const manifestPath = join(args.out, "Package.swift");
134
+ mkdirSync(dirname(manifestPath), { recursive: true });
135
+ writeFileSync(manifestPath, SWIFT_PACKAGE_MANIFEST(args.className));
136
+ console.log(`✓ pantoken: wrote ${file}`);
137
+ console.log(`✓ pantoken: wrote ${manifestPath} (SwiftPM manifest stub)`);
138
+ return;
139
+ }
140
+ if (args.target === "android") {
141
+ const files = await generateAndroid({
142
+ outDir: args.out,
143
+ theme: args.theme,
144
+ icons: args.icons
145
+ });
146
+ for (const file of files) console.log(`✓ pantoken: wrote ${file}`);
147
+ return;
148
+ }
149
+ if (args.target === "compose") {
150
+ const file = await generateCompose({
151
+ outDir: args.out,
152
+ theme: args.theme,
153
+ className: args.className
154
+ });
155
+ console.log(`✓ pantoken: wrote ${file}`);
156
+ return;
157
+ }
158
+ if (args.target === "flutter") {
159
+ const file = await generateFlutter({
160
+ outDir: args.out,
161
+ theme: args.theme,
162
+ className: args.className,
163
+ icons: args.icons
164
+ });
165
+ console.log(`✓ pantoken: wrote ${file}`);
166
+ return;
167
+ }
168
+ if (args.target === "wordpress") {
169
+ mkdirSync(args.out, { recursive: true });
170
+ const file = join(args.out, "theme.json");
171
+ writeFileSync(file, `${JSON.stringify(toThemeJson(byTheme(args.theme)), null, 2)}\n`);
172
+ console.log(`✓ pantoken: wrote ${file}`);
173
+ return;
174
+ }
175
+ if (args.target === "vanilla") {
176
+ mkdirSync(args.out, { recursive: true });
177
+ const file = join(args.out, "variables.json");
178
+ writeFileSync(file, `${JSON.stringify(toVanillaVariables(byTheme(args.theme)), null, 2)}\n`);
179
+ console.log(`✓ pantoken: wrote ${file}`);
180
+ return;
181
+ }
182
+ if (args.target === "mintlify") {
183
+ mkdirSync(args.out, { recursive: true });
184
+ const file = join(args.out, "docs.json");
185
+ writeFileSync(file, `${JSON.stringify(toMintlifyConfig(byTheme(args.theme)), null, 2)}\n`);
186
+ console.log(`✓ pantoken: wrote ${file}`);
187
+ return;
188
+ }
189
+ if (args.target === "drupal") {
190
+ for (const asset of toDrupalTheme()) {
191
+ const file = join(args.out, asset.path);
192
+ mkdirSync(dirname(file), { recursive: true });
193
+ writeFileSync(file, asset.content);
194
+ console.log(`✓ pantoken: wrote ${file}`);
195
+ }
196
+ return;
197
+ }
198
+ if (args.target === "rust") {
199
+ const format = args.format === "iced" ? "iced" : "egui";
200
+ const file = args.out.includes(".") ? args.out : join(args.out, "tokens.rs");
201
+ mkdirSync(dirname(file), { recursive: true });
202
+ writeFileSync(file, generateRust({
203
+ format,
204
+ theme: args.theme
205
+ }));
206
+ console.log(`✓ pantoken: wrote ${file}`);
207
+ return;
208
+ }
209
+ if (args.target === "swatches") {
210
+ const format = args.format ?? "ase";
211
+ const swatches = toSwatches(byTheme(args.theme));
212
+ const ext = format === "sketch" ? "sketchpalette" : format;
213
+ const file = args.out.includes(".") ? args.out : join(args.out, `instructure.${ext}`);
214
+ mkdirSync(dirname(file), { recursive: true });
215
+ if (format === "ase") writeFileSync(file, toAse(swatches));
216
+ else if (format === "gpl") writeFileSync(file, toGpl(swatches));
217
+ else if (format === "sketch") writeFileSync(file, `${JSON.stringify(toSketchPalette(swatches), null, 2)}\n`);
218
+ else if (format === "svg") writeFileSync(file, toSvg(swatches));
219
+ else throw new Error(`Unknown swatch format "${format}". Use ase, gpl, sketch, or svg.`);
220
+ console.log(`✓ pantoken: wrote ${file}`);
221
+ return;
222
+ }
223
+ if (args.target === "icon-font") {
224
+ const font = await buildIconFont({
225
+ theme: args.theme,
226
+ icons: args.icons,
227
+ fontName: args.className
228
+ });
229
+ mkdirSync(args.out, { recursive: true });
230
+ const ttf = join(args.out, `${args.className}.ttf`);
231
+ const woff2 = join(args.out, `${args.className}.woff2`);
232
+ const cssFile = join(args.out, "icons.css");
233
+ const codepoints = join(args.out, "codepoints.json");
234
+ writeFileSync(ttf, font.ttf);
235
+ writeFileSync(woff2, font.woff2);
236
+ writeFileSync(cssFile, font.css);
237
+ writeFileSync(codepoints, `${JSON.stringify(font.codepoints, null, 2)}\n`);
238
+ for (const file of [
239
+ ttf,
240
+ woff2,
241
+ cssFile,
242
+ codepoints
243
+ ]) console.log(`✓ pantoken: wrote ${file}`);
244
+ return;
245
+ }
246
+ if (args.target === "jekyll" || args.target === "hugo") {
247
+ const assets = args.target === "jekyll" ? toJekyllAssets() : toHugoAssets();
248
+ for (const asset of assets) {
249
+ const file = join(args.out, asset.path);
250
+ mkdirSync(dirname(file), { recursive: true });
251
+ writeFileSync(file, asset.content);
252
+ console.log(`✓ pantoken: wrote ${file}`);
253
+ }
254
+ return;
255
+ }
256
+ if (args.target === "pendo") {
257
+ mkdirSync(args.out, { recursive: true });
258
+ const file = join(args.out, "global.css");
259
+ writeFileSync(file, buildPendoCss({
260
+ theme: args.theme,
261
+ scope: !args.noScope,
262
+ important: !args.noImportant,
263
+ prune: !args.noPrune
264
+ }));
265
+ console.log(`✓ pantoken: wrote ${file}`);
266
+ return;
267
+ }
268
+ }
269
+ //#endregion
270
+ export { parseArgs, run };
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@pantoken/cli",
3
+ "version": "0.1.0",
4
+ "description": "pantoken generate <target> — emit native design-token source (Swift now; Kotlin/Dart/Drupal to follow).",
5
+ "license": "MIT",
6
+ "bin": {
7
+ "pantoken": "bin/pantoken.mjs"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "bin"
12
+ ],
13
+ "type": "module",
14
+ "exports": {
15
+ ".": "./dist/index.mjs",
16
+ "./package.json": "./package.json"
17
+ },
18
+ "publishConfig": {
19
+ "access": "public"
20
+ },
21
+ "dependencies": {
22
+ "@pantoken/android": "0.1.0",
23
+ "@pantoken/drupal": "0.1.0",
24
+ "@pantoken/flutter": "0.1.0",
25
+ "@pantoken/compose": "0.1.0",
26
+ "@pantoken/hugo": "0.1.0",
27
+ "@pantoken/icon-font": "0.1.0",
28
+ "@pantoken/mintlify": "0.1.0",
29
+ "@pantoken/model": "0.1.0",
30
+ "@pantoken/pendo": "0.1.0",
31
+ "@pantoken/rust": "0.1.0",
32
+ "@pantoken/swift": "0.1.0",
33
+ "@pantoken/swatches": "0.1.0",
34
+ "@pantoken/jekyll": "0.1.0",
35
+ "@pantoken/tokens": "0.1.0",
36
+ "@pantoken/vanilla": "0.1.0",
37
+ "@pantoken/wordpress": "0.1.0"
38
+ },
39
+ "devDependencies": {
40
+ "@types/node": "^24.13.3",
41
+ "typescript": "^6.0.3",
42
+ "vite": "npm:@voidzero-dev/vite-plus-core@0.2.4",
43
+ "vite-plus": "0.2.4"
44
+ },
45
+ "scripts": {
46
+ "build": "vp pack",
47
+ "dev": "vp pack --watch",
48
+ "test": "vp test",
49
+ "check": "vp check"
50
+ }
51
+ }