@flowgram.ai/form-materials 0.3.3 → 0.3.5

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.
Files changed (103) hide show
  1. package/bin/index.ts +5 -19
  2. package/bin/materials.ts +31 -89
  3. package/bin/project.ts +4 -0
  4. package/bin/utils/import.ts +127 -0
  5. package/bin/utils/traverse-file.ts +60 -0
  6. package/dist/esm/index.js +431 -505
  7. package/dist/esm/index.js.map +1 -1
  8. package/dist/index.d.mts +77 -23
  9. package/dist/index.d.ts +77 -23
  10. package/dist/index.js +657 -731
  11. package/dist/index.js.map +1 -1
  12. package/package.json +5 -5
  13. package/src/components/assign-row/index.tsx +4 -4
  14. package/src/components/assign-rows/index.tsx +1 -1
  15. package/src/components/batch-outputs/index.tsx +4 -3
  16. package/src/components/batch-outputs/types.ts +1 -1
  17. package/src/components/batch-variable-selector/index.tsx +1 -1
  18. package/src/components/code-editor-mini/index.tsx +1 -1
  19. package/src/components/condition-row/constants.ts +2 -2
  20. package/src/components/condition-row/hooks/useOp.tsx +13 -9
  21. package/src/components/condition-row/hooks/useRule.ts +8 -4
  22. package/src/components/condition-row/index.tsx +27 -10
  23. package/src/components/condition-row/types.ts +5 -7
  24. package/src/components/constant-input/index.tsx +5 -2
  25. package/src/components/constant-input/types.ts +1 -1
  26. package/src/components/display-flow-value/index.tsx +2 -2
  27. package/src/components/display-inputs-values/index.tsx +3 -2
  28. package/src/components/display-outputs/index.tsx +2 -1
  29. package/src/components/display-schema-tag/index.tsx +3 -2
  30. package/src/components/display-schema-tree/index.tsx +2 -1
  31. package/src/components/dynamic-value-input/hooks.ts +1 -1
  32. package/src/components/dynamic-value-input/index.tsx +13 -9
  33. package/src/components/inputs-values/index.tsx +7 -5
  34. package/src/components/inputs-values/types.ts +3 -3
  35. package/src/components/json-editor-with-variables/extensions/variable-tree.tsx +1 -1
  36. package/src/components/json-editor-with-variables/index.tsx +2 -1
  37. package/src/components/json-schema-editor/default-value.tsx +11 -105
  38. package/src/components/json-schema-editor/hooks.tsx +53 -94
  39. package/src/components/json-schema-editor/index.tsx +18 -12
  40. package/src/components/json-schema-editor/styles.tsx +0 -29
  41. package/src/components/prompt-editor/types.tsx +1 -1
  42. package/src/components/prompt-editor-with-inputs/extensions/inputs-tree.tsx +2 -1
  43. package/src/components/prompt-editor-with-inputs/index.tsx +3 -2
  44. package/src/components/prompt-editor-with-inputs/inputs-picker.tsx +1 -1
  45. package/src/components/prompt-editor-with-variables/extensions/variable-tree.tsx +1 -1
  46. package/src/components/prompt-editor-with-variables/index.tsx +2 -1
  47. package/src/components/type-selector/index.tsx +9 -7
  48. package/src/components/variable-selector/index.tsx +9 -5
  49. package/src/components/variable-selector/use-variable-tree.tsx +1 -1
  50. package/src/effects/auto-rename-ref/index.ts +1 -1
  51. package/src/effects/listen-ref-schema-change/index.ts +1 -1
  52. package/src/effects/listen-ref-value-change/index.ts +1 -1
  53. package/src/effects/provide-batch-input/index.ts +1 -1
  54. package/src/form-plugins/batch-outputs-plugin/index.ts +1 -1
  55. package/src/form-plugins/infer-assign-plugin/index.ts +1 -1
  56. package/src/form-plugins/infer-inputs-plugin/index.ts +1 -1
  57. package/src/plugins/json-schema-preset/type-definition/array.tsx +3 -1
  58. package/src/plugins/json-schema-preset/type-definition/boolean.tsx +4 -3
  59. package/src/plugins/json-schema-preset/type-definition/integer.tsx +2 -1
  60. package/src/plugins/json-schema-preset/type-definition/number.tsx +2 -1
  61. package/src/plugins/json-schema-preset/type-definition/object.tsx +3 -1
  62. package/src/plugins/json-schema-preset/type-definition/string.tsx +7 -1
  63. package/src/shared/index.ts +1 -0
  64. package/src/shared/inject-material/README.md +170 -0
  65. package/src/shared/inject-material/README.zh.md +174 -0
  66. package/src/shared/inject-material/index.tsx +87 -0
  67. package/src/components/assign-row/config.json +0 -11
  68. package/src/components/assign-rows/config.json +0 -11
  69. package/src/components/batch-outputs/config.json +0 -13
  70. package/src/components/batch-variable-selector/config.json +0 -9
  71. package/src/components/code-editor/config.json +0 -10
  72. package/src/components/code-editor-mini/config.json +0 -7
  73. package/src/components/condition-row/config.json +0 -13
  74. package/src/components/constant-input/config.json +0 -9
  75. package/src/components/display-flow-value/config.json +0 -8
  76. package/src/components/display-inputs-values/config.json +0 -9
  77. package/src/components/display-outputs/config.json +0 -10
  78. package/src/components/display-schema-tag/config.json +0 -10
  79. package/src/components/display-schema-tree/config.json +0 -11
  80. package/src/components/dynamic-value-input/config.json +0 -14
  81. package/src/components/inputs-values/config.json +0 -13
  82. package/src/components/json-editor-with-variables/config.json +0 -13
  83. package/src/components/json-schema-editor/config.json +0 -13
  84. package/src/components/json-schema-editor/utils.ts +0 -29
  85. package/src/components/prompt-editor/config.json +0 -9
  86. package/src/components/prompt-editor-with-inputs/config.json +0 -13
  87. package/src/components/prompt-editor-with-variables/config.json +0 -13
  88. package/src/components/type-selector/config.json +0 -9
  89. package/src/components/variable-selector/config.json +0 -9
  90. package/src/effects/auto-rename-ref/config.json +0 -5
  91. package/src/effects/listen-ref-schema-change/config.json +0 -10
  92. package/src/effects/listen-ref-value-change/config.json +0 -9
  93. package/src/effects/provide-batch-input/config.json +0 -5
  94. package/src/effects/provide-json-schema-outputs/config.json +0 -7
  95. package/src/effects/sync-variable-title/config.json +0 -5
  96. package/src/effects/validate-when-variable-sync/config.json +0 -5
  97. package/src/form-plugins/batch-outputs-plugin/config.json +0 -7
  98. package/src/form-plugins/infer-assign-plugin/config.json +0 -7
  99. package/src/form-plugins/infer-inputs-plugin/config.json +0 -9
  100. package/src/hooks/use-object-list/config.json +0 -8
  101. package/src/shared/format-legacy-refs/config.json +0 -5
  102. package/src/typings/flow-value/config.json +0 -7
  103. package/src/validate/validate-flow-value/config.json +0 -7
