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