@blocklet/pages-kit-block-studio 0.4.65 → 0.4.66
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/lib/cjs/constants/new-block-template/index.tsx +13 -4
- package/lib/cjs/middlewares/init-block-studio-router.js +194 -0
- package/lib/cjs/plugins/_theme.js +536 -3
- package/lib/cjs/plugins/vite-plugin-block-studio.js +2 -2
- package/lib/cjs/tsconfig.tsbuildinfo +1 -1
- package/lib/cjs/types/properties.js +2 -0
- package/lib/cjs/utils/block-props-utils.js +151 -0
- package/lib/cjs/utils/generate-wrapper-code.js +127 -345
- package/lib/cjs/utils/ts-morph-utils.js +255 -0
- package/lib/cjs/utils/zod-utils.js +314 -0
- package/lib/esm/constants/new-block-template/index.tsx +13 -4
- package/lib/esm/middlewares/init-block-studio-router.js +161 -0
- package/lib/esm/plugins/_theme.js +501 -3
- package/lib/esm/plugins/vite-plugin-block-studio.js +2 -2
- package/lib/esm/tsconfig.tsbuildinfo +1 -1
- package/lib/esm/types/properties.js +1 -0
- package/lib/esm/utils/block-props-utils.js +114 -0
- package/lib/esm/utils/generate-wrapper-code.js +123 -345
- package/lib/esm/utils/ts-morph-utils.js +217 -0
- package/lib/esm/utils/zod-utils.js +269 -0
- package/lib/types/constants/new-block-template/index.d.ts +13 -6
- package/lib/types/plugins/_theme.d.ts +5 -1
- package/lib/types/tsconfig.tsbuildinfo +1 -1
- package/lib/types/types/properties.d.ts +17 -0
- package/lib/types/utils/block-props-utils.d.ts +103 -0
- package/lib/types/utils/generate-wrapper-code.d.ts +24 -0
- package/lib/types/utils/ts-morph-utils.d.ts +24 -0
- package/lib/types/utils/zod-utils.d.ts +67 -0
- package/package.json +19 -3
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
|
-
export interface
|
|
3
|
+
export interface BlockProps {
|
|
4
|
+
/** @description id: gs1rn5jmxfvpxptx | type: string | visible: true */
|
|
4
5
|
title?: string;
|
|
5
|
-
|
|
6
|
+
/** @description id: 9ajrz12ik7esfk1z | type: string | visible: true */
|
|
6
7
|
description?: string;
|
|
8
|
+
/** @description id: 3ckcfvf6b7zyskk8 | type: url | visible: true */
|
|
9
|
+
logo?: {
|
|
10
|
+
url: string;
|
|
11
|
+
mediaKitUrl?: string;
|
|
12
|
+
width?: number;
|
|
13
|
+
height?: number;
|
|
14
|
+
};
|
|
15
|
+
/** @description id: x3lqht8ikble1itx | type: string | visible: false */
|
|
7
16
|
copyright?: string;
|
|
8
17
|
}
|
|
9
18
|
|
|
10
19
|
// default export
|
|
11
|
-
export default function HelloWorld({ title = 'Hello World', logo, description, copyright }:
|
|
20
|
+
export default function HelloWorld({ title = 'Hello World', logo, description, copyright }: BlockProps) {
|
|
12
21
|
return (
|
|
13
22
|
<div
|
|
14
23
|
style={{
|
|
@@ -52,7 +61,7 @@ export default function HelloWorld({ title = 'Hello World', logo, description, c
|
|
|
52
61
|
}
|
|
53
62
|
|
|
54
63
|
// export edit component
|
|
55
|
-
export const EditComponent: React.FC<
|
|
64
|
+
export const EditComponent: React.FC<BlockProps & { onChange?: (value: BlockProps) => void }> = ({
|
|
56
65
|
onChange,
|
|
57
66
|
...props
|
|
58
67
|
}) => {
|
|
@@ -1,17 +1,83 @@
|
|
|
1
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
|
+
})();
|
|
2
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
37
|
};
|
|
5
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
39
|
exports.initBlockStudioRouter = void 0;
|
|
40
|
+
/* eslint-disable */
|
|
7
41
|
const express_1 = require("express");
|
|
8
42
|
const fs_1 = __importDefault(require("fs"));
|
|
9
43
|
const lodash_1 = require("lodash");
|
|
10
44
|
const path_1 = __importDefault(require("path"));
|
|
45
|
+
const ts = __importStar(require("typescript"));
|
|
11
46
|
const constants_1 = require("../constants");
|
|
47
|
+
// 导入Zod相关工具
|
|
48
|
+
const block_props_utils_1 = require("../utils/block-props-utils");
|
|
12
49
|
const helper_1 = require("../utils/helper");
|
|
50
|
+
const zod_utils_1 = require("../utils/zod-utils");
|
|
13
51
|
exports.initBlockStudioRouter = (0, express_1.Router)();
|
|
14
52
|
const BINARY_EXTENSIONS = ['.png', '.jpg', '.jpeg', '.gif', '.webp', '.ico', '.svg'];
|
|
53
|
+
// 共享的请求验证和文件路径处理
|
|
54
|
+
const validateRequest = (req, res) => {
|
|
55
|
+
if (!helper_1.isDev) {
|
|
56
|
+
return { error: res.status(403).json({ error: 'Only available in development mode' }) };
|
|
57
|
+
}
|
|
58
|
+
const { componentPath } = req.body;
|
|
59
|
+
if (!componentPath) {
|
|
60
|
+
return { error: res.status(400).json({ error: 'Component path is required' }) };
|
|
61
|
+
}
|
|
62
|
+
if (!(0, helper_1.isPathSafe)(componentPath)) {
|
|
63
|
+
return { error: res.status(403).json({ error: 'Invalid component path' }) };
|
|
64
|
+
}
|
|
65
|
+
return { componentPath };
|
|
66
|
+
};
|
|
67
|
+
// 解析组件源文件
|
|
68
|
+
const parseComponentFile = (componentPath) => {
|
|
69
|
+
// 读取组件文件内容
|
|
70
|
+
const code = fs_1.default.readFileSync(componentPath, 'utf-8');
|
|
71
|
+
const sourceFile = ts.createSourceFile(componentPath, code, ts.ScriptTarget.Latest, true);
|
|
72
|
+
const metadataPath = path_1.default.join(path_1.default.dirname(componentPath), constants_1.METADATA_FILE_NAME);
|
|
73
|
+
const currentMetadata = (0, helper_1.initializeMetadata)(metadataPath);
|
|
74
|
+
return {
|
|
75
|
+
code,
|
|
76
|
+
sourceFile,
|
|
77
|
+
metadataPath,
|
|
78
|
+
currentMetadata,
|
|
79
|
+
};
|
|
80
|
+
};
|
|
15
81
|
exports.initBlockStudioRouter.get('/', async (req, res) => {
|
|
16
82
|
if (!helper_1.isDev) {
|
|
17
83
|
return res.status(403).json({ error: 'Only available in development mode' });
|
|
@@ -154,4 +220,132 @@ exports.initBlockStudioRouter.get('/all', async (req, res) => {
|
|
|
154
220
|
}
|
|
155
221
|
return res.json((0, lodash_1.keyBy)(allBlocksWithCode, 'id'));
|
|
156
222
|
});
|
|
223
|
+
// 统一的属性到接口转换端点 - 可以预览或生成
|
|
224
|
+
exports.initBlockStudioRouter.post('/properties-to-interface', async (req, res) => {
|
|
225
|
+
const write = req.body.write === true;
|
|
226
|
+
const validation = validateRequest(req, res);
|
|
227
|
+
if (validation.error)
|
|
228
|
+
return validation.error;
|
|
229
|
+
const { componentPath } = validation;
|
|
230
|
+
try {
|
|
231
|
+
// 检查文件是否存在
|
|
232
|
+
if (!fs_1.default.existsSync(componentPath)) {
|
|
233
|
+
return res.status(404).json({ success: false, error: 'Component file not found' });
|
|
234
|
+
}
|
|
235
|
+
// 解析源文件和元数据
|
|
236
|
+
const { code, sourceFile, metadataPath } = parseComponentFile(componentPath);
|
|
237
|
+
// 获取元数据
|
|
238
|
+
if (!fs_1.default.existsSync(metadataPath)) {
|
|
239
|
+
return res.status(404).json({ success: false, error: 'Metadata file not found' });
|
|
240
|
+
}
|
|
241
|
+
const metadata = JSON.parse(fs_1.default.readFileSync(metadataPath, 'utf-8'));
|
|
242
|
+
if (!metadata.properties) {
|
|
243
|
+
return res.status(400).json({ success: false, error: 'No properties found in metadata' });
|
|
244
|
+
}
|
|
245
|
+
// 查找接口位置
|
|
246
|
+
const { found, interfaceText, interfaceStart, interfaceEnd, leadingComments } = (0, block_props_utils_1.findBlockPropsInterface)(sourceFile);
|
|
247
|
+
if (!found) {
|
|
248
|
+
return res.status(404).json({ success: false, error: 'BlockProps interface not found in component file' });
|
|
249
|
+
}
|
|
250
|
+
try {
|
|
251
|
+
const zodSchema = (0, zod_utils_1.propertiesToZodSchema)(metadata.properties || {}, {
|
|
252
|
+
addZodDescribe: true,
|
|
253
|
+
});
|
|
254
|
+
const typeString = (0, zod_utils_1.zodSchemaToTypeString)(zodSchema, 'BlockProps');
|
|
255
|
+
// 创建最终的接口定义
|
|
256
|
+
const newInterface = `export interface BlockProps ${typeString}`;
|
|
257
|
+
// 如果请求要求写入文件
|
|
258
|
+
if (write) {
|
|
259
|
+
// 拼接新的代码
|
|
260
|
+
const updatedCode = code.substring(0, interfaceStart) + (leadingComments || '') + newInterface + code.substring(interfaceEnd);
|
|
261
|
+
// 写入更新后的文件
|
|
262
|
+
fs_1.default.writeFileSync(componentPath, updatedCode);
|
|
263
|
+
return res.json({
|
|
264
|
+
success: true,
|
|
265
|
+
message: 'TypeScript接口已成功从metadata生成并写入文件',
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
// 否则,只返回生成的接口内容,不写入文件
|
|
269
|
+
return res.json({
|
|
270
|
+
success: true,
|
|
271
|
+
currentInterface: interfaceText,
|
|
272
|
+
newInterface,
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
catch (conversionError) {
|
|
276
|
+
console.error('Failed to convert properties to interface:', conversionError);
|
|
277
|
+
return res.status(500).json({
|
|
278
|
+
success: false,
|
|
279
|
+
error: `Failed to convert properties to interface: ${conversionError.message}`,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
catch (error) {
|
|
284
|
+
console.error('Failed to generate interface:', error);
|
|
285
|
+
return res.status(500).json({
|
|
286
|
+
success: false,
|
|
287
|
+
error: `Failed to generate interface: ${error.message}`,
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
// 统一的接口到属性转换端点 - 可以预览或生成
|
|
292
|
+
exports.initBlockStudioRouter.post('/interface-to-properties', async (req, res) => {
|
|
293
|
+
const write = req.body.write === true;
|
|
294
|
+
const validation = validateRequest(req, res);
|
|
295
|
+
if (validation.error)
|
|
296
|
+
return validation.error;
|
|
297
|
+
const { componentPath } = validation;
|
|
298
|
+
try {
|
|
299
|
+
// 检查文件是否存在
|
|
300
|
+
if (!fs_1.default.existsSync(componentPath)) {
|
|
301
|
+
return res.status(404).json({ success: false, error: 'Component file not found' });
|
|
302
|
+
}
|
|
303
|
+
// 解析源文件
|
|
304
|
+
const { sourceFile, metadataPath, currentMetadata } = parseComponentFile(componentPath);
|
|
305
|
+
// 查找BlockProps接口
|
|
306
|
+
const { found, interfaceText } = (0, block_props_utils_1.findBlockPropsInterface)(sourceFile);
|
|
307
|
+
if (!found || !interfaceText) {
|
|
308
|
+
return res.status(404).json({ success: false, error: 'BlockProps interface not found or could not be parsed' });
|
|
309
|
+
}
|
|
310
|
+
try {
|
|
311
|
+
const newProperties = await (0, zod_utils_1.tsFileInterfaceToProperties)(componentPath, 'BlockProps', currentMetadata.properties || {});
|
|
312
|
+
// 如果请求要求写入文件
|
|
313
|
+
if (write) {
|
|
314
|
+
// 更新元数据
|
|
315
|
+
const newMetadata = {
|
|
316
|
+
...currentMetadata,
|
|
317
|
+
properties: newProperties,
|
|
318
|
+
updatedAt: new Date().toISOString(),
|
|
319
|
+
};
|
|
320
|
+
// 写入文件
|
|
321
|
+
fs_1.default.writeFileSync(metadataPath, JSON.stringify(newMetadata, null, 2));
|
|
322
|
+
return res.json({
|
|
323
|
+
success: true,
|
|
324
|
+
metadata: newMetadata,
|
|
325
|
+
message: 'Metadata 完全更新成功',
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
// 否则,只返回差异信息,不写入文件
|
|
329
|
+
return res.json({
|
|
330
|
+
success: true,
|
|
331
|
+
currentProperties: currentMetadata.properties || {},
|
|
332
|
+
newProperties,
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
catch (conversionError) {
|
|
336
|
+
console.error('Failed to convert interface to properties:', conversionError);
|
|
337
|
+
return res.status(500).json({
|
|
338
|
+
success: false,
|
|
339
|
+
error: `Failed to convert interface to properties: ${conversionError.message}`,
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
catch (error) {
|
|
344
|
+
console.error('Failed to generate metadata:', error);
|
|
345
|
+
return res.status(500).json({
|
|
346
|
+
success: false,
|
|
347
|
+
error: `Failed to generate metadata: ${error.message}`,
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
});
|
|
157
351
|
exports.default = exports.initBlockStudioRouter;
|