@flowgram.ai/cli 0.4.10 → 0.4.12

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/dist/index.cjs CHANGED
@@ -23,34 +23,108 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
23
  ));
24
24
 
25
25
  // src/index.ts
26
+ var import_path10 = __toESM(require("path"), 1);
26
27
  var import_commander = require("commander");
27
28
 
28
- // src/materials/index.ts
29
- var import_inquirer = __toESM(require("inquirer"), 1);
30
- var import_chalk3 = __toESM(require("chalk"), 1);
29
+ // src/update-version/index.ts
30
+ var import_chalk = __toESM(require("chalk"), 1);
31
31
 
32
- // src/materials/materials.ts
33
- var import_path3 = __toESM(require("path"), 1);
34
- var import_fs3 = __toESM(require("fs"), 1);
32
+ // src/utils/npm.ts
33
+ var import_path = __toESM(require("path"), 1);
34
+ var import_https = __toESM(require("https"), 1);
35
+ var import_fs = require("fs");
36
+ var import_child_process = require("child_process");
37
+ var tar = __toESM(require("tar"), 1);
38
+ var import_fs_extra = __toESM(require("fs-extra"), 1);
39
+ var LoadedNpmPkg = class {
40
+ constructor(name, version, path11) {
41
+ this.name = name;
42
+ this.version = version;
43
+ this.path = path11;
44
+ }
45
+ get srcPath() {
46
+ return import_path.default.join(this.path, "src");
47
+ }
48
+ get distPath() {
49
+ return import_path.default.join(this.path, "dist");
50
+ }
51
+ get packageJson() {
52
+ if (!this._packageJson) {
53
+ this._packageJson = JSON.parse((0, import_fs.readFileSync)(import_path.default.join(this.path, "package.json"), "utf8"));
54
+ }
55
+ return this._packageJson;
56
+ }
57
+ get dependencies() {
58
+ return this.packageJson.dependencies;
59
+ }
60
+ };
61
+ function downloadFile(url, dest) {
62
+ return new Promise((resolve, reject) => {
63
+ const file = import_fs_extra.default.createWriteStream(dest);
64
+ import_https.default.get(url, (response) => {
65
+ if (response.statusCode !== 200) {
66
+ reject(new Error(`Download failed: ${response.statusCode}`));
67
+ return;
68
+ }
69
+ response.pipe(file);
70
+ file.on("finish", () => {
71
+ file.close();
72
+ resolve();
73
+ });
74
+ }).on("error", (err) => {
75
+ import_fs_extra.default.unlink(dest, () => reject(err));
76
+ });
77
+ file.on("error", (err) => {
78
+ import_fs_extra.default.unlink(dest, () => reject(err));
79
+ });
80
+ });
81
+ }
82
+ async function getLatestVersion(packageName) {
83
+ return (0, import_child_process.execSync)(`npm view ${packageName} version --tag=latest`).toString().trim();
84
+ }
85
+ async function loadNpm(packageName) {
86
+ const packageLatestVersion = await getLatestVersion(packageName);
87
+ const packagePath = import_path.default.join(__dirname, `./.download/${packageName}-${packageLatestVersion}`);
88
+ if ((0, import_fs.existsSync)(packagePath)) {
89
+ return new LoadedNpmPkg(packageName, packageLatestVersion, packagePath);
90
+ }
91
+ try {
92
+ const tarballUrl = (0, import_child_process.execSync)(`npm view ${packageName}@${packageLatestVersion} dist.tarball`).toString().trim();
93
+ const tempTarballPath = import_path.default.join(
94
+ __dirname,
95
+ `./.download/${packageName}-${packageLatestVersion}.tgz`
96
+ );
97
+ import_fs_extra.default.ensureDirSync(import_path.default.dirname(tempTarballPath));
98
+ await downloadFile(tarballUrl, tempTarballPath);
99
+ import_fs_extra.default.ensureDirSync(packagePath);
100
+ await tar.x({
101
+ file: tempTarballPath,
102
+ cwd: packagePath,
103
+ strip: 1
104
+ });
105
+ import_fs_extra.default.unlinkSync(tempTarballPath);
106
+ return new LoadedNpmPkg(packageName, packageLatestVersion, packagePath);
107
+ } catch (error) {
108
+ console.error(`Error downloading or extracting package: ${error}`);
109
+ throw error;
110
+ }
111
+ }
35
112
 
36
- // src/utils/ts-file.ts
113
+ // src/utils/file.ts
37
114
  var import_path2 = __toESM(require("path"), 1);
38
115
  var import_fs2 = __toESM(require("fs"), 1);
