@meituan-nocode/vite-plugin-nocode-compiler 0.1.0-beta.2 → 0.1.0-beta.21-z

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.
package/README.md CHANGED
@@ -1,129 +1,236 @@
1
1
  # @meituan-nocode/vite-plugin-nocode-compiler
2
2
 
3
- 一个用于 Vite nocode 编译插件,为 JSX 元素自动添加 nocode 所需的标识属性。
3
+ Vite 插件,用于在构建过程中为 Vue React 组件自动添加属性,支持无代码平台的可视化编辑。
4
4
 
5
- ## 功能
5
+ ## 🚀 特性
6
6
 
7
- - 🚀 **多框架支持**: 模块化设计,当前支持 JSX,未来将支持 Vue
8
- - 📦 **自动元素标记**: 为非 Three.js Fiber 和非 Drei 的元素自动添加 nocode 标识
9
- - 🔄 **数组上下文检测**: 智能识别数组映射,添加索引信息
10
- - 🛠️ **可配置**: 支持自定义配置选项
11
- - 📝 **详细日志**: 提供完整的调试信息
7
+ - 支持 Vue 单文件组件 (`.vue`)
8
+ - 支持 React JSX/TSX 组件 (`.jsx`, `.tsx`)
9
+ - 支持 Vue 文件中的 JSX 语法
10
+ - 支持外部模板文件 (`<template src="xxx.html">`)
11
+ - 兼容 Vite 4.x 和 5.x 版本
12
+ - ✅ 可配置的日志输出
13
+ - ✅ 支持 ESM 和 CommonJS 导入方式
14
+ - ✅ 自动跳过 `node_modules` 文件
12
15
 
13
- ## 安装
16
+ ## 📦 安装
14
17
 
15
18
  ```bash
19
+ # npm
16
20
  npm install @meituan-nocode/vite-plugin-nocode-compiler --save-dev
21
+
22
+ # yarn
23
+ yarn add @meituan-nocode/vite-plugin-nocode-compiler --dev
24
+
25
+ # pnpm
26
+ pnpm add @meituan-nocode/vite-plugin-nocode-compiler -D
17
27
  ```
18
28
 
19
- ## 使用
29
+ ## 🔧 快速开始
20
30
 
21
- ### 基础使用
31
+ ### 基础配置
22
32
 
23
- 在你的 `vite.config.js` 或 `vite.config.ts` 中:
33
+ 在项目的 `vite.config.js` 或 `vite.config.ts` 中配置插件:
24
34
 
25
- ```javascript
35
+ ```typescript
36
+ // vite.config.ts
26
37
  import { defineConfig } from 'vite';
27
- import { componentCompiler } from '@meituan-nocode/vite-plugin-nocode-compiler';
38
+ import componentCompiler from '@meituan-nocode/vite-plugin-nocode-compiler';
28
39
 
29
40
  export default defineConfig({
30
41
  plugins: [
31
- componentCompiler(),
32
- // 其他插件...
42
+ componentCompiler({
43
+ enableLogging: true, // 开发时建议开启日志
44
+ }),
33
45
  ],
34
46
  });
35
47
  ```
36
48
 
37
- ### 自定义配置
49
+ ### CommonJS 配置
38
50
 
39
51
  ```javascript
40
- import { defineConfig } from 'vite';
41
- import { componentCompiler } from '@meituan-nocode/vite-plugin-nocode-compiler';
52
+ // vite.config.js
53
+ const { defineConfig } = require('vite');
54
+ const componentCompiler = require('@meituan-nocode/vite-plugin-nocode-compiler').default;
55
+
56
+ module.exports = defineConfig({
57
+ plugins: [
58
+ componentCompiler({
59
+ enableLogging: true,
60
+ }),
61
+ ],
62
+ });
63
+ ```
42
64
 
65
+ ## ⚙️ 配置选项
66
+
67
+ | 选项 | 类型 | 默认值 | 描述 |
68
+ | --------------- | --------- | ------- | ------------------------------------------------------ |
69
+ | `enableLogging` | `boolean` | `false` | 是否启用日志输出,开启后会输出详细的处理过程和调试信息 |
70
+ | `rootPath` | `string` | - | 项目根路径,用于生成相对路径标识 |
71
+
72
+ ### 配置示例
73
+
74
+ ```typescript
75
+ // 完整配置示例
43
76
  export default defineConfig({
44
77
  plugins: [
45
78
  componentCompiler({
46
- validExtensions: new Set(['.jsx', '.tsx']), // 支持的文件扩展名
47
- enableLogging: true, // 启用调试日志
48
- threeFiberElems: [
49
- /* 自定义列表 */
50
- ], // 自定义 Three.js 元素
51
- dreiElems: [
52
- /* 自定义列表 */
53
- ], // 自定义 Drei 元素
79
+ enableLogging: process.env.NODE_ENV === 'development',
80
+ rootPath: process.cwd(),
54
81
  }),
55
82
  ],
56
83
  });
57
84
  ```
58
85
 
59
- ## 工作原理
86
+ ## 📁 处理的文件类型
87
+
88
+ ### Vue 文件
89
+
90
+ - `.vue` 单文件组件的 `<template>` 部分
91
+ - Vue 文件中的 JSX/TSX `<script>` 部分
92
+ - 外部模板文件 `<template src="xxx.html">`
93
+
94
+ ### React 文件
95
+
96
+ - `.jsx` 文件
97
+ - `.tsx` 文件
98
+ - 包含 JSX 语法的 `.js` 和 `.ts` 文件
60
99
 
61
- 插件会扫描 `.jsx` 文件中的 JSX 元素,对于不在 Three.js Fiber 元素列表和 Drei 元素列表中的元素,自动添加以下属性:
100
+ ### 文件处理逻辑
62
101
 
63
- - `data-nocode-id`: 格式为 `文件路径:行号:列号`
64
- - `data-nocode-name`: 元素名称
65
- - `data-nocode-array`: 当元素在数组映射中时,包含数组名称
66
- - `data-nocode-index`: 当元素在数组映射中时,包含索引变量
102
+ 插件会根据文件扩展名和 Vite 查询参数智能判断文件类型:
67
103
 
68
- ## 示例
104
+ ```typescript
105
+ // Vue 文件中的 JSX 处理
106
+ // App.vue?type=script&lang.tsx
107
+ // App.vue?isJsx
69
108
 
