Skip to content

Commit

Permalink
feat(vue-dsl): add app generate code
Browse files Browse the repository at this point in the history
  • Loading branch information
chilingling committed Dec 21, 2023
1 parent 60a6a88 commit 5f8f87b
Show file tree
Hide file tree
Showing 16 changed files with 830 additions and 36 deletions.
118 changes: 118 additions & 0 deletions packages/vue-generator/src/generator/codeGenerator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
class CodeGenerator {
config = {}
genResult = []
plugins = []
genLogs = []
schema = {}
parsedSchema = {}
context = {}
constructor(config) {
this.config = config
this.plugins = config.plugins
}
getContext() {
return {
config: this.config,
genResult: this.genResult,
plugins: this.plugins,
genLogs: this.genLogs,
schema: this.schema,
parsedSchema: this.parsedSchema,
...this.context
}
}
getPluginsByHook(hookName) {
const res = []

for (const pluginItem of this.plugins) {
if (typeof pluginItem[hookName] === 'function') {
res.push(pluginItem[hookName])
}
}

return res
}
async generate(schema) {
const hooks = ['transformStart', 'parseConfig', 'parseSchema', 'transform', 'transformEnd']
let err = null

this.schema = schema

try {
for (const hookItem of hooks) {
const plugins = this.getPluginsByHook(hookItem)

await this[hookItem](plugins)
}
} catch (error) {
err = error
} finally {
const plugins = this.getPluginsByHook('transformEnd')
await this.transformEnd(plugins, err)
}

return {
genResult: this.genResult,
genLogs: this.genLogs
}
}
async transformStart(plugins) {
for (const pluginItem of plugins) {
await pluginItem.apply(this, [this.config])
}
}
async parseConfig(plugins) {
for (const pluginItem of plugins) {
const newConfig = await pluginItem.apply(this, [this.config])

if (newConfig) {
this.config = newConfig
}
}
}

async parseSchema(plugins) {
for (const pluginItem of plugins) {
const parseResult = await pluginItem.apply(this, [this.schema])

if (!parseResult?.id || !parseResult?.result) {
continue
}

this.parsedSchema[parseResult.id] = parseResult.result
}
}
async transform(plugins) {
for (const pluginItem of plugins) {
const transformRes = await pluginItem.apply(this, [this.parsedSchema])

if (!transformRes) {
return
}

if (Array.isArray(transformRes)) {
this.genResult.push(...transformRes)
} else {
this.genResult.push(transformRes)
}
}
}
async transformEnd(plugins, err) {
for (const pluginItem of plugins) {
await pluginItem.apply(this, [err])
}
}
replaceGenResult(resultItem) {
const { path, fileName } = resultItem

const index = this.genResult.findIndex((item) => item.path === path && item.fileName === fileName)

if (index === -1) {
return
}

this.genResult.splice(index, 1, resultItem)
}
}

export default CodeGenerator
128 changes: 102 additions & 26 deletions packages/vue-generator/src/generator/generateApp.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,116 @@
import { generateTemplate } from '../templates/vue-template'
import { generateTemplate as genDefaultStaticTemplate } from '../templates/vue-template'

Check failure on line 1 in packages/vue-generator/src/generator/generateApp.js

View workflow job for this annotation

GitHub Actions / push-check

'genDefaultStaticTemplate' is defined but never used
import {
genBlockPlugin,
genDataSourcePlugin,
genDependenciesPlugin,
genI18nPlugin,
genPagePlugin,
genRouterPlugin,
genTemplatePlugin,
genUtilsPlugin
} from '../plugins'
import CodeGenerator from './codeGenerator'

