materials.ts 4.4 KB

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