@figtools/cli 0.1.0 → 0.2.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.es.md CHANGED
@@ -72,10 +72,14 @@ Omite el mensaje `Resolving N URL(s)...` en stderr — útil si estás capturand
72
72
  | `--format` | `json`, `markdown` | `json` | Formato de salida |
73
73
  | `--output` | ruta de archivo o carpeta | stdout (json) / `.` (markdown) | Dónde escribir el resultado |
74
74
  | `--quiet` | — | `false` | Omite el mensaje de progreso en stderr |
75
+ | `--help`, `-h` | — | — | Imprime información de uso y termina |
76
+ | `--version`, `-v` | — | — | Imprime la versión del CLI y termina |
75
77
 
76
78
  ## Troubleshooting
77
79
 
78
80
  - **`Error: unsupported extension "<ext>"`**: con `--format markdown`, `--output` siempre se trata como una carpeta. Con `--format json`, solo se acepta una ruta terminada en `.json` o sin extensión (tratada como carpeta); cualquier otra extensión falla explícitamente.
81
+ - **`--format` argument 'xml' is invalid. Allowed choices are json, markdown.`**: un valor de `--format` no soportado se rechaza explícitamente en vez de caer en `json` en silencio.
82
+ - **`error: unknown option '--foo'`**: una flag no reconocida se rechaza explícitamente en vez de ser ignorada en silencio.
79
83
  - **El proceso termina con código `1` pero imprimió resultados**: significa que al menos una de las URLs falló — revisa el bloque `URLs with errors:` al final de stderr para ver el código (`FigmaScraperErrorCode`) y mensaje de cada una. Ver la tabla de errores en el [README de `@figtools/core`](../core/README.es.md#errores-posibles).
80
84
  - **`figtools login` no avanza**: la ventana de Chromium espera indefinidamente a que termines el login manual; confirma que llegaste a `https://www.figma.com/files/...` antes de cerrar la ventana.
81
85
 
package/README.md CHANGED
@@ -72,10 +72,14 @@ Omits the `Resolving N URL(s)...` message on stderr — useful if you're capturi
72
72
  | `--format` | `json`, `markdown` | `json` | Output format |
73
73
  | `--output` | file or folder path | stdout (json) / `.` (markdown) | Where to write the result |
74
74
  | `--quiet` | — | `false` | Omits the progress message on stderr |
75
+ | `--help`, `-h` | — | — | Prints usage information and exits |
76
+ | `--version`, `-v` | — | — | Prints the CLI's version and exits |
75
77
 
76
78
  ## Troubleshooting
77
79
 
78
80
  - **`Error: unsupported extension "<ext>"`**: with `--format markdown`, `--output` is always treated as a folder. With `--format json`, only a path ending in `.json` or with no extension (treated as a folder) is accepted; any other extension fails explicitly.
81
+ - **`--format` argument 'xml' is invalid. Allowed choices are json, markdown.**: an unsupported `--format` value is rejected explicitly instead of silently falling back to `json`.
82
+ - **`error: unknown option '--foo'`**: an unrecognized flag is rejected explicitly instead of being silently ignored.
79
83
  - **The process exits with code `1` but printed results**: at least one of the URLs failed — check the `URLs with errors:` block at the end of stderr for each one's code (`FigmaScraperErrorCode`) and message. See the error table in the [`@figtools/core` README](../core#possible-errors).
80
84
  - **`figtools login` doesn't progress**: the Chromium window waits indefinitely for you to finish the manual login; confirm you reached `https://www.figma.com/files/...` before closing the window.
81
85
 
package/dist/cli.d.ts CHANGED
@@ -7,15 +7,22 @@ export interface ParsedArgs {
7
7
  command?: "login";
8
8
  }
9
9
  type ParseArgsError = {
10
- code: "VALIDATION_NO_URLS" | "VALIDATION_UNSUPPORTED_EXTENSION";
10
+ code: "VALIDATION_NO_URLS" | "VALIDATION_UNSUPPORTED_EXTENSION" | "COMMANDER_ERROR";
11
11
  message: string;
12
12
  };
