@lcap/builder
Version:
lcap builder utils
229 lines (226 loc) • 9.81 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateBlockFile = void 0;
/* eslint-disable quotes */
const parser = __importStar(require("@babel/parser"));
const traverse_1 = __importDefault(require("@babel/traverse"));
const generator_1 = __importDefault(require("@babel/generator"));
const fast_glob_1 = __importDefault(require("fast-glob"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const path_1 = __importDefault(require("path"));
const utils_1 = require("./utils");
const constants_1 = require("./constants");
function getBlockCodeFromData(context) {
let blocks = [{
code: `<${context.tagName}></${context.tagName}>`,
title: '基本用法',
}];
if (context.naslUIConfig.blocks && context.naslUIConfig.blocks.length > 0) {
blocks = [...context.naslUIConfig.blocks];
}
const blockCodes = blocks.map((block, i) => {
let code = (0, utils_1.replaceTagName)(block.code, context.naslUIConfig.kebabName, context.tagName).trim();
if (code.startsWith('<template>') && code.endsWith('</template>')) {
code = code.substring('<template>'.length, code.length - '</template>'.length).trim();
}
return [
`export const Block${i + 1} = {`,
` name: '${block.title || '基本用法'}',`,
' render: () => ({',
` template: \`${code}\`,`,
' }),',
'};',
].join('\n');
});
return `import Component from '../index';
export default {
id: '${context.tagName}-blocks',
title: '组件列表/${context.name}/内置区块',
component: Component,
parameters: {
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
layout: 'centered',
},
};
${blockCodes.join('\n\n')}
`;
}
function getBlockInfos(code, context) {
const ast = parser.parse(code, {
sourceType: 'module',
plugins: ['typescript', 'jsx'],
});
const blocks = [];
const waitImports = [];
(0, traverse_1.default)(ast, {
VariableDeclarator(bpath) {
const hasExporedName = bpath.findParent((p) => p.type === 'ExportNamedDeclaration');
if (!hasExporedName || !bpath.node.id || !bpath.node.init
|| bpath.node.id.type !== 'Identifier'
|| bpath.node.init.type !== 'ObjectExpression'
|| !bpath.node.init.properties
|| bpath.node.init.properties.length === 0) {
return;
}
const block = {
name: bpath.node.id.name,
ast: null,
};
bpath.traverse({
ObjectProperty: (p) => {
if (p.node.key && p.node.key.type === 'Identifier' && p.node.key.name === 'name' && p.node.value && p.node.value.type === 'StringLiteral') {
block.name = p.node.value.value;
p.skip();
}
},
JSXElement: (p) => {
const inRenderProps = p.findParent((parentPath) => parentPath.type === 'ObjectProperty' && parentPath.node.key && parentPath.node.key.name === 'render');
if (inRenderProps && ['ReturnStatement', 'ArrowFunctionExpression'].indexOf(p.parent.type) === -1) {
return;
}
block.ast = p.node;
p.skip();
},
});
blocks.push(block);
},
JSXElement(pt) {
if (pt.node.openingElement.name.type !== 'JSXIdentifier') {
return;
}
const tagName = pt.node.openingElement.name.name;
if (tagName === context.naslUIConfig.name) {
pt.node.openingElement.name.name = context.tagName;
if (pt.node.closingElement && pt.node.closingElement.name.type === 'JSXIdentifier') {
pt.node.closingElement.name.name = context.tagName;
}
}
else if (waitImports.indexOf(tagName) === -1
&& context.findNaslUIConfig(tagName)) {
waitImports.push(tagName);
}
},
});
return {
blocks,
waitImports,
};
}
function getBlockCodeFromFile(filePath, context) {
const tsCode = fs_extra_1.default.readFileSync(filePath, 'utf-8');
const { blocks, waitImports } = getBlockInfos(tsCode, context);
const BASE_STORIES_CODE = [
`import React from 'react';${waitImports.length > 0 ? `\nimport { ${waitImports.join(', ')} } from '${constants_1.LCAP_UI_PACKAGE_NAME}';` : ''}`,
`import ${context.name} from '../index';`,
`export default {`,
` id: '${context.name}-Blocks',`,
` title: '组件列表/${context.name}/内置区块',`,
` component: ${context.name},`,
` parameters: {`,
` layout: 'centered',`,
` },`,
`};`,
'',
].join('\n');
const baseAST = parser.parse(BASE_STORIES_CODE, {
sourceType: 'module',
plugins: ['typescript', 'jsx'],
});
baseAST.program.body.push(...blocks.map((block, i) => {
return {
type: 'ExportNamedDeclaration',
specifiers: [],
declaration: {
type: 'VariableDeclaration',
kind: 'const',
declarations: [{
type: 'VariableDeclarator',
id: {
type: 'Identifier',
name: `Block${i + 1}`,
},
init: {
type: 'ObjectExpression',
properties: [{
type: 'ObjectProperty',
key: {
type: 'Identifier',
name: 'name',
},
value: {
type: 'StringLiteral',
value: block.name,
extra: {
rawValue: block.name,
raw: `'${block.name}'`,
},
},
shorthand: false,
computed: false,
}, {
type: 'ObjectProperty',
key: {
type: 'Identifier',
name: 'render',
},
value: {
type: 'ArrowFunctionExpression',
generator: false,
async: false,
params: [],
body: block.ast,
},
shorthand: false,
computed: false,
}],
},
}],
},
};
}));
return (0, generator_1.default)(baseAST).code;
}
function generateBlockFile(context) {
if (['vue2', 'vue3'].includes(context.framework)) {
const content = getBlockCodeFromData(context);
fs_extra_1.default.writeFileSync(path_1.default.resolve(context.componentFolderPath, 'stories/block.stories.js'), (0, utils_1.replaceAllTagName)(content, context.replaceTagMap), 'utf-8');
return;
}
const storyFilePath = fast_glob_1.default.sync('stories/block.stories.{tsx,jsx}', { cwd: context.pkgComponentFolderPath, absolute: true })[0];
if (!storyFilePath) {
return;
}
const content = getBlockCodeFromFile(storyFilePath, context);
const tsxFilePath = path_1.default.resolve(context.componentFolderPath, 'stories/block.stories.tsx');
if (fs_extra_1.default.existsSync(tsxFilePath)) {
fs_extra_1.default.unlinkSync(tsxFilePath);
}
fs_extra_1.default.writeFileSync(path_1.default.resolve(context.componentFolderPath, 'stories/block.stories.jsx'), content, 'utf-8');
}
exports.generateBlockFile = generateBlockFile;