trans-spec 1.0.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/cli/index.js ADDED
@@ -0,0 +1,329 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { program } from "commander";
4
+ import chalk from "chalk";
5
+ import path from "path";
6
+ import { checkAuth } from "./src/auth.js";
7
+ import { setup } from "./src/setup.js";
8
+ import { generateConfig } from "./src/config.js";
9
+ import { translate } from "./src/translate.js";
10
+ const TRANSSPEC_DIR = ".trans-spec";
11
+ const EJECTED_VIEWER_DIR = "trans-spec-viewer";
12
+
13
+ program
14
+ .name("trans-spec")
15
+ .description("Translate your OpenAPI spec into multiple languages")
16
+ .version("1.0.0");
17
+
18
+ program
19
+ .command("generate")
20
+ .description("Translate an OpenAPI spec into multiple languages")
21
+ .requiredOption("--spec <path>", "Path to your OpenAPI spec file")
22
+ .option("--languages <languages>", "Target languages e.g. es,fr,de")
23
+ .option("--source <language>", "Source language (default: en)", "en")
24
+ .action(async (options) => {
25
+ console.log(chalk.bold("\nšŸŒ Trans-Spec\n"));
26
+
27
+ // Step 1: Check authentication
28
+ await checkAuth();
29
+
30
+ // Step 2: Setup folder structure and copy spec
31
+ await setup(options.spec, options.source);
32
+
33
+ // Step 3: Generate i18n.json config
34
+ const targets = await generateConfig(options.languages, options.source);
35
+
36
+ // Step 4: Run translations
37
+ await translate(targets);
38
+
39
+ // Step 5: Tell user where their files are
40
+ console.log(chalk.bold("\nāœ” Done! Your translated specs are in:\n"));
41
+ targets.forEach((lang) => {
42
+ console.log(chalk.cyan(` ${TRANSSPEC_DIR}/i18n/${lang}/api.yaml`));
43
+ });
44
+ console.log(chalk.white("\nTo view your docs, run:"));
45
+ console.log(chalk.cyan(" npx trans-spec serve\n"));
46
+ });
47
+
48
+ program
49
+ .command("eject")
50
+ .description(
51
+ `Copy the viewer source into ./${EJECTED_VIEWER_DIR} so you can customize and deploy it`,
52
+ )
53
+ .action(async () => {
54
+ const fs = await import("fs");
55
+ const { fileURLToPath } = await import("url");
56
+
57
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
58
+ const packageViewerDir = path.resolve(__dirname, "../viewer");
59
+ const ejectedViewerDir = path.join(process.cwd(), EJECTED_VIEWER_DIR);
60
+
61
+ console.log(chalk.bold("\nšŸ“¦ Trans-Spec Eject\n"));
62
+
63
+ if (!fs.existsSync(packageViewerDir)) {
64
+ console.log(
65
+ chalk.red("āœ– Could not find the viewer source inside the package."),
66
+ );
67
+ console.log(chalk.gray(` Looked in: ${packageViewerDir}`));
68
+ process.exit(1);
69
+ }
70
+
71
+ if (fs.existsSync(ejectedViewerDir)) {
72
+ console.log(
73
+ chalk.red(
74
+ `āœ– ${EJECTED_VIEWER_DIR}/ already exists. Remove it first if you want to eject again.\n`,
75
+ ),
76
+ );
77
+ process.exit(1);
78
+ }
79
+
80
+ console.log(
81
+ chalk.white(
82
+ `Copying viewer into ${chalk.cyan(EJECTED_VIEWER_DIR + "/")}...\n`,
83
+ ),
84
+ );
85
+
86
+ try {
87
+ console.log(chalk.gray(` From: ${packageViewerDir}`));
88
+ console.log(chalk.gray(` To: ${ejectedViewerDir}`));
89
+ fs.cpSync(packageViewerDir, ejectedViewerDir, {
90
+ recursive: true,
91
+ filter: (src) => {
92
+ const parts = src.replace(packageViewerDir, "").split(path.sep);
93
+ return !parts.includes("node_modules");
94
+ },
95
+ });
96
+ } catch (err) {
97
+ console.log(chalk.red("\nāœ– Failed to copy viewer files:"));
98
+ console.log(err);
99
+ process.exit(1);
100
+ }
101
+
102
+ console.log(chalk.green(`āœ” Viewer ejected to ${EJECTED_VIEWER_DIR}/\n`));
103
+ console.log(chalk.white("Next steps:"));
104
+ console.log(chalk.cyan(` cd ${EJECTED_VIEWER_DIR} && npm install`));
105
+ console.log(
106
+ chalk.white("\nThe viewer will be used automatically when you run:"),
107
+ );
108
+ console.log(chalk.cyan(" npx trans-spec serve\n"));
109
+ console.log(chalk.white("Or run it directly for full control:"));
110
+ console.log(chalk.cyan(` cd ${EJECTED_VIEWER_DIR} && npm run dev\n`));
111
+ });
112
+
113
+ program
114
+ .command("serve")
115
+ .description("Start the local docs viewer")
116
+ .option("-p, --port <port>", "Port to run server on", "3000")
117
+ .action(async (options) => {
118
+ const { spawn, execSync } = await import("child_process");
119
+ const path = await import("path");
120
+ const fs = await import("fs");
121
+ const readline = await import("readline");
122
+ const { fileURLToPath } = await import("url");
123
+
124
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
125
+
126
+ // Prefer ejected viewer in cwd over the package viewer
127
+ const ejectedViewerDir = path.join(process.cwd(), EJECTED_VIEWER_DIR);
128
+ const packageViewerDir = path.resolve(__dirname, "../viewer");
129
+ const isEjected = fs.existsSync(ejectedViewerDir);
130
+ const viewerDir = isEjected ? ejectedViewerDir : packageViewerDir;
131
+
132
+ if (isEjected) {
133
+ console.log(
134
+ chalk.cyan(`\nšŸ”§ Using ejected viewer from ./${EJECTED_VIEWER_DIR}\n`),
135
+ );
136
+ }
137
+
138
+ const publicDir = path.join(viewerDir, "public");
139
+ const transSpecSource = path.join(process.cwd(), ".trans-spec");
140
+ const transSpecDest = path.join(publicDir, "trans-spec");
141
+
142
+ // Check if .trans-spec exists
143
+ if (!fs.existsSync(transSpecSource)) {
144
+ console.log(
145
+ chalk.red("\nāœ– No .trans-spec folder found in current directory"),
146
+ );
147
+ console.log(
148
+ chalk.white(
149
+ "Run: npx trans-spec generate --spec api.yaml --languages es,fr first\n",
150
+ ),
151
+ );
152
+ process.exit(1);
153
+ }
154
+
155
+ // Read API spec languages
156
+ const i18nConfig = JSON.parse(
157
+ fs.readFileSync(path.join(transSpecSource, "i18n.json"), "utf-8"),
158
+ );
159
+ const sourceLocale = i18nConfig.locale.source;
160
+ const targetLocales = i18nConfig.locale.targets;
161
+
162
+ console.log(chalk.cyan("\nšŸš€ Starting Trans-Spec viewer...\n"));
163
+
164
+ // Check for API key and prompt if not found
165
+ let apiKey = process.env.LINGODOTDEV_API_KEY;
166
+ const envPath = path.join(viewerDir, ".env");
167
+
168
+ // Check if API key exists in viewer/.env
169
+ if (!apiKey && fs.existsSync(envPath)) {
170
+ const envContent = fs.readFileSync(envPath, "utf-8");
171
+ const match = envContent.match(/LINGODOTDEV_API_KEY=(.+)/);
172
+ if (match) {
173
+ apiKey = match[1].trim();
174
+ }
175
+ }
176
+
177
+ // Prompt for API key if not found
178
+ if (!apiKey) {
179
+ console.log(chalk.yellow("⚠ Lingo.dev API key not found.\n"));
180
+ console.log(chalk.white("To get your API key:"));
181
+ console.log(chalk.cyan(" 1. Visit https://lingo.dev"));
182
+ console.log(chalk.cyan(" 2. Sign in and go to Settings"));
183
+ console.log(chalk.cyan(" 3. Copy your API key\n"));
184
+
185
+ const rl = readline.createInterface({
186
+ input: process.stdin,
187
+ output: process.stdout,
188
+ });
189
+
190
+ apiKey = await new Promise((resolve) => {
191
+ rl.question(chalk.white("Enter your Lingo.dev API key: "), (answer) => {
192
+ rl.close();
193
+ resolve(answer.trim());
194
+ });
195
+ });
196
+
197
+ if (!apiKey) {
198
+ console.log(chalk.red("\nāœ– API key is required to run the viewer"));
199
+ process.exit(1);
200
+ }
201
+
202
+ // Save API key to viewer/.env for future use
203
+ let existingEnv = "";
204
+ if (fs.existsSync(envPath)) {
205
+ existingEnv = fs.readFileSync(envPath, "utf-8");
206
+ // Remove existing LINGODOTDEV_API_KEY line if present
207
+ existingEnv = existingEnv
208
+ .split("\n")
209
+ .filter((line) => !line.startsWith("LINGODOTDEV_API_KEY="))
210
+ .join("\n");
211
+ }
212
+ // Add the new API key
213
+ const newEnvContent = existingEnv
214
+ ? `${existingEnv}\nLINGODOTDEV_API_KEY=${apiKey}\n`
215
+ : `LINGODOTDEV_API_KEY=${apiKey}\n`;
216
+
217
+ fs.writeFileSync(envPath, newEnvContent);
218
+ console.log(chalk.green("\nāœ” API key saved to viewer/.env\n"));
219
+ } else {
220
+ console.log(chalk.green("āœ” API key found\n"));
221
+ }
222
+
223
+ // Copy .trans-spec to viewer/public
224
+ if (fs.existsSync(transSpecDest)) {
225
+ fs.rmSync(transSpecDest, { recursive: true });
226
+ }
227
+ fs.cpSync(transSpecSource, transSpecDest, { recursive: true });
228
+
229
+ // Create index of available spec files
230
+ const specI18nDir = path.join(transSpecSource, "i18n");
231
+ const languages = fs.readdirSync(specI18nDir);
232
+ const index = {};
233
+
234
+ languages.forEach((lang) => {
235
+ const langDir = path.join(specI18nDir, lang);
236
+ const files = fs
237
+ .readdirSync(langDir)
238
+ .filter((f) => f.endsWith(".yaml") || f.endsWith(".yml"))
239
+ .sort();
240
+
241
+ index[lang] = files;
242
+ });
243
+
244
+ fs.writeFileSync(
245
+ path.join(transSpecDest, "index.json"),
246
+ JSON.stringify(index, null, 2),
247
+ );
248
+
249
+ // Generate Vite config with Compiler
250
+ const viteConfigContent = `import { defineConfig } from 'vite'
251
+ import react from '@vitejs/plugin-react'
252
+ import { lingoCompilerPlugin } from '@lingo.dev/compiler/vite'
253
+ import tailwindcss from "@tailwindcss/vite";
254
+
255
+ export default defineConfig({
256
+ plugins: [
257
+ lingoCompilerPlugin({
258
+ sourceRoot: 'src',
259
+ sourceLocale: '${sourceLocale}',
260
+ targetLocales: ${JSON.stringify(targetLocales)},
261
+ models: 'lingo.dev',
262
+ dev: {
263
+ usePseudotranslator: false,
264
+ },
265
+ }),
266
+ react(),
267
+ tailwindcss(),
268
+ ],
269
+ })
270
+ `;
271
+
272
+ fs.writeFileSync(
273
+ path.join(viewerDir, "vite.config.generated.js"),
274
+ viteConfigContent,
275
+ );
276
+
277
+ console.log(chalk.green("āœ” Setup complete"));
278
+ // Install viewer dependencies if needed
279
+ const viewerNodeModules = path.join(viewerDir, "node_modules");
280
+ if (!fs.existsSync(viewerNodeModules)) {
281
+ console.log(
282
+ chalk.yellow(
283
+ "\nšŸ“¦ Installing viewer dependencies (one-time setup)...\n",
284
+ ),
285
+ );
286
+
287
+ try {
288
+ execSync("npm install", {
289
+ cwd: viewerDir,
290
+ stdio: "inherit",
291
+ shell: true,
292
+ });
293
+ console.log(chalk.green("\nāœ” Dependencies installed\n"));
294
+ } catch (err) {
295
+ console.log(chalk.red("\nāœ– Failed to install dependencies"));
296
+ console.log(err);
297
+ process.exit(1);
298
+ }
299
+ }
300
+ console.log(
301
+ chalk.cyan(`\nStarting server on http://localhost:${options.port}\n`),
302
+ );
303
+
304
+ // Start server
305
+ const server = spawn(
306
+ "npm",
307
+ [
308
+ "run",
309
+ "dev",
310
+ "--",
311
+ "--config",
312
+ "vite.config.generated.js",
313
+ "--port",
314
+ options.port,
315
+ ],
316
+ {
317
+ cwd: viewerDir,
318
+ stdio: "inherit",
319
+ shell: true,
320
+ },
321
+ );
322
+
323
+ server.on("error", (err) => {
324
+ console.log(chalk.red("Failed to start viewer:", err.message));
325
+ process.exit(1);
326
+ });
327
+ });
328
+
329
+ program.parse();
@@ -0,0 +1,278 @@
1
+ {
2
+ "name": "cli",
3
+ "version": "1.0.0",
4
+ "lockfileVersion": 3,
5
+ "requires": true,
6
+ "packages": {
7
+ "": {
8
+ "name": "cli",
9
+ "version": "1.0.0",
10
+ "license": "ISC",
11
+ "dependencies": {
12
+ "chalk": "^5.6.2",
13
+ "commander": "^14.0.3",
14
+ "dotenv": "^17.3.1",
15
+ "ora": "^9.3.0"
16
+ },
17
+ "bin": {
18
+ "trans-spec": "index.js"
19
+ }
20
+ },
21
+ "node_modules/ansi-regex": {
22
+ "version": "6.2.2",
23
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
24
+ "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
25
+ "license": "MIT",
26
+ "engines": {
27
+ "node": ">=12"
28
+ },
29
+ "funding": {
30
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
31
+ }
32
+ },
33
+ "node_modules/chalk": {
34
+ "version": "5.6.2",
35
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
36
+ "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==",
37
+ "license": "MIT",
38
+ "engines": {
39
+ "node": "^12.17.0 || ^14.13 || >=16.0.0"
40
+ },
41
+ "funding": {
42
+ "url": "https://github.com/chalk/chalk?sponsor=1"
43
+ }
44
+ },
45
+ "node_modules/cli-cursor": {
46
+ "version": "5.0.0",
47
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz",
48
+ "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==",
49
+ "license": "MIT",
50
+ "dependencies": {
51
+ "restore-cursor": "^5.0.0"
52
+ },
53
+ "engines": {
54
+ "node": ">=18"
55
+ },
56
+ "funding": {
57
+ "url": "https://github.com/sponsors/sindresorhus"
58
+ }
59
+ },
60
+ "node_modules/cli-spinners": {
61
+ "version": "3.4.0",
62
+ "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-3.4.0.tgz",
63
+ "integrity": "sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw==",
64
+ "license": "MIT",
65
+ "engines": {
66
+ "node": ">=18.20"
67
+ },
68
+ "funding": {
69
+ "url": "https://github.com/sponsors/sindresorhus"
70
+ }
71
+ },
72
+ "node_modules/commander": {
73
+ "version": "14.0.3",
74
+ "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz",
75
+ "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==",
76
+ "license": "MIT",
77
+ "engines": {
78
+ "node": ">=20"
79
+ }
80
+ },
81
+ "node_modules/dotenv": {
82
+ "version": "17.3.1",
83
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.3.1.tgz",
84
+ "integrity": "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==",
85
+ "license": "BSD-2-Clause",
86
+ "engines": {
87
+ "node": ">=12"
88
+ },
89
+ "funding": {
90
+ "url": "https://dotenvx.com"
91
+ }
92
+ },
93
+ "node_modules/get-east-asian-width": {
94
+ "version": "1.4.0",
95
+ "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz",
96
+ "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==",
97
+ "license": "MIT",
98
+ "engines": {
99
+ "node": ">=18"
100
+ },
101
+ "funding": {
102
+ "url": "https://github.com/sponsors/sindresorhus"
103
+ }
104
+ },
105
+ "node_modules/is-interactive": {
106
+ "version": "2.0.0",
107
+ "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz",
108
+ "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==",
109
+ "license": "MIT",
110
+ "engines": {
111
+ "node": ">=12"
112
+ },
113
+ "funding": {
114
+ "url": "https://github.com/sponsors/sindresorhus"
115
+ }
116
+ },
117
+ "node_modules/is-unicode-supported": {
118
+ "version": "2.1.0",
119
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz",
120
+ "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==",
121
+ "license": "MIT",
122
+ "engines": {
123
+ "node": ">=18"
124
+ },
125
+ "funding": {
126
+ "url": "https://github.com/sponsors/sindresorhus"
127
+ }
128
+ },
129
+ "node_modules/log-symbols": {
130
+ "version": "7.0.1",
131
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-7.0.1.tgz",
132
+ "integrity": "sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==",
133
+ "license": "MIT",
134
+ "dependencies": {
135
+ "is-unicode-supported": "^2.0.0",
136
+ "yoctocolors": "^2.1.1"
137
+ },
138
+ "engines": {
139
+ "node": ">=18"
140
+ },
141
+ "funding": {
142
+ "url": "https://github.com/sponsors/sindresorhus"
143
+ }
144
+ },
145
+ "node_modules/mimic-function": {
146
+ "version": "5.0.1",
147
+ "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz",
148
+ "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==",
149
+ "license": "MIT",
150
+ "engines": {
151
+ "node": ">=18"
152
+ },
153
+ "funding": {
154
+ "url": "https://github.com/sponsors/sindresorhus"
155
+ }
156
+ },
157
+ "node_modules/onetime": {
158
+ "version": "7.0.0",
159
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz",
160
+ "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==",
161
+ "license": "MIT",
162
+ "dependencies": {
163
+ "mimic-function": "^5.0.0"
164
+ },
165
+ "engines": {
166
+ "node": ">=18"
167
+ },
168
+ "funding": {
169
+ "url": "https://github.com/sponsors/sindresorhus"
170
+ }
171
+ },
172
+ "node_modules/ora": {
173
+ "version": "9.3.0",
174
+ "resolved": "https://registry.npmjs.org/ora/-/ora-9.3.0.tgz",
175
+ "integrity": "sha512-lBX72MWFduWEf7v7uWf5DHp9Jn5BI8bNPGuFgtXMmr2uDz2Gz2749y3am3agSDdkhHPHYmmxEGSKH85ZLGzgXw==",
176
+ "license": "MIT",
177
+ "dependencies": {
178
+ "chalk": "^5.6.2",
179
+ "cli-cursor": "^5.0.0",
180
+ "cli-spinners": "^3.2.0",
181
+ "is-interactive": "^2.0.0",
182
+ "is-unicode-supported": "^2.1.0",
183
+ "log-symbols": "^7.0.1",
184
+ "stdin-discarder": "^0.3.1",
185
+ "string-width": "^8.1.0"
186
+ },
187
+ "engines": {
188
+ "node": ">=20"
189
+ },
190
+ "funding": {
191
+ "url": "https://github.com/sponsors/sindresorhus"
192
+ }
193
+ },
194
+ "node_modules/restore-cursor": {
195
+ "version": "5.1.0",
196
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz",
197
+ "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==",
198
+ "license": "MIT",
199
+ "dependencies": {
200
+ "onetime": "^7.0.0",
201
+ "signal-exit": "^4.1.0"
202
+ },
203
+ "engines": {
204
+ "node": ">=18"
205
+ },
206
+ "funding": {
207
+ "url": "https://github.com/sponsors/sindresorhus"
208
+ }
209
+ },
210
+ "node_modules/signal-exit": {
211
+ "version": "4.1.0",
212
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
213
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
214
+ "license": "ISC",
215
+ "engines": {
216
+ "node": ">=14"
217
+ },
218
+ "funding": {
219
+ "url": "https://github.com/sponsors/isaacs"
220
+ }
221
+ },
222
+ "node_modules/stdin-discarder": {
223
+ "version": "0.3.1",
224
+ "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.3.1.tgz",
225
+ "integrity": "sha512-reExS1kSGoElkextOcPkel4NE99S0BWxjUHQeDFnR8S993JxpPX7KU4MNmO19NXhlJp+8dmdCbKQVNgLJh2teA==",
226
+ "license": "MIT",
227
+ "engines": {
228
+ "node": ">=18"
229
+ },
230
+ "funding": {
231
+ "url": "https://github.com/sponsors/sindresorhus"
232
+ }
233
+ },
234
+ "node_modules/string-width": {
235
+ "version": "8.1.1",
236
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.1.1.tgz",
237
+ "integrity": "sha512-KpqHIdDL9KwYk22wEOg/VIqYbrnLeSApsKT/bSj6Ez7pn3CftUiLAv2Lccpq1ALcpLV9UX1Ppn92npZWu2w/aw==",
238
+ "license": "MIT",
239
+ "dependencies": {
240
+ "get-east-asian-width": "^1.3.0",
241
+ "strip-ansi": "^7.1.0"
242
+ },
243
+ "engines": {
244
+ "node": ">=20"
245
+ },
246
+ "funding": {
247
+ "url": "https://github.com/sponsors/sindresorhus"
248
+ }
249
+ },
250
+ "node_modules/strip-ansi": {
251
+ "version": "7.1.2",
252
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
253
+ "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
254
+ "license": "MIT",
255
+ "dependencies": {
256
+ "ansi-regex": "^6.0.1"
257
+ },
258
+ "engines": {
259
+ "node": ">=12"
260
+ },
261
+ "funding": {
262
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
263
+ }
264
+ },
265
+ "node_modules/yoctocolors": {
266
+ "version": "2.1.2",
267
+ "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz",
268
+ "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==",
269
+ "license": "MIT",
270
+ "engines": {
271
+ "node": ">=18"
272
+ },
273
+ "funding": {
274
+ "url": "https://github.com/sponsors/sindresorhus"
275
+ }
276
+ }
277
+ }
278
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "cli",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "bin": {
10
+ "trans-spec": "./index.js"
11
+ },
12
+ "keywords": [],
13
+ "author": "",
14
+ "license": "ISC",
15
+ "type": "module",
16
+ "dependencies": {
17
+ "chalk": "^5.6.2",
18
+ "commander": "^14.0.3",
19
+ "dotenv": "^17.3.1",
20
+ "ora": "^9.3.0"
21
+ }
22
+ }