Skip to content

Commit b477181

Browse files
authored
feat(material): use tsx in cli (bytedance#295)
1 parent 8a6b50b commit b477181

File tree

7 files changed

+198
-124
lines changed

7 files changed

+198
-124
lines changed

common/config/rush/pnpm-lock.yaml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/materials/form-materials/bin/index.js renamed to packages/materials/form-materials/bin/index.ts

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,31 @@
1-
#!/usr/bin/env node
1+
#!/usr/bin/env -S npx tsx@latest
22

3-
import chalk from 'chalk';
4-
import { Command } from 'commander';
53
import inquirer from 'inquirer';
4+
import { Command } from 'commander';
5+
import chalk from 'chalk';
66

7-
import { bfsMaterials, copyMaterial, listAllMaterials } from './materials.js';
8-
import { getProjectInfo, installDependencies } from './project.js';
7+
import { getProjectInfo, installDependencies, ProjectInfo } from './project.js';
8+
import { bfsMaterials, copyMaterial, listAllMaterials, Material } from './materials.js';
99

1010
const program = new Command();
1111

1212
program
13-
.version('1.0.0')
13+
.version('1.0.1')
1414
.description('Add official materials to your project')
1515
.argument('[materialName]', 'Optional material name to skip selection (format: type/name)')
16-
.action(async (materialName) => {
16+
.action(async (materialName?: string) => {
17+
// materialName can be undefined
1718
console.log(chalk.bgGreenBright('Welcome to @flowgram.ai/form-materials CLI!'));
1819

19-
const projectInfo = getProjectInfo();
20+
const projectInfo: ProjectInfo = getProjectInfo();
2021

2122
console.log(chalk.bold('Project Info:'));
2223
console.log(chalk.black(` - Flowgram Version: ${projectInfo.flowgramVersion}`));
2324
console.log(chalk.black(` - Project Path: ${projectInfo.projectPath}`));
2425

25-
const materials = listAllMaterials();
26+
const materials: Material[] = listAllMaterials();
2627

27-
let material;
28+
let material: Material | undefined; // material can be undefined
2829

2930
// Check if materialName is provided and exists in materials
3031
if (materialName) {
@@ -42,7 +43,9 @@ program
4243
// If material not found or materialName not provided, prompt user to select
4344
if (!material) {
4445
// User select one component
45-
const result = await inquirer.prompt([
46+
const result = await inquirer.prompt<{
47+
material: Material; // Specify type for prompt result
48+
}>([
4649
{
4750
type: 'list',
4851
name: 'material',
@@ -57,18 +60,23 @@ program
5760
]);
5861
material = result.material;
5962
}
63+
// Ensure material is defined before proceeding
64+
if (!material) {
65+
console.error(chalk.red('No material selected. Exiting.'));
66+
process.exit(1);
67+
}
6068

6169
console.log(material);
6270

6371
// 3. Get the component dependencies by BFS (include depMaterials and depPackages)
64-
const { allMaterials, allPackages } = bfsMaterials(material, materials);
72+
const { allMaterials, allPackages } = bfsMaterials(material!, materials);
6573

6674
// 4. Install the dependencies
6775
let flowgramPackage = `@flowgram.ai/editor`;
6876
if (projectInfo.flowgramVersion !== 'workspace:*') {
6977
flowgramPackage = `@flowgram.ai/editor@${projectInfo.flowgramVersion}`;
7078
}
71-
const packagesToInstall = [flowgramPackage, ...allPackages];
79+
const packagesToInstall: string[] = [flowgramPackage, ...allPackages];
7280

7381
console.log(chalk.bold('These npm dependencies will be added to your project'));
7482
console.log(packagesToInstall);
@@ -77,8 +85,9 @@ program
7785
// 5. Copy the materials to the project
7886
console.log(chalk.bold('These Materials will be added to your project'));
7987
console.log(allMaterials);
80-
allMaterials.forEach((material) => {
81-
copyMaterial(material, projectInfo);
88+
allMaterials.forEach((mat: Material) => {
89+
// Add type for mat
90+
copyMaterial(mat, projectInfo);
8291
});
8392
});
8493

packages/materials/form-materials/bin/materials.js

Lines changed: 0 additions & 93 deletions
This file was deleted.
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import { fileURLToPath } from 'url';
2+
import path from 'path';
3+
import fs from 'fs';
4+
5+
import { ProjectInfo } from './project'; // Import ProjectInfo
6+
7+
const __filename = fileURLToPath(import.meta.url);
8+
const __dirname = path.dirname(__filename);
9+
10+
// Added type definitions
11+
export interface Material {
12+
name: string;
13+
type: string;
14+
path: string;
15+
depPackages?: string[];
16+
depMaterials?: string[];
17+
[key: string]: any; // For other properties from config.json
18+
}
19+
20+
const _types: string[] = ['components', 'effects', 'utils', 'typings'];
21+
22+
export function listAllMaterials(): Material[] {
23+
const _materials: Material[] = [];
24+
25+
for (const _type of _types) {
26+
// 在 Node.js 中,import.meta.dirname 不可用,可使用 import.meta.url 结合 url 模块来获取目录路径
27+
28+
const materialsPath: string = path.join(__dirname, '..', 'src', _type);
29+
_materials.push(
30+
...fs
31+
.readdirSync(materialsPath)
32+
.map((_path: string) => {
33+
if (_path === 'index.ts') {
34+
return null;
35+
}
36+
37+
const configPath = path.join(materialsPath, _path, 'config.json');
38+
// Check if config.json exists before reading
39+
if (!fs.existsSync(configPath)) {
40+
console.warn(
41+
`Warning: config.json not found for material at ${path.join(materialsPath, _path)}`
42+
);
43+
return null;
44+
}
45+
const configContent = fs.readFileSync(configPath, 'utf8');
46+
const config = JSON.parse(configContent);
47+
48+
return {
49+
...config,
50+
name: _path, // Assuming the folder name is the material name
51+
type: _type,
52+
path: path.join(materialsPath, _path),
53+
} as Material;
54+
})
55+
.filter((material): material is Material => material !== null)
56+
);
57+
}
58+
59+
return _materials;
60+
}
61+
62+
interface BfsResult {
63+
allMaterials: Material[];
64+
allPackages: string[];
65+
}
66+
67+
export function bfsMaterials(material: Material, _materials: Material[] = []): BfsResult {
68+
function findConfigByName(name: string): Material | undefined {
69+
return _materials.find(
70+
(_config) => _config.name === name || `${_config.type}/${_config.name}` === name
71+
);
72+
}
73+
74+
const queue: (Material | undefined)[] = [material]; // Queue can hold undefined if findConfigByName returns undefined
75+
const allMaterials = new Set<Material>();
76+
const allPackages = new Set<string>();
77+
78+
while (queue.length > 0) {
79+
const _material = queue.shift();
80+
if (!_material || allMaterials.has(_material)) {
81+
// Check if _material is defined
82+
continue;
83+
}
84+
allMaterials.add(_material);
85+
86+
if (_material.depPackages) {
87+
for (const _package of _material.depPackages) {
88+
allPackages.add(_package);
89+
}
90+
}
91+
92+
if (_material.depMaterials) {
93+
for (const _materialName of _material.depMaterials) {
94+
const depMaterial = findConfigByName(_materialName);
95+
if (depMaterial) {
96+
// Ensure dependent material is found before adding to queue
97+
queue.push(depMaterial);
98+
} else {
99+
console.warn(
100+
`Warning: Dependent material "${_materialName}" not found for material "${_material.name}".`
101+
);
102+
}
103+
}
104+
}
105+
}
106+
107+
return {
108+
allMaterials: Array.from(allMaterials),
109+
allPackages: Array.from(allPackages),
110+
};
111+
}
112+
113+
export const copyMaterial = (material: Material, projectInfo: ProjectInfo): void => {
114+
const sourceDir: string = material.path;
115+
const materialRoot: string = path.join(
116+
projectInfo.projectPath,
117+
'src',
118+
'form-materials',
119+
`${material.type}`
120+
);
121+
const targetDir = path.join(materialRoot, material.name);
122+
fs.cpSync(sourceDir, targetDir, { recursive: true });
123+
124+
let materialRootIndexTs: string = '';
125+
const indexTsPath = path.join(materialRoot, 'index.ts');
126+
if (fs.existsSync(indexTsPath)) {
127+
materialRootIndexTs = fs.readFileSync(indexTsPath, 'utf8');
128+
}
129+
if (!materialRootIndexTs.includes(material.name)) {
130+
fs.writeFileSync(
131+
indexTsPath,
132+
`${materialRootIndexTs}${materialRootIndexTs.endsWith('\n') ? '' : '\n'}export * from './${
133+
material.name
134+
}';\n`
135+
);
136+
}
137+
};

0 commit comments

Comments
 (0)