const templateMap = {
default: generateTemplate
const inputMock = {

Check failure on line 14 in packages/vue-generator/src/generator/generateApp.js

View workflow job for this annotation

GitHub Actions / push-check

'inputMock' is assigned a value but never used
// 应用相关配置信息
//config: {},
// 应用相关的 meta 信息
appMeta: {},
// 页面区块信息
componentsTree: [],
blockList: [],
// 数据源信息
dataSource: [],
// i18n 信息
i18n: {},
// utils 信息
utils: [],
// 全局状态
globalState: []
}

// function
// TODO 解析整个应用用到的区块
// 1. 解析页面中用到的区块
// 2. 解析区块中用到的区块

function generateI18n() {}

function generateDataSource() {}
const transformedSchema = {

Check failure on line 36 in packages/vue-generator/src/generator/generateApp.js

View workflow job for this annotation

GitHub Actions / push-check

'transformedSchema' is assigned a value but never used
// 整体应用 meta 信息
appMeta: {
name: 'test'
},
// 需要生成的页面
pageCode: [
{
// 类型是页面
// type: 'PAGE',
// 类型是区块
// type: 'BLOCK',
// 页面 meta 信息
meta: {},
// schema 信息,如果是 文件夹,则不需要
schema: {}
// ...
}
],
dataSource: {},
i18n: {},
routes: {},
utils: {},
globalState: [
{
actions: {},
getters: {},
id: '',
state: {}
}
]
}

function generatePageOrComponent() {}
// 预处理输入的 schema,转换为标准的格式
function transformSchema(appSchema) {

Check failure on line 70 in packages/vue-generator/src/generator/generateApp.js

View workflow job for this annotation

GitHub Actions / push-check

'transformSchema' is defined but never used
const { appMeta, pageCode, dataSource, i18n, utils, globalState } = appSchema

function generateRouter() {}
const routes = pageCode.map(({ meta: { isHome, router }, fileName }) => ({
fileName,
isHome,
path: router.startsWith('/') ? router : `/${router}`
}))

function generateDependencies() {}
const hasRoot = routes.some(({ path }) => path === '/')

/**
* 整体应用出码
*/
export function generateApp(config, appSchema) {
// 预处理 app schema
if (!hasRoot && routes.length) {
const { path: homePath } = routes.find(({ isHome }) => isHome) || { path: routes[0].path }

// 初始化模板
const { staticTemplate } = config
routes.unshift({ path: '/', redirect: homePath })
}

if (typeof staticTemplate === 'function') {
staticTemplate({})
return {
appMeta,
pageCode,
dataSource,
i18n,
utils,
globalState,
routes
}
}

// 国际化出码
/**
* 整体应用出码
*/
export async function generateApp(appSchema) {
const codeGenInstance = new CodeGenerator({
plugins: [
genBlockPlugin(),
genDataSourcePlugin(),
genDependenciesPlugin(),
genI18nPlugin(),
genPagePlugin(),
genRouterPlugin(),
genTemplatePlugin(),
genUtilsPlugin()
]
})

// 数据源出码
// 页面出码
// 区块出码
// utils 工具类出码
// 路由出码
// 依赖出码
return codeGenInstance.generate(appSchema)
}
20 changes: 10 additions & 10 deletions packages/vue-generator/src/generator/index.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
/**
* Copyright (c) 2023 - present TinyEngine Authors.
* Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd.
*
* Use of this source code is governed by an MIT-style license.
*
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
*
*/
* Copyright (c) 2023 - present TinyEngine Authors.
* Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd.
*
* Use of this source code is governed by an MIT-style license.
*
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
*
*/

import { generateCode, generateBlocksCode, generatePageCode } from './page'

Expand Down
57 changes: 57 additions & 0 deletions packages/vue-generator/src/plugins/genBlockPlugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { mergeOptions } from '../utils/mergeOptions'
import { generatePageCode } from '../generator/page'

const defaultOption = {
blockBasePath: './src/components'
}

function genBlockPlugin(options = {}) {
const realOptions = mergeOptions(defaultOption, options)

const { blockBasePath } = realOptions

return {
name: 'tinyengine-plugin-generatecode-block',
description: 'transform block schema to code',
parseSchema(schema) {
const { blockHistories } = schema
const blockSchema = blockHistories.map((block) => block?.content).filter((schema) => typeof schema === 'object')

return {
id: 'blocks',
result: blockSchema
}
},
transform(transformedSchema) {
const { blocks } = transformedSchema

const resBlocks = []

for (const block of blocks) {
const res = generatePageCode({
pageInfo: { schema: block, name: block.componentName },
componentsMap: this.schema.componentsMap
})

const { errors, ...restInfo } = res[0]

if (errors?.length > 0) {
this.genLogs.push(...errors)
continue
}

const { panelName, panelValue } = restInfo

resBlocks.push({
fileName: panelName,
path: blockBasePath,
fileContent: panelValue
})
}

return resBlocks
}
}
}

export default genBlockPlugin
52 changes: 52 additions & 0 deletions packages/vue-generator/src/plugins/genDataSourcePlugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { mergeOptions } from '../utils/mergeOptions'

const defaultOption = {
fileName: 'dataSource.json',
path: './src'
}

function genDataSourcePlugin(options = {}) {
const realOptions = mergeOptions(defaultOption, options)

const { path, fileName } = realOptions

return {
name: 'tinyengine-plugin-generatecode-datasource',
description: 'transform schema to dataSource plugin',
parseSchema(schema) {
return {
id: 'dataSource',
result: schema?.dataSource || {}
}
},
transform(transformedSchema) {
const dataSource = transformedSchema.dataSource

const { dataHandler, errorHandler, willFetch, list } = dataSource || {}

const data = {
list: list.map(({ id, name, data }) => ({ id, name, ...data }))
}

if (dataHandler) {
data.dataHandler = dataHandler
}

if (errorHandler) {
data.errorHandler = errorHandler
}

if (willFetch) {
data.willFetch = willFetch
}

return {
fileName,
path,
fileContent: JSON.stringify(data)
}
}
}
}

export default genDataSourcePlugin
Loading

0 comments on commit 5f8f87b

Please sign in to comment.