package/bin/index.ts CHANGED
@@ -5,7 +5,7 @@ import { Command } from 'commander';
5
5
  import chalk from 'chalk';
6
6
 
7
7
  import { getProjectInfo, installDependencies, ProjectInfo } from './project.js';
8
- import { bfsMaterials, copyMaterial, listAllMaterials, Material } from './materials.js';
8
+ import { copyMaterial, listAllMaterials, Material } from './materials.js';
9
9
 
10
10
  const program = new Command();
11
11
 
@@ -66,14 +66,13 @@ program
66
66
  process.exit(1);
67
67
  }
68
68
 
69
+ // 4. Copy the materials to the project
70
+ console.log(chalk.bold('The following materials will be added to your project'));
69
71
  console.log(material);
70
-
71
- // 3. Get the component dependencies by BFS (include depMaterials and depPackages)
72
- const { allMaterials, allPackages } = bfsMaterials(material!, materials);
72
+ let { packagesToInstall } = copyMaterial(material, projectInfo);
73
73
 
74
74
  // 4. Install the dependencies
75
- allPackages.push(`@flowgram.ai/editor`);
76
- const packagesToInstall: string[] = allPackages.map((_pkg) => {
75
+ packagesToInstall = packagesToInstall.map((_pkg) => {
77
76
  if (
78
77
  _pkg.startsWith(`@flowgram.ai/`) &&
79
78
  projectInfo.flowgramVersion !== 'workspace:*' &&
@@ -87,19 +86,6 @@ program
87
86
  console.log(chalk.bold('These npm dependencies will be added to your project'));
88
87
  console.log(packagesToInstall);
89
88
  installDependencies(packagesToInstall, projectInfo);
90
-
91
- // 5. Copy the materials to the project
92
- console.log(chalk.bold('These Materials will be added to your project'));
93
- console.log(allMaterials);
94
- copyMaterial(material, projectInfo, { overwrite: true });
95
-
96
- allMaterials.forEach((mat: Material) => {
97
- if (mat === material) {
98
- return;
99
- }
100
- // Add type for mat
101
- copyMaterial(mat, projectInfo, { overwrite: false });
102
- });
103
89
  });
104
90
 
105
91
  program.parse(process.argv);
package/bin/materials.ts CHANGED
@@ -7,6 +7,8 @@ import { fileURLToPath } from 'url';
7
7
  import path from 'path';
8
8
  import fs from 'fs';
9
9
 
10
+ import { traverseRecursiveFiles } from './utils/traverse-file';
11
+ import { replaceImport, traverseFileImports } from './utils/import';
10
12
  import { ProjectInfo } from './project'; // Import ProjectInfo
11
13
 
12
14
  const __filename = fileURLToPath(import.meta.url);
@@ -17,8 +19,6 @@ export interface Material {
17
19
  name: string;
18
20
  type: string;
19
21
  path: string;
20
- depPackages?: string[];
21
- depMaterials?: string[];
22
22
  [key: string]: any; // For other properties from config.json
23
23
  }
24
24
 
@@ -48,19 +48,7 @@ export function listAllMaterials(): Material[] {
48
48
  return null;
49
49
  }
50
50
 
51
- const configPath = path.join(materialsPath, _path, 'config.json');
52
- // Check if config.json exists before reading
53
- if (!fs.existsSync(configPath)) {
54
- console.warn(
55
- `Warning: config.json not found for material at ${path.join(materialsPath, _path)}`
56
- );
57
- return null;
58
- }
59
- const configContent = fs.readFileSync(configPath, 'utf8');
60
- const config = JSON.parse(configContent);
61
-
62
51
  return {
63
- ...config,
64
52
  name: _path, // Assuming the folder name is the material name
65
53
  type: _type,
66
54
  path: path.join(materialsPath, _path),
@@ -73,66 +61,12 @@ export function listAllMaterials(): Material[] {
73
61
  return _materials;
74
62
  }
75
63
 
76
- interface BfsResult {
77
- allMaterials: Material[];
78
- allPackages: string[];
79
- }
80
-
81
- export function bfsMaterials(material: Material, _materials: Material[] = []): BfsResult {
82
- function findConfigByName(name: string): Material | undefined {
83
- return _materials.find(
84
- (_config) => _config.name === name || `${_config.type}/${_config.name}` === name
85
- );
86
- }
87
-
88
- const queue: (Material | undefined)[] = [material]; // Queue can hold undefined if findConfigByName returns undefined
89
- const allMaterials = new Set<Material>();
90
- const allPackages = new Set<string>();
91
-
92
- while (queue.length > 0) {
93
- const _material = queue.shift();
94
- if (!_material || allMaterials.has(_material)) {
95
- // Check if _material is defined
96
- continue;
97
- }
98
- allMaterials.add(_material);
99
-
100
- if (_material.depPackages) {
101
- for (const _package of _material.depPackages) {
102
- allPackages.add(_package);
103
- }
104
- }
105
-
106
- if (_material.depMaterials) {
107
- for (const _materialName of _material.depMaterials) {
108
- const depMaterial = findConfigByName(_materialName);
109
- if (depMaterial) {
110
- // Ensure dependent material is found before adding to queue
111
- queue.push(depMaterial);
112
- } else {
113
- console.warn(
114
- `Warning: Dependent material "${_materialName}" not found for material "${_material.name}".`
115
- );
116
- }
117
- }
118
- }
119
- }
120
-
121
- return {
122
- allMaterials: Array.from(allMaterials),
123
- allPackages: Array.from(allPackages),
124
- };
125
- }
126
-
127
64
  export const copyMaterial = (
128
65
  material: Material,
129
- projectInfo: ProjectInfo,
130
- {
131
- overwrite,
132
- }: {
133
- overwrite?: boolean;
134
- } = {}
135
- ): void => {
66
+ projectInfo: ProjectInfo
67
+ ): {
68
+ packagesToInstall: string[];
69
+ } => {
136
70
  const sourceDir: string = material.path;
137
71
  const materialRoot: string = path.join(
138
72
  projectInfo.projectPath,
@@ -141,25 +75,33 @@ export const copyMaterial = (
141
75
  `${material.type}`
142
76
  );
143
77
  const targetDir = path.join(materialRoot, material.name);
144
-
145
- if (!overwrite && fs.readdirSync(targetDir)?.length > 0) {
146
- console.log(`Material ${material.name} already exists in ${materialRoot}, skip copying.`);
147
- return;
148
- }
78
+ const packagesToInstall: Set<string> = new Set();
149
79
 
150
80
  fs.cpSync(sourceDir, targetDir, { recursive: true });
151
81
 
152
- let materialRootIndexTs: string = '';
153
- const indexTsPath = path.join(materialRoot, 'index.ts');
154
- if (fs.existsSync(indexTsPath)) {
155
- materialRootIndexTs = fs.readFileSync(indexTsPath, 'utf8');
156
- }
157
- if (!materialRootIndexTs.includes(material.name)) {
158
- fs.writeFileSync(
159
- indexTsPath,
160
- `${materialRootIndexTs}${materialRootIndexTs.endsWith('\n') ? '' : '\n'}export * from './${
161
- material.name
162
- }';\n`
163
- );
82
+ for (const file of traverseRecursiveFiles(targetDir)) {
83
+ if (['.ts', '.tsx'].includes(file.suffix)) {
84
+ for (const importDeclaration of traverseFileImports(file.content)) {
85
+ const { source } = importDeclaration;
86
+
87
+ if (source.startsWith('@/')) {
88
+ // is inner import
89
+ console.log(`Replace Import from ${source} to @flowgram.ai/form-materials`);
90
+ file.replace((content) =>
91
+ replaceImport(content, importDeclaration, [
92
+ { ...importDeclaration, source: '@flowgram.ai/form-materials' },
93
+ ])
94
+ );
95
+ packagesToInstall.add('@flowgram.ai/form-materials');
96
+ } else if (!source.startsWith('.') && !source.startsWith('react')) {
97
+ // check if is third party npm packages
98
+ packagesToInstall.add(source);
99
+ }
100
+ }
101
+ }
164
102
  }
103
+
104
+ return {
105
+ packagesToInstall: [...packagesToInstall],
106
+ };
165
107
  };
package/bin/project.ts CHANGED
@@ -70,22 +70,26 @@ export function findRushJson(startPath: string): string | null {
70
70
 
71
71
  export function installDependencies(packages: string[], projectInfo: ProjectInfo): void {
72
72
  if (fs.existsSync(path.join(projectInfo.projectPath, 'yarn.lock'))) {
73
+ console.log(`yarn add ${packages.join(' ')}`);
73
74
  execSync(`yarn add ${packages.join(' ')}`, { stdio: 'inherit' });
74
75
  return;
75
76
  }
76
77
 
77
78
  if (fs.existsSync(path.join(projectInfo.projectPath, 'pnpm-lock.yaml'))) {
79
+ console.log(`pnpm add ${packages.join(' ')}`);
78
80
  execSync(`pnpm add ${packages.join(' ')}`, { stdio: 'inherit' });
79
81
  return;
80
82
  }
81
83
 
82
84
  // rush monorepo
83
85
  if (findRushJson(projectInfo.projectPath)) {
86
+ console.log(`rush add ${packages.map((pkg) => `--package ${pkg}`).join(' ')}`);
84
87
  execSync(`rush add ${packages.map((pkg) => `--package ${pkg}`).join(' ')}`, {
85
88
  stdio: 'inherit',
86
89
  });
87
90
  return;
88
91
  }
89
92
 
93
+ console.log(`npm install ${packages.join(' ')}`);
90
94
  execSync(`npm install ${packages.join(' ')}`, { stdio: 'inherit' });
91
95
  }
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ /**
7
+ * Cases
8
+ * import { A, B } from 'module';
9
+ * import A from 'module';
10
+ * import * as C from 'module';
11
+ * import D, { type E, F } from 'module';
12
+ * import A, { B as B1 } from 'module';
13
+ */
14
+ interface ImportDeclaration {
15
+ // origin statement
16
+ statement: string;
17
+
18
+ // import { A, B } from 'module';
19
+ namedImports?: {
20
+ local?: string;
21
+ imported: string;
22
+ typeOnly?: boolean;
23
+ }[];
24
+
25
+ // import A from 'module';
26
+ defaultImport?: string;
27
+
28
+ // import * as C from 'module';
29
+ namespaceImport?: string;
30
+
31
+ source: string;
32
+ }
33
+
34
+ export function assembleImport(declaration: ImportDeclaration): string {
35
+ const { namedImports, defaultImport, namespaceImport, source } = declaration;
36
+ const importClauses = [];
37
+ if (namedImports) {
38
+ importClauses.push(
39
+ `{ ${namedImports
40
+ .map(
41
+ ({ local, imported, typeOnly }) =>
42
+ `${typeOnly ? 'type ' : ''}${imported}${local ? ` as ${local}` : ''}`
43
+ )
44
+ .join(', ')} }`
45
+ );
46
+ }
47
+ if (defaultImport) {
48
+ importClauses.push(defaultImport);
49
+ }
50
+ if (namespaceImport) {
51
+ importClauses.push(`* as ${namespaceImport}`);
52
+ }
53
+ return `import ${importClauses.join(', ')} from '${source}'`;
54
+ }
55
+
56
+ export function replaceImport(
57
+ fileContent: string,
58
+ origin: ImportDeclaration,
59
+ replaceTo: ImportDeclaration[]
60
+ ): string {
61
+ const replaceImportStatements = replaceTo.map(assembleImport);
62
+ // replace origin statement
63
+ return fileContent.replace(origin.statement, replaceImportStatements.join('\n'));
64
+ }
65
+
66
+ export function* traverseFileImports(fileContent: string): Generator<ImportDeclaration> {
67
+ // 匹配所有 import 语句的正则表达式
68
+ const importRegex =
69
+ /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;
70
+
71
+ let match;
72
+ while ((match = importRegex.exec(fileContent)) !== null) {
73
+ const [fullMatch, defaultPart, namespacePart, namedPart, defaultPart2, source] = match;
74
+
75
+ const declaration: ImportDeclaration = {
76
+ statement: fullMatch,
77
+ source: source,
78
+ };
79
+
80
+ // 处理默认导入
81
+ const defaultImport = defaultPart?.trim() || defaultPart2?.trim();
82
+ if (defaultImport && !namespacePart && !namedPart) {
83
+ declaration.defaultImport = defaultImport;
84
+ } else if (defaultImport && (namespacePart || namedPart)) {
85
+ declaration.defaultImport = defaultImport;
86
+ }
87
+
88
+ // 处理命名空间导入 (* as)
89
+ if (namespacePart) {
90
+ declaration.namespaceImport = namespacePart.trim();
91
+ }
92
+
93
+ // 处理命名导入
94
+ if (namedPart) {
95
+ const namedImports = [];
96
+ const namedItems = namedPart
97
+ .split(',')
98
+ .map((item) => item.trim())
99
+ .filter(Boolean);
100
+
101
+ for (const item of namedItems) {
102
+ const typeOnly = item.startsWith('type ');
103
+ const cleanItem = typeOnly ? item.slice(5).trim() : item;
104
+
105
+ if (cleanItem.includes(' as ')) {
106
+ const [imported, local] = cleanItem.split(' as ').map((s) => s.trim());
107
+ namedImports.push({
108
+ imported,
109
+ local,
110
+ typeOnly,
111
+ });
112
+ } else {
113
+ namedImports.push({
114
+ imported: cleanItem,
115
+ typeOnly,
116
+ });
117
+ }
118
+ }
119
+
120
+ if (namedImports.length > 0) {
121
+ declaration.namedImports = namedImports;
122
+ }
123
+ }
124
+
125
+ yield declaration;
126
+ }
127
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import path from 'path';
7
+ import fs from 'fs';
8
+
9
+ class File {
10
+ content: string;
11
+
12
+ isUtf8: boolean;
13
+
14
+ relativePath: string;
15
+
16
+ path: string;
17
+
18
+ suffix: string;
19
+
20
+ constructor(filePath: string, public root: string = '/') {
21
+ this.path = filePath;
22
+ this.relativePath = path.relative(this.root, this.path);
23
+ this.suffix = path.extname(this.path);
24
+
25
+ // Check if exists
26
+ if (!fs.existsSync(this.path)) {
27
+ throw Error(`File ${path} Not Exists`);
28
+ }
29
+
30
+ // If no utf-8, skip
31
+ try {
32
+ this.content = fs.readFileSync(this.path, 'utf-8');
33
+ this.isUtf8 = true;
34
+ } catch (e) {
35
+ this.isUtf8 = false;
36
+ return;
37
+ }
38
+ }
39
+
40
+ replace(updater: (content: string) => string) {
41
+ if (!this.isUtf8) {
42
+ console.warn('Not UTF-8 file skipped: ', this.path);
43
+ return;
44
+ }
45
+ this.content = updater(this.content);
46
+ fs.writeFileSync(this.path, this.content, 'utf-8');
47
+ }
48
+ }
49
+
50
+ export function* traverseRecursiveFiles(folder: string): Generator<File> {
51
+ const files = fs.readdirSync(folder);
52
+ for (const file of files) {
53
+ const filePath = path.join(folder, file);
54
+ if (fs.statSync(filePath).isDirectory()) {
55
+ yield* traverseRecursiveFiles(filePath);
56
+ } else {
57
+ yield new File(filePath);
58
+ }
59
+ }
60
+ }