13
+ type ParseArgsInfo = {
14
+ code: "HELP_DISPLAYED" | "VERSION_DISPLAYED";
15
+ output: string;
16
+ };
13
17
  export type ParseArgsResult = {
14
18
  ok: true;
15
19
  value: ParsedArgs;
16
20
  } | {
17
21
  ok: false;
18
22
  error: ParseArgsError;
23
+ } | {
24
+ ok: false;
25
+ info: ParseArgsInfo;
19
26
  };
20
27
  export type OutputTarget = {
21
28
  kind: "stdout";
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAYA,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,UAAU,CAAC;AAE/C,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,EAAE,YAAY,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,KAAK,cAAc,GAAG;IACpB,IAAI,EAAE,oBAAoB,GAAG,kCAAkC,CAAC;IAChE,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,eAAe,GACvB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,GAC/B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,cAAc,CAAA;CAAE,CAAC;AAEzC,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,uBAAuB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,eAAe,CA+BzD;AAED,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,MAAM,EAAE,YAAY,GACnB,YAAY,CAad"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,UAAU,CAAC;AAE/C,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,EAAE,YAAY,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,KAAK,cAAc,GAAG;IACpB,IAAI,EAAE,oBAAoB,GAAG,kCAAkC,GAAG,iBAAiB,CAAC;IACpF,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAMF,KAAK,aAAa,GAAG;IAAE,IAAI,EAAE,gBAAgB,GAAG,mBAAmB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtF,MAAM,MAAM,eAAe,GACvB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,GAC/B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,cAAc,CAAA;CAAE,GACpC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,aAAa,CAAA;CAAE,CAAC;AAEvC,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,uBAAuB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AA8DzD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,eAAe,CAmCzD;AAED,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,MAAM,EAAE,YAAY,GACnB,YAAY,CAad"}
package/dist/cli.js CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { extname, join } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
+ import { Command, CommanderError, InvalidArgumentError } from "commander";
4
5
  import { CookieSessionStore, PlaywrightFigmaGateway, PlaywrightLogin, createFigmaScraperCore } from "@figtools/core";
5
6
  import { mkdir, writeFile } from "node:fs/promises";