39
-
40
- // src/utils/file.ts
41
- var import_path = __toESM(require("path"), 1);
42
- var import_fs = __toESM(require("fs"), 1);
116
+ var import_ignore = __toESM(require("ignore"), 1);
43
117
  var File = class {
44
118
  constructor(filePath, root = "/") {
45
119
  this.root = root;
46
120
  this.path = filePath;
47
- this.relativePath = import_path.default.relative(this.root, this.path);
48
- this.suffix = import_path.default.extname(this.path);
49
- if (!import_fs.default.existsSync(this.path)) {
50
- throw Error(`File ${import_path.default} Not Exists`);
121
+ this.relativePath = import_path2.default.relative(this.root, this.path);
122
+ this.suffix = import_path2.default.extname(this.path);
123
+ if (!import_fs2.default.existsSync(this.path)) {
124
+ throw Error(`File ${import_path2.default} Not Exists`);
51
125
  }
52
126
  try {
53
- this.content = import_fs.default.readFileSync(this.path, "utf-8");
127
+ this.content = import_fs2.default.readFileSync(this.path, "utf-8");
54
128
  this.isUtf8 = true;
55
129
  } catch (e) {
56
130
  this.isUtf8 = false;
@@ -63,19 +137,220 @@ var File = class {
63
137
  return;
64
138
  }
65
139
  this.content = updater(this.content);
66
- import_fs.default.writeFileSync(this.path, this.content, "utf-8");
140
+ import_fs2.default.writeFileSync(this.path, this.content, "utf-8");
141
+ }
142
+ write(nextContent) {
143
+ this.content = nextContent;
144
+ import_fs2.default.writeFileSync(this.path, this.content, "utf-8");
145
+ }
146
+ };
147
+ function* traverseRecursiveFilePaths(folder, ig = (0, import_ignore.default)().add(".git"), root = folder) {
148
+ const files = import_fs2.default.readdirSync(folder);
149
+ if (import_fs2.default.existsSync(import_path2.default.join(folder, ".gitignore"))) {
150
+ ig.add(import_fs2.default.readFileSync(import_path2.default.join(folder, ".gitignore"), "utf-8"));
151
+ }
152
+ for (const file of files) {
153
+ const filePath = import_path2.default.join(folder, file);
154
+ if (ig.ignores(import_path2.default.relative(root, filePath))) {
155
+ continue;
156
+ }
157
+ if (import_fs2.default.statSync(filePath).isDirectory()) {
158
+ yield* traverseRecursiveFilePaths(filePath, ig, root);
159
+ } else {
160
+ yield filePath;
161
+ }
162
+ }
163
+ }
164
+ function* traverseRecursiveFiles(folder) {
165
+ for (const filePath of traverseRecursiveFilePaths(folder)) {
166
+ yield new File(filePath, folder);
167
+ }
168
+ }
169
+
170
+ // src/update-version/index.ts
171
+ async function updateFlowgramVersion(inputVersion) {
172
+ console.log(import_chalk.default.bold("\u{1F680} Welcome to @flowgram.ai update-version helper"));
173
+ const latestVersion = await getLatestVersion("@flowgram.ai/editor");
174
+ const currentPath = process.cwd();
175
+ console.log("- Latest flowgram version: ", latestVersion);
176
+ console.log("- Current Path: ", currentPath);
177
+ const flowgramVersion = inputVersion || latestVersion;
178
+ for (const file of traverseRecursiveFiles(currentPath)) {
179
+ if (file.path.endsWith("package.json")) {
180
+ console.log("\u{1F440} Find package.json: ", file.path);
181
+ let updated = false;
182
+ const json = JSON.parse(file.content);
183
+ if (json.dependencies) {
184
+ for (const key in json.dependencies) {
185
+ if (key.startsWith("@flowgram.ai/")) {
186
+ updated = true;
187
+ json.dependencies[key] = flowgramVersion;
188
+ console.log(`- Update ${key} to ${flowgramVersion}`);
189
+ }
190
+ }
191
+ }
192
+ if (json.devDependencies) {
193
+ for (const key in json.devDependencies) {
194
+ if (key.startsWith("@flowgram.ai/")) {
195
+ updated = true;
196
+ json.devDependencies[key] = flowgramVersion;
197
+ console.log(`- Update ${key} to ${flowgramVersion}`);
198
+ }
199
+ }
200
+ }
201
+ if (updated) {
202
+ file.write(JSON.stringify(json, null, 2));
203
+ console.log(`\u2705 ${file.path} Updated`);
204
+ }
205
+ }
206
+ }
207
+ }
208
+
209
+ // src/materials/index.ts
210
+ var import_path8 = __toESM(require("path"), 1);
211
+ var import_chalk5 = __toESM(require("chalk"), 1);
212
+
213
+ // src/utils/project.ts
214
+ var import_path3 = __toESM(require("path"), 1);
215
+ var import_fs3 = require("fs");
216
+ var import_chalk2 = __toESM(require("chalk"), 1);
217
+ var Project = class _Project {
218
+ constructor() {
219
+ }
220
+ async init() {
221
+ let projectPath = process.cwd();
222
+ while (projectPath !== "/" && !(0, import_fs3.existsSync)(import_path3.default.join(projectPath, "package.json"))) {
223
+ projectPath = import_path3.default.join(projectPath, "..");
224
+ }
225
+ if (projectPath === "/") {
226
+ throw new Error("Please run this command in a valid project");
227
+ }
228
+ this.projectPath = projectPath;
229
+ this.srcPath = import_path3.default.join(projectPath, "src");
230
+ this.packageJsonPath = import_path3.default.join(projectPath, "package.json");
231
+ this.packageJson = JSON.parse((0, import_fs3.readFileSync)(this.packageJsonPath, "utf8"));
232
+ this.flowgramVersion = this.packageJson.dependencies["@flowgram.ai/fixed-layout-editor"] || this.packageJson.dependencies["@flowgram.ai/free-layout-editor"] || this.packageJson.dependencies["@flowgram.ai/editor"];
233
+ }
234
+ async addDependency(dependency) {
235
+ let name;
236
+ let version;
237
+ const lastAtIndex = dependency.lastIndexOf("@");
238
+ if (lastAtIndex <= 0) {
239
+ name = dependency;
240
+ version = await getLatestVersion(name);
241
+ } else {
242
+ name = dependency.substring(0, lastAtIndex);
243
+ version = dependency.substring(lastAtIndex + 1);
244
+ if (!version.trim()) {
245
+ version = await getLatestVersion(name);
246
+ }
247
+ }
248
+ this.packageJson.dependencies[name] = version;
249
+ (0, import_fs3.writeFileSync)(this.packageJsonPath, JSON.stringify(this.packageJson, null, 2));
250
+ }
251
+ async addDependencies(dependencies) {
252
+ for (const dependency of dependencies) {
253
+ await this.addDependency(dependency);
254
+ }
255
+ }
256
+ writeToPackageJsonFile() {
257
+ (0, import_fs3.writeFileSync)(this.packageJsonPath, JSON.stringify(this.packageJson, null, 2));
258
+ }
259
+ printInfo() {
260
+ console.log(import_chalk2.default.bold("Project Info:"));
261
+ console.log(import_chalk2.default.black(` - Flowgram Version: ${this.flowgramVersion}`));
262
+ console.log(import_chalk2.default.black(` - Project Path: ${this.projectPath}`));
263
+ }
264
+ static async getSingleton() {
265
+ const info = new _Project();
266
+ await info.init();
267
+ return info;
67
268
  }
68
269
  };
69
270
 
271
+ // src/materials/select.ts
272
+ var import_inquirer = __toESM(require("inquirer"), 1);
273
+ var import_chalk3 = __toESM(require("chalk"), 1);
274
+
275
+ // src/materials/material.ts
276
+ var import_path5 = __toESM(require("path"), 1);
277
+ var import_fs5 = require("fs");
278
+
279
+ // src/utils/ts-file.ts
280
+ var import_path4 = __toESM(require("path"), 1);
281
+ var import_fs4 = __toESM(require("fs"), 1);
282
+
283
+ // src/utils/import.ts
284
+ function assembleImport(declaration) {
285
+ const { namedImports, defaultImport, namespaceImport, source } = declaration;
286
+ const importClauses = [];
287
+ if (namedImports) {
288
+ importClauses.push(
289
+ `{ ${namedImports.map(
290
+ ({ local, imported, typeOnly }) => `${typeOnly ? "type " : ""}${imported}${local ? ` as ${local}` : ""}`
291
+ ).join(", ")} }`
292
+ );
293
+ }
294
+ if (defaultImport) {
295
+ importClauses.push(defaultImport);
296
+ }
297
+ if (namespaceImport) {
298
+ importClauses.push(`* as ${namespaceImport}`);
299
+ }
300
+ return `import ${importClauses.join(", ")} from '${source}';`;
301
+ }
302
+ function* traverseFileImports(fileContent) {
303
+ const importRegex = /import\s+([^{}*,]*?)?(?:\s*\*\s*as\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*,?)?(?:\s*\{([^}]*)\}\s*,?)?(?:\s*([a-zA-Z_$][a-zA-Z0-9_$]*)\s*,?)?\s*from\s*['"`]([^'"`]+)['"`]\;?/g;
304
+ let match;
305
+ while ((match = importRegex.exec(fileContent)) !== null) {
306
+ const [fullMatch, defaultPart, namespacePart, namedPart, defaultPart2, source] = match;
307
+ const declaration = {
308
+ statement: fullMatch,
309
+ source
310
+ };
311
+ const defaultImport = defaultPart?.trim() || defaultPart2?.trim();
312
+ if (defaultImport && !namespacePart && !namedPart) {
313
+ declaration.defaultImport = defaultImport;
314
+ } else if (defaultImport && (namespacePart || namedPart)) {
315
+ declaration.defaultImport = defaultImport;
316
+ }
317
+ if (namespacePart) {
318
+ declaration.namespaceImport = namespacePart.trim();
319
+ }
320
+ if (namedPart) {
321
+ const namedImports = [];
322
+ const namedItems = namedPart.split(",").map((item) => item.trim()).filter(Boolean);
323
+ for (const item of namedItems) {
324
+ const typeOnly = item.startsWith("type ");
325
+ const cleanItem = typeOnly ? item.slice(5).trim() : item;
326
+ if (cleanItem.includes(" as ")) {
327
+ const [imported, local] = cleanItem.split(" as ").map((s) => s.trim());
328
+ namedImports.push({
329
+ imported,
330
+ local,
331
+ typeOnly
332
+ });
333
+ } else {
334
+ namedImports.push({
335
+ imported: cleanItem,
336
+ typeOnly
337
+ });
338
+ }
339
+ }
340
+ if (namedImports.length > 0) {
341
+ declaration.namedImports = namedImports;
342
+ }
343
+ }
344
+ yield declaration;
345
+ }
346
+ }
347
+
70
348
  // src/utils/export.ts
71
349
  function extractNamedExports(content) {
72
350
  const valueExports = [];
73
351
  const typeExports = [];
74
352
  const typeDefinitions = /* @__PURE__ */ new Set();
75
- const typePatterns = [
76
- /\b(?:type|interface)\s+(\w+)/g,
77
- /\bexport\s+(?:type|interface)\s+(\w+)/g
78
- ];
353
+ const typePatterns = [/\b(?:type|interface)\s+(\w+)/g, /\bexport\s+(?:type|interface)\s+(\w+)/g];
79
354
  let match;
80
355
  for (const pattern of typePatterns) {
81
356
  while ((match = pattern.exec(content)) !== null) {
@@ -154,84 +429,17 @@ function extractNamedExports(content) {
154
429
  };
155
430
  }
156
431
 
157
- // src/utils/import.ts
158
- function assembleImport(declaration) {
159
- const { namedImports, defaultImport, namespaceImport, source } = declaration;
160
- const importClauses = [];
161
- if (namedImports) {
162
- importClauses.push(
163
- `{ ${namedImports.map(
164
- ({ local, imported, typeOnly }) => `${typeOnly ? "type " : ""}${imported}${local ? ` as ${local}` : ""}`
165
- ).join(", ")} }`
166
- );
167
- }
168
- if (defaultImport) {
169
- importClauses.push(defaultImport);
170
- }
171
- if (namespaceImport) {
172
- importClauses.push(`* as ${namespaceImport}`);
173
- }
174
- return `import ${importClauses.join(", ")} from '${source}';`;
175
- }
176
- function* traverseFileImports(fileContent) {
177
- const importRegex = /import\s+([^{}*,]*?)?(?:\s*\*\s*as\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*,?)?(?:\s*\{([^}]*)\}\s*,?)?(?:\s*([a-zA-Z_$][a-zA-Z0-9_$]*)\s*,?)?\s*from\s*['"`]([^'"`]+)['"`]\;?/g;
178
- let match;
179
- while ((match = importRegex.exec(fileContent)) !== null) {
180
- const [fullMatch, defaultPart, namespacePart, namedPart, defaultPart2, source] = match;
181
- const declaration = {
182
- statement: fullMatch,
183
- source
184
- };
185
- const defaultImport = defaultPart?.trim() || defaultPart2?.trim();
186
- if (defaultImport && !namespacePart && !namedPart) {
187
- declaration.defaultImport = defaultImport;
188
- } else if (defaultImport && (namespacePart || namedPart)) {
189
- declaration.defaultImport = defaultImport;
190
- }
191
- if (namespacePart) {
192
- declaration.namespaceImport = namespacePart.trim();
193
- }
194
- if (namedPart) {
195
- const namedImports = [];
196
- const namedItems = namedPart.split(",").map((item) => item.trim()).filter(Boolean);
197
- for (const item of namedItems) {
198
- const typeOnly = item.startsWith("type ");
199
- const cleanItem = typeOnly ? item.slice(5).trim() : item;
200
- if (cleanItem.includes(" as ")) {
201
- const [imported, local] = cleanItem.split(" as ").map((s) => s.trim());
202
- namedImports.push({
203
- imported,
204
- local,
205
- typeOnly
206
- });
207
- } else {
208
- namedImports.push({
209
- imported: cleanItem,
210
- typeOnly
211
- });
212
- }
213
- }
214
- if (namedImports.length > 0) {
215
- declaration.namedImports = namedImports;
216
- }
217
- }
218
- yield declaration;
219
- }
220
- }
221
-
222
432
  // src/utils/ts-file.ts
223
433
  var TsFile = class extends File {
224
- constructor(filePath) {
225
- super(filePath);
434
+ constructor(filePath, root) {
435
+ super(filePath, root);
226
436
  this.exports = {
227
437
  values: [],
228
438
  types: []
229
439
  };
230
440
  this.imports = [];
231
- this.exports = extractNamedExports(import_fs2.default.readFileSync(filePath, "utf-8"));
232
- this.imports = Array.from(
233
- traverseFileImports(import_fs2.default.readFileSync(filePath, "utf-8"))
234
- );
441
+ this.exports = extractNamedExports(import_fs4.default.readFileSync(filePath, "utf-8"));
442
+ this.imports = Array.from(traverseFileImports(import_fs4.default.readFileSync(filePath, "utf-8")));
235
443
  }
236
444
  get allExportNames() {
237
445
  return [...this.exports.values, ...this.exports.types];
@@ -245,9 +453,7 @@ var TsFile = class extends File {
245
453
  return content.replace(
246
454
  lastImportStatement.statement,
247
455
  `${lastImportStatement?.statement}
248
- ${importDeclarations.map(
249
- (item) => item.statement
250
- )}
456
+ ${importDeclarations.map((item) => item.statement)}
251
457
  `
252
458
  );
253
459
  });
@@ -255,14 +461,9 @@ ${importDeclarations.map(
255
461
  }
256
462
  removeImport(importDeclarations) {
257
463
  this.replace(
258
- (content) => importDeclarations.reduce(
259
- (prev, cur) => prev.replace(cur.statement, ""),
260
- content
261
- )
262
- );
263
- this.imports = this.imports.filter(
264
- (item) => !importDeclarations.includes(item)
464
+ (content) => importDeclarations.reduce((prev, cur) => prev.replace(cur.statement, ""), content)
265
465
  );
466
+ this.imports = this.imports.filter((item) => !importDeclarations.includes(item));
266
467
  }
267
468
  replaceImport(oldImports, newImports) {
268
469
  newImports.forEach((importDeclaration) => {
@@ -291,9 +492,7 @@ ${importDeclarations.map(
291
492
  content = content.replace(
292
493
  lastImportStatement,
293
494
  `${lastImportStatement}
294
- ${restNewImports.map(
295
- (item) => item.statement
296
- )}
495
+ ${restNewImports.map((item) => item.statement).join("\n")}
297
496
  `
298
497
  );
299
498
  }
@@ -303,238 +502,160 @@ ${restNewImports.map(
303
502
  }
304
503
  };
305
504
  function* traverseRecursiveTsFiles(folder) {
306
- const files = import_fs2.default.readdirSync(folder);
307
- for (const file of files) {
308
- const filePath = import_path2.default.join(folder, file);
309
- if (import_fs2.default.statSync(filePath).isDirectory()) {
310
- yield* traverseRecursiveTsFiles(filePath);
311
- } else {
312
- if (file.endsWith(".ts") || file.endsWith(".tsx")) {
313
- yield new TsFile(filePath);
314
- }
505
+ for (const filePath of traverseRecursiveFilePaths(folder)) {
506
+ if (filePath.endsWith(".ts") || filePath.endsWith(".tsx")) {
507
+ yield new TsFile(filePath, folder);
315
508
  }
316
509
  }
317
510
  }
318
511
  function getIndexTsFile(folder) {
319
- const files = import_fs2.default.readdirSync(folder);
512
+ const files = import_fs4.default.readdirSync(folder);
320
513
  for (const file of files) {
321
514
  if (file === "index.ts" || file === "index.tsx") {
322
- return new TsFile(import_path2.default.join(folder, file));
515
+ return new TsFile(import_path4.default.join(folder, file), folder);
323
516
  }
324
517
  }
325
518
  return void 0;
326
519
  }
327
520
 
328
- // src/materials/materials.ts
329
- var _types = [
521
+ // src/materials/material.ts
522
+ var _Material = class _Material {
523
+ constructor(type, name, formMaterialPkg) {
524
+ this.type = type;
525
+ this.name = name;
526
+ this.formMaterialPkg = formMaterialPkg;
527
+ }
528
+ get fullName() {
529
+ return `${this.type}/${this.name}`;
530
+ }
531
+ get sourceDir() {
532
+ return import_path5.default.join(this.formMaterialPkg.srcPath, this.type, this.name);
533
+ }
534
+ get indexFile() {
535
+ return getIndexTsFile(this.sourceDir);
536
+ }
537
+ get allExportNames() {
538
+ return this.indexFile?.allExportNames || [];
539
+ }
540
+ static listAll(formMaterialPkg) {
541
+ if (!this._all_materials_cache.length) {
542
+ this._all_materials_cache = _Material.ALL_TYPES.map((type) => {
543
+ const materialsPath = import_path5.default.join(formMaterialPkg.srcPath, type);
544
+ return (0, import_fs5.readdirSync)(materialsPath).map((_path) => {
545
+ if (_path === "index.ts") {
546
+ return null;
547
+ }
548
+ return new _Material(type, _path, formMaterialPkg);
549
+ }).filter((material) => material !== null);
550
+ }).flat();
551
+ }
552
+ return this._all_materials_cache;
553
+ }
554
+ };
555
+ _Material._all_materials_cache = [];
556
+ _Material.ALL_TYPES = [
330
557
  "components",
331
558
  "effects",
332
559
  "plugins",
333
560
  "shared",
334
- "typings",
335
561
  "validate",
336
562
  "form-plugins",
337
563
  "hooks"
338
564
  ];
339
- function listAllMaterials(formMaterialSrc) {
340
- const _materials = [];
341
- for (const _type of _types) {
342
- const materialsPath = import_path3.default.join(formMaterialSrc, _type);
343
- _materials.push(
344
- ...import_fs3.default.readdirSync(materialsPath).map((_path) => {
345
- if (_path === "index.ts") {
346
- return null;
347
- }
348
- return {
349
- name: _path,
350
- // Assuming the folder name is the material name
351
- type: _type,
352
- path: import_path3.default.join(materialsPath, _path)
353
- };
354
- }).filter((material) => material !== null)
355
- );
356
- }
357
- return _materials;
358
- }
359
- var getFormMaterialDependencies = (formMaterialPath) => {
360
- const packageJsonPath = import_path3.default.join(formMaterialPath, "package.json");
361
- const packageJson = JSON.parse(import_fs3.default.readFileSync(packageJsonPath, "utf8"));
362
- return packageJson.dependencies;
363
- };
364
- var copyMaterial = (material, project, formMaterialPath) => {
365
- const formMaterialDependencies = getFormMaterialDependencies(formMaterialPath);
366
- const sourceDir = material.path;
367
- const materialRoot = import_path3.default.join(
368
- project.projectPath,
369
- "src",
370
- "form-materials",
371
- `${material.type}`
372
- );
373
- const targetDir = import_path3.default.join(materialRoot, material.name);
374
- const packagesToInstall = /* @__PURE__ */ new Set();
375
- import_fs3.default.cpSync(sourceDir, targetDir, { recursive: true });
376
- for (const file of traverseRecursiveTsFiles(targetDir)) {
377
- for (const importDeclaration of file.imports) {
378
- const { source } = importDeclaration;
379
- if (source.startsWith("@/")) {
380
- console.log(
381
- `Replace Import from ${source} to @flowgram.ai/form-materials`
382
- );
383
- file.replaceImport(
384
- [importDeclaration],
385
- [{ ...importDeclaration, source: "@flowgram.ai/form-materials" }]
386
- );
387
- packagesToInstall.add(
388
- `@flowgram.ai/form-materials@${project.flowgramVersion}`
389
- );
390
- } else if (!source.startsWith(".") && !source.startsWith("react")) {
391
- const [dep, version] = Object.entries(formMaterialDependencies).find(
392
- ([_key]) => source.startsWith(_key)
393
- ) || [];
394
- if (!dep) {
395
- continue;
565
+ var Material = _Material;
566
+
567
+ // src/materials/select.ts
568
+ var getSelectedMaterials = async (cliOpts, formMaterialPkg) => {
569
+ const { materialName, selectMultiple } = cliOpts;
570
+ const materials = Material.listAll(formMaterialPkg);
571
+ let selectedMaterials = [];
572
+ if (materialName) {
573
+ selectedMaterials = materialName.split(",").map((_name) => materials.find((_m) => _m.fullName === _name.trim())).filter(Boolean);
574
+ }
575
+ if (!selectedMaterials.length) {
576
+ console.log(import_chalk3.default.yellow(`Material "${materialName}" not found. Please select from the list:`));
577
+ const choices = materials.map((_material) => ({
578
+ name: _material.fullName,
579
+ value: _material
580
+ }));
581
+ if (selectMultiple) {
582
+ const result = await import_inquirer.default.prompt([
583
+ {
584
+ type: "checkbox",
585
+ name: "material",
586
+ message: "Select multiple materials to add:",
587
+ choices
396
588
  }
397
- if (dep.startsWith("@flowgram.ai/")) {
398
- packagesToInstall.add(`${dep}@${project.flowgramVersion}`);
399
- } else {
400
- packagesToInstall.add(`${dep}@${version}`);
589
+ ]);
590
+ selectedMaterials = result.material;
591
+ } else {
592
+ const result = await import_inquirer.default.prompt([
593
+ {
594
+ type: "list",
595
+ name: "material",
596
+ message: "Select one material to add:",
597
+ choices
401
598
  }
402
- }
599
+ ]);
600
+ selectedMaterials = [result.material];
403
601
  }
404
602
  }
405
- return {
406
- packagesToInstall: [...packagesToInstall]
407
- };
603
+ return selectedMaterials;
408
604
  };
409
605
 
410
- // src/utils/npm.ts
411
- var import_child_process = require("child_process");
412
- var import_fs4 = require("fs");
413
- var import_path4 = __toESM(require("path"), 1);
414
- var import_download = __toESM(require("download"), 1);
415
- async function getLatestVersion(packageName) {
416
- return (0, import_child_process.execSync)(`npm view ${packageName} version --tag=latest`).toString().trim();
417
- }
418
- async function loadNpm(packageName) {
419
- const packageLatestVersion = await getLatestVersion(packageName);
420
- const packagePath = import_path4.default.join(
421
- __dirname,
422
- `./.download/${packageName}-${packageLatestVersion}`
423
- );
424
- if ((0, import_fs4.existsSync)(packagePath)) {
425
- return packagePath;
426
- }
427
- try {
428
- const tarballUrl = (0, import_child_process.execSync)(
429
- `npm view ${packageName}@${packageLatestVersion} dist.tarball`
430
- ).toString().trim();
431
- await (0, import_download.default)(tarballUrl, packagePath, { extract: true, strip: 1 });
432
- return packagePath;
433
- } catch (error) {
434
- console.error(`Error downloading or extracting package: ${error}`);
435
- throw error;
436
- }
437
- }
438
-
439
- // src/materials/index.ts
606
+ // src/materials/refresh-project-import.ts
440
607
  var import_path6 = __toESM(require("path"), 1);
441
-
442
- // src/utils/project.ts
443
- var import_fs5 = require("fs");
444
- var import_path5 = __toESM(require("path"), 1);
445
- var import_chalk = __toESM(require("chalk"), 1);
446
- var Project = class _Project {
447
- constructor() {
448
- }
449
- async init() {
450
- let projectPath = process.cwd();
451
- while (projectPath !== "/" && !(0, import_fs5.existsSync)(import_path5.default.join(projectPath, "package.json"))) {
452
- projectPath = import_path5.default.join(projectPath, "..");
453
- }
454
- if (projectPath === "/") {
455
- throw new Error("Please run this command in a valid project");
456
- }
457
- this.projectPath = projectPath;
458
- this.srcPath = import_path5.default.join(projectPath, "src");
459
- this.packageJsonPath = import_path5.default.join(projectPath, "package.json");
460
- this.packageJson = JSON.parse((0, import_fs5.readFileSync)(this.packageJsonPath, "utf8"));
461
- this.flowgramVersion = this.packageJson.dependencies["@flowgram.ai/fixed-layout-editor"] || this.packageJson.dependencies["@flowgram.ai/free-layout-editor"] || this.packageJson.dependencies["@flowgram.ai/editor"];
462
- }
463
- async addDependency(dependency) {
464
- let name;
465
- let version;
466
- const lastAtIndex = dependency.lastIndexOf("@");
467
- if (lastAtIndex <= 0) {
468
- name = dependency;
469
- version = await getLatestVersion(name);
470
- } else {
471
- name = dependency.substring(0, lastAtIndex);
472
- version = dependency.substring(lastAtIndex + 1);
473
- if (!version.trim()) {
474
- version = await getLatestVersion(name);
475
- }
476
- }
477
- this.packageJson.dependencies[name] = version;
478
- (0, import_fs5.writeFileSync)(
479
- this.packageJsonPath,
480
- JSON.stringify(this.packageJson, null, 2)
481
- );
482
- }
483
- async addDependencies(dependencies) {
484
- for (const dependency of dependencies) {
485
- await this.addDependency(dependency);
608
+ var import_chalk4 = __toESM(require("chalk"), 1);
609
+ function executeRefreshProjectImport(context) {
610
+ const { selectedMaterials, project, targetFormMaterialRoot } = context;
611
+ const exportName2Material = /* @__PURE__ */ new Map();
612
+ const targetModule = `@/${import_path6.default.relative(project.srcPath, targetFormMaterialRoot)}`;
613
+ for (const material of selectedMaterials) {
614
+ if (!material.indexFile) {
615
+ console.warn(`Material ${material.name} not found`);
616
+ return;
486
617
  }
618
+ console.log(`\u{1F440} The exports of ${material.name} is ${material.allExportNames.join(",")}`);
619
+ material.allExportNames.forEach((exportName) => {
620
+ exportName2Material.set(exportName, material);
621
+ });
487
622
  }
488
- printInfo() {
489
- console.log(import_chalk.default.bold("Project Info:"));
490
- console.log(import_chalk.default.black(` - Flowgram Version: ${this.flowgramVersion}`));
491
- console.log(import_chalk.default.black(` - Project Path: ${this.projectPath}`));
492
- }
493
- static async getSingleton() {
494
- const info = new _Project();
495
- await info.init();
496
- return info;
497
- }
498
- };
499
-
500
- // src/materials/refresh-project-import.ts
501
- var import_chalk2 = __toESM(require("chalk"), 1);
502
- function executeRefreshProjectImport(project, material) {
503
- const materialFile = getIndexTsFile(material.path);
504
- if (!materialFile) {
505
- console.warn(`Material ${material.name} not found`);
506
- return;
507
- }
508
- const targetDir = `@/form-materials/${material.type}/${material.name}`;
509
- const exportNames = materialFile.allExportNames;
510
- console.log(`\u{1F440} The exports of ${material.name} is ${exportNames.join(",")}`);
511
623
  for (const tsFile of traverseRecursiveTsFiles(project.srcPath)) {
512
624
  for (const importDeclaration of tsFile.imports) {
513
- if (importDeclaration.source === "@flowgram.ai/form-materials") {
514
- const currentMaterialImports = importDeclaration.namedImports?.filter(
515
- (item) => exportNames.includes(item.imported)
516
- );
517
- if (!currentMaterialImports?.length) {
625
+ if (importDeclaration.source.startsWith("@flowgram.ai/form-materials")) {
626
+ const restImports = [];
627
+ const importMap = {};
628
+ if (!importDeclaration.namedImports) {
518
629
  continue;
519
630
  }
520
- const nextImports = [
521
- {
522
- ...importDeclaration,
523
- namedImports: currentMaterialImports,
524
- source: targetDir
631
+ for (const nameImport of importDeclaration.namedImports) {
632
+ const material = exportName2Material.get(nameImport.imported);
633
+ if (material) {
634
+ const importModule = `${targetModule}/${material.fullName}`;
635
+ importMap[importModule] = importMap[importModule] || [];
636
+ importMap[importModule].push(nameImport);
637
+ } else {
638
+ restImports.push(nameImport);
525
639
  }
526
- ];
527
- const keepImportNames = importDeclaration.namedImports?.filter(
528
- (item) => !exportNames.includes(item.imported)
640
+ }
641
+ if (Object.keys(importMap).length === 0) {
642
+ continue;
643
+ }
644
+ const nextImports = Object.entries(importMap).map(
645
+ ([importModule, namedImports]) => ({
646
+ ...importDeclaration,
647
+ namedImports,
648
+ source: importModule
649
+ })
529
650
  );
530
- if (keepImportNames?.length) {
651
+ if (restImports?.length) {
531
652
  nextImports.unshift({
532
653
  ...importDeclaration,
533
- namedImports: keepImportNames
654
+ namedImports: restImports
534
655
  });
535
656
  }
536
657
  tsFile.replaceImport([importDeclaration], nextImports);
537
- console.log(import_chalk2.default.green(`\u{1F504} Refresh Imports In: ${tsFile.path}`));
658
+ console.log(import_chalk4.default.green(`\u{1F504} Refresh Imports In: ${tsFile.path}`));
538
659
  console.log(
539
660
  `From:
540
661
  ${importDeclaration.statement}
@@ -546,86 +667,147 @@ ${nextImports.map((item) => item.statement).join("\n")}`
546
667
  }
547
668
  }
548
669
 
670
+ // src/materials/copy.ts
671
+ var import_path7 = __toESM(require("path"), 1);
672
+ var import_fs6 = __toESM(require("fs"), 1);
673
+ var copyMaterials = (ctx) => {
674
+ const { selectedMaterials, project, formMaterialPkg, targetFormMaterialRoot } = ctx;
675
+ const formMaterialDependencies = formMaterialPkg.dependencies;
676
+ const packagesToInstall = /* @__PURE__ */ new Set();
677
+ for (const material of selectedMaterials) {
678
+ const sourceDir = material.sourceDir;
679
+ const targetDir = import_path7.default.join(targetFormMaterialRoot, material.type, material.name);
680
+ import_fs6.default.cpSync(sourceDir, targetDir, { recursive: true });
681
+ for (const file of traverseRecursiveTsFiles(targetDir)) {
682
+ for (const importDeclaration of file.imports) {
683
+ const { source } = importDeclaration;
684
+ if (source.startsWith("@/")) {
685
+ console.log(`Replace Import from ${source} to @flowgram.ai/form-materials`);
686
+ file.replaceImport(
687
+ [importDeclaration],
688
+ [{ ...importDeclaration, source: "@flowgram.ai/form-materials" }]
689
+ );
690
+ packagesToInstall.add(`@flowgram.ai/form-materials@${project.flowgramVersion}`);
691
+ } else if (!source.startsWith(".") && !source.startsWith("react")) {
692
+ const [dep, version] = Object.entries(formMaterialDependencies).find(([_key]) => source.startsWith(_key)) || [];
693
+ if (!dep) {
694
+ continue;
695
+ }
696
+ if (dep.startsWith("@flowgram.ai/")) {
697
+ packagesToInstall.add(`${dep}@${project.flowgramVersion}`);
698
+ } else {
699
+ packagesToInstall.add(`${dep}@${version}`);
700
+ }
701
+ }
702
+ }
703
+ }
704
+ }
705
+ return {
706
+ packagesToInstall: [...packagesToInstall]
707
+ };
708
+ };
709
+
549
710
  // src/materials/index.ts
550
- async function syncMaterial(opts) {
551
- const { materialName, refreshProjectImports } = opts;
552
- console.log(import_chalk3.default.bold("\u{1F680} Welcome to @flowgram.ai form-materials!"));
711
+ async function syncMaterial(cliOpts) {
712
+ const { refreshProjectImports, targetMaterialRootDir } = cliOpts;
713
+ console.log(import_chalk5.default.bold("\u{1F680} Welcome to @flowgram.ai form-materials CLI!"));
553
714
  const project = await Project.getSingleton();
554
715
  project.printInfo();
716
+ const targetFormMaterialRoot = targetMaterialRootDir || import_path8.default.join(project.projectPath, "src", "form-materials");
717
+ console.log(import_chalk5.default.black(` - Target material root: ${targetFormMaterialRoot}`));
555
718
  if (!project.flowgramVersion) {
556
719
  throw new Error(
557
- import_chalk3.default.red(
720
+ import_chalk5.default.red(
558
721
  "\u274C Please install @flowgram.ai/fixed-layout-editor or @flowgram.ai/free-layout-editor"
559
722
  )
560
723
  );
561
724
  }
562
- const formMaterialPath = await loadNpm("@flowgram.ai/form-materials");
563
- const formMaterialSrc = import_path6.default.join(formMaterialPath, "src");
564
- const materials = listAllMaterials(formMaterialSrc);
565
- let material;
566
- if (materialName) {
567
- const selectedMaterial = materials.find(
568
- (m) => `${m.type}/${m.name}` === materialName
569
- );
570
- if (selectedMaterial) {
571
- material = selectedMaterial;
572
- console.log(import_chalk3.default.green(`Using material: ${materialName}`));
573
- } else {
574
- console.log(
575
- import_chalk3.default.yellow(
576
- `Material "${materialName}" not found. Please select from the list:`
577
- )
578
- );
579
- }
580
- }
581
- if (!material) {
582
- const result = await import_inquirer.default.prompt([
583
- {
584
- type: "list",
585
- name: "material",
586
- message: "Select one material to add:",
587
- choices: [
588
- ...materials.map((_material) => ({
589
- name: `${_material.type}/${_material.name}`,
590
- value: _material
591
- }))
592
- ]
593
- }
594
- ]);
595
- material = result.material;
596
- }
597
- if (!material) {
598
- console.error(import_chalk3.default.red("No material selected. Exiting."));
725
+ const formMaterialPkg = await loadNpm("@flowgram.ai/form-materials");
726
+ let selectedMaterials = await getSelectedMaterials(cliOpts, formMaterialPkg);
727
+ if (!selectedMaterials.length) {
728
+ console.error(import_chalk5.default.red("No material selected. Exiting."));
599
729
  process.exit(1);
600
730
  }
731
+ const context = {
732
+ selectedMaterials,
733
+ project,
734
+ formMaterialPkg,
735
+ cliOpts,
736
+ targetFormMaterialRoot
737
+ };
738
+ console.log(import_chalk5.default.bold("\u{1F680} The following materials will be added to your project"));
739
+ console.log(selectedMaterials.map((material) => `\u{1F4E6} ${material.fullName}`).join("\n"));
740
+ console.log("\n");
741
+ let { packagesToInstall } = copyMaterials(context);
601
742
  if (refreshProjectImports) {
602
- console.log(import_chalk3.default.bold("\u{1F680} Refresh imports in your project"));
603
- executeRefreshProjectImport(project, material);
604
- }
605
- console.log(
606
- import_chalk3.default.bold("\u{1F680} The following materials will be added to your project")
607
- );
608
- console.log(material);
609
- let { packagesToInstall } = copyMaterial(material, project, formMaterialPath);
743
+ console.log(import_chalk5.default.bold("\u{1F680} Refresh imports in your project"));
744
+ executeRefreshProjectImport(context);
745
+ }
610
746
  await project.addDependencies(packagesToInstall);
611
- console.log(
612
- import_chalk3.default.bold("\u2705 These npm dependencies is added to your package.json")
613
- );
747
+ console.log(import_chalk5.default.bold("\n\u2705 These npm dependencies is added to your package.json"));
614
748
  packagesToInstall.forEach((_package) => {
615
749
  console.log(`- ${_package}`);
616
750
  });
617
- console.log(import_chalk3.default.bold("\n\u27A1\uFE0F Please run npm install to install dependencies\n"));
751
+ console.log(import_chalk5.default.bold(import_chalk5.default.bold("\n\u27A1\uFE0F Please run npm install to install dependencies\n")));
752
+ }
753
+
754
+ // src/find-materials/index.ts
755
+ var import_chalk6 = __toESM(require("chalk"), 1);
756
+ async function findUsedMaterials() {
757
+ console.log(import_chalk6.default.bold("\u{1F680} Welcome to @flowgram.ai form-materials CLI!"));
758
+ const project = await Project.getSingleton();
759
+ project.printInfo();
760
+ const formMaterialPkg = await loadNpm("@flowgram.ai/form-materials");
761
+ const materials = Material.listAll(formMaterialPkg);
762
+ const allUsedMaterials = /* @__PURE__ */ new Set();
763
+ const exportName2Material = /* @__PURE__ */ new Map();
764
+ for (const material of materials) {
765
+ if (!material.indexFile) {
766
+ console.warn(`Material ${material.name} not found`);
767
+ return;
768
+ }
769
+ console.log(`\u{1F440} The exports of ${material.name} is ${material.allExportNames.join(",")}`);
770
+ material.allExportNames.forEach((exportName) => {
771
+ exportName2Material.set(exportName, material);
772
+ });
773
+ }
774
+ for (const tsFile of traverseRecursiveTsFiles(project.srcPath)) {
775
+ const fileMaterials = /* @__PURE__ */ new Set();
776
+ let fileImportPrinted = false;
777
+ for (const importDeclaration of tsFile.imports) {
778
+ if (!importDeclaration.source.startsWith("@flowgram.ai/form-materials") || !importDeclaration.namedImports?.length) {
779
+ continue;
780
+ }
781
+ if (!fileImportPrinted) {
782
+ fileImportPrinted = true;
783
+ console.log(import_chalk6.default.bold(`
784
+ \u{1F440} Searching ${tsFile.path}`));
785
+ }
786
+ console.log(`\u{1F50D} ${importDeclaration.statement}`);
787
+ if (importDeclaration.namedImports) {
788
+ importDeclaration.namedImports.forEach((namedImport) => {
789
+ const material = exportName2Material.get(namedImport.imported);
790
+ if (material) {
791
+ fileMaterials.add(material);
792
+ allUsedMaterials.add(material);
793
+ console.log(`import ${import_chalk6.default.bold(material.fullName)} by ${namedImport.imported}`);
794
+ }
795
+ });
796
+ }
797
+ }
798
+ }
799
+ console.log(import_chalk6.default.bold("\n\u{1F4E6} All used materials:"));
800
+ console.log([...allUsedMaterials].map((_material) => _material.fullName).join(","));
618
801
  }
619
802
 
620
803
  // src/create-app/index.ts
621
- var import_path7 = __toESM(require("path"), 1);
804
+ var import_path9 = __toESM(require("path"), 1);
805
+ var import_https2 = __toESM(require("https"), 1);
622
806
  var import_child_process2 = require("child_process");
807
+ var tar2 = __toESM(require("tar"), 1);
623
808
  var import_inquirer2 = __toESM(require("inquirer"), 1);
624
- var import_fs_extra = __toESM(require("fs-extra"), 1);
625
- var import_chalk4 = __toESM(require("chalk"), 1);
626
- var import_download2 = __toESM(require("download"), 1);
627
- var tar = __toESM(require("tar"), 1);
628
- var args = process.argv.slice(2);
809
+ var import_fs_extra2 = __toESM(require("fs-extra"), 1);
810
+ var import_chalk7 = __toESM(require("chalk"), 1);
629
811
  var updateFlowGramVersions = (dependencies, latestVersion) => {
630
812
  for (const packageName in dependencies) {
631
813
  if (packageName.startsWith("@flowgram.ai")) {
@@ -633,8 +815,29 @@ var updateFlowGramVersions = (dependencies, latestVersion) => {
633
815
  }
634
816
  }
635
817
  };
818
+ function downloadFile2(url, dest) {
819
+ return new Promise((resolve, reject) => {
820
+ const file = import_fs_extra2.default.createWriteStream(dest);
821
+ import_https2.default.get(url, (response) => {
822
+ if (response.statusCode !== 200) {
823
+ reject(new Error(`Download failed: ${response.statusCode}`));
824
+ return;
825
+ }
826
+ response.pipe(file);
827
+ file.on("finish", () => {
828
+ file.close();
829
+ resolve();
830
+ });
831
+ }).on("error", (err) => {
832
+ import_fs_extra2.default.unlink(dest, () => reject(err));
833
+ });
834
+ file.on("error", (err) => {
835
+ import_fs_extra2.default.unlink(dest, () => reject(err));
836
+ });
837
+ });
838
+ }
636
839
  var createApp = async (projectName) => {
637
- console.log(import_chalk4.default.green("Welcome to @flowgram.ai/create-app CLI!"));
840
+ console.log(import_chalk7.default.green("Welcome to @flowgram.ai/create-app CLI!"));
638
841
  const latest = (0, import_child_process2.execSync)("npm view @flowgram.ai/demo-fixed-layout version --tag=latest latest").toString().trim();
639
842
  let folderName = "";
640
843
  if (!projectName) {
@@ -656,7 +859,14 @@ var createApp = async (projectName) => {
656
859
  ]);
657
860
  folderName = repo;
658
861
  } else {
659
- if (["fixed-layout", "free-layout", "fixed-layout-simple", "free-layout-simple", "playground", "nextjs"].includes(projectName)) {
862
+ if ([
863
+ "fixed-layout",
864
+ "free-layout",
865
+ "fixed-layout-simple",
866
+ "free-layout-simple",
867
+ "playground",
868
+ "nextjs"
869
+ ].includes(projectName)) {
660
870
  folderName = `demo-${projectName}`;
661
871
  } else {
662
872
  console.error('Invalid projectName. Please run "npx create-app" to choose demo.');
@@ -664,19 +874,20 @@ var createApp = async (projectName) => {
664
874
  }
665
875
  }
666
876
  try {
667
- const targetDir = import_path7.default.join(process.cwd());
877
+ const targetDir = import_path9.default.join(process.cwd());
668
878
  const downloadPackage = async () => {
669
879
  try {
670
- const tarballBuffer = await (0, import_download2.default)(`https://registry.npmjs.org/@flowgram.ai/${folderName}/-/${folderName}-${latest}.tgz`);
671
- import_fs_extra.default.ensureDirSync(targetDir);
672
- const tempTarballPath = import_path7.default.join(process.cwd(), `${folderName}.tgz`);
673
- import_fs_extra.default.writeFileSync(tempTarballPath, tarballBuffer);
674
- await tar.x({
880
+ const url = `https://registry.npmjs.org/@flowgram.ai/${folderName}/-/${folderName}-${latest}.tgz`;
881
+ const tempTarballPath = import_path9.default.join(process.cwd(), `${folderName}.tgz`);
882
+ console.log(import_chalk7.default.blue(`Downloading ${url} ...`));
883
+ await downloadFile2(url, tempTarballPath);
884
+ import_fs_extra2.default.ensureDirSync(targetDir);
885
+ await tar2.x({
675
886
  file: tempTarballPath,
676
887
  C: targetDir
677
888
  });
678
- import_fs_extra.default.renameSync(import_path7.default.join(targetDir, "package"), import_path7.default.join(targetDir, folderName));
679
- import_fs_extra.default.unlinkSync(tempTarballPath);
889
+ import_fs_extra2.default.renameSync(import_path9.default.join(targetDir, "package"), import_path9.default.join(targetDir, folderName));
890
+ import_fs_extra2.default.unlinkSync(tempTarballPath);
680
891
  return true;
681
892
  } catch (error) {
682
893
  console.error(`Error downloading or extracting package: ${error}`);
@@ -684,8 +895,8 @@ var createApp = async (projectName) => {
684
895
  }
685
896
  };
686
897
  const res = await downloadPackage();
687
- const pkgJsonPath = import_path7.default.join(targetDir, folderName, "package.json");
688
- const data = import_fs_extra.default.readFileSync(pkgJsonPath, "utf-8");
898
+ const pkgJsonPath = import_path9.default.join(targetDir, folderName, "package.json");
899
+ const data = import_fs_extra2.default.readFileSync(pkgJsonPath, "utf-8");
689
900
  const packageLatestVersion = (0, import_child_process2.execSync)("npm view @flowgram.ai/core version --tag=latest latest").toString().trim();
690
901
  const jsonData = JSON.parse(data);
691
902
  if (jsonData.dependencies) {
@@ -694,15 +905,15 @@ var createApp = async (projectName) => {
694
905
  if (jsonData.devDependencies) {
695
906
  updateFlowGramVersions(jsonData.devDependencies, packageLatestVersion);
696
907
  }
697
- import_fs_extra.default.writeFileSync(pkgJsonPath, JSON.stringify(jsonData, null, 2), "utf-8");
908
+ import_fs_extra2.default.writeFileSync(pkgJsonPath, JSON.stringify(jsonData, null, 2), "utf-8");
698
909
  if (res) {
699
- console.log(import_chalk4.default.green(`${folderName} Demo project created successfully!`));
700
- console.log(import_chalk4.default.yellow("Run the following commands to start:"));
701
- console.log(import_chalk4.default.cyan(` cd ${folderName}`));
702
- console.log(import_chalk4.default.cyan(" npm install"));
703
- console.log(import_chalk4.default.cyan(" npm start"));
910
+ console.log(import_chalk7.default.green(`${folderName} Demo project created successfully!`));
911
+ console.log(import_chalk7.default.yellow("Run the following commands to start:"));
912
+ console.log(import_chalk7.default.cyan(` cd ${folderName}`));
913
+ console.log(import_chalk7.default.cyan(" npm install"));
914
+ console.log(import_chalk7.default.cyan(" npm start"));
704
915
  } else {
705
- console.log(import_chalk4.default.red("Download failed"));
916
+ console.log(import_chalk7.default.red("Download failed"));
706
917
  }
707
918
  } catch (error) {
708
919
  console.error("Error downloading repo:", error);
@@ -716,7 +927,21 @@ program.name("flowgram-cli").version("1.0.0").description("Flowgram CLI");
716
927
  program.command("create-app").description("Create a new flowgram project").argument("[string]", "Project name").action(async (projectName) => {
717
928
  await createApp(projectName);
718
929
  });
719
- program.command("materials").description("Sync materials to the project").argument("[string]", "Material name").option("--refresh-project-imports", "Refresh project imports to copied materials", false).action(async (materialName, options) => {
720
- await syncMaterial({ materialName, refreshProjectImports: options.refreshProjectImports });
930
+ program.command("materials").description("Sync materials to the project").argument(
931
+ "[string]",
932
+ "Material name or names\nExample 1: components/variable-selector \nExample2: components/variable-selector,effect/provideJsonSchemaOutputs"
933
+ ).option("--refresh-project-imports", "Refresh project imports to copied materials", false).option("--target-material-root-dir <string>", "Target directory to copy materials").option("--select-multiple", "Select multiple materials", false).action(async (materialName, options) => {
934
+ await syncMaterial({
935
+ materialName,
936
+ refreshProjectImports: options.refreshProjectImports,
937
+ targetMaterialRootDir: options.targetMaterialRootDir ? import_path10.default.join(process.cwd(), options.targetMaterialRootDir) : void 0,
938
+ selectMultiple: options.selectMultiple
939
+ });
940
+ });
941
+ program.command("find-used-materials").description("Find used materials in the project").action(async () => {
942
+ await findUsedMaterials();
943
+ });
944
+ program.command("update-version").description("Update flowgram version in the project").argument("[string]", "Flowgram version").action(async (version) => {
945
+ await updateFlowgramVersion(version);
721
946
  });
722
947
  program.parse(process.argv);