70
- 输入:
109
+ // Vue 模板处理
110
+ // App.vue?type=template
71
111
 
72
- ```jsx
73
- function App() {
74
- return (
75
- <div>
76
- <button>Click me</button>
77
- {items.map((item, index) => (
78
- <span key={item.id}>{item.name}</span>
79
- ))}
80
- </div>
81
- );
82
- }
112
+ // 外部模板处理
113
+ // template.html?type=template&vue
83
114
  ```
84
115
 
85
- 输出:
86
-
87
- ```jsx
88
- function App() {
89
- return (
90
- <div data-nocode-id='App.jsx:3:4' data-nocode-name='div'>
91
- <button data-nocode-id='App.jsx:4:6' data-nocode-name='button'>
92
- Click me
93
- </button>
94
- {items.map((item, index) => (
95
- <span data-nocode-id='App.jsx:6:8' data-nocode-name='span' data-nocode-array='items' data-nocode-index='${index}' key={item.id}>
96
- {item.name}
97
- </span>
98
- ))}
99
- </div>
100
- );
101
- }
116
+ ## 🎯 工作原理
117
+
118
+ 插件会在构建过程中为符合条件的元素添加以下属性:
119
+
120
+ ```html
121
+ <!-- 处理前 -->
122
+ <div class="container">
123
+ <button>Click me</button>
124
+ </div>
125
+
126
+ <!-- 处理后 -->
127
+ <div class="container" data-nocode-id="src/App.vue:1:0" data-nocode-path="src/App.vue" data-nocode-line="1" data-nocode-col="0">
128
+ <button data-nocode-id="src/App.vue:2:2" data-nocode-path="src/App.vue" data-nocode-line="2" data-nocode-col="2">Click me</button>
129
+ </div>
102
130
  ```
103
131
 
104
- ## 架构
132
+ ### 添加的属性说明
105
133
 
106
- 该插件采用模块化设计,支持多种前端框架:
134
+ - `data-nocode-id`: 元素的唯一标识符(格式:`文件路径:行号:列号`)
135
+ - `data-nocode-path`: 相对文件路径
136
+ - `data-nocode-line`: 元素在文件中的行号
137
+ - `data-nocode-col`: 元素在文件中的列号
138
+ - `data-nocode-array`: (可选)当元素在 `v-for` 或 `map` 循环中时,标识数组名称
107
139
 
108
- - **JSX/TSX**: 已实现
109
- - **Vue**: 🚧 接口已预留,等待实现
140
+ ## 🏗️ Monorepo 项目中使用
110
141
 
111
- 详细架构说明请参考 [ARCHITECTURE.md](./ARCHITECTURE.md)
142
+ monorepo 项目中,建议在共享配置中定义插件:
112
143
 
113
- ## 开发
144
+ ```typescript
145
+ // packages/shared/vite-config.ts
146
+ import { defineConfig } from 'vite';
147
+ import componentCompiler from '@meituan-nocode/vite-plugin-nocode-compiler';
148
+
149
+ export const createViteConfig = (options: { enableLogging?: boolean } = {}) => {
150
+ return defineConfig({
151
+ plugins: [
152
+ componentCompiler({
153
+ enableLogging: options.enableLogging ?? process.env.NODE_ENV === 'development',
154
+ }),
155
+ ],
156
+ });
157
+ };
158
+
159
+ // 子项目中使用
160
+ // packages/app-a/vite.config.ts
161
+ import { createViteConfig } from '@shared/vite-config';
162
+
163
+ export default createViteConfig({ enableLogging: true });
164
+ ```
114
165
 
115
- ```bash
116
- # 构建
117
- npm run build
166
+ ## 🐛 调试和故障排除
118
167
 
119
- # 开发模式(监听文件变化)
120
- npm run dev
168
+ ### 启用调试日志
169
+
170
+ ```typescript
171
+ // vite.config.ts
172
+ export default defineConfig({
173
+ plugins: [
174
+ componentCompiler({
175
+ enableLogging: true, // 开启详细日志
176
+ }),
177
+ ],
178
+ });
121
179
  ```
122
180
 
