@vureact/compiler-core 1.3.0 → 1.4.0

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.
@@ -1,11 +1,150 @@
1
1
  import { GeneratorOptions as GeneratorOptions$1 } from '@babel/generator';
2
+ import { ParseResult as ParseResult$1 } from '@babel/parser';
2
3
  import * as t from '@babel/types';
3
4
  import { Expression, ArrayExpression, JSXIdentifier } from '@babel/types';
4
- import { ParseResult as ParseResult$1 } from '@babel/parser';
5
5
  import { RootNode, SourceLocation } from '@vue/compiler-core';
6
6
  import { SFCTemplateBlock, SFCScriptBlock, SFCStyleBlock } from '@vue/compiler-sfc';
7
7
  import { Options } from 'prettier';
8
8
 
9
+ interface FileLockOptions {
10
+ /**
11
+ * 锁过期时间(毫秒)
12
+ * 默认: 10000 (10秒)
13
+ */
14
+ stale?: number;
15
+ /**
16
+ * 锁更新间隔(毫秒)
17
+ * 默认: stale / 2
18
+ */
19
+ update?: number;
20
+ /**
21
+ * 重试配置
22
+ * 可以是重试次数或 retry 选项对象
23
+ * 默认: 5
24
+ */
25
+ retries?: number | {
26
+ retries?: number;
27
+ factor?: number;
28
+ minTimeout?: number;
29
+ maxTimeout?: number;
30
+ randomize?: boolean;
31
+ };
32
+ /**
33
+ * 是否解析符号链接
34
+ * 默认: true
35
+ */
36
+ realpath?: boolean;
37
+ /**
38
+ * 自定义锁文件路径
39
+ * 默认: `${filePath}.lock`
40
+ */
41
+ lockfilePath?: string;
42
+ }
43
+
44
+ type CompilationUnit = SFCUnit | ScriptUnit | StyleUnit;
45
+ interface SFCUnit extends BaseUnit {
46
+ type: CacheKey.SFC;
47
+ output?: {
48
+ jsx: OutputItem;
49
+ css: Partial<OutputItem>;
50
+ };
51
+ }
52
+ interface ScriptUnit extends BaseUnit {
53
+ type: CacheKey.SCRIPT;
54
+ output?: {
55
+ script: OutputItem;
56
+ };
57
+ }
58
+ interface StyleUnit extends Omit<BaseUnit, 'hasRoute'> {
59
+ type: CacheKey.STYLE;
60
+ output?: {
61
+ style: OutputItem;
62
+ };
63
+ }
64
+ interface AssetUnit extends Omit<BaseUnit, 'fileId' | 'source' | 'hasRoute'> {
65
+ type: CacheKey.ASSET;
66
+ }
67
+ interface BaseUnit extends FileMeta {
68
+ file: string;
69
+ fileId: string;
70
+ source: string;
71
+ hasRoute?: boolean;
72
+ }
73
+ interface OutputItem {
74
+ file: string;
75
+ code: string;
76
+ }
77
+
78
+ type LoadedCache<T = CacheMeta> = {
79
+ key: CacheKey;
80
+ target: T[];
81
+ source: CacheList;
82
+ };
83
+ type CacheMeta = Vue2ReactCacheMeta | FileCacheMeta;
84
+ declare enum CacheKey {
85
+ SFC = "sfc",
86
+ SCRIPT = "script",
87
+ STYLE = "style",
88
+ ASSET = "copied"
89
+ }
90
+ interface CacheList {
91
+ [CacheKey.SFC]: Vue2ReactCacheMeta[];
92
+ [CacheKey.SCRIPT]: ScriptCacheMeta[];
93
+ [CacheKey.STYLE]: StyleCacheMeta[];
94
+ [CacheKey.ASSET]: FileCacheMeta[];
95
+ }
96
+ type Vue2ReactCacheMeta = Omit<SFCUnit, 'source'>;
97
+ type ScriptCacheMeta = Omit<ScriptUnit, 'source'>;
98
+ type StyleCacheMeta = Omit<StyleUnit, 'source'>;
99
+ interface FileCacheMeta extends FileMeta {
100
+ file: string;
101
+ }
102
+ interface FileMeta {
103
+ fileSize: number;
104
+ mtime: number;
105
+ hash?: string;
106
+ }
107
+ interface CacheCheckResult {
108
+ shouldCompile: boolean;
109
+ hash?: string;
110
+ }
111
+
112
+ type CompilationResult = SFCCompilationResult | ScriptCompilationResult | StyleCompilationResult;
113
+ interface SFCCompilationResult extends BaseCompilationResult {
114
+ fileInfo: {
115
+ jsx: {
116
+ file: string;
117
+ lang: string;
118
+ };
119
+ css: {
120
+ file?: string;
121
+ hash?: string;
122
+ code?: string;
123
+ };
124
+ };
125
+ }
126
+ interface ScriptCompilationResult extends BaseCompilationResult {
127
+ fileInfo: {
128
+ script: {
129
+ file: string;
130
+ lang: string;
131
+ };
132
+ };
133
+ }
134
+ interface StyleCompilationResult extends Omit<BaseCompilationResult, 'hasRoute' | keyof GeneratorResult> {
135
+ code: string;
136
+ fileInfo: {
137
+ style: {
138
+ file: string;
139
+ lang: string;
140
+ };
141
+ };
142
+ }
143
+ interface BaseCompilationResult extends GeneratorResult {
144
+ fileId: string;
145
+ hasRoute?: boolean;
146
+ }
147
+
9
148
  type LangType = 'js' | 'jsx' | 'ts' | 'tsx';
10
149
 
11
150
  type ReactiveTypes = 'ref' | 'reactive' | 'indirect' | 'none';
@@ -122,1288 +261,1078 @@ interface IPropsContext {
122
261
  slotTypes: t.TSType[];
123
262
  }
124
263
 