6
7
  async function resolveAll(core, urls) {
@@ -97,28 +98,89 @@ async function writeAsMarkdownTree(fileKey, result, options) {
97
98
  await writeFile(join(fileKeyDir, "index.md"), containerContent(result.name, result.children, childSlugs), "utf8");
98
99
  for(let i = 0; i < result.children.length; i++)await writeChildNode(result.children[i], fileKeyDir, childSlugs[i]);
99
100
  }
100
- function parseArgs(argv) {
101
- if ("login" === argv[0]) return {
102
- ok: true,
103
- value: {
101
+ var package_namespaceObject = /*#__PURE__*/ JSON.parse('{"rE":"0.2.0","h_":"Resolves one or more Figma URLs from the command line and writes the result as JSON or as a navigable markdown tree meant to be used as a data source by an LLM."}');
102
+ function createProgram() {
103
+ let output = "";
104
+ let parsed;
105
+ const program = new Command().name("figtools").description(package_namespaceObject.h_).version(package_namespaceObject.rE, "-v, --version").exitOverride().configureOutput({
106
+ writeOut: (str)=>{
107
+ output += str;
108
+ },
109
+ writeErr: (str)=>{
110
+ output += str;
111
+ }
112
+ });
113
+ const resolveCommand = program.command("resolve", {
114
+ isDefault: true
115
+ }).description("Resolve one or more Figma URLs and write the result").argument("<urls...>", "One or more Figma URLs to resolve").option("--format <format>", "Output format (json or markdown)", parseFormat, "json").option("--output <path>", "File or directory to write the result to").option("--quiet", "Suppress progress messages on stderr", false).action((urls, opts)=>{
116
+ parsed = {
117
+ urls,
118
+ format: opts.format,
119
+ outputPath: opts.output,
120
+ quiet: opts.quiet
121
+ };
122
+ });
123
+ resolveCommand.exitOverride();
124
+ const loginCommand = program.command("login").description("Force a new interactive login, discarding any saved session").action(()=>{
125
+ parsed = {
104
126
  command: "login",
105
127
  urls: [],
106
128
  format: "json",
107
129
  quiet: false
108
- }
130
+ };
131
+ });
132
+ loginCommand.exitOverride();
133
+ return {
134
+ program,
135
+ getParsed: ()=>parsed,
136
+ getOutput: ()=>output
109
137
  };
110
- let format = "json";
111
- let outputPath;
112
- let quiet = false;
113
- const urls = [];
114
- for(let i = 0; i < argv.length; i++){
115
- const arg = argv[i];
116
- if ("--format" === arg) format = argv[++i];
117
- else if ("--output" === arg) outputPath = argv[++i];
118
- else if ("--quiet" === arg) quiet = true;
119
- else if (!arg.startsWith("--")) urls.push(arg);
138
+ }
139
+ function parseFormat(value) {
140
+ if ("json" !== value && "markdown" !== value) throw new InvalidArgumentError("Allowed choices are json, markdown.");
141
+ return value;
142
+ }
143
+ function parseArgs(argv) {
144
+ const { program, getParsed, getOutput } = createProgram();
145
+ try {
146
+ program.parse(argv, {
147
+ from: "user"
148
+ });
149
+ } catch (err) {
150
+ if (err instanceof CommanderError) {
151
+ if ("commander.helpDisplayed" === err.code) return {
152
+ ok: false,
153
+ info: {
154
+ code: "HELP_DISPLAYED",
155
+ output: getOutput()
156
+ }
157
+ };
158
+ if ("commander.version" === err.code) return {
159
+ ok: false,
160
+ info: {
161
+ code: "VERSION_DISPLAYED",
162
+ output: getOutput()
163
+ }
164
+ };
165
+ if ("commander.missingArgument" === err.code) return {
166
+ ok: false,
167
+ error: {
168
+ code: "VALIDATION_NO_URLS",
169
+ message: "At least one Figma URL is required"
170
+ }
171
+ };
172
+ return {
173
+ ok: false,
174
+ error: {
175
+ code: "COMMANDER_ERROR",
176
+ message: getOutput() || err.message
177
+ }
178
+ };
179
+ }
180
+ throw err;
120
181
  }
121
- if (0 === urls.length) return {
182
+ const value = getParsed();
183
+ if (!value) return {
122
184
  ok: false,
123
185
  error: {
124
186
  code: "VALIDATION_NO_URLS",
@@ -127,12 +189,7 @@ function parseArgs(argv) {
127
189
  };
128
190
  return {
129
191
  ok: true,
130
- value: {
131
- urls,
132
- format,
133
- outputPath,
134
- quiet
135
- }
192
+ value
136
193
  };
137
194
  }
138
195
  function decideOutputTarget(outputPath, format) {
@@ -166,6 +223,10 @@ function extractFileKey(url) {
166
223
  }
167
224
  async function main(argv) {
168
225
  const parsed = parseArgs(argv);
226
+ if (!parsed.ok && "info" in parsed) {
227
+ process.stdout.write(parsed.info.output);
228
+ process.exit(0);
229
+ }
169
230
  if (!parsed.ok) {
170
231
  process.stderr.write(`Error: ${parsed.error.message}\n`);
171
232
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@figtools/cli",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Resolves one or more Figma URLs from the command line and writes the result as JSON or as a navigable markdown tree meant to be used as a data source by an LLM.",
5
5
  "keywords": [
6
6
  "figma",
@@ -34,6 +34,7 @@
34
34
  "access": "public"
35
35
  },
36
36
  "dependencies": {
37
+ "commander": "^15.0.0",
37
38
  "playwright": "^1.61.1",
38
39
  "@figtools/core": "0.1.0"
39
40
  },