123
- ## 扩展支持
181
+ 开启后,构建时会输出类似日志:
182
+
183
+ ```
184
+ [vite-plugin-nocode-compiler] Processing Vue file: src/App.vue
185
+ [vue-compiler] File processing complete 5
186
+ [vite-plugin-nocode-compiler] Processing JSX file: src/components/Button.tsx
187
+ [jsx-compiler] File processing complete 3
188
+ ```
189
+
190
+ ### 常见问题
191
+
192
+ #### Q: 插件没有生效怎么办?
193
+
194
+ A: 检查以下几点:
195
+
196
+ 1. 确认插件已正确安装和配置
197
+ 2. 确保 `enforce: 'pre'` 设置正确(插件已内置)
198
+ 3. 检查文件是否在 `node_modules` 中(插件会自动跳过)
199
+ 4. 开启 `enableLogging` 查看是否有处理日志
200
+
201
+ #### Q: 某些文件没有被处理?
202
+
203
+ A: 可能的原因:
204
+
205
+ - 文件在 `node_modules` 目录下
206
+ - 文件类型不支持(如纯 CSS 文件)
207
+ - Vue 文件的 `<style>` 部分(插件只处理模板和脚本)
208
+
209
+ #### Q: 如何排除特定文件?
210
+
211
+ A: 目前插件没有内置排除选项,但可以通过 Vite 的 `optimizeDeps` 或自定义插件来实现:
212
+
213
+ ```typescript
214
+ export default defineConfig({
215
+ plugins: [
216
+ componentCompiler(),
217
+ // 自定义插件排除特定文件
218
+ {
219
+ name: 'exclude-files',
220
+ transform(code, id) {
221
+ if (id.includes('excluded-folder')) {
222
+ return null; // 跳过处理
223
+ }
224
+ },
225
+ },
226
+ ],
227
+ });
228
+ ```
124
229
 
125
- 如需添加新框架支持,请参考架构文档中的扩展指南。
230
+ ## 📚 依赖关系
126
231
 
127
- ## License
232
+ 该插件依赖于以下核心包:
128
233
 
129
- ISC
234
+ - `@meituan-nocode/nocode-compiler-core`: 提供核心编译逻辑
235
+ - `VueCompiler`: Vue 组件编译器
236
+ - `JSXCompiler`: JSX 组件编译器
package/dist/index.d.ts CHANGED
@@ -1,8 +1,14 @@
1
- import type { Plugin } from 'vite';
2
- import type { CompilerOptions } from './types';
1
+ export interface NocodeCompilerOptions {
2
+ enableLogging?: boolean;
3
+ rootPath?: string;
4
+ }
3
5
  /**
4
- * 创建 nocode 编译器插件
5
- * @param options 编译器选项
6
- * @returns Vite 插件
6
+ * Vite插件
7
+ * 用于在构建过程中处理Vue和React组件,添加nocode相关的标记
7
8
  */
8
- export declare function componentCompiler(options?: Partial<CompilerOptions>): Plugin;
9
+ export declare function componentCompiler(options?: NocodeCompilerOptions): {
10
+ name: string;
11
+ enforce: "pre";
12
+ transform(code: string, id: string): Promise<string>;
13
+ };
14
+ export default componentCompiler;
package/dist/index.js CHANGED
@@ -1,63 +1,60 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.componentCompiler = componentCompiler;
4
- const constants_1 = require("./utils/constants");
5
- const base_compiler_1 = require("./modules/base-compiler");
6
- const jsx_compiler_1 = require("./modules/jsx-compiler");
7
- const utils_1 = require("./utils/utils");
4
+ const nocode_compiler_core_1 = require("@meituan-nocode/nocode-compiler-core");
5
+ const utils_1 = require("./utils");
8
6
  /**
9
- * 创建 nocode 编译器插件
10
- * @param options 编译器选项
11
- * @returns Vite 插件
7
+ * Vite插件
8
+ * 用于在构建过程中处理Vue和React组件,添加nocode相关的标记
12
9
  */