125
- interface ParseResult {
126
- template: BlockIR<SFCTemplateBlock, RootNode>;
127
- script: BlockIR<SFCScriptBlock, ParseResult$1>;
128
- style: BlockIR<SFCStyleBlock, undefined>;
129
- }
130
- type BlockIR<S, T> = {
131
- source?: S;
132
- ast: T;
133
- } | null;
134
- interface ParserOptions {
135
- plugins?: PluginRegister<ParseResult>;
136
- }
137
- /**
138
- * 解析 Vue 单文件组件(SFC)源码,生成结构化解析结果。
139
- *
140
- * 此函数是解析阶段的核心入口,
141
- * 负责将 Vue SFC 源码解析为包含模板、脚本、样式等各个块的结构化数据。
142
- *
143
- * @param source - Vue 单文件组件的源码字符串
144
- * @param ctx - 编译上下文对象
145
- * @param plugins - 可选的插件注册表,用于对解析结果进行自定义处理和增强
146
- * @returns 解析结果对象,包含模板、脚本、样式块的解析信息
147
- * @throws 不会直接抛出异常,错误信息会通过日志系统记录
148
- *
149
- * @remarks
150
- * - 函数内部使用 Vue 官方的 `@vue/compiler-sfc` 进行基础解析
151
- * - 解析结果会经过后处理阶段,包括脚本元数据扫描
152
- * - 插件按照注册顺序依次执行,可以对解析结果进行修改或增强
153
- * - 错误处理:语法错误和编译错误会通过日志系统记录,不会中断执行
154
- *
155
- * @example
156
- * ```typescript
157
- * // 基础用法:解析一个简单的 Vue 组件
158
- *
159
- * const vueSource = `
160
- * <template>
161
- * <div class="greeting">
162
- * Hello, {{ name }}!
163
- * </div>
164
- * </template>
165
- *
166
- * <script setup lang="ts">
167
- * import { ref } from 'vue'
168
- *
169
- * const name = ref('World')
170
- * const count = ref(0)
171
- *
172
- * function increment() {
173
- * count.value++
174
- * }
175
- * </script>
176
- *
177
- * <style scoped>
178
- * .greeting {
179
- * color: #42b983;
180
- * font-size: 1.5rem;
181
- * }
182
- * </style>
183
- * `;
184
- *
185
- * const ctx: ICompilationContext = {
186
- * filename: 'MyComponent.vue',
187
- * // 其他上下文配置...
188
- * };
189
- *
190
- * const result = parseSFC(vueSource, ctx);
191
- *
192
- * // 访问解析结果
193
- * console.log(result.template?.ast); // 模板的 AST 节点
194
- * console.log(result.script?.ast); // 脚本的 Babel 解析结果
195
- * console.log(result.style?.source); // 样式块原始信息
196
- *
197
- * // 使用可选插件配置,进行自定义处理
198
- * const options: ParserOptions = {
199
- * plugins: {
200
- * myPlugin: (result, ctx) => {
201
- * // 提取组件元数据
202
- * const componentName = extractComponentName(result);
203
- * // 添加自定义分析结果
204
- * result.metadata = {
205
- * name: componentName,
206
- * analyzedAt: new Date().toISOString()
207
- * };
208
- * }
209
- * }
210
- * };
211
- *
212
- * const resultWithPlugin = parseSFC(vueSource, compilationContext, options);
213
- * ```
214
- */
215
- declare function parseSFC(source: string, ctx: ICompilationContext, options?: ParserOptions): ParseResult;
216
-
217
- /**
218
- * 仅用于解析 script 文件,参数与 parseSFC 一致
219
- */
220
- declare function parseOnlyScript(source: string, ctx: ICompilationContext, options?: ParserOptions): ParseResult;
221
-
222
- /**
223
- * 解析 Vue 组件源码的统一入口函数。
224
- *
225
- * 根据输入类型自动选择解析器:
226
- * - `sfc`: 解析 Vue 单文件组件(包含 template/script/style)
227
- * - `script-*`: 仅解析脚本文件(如 .js、.ts)
228
- *
229
- * @param source - 源码字符串
230
- * @param ctx - 编译上下文,包含输入类型、文件名等信息
231
- * @param options - 可选的解析器配置,如插件
232
- * @returns 解析结果对象,包含模板、脚本、样式的结构化数据
233
- */
234
- declare function parse(source: string, ctx: ICompilationContext, options?: ParserOptions): ParseResult;
235
-
236
- interface ScriptBlockIR {
237
- /** Transformed full script AST (used for script-only input). */
238
- scriptAST?: ParseResult$1;
239
- imports: t.ImportDeclaration[];
240
- exports: t.ExportDeclaration[];
241
- tsTypes: t.TypeScript[];
242
- /** Executable statements extracted from script block. */
243
- statement: {
244
- /** Statements hoisted outside component function. */
245
- global: t.Node[];
246
- /** Statements kept inside component function. */
247
- local: ParseResult$1<t.File> | null;
248
- };
264
+ type CompilerPlugins = PluginRegister<CompilationResult> & {
265
+ /**
266
+ * Register parser plugins
267
+ */
268
+ parser?: PluginRegister<ParseResult>;
269
+ /**
270
+ * Register transformer plugins
271
+ */
272
+ transformer?: PluginRegister<ReactIRDescriptor>;
273
+ /**
274
+ * Register codegen plugins
275
+ */
276
+ codegen?: PluginRegister<GeneratorResult>;
277
+ };
278
+ interface PluginRegister<T> {
279
+ [name: string]: (result: T, ctx: ICompilationContext) => void;
249
280
  }
250
281
 
251
- declare const enum NodeTypes {
252
- FRAGMENT = 0,
253
- ELEMENT = 1,
254
- TEXT = 2,
255
- COMMENT = 3,
256
- JSX_INTERPOLATION = 4
257
- }
258
- declare const enum PropTypes {
259
- ATTRIBUTE = 1,
260
- SLOT = 2,
261
- EVENT = 3,
262
- DYNAMIC_ATTRIBUTE = 4
263
- }
264
- interface BabelExp<T = Expression> {
265
- content: string;
266
- ast: T;
267
- }
268
-
269
- interface BaseSimpleNodeIR {
270
- type: NodeTypes;
271
- content: string;
272
- babelExp: Expression;
273
- }
274
- interface FragmentNodeIR {
275
- type: NodeTypes;
276
- children: TemplateChildNodeIR[];
277
- }
278
-
279
- interface ElementNodeIR extends BaseElementNodeIR {
280
- type: NodeTypes;
281
- props: (PropsIR | SlotPropsIR)[];
282
- children: TemplateChildNodeIR[];
283
- meta: Partial<ElementNodeIRMeta>;
284
- conditionIsHandled: boolean;
285
- isBuiltIn?: boolean;
286
- isRoute?: boolean;
287
- }
288
- interface BaseElementNodeIR {
289
- tag: string;
290
- isComponent?: boolean;
291
- isSelfClosing?: boolean;
292
- ref?: string;
293
- loc?: SourceLocation;
294
- }
295
- interface ElementNodeIRMeta {
296
- condition: ConditionMeta;
297
- loop: LoopMeta;
298
- memo: MemoMeta;
299
- show: ShowMeta;
300
- }
301
- type ConditionMeta = {
302
- if?: boolean;
303
- elseIf?: boolean;
304
- else?: boolean;
305
- value: string;
306
- babelExp: BabelExp;
307
- next?: ElementNodeIR;
308
- isHandled: boolean;
309
- };
310
- type LoopMeta = {
311
- isLoop?: boolean;
312
- value: {
313
- source: string;
314
- value: string;
315
- key?: string;
316
- index?: string;
317
- };
318
- isHandled: boolean;
319
- };
320
- type MemoMeta = {
321
- isMemo?: boolean;
322
- value: string;
323
- babelExp: BabelExp<ArrayExpression>;
324
- isHandled: boolean;
325
- };
326
- type ShowMeta = {
327
- isShow?: boolean;
328
- value: string;
329
- babelExp: BabelExp;
330
- };
331
-
332
- interface PropsIR {
333
- type: PropTypes;
334
- rawName?: string;
335
- name: string;
336
- isStatic?: boolean;
337
- modifiers?: string[];
338
- value: PropIRValue;
339
- isKeyLessVBind?: boolean;
340
- babelExp: BabelExp<JSXIdentifier | Expression>;
282
+ interface CompilerOptions {
283
+ /**
284
+ * Manually specify the root directory.
285
+ * @default process.cwd()
286
+ */
287
+ root?: string;
288
+ /**
289
+ * Path to the source file or directory.
290
+ * - If it is a file, compile the single file.
291
+ * - If it is a directory, recursively compile all .vue files under the directory.
292
+ *
293
+ * @default
294
+ * 'src/' // The src directory under the root directory
295
+ */
296
+ input?: string;
297
+ /**
298
+ * Whether to enable build cache and reuse the previous cache results
299
+ * @default true
300
+ */
301
+ cache?: boolean;
302
+ /**
303
+ * @see {@link OutputConfig}
304
+ */
305
+ output?: OutputConfig;
306
+ /**
307
+ * Excluded file/directory matching patterns (glob syntax supported).
308
+ * @default
309
+ * [
310
+ * 'node_modules/**',
311
+ * 'dist/**',
312
+ * 'build/**',
313
+ * '.git/**',
314
+ * '.vureact/**'
315
+ * ]
316
+ */
317
+ exclude?: string[];
318
+ /**
319
+ * Whether to recursively search subdirectories.
320
+ * @default true
321
+ */
322
+ recursive?: boolean;
323
+ /**
324
+ * Options passed through to babel-generator.
325
+ * @see {@link GeneratorOptions}
326
+ */
327
+ generate?: GeneratorOptions$1;
328
+ /**
329
+ * Watch files in real time and auto-recompile on changes.
330
+ * @default false
331
+ */
332
+ watch?: boolean;
333
+ /**
334
+ * Whether to process Less/Sass style languages into CSS
335
+ * @default true
336
+ */
337
+ preprocessStyles?: boolean;
338
+ /**
339
+ * Specify the path to the Vue Router config file
340
+ * The file must default export createRouter
341
+ * Used to inject Router Provider in React's main.tsx or main.jsx
342
+ *
343
+ *
344
+ *
345
+ * @see {@link RouterConfig}
346
+ *
347
+ * @example
348
+ * ```js
349
+ * router: {
350
+ * configFile: 'src/router/index.ts'
351
+ * }
352
+ * ```
353
+ *
354
+ * Assumes the config file default exports createRouter:
355
+ *
356
+ * ```js
357
+ * // src/router/index.ts
358
+ * export default createRouter({ ... })
359
+ * ```
360
+ */
361
+ router?: RouterConfig;
362
+ /**
363
+ * Can be used to add plugins and customize the output results of
364
+ * the parse/transform/codegen/compiled stages respectively.
365
+ *
366
+ * @see {@link CompilerPlugins}
367
+ *
368
+ * @example
369
+ * ```ts
370
+ * plugins: {
371
+ * // For example, add custom data to the parsing results.
372
+ * parser: {
373
+ * myPlugin: (result, ctx) => {
374
+ * result.metadata = {
375
+ * timestamp: Date.now()
376
+ * }
377
+ * },
378
+ * },
379
+ *
380
+ * // If the key names parse/transform/codegen are not specified,
381
+ * // the plugin will execute upon completion of compilation.
382
+ * yourPlguin: (result) => {
383
+ * console.log(result)
384
+ * }
385
+ * }
386
+ * ```
387
+ */
388
+ plugins?: CompilerPlugins;
389
+ /**
390
+ * @see {@link FormatConfig}
391
+ */
392
+ format?: FormatConfig;
393
+ /**
394
+ * Log Control Options
395
+ * @see {@link LoggingConfig}
396
+ */
397
+ logging?: LoggingConfig;
398
+ /**
399
+ * Execute only after the first successful full compilation.
400
+ */
401
+ onSuccess?: () => Promise<void | undefined>;
402
+ /**
403
+ * Execute after file are added or recompiled in `watch` mode.
404
+ *
405
+ * @param event Add or modify file
406
+ * @param unit Current sfc or script file compilation unit
407
+ */
408
+ onChange?: (event: 'add' | 'change', unit: CompilationUnit) => Promise<void | undefined>;
341
409
  }
342
- type PropIRValue = {
343
- content: string;
344
- isStringLiteral?: boolean;
345
- merge?: string[];
346
- babelExp: BabelExp;
347
- };
348
-
349
- interface SlotPropsIR {
350
- type: PropTypes.SLOT;
351
- name: string;
352
- rawName: string;
353
- isStatic: boolean;
354
- isScoped: boolean;
355
- content?: TemplateChildNodeIR[];
356
- callback?: {
357
- arg: string;
358
- exp: TemplateChildNodeIR[];
410
+ interface OutputConfig {
411
+ /**
412
+ * Output the name of the root directory corresponding to the file's location.
413
+ * @default '.vureact'
414
+ */
415
+ workspace?: string;
416
+ /**
417
+ * Output directory name, relative to `output.workspace`
418
+ * @default 'dist'
419
+ */
420
+ outDir?: string;
421
+ /**
422
+ * Whether to automatically call Vite to initialize a standard
423
+ * React project environment before compilation.
424
+ * @default true
425
+ */
426
+ bootstrapVite?: boolean | {
427
+ /**
428
+ * Specify the React template type.
429
+ * @default 'react-ts'
430
+ */
431
+ template?: 'react-ts' | 'react';
432
+ /**
433
+ * Specify the Vite version for initial installation, which must start with '@'.
434
+ * @default '@latest'
435
+ *
436
+ * @example
437
+ *
438
+ * ```js
439
+ * { vite: '@7' }
440
+ * ```
441
+ */
442
+ vite?: string;
443
+ /**
444
+ * Specify the React version for initial installation.
445
+ * @default 'latest'
446
+ *
447
+ * @example
448
+ *
449
+ * ```js
450
+ * { react: '^19.2.0' }
451
+ * ```
452
+ */
453
+ react?: string;
359
454
  };
455
+ /**
456
+ * Specify asset files that do not need to be copied.
457
+ * They can be filenames or paths, using fuzzy matching.
458
+ * @default
459
+ * [
460
+ * 'package.json',
461
+ * 'package-lock.json',
462
+ * 'pnpm-lock.yaml',
463
+ * 'index.html',
464
+ * 'tsconfig.',
465
+ * 'vite.config.',
466
+ * 'eslint.config.',
467
+ * 'readme.',
468
+ * 'vue.',
469
+ * '.vue',
470
+ * 'vureact.config.js',
471
+ * 'vureact.config.ts',
472
+ * ]
473
+ */
474
+ ignoreAssets?: string[];
360
475
  }
361
-
362
- interface TemplateBlockIR {
363
- children: TemplateChildNodeIR[];
476
+ interface RouterConfig {
477
+ /**
478
+ * Path to the Vue Router config file.
479
+ * Must be the location where `createRouter` is **exported as default**.
480
+ */
481
+ configFile: string;
482
+ /**
483
+ * Automatically update the react app entry file to use the VuReact Router Provider.
484
+ *
485
+ * Note: Injection only occurs when `output.bootstrapVite` is enabled.
486
+ *
487
+ * @default true
488
+ */
489
+ autoUpdateEntry?: boolean;
364
490
  }
365
- type TemplateChildNodeIR = ElementNodeIR | BaseSimpleNodeIR | FragmentNodeIR;
366
-
367
- interface ReactIRDescriptor {
368
- template: TemplateBlockIR;
369
- script: ScriptBlockIR;
370
- style?: string;
491
+ interface FormatConfig {
492
+ /**
493
+ * @default false
494
+ */
495
+ enabled?: boolean;
496
+ /**
497
+ * @default 'prettier'
498
+ */
499
+ formatter?: 'prettier' | 'builtin';
500
+ /**
501
+ * Configure the formatting options for Prettier,
502
+ * which takes effect only when the formatter is set to 'prettier'.
503
+ */
504
+ prettierOptions?: Options;
371
505
  }
372
- interface TransformerOptions {
373
- plugins?: PluginRegister<ReactIRDescriptor>;
506
+ interface LoggingConfig {
507
+ /**
508
+ * @default true
509
+ */
510
+ enabled?: boolean;
511
+ /** Whether to output warning messages. */
512
+ warnings?: boolean;
513
+ /** Whether to output info messages. */
514
+ info?: boolean;
515
+ /** Whether to output error messages. */
516
+ errors?: boolean;
374
517
  }
375
- /**
376
- * Vue SFC 解析结果转换为 React 中间表示(IR)。
377
- *
378
- * 此函数是转换阶段的核心入口,负责将 Vue 组件的解析结果(AST)转换为
379
- * 适合生成 React 代码的中间表示形式。转换过程包括模板转换和脚本转换。
380
- *
381
- * @param ast - Vue SFC 的解析结果,来自 {@link parse} 函数的返回值
382
- * @param ctx - 编译上下文对象
383
- * @param plugins - 可选的插件注册表,用于对转换结果进行自定义处理和增强
384
- * @returns React 中间表示描述符,包含模板、脚本和样式的转换结果
385
- *
386
- * @remarks
387
- * - 模板转换:将 Vue 模板 AST 转换为 React 可用的模板 IR
388
- * - 脚本转换:将 Vue 脚本 AST 转换为 React 可用的脚本 IR
389
- * - 样式处理:提取样式块内容,保留原始 CSS 字符串
390
- * - 插件支持:支持通过插件对转换结果进行自定义处理
391
- *
392
- * @example
393
- * ```typescript
394
- * // 转换示例
395
- *
396
- * const ctx: ICompilationContext = {
397
- * filename: 'MyComponent.vue',
398
- * // 其他上下文配置...
399
- * };
400
- *
401
- * // 1. 首先解析 Vue SFC
402
- * const parseResult = parse(vueSource, ctx);
403
- *
404
- * // 2. 将解析结果转换为 React IR
405
- * const reactIR = transform(parseResult, ctx);
406
- *
407
- * // 访问转换结果
408
- * console.log(reactIR.template); // 模板转换结果
409
- * console.log(reactIR.script); // 脚本转换结果
410
- * console.log(reactIR.style); // 样式内容字符串
411
- *
412
- * // 使用可选插件配置,进行自定义处理
413
- * const options: TransformerOptions = {
414
- * plugins: {
415
- * extractMetadata: (result, ctx) => {
416
- * const componentName = extractComponentNameFromScript(result.script);
417
- * const propsCount = countProps(result.script);
418
- *
419
- * result.metadata = {
420
- * name: componentName,
421
- * propsCount,
422
- * hasStyle: !!result.style,
423
- * convertedAt: new Date().toISOString(),
424
- * };
425
- * },
426
- *
427
- * // 插2:样式预处理
428
- * preprocessStyles: (result, ctx) => {
429
- * if (result.style) {
430
- * // 对样式进行预处理,如添加前缀等
431
- * result.style = addVendorPrefixes(result.style);
432
- * result.style = minifyCSS(result.style);
433
- * }
434
- * },
435
- * }
436
- * }
437
- *
438
- * // 使用多个插件进行转换
439
- * const reactIRWithPlugins = transform(parseResult, ctx, plugins);
518
+
519
+ declare class Helper {
520
+ private compilerOpts;
521
+ private pathFilter;
522
+ private workspaceDir;
523
+ private outDir;
524
+ constructor(opts: CompilerOptions);
525
+ /**
526
+ * 获取用户的项目根目录
527
+ */
528
+ getProjectRoot(): string;
529
+ /**
530
+ * 获取输入文件的路径
531
+ */
532
+ getInputPath(): string;
533
+ /**
534
+ * 检查 input 路径是否是单个文件
535
+ */
536
+ isSingleFile(): boolean;
537
+ /**
538
+ * 获取输出文件的路径。如:'[root]/.vureact/dist/'
539
+ * @param addInput 会输出如:'[root]/.vureact/dist/[input]/'
540
+ */
541
+ getOuputPath(addInput?: boolean): string;
542
+ getOutDirName(): string;
543
+ getWorkspaceDir(): string;
544
+ /**
545
+ * 根据相对输出路径反推源文件路径
546
+ */
547
+ getSourcePath(outputPath: string): string;
548
+ getIgnoreAssets(): Set<string>;
549
+ getIsCache(): boolean;
550
+ /**
551
+ * 返回原始目录下的 package.json 路径
552
+ */
553
+ getRootPkgPath(): string;
554
+ /**
555
+ * 返回 output 的 package.json 路径
556
+ */
557
+ getOutputPkgPath(): string;
558
+ /**
559
+ * 返回文件相对工作区的路径
560
+ */
561
+ relativePath(filePath: string): string;
562
+ /**
563
+ * 替换 .vue 文件名后缀为 .jsx/.tsx
564
+ * @param filePath 文件完整路径
565
+ * @param ext 文件拓展名
566
+ * @returns 返回文件的相对路径,不包含当前工作区路径
567
+ */
568
+ replaceVueFileExt(filePath: string, ext: string): string;
569
+ /**
570
+ * 判断是否应该跳过不需要进行文件搜索的路径
571
+ */
572
+ shouldSkipPath(filePath: string): boolean;
573
+ /**
574
+ * 自动根据项目结构推导 react-app 目录下的对应位置
575
+ */
576
+ resolveOutputPath(filePath: string, extname?: string): string;
577
+ /**
578
+ * 格式化代码
579
+ */
580
+ formatCode({ code, fileInfo }: CompilationResult): Promise<string>;
581
+ /**
582
+ * 通用的缓存校验工具函数
583
+ * @param current 当前文件元数据
584
+ * @param cached 缓存中的旧数据
585
+ * @param getSource 获取文件内容的函数(仅在元数据不一致时才调用,避免多余 I/O)
586
+ */
587
+ checkCacheStatus(current: FileMeta, cached: CacheMeta | undefined, getSource: () => Promise<string>): Promise<CacheCheckResult>;
588
+ /**
589
+ * 对比相同两个文件的基础元数据
590
+ */
591
+ compareFileMeta(a: FileMeta, b: FileMeta): boolean;
592
+ /**
593
+ * 统一的写文件方法,包含自动创建目录(带文件互斥锁可选)
594
+ * @param filePath - 要写入的文件路径
595
+ * @param content - 要写入的内容
596
+ * @param options - 可选配置项
597
+ * @param options.lock - 是否启用文件锁(默认false)
598
+ */
599
+ writeFileWithDir(filePath: string, content: string, options?: FileLockOptions & {
600
+ lock?: boolean;
601
+ }): Promise<void>;
602
+ rmFile(filePath: string): Promise<void>;
603
+ /**
604
+ * 加载指定文件的缓存内容
605
+ * @param key 缓存键
606
+ */
607
+ loadCache(key: CacheKey.SFC): Promise<LoadedCache<Vue2ReactCacheMeta>>;
608
+ loadCache(key: CacheKey.SCRIPT | CacheKey.STYLE | CacheKey.ASSET): Promise<LoadedCache<FileCacheMeta>>;
609
+ loadCache(key: CacheKey.SFC | CacheKey.SCRIPT | CacheKey.STYLE | CacheKey.ASSET): Promise<LoadedCache<Vue2ReactCacheMeta | FileCacheMeta>>;
610
+ createCacheData(key: CacheKey): LoadedCache;
611
+ /**
612
+ * 获取缓存文件路径
613
+ */
614
+ getCachePath(): string;
615
+ saveCache(data?: LoadedCache): Promise<void>;
616
+ genHash(content: string): string;
617
+ /**
618
+ * 扫描指定目录下的所有文件
619
+ * @param dir 目标目录
620
+ * @param filter 筛选指定的文件后缀名
621
+ */
622
+ scanFiles(dir: string, filter: (file: string) => boolean): string[];
623
+ getAbsPath(filePath: string): string;
624
+ getFileMeta(filePath: string): Promise<FileMeta>;
625
+ removeOutputFile(filePath: string, resolveOutputPath?: boolean): Promise<void>;
626
+ updateCache(targetFile: string, newData: any, cache: LoadedCache): void;
627
+ /**
628
+ * 获取需要排除编译的文件
629
+ */
630
+ getExcludes(): string[];
631
+ /**
632
+ * 打印 core 模块执行过程中收集的日志
633
+ */
634
+ printCoreLogs(): void;
635
+ printCompileInfo(file: string, duration: string): void;
636
+ print(...message: any[]): void;
637
+ /**
638
+ * 读取 package.json 文件内容,并处理成对象返回
639
+ */
640
+ resolvePackageFile(path: string): Promise<Record<string, any>>;
641
+ /**
642
+ * 获取目录到文件的相对路径
643
+ * @returns 结果路径不包含文件拓展名,并以诸如 ./ 开头
644
+ */
645
+ resolveRelativePath(from: string, to: string): string;
646
+ }
647
+
648
+ /**
649
+ * 基础编译器类 - Vue 到 React 代码转换的核心实现
440
650
  *
441
- * // 插件处理后的结果包含自定义数据
442
- * console.log(reactIRWithPlugins.metadata);
443
- * ```
651
+ * 继承自 Helper,提供单文件编译功能,支持插件系统和三阶段编译流程。
652
+ * 主要用于文件系统批量编译和单文件编译场景。
444
653
  */
445
- declare function transform(ast: ParseResult, ctx: ICompilationContext, options?: TransformerOptions): ReactIRDescriptor;
654
+ declare class BaseCompiler extends Helper {
655
+ version: string;
656
+ options: CompilerOptions;
657
+ private createContext;
658
+ constructor(options?: CompilerOptions);
659
+ /** 编译 Vue 源代码为 React 代码 */
660
+ compile(source: string, filename: string): CompilationResult;
661
+ private prepareGenerateOptions;
662
+ private resolveMainResult;
663
+ private resolveStyleResult;
664
+ }
446
665
 
447
- interface GeneratorOptions extends GeneratorOptions$1 {
448
- plugins?: PluginRegister<GeneratorResult>;
666
+ declare class CleanupManager {
667
+ private fileCompiler;
668
+ constructor(fileCompiler: FileCompiler);
669
+ /**
670
+ * Delete the build artifacts and cache corresponding to the specified path.
671
+ */
672
+ removeOutputPath(targetPath: string, type: CacheKey): Promise<void>;
673
+ /**
674
+ * Delete the build artifacts or asset files and cache corresponding to the specified path.
675
+ */
676
+ cleanupOldOutput(key: CacheKey, filter: (m: CacheMeta) => boolean): Promise<void>;
449
677
  }
450
- interface GeneratorResult {
451
- ast: t.Program | ParseResult$1;
452
- code: string;
453
- source: string;
678
+
679
+ declare class AssetManager {
680
+ private fileCompiler;
681
+ private cleanupManager;
682
+ pipelineFiles: string[];
683
+ private skippedCount;
684
+ constructor(fileCompiler: FileCompiler, cleanupManager: CleanupManager);
685
+ /**
686
+ * 运行资源文件处理管线
687
+ */
688
+ runAssetPipeline(): Promise<number>;
689
+ /**
690
+ * Process single asset file, compare with cache and decide whether to copy.
691
+ */
692
+ processAsset(filePath: string, existingCache?: LoadedCache<FileCacheMeta>): Promise<FileCacheMeta | undefined>;
693
+ /**
694
+ * 更新缓存
695
+ */
696
+ private updateCache;
697
+ /**
698
+ * 获取跳过的文件数量
699
+ */
700
+ getSkippedCount(): number;
701
+ /**
702
+ * 重置跳过的文件数量
703
+ */
704
+ resetSkippedCount(): void;
454
705
  }
455
- /**
456
- * 将 React 中间表示(IR)生成为可执行的 JSX/TSX 代码。
457
- *
458
- * 此函数是代码生成阶段的核心入口,负责将转换后的 React IR 转换为
459
- * 完整的 AST 并最终生成源代码。生成过程包括 JSX 构建和脚本构建。
460
- *
461
- * @param ir - React 中间表示描述符,来自 {@link transform} 函数的返回值
462
- * @param ctx - 编译上下文对象
463
- * @param options - 可选的生成选项,包括 Babel 生成器选项和插件
464
- * @returns 生成结果对象,包含 AST、生成的代码和原始源码引用
465
- *
466
- * @remarks
467
- * - JSX 构建:将模板 IR 转换为 JSX AST 节点
468
- * - 脚本构建:将脚本 IR 与 JSX 结合,构建完整的程序 AST
469
- * - 代码生成:使用 Babel 生成器将 AST 转换为源代码字符串
470
- * - 插件支持:支持通过插件对生成结果进行自定义处理
471
- *
472
- * @example
473
- * ```typescript
474
- * // 生成示例
475
- *
476
- * const ctx: ICompilationContext = {
477
- * filename: 'MyComponent.vue',
478
- * source: vueSource,
479
- * // 其他上下文配置...
480
- * };
481
- *
482
- * // 1. 解析 Vue SFC
483
- * const parseResult = parse(vueSource, ctx);
484
- *
485
- * // 2. 转换为 React IR
486
- * const reactIR = transform(parseResult, ctx);
487
- *
488
- * // 使用可选配置项进行自定义处理
489
- * const generatorOptions: GeneratorOptions = {
490
- * // 配置 jsesc 避免 Unicode 转义
491
- * jsescOption: {
492
- * minimal: true,
493
- * quotes: 'single'
494
- * },
495
- * minified: true,
496
- *
497
- * // 自定义插件
498
- * plugins: {
499
- * // 插件1:代码格式化
500
- * formatCode: (result, ctx) => {
501
- * // 使用 prettier 格式化生成的代码
502
- * result.code = prettier.format(result.code, {
503
- * parser: 'babel',
504
- * semi: true,
505
- * singleQuote: true,
506
- * });
507
- * },
508
- *
509
- * // 插件2:代码质量检查
510
- * lintGeneratedCode: (result, ctx) => {
511
- * const issues = eslint.verify(result.code, {
512
- * rules: {
513
- * 'react/react-in-jsx-scope': 'off',
514
- * 'no-unused-vars': 'warn',
515
- * },
516
- * });
517
- *
518
- * if (issues.length > 0) {
519
- * result.lintIssues = issues;
520
- * console.warn(`Found ${issues.length} lint issues in generated code`);
521
- * }
522
- * },
523
- * },
524
- * };
525
- *
526
- * // 3. 生成 React 组件
527
- * const generated = generateComponent(reactIR, ctx, generatorOptions);
528
- *
529
- * // 访问生成结果
530
- * console.log(generated.ast); // 完整的 Babel AST
531
- * console.log(generated.code); // 生成的 React 代码
532
- * console.log(generated.source); // 原始 Vue 源码
533
- * ```
534
- */
535
- declare function generateComponent(ir: ReactIRDescriptor, ctx: ICompilationContext, options?: GeneratorOptions): GeneratorResult;
536
706
 
537
- declare function generateOnlyScript(ir: ReactIRDescriptor, ctx: ICompilationContext, options?: GeneratorOptions): GeneratorResult;
707
+ declare class CacheManager {
708
+ private fileCompiler;
709
+ private pendingUpdates;
710
+ constructor(fileCompiler: FileCompiler);
711
+ /**
712
+ * 批量更新缓存记录
713
+ */
714
+ updateCacheIncrementally(unit: CompilationUnit, key: CacheKey): Promise<void>;
715
+ /**
716
+ * 批量保存缓存
717
+ */
718
+ flushCache(key: CacheKey): Promise<void>;
719
+ /**
720
+ * 更新缓存
721
+ */
722
+ private updateCache;
723
+ }
538
724
 
539
- /**
540
- * 代码生成的统一入口函数。
541
- *
542
- * 根据输入类型自动选择生成器:
543
- * - `sfc`: 生成完整的 React 组件(包含 JSX 和脚本)
544
- * - `script-*`: 仅生成脚本代码(如 .js、.ts)
545
- *
546
- * @param ir - React 中间表示描述符,来自转换阶段的结果
547
- * @param ctx - 编译上下文,包含输入类型、源码等信息
548
- * @param options - 可选的生成器配置,如 Babel 生成选项和插件
549
- * @returns 生成结果对象,包含 AST、生成的代码和原始源码
550
- */
551
- declare function generate(ir: ReactIRDescriptor, ctx: ICompilationContext, options?: GeneratorOptions): GeneratorResult;
725
+ declare class CompilationUnitProcessor {
726
+ private fileCompiler;
727
+ constructor(fileCompiler: FileCompiler);
728
+ /**
729
+ * 处理编译单元,落地成对应代码和文件
730
+ */
731
+ resolve(unit: CompilationUnit, key: CacheKey): Promise<CompilationUnit>;
732
+ private resolveResult;
733
+ /**
734
+ * 将编译产物写入磁盘
735
+ */
736
+ saveCompiledFiles(unit: CompilationUnit, key: CacheKey): Promise<void>;
737
+ }
552
738
 
553
- interface CompilerOptions {
739
+ declare class FileProcessor {
740
+ private fileCompiler;
741
+ private compilationUnitProcessor;
742
+ private cacheManager;
743
+ private skippedCount;
744
+ constructor(fileCompiler: FileCompiler, compilationUnitProcessor: CompilationUnitProcessor, cacheManager: CacheManager);
554
745
  /**
555
- * Manually specify the root directory.
556
- * @default process.cwd()
746
+ * Process a single Vue file (this method is called directly in CLI Watch mode)
557
747
  */
558
- root?: string;
748
+ processSFC(filePath: string, existingCache?: LoadedCache<Vue2ReactCacheMeta>): Promise<SFCUnit | undefined>;
559
749
  /**
560
- * Path to the source file or directory.
561
- * - If it is a file, compile the single file.
562
- * - If it is a directory, recursively compile all .vue files under the directory.
563
- *
564
- * @default
565
- * 'src/' // The src directory under the root directory
750
+ * Process a single script file (this method is called directly in CLI Watch mode)
566
751
  */
567
- input?: string;
752
+ processScript(filePath: string, existingCache?: LoadedCache<FileCacheMeta>): Promise<ScriptUnit | undefined>;
568
753
  /**
569
- * Whether to enable build cache and reuse the previous cache results
570
- * @default true
754
+ * Process a single style file (this method is called directly in CLI Watch mode)
571
755
  */
572
- cache?: boolean;
573
- output?: {
574
- /**
575
- * Output the name of the root directory corresponding to the file's location.
576
- * @default '.vureact'
577
- */
578
- workspace?: string;
579
- /**
580
- * Output directory name, relative to `output.workspace`
581
- * @default 'dist'
582
- */
583
- outDir?: string;
584
- /**
585
- * Whether to automatically call Vite to initialize a standard
586
- * React project environment before compilation.
587
- * @default true
588
- */
589
- bootstrapVite?: boolean | {
590
- /**
591
- * @default 'react-ts'
592
- */
593
- template: 'react-ts' | 'react';
594
- };
595
- /**
596
- * Specify asset files that do not need to be copied.
597
- * They can be filenames or paths, using fuzzy matching.
598
- * @default
599
- * [
600
- * 'package.json',
601
- * 'package-lock.json',
602
- * 'pnpm-lock.yaml',
603
- * 'index.html',
604
- * 'tsconfig.',
605
- * 'vite.config.',
606
- * 'eslint.config.',
607
- * 'readme.',
608
- * 'vue.',
609
- * 'vureact.config.js',
610
- * ]
611
- */
612
- ignoreAssets?: string[];
613
- };
756
+ processStyle(filePath: string, existingCache?: LoadedCache<FileCacheMeta>): Promise<StyleUnit | undefined>;
614
757
  /**
615
- * Excluded file/directory matching patterns (glob syntax supported).
616
- * @default
617
- * [
618
- * 'node_modules/**',
619
- * 'dist/**',
620
- * 'build/**',
621
- * '.git/**',
622
- * '.vureact/**'
623
- * ]
758
+ * Process a single vue file
624
759
  */
625
- exclude?: string[];
760
+ processFile(key: CacheKey.SFC, filePath: string, existingCache?: LoadedCache<Vue2ReactCacheMeta>): Promise<SFCUnit | undefined>;
626
761
  /**
627
- * Whether to recursively search subdirectories.
628
- * @default true
762
+ * Process a single script file
629
763
  */
630
- recursive?: boolean;
764
+ processFile(key: CacheKey.SCRIPT, filePath: string, existingCache?: LoadedCache<FileCacheMeta>): Promise<ScriptUnit | undefined>;
631
765
  /**
632
- * Options passed through to babel-generator.
766
+ * Process a single style file
633
767
  */
634
- generate?: GeneratorOptions$1;
768
+ processFile(key: CacheKey.STYLE, filePath: string, existingCache?: LoadedCache<FileCacheMeta>): Promise<StyleUnit | undefined>;
635
769
  /**
636
- * Watch files in real time and auto-recompile on changes.
637
- * @default false
770
+ * Process a single vue/script/style file
638
771
  */
639
- watch?: boolean;
772
+ processFile(key: CacheKey, filePath: string, existingCache?: LoadedCache<FileCacheMeta>): Promise<CompilationUnit | undefined>;
640
773
  /**
641
- * Whether to process Less/Sass style languages into CSS
642
- * @default true
774
+ * package.json 注入路由依赖项
643
775
  */
644
- preprocessStyles?: boolean;
776
+ private addRouterToPackageJson;
645
777
  /**
646
- * Can be used to add plugins and customize the output results of
647
- * the parse/transform/codegen/compiled stages respectively.
648
- *
649
- * @example
650
- * ```ts
651
- * plugins: {
652
- * // For example, add custom data to the parsing results.
653
- * parser: {
654
- * myPlugin: (result, ctx) => {
655
- * result.metadata = {
656
- * timestamp: Date.now()
657
- * }
658
- * },
659
- * },
660
- *
661
- * // If the key names parse/transform/codegen are not specified,
662
- * // the plugin will execute upon completion of compilation.
663
- * yourPlguin: (result) => {
664
- * console.log(result)
665
- * }
666
- * }
667
- * ```
778
+ * 注入路由提供器到 React 应用的入口文件(如 main.tsx)
779
+ */
780
+ private updateEntryWithRouterProvider;
781
+ /**
782
+ * 获取跳过的文件数量
783
+ */
784
+ getSkippedCount(): number;
785
+ /**
786
+ * 重置跳过的文件数量
787
+ */
788
+ resetSkippedCount(): void;
789
+ }
790
+
791
+ declare class PipelineManager {
792
+ private fileCompiler;
793
+ private fileProcessor;
794
+ private skippedCount;
795
+ private cleanupManager;
796
+ constructor(fileCompiler: FileCompiler, fileProcessor: FileProcessor);
797
+ /**
798
+ * 运行 SFC 编译管线
799
+ */
800
+ runSfcPipeline(): Promise<number>;
801
+ /**
802
+ * 运行 Script 编译管线
803
+ */
804
+ runScriptPipeline(): Promise<number>;
805
+ /**
806
+ * 运行 Style 编译管线
807
+ */
808
+ runStylePipeline(): Promise<number>;
809
+ /**
810
+ * 核心编译管线
811
+ */
812
+ private runCorePipeline;
813
+ /**
814
+ * 获取跳过的文件数量
815
+ */
816
+ getSkippedCount(): number;
817
+ /**
818
+ * 重置跳过的文件数量
668
819
  */
669
- plugins?: PluginRegister<CompilationResult> & {
670
- /**
671
- * Register parser plugins
672
- */
673
- parser?: PluginRegister<ParseResult>;
674
- /**
675
- * Register transformer plugins
676
- */
677
- transformer?: PluginRegister<ReactIRDescriptor>;
678
- /**
679
- * Register codegen plugins
680
- */
681
- codegen?: PluginRegister<GeneratorResult>;
682
- };
683
- format?: {
684
- /**
685
- * @default false
686
- */
687
- enabled?: boolean;
688
- /**
689
- * @default 'prettier'
690
- */
691
- formatter?: 'prettier' | 'builtin';
692
- /**
693
- * Configure the formatting options for Prettier,
694
- * which takes effect only when the formatter is set to 'prettier'.
695
- */
696
- prettierOptions?: Options;
697
- };
820
+ resetSkippedCount(): void;
821
+ }
822
+
823
+ /**
824
+ * Vite 环境初始化管理器
825
+ */
826
+ declare class ViteBootstrapper {
827
+ private fileCompiler;
828
+ private options;
829
+ private spinner;
830
+ private defaultConfig;
831
+ constructor(fileCompiler: FileCompiler, options: CompilerOptions);
698
832
  /**
699
- * Log Control Options
833
+ * 检查是否需要初始化 Vite 环境
700
834
  */
701
- logging?: {
702
- /**
703
- * @default true
704
- */
705
- enabled?: boolean;
706
- /** Whether to output warning messages. */
707
- warnings?: boolean;
708
- /** Whether to output info messages. */
709
- info?: boolean;
710
- /** Whether to output error messages. */
711
- errors?: boolean;
712
- };
835
+ private isSingleFile;
713
836
  /**
714
- * Execute only after the first successful full compilation.
837
+ * 利用 Vite 官方脚手架创建标准 React 环境
715
838
  */
716
- onSuccess?: () => Promise<void | undefined>;
839
+ bootstrapIfNeeded(): Promise<boolean>;
717
840
  /**
718
- * Execute after file are added or recompiled in `watch` mode.
719
- *
720
- * @param event Add or modify file
721
- * @param unit Current sfc or script file compilation unit
841
+ * 执行 vite 创建命令
722
842
  */
723
- onChange?: (event: 'add' | 'change', unit: CompilationUnit) => Promise<void | undefined>;
843
+ private resolveViteCreateApp;
844
+ /**
845
+ * 处理 React 包版本
846
+ * @param ver 版本号
847
+ */
848
+ private resolveReactVersion;
724
849
  }
725
- interface PluginRegister<T> {
726
- [name: string]: (result: T, ctx: ICompilationContext) => void;
850
+
851
+ interface CompilerManager {
852
+ viteBootstrapper: ViteBootstrapper;
853
+ fileProcessor: FileProcessor;
854
+ pipelineManager: PipelineManager;
855
+ assetManager: AssetManager;
856
+ cacheManager: CacheManager;
857
+ cleanupManager: CleanupManager;
727
858
  }
728
- type CompilationResult = SFCCompilationResult | ScriptCompilationResult | StyleCompilationResult;
729
- interface SFCCompilationResult extends BaseCompilationResult {
730
- fileInfo: {
731
- jsx: {
732
- file: string;
733
- lang: string;
734
- };
735
- css: {
736
- file?: string;
737
- hash?: string;
738
- code?: string;
739
- };
740
- };
859
+
860
+ /**
861
+ * 文件系统编译器 - 将 Vue 项目批量转换为 React 项目
862
+ *
863
+ * 提供完整的文件系统级别编译功能,包括 SFC、脚本、样式编译,
864
+ * 资源拷贝、增量编译、缓存管理和 Vite 环境初始化。
865
+ */
866
+ declare class FileCompiler extends BaseCompiler {
867
+ manager: CompilerManager;
868
+ private spinner;
869
+ constructor(options?: CompilerOptions);
870
+ /** 执行完整的编译流程 */
871
+ execute(): Promise<void>;
872
+ /** 处理单个 Vue 单文件组件(SFC) */
873
+ processSFC(filePath: string, existingCache?: LoadedCache<Vue2ReactCacheMeta>): Promise<SFCUnit | undefined>;
874
+ /** 处理单个 JavaScript/TypeScript 脚本文件 */
875
+ processScript(filePath: string, existingCache?: LoadedCache<FileCacheMeta>): Promise<ScriptUnit | undefined>;
876
+ /** 处理单个 CSS/LESS/SCSS 样式文件 */
877
+ processStyle(filePath: string, existingCache?: LoadedCache<FileCacheMeta>): Promise<StyleUnit | undefined>;
878
+ /** 处理单个文件(Vue 或 Script) */
879
+ processFile(key: CacheKey, filePath: string, existingCache?: LoadedCache): Promise<CompilationUnit | undefined>;
880
+ /** 处理单个资源文件 */
881
+ processAsset(filePath: string, existingCache?: LoadedCache<FileCacheMeta>): Promise<FileCacheMeta | undefined>;
882
+ /** 批量保存缓存 */
883
+ flushCache(key: CacheKey): Promise<void>;
884
+ /** 删除指定路径对应的输出文件和缓存 */
885
+ removeOutputPath(targetPath: string, type: CacheKey): Promise<void>;
886
+ private runPipelineWithSpinner;
887
+ private showCompileStats;
888
+ private resetSkippedCount;
741
889
  }
742
- interface ScriptCompilationResult extends BaseCompilationResult {
743
- fileInfo: {
744
- script: {
745
- file: string;
746
- lang: string;
747
- };
748
- };
890
+
891
+ /**
892
+ * Type helper to make it easier to use vureact.config.js
893
+ * accepts a direct {@link UserConfig} object, or a function that returns it.
894
+ */
895
+ declare function defineConfig(config: CompilerOptions): CompilerOptions;
896
+ declare function defineConfig(config: UserConfigFnObject): CompilerOptions;
897
+ type UserConfigFnObject = () => CompilerOptions;
898
+
899
+ /**
900
+ * Next Vue to React compiler, compiles Vue 3 syntax into runnable React 18+ code.
901
+ *
902
+ * @extends FileCompiler
903
+ *
904
+ * @see {@link FileCompiler}
905
+ * @see https://vureact.top
906
+ */
907
+ declare class VuReact extends FileCompiler {
749
908
  }
750
- interface StyleCompilationResult extends Omit<BaseCompilationResult, 'hasRoute' | keyof GeneratorResult> {
751
- code: string;
752
- fileInfo: {
753
- style: {
754
- file: string;
755
- lang: string;
756
- };
757
- };
909
+
910
+ interface ParseResult {
911
+ template: BlockIR<SFCTemplateBlock, RootNode>;
912
+ script: BlockIR<SFCScriptBlock, ParseResult$1>;
913
+ style: BlockIR<SFCStyleBlock, undefined>;
758
914
  }
759
- interface BaseCompilationResult extends GeneratorResult {
760
- fileId: string;
761
- hasRoute?: boolean;
915
+ type BlockIR<S, T> = {
916
+ source?: S;
917
+ ast: T;
918
+ } | null;
919
+ interface ParserOptions {
920
+ plugins?: PluginRegister<ParseResult>;
762
921
  }
763
- type CompilationUnit = SFCUnit | ScriptUnit | StyleUnit;
764
- interface SFCUnit extends BaseUnit {
765
- type: CacheKey.SFC;
766
- output?: {
767
- jsx: OutputItem;
768
- css: Partial<OutputItem>;
922
+ /**
923
+ * 解析 Vue 单文件组件(SFC)源码,生成结构化解析结果。
924
+ *
925
+ * 此函数是解析阶段的核心入口,
926
+ * 负责将 Vue SFC 源码解析为包含模板、脚本、样式等各个块的结构化数据。
927
+ *
928
+ * @param source - Vue 单文件组件的源码字符串
929
+ * @param ctx - 编译上下文对象
930
+ * @param plugins - 可选的插件注册表,用于对解析结果进行自定义处理和增强
931
+ * @returns 解析结果对象,包含模板、脚本、样式块的解析信息
932
+ * @throws 不会直接抛出异常,错误信息会通过日志系统记录
933
+ *
934
+ * @remarks
935
+ * - 函数内部使用 Vue 官方的 `@vue/compiler-sfc` 进行基础解析
936
+ * - 解析结果会经过后处理阶段,包括脚本元数据扫描
937
+ * - 插件按照注册顺序依次执行,可以对解析结果进行修改或增强
938
+ * - 错误处理:语法错误和编译错误会通过日志系统记录,不会中断执行
939
+ *
940
+ * @example
941
+ * ```typescript
942
+ * // 基础用法:解析一个简单的 Vue 组件
943
+ *
944
+ * const vueSource = `
945
+ * <template>
946
+ * <div class="greeting">
947
+ * Hello, {{ name }}!
948
+ * </div>
949
+ * </template>
950
+ *
951
+ * <script setup lang="ts">
952
+ * import { ref } from 'vue'
953
+ *
954
+ * const name = ref('World')
955
+ * const count = ref(0)
956
+ *
957
+ * function increment() {
958
+ * count.value++
959
+ * }
960
+ * </script>
961
+ *
962
+ * <style scoped>
963
+ * .greeting {
964
+ * color: #42b983;
965
+ * font-size: 1.5rem;
966
+ * }
967
+ * </style>
968
+ * `;
969
+ *
970
+ * const ctx: ICompilationContext = {
971
+ * filename: 'MyComponent.vue',
972
+ * // 其他上下文配置...
973
+ * };
974
+ *
975
+ * const result = parseSFC(vueSource, ctx);
976
+ *
977
+ * // 访问解析结果
978
+ * console.log(result.template?.ast); // 模板的 AST 节点
979
+ * console.log(result.script?.ast); // 脚本的 Babel 解析结果
980
+ * console.log(result.style?.source); // 样式块原始信息
981
+ *
982
+ * // 使用可选插件配置,进行自定义处理
983
+ * const options: ParserOptions = {
984
+ * plugins: {
985
+ * myPlugin: (result, ctx) => {
986
+ * // 提取组件元数据
987
+ * const componentName = extractComponentName(result);
988
+ * // 添加自定义分析结果
989
+ * result.metadata = {
990
+ * name: componentName,
991
+ * analyzedAt: new Date().toISOString()
992
+ * };
993
+ * }
994
+ * }
995
+ * };
996
+ *
997
+ * const resultWithPlugin = parseSFC(vueSource, compilationContext, options);
998
+ * ```
999
+ */
1000
+ declare function parseSFC(source: string, ctx: ICompilationContext, options?: ParserOptions): ParseResult;
1001
+
1002
+ /**
1003
+ * 仅用于解析 script 文件,参数与 parseSFC 一致
1004
+ */
1005
+ declare function parseOnlyScript(source: string, ctx: ICompilationContext, options?: ParserOptions): ParseResult;
1006
+
1007
+ /**
1008
+ * 解析 Vue 组件源码的统一入口函数。
1009
+ *
1010
+ * 根据输入类型自动选择解析器:
1011
+ * - `sfc`: 解析 Vue 单文件组件(包含 template/script/style)
1012
+ * - `script-*`: 仅解析脚本文件(如 .js、.ts)
1013
+ *
1014
+ * @param source - 源码字符串
1015
+ * @param ctx - 编译上下文,包含输入类型、文件名等信息
1016
+ * @param options - 可选的解析器配置,如插件
1017
+ * @returns 解析结果对象,包含模板、脚本、样式的结构化数据
1018
+ */
1019
+ declare function parse(source: string, ctx: ICompilationContext, options?: ParserOptions): ParseResult;
1020
+
1021
+ interface ScriptBlockIR {
1022
+ /** Transformed full script AST (used for script-only input). */
1023
+ scriptAST?: ParseResult$1;
1024
+ imports: t.ImportDeclaration[];
1025
+ exports: t.ExportDeclaration[];
1026
+ tsTypes: t.TypeScript[];
1027
+ /** Executable statements extracted from script block. */
1028
+ statement: {
1029
+ /** Statements hoisted outside component function. */
1030
+ global: t.Node[];
1031
+ /** Statements kept inside component function. */
1032
+ local: ParseResult$1<t.File> | null;
769
1033
  };
770
1034
  }
771
- interface ScriptUnit extends BaseUnit {
772
- type: CacheKey.SCRIPT;
773
- output?: {
774
- script: OutputItem;
775
- };
1035
+
1036
+ declare const enum NodeTypes {
1037
+ FRAGMENT = 0,
1038
+ ELEMENT = 1,
1039
+ TEXT = 2,
1040
+ COMMENT = 3,
1041
+ JSX_INTERPOLATION = 4
776
1042
  }
777
- interface StyleUnit extends Omit<BaseUnit, 'hasRoute'> {
778
- type: CacheKey.STYLE;
779
- output?: {
780
- style: OutputItem;
781
- };
1043
+ declare const enum PropTypes {
1044
+ ATTRIBUTE = 1,
1045
+ SLOT = 2,
1046
+ EVENT = 3,
1047
+ DYNAMIC_ATTRIBUTE = 4
782
1048
  }
783
- interface AssetUnit extends Omit<BaseUnit, 'fileId' | 'source' | 'hasRoute'> {
784
- type: CacheKey.ASSET;
1049
+ interface BabelExp<T = Expression> {
1050
+ content: string;
1051
+ ast: T;
785
1052
  }
786
- interface BaseUnit extends FileMeta {
787
- file: string;
788
- fileId: string;
789
- source: string;
790
- hasRoute?: boolean;
1053
+
1054
+ interface BaseSimpleNodeIR {
1055
+ type: NodeTypes;
1056
+ content: string;
1057
+ babelExp: Expression;
791
1058
  }
792
- interface OutputItem {
793
- file: string;
794
- code: string;
1059
+ interface FragmentNodeIR {
1060
+ type: NodeTypes;
1061
+ children: TemplateChildNodeIR[];
795
1062
  }
796
- type LoadedCache<T = CacheMeta> = {
797
- key: CacheKey;
798
- target: T[];
799
- source: CacheList;
800
- };
801
- type CacheMeta = Vue2ReactCacheMeta | FileCacheMeta;
802
- declare enum CacheKey {
803
- SFC = "sfc",
804
- SCRIPT = "script",
805
- STYLE = "style",
806
- ASSET = "copied"
1063
+
1064
+ interface ElementNodeIR extends BaseElementNodeIR {
1065
+ type: NodeTypes;
1066
+ props: (PropsIR | SlotPropsIR)[];
1067
+ children: TemplateChildNodeIR[];
1068
+ meta: Partial<ElementNodeIRMeta>;
1069
+ conditionIsHandled: boolean;
1070
+ isBuiltIn?: boolean;
1071
+ isRoute?: boolean;
807
1072
  }
808
- interface CacheList {
809
- [CacheKey.SFC]: Vue2ReactCacheMeta[];
810
- [CacheKey.SCRIPT]: FileCacheMeta[];
811
- [CacheKey.STYLE]: FileCacheMeta[];
812
- [CacheKey.ASSET]: FileCacheMeta[];
1073
+ interface BaseElementNodeIR {
1074
+ tag: string;
1075
+ isComponent?: boolean;
1076
+ isSelfClosing?: boolean;
1077
+ ref?: string;
1078
+ loc?: SourceLocation;
813
1079
  }
814
- type Vue2ReactCacheMeta = Omit<SFCUnit, 'source'>;
815
- interface FileCacheMeta extends FileMeta {
816
- file: string;
1080
+ interface ElementNodeIRMeta {
1081
+ condition: ConditionMeta;
1082
+ loop: LoopMeta;
1083
+ memo: MemoMeta;
1084
+ show: ShowMeta;
817
1085
  }
818
- interface FileMeta {
819
- fileSize: number;
820
- mtime: number;
821
- hash?: string;
1086
+ type ConditionMeta = {
1087
+ if?: boolean;
1088
+ elseIf?: boolean;
1089
+ else?: boolean;
1090
+ value: string;
1091
+ babelExp: BabelExp;
1092
+ next?: ElementNodeIR;
1093
+ isHandled: boolean;
1094
+ };
1095
+ type LoopMeta = {
1096
+ isLoop?: boolean;
1097
+ value: {
1098
+ source: string;
1099
+ value: string;
1100
+ key?: string;
1101
+ index?: string;
1102
+ };
1103
+ isHandled: boolean;
1104
+ };
1105
+ type MemoMeta = {
1106
+ isMemo?: boolean;
1107
+ value: string;
1108
+ babelExp: BabelExp<ArrayExpression>;
1109
+ isHandled: boolean;
1110
+ };
1111
+ type ShowMeta = {
1112
+ isShow?: boolean;
1113
+ value: string;
1114
+ babelExp: BabelExp;
1115
+ };
1116
+
1117
+ interface PropsIR {
1118
+ type: PropTypes;
1119
+ rawName?: string;
1120
+ name: string;
1121
+ isStatic?: boolean;
1122
+ modifiers?: string[];
1123
+ value: PropIRValue;
1124
+ isKeyLessVBind?: boolean;
1125
+ babelExp: BabelExp<JSXIdentifier | Expression>;
822
1126
  }
823
- interface CacheCheckResult {
824
- shouldCompile: boolean;
825
- hash?: string;
1127
+ type PropIRValue = {
1128
+ content: string;
1129
+ isStringLiteral?: boolean;
1130
+ merge?: string[];
1131
+ babelExp: BabelExp;
1132
+ };
1133
+
1134
+ interface SlotPropsIR {
1135
+ type: PropTypes.SLOT;
1136
+ name: string;
1137
+ rawName: string;
1138
+ isStatic: boolean;
1139
+ isScoped: boolean;
1140
+ content?: TemplateChildNodeIR[];
1141
+ callback?: {
1142
+ arg: string;
1143
+ exp: TemplateChildNodeIR[];
1144
+ };
826
1145
  }
827
1146
 
828
- declare class Helper {
829
- private compilerOpts;
830
- private pathFilter;
831
- private workspaceDir;
832
- private outDir;
833
- constructor(opts: CompilerOptions);
834
- /**
835
- * 获取用户的项目根目录
836
- */
837
- getProjectRoot(): string;
838
- /**
839
- * 获取输入文件的路径
840
- */
841
- getInputPath(): string;
842
- /**
843
- * 检查 input 路径是否是单个文件
844
- */
845
- isSingleFile(): boolean;
846
- /**
847
- * 获取输出文件的路径。如:'[root]/.vureact/dist/'
848
- */
849
- getOuputPath(): string;
850
- getOutDirName(): string;
851
- getWorkspaceDir(): string;
852
- /**
853
- * 根据相对输出路径反推源文件路径
854
- */
855
- getSourcePath(outputPath: string): string;
856
- getIgnoreAssets(): Set<string>;
857
- getIsCache(): boolean;
858
- /**
859
- * 返回原始目录下的 package.json 路径
860
- */
861
- getRootPkgPath(): string;
862
- /**
863
- * 返回 output 的 package.json 路径
864
- */
865
- getOutputPkgPath(): string;
866
- /**
867
- * 返回文件相对工作区的路径
868
- */
869
- relativePath(filePath: string): string;
870
- /**
871
- * 替换 .vue 文件名后缀为 .jsx/.tsx
872
- * @param filePath 文件完整路径
873
- * @param ext 文件拓展名
874
- * @returns 返回文件的相对路径,不包含当前工作区路径
875
- */
876
- replaceVueFileExt(filePath: string, ext: string): string;
877
- /**
878
- * 判断是否应该跳过不需要进行文件搜索的路径
879
- */
880
- shouldSkipPath(filePath: string): boolean;
881
- /**
882
- * 自动根据项目结构推导 react-app 目录下的对应位置
883
- */
884
- resolveOutputPath(filePath: string, extname?: string): string;
885
- /**
886
- * 格式化代码
887
- */
888
- formatCode({ code, fileInfo }: CompilationResult): Promise<string>;
889
- /**
890
- * 通用的缓存校验工具函数
891
- * @param current 当前文件元数据
892
- * @param cached 缓存中的旧数据
893
- * @param getSource 获取文件内容的函数(仅在元数据不一致时才调用,避免多余 I/O)
894
- */
895
- checkCacheStatus(current: FileMeta, cached: CacheMeta | undefined, getSource: () => Promise<string>): Promise<CacheCheckResult>;
896
- /**
897
- * 对比相同两个文件的基础元数据
898
- */
899
- compareFileMeta(a: FileMeta, b: FileMeta): boolean;
900
- /**
901
- * 统一的写文件方法,包含自动创建目录
902
- */
903
- writeFileWithDir(filePath: string, content: string): Promise<void>;
904
- /**
905
- * 加载指定文件的缓存内容
906
- * @param key 缓存键
907
- */
908
- loadCache(key: CacheKey.SFC): Promise<LoadedCache<Vue2ReactCacheMeta>>;
909
- loadCache(key: CacheKey.SCRIPT | CacheKey.STYLE | CacheKey.ASSET): Promise<LoadedCache<FileCacheMeta>>;
910
- loadCache(key: CacheKey.SFC | CacheKey.SCRIPT | CacheKey.STYLE | CacheKey.ASSET): Promise<LoadedCache<Vue2ReactCacheMeta | FileCacheMeta>>;
911
- createCacheData(key: CacheKey): LoadedCache;
912
- /**
913
- * 获取缓存文件路径
914
- */
915
- getCachePath(): string;
916
- saveCache(data?: LoadedCache): Promise<void>;
917
- genHash(content: string): string;
918
- /**
919
- * 扫描指定目录下的所有文件
920
- * @param dir 目标目录
921
- * @param filter 筛选指定的文件后缀名
922
- */
923
- scanFiles(dir: string, filter: (file: string) => boolean): string[];
924
- getAbsPath(filePath: string): string;
925
- getFileMeta(filePath: string): Promise<FileMeta>;
926
- removeOutputFile(filePath: string, resolveOutputPath?: boolean): Promise<void>;
927
- updateCache(targetFile: string, newData: any, cache: LoadedCache): void;
928
- resolveViteCreateApp(): void;
929
- /**
930
- * 获取需要排除编译的文件
931
- */
932
- getExcludes(): string[];
933
- /**
934
- * 打印 core 模块执行过程中收集的日志
935
- */
936
- printCoreLogs(): void;
937
- printCompileInfo(file: string, duration: string): void;
938
- print(...message: any[]): void;
939
- /**
940
- * 读取 package.json 文件内容,并处理成对象返回
941
- */
942
- resolvePackageFile(path: string): Promise<Record<string, any>>;
1147
+ interface TemplateBlockIR {
1148
+ children: TemplateChildNodeIR[];
943
1149
  }
1150
+ type TemplateChildNodeIR = ElementNodeIR | BaseSimpleNodeIR | FragmentNodeIR;
944
1151
 
1152
+ interface ReactIRDescriptor {
1153
+ template: TemplateBlockIR;
1154
+ script: ScriptBlockIR;
1155
+ style?: string;
1156
+ }
1157
+ interface TransformerOptions {
1158
+ plugins?: PluginRegister<ReactIRDescriptor>;
1159
+ }
945
1160
  /**
946
- * 基础编译器类,提供 Vue React 代码转换的核心编译功能。
1161
+ * Vue SFC 解析结果转换为 React 中间表示(IR)。
1162
+ *
1163
+ * 此函数是转换阶段的核心入口,负责将 Vue 组件的解析结果(AST)转换为
1164
+ * 适合生成 React 代码的中间表示形式。转换过程包括模板转换和脚本转换。
1165
+ *
1166
+ * @param ast - Vue SFC 的解析结果,来自 {@link parse} 函数的返回值
1167
+ * @param ctx - 编译上下文对象
1168
+ * @param plugins - 可选的插件注册表,用于对转换结果进行自定义处理和增强
1169
+ * @returns React 中间表示描述符,包含模板、脚本和样式的转换结果
1170
+ *
1171
+ * @remarks
1172
+ * - 模板转换:将 Vue 模板 AST 转换为 React 可用的模板 IR
1173
+ * - 脚本转换:将 Vue 脚本 AST 转换为 React 可用的脚本 IR
1174
+ * - 样式处理:提取样式块内容,保留原始 CSS 字符串
1175
+ * - 插件支持:支持通过插件对转换结果进行自定义处理
1176
+ *
1177
+ * @example
1178
+ * ```typescript
1179
+ * // 转换示例
947
1180
  *
948
- * 此类继承自 {@link Helper},是 VuReact 编译器的核心实现,负责:
949
- * 1. 初始化编译上下文:为每次编译创建独立的上下文环境
950
- * 2. 执行完整的编译流程:解析(parse)→ 转换(transform)→ 生成(generate)
951
- * 3. 管理编译选项和配置:处理用户传入的编译器配置
952
- * 4. 插件系统集成:支持解析、转换、生成各阶段的插件扩展
953
- * 5. 错误处理和日志记录:通过日志系统记录编译过程中的信息
1181
+ * const ctx: ICompilationContext = {
1182
+ * filename: 'MyComponent.vue',
1183
+ * // 其他上下文配置...
1184
+ * };
954
1185
  *
955
- * 主要用途:
956
- * - {@link FileCompiler} 继承使用,实现文件系统级别的批量编译
957
- * - 直接实例化用于单文件编译,适合集成到其他工具链中
1186
+ * // 1. 首先解析 Vue SFC
1187
+ * const parseResult = parse(vueSource, ctx);
958
1188
  *
959
- * 核心特性:
960
- * - 三阶段编译流水线:严格遵循解析→转换→生成的编译模型
961
- * - 插件化架构:支持在编译各阶段插入自定义逻辑
962
- * - 上下文隔离:每次编译创建独立上下文,避免状态污染
963
- * - 资源感知:自动处理样式预处理和路由依赖检测
964
- * - 错误恢复:编译错误通过日志记录,不会中断整个流程
1189
+ * // 2. 将解析结果转换为 React IR
1190
+ * const reactIR = transform(parseResult, ctx);
965
1191
  *
966
- * 编译流程详解:
967
- * 1. 解析阶段:使用 {@link parse} 将 Vue 代码解析为抽象语法树(AST)
968
- * 2. 转换阶段:使用 {@link transform} 将 Vue AST 转换为 React 中间表示(IR)
969
- * 3. 生成阶段:使用 {@link generate} 将 React IR 生成为目标代码
970
- * 4. 插件执行:在各阶段执行注册的插件,支持自定义扩展
1192
+ * // 访问转换结果
1193
+ * console.log(reactIR.template); // 模板转换结果
1194
+ * console.log(reactIR.script); // 脚本转换结果
1195
+ * console.log(reactIR.style); // 样式内容字符串
971
1196
  *
972
- * @example
973
- * ```typescript
974
- * // 创建基础编译器实例
975
- * const compiler = new BaseCompiler({
976
- * cache: true,
977
- * preprocessStyles: true,
1197
+ * // 使用可选插件配置,进行自定义处理
1198
+ * const options: TransformerOptions = {
978
1199
  * plugins: {
979
- * parser: {
980
- * myParserPlugin: (result, ctx) => {
981
- * // 解析阶段插件
982
- * }
1200
+ * extractMetadata: (result, ctx) => {
1201
+ * const componentName = extractComponentNameFromScript(result.script);
1202
+ * const propsCount = countProps(result.script);
1203
+ *
1204
+ * result.metadata = {
1205
+ * name: componentName,
1206
+ * propsCount,
1207
+ * hasStyle: !!result.style,
1208
+ * convertedAt: new Date().toISOString(),
1209
+ * };
983
1210
  * },
984
- * transformer: {
985
- * myTransformerPlugin: (result, ctx) => {
986
- * // 转换阶段插件
1211
+ *
1212
+ * // 插2:样式预处理
1213
+ * preprocessStyles: (result, ctx) => {
1214
+ * if (result.style) {
1215
+ * // 对样式进行预处理,如添加前缀等
1216
+ * result.style = addVendorPrefixes(result.style);
1217
+ * result.style = minifyCSS(result.style);
987
1218
  * }
988
- * }
1219
+ * },
989
1220
  * }
990
- * });
1221
+ * }
991
1222
  *
992
- * // 编译单个 Vue 文件
993
- * const result = compiler.compile(vueSourceCode, '/path/to/Component.vue');
1223
+ * // 使用多个插件进行转换
1224
+ * const reactIRWithPlugins = transform(parseResult, ctx, plugins);
994
1225
  *
995
- * // 获取编译结果
996
- * console.log(result.fileInfo); // 包含 JSX 和 CSS 文件信息
997
- * console.log(result.code); // 生成的 React 代码
1226
+ * // 插件处理后的结果包含自定义数据
1227
+ * console.log(reactIRWithPlugins.metadata);
998
1228
  * ```
999
- *
1000
- * @remarks
1001
- * - 上下文管理:使用 {@link CompilationAdapter.createContext} 创建编译上下文
1002
- * - 错误处理:编译过程中的错误通过 {@link logger} 记录,不会抛出异常
1003
- * - 配置继承:继承 {@link Helper} 类的文件路径处理、缓存管理、格式化等工具方法
1004
- * - 版本管理:自动读取 package.json 中的版本号,便于调试和日志记录
1005
- *
1006
- * @see {@link FileCompiler} 用于文件系统级别的批量编译和增量构建
1007
- * @see {@link Helper} 提供基础的文件路径处理、缓存管理和格式化工具
1008
- * @see {@link CompilerOptions} 查看完整的编译器配置选项
1009
- * @see {@link CompilationResult} 编译结果的数据结构
1010
1229
  */
1011
- declare class BaseCompiler extends Helper {
1012
- version: string;
1013
- options: CompilerOptions;
1014
- private createContext;
1015
- /**
1016
- * 创建基础编译器实例
1017
- *
1018
- * @param options - 编译器配置选项,包括缓存设置、插件配置、样式预处理等,
1019
- * 所有选项都会传递给父类 {@link Helper} 进行初始化
1020
- *
1021
- * @see {@link CompilerOptions} 查看完整的配置选项说明
1022
- */
1023
- constructor(options?: CompilerOptions);
1024
- /**
1025
- * 编译 Vue 源代码为 React 代码
1026
- *
1027
- * 该方法执行完整的编译流程,包括:
1028
- * 1. 上下文初始化:创建独立的编译上下文
1029
- * 2. 解析阶段:将 Vue 源代码解析为抽象语法树(AST)
1030
- * 3. 转换阶段:将 Vue AST 转换为 React 中间表示(IR)
1031
- * 4. 生成阶段:将 React IR 生成为目标代码
1032
- * 5. 插件执行:在各阶段执行注册的插件
1033
- * 6. 结果处理:整理编译结果并返回
1034
- *
1035
- * 编译过程使用 try-finally 确保上下文资源被正确清理,
1036
- * 即使编译过程中发生错误也不会导致资源泄漏。
1037
- *
1038
- * @param source - Vue 源代码字符串
1039
- * @param filename - 源文件名,用于生成文件ID和输出路径
1040
- * @returns {CompilationResult} 编译结果,包含生成的代码和文件信息
1041
- *
1042
- * @example
1043
- * ```typescript
1044
- * const vueCode = `
1045
- * <template>
1046
- * <div class="container">{{ message }}</div>
1047
- * </template>
1048
- *
1049
- * <script setup lang="ts">
1050
- * import { ref } from 'vue;
1051
- * const message = ref('Hello Vue')
1052
- * </script>
1053
- *
1054
- * <style scoped>
1055
- * .container {
1056
- * padding: 20px;
1057
- * }
1058
- * </style>
1059
- * `;
1060
- *
1061
- * const result = compiler.compile(vueCode, 'MyComponent.vue');
1062
- * console.log(result);
1063
- * ```
1064
- *
1065
- * @throws 不会直接抛出异常,错误通过日志系统记录
1066
- * @see {@link parse} 解析函数
1067
- * @see {@link transform} 转换函数
1068
- * @see {@link generate} 生成函数
1069
- * @see {@link executePlugins} 插件执行函数
1070
- */
1071
- compile(source: string, filename: string): CompilationResult;
1072
- /**
1073
- * 初始化 Babel 代码生成选项
1074
- *
1075
- * 合并用户自定义的生成选项与默认选项,确保代码生成的一致性和正确性。
1076
- * 默认配置优化了代码的可读性和性能:
1077
- * 1. 最小化 Unicode 转义:只转义必要的字符,保持代码可读性
1078
- * 2. 统一引号风格:使用单引号,符合 JavaScript 社区常见约定
1079
- * 3. 代码压缩:启用最小化,移除不必要的空白字符
1080
- *
1081
- * 如果用户提供了自定义选项,会与默认选项进行深度合并,
1082
- * 用户选项的优先级高于默认选项。
1083
- *
1084
- * @private
1085
- * @param filename - 可选的文件名,用于源码映射配置
1086
- * @returns {GeneratorOptions} 合并后的 Babel 生成选项
1087
- *
1088
- * @remarks
1089
- * - 源码映射支持:如果启用了 sourceMaps 且提供了文件名,会自动设置 sourceFileName
1090
- * - 选项合并策略:用户选项会覆盖默认选项,实现灵活的配置
1091
- * - 性能优化:默认启用 minified 以减少生成代码的体积
1092
- * - 编码安全:使用 jsesc 确保特殊字符的正确转义
1093
- *
1094
- * @example
1095
- * ```typescript
1096
- * // 默认选项
1097
- * const defaultOptions = {
1098
- * jsescOption: { minimal: true, quotes: 'single' },
1099
- * minified: true
1100
- * };
1101
- *
1102
- * // 用户自定义选项
1103
- * const userOptions = {
1104
- * minified: false, // 覆盖默认值
1105
- * sourceMaps: true // 新增选项
1106
- * };
1107
- *
1108
- * // 合并结果
1109
- * const merged = {
1110
- * jsescOption: { minimal: true, quotes: 'single' },
1111
- * minified: false, // 用户值
1112
- * sourceMaps: true // 用户值
1113
- * };
1114
- * ```
1115
- *
1116
- * @see {@link GeneratorOptions} Babel 生成选项类型定义
1117
- */
1118
- private prepareGenerateOptions;
1119
- /**
1120
- * 处理 SFC 和 Script 文件的编译结果
1121
- *
1122
- * 根据编译上下文中的输入类型(SFC 或 Script),整理并返回相应的编译结果。
1123
- * 对于 SFC 文件,返回包含 JSX 和 CSS 信息的完整结果;
1124
- * 对于 Script 文件,返回仅包含脚本信息的结果。
1125
- *
1126
- * 关键处理逻辑:
1127
- * 1. 构建基础结果:包含文件ID、路由信息和生成的代码
1128
- * 2. 确定输出路径:根据源文件路径和语言类型生成输出文件路径
1129
- * 3. 区分文件类型:
1130
- * - SFC 文件:生成 .tsx 扩展名,包含样式信息
1131
- * - Script 文件:保持原扩展名,不包含样式信息
1132
- * 4. 样式处理:提取样式文件路径、作用域ID和样式代码
1133
- *
1134
- * @private
1135
- * @param ir - React 中间表示(IR)描述符,包含转换后的组件信息
1136
- * @param gen - 代码生成结果,包含生成的代码和源码映射
1137
- * @param ctxData - 编译上下文数据,包含文件信息和编译状态
1138
- * @returns {CompilationResult} 整理后的编译结果
1139
- *
1140
- * @remarks
1141
- * - 文件扩展名处理:Vue SFC 文件会转换为 .tsx 或 .jsx 文件
1142
- * - 样式分离:SFC 中的样式会被提取到独立的 CSS 文件中
1143
- * - 路由检测:自动检测组件是否使用路由,用于依赖注入
1144
- * - 作用域样式:为 Scoped CSS 生成唯一的作用域ID
1145
- *
1146
- * @see {@link SFCCompilationResult} SFC 编译结果类型
1147
- * @see {@link ScriptCompilationResult} Script 编译结果类型
1148
- */
1149
- private resolveMainResult;
1150
- /**
1151
- * 处理 Style 文件的编译结果
1152
- * @param data style 文件解析结果
1153
- * @param ctxData 上下文数据
1154
- */
1155
- private resolveStyleResult;
1156
- }
1230
+ declare function transform(ast: ParseResult, ctx: ICompilationContext, options?: TransformerOptions): ReactIRDescriptor;
1157
1231
 
1232
+ interface GeneratorOptions extends GeneratorOptions$1 {
1233
+ plugins?: PluginRegister<GeneratorResult>;
1234
+ }
1235
+ interface GeneratorResult {
1236
+ ast: t.Program | ParseResult$1;
1237
+ code: string;
1238
+ source: string;
1239
+ }
1158
1240
  /**
1159
- * 文件系统编译器,负责将 Vue 项目批量转换为 React 项目。
1241
+ * React 中间表示(IR)生成为可执行的 JSX/TSX 代码。
1160
1242
  *
1161
- * 此类继承自 {@link BaseCompiler},提供完整的文件系统级别编译功能,包括:
1162
- * 1. 批量扫描和编译 Vue 单文件组件(SFC)
1163
- * 2. 处理 JavaScript/TypeScript 脚本文件
1164
- * 3. 资源文件(图片、样式、字体等)的智能拷贝
1165
- * 4. 增量编译和高效的缓存管理
1166
- * 5. 文件系统监控和自动清理
1167
- * 6. Vite 项目环境自动初始化
1243
+ * 此函数是代码生成阶段的核心入口,负责将转换后的 React IR 转换为
1244
+ * 完整的 AST 并最终生成源代码。生成过程包括 JSX 构建和脚本构建。
1168
1245
  *
1169
- * 主要特性:
1170
- * - 增量编译:基于文件哈希、大小和修改时间进行变更检测,跳过未变更的文件
1171
- * - 智能缓存:维护编译缓存,支持清理过期文件,提高编译效率
1172
- * - 资源处理:自动识别并拷贝非编译文件,保持目录结构
1173
- * - 错误隔离:单个文件编译失败不影响其他文件处理
1174
- * - 并发处理:支持 Promise.all 并发处理多个文件,提升编译速度
1175
- * - 路由感知:自动检测并注入 Vue Router 到 React Router 的转换依赖
1246
+ * @param ir - React 中间表示描述符,来自 {@link transform} 函数的返回值
1247
+ * @param ctx - 编译上下文对象
1248
+ * @param options - 可选的生成选项,包括 Babel 生成器选项和插件
1249
+ * @returns 生成结果对象,包含 AST、生成的代码和原始源码引用
1176
1250
  *
1177
- * 架构设计:
1178
- * 该类采用管理器模式,将不同职责分解到独立的子管理器中:
1179
- * - {@link PipelineManager}: 管理编译管线流程
1180
- * - {@link FileProcessor}: 处理单个文件的编译逻辑
1181
- * - {@link CacheManager}: 管理编译缓存
1182
- * - {@link AssetManager}: 处理资源文件拷贝
1183
- * - {@link CleanupManager}: 清理过期文件和缓存
1184
- * - {@link ViteBootstrapper}: 初始化 Vite React 项目环境
1251
+ * @remarks
1252
+ * - JSX 构建:将模板 IR 转换为 JSX AST 节点
1253
+ * - 脚本构建:将脚本 IR 与 JSX 结合,构建完整的程序 AST
1254
+ * - 代码生成:使用 Babel 生成器将 AST 转换为源代码字符串
1255
+ * - 插件支持:支持通过插件对生成结果进行自定义处理
1185
1256
  *
1186
1257
  * @example
1187
1258
  * ```typescript
1188
- * // 创建文件编译器实例
1189
- * const compiler = new FileCompiler({
1190
- * input: 'src',
1191
- * exclude: ['src/main.ts'],
1192
- * output: {
1193
- * workspace: '.vureact',
1194
- * outDir: 'react-app',
1195
- * bootstrapVite: true
1196
- * },
1197
- * cache: true,
1198
- * watch: false
1199
- * });
1259
+ * // 生成示例
1260
+ *
1261
+ * const ctx: ICompilationContext = {
1262
+ * filename: 'MyComponent.vue',
1263
+ * source: vueSource,
1264
+ * // 其他上下文配置...
1265
+ * };
1266
+ *
1267
+ * // 1. 解析 Vue SFC
1268
+ * const parseResult = parse(vueSource, ctx);
1200
1269
  *
1201
- * // 执行完整编译
1202
- * await compiler.execute();
1270
+ * // 2. 转换为 React IR
1271
+ * const reactIR = transform(parseResult, ctx);
1203
1272
  *
1204
- * // 处理单个 Vue 文件(适用于 watch 模式)
1205
- * await compiler.processSFC('/path/to/Component.vue');
1273
+ * // 使用可选配置项进行自定义处理
1274
+ * const generatorOptions: GeneratorOptions = {
1275
+ * // 配置 jsesc 避免 Unicode 转义
1276
+ * jsescOption: {
1277
+ * minimal: true,
1278
+ * quotes: 'single'
1279
+ * },
1280
+ * minified: true,
1206
1281
  *
1207
- * // 处理单个 Script 文件
1208
- * await compiler.processScript('/path/to/foo.ts');
1282
+ * // 自定义插件
1283
+ * plugins: {
1284
+ * // 插件1:代码格式化
1285
+ * formatCode: (result, ctx) => {
1286
+ * // 使用 prettier 格式化生成的代码
1287
+ * result.code = prettier.format(result.code, {
1288
+ * parser: 'babel',
1289
+ * semi: true,
1290
+ * singleQuote: true,
1291
+ * });
1292
+ * },
1209
1293
  *
1210
- * // 处理单个资源文件
1211
- * await compiler.processAsset('/path/to/image.png');
1294
+ * // 插件2:代码质量检查
1295
+ * lintGeneratedCode: (result, ctx) => {
1296
+ * const issues = eslint.verify(result.code, {
1297
+ * rules: {
1298
+ * 'react/react-in-jsx-scope': 'off',
1299
+ * 'no-unused-vars': 'warn',
1300
+ * },
1301
+ * });
1212
1302
  *
1213
- * // 清理指定路径的输出文件
1214
- * await compiler.removeOutputPath('/path/to/old-component.vue', CacheKey.SFC);
1215
- * ```
1303
+ * if (issues.length > 0) {
1304
+ * result.lintIssues = issues;
1305
+ * console.warn(`Found ${issues.length} lint issues in generated code`);
1306
+ * }
1307
+ * },
1308
+ * },
1309
+ * };
1216
1310
  *
1217
- * @remarks
1218
- * - 编译流程:遵循 "环境初始化 SFC编译 → Script编译 → 资源拷贝" 的顺序
1219
- * - 缓存机制:使用文件哈希、大小和修改时间三重验证确保准确性
1220
- * - 目录结构:保持输入目录结构到输出目录,便于项目迁移
1221
- * - 错误处理:编译错误会记录到日志系统,但不会中断整个编译流程
1222
- * - 性能优化:支持并发处理和增量编译,大幅提升大型项目编译速度
1311
+ * // 3. 生成 React 组件
1312
+ * const generated = generateComponent(reactIR, ctx, generatorOptions);
1223
1313
  *
1224
- * @see {@link BaseCompiler} 提供核心的单文件编译功能
1225
- * @see {@link Helper} 提供基础的文件路径处理和工具方法
1226
- * @see {@link CompilerOptions} 完整的编译器配置选项
1314
+ * // 访问生成结果
1315
+ * console.log(generated.ast); // 完整的 Babel AST
1316
+ * console.log(generated.code); // 生成的 React 代码
1317
+ * console.log(generated.source); // 原始 Vue 源码
1318
+ * ```
1227
1319
  */
1228
- declare class FileCompiler extends BaseCompiler {
1229
- private skippedCount;
1230
- private spinner;
1231
- private viteBootstrapper;
1232
- private pipelineManager;
1233
- private fileProcessor;
1234
- private compilationUnitProcessor;
1235
- private cacheManager;
1236
- private assetManager;
1237
- private cleanupManager;
1238
- /**
1239
- * 创建文件系统编译器实例
1240
- *
1241
- * @param options - 编译器配置选项,继承自 BaseCompiler 的选项
1242
- * 包括输入路径、输出配置、缓存设置、排除模式等
1243
- * @see {@link CompilerOptions} 查看完整的选项说明
1244
- */
1245
- constructor(options?: CompilerOptions);
1246
- /**
1247
- * 初始化所有管理器实例
1248
- *
1249
- * 按照依赖关系顺序创建各个管理器:
1250
- * 1. 基础管理器(无依赖)
1251
- * 2. 依赖基础管理器的管理器
1252
- * 3. 依赖其他管理器的管理器
1253
- *
1254
- * @private
1255
- */
1256
- private initializeManagers;
1257
- /**
1258
- * 执行完整的编译流程
1259
- *
1260
- * 该方法执行以下步骤:
1261
- * 1. 环境初始化:清理旧输出(如果禁用缓存)并初始化 Vite 项目环境
1262
- * 2. Vue 文件编译:批量处理所有 .vue 文件
1263
- * 3. Script 文件编译:批量处理所有 .js/.ts 文件
1264
- * 4. 资源文件拷贝:处理剩余的非编译文件
1265
- * 5. 统计输出:显示编译结果和性能统计
1266
- *
1267
- * @async
1268
- * @throws {Error} 当编译过程中发生致命错误时抛出
1269
- * @returns {Promise<void>}
1270
- */
1271
- execute(): Promise<void>;
1272
- /**
1273
- * 运行管线并显示加载动画
1274
- *
1275
- * @private
1276
- * @param text - 加载动画显示的文本
1277
- * @param pipelineFn - 要执行的管线函数
1278
- * @returns 返回的处理的文件数
1279
- */
1280
- private runPipelineWithSpinner;
1281
- /**
1282
- * 处理单个 Vue 单文件组件(SFC)
1283
- *
1284
- * 此方法主要用于 CLI 的 watch 模式,当检测到文件变更时调用。
1285
- * 支持增量编译,如果文件未变更则跳过编译。
1286
- *
1287
- * @async
1288
- * @param filePath - Vue 文件的绝对路径
1289
- * @param existingCache - 可选的预加载缓存对象,用于增量编译
1290
- * @returns {Promise<SFCUnit | undefined>} 编译单元对象,如果跳过编译则返回 undefined
1291
- * @see {@link FileProcessor.processSFC}
1292
- */
1293
- processSFC(filePath: string, existingCache?: LoadedCache<Vue2ReactCacheMeta>): Promise<SFCUnit | undefined>;
1294
- /**
1295
- * 处理单个 JavaScript/TypeScript 脚本文件
1296
- *
1297
- * 此方法主要用于 CLI 的 watch 模式,当检测到文件变更时调用。
1298
- * 支持增量编译,如果文件未变更则跳过编译。
1299
- *
1300
- * @async
1301
- * @param filePath - 脚本文件的绝对路径
1302
- * @param existingCache - 可选的预加载缓存对象,用于增量编译
1303
- * @returns {Promise<ScriptUnit | undefined>} 编译单元对象,如果跳过编译则返回 undefined
1304
- * @see {@link FileProcessor.processScript}
1305
- */
1306
- processScript(filePath: string, existingCache?: LoadedCache<FileCacheMeta>): Promise<ScriptUnit | undefined>;
1307
- /**
1308
- * 处理单个 CSS/LESS/SCSS 样式文件
1309
- *
1310
- * 此方法主要用于 CLI 的 watch 模式,当检测到文件变更时调用。
1311
- * 支持增量编译,如果文件未变更则跳过编译。
1312
- *
1313
- * @async
1314
- * @param filePath - style 文件的绝对路径
1315
- * @param existingCache - 可选的预加载缓存对象,用于增量编译
1316
- * @returns {Promise<ScriptUnit | undefined>} 编译单元对象,如果跳过编译则返回 undefined
1317
- * @see {@link FileProcessor.processStyle}
1318
- */
1319
- processStyle(filePath: string, existingCache?: LoadedCache<FileCacheMeta>): Promise<StyleUnit | undefined>;
1320
- /**
1321
- * 处理单个文件(Vue 或 Script)
1322
- *
1323
- * 通用的文件处理方法,根据 CacheKey 类型自动选择处理逻辑。
1324
- * 主要用于内部调用和统一的文件处理接口。
1325
- *
1326
- * @async
1327
- * @param key - 文件类型标识(SFC 或 SCRIPT)
1328
- * @param filePath - 文件的绝对路径
1329
- * @param existingCache - 可选的预加载缓存对象
1330
- * @returns {Promise<SFCUnit | ScriptUnit | undefined>} 编译单元对象
1331
- * @see {@link FileProcessor.processFile}
1332
- */
1333
- processFile(key: CacheKey, filePath: string, existingCache?: LoadedCache): Promise<CompilationUnit | undefined>;
1334
- /**
1335
- * 处理单个资源文件
1336
- *
1337
- * 比较文件与缓存,决定是否需要拷贝。
1338
- * 资源文件包括图片、字体、样式文件等非编译文件。
1339
- *
1340
- * @async
1341
- * @param filePath - 资源文件的绝对路径
1342
- * @param existingCache - 可选的预加载缓存对象
1343
- * @returns {Promise<FileCacheMeta>} 资源文件的缓存元数据
1344
- * @see {@link AssetManager.processAsset}
1345
- */
1346
- processAsset(filePath: string, existingCache?: LoadedCache<FileCacheMeta>): Promise<FileCacheMeta>;
1347
- /**
1348
- * 删除指定路径对应的输出文件和缓存
1349
- *
1350
- * 当源文件被删除或重命名时,需要清理对应的输出文件。
1351
- * 主要用于 watch 模式下的文件删除处理。
1352
- *
1353
- * @async
1354
- * @param targetPath - 源代码的路径(文件或文件夹)
1355
- * @param type - 清理类型,指定是 SFC、SCRIPT 还是 ASSET
1356
- * @returns {Promise<void>}
1357
- * @see {@link CleanupManager.removeOutputPath}
1358
- */
1359
- removeOutputPath(targetPath: string, type: CacheKey): Promise<void>;
1360
- /**
1361
- * 获取跳过的文件数量
1362
- *
1363
- * 在增量编译中,未变更的文件会被跳过。
1364
- * 此方法返回当前编译会话中跳过的文件数量。
1365
- *
1366
- * @returns {number} 跳过的文件数量
1367
- */
1368
- getSkippedCount(): number;
1369
- /**
1370
- * 重置跳过的文件数量
1371
- *
1372
- * 在每次新的编译会话开始时调用,重置计数器。
1373
- */
1374
- resetSkippedCount(): void;
1375
- /**
1376
- * 显示编译统计信息
1377
- *
1378
- * 在编译完成后调用,显示以下信息:
1379
- * 1. 编译耗时
1380
- * 2. 输出目录
1381
- * 3. 跳过的文件数量
1382
- * 4. 处理的文件分类统计
1383
- *
1384
- * @private
1385
- * @param endTime - 格式化后的编译耗时字符串
1386
- * @param sfcCount - 处理的 Vue 文件数量
1387
- * @param scriptCount - 处理的脚本文件数量
1388
- * @param assetCount - 处理的资源文件数量
1389
- */
1390
- private showCompileStats;
1391
- }
1320
+ declare function generateComponent(ir: ReactIRDescriptor, ctx: ICompilationContext, options?: GeneratorOptions): GeneratorResult;
1392
1321
 
1393
- /**
1394
- * @see {@link CompilerOptions}
1395
- */
1396
- declare function defineConfig(options: CompilerOptions): CompilerOptions;
1322
+ declare function generateOnlyScript(ir: ReactIRDescriptor, ctx: ICompilationContext, options?: GeneratorOptions): GeneratorResult;
1397
1323
 
1398
1324
  /**
1399
- * Next Vue to React compiler, compiles Vue 3 syntax into runnable React 18+ code.
1325
+ * 代码生成的统一入口函数。
1400
1326
  *
1401
- * @extends FileCompiler
1327
+ * 根据输入类型自动选择生成器:
1328
+ * - `sfc`: 生成完整的 React 组件(包含 JSX 和脚本)
1329
+ * - `script-*`: 仅生成脚本代码(如 .js、.ts)
1402
1330
  *
1403
- * @see {@link FileCompiler}
1404
- * @see https://vureact.top
1331
+ * @param ir - React 中间表示描述符,来自转换阶段的结果
1332
+ * @param ctx - 编译上下文,包含输入类型、源码等信息
1333
+ * @param options - 可选的生成器配置,如 Babel 生成选项和插件
1334
+ * @returns 生成结果对象,包含 AST、生成的代码和原始源码
1405
1335
  */
1406
- declare class VuReact extends FileCompiler {
1407
- }
1336
+ declare function generate(ir: ReactIRDescriptor, ctx: ICompilationContext, options?: GeneratorOptions): GeneratorResult;
1408
1337
 
1409
- export { type AssetUnit, type BaseCompilationResult, BaseCompiler, type BaseUnit, type CacheCheckResult, CacheKey, type CacheList, type CacheMeta, type CompilationResult, type CompilationUnit, type CompilerOptions, type FileCacheMeta, FileCompiler, type FileMeta, type GeneratorOptions, type GeneratorResult, Helper, type LoadedCache, type ParseResult, type ParserOptions, type PluginRegister, type ReactIRDescriptor, type SFCCompilationResult, type SFCUnit, type ScriptCompilationResult, type ScriptUnit, type StyleCompilationResult, type StyleUnit, type TransformerOptions, VuReact, type Vue2ReactCacheMeta, defineConfig, generate, generateComponent, generateOnlyScript, parse, parseOnlyScript, parseSFC, transform };
1338
+ export { type AssetUnit, type BaseCompilationResult, BaseCompiler, type BaseUnit, type CacheCheckResult, CacheKey, type CacheList, type CacheMeta, type CompilationResult, type CompilationUnit, type CompilerOptions, type CompilerPlugins, type FileCacheMeta, FileCompiler, type FileMeta, type FormatConfig, type GeneratorOptions, type GeneratorResult, Helper, type LoadedCache, type LoggingConfig, type OutputConfig, type ParseResult, type ParserOptions, type PluginRegister, type ReactIRDescriptor, type RouterConfig, type SFCCompilationResult, type SFCUnit, type ScriptCacheMeta, type ScriptCompilationResult, type ScriptUnit, type StyleCacheMeta, type StyleCompilationResult, type StyleUnit, type TransformerOptions, type UserConfigFnObject, VuReact, type Vue2ReactCacheMeta, defineConfig, generate, generateComponent, generateOnlyScript, parse, parseOnlyScript, parseSFC, transform };