@nbreak/sdk 0.1.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.
- package/LICENSE +34 -0
- package/README.md +3 -0
- package/bin/datascreen.js +14 -0
- package/dist/cjs/cli/index.cjs +823 -0
- package/dist/cjs/cli/index.cjs.map +1 -0
- package/dist/cjs/index.cjs +345 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/esm/cli/index.js +821 -0
- package/dist/esm/cli/index.js.map +1 -0
- package/dist/esm/index.js +279 -0
- package/dist/esm/index.js.map +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1,823 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
4
|
+
//#endregion
|
|
5
|
+
let _nbreak_shared = require("@nbreak/shared");
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region src/templates/component.js
|
|
8
|
+
var import___vite_browser_external = (/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
9
|
+
module.exports = {};
|
|
10
|
+
})))();
|
|
11
|
+
/**
|
|
12
|
+
* 组件扩展模板
|
|
13
|
+
*/
|
|
14
|
+
function componentTemplate(name) {
|
|
15
|
+
const componentName = name.replace(/[^a-zA-Z0-9]/g, "");
|
|
16
|
+
return {
|
|
17
|
+
"src/index.js": `import { defineComponentExtension } from '@nbreak/sdk';
|
|
18
|
+
import Component from './${componentName}.vue';
|
|
19
|
+
import schema from './schema.js';
|
|
20
|
+
import defaults from './defaults.js';
|
|
21
|
+
|
|
22
|
+
export default defineComponentExtension({
|
|
23
|
+
type: '${name}',
|
|
24
|
+
name: '${name}',
|
|
25
|
+
category: 'charts',
|
|
26
|
+
component: Component,
|
|
27
|
+
schema,
|
|
28
|
+
defaults,
|
|
29
|
+
tags: ['自定义'],
|
|
30
|
+
icon: 'AppstoreOutlined',
|
|
31
|
+
description: '${name} 自定义组件',
|
|
32
|
+
});
|
|
33
|
+
`,
|
|
34
|
+
[`src/${componentName}.vue`]: `<template>
|
|
35
|
+
<div class="${name}-container">
|
|
36
|
+
<h3>{{ title }}</h3>
|
|
37
|
+
<p>{{ content }}</p>
|
|
38
|
+
</div>
|
|
39
|
+
</template>
|
|
40
|
+
|
|
41
|
+
<script setup>
|
|
42
|
+
defineProps({
|
|
43
|
+
title: { type: String, default: '默认标题' },
|
|
44
|
+
content: { type: String, default: '默认内容' },
|
|
45
|
+
color: { type: String, default: '#1890ff' },
|
|
46
|
+
});
|
|
47
|
+
<\/script>
|
|
48
|
+
|
|
49
|
+
<style scoped>
|
|
50
|
+
.${name}-container {
|
|
51
|
+
padding: 16px;
|
|
52
|
+
border: 1px solid rgba(255,255,255,0.1);
|
|
53
|
+
border-radius: 8px;
|
|
54
|
+
}
|
|
55
|
+
</style>
|
|
56
|
+
`,
|
|
57
|
+
"src/schema.js": `export default [
|
|
58
|
+
{
|
|
59
|
+
key: 'title',
|
|
60
|
+
label: '标题',
|
|
61
|
+
type: 'text',
|
|
62
|
+
group: '基础',
|
|
63
|
+
default: '默认标题',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
key: 'content',
|
|
67
|
+
label: '内容',
|
|
68
|
+
type: 'textarea',
|
|
69
|
+
group: '基础',
|
|
70
|
+
default: '默认内容',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
key: 'color',
|
|
74
|
+
label: '主色',
|
|
75
|
+
type: 'color',
|
|
76
|
+
group: '样式',
|
|
77
|
+
default: '#1890ff',
|
|
78
|
+
},
|
|
79
|
+
];
|
|
80
|
+
`,
|
|
81
|
+
"src/defaults.js": `export default {
|
|
82
|
+
title: '默认标题',
|
|
83
|
+
content: '默认内容',
|
|
84
|
+
color: '#1890ff',
|
|
85
|
+
};
|
|
86
|
+
`
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
//#endregion
|
|
90
|
+
//#region src/templates/theme.js
|
|
91
|
+
/**
|
|
92
|
+
* 主题扩展模板
|
|
93
|
+
*/
|
|
94
|
+
function themeTemplate(name) {
|
|
95
|
+
return {
|
|
96
|
+
"src/index.js": `import { defineThemeExtension } from '@nbreak/sdk';
|
|
97
|
+
import tokens from './tokens.js';
|
|
98
|
+
|
|
99
|
+
export default defineThemeExtension({
|
|
100
|
+
id: '${name}',
|
|
101
|
+
name: '${name} 主题',
|
|
102
|
+
tokens,
|
|
103
|
+
isDark: true,
|
|
104
|
+
description: '${name} 自定义主题',
|
|
105
|
+
});
|
|
106
|
+
`,
|
|
107
|
+
"src/tokens.js": `export default {
|
|
108
|
+
'--ds-color-primary': '#1890ff',
|
|
109
|
+
'--ds-color-success': '#52c41a',
|
|
110
|
+
'--ds-color-warning': '#faad14',
|
|
111
|
+
'--ds-color-error': '#f5222d',
|
|
112
|
+
'--ds-color-text': 'rgba(255,255,255,0.85)',
|
|
113
|
+
'--ds-color-text-secondary': 'rgba(255,255,255,0.65)',
|
|
114
|
+
'--ds-color-bg': '#0a1628',
|
|
115
|
+
'--ds-color-bg-secondary': '#0d1f3c',
|
|
116
|
+
'--ds-color-border': 'rgba(255,255,255,0.1)',
|
|
117
|
+
'--ds-font-size-base': '14px',
|
|
118
|
+
'--ds-font-size-lg': '16px',
|
|
119
|
+
'--ds-font-size-sm': '12px',
|
|
120
|
+
'--ds-border-radius': '6px',
|
|
121
|
+
'--ds-spacing-base': '8px',
|
|
122
|
+
};
|
|
123
|
+
`
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
//#endregion
|
|
127
|
+
//#region src/templates/datasource.js
|
|
128
|
+
/**
|
|
129
|
+
* 数据源扩展模板
|
|
130
|
+
*/
|
|
131
|
+
function datasourceTemplate(name) {
|
|
132
|
+
return {
|
|
133
|
+
"src/index.js": `import { defineDataSourceExtension } from '@nbreak/sdk';
|
|
134
|
+
import configSchema from './schema.js';
|
|
135
|
+
import defaults from './defaults.js';
|
|
136
|
+
|
|
137
|
+
class ${pascalCase(name)}Adapter {
|
|
138
|
+
async fetchData(config) {
|
|
139
|
+
// TODO: 实现 ${name} 数据获取逻辑
|
|
140
|
+
// config 包含数据源配置项
|
|
141
|
+
// 返回 { data: any, meta?: { total, page } }
|
|
142
|
+
return {
|
|
143
|
+
data: [
|
|
144
|
+
{ label: '示例 A', value: 100 },
|
|
145
|
+
{ label: '示例 B', value: 200 },
|
|
146
|
+
],
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async subscribe(config, callback) {
|
|
151
|
+
// TODO: 实现实时数据订阅(如需要)
|
|
152
|
+
// 调用 callback(data) 推送数据
|
|
153
|
+
// 返回取消订阅函数
|
|
154
|
+
return () => {};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async test(config) {
|
|
158
|
+
// 测试连接是否可用
|
|
159
|
+
try {
|
|
160
|
+
await this.fetchData(config);
|
|
161
|
+
return { success: true, message: '连接成功' };
|
|
162
|
+
} catch (e) {
|
|
163
|
+
return { success: false, message: e.message };
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export default defineDataSourceExtension({
|
|
169
|
+
type: '${name}',
|
|
170
|
+
name: '${name} 数据源',
|
|
171
|
+
adapter: new ${pascalCase(name)}Adapter(),
|
|
172
|
+
configSchema,
|
|
173
|
+
defaults,
|
|
174
|
+
description: '${name} 自定义数据源',
|
|
175
|
+
});
|
|
176
|
+
`,
|
|
177
|
+
"src/schema.js": `export default [
|
|
178
|
+
{
|
|
179
|
+
key: 'url',
|
|
180
|
+
label: '接口地址',
|
|
181
|
+
type: 'text',
|
|
182
|
+
group: '基础',
|
|
183
|
+
default: 'https://api.example.com/data',
|
|
184
|
+
required: true,
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
key: 'method',
|
|
188
|
+
label: '请求方法',
|
|
189
|
+
type: 'select',
|
|
190
|
+
group: '基础',
|
|
191
|
+
default: 'GET',
|
|
192
|
+
options: [
|
|
193
|
+
{ label: 'GET', value: 'GET' },
|
|
194
|
+
{ label: 'POST', value: 'POST' },
|
|
195
|
+
],
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
key: 'headers',
|
|
199
|
+
label: '请求头',
|
|
200
|
+
type: 'json',
|
|
201
|
+
group: '高级',
|
|
202
|
+
default: {},
|
|
203
|
+
},
|
|
204
|
+
];
|
|
205
|
+
`,
|
|
206
|
+
"src/defaults.js": `export default {
|
|
207
|
+
url: 'https://api.example.com/data',
|
|
208
|
+
method: 'GET',
|
|
209
|
+
headers: {},
|
|
210
|
+
params: {},
|
|
211
|
+
};
|
|
212
|
+
`
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
function pascalCase(str) {
|
|
216
|
+
return str.replace(/(^|[^a-zA-Z0-9])([a-z])/g, (_, __, c) => c.toUpperCase());
|
|
217
|
+
}
|
|
218
|
+
//#endregion
|
|
219
|
+
//#region src/templates/template.js
|
|
220
|
+
/**
|
|
221
|
+
* 模板扩展模板
|
|
222
|
+
*/
|
|
223
|
+
function templateTemplate(name) {
|
|
224
|
+
return {
|
|
225
|
+
"src/index.js": `import { defineTemplateExtension } from '@nbreak/sdk';
|
|
226
|
+
import pages from './pages.js';
|
|
227
|
+
|
|
228
|
+
export default defineTemplateExtension({
|
|
229
|
+
id: '${name}',
|
|
230
|
+
name: '${name} 模板',
|
|
231
|
+
pages,
|
|
232
|
+
thumbnail: '',
|
|
233
|
+
canvasConfig: {
|
|
234
|
+
width: 1920,
|
|
235
|
+
height: 1080,
|
|
236
|
+
background: '#0a1628',
|
|
237
|
+
},
|
|
238
|
+
description: '${name} 自定义模板',
|
|
239
|
+
});
|
|
240
|
+
`,
|
|
241
|
+
"src/pages.js": `export default [
|
|
242
|
+
{
|
|
243
|
+
id: 'page-1',
|
|
244
|
+
name: '主页面',
|
|
245
|
+
components: [
|
|
246
|
+
{
|
|
247
|
+
id: 'comp-title',
|
|
248
|
+
type: 'text',
|
|
249
|
+
x: 0,
|
|
250
|
+
y: 0,
|
|
251
|
+
width: 1920,
|
|
252
|
+
height: 80,
|
|
253
|
+
props: {
|
|
254
|
+
content: '${name}',
|
|
255
|
+
fontSize: 32,
|
|
256
|
+
color: '#1890ff',
|
|
257
|
+
textAlign: 'center',
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
],
|
|
261
|
+
},
|
|
262
|
+
];
|
|
263
|
+
`
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
//#endregion
|
|
267
|
+
//#region src/templates/action.js
|
|
268
|
+
/**
|
|
269
|
+
* 动作扩展模板
|
|
270
|
+
*/
|
|
271
|
+
function actionTemplate(name) {
|
|
272
|
+
return {
|
|
273
|
+
"src/index.js": `import { defineActionExtension } from '@nbreak/sdk';
|
|
274
|
+
import schema from './schema.js';
|
|
275
|
+
|
|
276
|
+
async function handler(params, context) {
|
|
277
|
+
// params: 用户配置的动作参数
|
|
278
|
+
// context: { componentId, event, data, store, eventBus }
|
|
279
|
+
// TODO: 实现 ${name} 动作逻辑
|
|
280
|
+
|
|
281
|
+
console.log('[${name} Action]', { params, context });
|
|
282
|
+
|
|
283
|
+
// 示例:更新组件数据
|
|
284
|
+
if (context.componentId && params.targetData) {
|
|
285
|
+
context.eventBus.emit('component:updateData', {
|
|
286
|
+
componentId: context.componentId,
|
|
287
|
+
data: params.targetData,
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return { success: true };
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
export default defineActionExtension({
|
|
295
|
+
actionType: '${name}',
|
|
296
|
+
handler,
|
|
297
|
+
schema,
|
|
298
|
+
category: 'general',
|
|
299
|
+
description: '${name} 自定义动作',
|
|
300
|
+
});
|
|
301
|
+
`,
|
|
302
|
+
"src/schema.js": `export default [
|
|
303
|
+
{
|
|
304
|
+
key: 'targetData',
|
|
305
|
+
label: '目标数据',
|
|
306
|
+
type: 'json',
|
|
307
|
+
group: '参数',
|
|
308
|
+
default: {},
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
key: 'message',
|
|
312
|
+
label: '提示消息',
|
|
313
|
+
type: 'text',
|
|
314
|
+
group: '参数',
|
|
315
|
+
default: '',
|
|
316
|
+
},
|
|
317
|
+
];
|
|
318
|
+
`
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
//#endregion
|
|
322
|
+
//#region src/templates/propertyField.js
|
|
323
|
+
/**
|
|
324
|
+
* 属性字段扩展模板
|
|
325
|
+
*/
|
|
326
|
+
function propertyFieldTemplate(name) {
|
|
327
|
+
return {
|
|
328
|
+
"src/index.js": `import { definePropertyFieldExtension } from '@nbreak/sdk';
|
|
329
|
+
import Editor from './Editor.vue';
|
|
330
|
+
|
|
331
|
+
export default definePropertyFieldExtension({
|
|
332
|
+
fieldType: '${name}',
|
|
333
|
+
editor: Editor,
|
|
334
|
+
defaultValue: () => null,
|
|
335
|
+
serialize: (value) => value,
|
|
336
|
+
deserialize: (value) => value,
|
|
337
|
+
description: '${name} 自定义属性编辑器',
|
|
338
|
+
});
|
|
339
|
+
`,
|
|
340
|
+
"src/Editor.vue": `<template>
|
|
341
|
+
<div class="ds-field-${name}">
|
|
342
|
+
<input
|
|
343
|
+
:value="modelValue"
|
|
344
|
+
@input="$emit('update:modelValue', $event.target.value)"
|
|
345
|
+
:placeholder="placeholder"
|
|
346
|
+
class="ds-field-input"
|
|
347
|
+
/>
|
|
348
|
+
</div>
|
|
349
|
+
</template>
|
|
350
|
+
|
|
351
|
+
<script setup>
|
|
352
|
+
defineProps({
|
|
353
|
+
modelValue: { default: null },
|
|
354
|
+
field: { type: Object, default: () => ({}) },
|
|
355
|
+
placeholder: { type: String, default: '' },
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
defineEmits(['update:modelValue']);
|
|
359
|
+
<\/script>
|
|
360
|
+
|
|
361
|
+
<style scoped>
|
|
362
|
+
.ds-field-${name} {
|
|
363
|
+
width: 100%;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.ds-field-input {
|
|
367
|
+
width: 100%;
|
|
368
|
+
padding: 4px 8px;
|
|
369
|
+
border: 1px solid rgba(255,255,255,0.2);
|
|
370
|
+
border-radius: 4px;
|
|
371
|
+
background: rgba(0,0,0,0.2);
|
|
372
|
+
color: inherit;
|
|
373
|
+
font-size: 13px;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
.ds-field-input:focus {
|
|
377
|
+
outline: none;
|
|
378
|
+
border-color: #1890ff;
|
|
379
|
+
}
|
|
380
|
+
</style>
|
|
381
|
+
`
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
//#endregion
|
|
385
|
+
//#region src/templates/shared.js
|
|
386
|
+
/**
|
|
387
|
+
* 共享模板文件(所有扩展类型都有)
|
|
388
|
+
*/
|
|
389
|
+
function sharedFiles(name, type) {
|
|
390
|
+
const pkgName = name.startsWith("@") ? name : `datascreen-${type}-${name}`;
|
|
391
|
+
return {
|
|
392
|
+
"package.json": JSON.stringify({
|
|
393
|
+
name: pkgName,
|
|
394
|
+
version: "0.1.0",
|
|
395
|
+
description: `DataScreen ${type} extension: ${name}`,
|
|
396
|
+
type: "module",
|
|
397
|
+
main: "./dist/index.js",
|
|
398
|
+
module: "./dist/index.mjs",
|
|
399
|
+
types: "./dist/index.d.ts",
|
|
400
|
+
files: ["dist", "datascreen.extension.json"],
|
|
401
|
+
scripts: {
|
|
402
|
+
build: "vite build",
|
|
403
|
+
dev: "vite build --watch"
|
|
404
|
+
},
|
|
405
|
+
datascreen: {
|
|
406
|
+
type,
|
|
407
|
+
displayName: name
|
|
408
|
+
},
|
|
409
|
+
dependencies: { "@nbreak/sdk": "^0.1.0" },
|
|
410
|
+
peerDependencies: { "@nbreak/core": "^0.1.0" },
|
|
411
|
+
publishConfig: { access: "public" }
|
|
412
|
+
}, null, 2) + "\n",
|
|
413
|
+
"datascreen.extension.json": JSON.stringify({
|
|
414
|
+
name: pkgName,
|
|
415
|
+
version: "0.1.0",
|
|
416
|
+
type,
|
|
417
|
+
entry: "./dist/index.js",
|
|
418
|
+
module: "./dist/index.mjs",
|
|
419
|
+
types: "./dist/index.d.ts",
|
|
420
|
+
datascreenVersion: ">=0.1.0",
|
|
421
|
+
dependencies: { "@nbreak/core": "^0.1.0" },
|
|
422
|
+
displayName: name,
|
|
423
|
+
description: `DataScreen ${type} extension`
|
|
424
|
+
}, null, 2) + "\n",
|
|
425
|
+
"vite.config.js": `import { defineConfig } from 'vite';
|
|
426
|
+
|
|
427
|
+
export default defineConfig({
|
|
428
|
+
build: {
|
|
429
|
+
outDir: 'dist',
|
|
430
|
+
sourcemap: true,
|
|
431
|
+
target: 'es2020',
|
|
432
|
+
minify: false,
|
|
433
|
+
lib: {
|
|
434
|
+
entry: 'src/index.js',
|
|
435
|
+
formats: ['es', 'cjs'],
|
|
436
|
+
fileName: (format) => format === 'es' ? 'index.mjs' : 'index.js',
|
|
437
|
+
},
|
|
438
|
+
rollupOptions: {
|
|
439
|
+
external: ['@nbreak/sdk', '@nbreak/core', '@nbreak/shared', 'vue'],
|
|
440
|
+
output: { exports: 'named' },
|
|
441
|
+
},
|
|
442
|
+
},
|
|
443
|
+
});
|
|
444
|
+
`,
|
|
445
|
+
".gitignore": `node_modules/
|
|
446
|
+
dist/
|
|
447
|
+
*.tgz
|
|
448
|
+
.DS_Store
|
|
449
|
+
`,
|
|
450
|
+
"README.md": `# ${pkgName}
|
|
451
|
+
|
|
452
|
+
DataScreen ${type} extension: ${name}
|
|
453
|
+
|
|
454
|
+
## 开发
|
|
455
|
+
|
|
456
|
+
\`\`\`bash
|
|
457
|
+
pnpm install
|
|
458
|
+
pnpm build
|
|
459
|
+
\`\`\`
|
|
460
|
+
|
|
461
|
+
## 发布
|
|
462
|
+
|
|
463
|
+
\`\`\`bash
|
|
464
|
+
npm publish
|
|
465
|
+
\`\`\`
|
|
466
|
+
`
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
//#endregion
|
|
470
|
+
//#region src/templates/index.js
|
|
471
|
+
/**
|
|
472
|
+
* 扩展项目模板生成器
|
|
473
|
+
*
|
|
474
|
+
* 为 6 种扩展类型生成完整的项目脚手架
|
|
475
|
+
*/
|
|
476
|
+
var TEMPLATE_MAP = {
|
|
477
|
+
component: componentTemplate,
|
|
478
|
+
theme: themeTemplate,
|
|
479
|
+
datasource: datasourceTemplate,
|
|
480
|
+
template: templateTemplate,
|
|
481
|
+
action: actionTemplate,
|
|
482
|
+
"property-field": propertyFieldTemplate
|
|
483
|
+
};
|
|
484
|
+
/**
|
|
485
|
+
* 生成扩展项目模板
|
|
486
|
+
* @param {string} type - 扩展类型
|
|
487
|
+
* @param {string} name - 扩展名称
|
|
488
|
+
* @returns {Object} 文件路径到内容的映射
|
|
489
|
+
*/
|
|
490
|
+
function generateExtensionTemplate(type, name) {
|
|
491
|
+
const generator = TEMPLATE_MAP[type];
|
|
492
|
+
if (!generator) throw new Error(`未知扩展类型: ${type}`);
|
|
493
|
+
const specificFiles = generator(name);
|
|
494
|
+
return {
|
|
495
|
+
...sharedFiles(name, type),
|
|
496
|
+
...specificFiles
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
//#endregion
|
|
500
|
+
//#region src/cli/commands/init.js
|
|
501
|
+
/**
|
|
502
|
+
* datascreen init <type> <name> [path]
|
|
503
|
+
*
|
|
504
|
+
* 脚手架生成扩展项目
|
|
505
|
+
*/
|
|
506
|
+
function initCommand(args) {
|
|
507
|
+
const [type, name, targetPath] = args;
|
|
508
|
+
if (!type || !name) {
|
|
509
|
+
console.error("用法: datascreen init <type> <name> [path]");
|
|
510
|
+
console.error(`type 可选: ${_nbreak_shared.ALL_EXTENSION_TYPES.join(", ")}`);
|
|
511
|
+
process.exit(1);
|
|
512
|
+
}
|
|
513
|
+
if (!_nbreak_shared.ALL_EXTENSION_TYPES.includes(type)) {
|
|
514
|
+
console.error(`无效的扩展类型: ${type}`);
|
|
515
|
+
console.error(`可选类型: ${_nbreak_shared.ALL_EXTENSION_TYPES.join(", ")}`);
|
|
516
|
+
process.exit(1);
|
|
517
|
+
}
|
|
518
|
+
const target = (0, import___vite_browser_external.resolve)(process.cwd(), targetPath || name);
|
|
519
|
+
if ((0, import___vite_browser_external.existsSync)(target)) {
|
|
520
|
+
console.error(`目标目录已存在: ${target}`);
|
|
521
|
+
process.exit(1);
|
|
522
|
+
}
|
|
523
|
+
console.log(`正在生成 ${type} 扩展: ${name}`);
|
|
524
|
+
console.log(`目标目录: ${target}`);
|
|
525
|
+
const files = generateExtensionTemplate(type, name);
|
|
526
|
+
for (const [filePath, content] of Object.entries(files)) {
|
|
527
|
+
const fullPath = (0, import___vite_browser_external.join)(target, filePath);
|
|
528
|
+
const dir = (0, import___vite_browser_external.dirname)(fullPath);
|
|
529
|
+
if (!(0, import___vite_browser_external.existsSync)(dir)) (0, import___vite_browser_external.mkdirSync)(dir, { recursive: true });
|
|
530
|
+
(0, import___vite_browser_external.writeFileSync)(fullPath, content, "utf-8");
|
|
531
|
+
console.log(` 创建: ${filePath}`);
|
|
532
|
+
}
|
|
533
|
+
console.log("\n扩展项目已生成!");
|
|
534
|
+
console.log("\n后续步骤:");
|
|
535
|
+
console.log(` cd ${name}`);
|
|
536
|
+
console.log(` pnpm install`);
|
|
537
|
+
console.log(` pnpm build`);
|
|
538
|
+
console.log(` npm publish # 发布到 npm`);
|
|
539
|
+
}
|
|
540
|
+
//#endregion
|
|
541
|
+
//#region src/manifest-node.js
|
|
542
|
+
/**
|
|
543
|
+
* @nbreak/sdk - Node-only Manifest 工具
|
|
544
|
+
*
|
|
545
|
+
* 这些函数依赖 node:fs / node:path,只能在 Node 环境(CLI / 服务端)使用。
|
|
546
|
+
* 浏览器侧请使用 manifest.js 中的 checkCompatibility / generateManifestTemplate。
|
|
547
|
+
*
|
|
548
|
+
* 拆分原因:原本与浏览器安全函数混在 manifest.js 中,
|
|
549
|
+
* 顶层 `import 'node:fs'` 会被 Vite 静态打包并 externalize,
|
|
550
|
+
* 导致浏览器运行时抛出 "Module node:fs has been externalized for browser" 错误。
|
|
551
|
+
*/
|
|
552
|
+
/**
|
|
553
|
+
* 从文件读取 manifest
|
|
554
|
+
* @param {string} manifestPath - datascreen.extension.json 路径
|
|
555
|
+
* @returns {Object|null}
|
|
556
|
+
*/
|
|
557
|
+
function readManifest(manifestPath) {
|
|
558
|
+
const absPath = (0, import___vite_browser_external.resolve)(process.cwd(), manifestPath);
|
|
559
|
+
if (!(0, import___vite_browser_external.existsSync)(absPath)) return null;
|
|
560
|
+
try {
|
|
561
|
+
const content = (0, import___vite_browser_external.readFileSync)(absPath, "utf-8");
|
|
562
|
+
return JSON.parse(content);
|
|
563
|
+
} catch (e) {
|
|
564
|
+
console.error(`[DataScreen SDK] 读取 manifest 失败: ${manifestPath}`, e);
|
|
565
|
+
return null;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* 校验 manifest 文件
|
|
570
|
+
* @param {string} manifestPath
|
|
571
|
+
* @returns {{valid: boolean, errors: Array, warnings: Array, manifest: Object|null}}
|
|
572
|
+
*/
|
|
573
|
+
function validateManifestFile(manifestPath) {
|
|
574
|
+
const manifest = readManifest(manifestPath);
|
|
575
|
+
if (!manifest) return {
|
|
576
|
+
valid: false,
|
|
577
|
+
errors: [`无法读取 manifest 文件: ${manifestPath}`],
|
|
578
|
+
warnings: [],
|
|
579
|
+
manifest: null
|
|
580
|
+
};
|
|
581
|
+
return {
|
|
582
|
+
...(0, _nbreak_shared.validateManifest)(manifest),
|
|
583
|
+
manifest
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
//#endregion
|
|
587
|
+
//#region src/cli/commands/build.js
|
|
588
|
+
/**
|
|
589
|
+
* datascreen build [path]
|
|
590
|
+
*
|
|
591
|
+
* 构建扩展包
|
|
592
|
+
* 调用 Vite 库模式构建,自动注入 manifest
|
|
593
|
+
*/
|
|
594
|
+
function buildCommand(args) {
|
|
595
|
+
const [targetPath = "."] = args;
|
|
596
|
+
const cwd = (0, import___vite_browser_external.resolve)(process.cwd(), targetPath);
|
|
597
|
+
const manifestPath = join$2(cwd, "datascreen.extension.json");
|
|
598
|
+
if ((0, import___vite_browser_external.existsSync)(manifestPath)) {
|
|
599
|
+
console.log("校验 manifest...");
|
|
600
|
+
const result = validateManifestFile(manifestPath);
|
|
601
|
+
if (!result.valid) {
|
|
602
|
+
console.error("manifest 校验失败:");
|
|
603
|
+
result.errors.forEach((e) => console.error(` - ${e}`));
|
|
604
|
+
process.exit(1);
|
|
605
|
+
}
|
|
606
|
+
if (result.warnings.length > 0) {
|
|
607
|
+
console.warn("manifest 警告:");
|
|
608
|
+
result.warnings.forEach((w) => console.warn(` - ${w}`));
|
|
609
|
+
}
|
|
610
|
+
console.log("manifest 校验通过");
|
|
611
|
+
} else console.warn("未找到 datascreen.extension.json,跳过 manifest 校验");
|
|
612
|
+
if (!(0, import___vite_browser_external.existsSync)(join$2(cwd, "vite.config.js"))) {
|
|
613
|
+
console.error("未找到 vite.config.js,无法构建");
|
|
614
|
+
console.error("请确保在扩展项目根目录运行此命令,或使用 datascreen init 生成项目");
|
|
615
|
+
process.exit(1);
|
|
616
|
+
}
|
|
617
|
+
if (!(0, import___vite_browser_external.existsSync)(join$2(cwd, "package.json"))) {
|
|
618
|
+
console.error("未找到 package.json");
|
|
619
|
+
process.exit(1);
|
|
620
|
+
}
|
|
621
|
+
console.log("开始构建...");
|
|
622
|
+
const result = (0, import___vite_browser_external.spawnSync)("npx", ["vite", "build"], {
|
|
623
|
+
cwd,
|
|
624
|
+
stdio: "inherit",
|
|
625
|
+
shell: true
|
|
626
|
+
});
|
|
627
|
+
if (result.status !== 0) {
|
|
628
|
+
console.error("构建失败");
|
|
629
|
+
process.exit(result.status || 1);
|
|
630
|
+
}
|
|
631
|
+
console.log("构建成功!");
|
|
632
|
+
if ((0, import___vite_browser_external.existsSync)(manifestPath)) {
|
|
633
|
+
const manifest = JSON.parse((0, import___vite_browser_external.readFileSync)(manifestPath, "utf-8"));
|
|
634
|
+
console.log(`扩展: ${manifest.name}@${manifest.version} (${manifest.type})`);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
function join$2(...paths) {
|
|
638
|
+
return paths.reduce((acc, p) => acc + "/" + p).replace(/\/+/g, "/");
|
|
639
|
+
}
|
|
640
|
+
//#endregion
|
|
641
|
+
//#region src/cli/commands/pack.js
|
|
642
|
+
/**
|
|
643
|
+
* datascreen pack [path]
|
|
644
|
+
*
|
|
645
|
+
* 打包扩展为 npm tarball
|
|
646
|
+
*/
|
|
647
|
+
function packCommand(args) {
|
|
648
|
+
const [targetPath = "."] = args;
|
|
649
|
+
const cwd = (0, import___vite_browser_external.resolve)(process.cwd(), targetPath);
|
|
650
|
+
const manifestPath = join$1(cwd, "datascreen.extension.json");
|
|
651
|
+
if ((0, import___vite_browser_external.existsSync)(manifestPath)) {
|
|
652
|
+
console.log("校验 manifest...");
|
|
653
|
+
const result = validateManifestFile(manifestPath);
|
|
654
|
+
if (!result.valid) {
|
|
655
|
+
console.error("manifest 校验失败:");
|
|
656
|
+
result.errors.forEach((e) => console.error(` - ${e}`));
|
|
657
|
+
process.exit(1);
|
|
658
|
+
}
|
|
659
|
+
console.log("manifest 校验通过");
|
|
660
|
+
}
|
|
661
|
+
const distPath = join$1(cwd, "dist");
|
|
662
|
+
if (!(0, import___vite_browser_external.existsSync)(distPath)) {
|
|
663
|
+
console.error("未找到 dist 目录,请先运行 datascreen build");
|
|
664
|
+
process.exit(1);
|
|
665
|
+
}
|
|
666
|
+
if ((0, import___vite_browser_external.existsSync)(manifestPath)) {
|
|
667
|
+
const manifest = JSON.parse((0, import___vite_browser_external.readFileSync)(manifestPath, "utf-8"));
|
|
668
|
+
(0, import___vite_browser_external.writeFileSync)(join$1(distPath, "datascreen.extension.json"), JSON.stringify(manifest, null, 2), "utf-8");
|
|
669
|
+
console.log("已复制 manifest 到 dist");
|
|
670
|
+
}
|
|
671
|
+
console.log("打包中...");
|
|
672
|
+
const result = (0, import___vite_browser_external.spawnSync)("npm", ["pack"], {
|
|
673
|
+
cwd,
|
|
674
|
+
stdio: "inherit",
|
|
675
|
+
shell: true
|
|
676
|
+
});
|
|
677
|
+
if (result.status !== 0) {
|
|
678
|
+
console.error("打包失败");
|
|
679
|
+
process.exit(result.status || 1);
|
|
680
|
+
}
|
|
681
|
+
console.log("打包成功!");
|
|
682
|
+
console.log("生成文件: <name>-<version>.tgz");
|
|
683
|
+
console.log("发布到 npm: npm publish");
|
|
684
|
+
}
|
|
685
|
+
function join$1(...paths) {
|
|
686
|
+
return paths.reduce((acc, p) => acc + "/" + p).replace(/\/+/g, "/");
|
|
687
|
+
}
|
|
688
|
+
//#endregion
|
|
689
|
+
//#region src/cli/commands/list.js
|
|
690
|
+
/**
|
|
691
|
+
* datascreen list
|
|
692
|
+
*
|
|
693
|
+
* 列出当前项目的扩展信息
|
|
694
|
+
*/
|
|
695
|
+
function listCommand(args) {
|
|
696
|
+
const [targetPath = "."] = args;
|
|
697
|
+
const cwd = (0, import___vite_browser_external.resolve)(process.cwd(), targetPath);
|
|
698
|
+
const manifestPath = join(cwd, "datascreen.extension.json");
|
|
699
|
+
const pkgPath = join(cwd, "package.json");
|
|
700
|
+
let manifest = null;
|
|
701
|
+
let pkg = null;
|
|
702
|
+
if ((0, import___vite_browser_external.existsSync)(manifestPath)) manifest = JSON.parse((0, import___vite_browser_external.readFileSync)(manifestPath, "utf-8"));
|
|
703
|
+
if ((0, import___vite_browser_external.existsSync)(pkgPath)) pkg = JSON.parse((0, import___vite_browser_external.readFileSync)(pkgPath, "utf-8"));
|
|
704
|
+
if (!manifest && !pkg) {
|
|
705
|
+
console.error("未找到 datascreen.extension.json 或 package.json");
|
|
706
|
+
process.exit(1);
|
|
707
|
+
}
|
|
708
|
+
console.log("\n=== DataScreen 扩展信息 ===\n");
|
|
709
|
+
if (manifest) {
|
|
710
|
+
console.log(`名称: ${manifest.name}`);
|
|
711
|
+
console.log(`版本: ${manifest.version}`);
|
|
712
|
+
console.log(`类型: ${manifest.type}`);
|
|
713
|
+
console.log(`入口: ${manifest.entry}`);
|
|
714
|
+
console.log(`显示名: ${manifest.displayName || manifest.name}`);
|
|
715
|
+
console.log(`描述: ${manifest.description || "-"}`);
|
|
716
|
+
console.log(`兼容版本: ${manifest.datascreenVersion || "-"}`);
|
|
717
|
+
} else if (pkg) {
|
|
718
|
+
console.log(`包名: ${pkg.name}`);
|
|
719
|
+
console.log(`版本: ${pkg.version}`);
|
|
720
|
+
const ds = pkg.datascreen || {};
|
|
721
|
+
console.log(`类型: ${ds.type || "(未声明)"}`);
|
|
722
|
+
console.log(`入口: ${pkg.main || "-"}`);
|
|
723
|
+
}
|
|
724
|
+
const distPath = join(cwd, "dist");
|
|
725
|
+
if ((0, import___vite_browser_external.existsSync)(distPath)) {
|
|
726
|
+
const files = (0, import___vite_browser_external.readdirSync)(distPath);
|
|
727
|
+
console.log(`\n构建产物 (${distPath}):`);
|
|
728
|
+
files.forEach((f) => console.log(` - ${f}`));
|
|
729
|
+
} else console.log("\n(未构建,运行 datascreen build)");
|
|
730
|
+
}
|
|
731
|
+
function join(...paths) {
|
|
732
|
+
return paths.reduce((acc, p) => acc + "/" + p).replace(/\/+/g, "/");
|
|
733
|
+
}
|
|
734
|
+
//#endregion
|
|
735
|
+
//#region src/cli/commands/validate.js
|
|
736
|
+
/**
|
|
737
|
+
* datascreen validate [manifestPath]
|
|
738
|
+
*
|
|
739
|
+
* 校验 manifest 文件
|
|
740
|
+
*/
|
|
741
|
+
function validateCommand(args) {
|
|
742
|
+
const [manifestPath = "datascreen.extension.json"] = args;
|
|
743
|
+
console.log(`校验 manifest: ${manifestPath}`);
|
|
744
|
+
const result = validateManifestFile(manifestPath);
|
|
745
|
+
if (result.errors.length > 0) {
|
|
746
|
+
console.error("\n错误:");
|
|
747
|
+
result.errors.forEach((e) => console.error(` ✗ ${e}`));
|
|
748
|
+
}
|
|
749
|
+
if (result.warnings.length > 0) {
|
|
750
|
+
console.warn("\n警告:");
|
|
751
|
+
result.warnings.forEach((w) => console.warn(` ⚠ ${w}`));
|
|
752
|
+
}
|
|
753
|
+
if (result.valid) {
|
|
754
|
+
console.log("\n✓ manifest 校验通过");
|
|
755
|
+
if (result.manifest) {
|
|
756
|
+
console.log(` 名称: ${result.manifest.name}`);
|
|
757
|
+
console.log(` 版本: ${result.manifest.version}`);
|
|
758
|
+
console.log(` 类型: ${result.manifest.type}`);
|
|
759
|
+
}
|
|
760
|
+
process.exit(0);
|
|
761
|
+
} else {
|
|
762
|
+
console.log("\n✗ manifest 校验失败");
|
|
763
|
+
process.exit(1);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
//#endregion
|
|
767
|
+
//#region src/cli/index.js
|
|
768
|
+
/**
|
|
769
|
+
* DataScreen CLI 主入口
|
|
770
|
+
*/
|
|
771
|
+
var VERSION = "0.1.0";
|
|
772
|
+
var HELP_TEXT = `
|
|
773
|
+
DataScreen CLI v${VERSION}
|
|
774
|
+
|
|
775
|
+
用法:
|
|
776
|
+
datascreen <command> [options]
|
|
777
|
+
|
|
778
|
+
命令:
|
|
779
|
+
init <type> <name> [path] 生成扩展项目(type: component/theme/datasource/template/action/property-field)
|
|
780
|
+
build [path] 构建扩展包
|
|
781
|
+
pack [path] 打包为 npm tarball
|
|
782
|
+
list 列出当前项目的扩展
|
|
783
|
+
validate [manifestPath] 校验 manifest 文件
|
|
784
|
+
|
|
785
|
+
示例:
|
|
786
|
+
datascreen init component my-chart
|
|
787
|
+
datascreen init theme my-theme ./packages/my-theme
|
|
788
|
+
datascreen build
|
|
789
|
+
datascreen pack
|
|
790
|
+
datascreen validate ./datascreen.extension.json
|
|
791
|
+
|
|
792
|
+
选项:
|
|
793
|
+
-h, --help 显示帮助
|
|
794
|
+
-v, --version 显示版本
|
|
795
|
+
`;
|
|
796
|
+
function runCli(args) {
|
|
797
|
+
const [command, ...rest] = args;
|
|
798
|
+
if (!command || command === "-h" || command === "--help") {
|
|
799
|
+
console.log(HELP_TEXT);
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
if (command === "-v" || command === "--version") {
|
|
803
|
+
console.log(VERSION);
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
const handler = {
|
|
807
|
+
init: initCommand,
|
|
808
|
+
build: buildCommand,
|
|
809
|
+
pack: packCommand,
|
|
810
|
+
list: listCommand,
|
|
811
|
+
validate: validateCommand
|
|
812
|
+
}[command];
|
|
813
|
+
if (!handler) {
|
|
814
|
+
console.error(`未知命令: ${command}`);
|
|
815
|
+
console.log(HELP_TEXT);
|
|
816
|
+
process.exit(1);
|
|
817
|
+
}
|
|
818
|
+
handler(rest);
|
|
819
|
+
}
|
|
820
|
+
//#endregion
|
|
821
|
+
exports.runCli = runCli;
|
|
822
|
+
|
|
823
|
+
//# sourceMappingURL=index.cjs.map
|