13
10
  function componentCompiler(options = {}) {
14
- // 合并默认配置
15
- const config = {
16
- ...constants_1.DEFAULT_CONFIG,
11
+ options = {
12
+ enableLogging: false,
17
13
  ...options,
18
- validExtensions: new Set([...Array.from(constants_1.DEFAULT_CONFIG.validExtensions), ...(options.validExtensions ? Array.from(options.validExtensions) : [])]),
19
- threeFiberElems: options.threeFiberElems || constants_1.DEFAULT_CONFIG.threeFiberElems,
20
- dreiElems: options.dreiElems || constants_1.DEFAULT_CONFIG.dreiElems,
21
14
  };
22
- // 创建编译器注册表
23
- const registry = new base_compiler_1.CompilerRegistry();
24
- // 注册 JSX 编译器
25
- registry.register({
26
- name: 'jsx',
27
- supportedExtensions: jsx_compiler_1.JSXCompiler.supportedExtensions,
28
- CompilerClass: jsx_compiler_1.JSXCompiler,
29
- });
30
- // 未来可以在这里注册 Vue 编译器
31
- // registry.register({
32
- // name: 'vue',
33
- // supportedExtensions: VueCompiler.supportedExtensions,
34
- // CompilerClass: VueCompiler,
35
- // });
36
- // 创建统计管理器
37
- const statsManager = new utils_1.StatsManager();
15
+ // 创建代码转换器实例
16
+ // const codeTransformer = new CodeTransformer(options);
17
+ const vueCompiler = new nocode_compiler_core_1.VueCompiler(options);
18
+ const jsxCompiler = new nocode_compiler_core_1.JSXCompiler(options);
38
19
  return {
39
20
  name: 'vite-plugin-nocode-compiler',
40
21
  enforce: 'pre',
41
22
  async transform(code, id) {
42
- // 获取适合的编译器
43
- const compiler = registry.getCompilerForFile(id, {
44
- validExtensions: config.validExtensions,
45
- threeFiberElems: config.threeFiberElems,
46
- dreiElems: config.dreiElems,
47
- enableLogging: config.enableLogging,
48
- });
49
- if (!compiler) {
50
- return null;
23
+ // 跳过node_modules
24
+ if (id.includes('node_modules')) {
25
+ return code;
51
26
  }
52
- // 统计文件处理
53
- statsManager.incrementTotalFiles();
54
- // 编译代码
55
- const result = await compiler.compile(code, id);
56
- if (result) {
57
- statsManager.incrementProcessedFiles();
58
- // 这里可以添加元素计数,如果编译器返回相关信息的话
27
+ const [_completePath, query] = id.split('?', 2); // 当前文件的绝对路径
28
+ let filePath = _completePath;
29
+ const params = new URLSearchParams(query);
30
+ // let fileType = '';
31
+ if ((0, utils_1.isJsTypeFile)(filePath) || (filePath.endsWith('.vue') && (utils_1.JsxParamList.some(param => params.get(param) !== null) || params.get('lang') === 'tsx' || params.get('lang') === 'jsx'))) {
32
+ // jsx 代码
33
+ return jsxCompiler.compile(code, filePath) || code;
59
34
  }
60
- return result;
35
+ else if (filePath.endsWith('.html') && params.get('type') === 'template' && params.has('vue')) {
36
+ // <template src="xxx.html"></template>
37
+ return vueCompiler.compile(code, filePath) || code;
38
+ }
39
+ else if (filePath.endsWith('.vue') && params.get('type') !== 'style' && params.get('raw') === null) {
40
+ // vue 代码
41
+ return vueCompiler.compile(code, filePath) || code;
42
+ }
43
+ // // 如果是Vue文件但@vue/compiler-dom不可用,跳过处理
44
+ // if (fileType === 'vue' && !vueCompilerAvailable) {
45
+ // console.warn(`[vite-plugin-nocode-compiler] Skipping Vue file processing for ${filePath} due to missing @vue/compiler-dom`);
46
+ // return code;
47
+ // }
48
+ // if (fileType) {
49
+ // return codeTransformer.transformCode({
50
+ // content: code,
51
+ // filePath,
52
+ // fileType,
53
+ // });
54
+ // }
55
+ return code;
61
56
  },
62
57
  };
63
58
  }
59
+ // 添加默认导出,使 ESM 导入更方便
60
+ exports.default = componentCompiler;
@@ -0,0 +1,9 @@
1
+ export declare const JsFileExtList: string[];
2
+ export declare const JsxParamList: string[];
3
+ export declare function isJsTypeFile(file: string): boolean;
4
+ /**
5
+ * 规范化路径,将反斜杠转换为正斜杠
6
+ * @param filePath 文件路径
7
+ * @returns 规范化后的路径
8
+ */
9
+ export declare function normalizePath(filePath: string): string;
package/dist/utils.js ADDED
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JsxParamList = exports.JsFileExtList = void 0;
4
+ exports.isJsTypeFile = isJsTypeFile;
5
+ exports.normalizePath = normalizePath;
6
+ exports.JsFileExtList = ['.js', '.ts', '.mjs', '.mts', '.jsx', '.tsx'];
7
+ exports.JsxParamList = ['isJsx', 'isTsx', 'lang.jsx', 'lang.tsx'];
8
+ // 是否为 JS 类型的文件
9
+ function isJsTypeFile(file) {
10
+ return exports.JsFileExtList.some(ext => file.endsWith(ext));
11
+ }
12
+ /**
13
+ * 规范化路径,将反斜杠转换为正斜杠
14
+ * @param filePath 文件路径
15
+ * @returns 规范化后的路径
16
+ */
17
+ function normalizePath(filePath) {
18
+ if (!filePath)
19
+ return '';
20
+ return filePath.replace(/\\/g, '/');
21
+ }
package/package.json CHANGED
@@ -1,10 +1,18 @@
1
1
  {
2
2
  "name": "@meituan-nocode/vite-plugin-nocode-compiler",
3
- "version": "0.1.0-beta.2",
4
- "description": "nocode编译插件",
5
- "main": "dist/index.js",
6
- "module": "dist/index.mjs",
3
+ "version": "0.1.0-beta.21-z",
4
+ "description": "nocode compiler plugin",
5
+ "type": "module",
6
+ "main": "dist/index.cjs.js",
7
+ "module": "dist/index.es.js",
7
8
  "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "require": "./dist/index.cjs.js",
12
+ "import": "./dist/index.es.js",
13
+ "types": "./dist/index.d.ts"
14
+ }
15
+ },
8
16
  "files": [
9
17
  "dist"
10
18
  ],
@@ -13,18 +21,12 @@
13
21
  "build": "tsc",
14
22
  "prepublishOnly": "npm run build"
15
23
  },
16
- "peerDependencies": {
17
- "vite": "^5.4.0"
18
- },
19
24
  "devDependencies": {
20
25
  "@types/node": "^20.0.0",
21
26
  "typescript": "^5.0.0",
22
- "vite": "^5.4.0"
27
+ "vite": "^4.5.14"
23
28
  },
24
29
  "dependencies": {
25
- "@babel/parser": "^7.23.0",
26
- "@babel/types": "^7.23.0",
27
- "magic-string": "^0.30.0",
28
- "estree-walker": "^3.0.0"
30
+ "@meituan-nocode/nocode-compiler-core": "0.1.0-beta.21-z"
29
31
  }
30
32
  }
