| 43 | // this is called in the build script entry once |
| 44 | // so the data can be shared across concurrent Rollup processes |
| 45 | export function scanEnums() { |
| 46 | /** @type {{ [file: string]: EnumDeclaration[] }} */ |
| 47 | const declarations = Object.create(null) |
| 48 | /** @type {{ [id_key: `${string}.${string}`]: string; }} */ |
| 49 | const defines = Object.create(null) |
| 50 | |
| 51 | // 1. grep for files with exported enum |
| 52 | const { stdout } = spawnSync('git', ['grep', `export enum`]) |
| 53 | const files = [ |
| 54 | ...new Set( |
| 55 | stdout |
| 56 | .toString() |
| 57 | .trim() |
| 58 | .split('\n') |
| 59 | .map(line => line.split(':')[0]), |
| 60 | ), |
| 61 | ] |
| 62 | |
| 63 | // 2. parse matched files to collect enum info |
| 64 | for (const relativeFile of files) { |
| 65 | const file = path.resolve(process.cwd(), relativeFile) |
| 66 | const content = readFileSync(file, 'utf-8') |
| 67 | const ast = parse(content, { |
| 68 | plugins: ['typescript'], |
| 69 | sourceType: 'module', |
| 70 | }) |
| 71 | |
| 72 | /** @type {Set<string>} */ |
| 73 | const enumIds = new Set() |
| 74 | for (const node of ast.program.body) { |
| 75 | if ( |
| 76 | node.type === 'ExportNamedDeclaration' && |
| 77 | node.declaration && |
| 78 | node.declaration.type === 'TSEnumDeclaration' |
| 79 | ) { |
| 80 | const decl = node.declaration |
| 81 | const id = decl.id.name |
| 82 | if (enumIds.has(id)) { |
| 83 | throw new Error( |
| 84 | `not support declaration merging for enum ${id} in ${file}`, |
| 85 | ) |
| 86 | } |
| 87 | enumIds.add(id) |
| 88 | /** @type {string | number | undefined} */ |
| 89 | let lastInitialized |
| 90 | /** @type {Array<EnumMember>} */ |
| 91 | const members = [] |
| 92 | |
| 93 | for (let i = 0; i < decl.members.length; i++) { |
| 94 | const e = decl.members[i] |
| 95 | const key = e.id.type === 'Identifier' ? e.id.name : e.id.value |
| 96 | const fullKey = /** @type {const} */ (`${id}.${key}`) |
| 97 | const saveValue = (/** @type {string | number} */ value) => { |
| 98 | // We need allow same name enum in different file. |
| 99 | // For example: enum ErrorCodes exist in both @vue/compiler-core and @vue/runtime-core |
| 100 | // But not allow `ErrorCodes.__EXTEND_POINT__` appear in two same name enum |
| 101 | if (fullKey in defines) { |
| 102 | throw new Error(`name conflict for enum ${id} in ${file}`) |