@@ -1,51 +0,0 @@
1
- /**
2
- * 基础编译器接口
3
- * 定义所有编译器(JSX、Vue等)的通用接口
4
- */
5
- export interface BaseCompiler {
6
- /**
7
- * 编译代码
8
- * @param code 源代码
9
- * @param id 文件路径
10
- * @returns 编译结果或null(如果不需要处理)
11
- */
12
- compile(code: string, id: string): Promise<{
13
- code: string;
14
- map: any;
15
- } | null>;
16
- }
17
- /**
18
- * 编译器类构造函数类型
19
- */
20
- export type CompilerConstructor = new (options: any) => BaseCompiler;
21
- /**
22
- * 编译器信息接口
23
- */
24
- export interface CompilerInfo {
25
- name: string;
26
- supportedExtensions: string[];
27
- CompilerClass: CompilerConstructor;
28
- }
29
- /**
30
- * 编译器注册表
31
- * 管理不同类型的编译器
32
- */
33
- export declare class CompilerRegistry {
34
- private compilers;
35
- /**
36
- * 注册编译器
37
- */
38
- register(info: CompilerInfo): void;
39
- /**
40
- * 获取编译器信息
41
- */
42
- getCompilerInfo(name: string): CompilerInfo | undefined;
43
- /**
44
- * 获取所有支持的文件扩展名
45
- */
46
- getAllSupportedExtensions(): string[];
47
- /**
48
- * 根据文件扩展名获取合适的编译器
49
- */
50
- getCompilerForFile(filePath: string, options: any): BaseCompiler | null;
51
- }
@@ -1,44 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CompilerRegistry = void 0;
4
- /**
5
- * 编译器注册表
6
- * 管理不同类型的编译器
7
- */
8
- class CompilerRegistry {
9
- compilers = new Map();
10
- /**
11
- * 注册编译器
12
- */
13
- register(info) {
14
- this.compilers.set(info.name, info);
15
- }
16
- /**
17
- * 获取编译器信息
18
- */
19
- getCompilerInfo(name) {
20
- return this.compilers.get(name);
21
- }
22
- /**
23
- * 获取所有支持的文件扩展名
24
- */
25
- getAllSupportedExtensions() {
26
- const extensions = [];
27
- for (const info of this.compilers.values()) {
28
- extensions.push(...info.supportedExtensions);
29
- }
30
- return [...new Set(extensions)];
31
- }
32
- /**
33
- * 根据文件扩展名获取合适的编译器
34
- */
35
- getCompilerForFile(filePath, options) {
36
- for (const info of this.compilers.values()) {
37
- if (info.supportedExtensions.some(ext => filePath.endsWith(ext))) {
38
- return new info.CompilerClass(options);
39
- }
40
- }
41
- return null;
42
- }
43
- }
44
- exports.CompilerRegistry = CompilerRegistry;
@@ -1,26 +0,0 @@
1
- import type { BaseCompiler } from './base-compiler';
2
- export interface JSXCompilerOptions {
3
- validExtensions: Set<string>;
4
- threeFiberElems: string[];
5
- dreiElems: string[];
6
- enableLogging?: boolean;
7
- }
8
- /**
9
- * JSX 编译器类
10
- * 负责处理 JSX 文件的编译逻辑
11
- */
12
- export declare class JSXCompiler implements BaseCompiler {
13
- static readonly supportedExtensions: string[];
14
- static readonly name = "jsx";
15
- private options;
16
- private logger;
17
- private cwd;
18
- constructor(options: JSXCompilerOptions);
19
- /**
20
- * 编译 JSX 代码
21
- */
22
- compile(code: string, id: string): Promise<{
23
- code: string;
24
- map: any;
25
- } | null>;
26
- }
@@ -1,157 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.JSXCompiler = void 0;
40
- const parser_1 = require("@babel/parser");
41
- const magic_string_1 = __importDefault(require("magic-string"));
42
- const path_1 = __importDefault(require("path"));
43
- const utils_1 = require("../utils/utils");
44
- /**
45
- * JSX 编译器类
46
- * 负责处理 JSX 文件的编译逻辑
47
- */
48
- class JSXCompiler {
49
- static supportedExtensions = ['.jsx'];
50
- static name = 'jsx';
51
- options;
52
- logger;
53
- cwd;
54
- constructor(options) {
55
- this.options = options;
56
- this.logger = new utils_1.Logger(options.enableLogging);
57
- this.cwd = process.cwd();
58
- }
59
- /**
60
- * 编译 JSX 代码
61
- */
62
- async compile(code, id) {
63
- this.logger.log('\nProcessing file:', id);
64
- if (!(0, utils_1.shouldProcessFile)(id, this.options.validExtensions)) {
65
- this.logger.log('Skipping file (not .jsx or in node_modules):', id);
66
- return null;
67
- }
68
- const relativePath = path_1.default.relative(this.cwd, id);
69
- this.logger.log('Relative path:', relativePath);
70
- try {
71
- const parserOptions = {
72
- sourceType: 'module',
73
- plugins: ['jsx'],
74
- };
75
- const ast = (0, parser_1.parse)(code, parserOptions);
76
- const magicString = new magic_string_1.default(code);
77
- let changedElementsCount = 0;
78
- let currentElement = null;
79
- let arrayContext = null;
80
- const { walk } = await Promise.resolve().then(() => __importStar(require('estree-walker')));
81
- walk(ast, {
82
- enter: (node) => {
83
- // 检测数组的 map 调用
84
- if (node.type === 'CallExpression' && node.callee?.type === 'MemberExpression' && node.callee.property?.name === 'map') {
85
- this.logger.log('Found array map:', node);
86
- const callee = node.callee;
87
- const arrayName = callee.object.name || (callee.object.type === 'MemberExpression' ? `${callee.object.object.name}.${callee.object.property.name}` : null);
88
- if (arrayName) {
89
- const paramName = node.arguments[0].params?.[1]?.name || 'index';
90
- arrayContext = { arrayName, paramName };
91
- this.logger.log('Found array map:', { arrayName, paramName });
92
- }
93
- }
94
- if (node.type === 'JSXElement') {
95
- currentElement = node;
96
- }
97
- if (node.type === 'JSXOpeningElement') {
98
- const jsxNode = node;
99
- let elementName;
100
- if (jsxNode.name.type === 'JSXIdentifier') {
101
- elementName = jsxNode.name.name;
102
- }
103
- else if (jsxNode.name.type === 'JSXMemberExpression') {
104
- const memberExpr = jsxNode.name;
105
- elementName = `${memberExpr.object.name}.${memberExpr.property.name}`;
106
- }
107
- else {
108
- return;
109
- }
110
- if (elementName === 'Fragment' || elementName === 'React.Fragment') {
111
- return;
112
- }
113
- const shouldTag = (0, utils_1.shouldTagElement)(elementName, this.options.threeFiberElems, this.options.dreiElems);
114
- this.logger.log('Found JSX element:', {
115
- elementName,
116
- shouldTag,
117
- hasArrayContext: !!arrayContext,
118
- });
119
- if (shouldTag) {
120
- const line = jsxNode.loc?.start?.line ?? 0;
121
- const col = jsxNode.loc?.start?.column ?? 0;
122
- const attributes = (0, utils_1.generateDataAttributes)(relativePath, line, col, elementName, arrayContext);
123
- this.logger.log('Adding attributes:', attributes);
124
- magicString.appendLeft(jsxNode.name.end ?? 0, attributes);
125
- changedElementsCount++;
126
- }
127
- }
128
- },
129
- leave: (node) => {
130
- if (node.type === 'CallExpression' && node.callee?.type === 'MemberExpression' && node.callee.property?.name === 'map') {
131
- if (arrayContext) {
132
- this.logger.log('Leaving array map context:', arrayContext.arrayName);
133
- }
134
- arrayContext = null;
135
- }
136
- },
137
- });
138
- this.logger.log('File processing complete:', {
139
- file: relativePath,
140
- elementsChanged: changedElementsCount,
141
- });
142
- if (changedElementsCount > 0) {
143
- this.logger.log('Modified code preview:', magicString.toString().slice(0, 500) + '...');
144
- }
145
- return {
146
- code: magicString.toString(),
147
- map: magicString.generateMap({ hires: true }),
148
- };
149
- }
150
- catch (error) {
151
- this.logger.error('Error processing file:', relativePath);
152
- this.logger.error('Error', error);
153
- return null;
154
- }
155
- }
156
- }
157
- exports.JSXCompiler = JSXCompiler;
package/dist/types.d.ts DELETED
@@ -1,17 +0,0 @@
1
- import type { Plugin } from 'vite';
2
- export interface ArrayContext {
3
- arrayName: string;
4
- paramName: string;
5
- }
6
- export interface CompilerStats {
7
- totalFiles: number;
8
- processedFiles: number;
9
- totalElements: number;
10
- }
11
- export interface CompilerOptions {
12
- validExtensions?: Set<string>;
13
- threeFiberElems?: string[];
14
- dreiElems?: string[];
15
- enableLogging?: boolean;
16
- }
17
- export type NocodeCompilerPlugin = (options?: Partial<CompilerOptions>) => Plugin;
package/dist/types.js DELETED
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,23 +0,0 @@
1
- /**
2
- * Three.js Fiber 元素列表
3
- * 这些元素不需要添加 nocode 标识
4
- */
5
- export declare const threeFiberElems: string[];
6
- /**
7
- * Drei 元素列表
8
- * 这些元素不需要添加 nocode 标识
9
- */
10
- export declare const dreiElems: string[];
11
- /**
12
- * 支持的文件扩展名
13
- */
14
- export declare const DEFAULT_VALID_EXTENSIONS: Set<string>;
15
- /**
16
- * 默认配置
17
- */
18
- export declare const DEFAULT_CONFIG: {
19
- validExtensions: Set<string>;
20
- threeFiberElems: string[];
21
- dreiElems: string[];
22
- enableLogging: boolean;
23
- };
@@ -1,287 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEFAULT_CONFIG = exports.DEFAULT_VALID_EXTENSIONS = exports.dreiElems = exports.threeFiberElems = void 0;
4
- /**
5
- * Three.js Fiber 元素列表
6
- * 这些元素不需要添加 nocode 标识
7
- */
8
- exports.threeFiberElems = [
9
- 'object3D',
10
- 'audioListener',
11
- 'positionalAudio',
12
- 'mesh',
13
- 'batchedMesh',
14
- 'instancedMesh',
15
- 'scene',
16
- 'sprite',
17
- 'lOD',
18
- 'skinnedMesh',
19
- 'skeleton',
20
- 'bone',
21
- 'lineSegments',
22
- 'lineLoop',
23
- 'points',
24
- 'group',
25
- 'camera',
26
- 'perspectiveCamera',
27
- 'orthographicCamera',
28
- 'cubeCamera',
29
- 'arrayCamera',
30
- 'instancedBufferGeometry',
31
- 'bufferGeometry',
32
- 'boxBufferGeometry',
33
- 'circleBufferGeometry',
34
- 'coneBufferGeometry',
35
- 'cylinderBufferGeometry',
36
- 'dodecahedronBufferGeometry',
37
- 'extrudeBufferGeometry',
38
- 'icosahedronBufferGeometry',
39
- 'latheBufferGeometry',
40
- 'octahedronBufferGeometry',
41
- 'planeBufferGeometry',
42
- 'polyhedronBufferGeometry',
43
- 'ringBufferGeometry',
44
- 'shapeBufferGeometry',
45
- 'sphereBufferGeometry',
46
- 'tetrahedronBufferGeometry',
47
- 'torusBufferGeometry',
48
- 'torusKnotBufferGeometry',
49
- 'tubeBufferGeometry',
50
- 'wireframeGeometry',
51
- 'tetrahedronGeometry',
52
- 'octahedronGeometry',
53
- 'icosahedronGeometry',
54
- 'dodecahedronGeometry',
55
- 'polyhedronGeometry',
56
- 'tubeGeometry',
57
- 'torusKnotGeometry',
58
- 'torusGeometry',
59
- 'sphereGeometry',
60
- 'ringGeometry',
61
- 'planeGeometry',
62
- 'latheGeometry',
63
- 'shapeGeometry',
64
- 'extrudeGeometry',
65
- 'edgesGeometry',
66
- 'coneGeometry',
67
- 'cylinderGeometry',
68
- 'circleGeometry',
69
- 'boxGeometry',
70
- 'capsuleGeometry',
71
- 'material',
72
- 'shadowMaterial',
73
- 'spriteMaterial',
74
- 'rawShaderMaterial',
75
- 'shaderMaterial',
76
- 'pointsMaterial',
77
- 'meshPhysicalMaterial',
78
- 'meshStandardMaterial',
79
- 'meshPhongMaterial',
80
- 'meshToonMaterial',
81
- 'meshNormalMaterial',
82
- 'meshLambertMaterial',
83
- 'meshDepthMaterial',
84
- 'meshDistanceMaterial',
85
- 'meshBasicMaterial',
86
- 'meshMatcapMaterial',
87
- 'lineDashedMaterial',
88
- 'lineBasicMaterial',
89
- 'primitive',
90
- 'light',
91
- 'spotLightShadow',
92
- 'spotLight',
93
- 'pointLight',
94
- 'rectAreaLight',
95
- 'hemisphereLight',
96
- 'directionalLightShadow',
97
- 'directionalLight',
98
- 'ambientLight',
99
- 'lightShadow',
100
- 'ambientLightProbe',
101
- 'hemisphereLightProbe',
102
- 'lightProbe',
103
- 'spotLightHelper',
104
- 'skeletonHelper',
105
- 'pointLightHelper',
106
- 'hemisphereLightHelper',
107
- 'gridHelper',
108
- 'polarGridHelper',
109
- 'directionalLightHelper',
110
- 'cameraHelper',
111
- 'boxHelper',
112
- 'box3Helper',
113
- 'planeHelper',
114
- 'arrowHelper',
115
- 'axesHelper',
116
- 'texture',
117
- 'videoTexture',
118
- 'dataTexture',
119
- 'dataTexture3D',
120
- 'compressedTexture',
121
- 'cubeTexture',
122
- 'canvasTexture',
123
- 'depthTexture',
124
- 'raycaster',
125
- 'vector2',
126
- 'vector3',
127
- 'vector4',
128
- 'euler',
129
- 'matrix3',
130
- 'matrix4',
131
- 'quaternion',
132
- 'bufferAttribute',
133
- 'float16BufferAttribute',
134
- 'float32BufferAttribute',
135
- 'float64BufferAttribute',
136
- 'int8BufferAttribute',
137
- 'int16BufferAttribute',
138
- 'int32BufferAttribute',
139
- 'uint8BufferAttribute',
140
- 'uint16BufferAttribute',
141
- 'uint32BufferAttribute',
142
- 'instancedBufferAttribute',
143
- 'color',
144
- 'fog',
145
- 'fogExp2',
146
- 'shape',
147
- 'colorShiftMaterial',
148
- ];
149
- /**
150
- * Drei 元素列表
151
- * 这些元素不需要添加 nocode 标识
152
- */
153
- exports.dreiElems = [
154
- 'AsciiRenderer',
155
- 'Billboard',
156
- 'Clone',
157
- 'ComputedAttribute',
158
- 'Decal',
159
- 'Edges',
160
- 'Effects',
161
- 'GradientTexture',
162
- 'Image',
163
- 'MarchingCubes',
164
- 'Outlines',
165
- 'PositionalAudio',
166
- 'Sampler',
167
- 'ScreenSizer',
168
- 'ScreenSpace',
169
- 'Splat',
170
- 'Svg',
171
- 'Text',
172
- 'Text3D',
173
- 'Trail',
174
- 'CubeCamera',
175
- 'OrthographicCamera',
176
- 'PerspectiveCamera',
177
- 'CameraControls',
178
- 'FaceControls',
179
- 'KeyboardControls',
180
- 'MotionPathControls',
181
- 'PresentationControls',
182
- 'ScrollControls',
183
- 'DragControls',
184
- 'GizmoHelper',
185
- 'Grid',
186
- 'Helper',
187
- 'PivotControls',
188
- 'TransformControls',
189
- 'CubeTexture',
190
- 'Fbx',
191
- 'Gltf',
192
- 'Ktx2',
193
- 'Loader',
194
- 'Progress',
195
- 'ScreenVideoTexture',
196
- 'Texture',
197
- 'TrailTexture',
198
- 'VideoTexture',
199
- 'WebcamVideoTexture',
200
- 'CycleRaycast',
201
- 'DetectGPU',
202
- 'Example',
203
- 'FaceLandmarker',
204
- 'Fbo',
205
- 'Html',
206
- 'Select',
207
- 'SpriteAnimator',
208
- 'StatsGl',
209
- 'Stats',
210
- 'Trail',
211
- 'Wireframe',
212
- 'CurveModifier',
213
- 'AdaptiveDpr',
214
- 'AdaptiveEvents',
215
- 'BakeShadows',
216
- 'Bvh',
217
- 'Detailed',
218
- 'Instances',
219
- 'Merged',
220
- 'meshBounds',
221
- 'PerformanceMonitor',
222
- 'Points',
223
- 'Preload',
224
- 'Segments',
225
- 'Fisheye',
226
- 'Hud',
227
- 'Mask',
228
- 'MeshPortalMaterial',
229
- 'RenderCubeTexture',
230
- 'RenderTexture',
231
- 'View',
232
- 'MeshDiscardMaterial',
233
- 'MeshDistortMaterial',
234
- 'MeshReflectorMaterial',
235
- 'MeshRefractionMaterial',
236
- 'MeshTransmissionMaterial',
237
- 'MeshWobbleMaterial',
238
- 'PointMaterial',
239
- 'shaderMaterial',
240
- 'SoftShadows',
241
- 'CatmullRomLine',
242
- 'CubicBezierLine',
243
- 'Facemesh',
244
- 'Line',
245
- 'Mesh',
246
- 'QuadraticBezierLine',
247
- 'RoundedBox',
248
- 'ScreenQuad',
249
- 'AccumulativeShadows',
250
- 'Backdrop',
251
- 'BBAnchor',
252
- 'Bounds',
253
- 'CameraShake',
254
- 'Caustics',
255
- 'Center',
256
- 'Cloud',
257
- 'ContactShadows',
258
- 'Environment',
259
- 'Float',
260
- 'Lightformer',
261
- 'MatcapTexture',
262
- 'NormalTexture',
263
- 'RandomizedLight',
264
- 'Resize',
265
- 'ShadowAlpha',
266
- 'Shadow',
267
- 'Sky',
268
- 'Sparkles',
269
- 'SpotLightShadow',
270
- 'SpotLight',
271
- 'Stage',
272
- 'Stars',
273
- 'OrbitControls',
274
- ];
275
- /**
276
- * 支持的文件扩展名
277
- */
278
- exports.DEFAULT_VALID_EXTENSIONS = new Set(['.jsx']);
279
- /**
280
- * 默认配置
281
- */
282
- exports.DEFAULT_CONFIG = {
283
- validExtensions: exports.DEFAULT_VALID_EXTENSIONS,
284
- threeFiberElems: exports.threeFiberElems,
285
- dreiElems: exports.dreiElems,
286
- enableLogging: true,
287
- };
@@ -1,33 +0,0 @@
1
- import type { ArrayContext, CompilerStats } from '../types';
2
- /**
3
- * 判断是否需要给元素打标
4
- */
5
- export declare function shouldTagElement(elementName: string, threeFiberElems: string[], dreiElems: string[]): boolean;
6
- /**
7
- * 生成数据属性字符串
8
- */
9
- export declare function generateDataAttributes(relativePath: string, line: number, col: number, elementName: string, arrayContext?: ArrayContext | null): string;
10
- /**
11
- * 日志记录工具
12
- */
13
- export declare class Logger {
14
- private enableLogging;
15
- constructor(enableLogging?: boolean);
16
- log(message: string, ...args: any[]): void;
17
- error(message: string, ...args: any[]): void;
18
- }
19
- /**
20
- * 统计信息管理
21
- */
22
- export declare class StatsManager {
23
- private stats;
24
- constructor();
25
- incrementTotalFiles(): void;
26
- incrementProcessedFiles(): void;
27
- addElements(count: number): void;
28
- getStats(): CompilerStats;
29
- }
30
- /**
31
- * 检查文件是否应该被处理
32
- */
33
- export declare function shouldProcessFile(id: string, validExtensions: Set<string>): boolean;
@@ -1,79 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.StatsManager = exports.Logger = void 0;
7
- exports.shouldTagElement = shouldTagElement;
8
- exports.generateDataAttributes = generateDataAttributes;
9
- exports.shouldProcessFile = shouldProcessFile;
10
- const path_1 = __importDefault(require("path"));
11
- /**
12
- * 判断是否需要给元素打标
13
- */
14
- function shouldTagElement(elementName, threeFiberElems, dreiElems) {
15
- return !threeFiberElems.includes(elementName) && !dreiElems.includes(elementName);
16
- }
17
- /**
18
- * 生成数据属性字符串
19
- */
20
- function generateDataAttributes(relativePath, line, col, elementName, arrayContext) {
21
- const dataComponentId = `${relativePath}:${line}:${col}`;
22
- let arrayAttrs = '';
23
- if (arrayContext) {
24
- arrayAttrs = ` data-nocode-array="${arrayContext.arrayName}" data-nocode-index="\${${arrayContext.paramName}}"`;
25
- }
26
- return ` data-nocode-id="${dataComponentId}" data-nocode-name="${elementName}"${arrayAttrs}`;
27
- }
28
- /**
29
- * 日志记录工具
30
- */
31
- class Logger {
32
- enableLogging;
33
- constructor(enableLogging = true) {
34
- this.enableLogging = enableLogging;
35
- }
36
- log(message, ...args) {
37
- if (this.enableLogging) {
38
- console.log(`[nocode-compiler] ${message}`, ...args);
39
- }
40
- }
41
- error(message, ...args) {
42
- if (this.enableLogging) {
43
- console.error(`[nocode-compiler] ${message}`, ...args);
44
- }
45
- }
46
- }
47
- exports.Logger = Logger;
48
- /**
49
- * 统计信息管理
50
- */
51
- class StatsManager {
52
- stats;
53
- constructor() {
54
- this.stats = {
55
- totalFiles: 0,
56
- processedFiles: 0,
57
- totalElements: 0,
58
- };
59
- }
60
- incrementTotalFiles() {
61
- this.stats.totalFiles++;
62
- }
63
- incrementProcessedFiles() {
64
- this.stats.processedFiles++;
65
- }
66
- addElements(count) {
67
- this.stats.totalElements += count;
68
- }
69
- getStats() {
70
- return { ...this.stats };
71
- }
72
- }
73
- exports.StatsManager = StatsManager;
74
- /**
75
- * 检查文件是否应该被处理
76
- */
77
- function shouldProcessFile(id, validExtensions) {
78
- return validExtensions.has(path_1.default.extname(id)) && !id.includes('node_modules');
79
- }