├── .jshintrc
├── .gitignore
├── src
├── template.xtpl
├── core
│ ├── exportGlobalCss.ts
│ ├── interface.ts
│ ├── consts.ts
│ ├── exportCreateApp.ts
│ ├── entry.ts
│ ├── exportBlock.ts
│ └── utils.ts
└── entry_back.js
├── schema.md
├── webpack.config.js
├── tsconfig.json
├── README.zh-CN.md
├── package.json
├── README.md
├── code
├── style.js
├── style.responsive.js
├── style.less
├── index.jsx
├── result.js
├── style.css
└── style.responsive.css
├── test
├── index.js
├── react.test.js
├── data.js
└── animation.js
└── dist
└── main.js
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esversion": 6
3 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | npm-debug.log
3 | .idea/
4 | .vscode
5 | /test/template.*
6 | codeExample
7 | demo
8 | demo-ts
9 | dist/
10 | coverage
11 | .nyc_output
--------------------------------------------------------------------------------
/src/template.xtpl:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React, { Component } from 'react';
4 |
5 | {{{imports}}}
6 |
7 | {{{utils}}}
8 |
9 | {{{style}}}
10 |
11 | {{{classes}}}
12 |
13 | {{{exports}}}
14 |
--------------------------------------------------------------------------------
/schema.md:
--------------------------------------------------------------------------------
1 | ## D2C Schema
2 |
3 | * [D2C Schema 介绍](https://www.imgcook.com/docs?slug=d2c-json-info)
4 | * [D2C Schema TS 描述](https://www.imgcook.com/docs?slug=d2c-schema-ts)
5 | * [D2C Schema Demo](https://www.imgcook.com/docs?slug=d2c-schema-demo)
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | watch: false,
5 | // entry: './src/entry.js',
6 | entry: './src/core/entry.ts',
7 | resolve: {
8 | extensions: ['.tsx', '.ts', '.js'],
9 | },
10 | module: {
11 | rules: [
12 | {
13 | test: /\.tsx?$/,
14 | use:'ts-loader',
15 | exclude: /node_modules/,
16 | },
17 |
18 | ]
19 | },
20 | output: {
21 | filename: 'index.js',
22 | path: path.resolve(__dirname, 'src'),
23 | libraryTarget: 'commonjs2',
24 | }
25 | };
--------------------------------------------------------------------------------
/src/core/exportGlobalCss.ts:
--------------------------------------------------------------------------------
1 | import { IPanelDisplay } from './interface';
2 | const { CSS_TYPE, prettierCssOpt } = require('./consts');
3 |
4 | export default function exportGlobalCss(schema, option): IPanelDisplay[] {
5 | const {
6 | prettier,
7 | dslConfig,
8 | _,
9 | folder = ''
10 | } = option;
11 |
12 | // 只有一个模块时,生成到当前模块
13 | if (dslConfig.globalCss && dslConfig.inlineStyle !== CSS_TYPE.INLINE_CSS) {
14 | return [
15 | {
16 | panelName: `global.css`,
17 | panelValue: prettier.format(schema.css || '', prettierCssOpt),
18 | panelType: 'css',
19 | folder: folder,
20 | },
21 | ];
22 | } else {
23 | return [];
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2017",
4 | "module": "commonjs",
5 | "jsx": "preserve",
6 | "declaration": true,
7 | "outDir": "./dist",
8 | "strict": true,
9 | "noImplicitAny": false,
10 | "moduleResolution": "node",
11 | "allowSyntheticDefaultImports": true,
12 | "esModuleInterop": true,
13 | "resolveJsonModule": true,
14 | "experimentalDecorators": true,
15 | "emitDecoratorMetadata": true,
16 | "noImplicitThis": true,
17 | "noUnusedLocals": false,
18 | "stripInternal": true,
19 | "pretty": true,
20 | "lib": [
21 | "es2017",
22 | "dom"
23 | ]
24 | },
25 | "include": [
26 | "./src"
27 | ],
28 | "exclude": [
29 | "node_modules"
30 | ]
31 | }
--------------------------------------------------------------------------------
/src/core/interface.ts:
--------------------------------------------------------------------------------
1 |
2 | export interface IPanelDisplay {
3 | panelName: string;
4 | panelValue: string;
5 | panelType: string;
6 | folder?: string;
7 | panelDependencies?: IDependence[]
8 | }
9 |
10 | export interface IImport {
11 | _import: string;
12 | package: string;
13 | version: string;
14 | }
15 |
16 | export interface IDependence {
17 | package: string;
18 | version: string;
19 | }
20 |
21 |
22 | export interface IDslConfig {
23 | responseWidth: number;
24 | scale: number;
25 | globalCss: boolean;
26 | componentStyle: 'components' | 'hooks';
27 | cssUnit: 'px' | 'vw' | 'rpx' | 'rem';
28 | inlineStyle: 'import' | 'module' | 'inline' | 'module_style';
29 | outputStyle: 'project' | 'component';
30 | cssStyle: 'kebabCase' | 'camelCase' | 'snakeCase',
31 | htmlFontSize: number
32 | }
--------------------------------------------------------------------------------
/README.zh-CN.md:
--------------------------------------------------------------------------------
1 | 简体中文 | [English](https://github.com/imgcook-dsl/react-standard/blob/master/README.md)
2 |
3 | ## 概述
4 |
5 | 为了让开发者能够在 imgcook 平台还原生成满足自己诉求的代码,我们提供了开放的 DSL 机制,在这套开放体系下,开发者可以根据 imgcook 提供的数据和能力生成自己所需的代码,不再局限于官方所提供的代码。
6 |
7 |
8 | ## 如何使用
9 |
10 | ### 选择 DSL 代码生成
11 |
12 | DSL 使用方式是在[编辑器](https://www.imgcook.com/editor#/)中点击「生成代码」按钮选择的 DSL 列表默认加载 DSL 官方提供的和自己定义的如图。
13 |
14 |
15 |
16 |
17 | ### 使用第三方 DSL
18 |
19 | 如果要使用其他开发者开发的 DSL 需要去 [DSL 广场](https://www.imgcook.com/dsl)收藏(如图),收藏后会在生成代码 DSL 选择列表中出现。
20 |
21 |
22 |
23 |
24 | ## 如何开发
25 |
26 | 参考开发文档:https://www.imgcook.com/docs?slug=dsl-dev
27 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-standard",
3 | "version": "1.0.0",
4 | "devDependencies": {
5 | "@babel/preset-env": "^7.7.7",
6 | "@babel/preset-stage-0": "^7.0.0",
7 | "@imgcook/dsl-helper": "0.0.1-alpha.0",
8 | "@types/node": "^16.11.7",
9 | "chai": "^4.3.4",
10 | "co": "^4.6.0",
11 | "css": "^3.0.0",
12 | "fs-extra": "^8.0.1",
13 | "lodash": "^4.17.11",
14 | "mocha": "^9.1.3",
15 | "nyc": "^15.1.0",
16 | "prettier": "^2.4.1",
17 | "thunkify": "^2.1.2",
18 | "ts-loader": "^8.2.0",
19 | "typescript": "^4.4.4",
20 | "vm2": "^3.5.2",
21 | "webpack": "^4.41.5",
22 | "webpack-cli": "^3.3.10",
23 | "xml-beautifier": "^0.4.0",
24 | "xtemplate": "^4.6.1",
25 | "xtpl": "^3.4.0"
26 | },
27 | "scripts": {
28 | "debug": "npx webpack --config webpack.config.js --mode=development",
29 | "build": "npx webpack --config webpack.config.js --mode=production",
30 | "demo": "node ./test/index.js",
31 | "test": "mocha --colors test/**/*.test.js",
32 | "start": "node ./test/index.js",
33 | "test-with-coverage": "nyc --reporter=html mocha --exit --colors test/**/*.test.js "
34 | },
35 | "dependencies": {}
36 | }
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | English | [简体中文](https://github.com/imgcook-dsl/react-standard/blob/master/README.zh-CN.md)
2 |
3 | ## Abstract
4 |
5 | To provide a better experience for users who use imgcook to generate codes on multiple platforms, we provide Open DSL System (open domain-specific language system) that transcodes imgcook schema to any programming languages you love. The developers can use default DSLs provided imgcook (React, React Hooks, Rax, etc.) or submit there own DSLs to generate customized codes.
6 |
7 | ## Usage
8 |
9 | ### Select a DSL for code generation
10 |
11 | In the imgcook editor, you can select a DSL for your project in the「code generation」panel. After that, we will generate your desired codes in the format of the language you chose.
12 |
13 | 
14 |
15 |
16 | ### Use a third-party DSL
17 |
18 | If you do not want to use the official DSL provided by imgcook. You can go to the [DSL Market](https://www.imgcook.com/dsl) to add the third-party DSLs to your own DSL list.
19 |
20 | 
21 |
22 |
23 | ## How to make your own DSL
24 |
25 | Please refer to the DSL development part: https://www.imgcook.com/docs?slug=dsl-dev
26 |
--------------------------------------------------------------------------------
/src/core/consts.ts:
--------------------------------------------------------------------------------
1 | import { IPanelDisplay, IDslConfig } from './interface';
2 | export const prettierJsOpt = {
3 | parser: 'babel',
4 | printWidth: 120,
5 | singleQuote: true,
6 | };
7 | export const prettierCssOpt = {
8 | parser: 'css',
9 | };
10 |
11 | export const prettierJsonOpt = {
12 | parser: 'json',
13 | };
14 |
15 | export const prettierScssOpt = {
16 | parser: 'scss',
17 | tabWidth: 2,
18 | printWidth: 120,
19 | singleQuote: true
20 | };
21 |
22 | export const prettierLessOpt = {
23 | parser: 'less',
24 | tabWidth: 2,
25 | printWidth: 120,
26 | singleQuote: true
27 | };
28 |
29 | export const prettierHtmlOpt = {
30 | parser: 'html',
31 | printWidth: 120,
32 | singleQuote: true
33 | };
34 |
35 |
36 | export const CSS_TYPE = {
37 | MODULE_CLASS: 'module',
38 | MODULE_STYLE: 'module_style',
39 | IMPORT_CLASS: 'import',
40 | INLINE_CSS: 'inline',
41 | }
42 |
43 | export const COMPONENT_TYPE = {
44 | HOOKS: 'hooks',
45 | COMPONENT: 'component',
46 | }
47 |
48 | export const OUTPUT_TYPE = {
49 | PROJECT: 'project',
50 | COMPONENT: 'component',
51 | }
52 |
53 |
54 | // 记录全局参数配置,初始化时直接修改
55 | export let DSL_CONFIG: IDslConfig = {
56 | responseWidth: 750,
57 | scale: 1,
58 | globalCss: false,
59 | cssUnit: 'px',
60 | componentStyle: 'hooks',
61 | inlineStyle: 'module',
62 | outputStyle: 'component',
63 | cssStyle: 'camelCase',
64 | htmlFontSize: 16
65 | };
66 |
67 |
68 | export const initConfig = (cfg)=>{
69 | DSL_CONFIG = Object.assign(DSL_CONFIG, cfg)
70 | }
71 |
72 |
73 |
74 |
75 | export const defaultGlobalCss = `/**
76 | * 全局样式 global.css
77 | */
78 | .flex-row {
79 | display: flex;
80 | flex-direction: row;
81 | }
82 |
83 | .flex-col {
84 | display: flex;
85 | flex-direction: column;
86 | }
87 |
88 | .justify-start {
89 | display: flex;
90 | justify-content: flex-start;
91 | }
92 |
93 | .justify-center {
94 | display: flex;
95 | justify-content: center;
96 | }
97 |
98 | .justify-end {
99 | display: flex;
100 | justify-content: flex-end;
101 | }
102 |
103 | .justify-between {
104 | display: flex;
105 | justify-content: space-between;
106 | }
107 |
108 | .items-start {
109 | display: flex;
110 | align-items: flex-start;
111 | }
112 |
113 | .items-center {
114 | display: flex;
115 | align-items: center;
116 | }
117 |
118 | .items-end {
119 | display: flex;
120 | align-items: flex-end;
121 | }
122 |
123 | `
--------------------------------------------------------------------------------
/code/style.js:
--------------------------------------------------------------------------------
1 | export default {
2 | box: {
3 | display: 'flex',
4 | flexDirection: 'row',
5 | justifyContent: 'space-around',
6 | alignItems: 'flex-start',
7 | height: '534px'
8 | },
9 | bd: {
10 | display: 'flex',
11 | position: 'relative',
12 | alignItems: 'flex-start',
13 | flexDirection: 'row',
14 | opacity: '1.00',
15 | width: '342px',
16 | height: '342px'
17 | },
18 | layer: { position: 'absolute', top: '0px', left: '0px', width: '342px', height: '342px', overflow: 'hidden' },
19 | bg: { position: 'absolute', top: '0px', left: '0px', opacity: '1.00', width: '342px', height: '342px' },
20 | wrap: {
21 | boxSizing: 'border-box',
22 | display: 'flex',
23 | position: 'relative',
24 | alignItems: 'center',
25 | flexDirection: 'row',
26 | marginTop: '18px',
27 | marginLeft: '18px',
28 | borderRadius: '15px',
29 | backgroundColor: 'rgba(0,0,0,0.40)',
30 | paddingRight: '9px',
31 | paddingLeft: '10px',
32 | height: '30px'
33 | },
34 | riverdinwei: { opacity: '1.00', width: '14px', height: '18px' },
35 | distance: {
36 | marginLeft: '4px',
37 | height: '22px',
38 | fontWeight: 400,
39 | fontSize: '18px',
40 | color: '#ffffff',
41 | lineHeight: '22px',
42 | whiteSpace: 'nowrap'
43 | },
44 | main: {
45 | display: 'flex',
46 | alignItems: 'flex-start',
47 | flexDirection: 'row',
48 | justifyContent: 'center',
49 | backgroundColor: '#ffffff',
50 | width: '342px',
51 | height: '114px'
52 | },
53 | title: {
54 | marginTop: '22px',
55 | width: '300px',
56 | height: '88px',
57 | fontWeight: 400,
58 | fontSize: '30px',
59 | color: '#333333',
60 | lineHeight: '44px',
61 | overflow: 'hidden',
62 | textOverflow: 'ellipsis'
63 | },
64 | ft: {
65 | boxSizing: 'border-box',
66 | display: 'flex',
67 | alignItems: 'center',
68 | flexDirection: 'row',
69 | justifyContent: 'space-between',
70 | borderBottomLeftRadius: '12px',
71 | borderBottomRightRadius: '12px',
72 | backgroundColor: '#ffffff',
73 | paddingRight: '17px',
74 | paddingLeft: '18px',
75 | width: '342px',
76 | height: '78px',
77 | overflow: 'hidden'
78 | },
79 | block: { display: 'flex', alignItems: 'center', flexDirection: 'row', height: '30px' },
80 | xianjin: { width: '30px', height: '30px' },
81 | fashionHome: {
82 | marginLeft: '6px',
83 | height: '28px',
84 | fontWeight: 300,
85 | fontSize: '24px',
86 | color: '#666666',
87 | lineHeight: '28px',
88 | whiteSpace: 'nowrap'
89 | },
90 | group: { display: 'flex', alignItems: 'center', flexDirection: 'row', height: '30px' },
91 | favorite: { width: '22px', height: '22px' },
92 | num: {
93 | marginLeft: '5px',
94 | height: '26px',
95 | fontWeight: 400,
96 | fontSize: '22px',
97 | color: '#999999',
98 | lineHeight: '26px',
99 | whiteSpace: 'nowrap'
100 | }
101 | };
102 |
--------------------------------------------------------------------------------
/code/style.responsive.js:
--------------------------------------------------------------------------------
1 | export default {
2 | box: {
3 | display: 'flex',
4 | flexDirection: 'row',
5 | justifyContent: 'space-around',
6 | alignItems: 'flex-start',
7 | height: '71.20vw'
8 | },
9 | bd: {
10 | display: 'flex',
11 | position: 'relative',
12 | alignItems: 'flex-start',
13 | flexDirection: 'row',
14 | opacity: '1.00',
15 | width: '45.60vw',
16 | height: '45.60vw'
17 | },
18 | layer: {
19 | position: 'absolute',
20 | top: '0.00vw',
21 | left: '0.00vw',
22 | width: '45.60vw',
23 | height: '45.60vw',
24 | overflow: 'hidden'
25 | },
26 | bg: { position: 'absolute', top: '0.00vw', left: '0.00vw', opacity: '1.00', width: '45.60vw', height: '45.60vw' },
27 | wrap: {
28 | boxSizing: 'border-box',
29 | display: 'flex',
30 | position: 'relative',
31 | alignItems: 'center',
32 | flexDirection: 'row',
33 | marginTop: '2.40vw',
34 | marginLeft: '2.40vw',
35 | borderRadius: '2.00vw',
36 | backgroundColor: 'rgba(0,0,0,0.40)',
37 | paddingRight: '1.20vw',
38 | paddingLeft: '1.33vw',
39 | height: '4.00vw'
40 | },
41 | riverdinwei: { opacity: '1.00', width: '1.87vw', height: '2.40vw' },
42 | distance: {
43 | marginLeft: '0.53vw',
44 | height: '2.93vw',
45 | fontWeight: 400,
46 | fontSize: '2.40vw',
47 | color: '#ffffff',
48 | lineHeight: '2.93vw',
49 | whiteSpace: 'nowrap'
50 | },
51 | main: {
52 | display: 'flex',
53 | alignItems: 'flex-start',
54 | flexDirection: 'row',
55 | justifyContent: 'center',
56 | backgroundColor: '#ffffff',
57 | width: '45.60vw',
58 | height: '15.20vw'
59 | },
60 | title: {
61 | marginTop: '2.93vw',
62 | width: '40.00vw',
63 | height: '11.73vw',
64 | fontWeight: 400,
65 | fontSize: '4.00vw',
66 | color: '#333333',
67 | lineHeight: '5.87vw',
68 | overflow: 'hidden',
69 | textOverflow: 'ellipsis'
70 | },
71 | ft: {
72 | boxSizing: 'border-box',
73 | display: 'flex',
74 | alignItems: 'center',
75 | flexDirection: 'row',
76 | justifyContent: 'space-between',
77 | borderBottomLeftRadius: '1.60vw',
78 | borderBottomRightRadius: '1.60vw',
79 | backgroundColor: '#ffffff',
80 | paddingRight: '2.27vw',
81 | paddingLeft: '2.40vw',
82 | width: '45.60vw',
83 | height: '10.40vw',
84 | overflow: 'hidden'
85 | },
86 | block: { display: 'flex', alignItems: 'center', flexDirection: 'row', height: '4.00vw' },
87 | xianjin: { width: '4.00vw', height: '4.00vw' },
88 | fashionHome: {
89 | marginLeft: '0.80vw',
90 | height: '3.73vw',
91 | fontWeight: 300,
92 | fontSize: '3.20vw',
93 | color: '#666666',
94 | lineHeight: '3.73vw',
95 | whiteSpace: 'nowrap'
96 | },
97 | group: { display: 'flex', alignItems: 'center', flexDirection: 'row', height: '4.00vw' },
98 | favorite: { width: '2.93vw', height: '2.93vw' },
99 | num: {
100 | marginLeft: '0.67vw',
101 | height: '3.47vw',
102 | fontWeight: 400,
103 | fontSize: '2.93vw',
104 | color: '#999999',
105 | lineHeight: '3.47vw',
106 | whiteSpace: 'nowrap'
107 | }
108 | };
109 |
--------------------------------------------------------------------------------
/code/style.less:
--------------------------------------------------------------------------------
1 | .box {
2 | display: flex;
3 | flex-direction: row;
4 | justify-content: space-around;
5 | align-items: flex-start;
6 | height: 534px;
7 | .bd {
8 | display: flex;
9 | position: relative;
10 | align-items: flex-start;
11 | flex-direction: row;
12 | opacity: 1;
13 | width: 342px;
14 | height: 342px;
15 | .layer {
16 | position: absolute;
17 | top: 0px;
18 | left: 0px;
19 | width: 342px;
20 | height: 342px;
21 | overflow: hidden;
22 | }
23 | .bg {
24 | position: absolute;
25 | top: 0px;
26 | left: 0px;
27 | opacity: 1;
28 | width: 342px;
29 | height: 342px;
30 | }
31 | .wrap {
32 | box-sizing: border-box;
33 | display: flex;
34 | position: relative;
35 | align-items: center;
36 | flex-direction: row;
37 | margin-top: 18px;
38 | margin-left: 18px;
39 | border-radius: 15px;
40 | background-color: rgba(0, 0, 0, 0.4);
41 | padding-right: 9px;
42 | padding-left: 10px;
43 | height: 30px;
44 | .riverdinwei {
45 | opacity: 1;
46 | width: 14px;
47 | height: 18px;
48 | }
49 | .distance {
50 | margin-left: 4px;
51 | height: 22px;
52 | font-weight: 400;
53 | font-size: 18px;
54 | color: #ffffff;
55 | line-height: 22px;
56 | white-space: nowrap;
57 | }
58 | }
59 | }
60 | .main {
61 | display: flex;
62 | align-items: flex-start;
63 | flex-direction: row;
64 | justify-content: center;
65 | background-color: #ffffff;
66 | width: 342px;
67 | height: 114px;
68 | .title {
69 | margin-top: 22px;
70 | width: 300px;
71 | height: 88px;
72 | font-weight: 400;
73 | font-size: 30px;
74 | color: #333333;
75 | line-height: 44px;
76 | overflow: hidden;
77 | text-overflow: ellipsis;
78 | }
79 | }
80 | .ft {
81 | box-sizing: border-box;
82 | display: flex;
83 | align-items: center;
84 | flex-direction: row;
85 | justify-content: space-between;
86 | border-bottom-left-radius: 12px;
87 | border-bottom-right-radius: 12px;
88 | background-color: #ffffff;
89 | padding-right: 17px;
90 | padding-left: 18px;
91 | width: 342px;
92 | height: 78px;
93 | overflow: hidden;
94 | .block {
95 | display: flex;
96 | align-items: center;
97 | flex-direction: row;
98 | height: 30px;
99 | .xianjin {
100 | width: 30px;
101 | height: 30px;
102 | }
103 | .fashionHome {
104 | margin-left: 6px;
105 | height: 28px;
106 | font-weight: 300;
107 | font-size: 24px;
108 | color: #666666;
109 | line-height: 28px;
110 | white-space: nowrap;
111 | }
112 | }
113 | .group {
114 | display: flex;
115 | align-items: center;
116 | flex-direction: row;
117 | height: 30px;
118 | .favorite {
119 | width: 22px;
120 | height: 22px;
121 | }
122 | .num {
123 | margin-left: 5px;
124 | height: 26px;
125 | font-weight: 400;
126 | font-size: 22px;
127 | color: #999999;
128 | line-height: 26px;
129 | white-space: nowrap;
130 | }
131 | }
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | const co = require('co');
2 | const xtpl = require('xtpl');
3 | const fs = require('fs');
4 | const thunkify = require('thunkify');
5 | const path = require('path');
6 | const { NodeVM } = require('vm2');
7 | const _ = require('lodash');
8 | const data = require('./data');
9 | const componentsMap = require('./componentsMap');
10 | const helper = require('@imgcook/dsl-helper');
11 |
12 | const prettier = require('prettier/standalone');
13 |
14 | const parserHtml =require('prettier/parser-html');
15 | const parserBabel= require('prettier/parser-babel');
16 | const parserCss =require('prettier/parser-postcss');
17 | const parserMarkDown=require('prettier/parser-markdown');
18 |
19 | const entry = require('../src/index')
20 | const browerParser = {
21 | babel: parserBabel,
22 | json: parserBabel,
23 | vue: parserHtml,
24 | css: parserCss,
25 | scss: parserCss,
26 | less: parserCss,
27 | html: parserHtml,
28 | md: parserMarkDown
29 | }
30 |
31 | const vm = new NodeVM({
32 | console: 'inherit',
33 | sandbox: {},
34 | });
35 |
36 | const runCode = (data, dslConfig) => {
37 | data = _.cloneDeep(data);
38 | const config = _.get(data, 'imgcook.dslConfig', {});
39 | _.set(data, 'imgcook.dslConfig', Object.assign(config, dslConfig));
40 |
41 | const code = fs.readFileSync(
42 | path.resolve(__dirname, '../src/index.js'),
43 | 'utf8'
44 | );
45 | const options = {
46 | prettier: {
47 | format: (str, opt) => {
48 | if (opt && browerParser[opt.parser]) {
49 | opt.plugins = [browerParser[opt.parser]]
50 | } else {
51 | return str
52 | }
53 | try{
54 | return prettier.format(str, opt)
55 | }catch(e){
56 | console.error('format error', e)
57 | return str
58 | }
59 |
60 | }
61 | },
62 | _: _,
63 | responsive: {
64 | width: 750,
65 | viewportWidth: 375,
66 | },
67 | helper,
68 | componentsMap,
69 | }
70 |
71 | // const files = vm.run(code)(data,options);
72 |
73 | const files = entry(data, options);
74 | return files.panelDisplay;
75 | };
76 |
77 | co(function*() {
78 | const panelDisplay = runCode(data, {
79 | componentStyle: "hooks",
80 | cssUnit: "rpx",
81 | dsl: "rax",
82 | globalCss: true,
83 | htmlFontSize: "16",
84 | inlineStyle: "module",
85 | responseHeight: 1334,
86 | responseWidth: 750,
87 | useHooks: true,
88 | useTypescript: false
89 | });
90 |
91 | // console.log('panelDisplay', panelDisplay)
92 |
93 | const baseDir = '../demo/src/dist';
94 |
95 | if (fs.existsSync(path.join(__dirname, baseDir))) {
96 | fs.rmdirSync(path.join(__dirname, baseDir), { recursive: true });
97 | console.log('删除文件夹')
98 | }
99 | mkDirsSync(path.join(__dirname, baseDir));
100 | console.log('创建文件夹', path.join(__dirname, baseDir))
101 | // const baseDir = '../code';
102 | // 生成到目标目录运行
103 |
104 | panelDisplay.forEach((file) => {
105 | if (file.folder) {
106 | let fileFolder = path.join(__dirname, `${baseDir}/${file.folder}`);
107 | if (!fs.existsSync(fileFolder)) {
108 | mkDirsSync(fileFolder);
109 | }
110 | fs.writeFileSync(
111 | path.join(__dirname, `${baseDir}/${file.folder}/${file.panelName}`),
112 | file.panelValue
113 | );
114 | } else {
115 | fs.writeFileSync(
116 | path.join(__dirname, `${baseDir}/${file.panelName}`),
117 | file.panelValue
118 | );
119 | }
120 | });
121 | });
122 |
123 | function mkDirsSync(dirname) {
124 | if (fs.existsSync(dirname)) {
125 | return true;
126 | } else {
127 | if (mkDirsSync(path.dirname(dirname))) {
128 | fs.mkdirSync(dirname);
129 | return true;
130 | }
131 | }
132 | }
133 |
134 | module.exports = {
135 | runCode,
136 | };
137 |
--------------------------------------------------------------------------------
/src/core/exportCreateApp.ts:
--------------------------------------------------------------------------------
1 | import { IPanelDisplay } from './interface';
2 |
3 | import { CSS_TYPE, OUTPUT_TYPE, prettierJsOpt, prettierCssOpt, prettierJsonOpt, prettierHtmlOpt } from './consts';
4 |
5 |
6 | export default function exportCreateApp(schema, option): IPanelDisplay[] {
7 | const folderName = schema.folderName;
8 | const {
9 | dependencies,
10 | dslConfig,
11 | _,
12 | prettier
13 | } = option;
14 |
15 | let panelValue = '';
16 | const panelDisplay: IPanelDisplay[] = [];
17 |
18 | panelValue = `
19 |
20 |
21 |
22 |
23 |
24 |
25 |
29 | React App
30 |
31 |
32 |
33 |
34 |
35 | `
36 | panelDisplay.push({
37 | panelName: `index.html`,
38 | panelType: 'html',
39 | panelValue,
40 | folder: 'public',
41 | });
42 |
43 | // index.js
44 | const isGlobal = schema.css && dslConfig.globalCss && dslConfig.inlineStyle !== CSS_TYPE.INLINE_CSS;
45 | panelValue = `'use strict';
46 | import React from 'react';
47 | import ReactDOM from 'react-dom/client';
48 | ${isGlobal ? " import './global.css';" : ''}
49 | import './index.css';
50 | import App from './App';
51 |
52 | const root = ReactDOM.createRoot(document.getElementById('root'));
53 | root.render(
54 |
55 |
56 |
57 | );
58 |
59 | `
60 | panelDisplay.push({
61 | panelName: `index.${ dslConfig.useTypescript?'tsx': 'jsx'}`,
62 | panelType: dslConfig.useTypescript?'tsx': 'jsx',
63 | panelValue: prettier.format(panelValue, prettierJsOpt),
64 | folder: 'src',
65 | });
66 |
67 | // index.css
68 | panelValue = ``
69 | panelDisplay.push({
70 | panelName: `index.css`,
71 | panelType: 'css',
72 | panelValue: prettier.format(panelValue, prettierCssOpt),
73 | folder: 'src',
74 | });
75 |
76 |
77 |
78 | // dependencies
79 | let packDependencies = dependencies;
80 |
81 | // if (schema.imgcook && schema.imgcook.dependencies) {
82 | // schema.imgcook.dependencies.forEach(({packageRax1, versionRax1}) => {
83 | // packDependencies[packageRax1] = versionRax1
84 | // })
85 | // }
86 |
87 |
88 | // package.json
89 | const packageJson = {
90 | "title": "imgcook demo",
91 | "scripts": {
92 | "start": "react-scripts start",
93 | "build": "react-scripts build",
94 | "test": "react-scripts test",
95 | "eject": "react-scripts eject"
96 | },
97 | "main": "index.js",
98 | "devDependencies": {
99 | "typescript": "^4.0.5"
100 | },
101 | "dependencies": {
102 | "react": "^18.0.0",
103 | "react-dom": "^18.0.0",
104 | "react-scripts": "5.0.1",
105 | ...packDependencies
106 | },
107 | "browserslist": [
108 | ">0.2%",
109 | "not dead",
110 | "not ie <= 11",
111 | "not op_mini all"
112 | ]
113 | }
114 | panelValue = JSON.stringify(packageJson, null, 4)
115 | panelDisplay.push({
116 | panelName: `package.json`,
117 | panelType: 'json',
118 | panelValue: prettier.format(panelValue, prettierJsonOpt),
119 | folder: option.folder || '',
120 | });
121 |
122 |
123 | if (dslConfig.useTypescript) {
124 | panelValue = `{
125 | "compilerOptions": {
126 | "target": "es5",
127 | "lib": [
128 | "dom",
129 | "dom.iterable",
130 | "esnext"
131 | ],
132 | "allowJs": true,
133 | "skipLibCheck": true,
134 | "esModuleInterop": true,
135 | "allowSyntheticDefaultImports": true,
136 | "strict": true,
137 | "forceConsistentCasingInFileNames": true,
138 | "noFallthroughCasesInSwitch": true,
139 | "module": "esnext",
140 | "moduleResolution": "node",
141 | "resolveJsonModule": true,
142 | "isolatedModules": true,
143 | "noEmit": true,
144 | "jsx": "react-jsx"
145 | },
146 | "include": [
147 | "src"
148 | ]
149 | }
150 | `
151 | panelDisplay.push({
152 | panelName: `tsconfig.json`,
153 | panelType: 'json',
154 | panelValue: prettier.format(panelValue, prettierJsonOpt),
155 | folder: option.folder || '',
156 | });
157 | }
158 |
159 |
160 | return panelDisplay;
161 | }
162 |
--------------------------------------------------------------------------------
/src/core/entry.ts:
--------------------------------------------------------------------------------
1 | import { IPanelDisplay, IDslConfig } from './interface';
2 | import {
3 | line2Hump,
4 | transComponentsMap,
5 | initSchema,
6 | traverse,
7 | genStyleClass,
8 | getGlobalClassNames,
9 | genStyleCode,
10 | simpleStyle,
11 | commonStyle
12 | } from './utils';
13 | import { CSS_TYPE, COMPONENT_TYPE, OUTPUT_TYPE, initConfig, defaultGlobalCss } from './consts';
14 |
15 |
16 |
17 | import exportBlock from './exportBlock';
18 | // const exportPage from './exportPage';
19 | import exportCreateApp from './exportCreateApp';
20 | import exportGlobalCss from './exportGlobalCss';
21 |
22 | module.exports = function (schema, option) {
23 | // get blocks json
24 | const blocks: any[] = [];
25 | const pages: any[] = []
26 |
27 | // 参数设置
28 | option.scale = 750 / ((option.responsive && option.responsive.width) || 750);
29 | option.componentsMap = transComponentsMap(option.componentsMap);
30 | option.blockInPage = schema.componentName === 'Page';
31 | option.pageGlobalCss = schema.css || '';
32 |
33 | const dslConfig = Object.assign(
34 | {
35 | scale: option.scale,
36 | globalCss: true,
37 | cssUnit: 'px',
38 | inlineStyle: CSS_TYPE.MODULE_CLASS,
39 | componentStyle: COMPONENT_TYPE.HOOKS,
40 | htmlFontSize: 16
41 | },
42 | option._.get(schema, 'imgcook.dslConfig')
43 | );
44 |
45 | dslConfig.useHooks = dslConfig.componentStyle === COMPONENT_TYPE.HOOKS;
46 | dslConfig.useTypescript = dslConfig.jsx === 'typescript'
47 | option.dslConfig = dslConfig;
48 |
49 | schema.css = schema.css || defaultGlobalCss;
50 |
51 | // 初始化全局参数
52 | initConfig(dslConfig);
53 |
54 | // 可选 className name style
55 | // inlineStyle = inlineStyle !== 'className';
56 |
57 |
58 | const { inlineStyle } = dslConfig
59 | // clear schema
60 | initSchema(schema);
61 |
62 | const isProject = dslConfig.outputStyle == OUTPUT_TYPE.PROJECT;
63 | if(isProject){
64 | // 导出完整项目时,使根节点为Page
65 | schema.componentName = 'Page';
66 | }
67 | // 记录所有blocks
68 | traverse(schema, (json) => {
69 | switch (json.componentName.toLowerCase()) {
70 | case 'block':
71 | blocks.push(json);
72 | break;
73 | case 'page':
74 | pages.push(json);
75 | break;
76 | }
77 | });
78 |
79 |
80 | // 提取全局样式
81 | if([CSS_TYPE.IMPORT_CLASS].includes(inlineStyle)){
82 | traverse(schema, (json) => {
83 | let classnames: string[] = json.classnames || [];
84 | let style = json.props.style;
85 | const enableGlobalCss = dslConfig.globalCss && schema.css
86 |
87 | // 计算全局样式类名
88 | if (enableGlobalCss) {
89 | const cssResults = getGlobalClassNames(style, schema.css);
90 | if (cssResults.names.length > 0) {
91 | classnames = [...classnames, ...cssResults.names]
92 | }
93 | json.props.style = cssResults.style;
94 | json.classnames = classnames || []
95 | }
96 | });
97 | }
98 |
99 |
100 | // 提取公用样式
101 | if([CSS_TYPE.IMPORT_CLASS, CSS_TYPE.MODULE_CLASS].includes(inlineStyle)){
102 | blocks.forEach((block) => {
103 | commonStyle(block);
104 | });
105 |
106 | }
107 |
108 | // 精简默认样式
109 | simpleStyle(schema)
110 |
111 |
112 | // 提取全局样式,类名数组存于 json.classString , 剩余样式覆盖 style
113 | traverse(schema, (json) => {
114 | let classnames: string[] = json.classnames || [];
115 | const className = json.props && json.props.className || '';
116 |
117 | let classString = '';
118 | const style = json.props.style;
119 |
120 | // inline 内联 (不需要提取同名)
121 | if (inlineStyle === CSS_TYPE.INLINE_CSS) {
122 | className && (classString = `className="${className}"`);
123 | json.props.codeStyle = style; // 内联样式
124 | } else if (inlineStyle === CSS_TYPE.MODULE_STYLE) {
125 | className && (classString = ` style={${genStyleCode('styles', className)}}`);
126 | } else if(inlineStyle == CSS_TYPE.MODULE_CLASS) {
127 | classnames.push(className);
128 | classnames = classnames.filter(name=>name!=='');
129 | classnames = classnames.map(name=>genStyleCode('styles', name));
130 |
131 | if (classnames.length > 1) {
132 | classString = ` className={\`${classnames.map(name=>`\$\{${name}\}`).join(' ').trim()}\`}`;
133 | } else if(classnames.length == 1) {
134 | classString = ` className={${classnames[0].trim()}}`;
135 | }
136 | }else if(inlineStyle == CSS_TYPE.IMPORT_CLASS){
137 | classnames.push(className);
138 | classnames = classnames.filter(name=>name!=='');
139 | if (classnames.length >= 1) {
140 | classString = ` className="${classnames.join(' ')}"`;
141 | }
142 | }
143 |
144 | json.props.style = style;
145 | json.classString = classString;
146 | });
147 |
148 |
149 |
150 |
151 | option.blocksCount = blocks.length;
152 | option.pagesCount = pages.length;
153 |
154 | // export module code
155 | let panelDisplay: IPanelDisplay[] = [];
156 |
157 |
158 | blocks.length > 0 &&
159 | blocks.forEach((block) => {
160 | const result = exportBlock(block, option);
161 | panelDisplay = panelDisplay.concat(result);
162 | });
163 | // export Page code
164 | if (schema.componentName === 'Page') {
165 | const result = exportBlock(schema, option);
166 | panelDisplay = panelDisplay.concat(result);
167 | }
168 |
169 |
170 |
171 | if (isProject) {
172 | // 依赖 package.json
173 | const dependencies = {};
174 | for (let item of panelDisplay) {
175 | if (item.panelDependencies && item.panelDependencies.length > 0) {
176 | for (let pack of item.panelDependencies) {
177 | dependencies[pack.package] = pack.version || '*'
178 | }
179 | }
180 | }
181 |
182 | // 项目模式生成文件放到src中
183 | panelDisplay = panelDisplay.map(item => {
184 | item.folder = 'src/' + item.folder
185 | return item;
186 | });
187 |
188 | // 项目文件
189 | panelDisplay = panelDisplay.concat(exportCreateApp(schema, { ...option, dependencies }));
190 | }
191 |
192 |
193 | // 全局样式
194 | panelDisplay = panelDisplay.concat(exportGlobalCss(schema, { ...option, folder: isProject ? 'src' : '' }));
195 |
196 |
197 | return {
198 | panelDisplay,
199 | noTemplate: true,
200 | };
201 | };
202 |
--------------------------------------------------------------------------------
/code/index.jsx:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React, { Component } from 'react';
4 |
5 | import './style.css';
6 |
7 | const print = function(value) {
8 | console.log(value);
9 | };
10 | class Block_0 extends Component {
11 | render() {
12 | return (
13 |
14 |
15 |
23 |
31 |
39 |
40 | {true &&
}
41 |
49 |
57 |
65 |
73 |
81 |
89 |
90 |
98 |
106 |
107 |
113 |
121 |
129 |
130 |
131 |
132 |
140 |
141 | 剩
142 | 3
143 | 次机会
144 |
145 |
153 |
154 |
155 |
163 |
164 |
165 |
173 |
181 |
189 |
190 |
191 |
192 |
193 | );
194 | }
195 | }
196 | export default Block_0;
197 |
--------------------------------------------------------------------------------
/dist/main.js:
--------------------------------------------------------------------------------
1 | !function(e){var t={};function n(o){if(t[o])return t[o].exports;var r=t[o]={i:o,l:!1,exports:{}};return e[o].call(r.exports,r,r.exports,n),r.l=!0,r.exports}n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)n.d(o,r,function(t){return e[t]}.bind(null,r));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t){e.exports=function(e,t){const{_:n,prettier:o}=t;componentsMap=((e={})=>{if(!e||!Array.isArray(e.list))return[];return e.list.reduce((e,t)=>{const n=t.name;if(!e[n]){if(t.dependence)try{let e="string"==typeof t.dependence?JSON.parse(t.dependence):t.dependence;e&&(t.packageName=e.package,t.dependence=e),t.dependenceVersion||(t.dependenceVersion="*"),t.exportName=e.export_name,t.subName=e.sub_name,/^\d/.test(t.dependenceVersion)&&(t.dependenceVersion="^"+t.dependenceVersion)}catch(e){console.log(e)}e[n]=t}return e},{})})(t.componentsMap);const r=new Map,s=[],a={},i=[],c=[],p=t.responsive.width/100||750;let l=!1;const d=e=>/^\{\{.*\}\}$/.test(e),f=e=>"[object Function]"==={}.toString.call(e)?e.toString():"string"==typeof e?e:"object"==typeof e?JSON.stringify(e,(e,t)=>"function"==typeof t?t.toString():t):String(e),u=(e,t)=>{let n="";return Object.keys(e).map(o=>{n+=`.${o}{${h(e[o],t)}}`}),n},m=["fontSize","marginTop","marginBottom","paddingTop","paddingBottom","height","top","bottom","width","maxWidth","left","right","paddingRight","paddingLeft","marginLeft","marginRight","lineHeight","borderBottomRightRadius","borderBottomLeftRadius","borderTopRightRadius","borderTopLeftRadius","borderRadius"],$=["opacity","fontWeight"],h=(e,t)=>{const o=[];for(let r in e){let s=e[r];-1!=m.indexOf(r)?(t?(s=(parseInt(s)/p).toFixed(2),s=0==s?s:s+"vw"):(s=parseInt(s).toFixed(2),s=0==s?s:s+"px"),o.push(`${n.kebabCase(r)}: ${s}`)):-1!=$.indexOf(r)?o.push(`${n.kebabCase(r)}: ${parseFloat(s)}`):o.push(`${n.kebabCase(r)}: ${s}`)}return o.join(";")},y=e=>{const t=e.toString();return{params:t.match(/\([^\(\)]*\)/)[0].slice(1,-1),content:t.slice(t.indexOf("{")+1,t.lastIndexOf("}"))}},g=(e,t)=>{if("string"==typeof e)return d(e)?t?e.slice(1,-1):e.slice(2,-2):t?e:`"${e}"`;if("function"==typeof e){const{params:t,content:n}=y(e);return`(${t}) => {${n}}`}return JSON.stringify(e)},b=e=>{const t=e.componentName.toLowerCase(),n=e.props&&e.props.className||"",o=n?` className="${n}"`:"";let s;n&&(a[n]=e.props.style);let i="";switch(Object.keys(e.props).forEach(t=>{-1===["className","style","text","src","lines"].indexOf(t)&&(i+=` ${t}={${g(e.props[t])}}`)}),t){case"text":const t=g(e.props.text,!0);s=`${t} `;break;case"image":const n=g(e.props.src);s=` `;break;case"div":case"page":case"block":case"component":s=e.children&&e.children.length?`${N(e.children)}
`:`
`;break;default:s=e.children&&e.children.length?`<${e.componentName}${o}${i}>${N(e.children)}${e.componentName}>`:`<${e.componentName}${o}${i} />`;const a=(e=>{if(!e)return;const t=componentsMap[e];if(t){const e=r.get(t.packageName);if(e)e.add(t);else{const e=new Set;e.add(t),r.set(t.packageName,e)}}else;})(e.componentName);a&&r.push(a)}var c,p;return e.loop&&(s=((e,t,n)=>{let o,r=t&&t[0]||"item",s=t&&t[1]||"index";Array.isArray(e)?o=f(e):d(e)&&(o=e.slice(2,-2));const a=n.match(/^<.+?\s/)[0].length;n=`${n.slice(0,a)} key={${s}}${n.slice(a)}`;const i=new RegExp("this."+r,"g");return`${o}.map((${r}, ${s}) => {\n return (${n=n.replace(i,r)});\n })`})(e.loop,e.loopArgs,s)),e.condition&&(c=e.condition,p=s,s="boolean"==typeof c?`${c} && ${p}`:"string"==typeof c?`${c.slice(2,-2)} && ${p}`:void 0),!e.loop&&!e.condition||e.isRoot||(s=`{${s}}`),s};let x=function(e,t){if(t.hasOwnProperty("children"))for(let n of t.children)e.push(n),x(e,n)};const j=function(e){let t="";for(let n of e.keyframes)t+=`\n ${(1e4*n.offset/100).toFixed(0)+"%"} {\n ${n.opacity?"opacity: ".concat(n.opacity)+";":""}\n ${n.transform?"transform: ".concat(n.transform)+";":""}\n }\n `;return`\n@keyframes ${e.name} {\n ${t}\n}\n`},N=e=>{let t="";if(Array.isArray(e))e.forEach(e=>{t+=N(e)});else if("string"==typeof e)t+=e;else if("object"==typeof e&&"string"==typeof e.componentName){let n=e.componentName.toLowerCase(),o=-1!==["block","component"].indexOf(n);if(l&&o&&(n="div",o=!1),"page"===n&&(l?n="div":(l=!0,o=!0)),o){const t=[],n=[],o=[],r=[],a=["render(){ return ("];let i=[`class ${e.componentName}_${c.length} extends Component {`];if(e.state&&t.push("state = "+f(e.state)),e.methods&&Object.keys(e.methods).forEach(t=>{const{params:n,content:r}=y(e.methods[t]);o.push(`${t}(${n}) {${r}}`)}),e.dataSource&&Array.isArray(e.dataSource.list)&&(e.dataSource.list.forEach(e=>{"boolean"==typeof e.isInit&&e.isInit?r.push(`this.${e.id}();`):"string"==typeof e.isInit&&r.push(`if (${g(e.isInit)}) { this.${e.id}(); }`),o.push((e=>{const t=e.id,{uri:n,method:o,params:r}=e.options,a=e.type;let i={};switch(a){case"fetch":-1===s.indexOf("import {fetch} from whatwg-fetch")&&s.push("import {fetch} from 'whatwg-fetch'"),i={method:o};break;case"jsonp":-1===s.indexOf("import {fetchJsonp} from fetch-jsonp")&&s.push("import jsonp from 'fetch-jsonp'")}Object.keys(e.options).forEach(t=>{-1===["uri","method","params"].indexOf(t)&&(i[t]=f(e.options[t]))}),i=r?`${f(i).slice(0,-1)} ,body: ${d(r)?g(r):f(r)}}`:f(i);let c=`{\n ${a}(${g(n)}, ${f(i)})\n .then((response) => response.json())\n `;if(e.dataHandler){const{params:t,content:n}=y(e.dataHandler);c+=`.then((${t}) => {${n}})\n .catch((e) => {\n console.log('error', e);\n })\n `}return c+="}",`${t}() ${c}`})(e))}),e.dataSource.dataHandler)){const{params:t,content:n}=y(e.dataSource.dataHandler);o.push(`dataHandler(${t}) {${n}}`),r.push("this.dataHandler()")}e.lifeCycles&&(e.lifeCycles._constructor||n.push(`constructor(props, context) { super(); ${r.join("\n")}}`),Object.keys(e.lifeCycles).forEach(t=>{const{params:o,content:s}=y(e.lifeCycles[t]);"_constructor"===t?n.push(`constructor(${o}) { super(); ${s} ${r.join("\n")}}`):n.push(`${t}(${o}) {${s}}`)})),a.push(b(e)),a.push(");}"),i=i.concat(t).concat(n).concat(o).concat(a),i.push("}"),c.push(i.join("\n"))}else t+=b(e)}return t};t.utils&&Object.keys(t.utils).forEach(e=>{i.push(`const ${e} = ${t.utils[e]}`)}),e.isRoot=!0;N(e);const O=function(e){let t="";e.animation&&(t+=j(e.animation));let n=[];x(n,e);for(let e of n)e.animation&&(t+=j(e.animation));return t}(e);let k=(()=>{const e=[],t=[];for(const[n,o]of r){const r=new Set,s=new Set;for(const e of o){let n=e.exportName,o=e.subName,a=e.name;e.subName&&t.push(`const ${a} = ${n}.${o};`),a===n||e.subName||(n=`${n} as ${a}`),e.dependence.destructuring?s.add(n):r.add(n)}const a=[...r].join(",");let i=[...s].join(",");const c=a&&i?",":"";i&&(i=`{${i}}`),e.push(`import ${a} ${c} ${i} from '${n}'`)}return e.concat(t)})();return k=k.concat(s),{panelDisplay:[{panelName:"index.jsx",panelValue:o.format(`\n 'use strict';\n\n import React, { Component } from 'react';\n ${k.join("\n")}\n import './style.css';\n\n ${i.join("\n")}\n ${c.join("\n")}\n export default ${e.componentName}_0;\n `,{parser:"babel",printWidth:120,singleQuote:!0}),panelType:"js"},{panelName:"style.css",panelValue:o.format(u(a),{parser:"css"})+O,panelType:"css"},{panelName:"style.responsive.css",panelValue:o.format(""+u(a,!0),{parser:"css"})+O,panelType:"css"}],noTemplate:!0}}}]);
--------------------------------------------------------------------------------
/code/result.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import React, { Component } from 'react';
4 |
5 | import { fetch } from 'whatwg-fetch';
6 | import jsonp from 'fetch-jsonp';
7 |
8 | const print = function(value) {
9 | console.log(value);
10 | };
11 |
12 | const styles = {
13 | box: {
14 | display: 'flex',
15 | flexDirection: 'row',
16 | justifyContent: 'space-around',
17 | alignItems: 'flex-start',
18 | height: '71.20vw'
19 | },
20 | bd: {
21 | display: 'flex',
22 | position: 'relative',
23 | alignItems: 'flex-start',
24 | flexDirection: 'row',
25 | opacity: '1.00',
26 | width: '45.60vw',
27 | height: '45.60vw'
28 | },
29 | layer: {
30 | position: 'absolute',
31 | top: '0.00vw',
32 | left: '0.00vw',
33 | width: '45.60vw',
34 | height: '45.60vw',
35 | overflow: 'hidden'
36 | },
37 | bg: { position: 'absolute', top: '0.00vw', left: '0.00vw', opacity: '1.00', width: '45.60vw', height: '45.60vw' },
38 | wrap: {
39 | boxSizing: 'border-box',
40 | display: 'flex',
41 | position: 'relative',
42 | alignItems: 'center',
43 | flexDirection: 'row',
44 | marginTop: '2.40vw',
45 | marginLeft: '2.40vw',
46 | borderRadius: '2.00vw',
47 | backgroundColor: 'rgba(0,0,0,0.40)',
48 | paddingRight: '1.20vw',
49 | paddingLeft: '1.33vw',
50 | height: '4.00vw'
51 | },
52 | riverdinwei: { opacity: '1.00', width: '1.87vw', height: '2.40vw' },
53 | distance: {
54 | marginLeft: '0.53vw',
55 | width: '11.20vw',
56 | height: '2.93vw',
57 | lineHeight: '2.93vw',
58 | whiteSpace: 'nowrap',
59 | color: '#ffffff',
60 | fontSize: '2.40vw',
61 | fontWeight: 400,
62 | lines: 1
63 | },
64 | main: {
65 | display: 'flex',
66 | alignItems: 'flex-start',
67 | flexDirection: 'row',
68 | justifyContent: 'center',
69 | backgroundColor: '#ffffff',
70 | width: '45.60vw',
71 | height: '15.20vw'
72 | },
73 | title: {
74 | marginTop: '2.93vw',
75 | width: '40.00vw',
76 | height: '11.73vw',
77 | overflow: 'hidden',
78 | textOverflow: 'ellipsis',
79 | lineHeight: '5.87vw',
80 | color: '#333333',
81 | fontSize: '4.00vw',
82 | fontWeight: 400,
83 | lines: 2
84 | },
85 | ft: {
86 | boxSizing: 'border-box',
87 | display: 'flex',
88 | alignItems: 'center',
89 | flexDirection: 'row',
90 | justifyContent: 'space-between',
91 | borderBottomLeftRadius: '1.60vw',
92 | borderBottomRightRadius: '1.60vw',
93 | backgroundColor: '#ffffff',
94 | paddingRight: '2.27vw',
95 | paddingLeft: '2.40vw',
96 | width: '45.60vw',
97 | height: '10.40vw',
98 | overflow: 'hidden'
99 | },
100 | block: { display: 'flex', alignItems: 'center', flexDirection: 'row', height: '4.00vw' },
101 | xianjin: { width: '4.00vw', height: '4.00vw' },
102 | fashionHome: {
103 | marginLeft: '0.80vw',
104 | width: '12.80vw',
105 | height: '3.73vw',
106 | lineHeight: '3.73vw',
107 | whiteSpace: 'nowrap',
108 | color: '#666666',
109 | fontSize: '3.20vw',
110 | fontWeight: 300,
111 | lines: 1
112 | },
113 | group: { display: 'flex', alignItems: 'center', flexDirection: 'row', height: '4.00vw' },
114 | favorite: { width: '2.93vw', height: '2.93vw' },
115 | num: {
116 | marginLeft: '0.67vw',
117 | width: '4.80vw',
118 | height: '3.47vw',
119 | lineHeight: '3.47vw',
120 | whiteSpace: 'nowrap',
121 | color: '#999999',
122 | fontSize: '2.93vw',
123 | fontWeight: 400,
124 | lines: 1
125 | }
126 | };
127 |
128 | class Page_0 extends Component {
129 | state = {
130 | data: [
131 | {
132 | title: '小户型卫浴怎样才能装得高大上?',
133 | coverImage: 'https://img.alicdn.com/tfs/TB1Txq6o7T2gK0jSZFkXXcIQFXa-684-684.png',
134 | readCount: 200,
135 | user: { userImage: 'https://img.alicdn.com/tfs/TB1DWe6oYj1gK0jSZFOXXc7GpXa-60-60.png', userName: '时尚家居' },
136 | url: 'https://www.imgcook.com'
137 | },
138 | {
139 | title: '拥有超多功能的40平米简约小公寓了解一下',
140 | coverImage: 'https://img.alicdn.com/tfs/TB1XRQTo7P2gK0jSZPxXXacQpXa-684-648.png',
141 | readCount: 500,
142 | user: {
143 | userImage: 'https://img.alicdn.com/tfs/TB1DWe6oYj1gK0jSZFOXXc7GpXa-60-60.png',
144 | userName: '花花设计工作'
145 | },
146 | url: 'https://www.imgcook.com/docs'
147 | }
148 | ]
149 | };
150 | constructor(props, context) {
151 | console.log('super props');
152 | this.fetch_example();
153 | this.jsonp_example();
154 | }
155 | componentDidUpdate(prevProps, prevState, snapshot) {}
156 | isReadCountShow(readCount) {
157 | return readCount > 300;
158 | }
159 | fetch_example() {
160 | fetch('https://jsonplaceholder.typicode.com/todos/1', { method: 'GET', headers: '{"Content-Type":"json"}' })
161 | .then(response => response.json())
162 | .then((data, error) => {
163 | console.log('fetch example: ', data, error);
164 | return data;
165 | })
166 | .catch(e => {
167 | console.log('error', e);
168 | });
169 | }
170 | jsonp_example() {
171 | jsonp('https://assets.airbnb.com/frontend/search_results.js', { jsonpCallbackFunction: 'search_results', body: {} })
172 | .then(response => response.json())
173 | .then((data, error) => {
174 | console.log('jsonp example: ', data, error);
175 | return data;
176 | })
177 | .catch(e => {
178 | console.log('error', e);
179 | });
180 | }
181 | render() {
182 | return (
183 |
184 | {this.state.data.map((item, index) => {
185 | return (
186 |
{
189 | window.open(item.url, '_blank');
190 | }}
191 | data-url={item.url}
192 | key={item.index}
193 | >
194 |
195 |
196 |
197 |
198 |
202 |
距离500m
203 |
204 |
205 |
206 | {item.title}
207 |
208 |
209 |
210 |
214 |
{item.user.userName}
215 |
216 | {this.isReadCountShow(item.readCount) && (
217 |
218 |
222 |
{item.readCount}
223 |
224 | )}
225 |
226 |
227 | );
228 | })}
229 |
230 | );
231 | }
232 | }
233 |
234 | export default Page_0;
235 |
--------------------------------------------------------------------------------
/test/react.test.js:
--------------------------------------------------------------------------------
1 | const { expect, assert } = require('chai');
2 | const { runCode } = require('./index');
3 | const data = require('./data');
4 | const _ = require('lodash');
5 |
6 |
7 |
8 | describe('componentStyle 组件格式', () => {
9 |
10 |
11 | it('componentStyle = hooks 时,使用hooks出码方式', async () => {
12 | const result = runCode(data, { globalCss: true, componentStyle: 'hooks'});
13 | const jsFile = _.find(result, { panelName:'index.jsx'});
14 | expect(jsFile).to.not.be.equal(undefined);
15 | expect(jsFile.panelValue.includes('useState')).to.be.equal(true);
16 | expect(jsFile.panelValue.includes('memo')).to.be.equal(true);
17 | expect(jsFile.panelValue.includes('Component')).to.be.equal(false);
18 | });
19 |
20 | it('componentStyle = component 时,使用 component 出码方式', async () => {
21 | const result = runCode(data, { globalCss: true, componentStyle: 'component'});
22 | const jsFile = _.find(result, { panelName:'index.jsx'});
23 | expect(jsFile).to.not.be.equal(undefined);
24 | expect(jsFile.panelValue.includes('useState')).to.be.equal(false);
25 | expect(jsFile.panelValue.includes('memo')).to.be.equal(false);
26 | expect(jsFile.panelValue.includes('Component')).to.be.equal(true);
27 | });
28 |
29 | });
30 |
31 | describe('globalCss 全局样式', () => {
32 | it('globalCss = true 时,有 global.css 文件', async () => {
33 | const result = runCode(data, { globalCss: true, outputStyle: 'project'});
34 | expect(_.find(result, { panelName:'global.css'})).to.not.be.equal(undefined);
35 | });
36 |
37 | it('globalCss = false 时,无 global.css 文件', async () => {
38 | const result = runCode(data, { globalCss: false, outputStyle: 'project'});
39 | expect(_.find(result, { panelName:'global.css'})).to.be.equal(undefined);
40 | });
41 | });
42 |
43 |
44 | describe('outputStyle 风格参数', () => {
45 | it('outputStyle = project 时, 有 package.json文件', async () => {
46 | const result = runCode(data, { globalCss: true, jsx: 'javascript', outputStyle: 'project'});
47 | expect(_.find(result, { panelName:'package.json'})).to.not.be.equal(undefined);
48 | expect(_.find(result, { panelName:'index.html'})).to.not.be.equal(undefined);
49 | expect(_.find(result, { panelName:'index.jsx'})).to.not.be.equal(undefined);
50 | expect(_.find(result, { panelName:'index.css'})).to.not.be.equal(undefined);
51 | });
52 |
53 | it('outputStyle = component 时, 无 package.json文件', async () => {
54 | const result = runCode(data, { globalCss: true, outputStyle: 'component'});
55 | expect(_.find(result, { panelName:'package.json'})).to.be.equal(undefined);
56 | });
57 | });
58 |
59 | describe('jsx 支持TS', () => {
60 | it(`jsx = javascript 时`, async () => {
61 | const schema = _.cloneDeep(data);
62 | const result = runCode(schema, { inlineStyle: 'import', jsx: 'javascript'});
63 | const file = _.find(result, { panelType:'tsx'});
64 | expect(file).to.be.equal(undefined);
65 | });
66 |
67 | it(`jsx = typescript 时`, async () => {
68 | const schema = _.cloneDeep(data);
69 | const result = runCode(schema, { inlineStyle: 'import', jsx: 'typescript'});
70 | const file = _.find(result, { panelType:'jsx'});
71 | expect(file).to.be.equal(undefined);
72 | });
73 | });
74 | describe('cssStyle 样式名风格', () => {
75 | it(`cssStyle = kebabCase 时,中划线命名`, async () => {
76 | const schema = _.cloneDeep(data);
77 | schema.componentName = 'Block';
78 | schema.fileName = 'BlockDemo';
79 | schema.props.className = "class-name-01"
80 | const result = runCode(schema, { inlineStyle: 'import', cssStyle: 'kebabCase'});
81 | const file = _.find(result, { panelName:'index.css', folder: 'components/BlockDemo'});
82 | expect(file.panelValue.includes(`.class-name-01`)).to.be.equal(true);
83 | });
84 |
85 | it(`cssStyle = snakeCase 时,下划线命名`, async () => {
86 | const schema = _.cloneDeep(data);
87 | schema.componentName = 'Block';
88 | schema.fileName = 'BlockDemo';
89 | schema.props.className = "class-name-01"
90 | const result = runCode(schema, { inlineStyle: 'import', cssStyle: 'snakeCase'});
91 | const file = _.find(result, { panelName:'index.css', folder: 'components/BlockDemo'});
92 |
93 | expect(file.panelValue.includes(`.class_name_01`)).to.be.equal(true);
94 | });
95 |
96 | it(`cssStyle = camelCase 时,驼峰式命名`, async () => {
97 | const schema = _.cloneDeep(data);
98 | schema.componentName = 'Block';
99 | schema.fileName = 'BlockDemo';
100 | schema.props.className = "class-name-01"
101 | const result = runCode(schema, { inlineStyle: 'import', cssStyle: 'camelCase'});
102 | const file = _.find(result, { panelName:'index.css', folder: 'components/BlockDemo'});
103 | expect(file.panelValue.includes(`.className01`)).to.be.equal(true);
104 | });
105 |
106 |
107 | })
108 |
109 | describe('inlineStyle 样式引入方式', () => {
110 | it(`inlineStyle = import 时,包含 import './index.css';`, async () => {
111 | const schema = _.cloneDeep(data);
112 | schema.componentName = 'Block';
113 | schema.fileName = 'BlockDemo';
114 | const result = runCode(schema, { inlineStyle: 'import',});
115 | const file = _.find(result, { panelName:'index.jsx', folder: 'components/BlockDemo'});
116 | expect(file.panelValue.includes(`import './index.css';`)).to.be.equal(true);
117 | });
118 |
119 | it(`inlineStyle = module 时,包含 import styles from './index.module.css'`, async () => {
120 | const schema = _.cloneDeep(data);
121 | schema.componentName = 'Block';
122 | schema.fileName = 'BlockDemo';
123 | const result = runCode(schema, { inlineStyle: 'module',});
124 | const file = _.find(result, { panelName:'index.jsx', folder: 'components/BlockDemo'});
125 | expect(file.panelValue.includes(`import styles from './index.module.css';`)).to.be.equal(true);
126 | });
127 |
128 | it(`inlineStyle = inline 时,不引入css文件`, async () => {
129 | const schema = _.cloneDeep(data);
130 | schema.componentName = 'Block';
131 | schema.fileName = 'BlockDemo';
132 | const result = runCode(schema, { inlineStyle: 'inline',});
133 | const file = _.find(result, { panelName:'index.jsx', folder: 'components/BlockDemo'});
134 | expect(file.panelValue.includes(`'./index.css';`)).to.be.equal(false);
135 | });
136 |
137 | });
138 |
139 | describe('cssUnit 单位设置', () => {
140 | it('cssUnit = px', async () => {
141 | const schema = _.cloneDeep(data);
142 | schema.componentName = 'Block';
143 | schema.fileName = 'BlockDemo';
144 | const result = runCode(schema, { inlineStyle: 'import', cssUnit: 'px'});
145 | const cssFile = _.find(result, { panelName:'index.css', folder: 'components/BlockDemo'});
146 | expect(cssFile.panelValue.includes('px')).to.be.equal(true);
147 | expect(cssFile.panelValue.includes('vw')).to.be.equal(false);
148 | expect(cssFile.panelValue.includes('rem')).to.be.equal(false);
149 | });
150 |
151 | it('cssUnit = vw', async () => {
152 | const schema = _.cloneDeep(data);
153 | schema.componentName = 'Block';
154 | schema.fileName = 'BlockDemo';
155 | const result = runCode(schema, { inlineStyle: 'import', cssUnit: 'vw'});
156 | const cssFile = _.find(result, { panelName:'index.css', folder: 'components/BlockDemo'});
157 | expect(cssFile.panelValue.includes('px')).to.be.equal(false);
158 | expect(cssFile.panelValue.includes('vw')).to.be.equal(true);
159 | expect(cssFile.panelValue.includes('rem')).to.be.equal(false);
160 | });
161 |
162 | it('cssUnit = rem', async () => {
163 | const schema = _.cloneDeep(data);
164 | schema.componentName = 'Block';
165 | schema.fileName = 'BlockDemo';
166 | const result = runCode(schema, { inlineStyle: 'import', cssUnit: 'rem'});
167 | const cssFile = _.find(result, { panelName:'index.css', folder: 'components/BlockDemo'});
168 | expect(cssFile.panelValue.includes('px')).to.be.equal(false);
169 | expect(cssFile.panelValue.includes('vw')).to.be.equal(false);
170 | expect(cssFile.panelValue.includes('rem')).to.be.equal(true);
171 | });
172 |
173 |
174 |
175 |
176 | });
177 |
178 |
179 |
--------------------------------------------------------------------------------
/code/style.css:
--------------------------------------------------------------------------------
1 | .mod {
2 | display: flex;
3 | flex-direction: row;
4 | align-items: flex-start;
5 | width: 565px;
6 | height: 623px;
7 | position: relative;
8 | animation-iteration-count: 1;
9 | animation-timing-function: linear;
10 | animation-duration: 1280ms;
11 | animation-name: swing;
12 | }
13 | .primary {
14 | display: flex;
15 | position: relative;
16 | align-items: flex-start;
17 | flex-direction: row;
18 | justify-content: center;
19 | margin-left: 94px;
20 | border-top-left-radius: 18px;
21 | border-top-right-radius: 18px;
22 | background-image: linear-gradient(148deg, #efeded 0%, #b4b4b4 76%);
23 | width: 438px;
24 | height: 461px;
25 | }
26 | .entry-pic {
27 | position: absolute;
28 | bottom: 12px;
29 | left: -14px;
30 | width: 405px;
31 | height: 310px;
32 | }
33 | .action-bg {
34 | position: relative;
35 | margin-top: 13px;
36 | margin-right: 87px;
37 | width: 201px;
38 | height: 76px;
39 | }
40 | .shop-logo {
41 | position: relative;
42 | margin-top: 20px;
43 | width: 106px;
44 | height: 52px;
45 | }
46 | .empty {
47 | position: absolute;
48 | top: 140px;
49 | right: 28px;
50 | width: 437px;
51 | height: 347px;
52 | overflow: hidden;
53 | }
54 | .item-long {
55 | position: absolute;
56 | top: 194px;
57 | left: 113px;
58 | animation-iteration-count: infinite;
59 | animation-timing-function: linear;
60 | animation-duration: 1280ms;
61 | animation-name: swing;
62 | width: 197px;
63 | height: 340px;
64 | }
65 | .product-long {
66 | position: absolute;
67 | top: 157px;
68 | left: 172px;
69 | animation-iteration-count: infinite;
70 | animation-timing-function: ease;
71 | animation-duration: 1280ms;
72 | animation-name: swing;
73 | width: 182px;
74 | height: 354px;
75 | }
76 | .item-long-1 {
77 | position: absolute;
78 | top: 154px;
79 | right: 173px;
80 | animation-iteration-count: infinite;
81 | animation-timing-function: ease;
82 | animation-duration: 1280ms;
83 | animation-name: swing;
84 | width: 179px;
85 | height: 388px;
86 | }
87 | .product-long-1 {
88 | position: absolute;
89 | right: 122px;
90 | bottom: 61px;
91 | animation-iteration-count: infinite;
92 | animation-timing-function: linear;
93 | animation-duration: 1280ms;
94 | animation-name: swing;
95 | width: 230px;
96 | height: 406px;
97 | }
98 | .item-long-2 {
99 | position: absolute;
100 | right: 56px;
101 | bottom: 37px;
102 | animation-iteration-count: infinite;
103 | animation-timing-function: ease;
104 | animation-duration: 1280ms;
105 | animation-name: swing;
106 | width: 302px;
107 | height: 417px;
108 | }
109 | .entry-pic-1 {
110 | position: absolute;
111 | right: 0;
112 | bottom: 20px;
113 | animation-iteration-count: infinite;
114 | animation-timing-function: linear;
115 | animation-duration: 1280ms;
116 | animation-name: swing;
117 | width: 392px;
118 | height: 251px;
119 | }
120 | .layer-wrapper {
121 | display: flex;
122 | position: absolute;
123 | top: 139px;
124 | right: 18px;
125 | align-items: center;
126 | flex-direction: row;
127 | width: 466px;
128 | height: 338px;
129 | }
130 | .layer {
131 | position: absolute;
132 | top: 0;
133 | left: 0;
134 | width: 466px;
135 | height: 338px;
136 | overflow: hidden;
137 | }
138 | .vertical-line {
139 | position: absolute;
140 | top: 1px;
141 | right: -2px;
142 | width: 3px;
143 | height: 309px;
144 | }
145 | .bg {
146 | position: absolute;
147 | top: 138px;
148 | left: 0;
149 | width: 319px;
150 | height: 3px;
151 | }
152 | .product-long-2 {
153 | position: absolute;
154 | top: 139px;
155 | left: 81px;
156 | width: 268px;
157 | height: 378px;
158 | overflow: hidden;
159 | }
160 | .background {
161 | position: absolute;
162 | top: 102px;
163 | right: 18px;
164 | width: 466px;
165 | height: 39px;
166 | }
167 | .wrapper {
168 | display: flex;
169 | position: absolute;
170 | right: 11px;
171 | bottom: 0;
172 | align-items: flex-start;
173 | flex-direction: row;
174 | }
175 | .wrapper-inner {
176 | display: flex;
177 | position: relative;
178 | align-items: center;
179 | flex-direction: row;
180 | margin-top: 17px;
181 | margin-left: 46px;
182 | background-size: contain;
183 | background-image: url(https://img.alicdn.com/imgextra/i2/O1CN01ofNLoD1YmIuIHhBl1_!!6000000003101-2-tps-964-380.png);
184 | height: 190px;
185 | }
186 | .group {
187 | display: flex;
188 | position: relative;
189 | align-items: flex-start;
190 | flex-direction: row;
191 | justify-content: center;
192 | background-color: #141414;
193 | width: 482px;
194 | height: 176px;
195 | overflow: hidden;
196 | }
197 | .entry-pic-2 {
198 | position: absolute;
199 | right: 12px;
200 | bottom: 0;
201 | width: 174px;
202 | height: 119px;
203 | }
204 | .view {
205 | display: flex;
206 | flex-direction: row;
207 | justify-content: center;
208 | align-items: center;
209 | margin-top: 2px;
210 | width: 159px;
211 | height: 40px;
212 | line-height: 26px;
213 | position: absolute;
214 | top: 110px;
215 | left: 29px;
216 | z-index: 10;
217 | background-image: url(https://img.alicdn.com/imgextra/i2/O1CN01A6AUU31FroypE1Fw8_!!6000000000541-2-tps-318-80.png);
218 | background-size: contain;
219 | white-space: nowrap;
220 | }
221 | .title {
222 | margin-top: -2px;
223 | color: #141414;
224 | font-family: PingFang SC;
225 | font-size: 26px;
226 | font-weight: 400;
227 | }
228 | .num {
229 | margin-top: -2px;
230 | color: #141414;
231 | font-family: PingFang SC;
232 | font-size: 26px;
233 | font-weight: 600;
234 | }
235 | .caption {
236 | margin-top: -2px;
237 | color: #141414;
238 | font-family: PingFang SC;
239 | font-size: 26px;
240 | font-weight: 400;
241 | }
242 | .bg-1 {
243 | position: relative;
244 | margin-top: 17px;
245 | width: 367px;
246 | height: 32px;
247 | }
248 | .entry-pic-3 {
249 | position: absolute;
250 | top: 0;
251 | left: 0;
252 | width: 174px;
253 | height: 119px;
254 | }
255 | .wrapper-inner-1 {
256 | display: flex;
257 | position: absolute;
258 | top: 90px;
259 | right: 39px;
260 | align-items: flex-start;
261 | flex-direction: column;
262 | border-width: 2px;
263 | border-style: solid;
264 | border-radius: 47px;
265 | border-color: rgba(0, 0, 0, 0.34);
266 | background-color: rgba(255, 255, 255, 0.1);
267 | width: 405px;
268 | height: 94px;
269 | }
270 | .button-bg-wrapper {
271 | display: flex;
272 | position: absolute;
273 | top: 10px;
274 | align-items: center;
275 | align-self: center;
276 | flex-direction: row;
277 | width: 382px;
278 | height: 74px;
279 | }
280 | .button-bg {
281 | position: absolute;
282 | top: 0;
283 | left: 0;
284 | width: 382px;
285 | height: 74px;
286 | overflow: hidden;
287 | }
288 | .background-1 {
289 | position: absolute;
290 | top: 0;
291 | left: 0;
292 | width: 382px;
293 | height: 49px;
294 | overflow: hidden;
295 | }
296 | .large-icon {
297 | position: absolute;
298 | top: 16px;
299 | right: 150px;
300 | width: 79px;
301 | height: 38px;
302 | }
303 |
304 | @keyframes swing {
305 |
306 | 20% {
307 |
308 | transform: rotate3d(0, 0, 1, 15deg);
309 | }
310 |
311 | 40% {
312 |
313 | transform: rotate3d(0, 0, 1, -10deg);
314 | }
315 |
316 | 60% {
317 |
318 | transform: rotate3d(0, 0, 1, 5deg);
319 | }
320 |
321 | 80% {
322 |
323 | transform: rotate3d(0, 0, 1, -5deg);
324 | }
325 |
326 | 100% {
327 |
328 | transform: rotate3d(0, 0, 1, 0deg);
329 | }
330 |
331 | }
332 |
333 | @keyframes swing {
334 |
335 | 20% {
336 |
337 | transform: rotate3d(0, 0, 1, 15deg);
338 | }
339 |
340 | 40% {
341 |
342 | transform: rotate3d(0, 0, 1, -10deg);
343 | }
344 |
345 | 60% {
346 |
347 | transform: rotate3d(0, 0, 1, 5deg);
348 | }
349 |
350 | 80% {
351 |
352 | transform: rotate3d(0, 0, 1, -5deg);
353 | }
354 |
355 | 100% {
356 |
357 | transform: rotate3d(0, 0, 1, 0deg);
358 | }
359 |
360 | }
361 |
362 | @keyframes swing {
363 |
364 | 20% {
365 |
366 | transform: rotate3d(0, 0, 1, 15deg);
367 | }
368 |
369 | 40% {
370 |
371 | transform: rotate3d(0, 0, 1, -10deg);
372 | }
373 |
374 | 60% {
375 |
376 | transform: rotate3d(0, 0, 1, 5deg);
377 | }
378 |
379 | 80% {
380 |
381 | transform: rotate3d(0, 0, 1, -5deg);
382 | }
383 |
384 | 100% {
385 |
386 | transform: rotate3d(0, 0, 1, 0deg);
387 | }
388 |
389 | }
390 |
391 | @keyframes swing {
392 |
393 | 20% {
394 |
395 | transform: rotate3d(0, 0, 1, 15deg);
396 | }
397 |
398 | 40% {
399 |
400 | transform: rotate3d(0, 0, 1, -10deg);
401 | }
402 |
403 | 60% {
404 |
405 | transform: rotate3d(0, 0, 1, 5deg);
406 | }
407 |
408 | 80% {
409 |
410 | transform: rotate3d(0, 0, 1, -5deg);
411 | }
412 |
413 | 100% {
414 |
415 | transform: rotate3d(0, 0, 1, 0deg);
416 | }
417 |
418 | }
419 |
420 | @keyframes swing {
421 |
422 | 20% {
423 |
424 | transform: rotate3d(0, 0, 1, 15deg);
425 | }
426 |
427 | 40% {
428 |
429 | transform: rotate3d(0, 0, 1, -10deg);
430 | }
431 |
432 | 60% {
433 |
434 | transform: rotate3d(0, 0, 1, 5deg);
435 | }
436 |
437 | 80% {
438 |
439 | transform: rotate3d(0, 0, 1, -5deg);
440 | }
441 |
442 | 100% {
443 |
444 | transform: rotate3d(0, 0, 1, 0deg);
445 | }
446 |
447 | }
448 |
449 | @keyframes swing {
450 |
451 | 20% {
452 |
453 | transform: rotate3d(0, 0, 1, 15deg);
454 | }
455 |
456 | 40% {
457 |
458 | transform: rotate3d(0, 0, 1, -10deg);
459 | }
460 |
461 | 60% {
462 |
463 | transform: rotate3d(0, 0, 1, 5deg);
464 | }
465 |
466 | 80% {
467 |
468 | transform: rotate3d(0, 0, 1, -5deg);
469 | }
470 |
471 | 100% {
472 |
473 | transform: rotate3d(0, 0, 1, 0deg);
474 | }
475 |
476 | }
477 |
478 | @keyframes swing {
479 |
480 | 20% {
481 |
482 | transform: rotate3d(0, 0, 1, 15deg);
483 | }
484 |
485 | 40% {
486 |
487 | transform: rotate3d(0, 0, 1, -10deg);
488 | }
489 |
490 | 60% {
491 |
492 | transform: rotate3d(0, 0, 1, 5deg);
493 | }
494 |
495 | 80% {
496 |
497 | transform: rotate3d(0, 0, 1, -5deg);
498 | }
499 |
500 | 100% {
501 |
502 | transform: rotate3d(0, 0, 1, 0deg);
503 | }
504 |
505 | }
506 |
--------------------------------------------------------------------------------
/code/style.responsive.css:
--------------------------------------------------------------------------------
1 | .mod {
2 | display: flex;
3 | flex-direction: row;
4 | align-items: flex-start;
5 | width: 75.33vw;
6 | height: 83.07vw;
7 | position: relative;
8 | animation-iteration-count: 1;
9 | animation-timing-function: linear;
10 | animation-duration: 1280ms;
11 | animation-name: swing;
12 | }
13 | .primary {
14 | display: flex;
15 | position: relative;
16 | align-items: flex-start;
17 | flex-direction: row;
18 | justify-content: center;
19 | margin-left: 12.53vw;
20 | border-top-left-radius: 2.4vw;
21 | border-top-right-radius: 2.4vw;
22 | background-image: linear-gradient(148deg, #efeded 0%, #b4b4b4 76%);
23 | width: 58.4vw;
24 | height: 61.47vw;
25 | }
26 | .entry-pic {
27 | position: absolute;
28 | bottom: 1.6vw;
29 | left: -1.87vw;
30 | width: 54vw;
31 | height: 41.33vw;
32 | }
33 | .action-bg {
34 | position: relative;
35 | margin-top: 1.73vw;
36 | margin-right: 11.6vw;
37 | width: 26.8vw;
38 | height: 10.13vw;
39 | }
40 | .shop-logo {
41 | position: relative;
42 | margin-top: 2.67vw;
43 | width: 14.13vw;
44 | height: 6.93vw;
45 | }
46 | .empty {
47 | position: absolute;
48 | top: 18.67vw;
49 | right: 3.73vw;
50 | width: 58.27vw;
51 | height: 46.27vw;
52 | overflow: hidden;
53 | }
54 | .item-long {
55 | position: absolute;
56 | top: 25.87vw;
57 | left: 15.07vw;
58 | animation-iteration-count: infinite;
59 | animation-timing-function: linear;
60 | animation-duration: 1280ms;
61 | animation-name: swing;
62 | width: 26.27vw;
63 | height: 45.33vw;
64 | }
65 | .product-long {
66 | position: absolute;
67 | top: 20.93vw;
68 | left: 22.93vw;
69 | animation-iteration-count: infinite;
70 | animation-timing-function: ease;
71 | animation-duration: 1280ms;
72 | animation-name: swing;
73 | width: 24.27vw;
74 | height: 47.2vw;
75 | }
76 | .item-long-1 {
77 | position: absolute;
78 | top: 20.53vw;
79 | right: 23.07vw;
80 | animation-iteration-count: infinite;
81 | animation-timing-function: ease;
82 | animation-duration: 1280ms;
83 | animation-name: swing;
84 | width: 23.87vw;
85 | height: 51.73vw;
86 | }
87 | .product-long-1 {
88 | position: absolute;
89 | right: 16.27vw;
90 | bottom: 8.13vw;
91 | animation-iteration-count: infinite;
92 | animation-timing-function: linear;
93 | animation-duration: 1280ms;
94 | animation-name: swing;
95 | width: 30.67vw;
96 | height: 54.13vw;
97 | }
98 | .item-long-2 {
99 | position: absolute;
100 | right: 7.47vw;
101 | bottom: 4.93vw;
102 | animation-iteration-count: infinite;
103 | animation-timing-function: ease;
104 | animation-duration: 1280ms;
105 | animation-name: swing;
106 | width: 40.27vw;
107 | height: 55.6vw;
108 | }
109 | .entry-pic-1 {
110 | position: absolute;
111 | right: 0;
112 | bottom: 2.67vw;
113 | animation-iteration-count: infinite;
114 | animation-timing-function: linear;
115 | animation-duration: 1280ms;
116 | animation-name: swing;
117 | width: 52.27vw;
118 | height: 33.47vw;
119 | }
120 | .layer-wrapper {
121 | display: flex;
122 | position: absolute;
123 | top: 18.53vw;
124 | right: 2.4vw;
125 | align-items: center;
126 | flex-direction: row;
127 | width: 62.13vw;
128 | height: 45.07vw;
129 | }
130 | .layer {
131 | position: absolute;
132 | top: 0;
133 | left: 0;
134 | width: 62.13vw;
135 | height: 45.07vw;
136 | overflow: hidden;
137 | }
138 | .vertical-line {
139 | position: absolute;
140 | top: 0.13vw;
141 | right: -0.27vw;
142 | width: 0.4vw;
143 | height: 41.2vw;
144 | }
145 | .bg {
146 | position: absolute;
147 | top: 18.4vw;
148 | left: 0;
149 | width: 42.53vw;
150 | height: 0.4vw;
151 | }
152 | .product-long-2 {
153 | position: absolute;
154 | top: 18.53vw;
155 | left: 10.8vw;
156 | width: 35.73vw;
157 | height: 50.4vw;
158 | overflow: hidden;
159 | }
160 | .background {
161 | position: absolute;
162 | top: 13.6vw;
163 | right: 2.4vw;
164 | width: 62.13vw;
165 | height: 5.2vw;
166 | }
167 | .wrapper {
168 | display: flex;
169 | position: absolute;
170 | right: 1.47vw;
171 | bottom: 0;
172 | align-items: flex-start;
173 | flex-direction: row;
174 | }
175 | .wrapper-inner {
176 | display: flex;
177 | position: relative;
178 | align-items: center;
179 | flex-direction: row;
180 | margin-top: 2.27vw;
181 | margin-left: 6.13vw;
182 | background-size: contain;
183 | background-image: url(https://img.alicdn.com/imgextra/i2/O1CN01ofNLoD1YmIuIHhBl1_!!6000000003101-2-tps-964-380.png);
184 | height: 25.33vw;
185 | }
186 | .group {
187 | display: flex;
188 | position: relative;
189 | align-items: flex-start;
190 | flex-direction: row;
191 | justify-content: center;
192 | background-color: #141414;
193 | width: 64.27vw;
194 | height: 23.47vw;
195 | overflow: hidden;
196 | }
197 | .entry-pic-2 {
198 | position: absolute;
199 | right: 1.6vw;
200 | bottom: 0;
201 | width: 23.2vw;
202 | height: 15.87vw;
203 | }
204 | .view {
205 | display: flex;
206 | flex-direction: row;
207 | justify-content: center;
208 | align-items: center;
209 | margin-top: 0.27vw;
210 | width: 21.2vw;
211 | height: 5.33vw;
212 | line-height: 3.47vw;
213 | position: absolute;
214 | top: 14.67vw;
215 | left: 3.87vw;
216 | z-index: 10;
217 | background-image: url(https://img.alicdn.com/imgextra/i2/O1CN01A6AUU31FroypE1Fw8_!!6000000000541-2-tps-318-80.png);
218 | background-size: contain;
219 | white-space: nowrap;
220 | }
221 | .title {
222 | margin-top: -0.27vw;
223 | color: #141414;
224 | font-family: PingFang SC;
225 | font-size: 3.47vw;
226 | font-weight: 400;
227 | }
228 | .num {
229 | margin-top: -0.27vw;
230 | color: #141414;
231 | font-family: PingFang SC;
232 | font-size: 3.47vw;
233 | font-weight: 600;
234 | }
235 | .caption {
236 | margin-top: -0.27vw;
237 | color: #141414;
238 | font-family: PingFang SC;
239 | font-size: 3.47vw;
240 | font-weight: 400;
241 | }
242 | .bg-1 {
243 | position: relative;
244 | margin-top: 2.27vw;
245 | width: 48.93vw;
246 | height: 4.27vw;
247 | }
248 | .entry-pic-3 {
249 | position: absolute;
250 | top: 0;
251 | left: 0;
252 | width: 23.2vw;
253 | height: 15.87vw;
254 | }
255 | .wrapper-inner-1 {
256 | display: flex;
257 | position: absolute;
258 | top: 12vw;
259 | right: 5.2vw;
260 | align-items: flex-start;
261 | flex-direction: column;
262 | border-width: 2px;
263 | border-style: solid;
264 | border-radius: 6.27vw;
265 | border-color: rgba(0, 0, 0, 0.34);
266 | background-color: rgba(255, 255, 255, 0.1);
267 | width: 54vw;
268 | height: 12.53vw;
269 | }
270 | .button-bg-wrapper {
271 | display: flex;
272 | position: absolute;
273 | top: 1.33vw;
274 | align-items: center;
275 | align-self: center;
276 | flex-direction: row;
277 | width: 50.93vw;
278 | height: 9.87vw;
279 | }
280 | .button-bg {
281 | position: absolute;
282 | top: 0;
283 | left: 0;
284 | width: 50.93vw;
285 | height: 9.87vw;
286 | overflow: hidden;
287 | }
288 | .background-1 {
289 | position: absolute;
290 | top: 0;
291 | left: 0;
292 | width: 50.93vw;
293 | height: 6.53vw;
294 | overflow: hidden;
295 | }
296 | .large-icon {
297 | position: absolute;
298 | top: 2.13vw;
299 | right: 20vw;
300 | width: 10.53vw;
301 | height: 5.07vw;
302 | }
303 |
304 | @keyframes swing {
305 |
306 | 20% {
307 |
308 | transform: rotate3d(0, 0, 1, 15deg);
309 | }
310 |
311 | 40% {
312 |
313 | transform: rotate3d(0, 0, 1, -10deg);
314 | }
315 |
316 | 60% {
317 |
318 | transform: rotate3d(0, 0, 1, 5deg);
319 | }
320 |
321 | 80% {
322 |
323 | transform: rotate3d(0, 0, 1, -5deg);
324 | }
325 |
326 | 100% {
327 |
328 | transform: rotate3d(0, 0, 1, 0deg);
329 | }
330 |
331 | }
332 |
333 | @keyframes swing {
334 |
335 | 20% {
336 |
337 | transform: rotate3d(0, 0, 1, 15deg);
338 | }
339 |
340 | 40% {
341 |
342 | transform: rotate3d(0, 0, 1, -10deg);
343 | }
344 |
345 | 60% {
346 |
347 | transform: rotate3d(0, 0, 1, 5deg);
348 | }
349 |
350 | 80% {
351 |
352 | transform: rotate3d(0, 0, 1, -5deg);
353 | }
354 |
355 | 100% {
356 |
357 | transform: rotate3d(0, 0, 1, 0deg);
358 | }
359 |
360 | }
361 |
362 | @keyframes swing {
363 |
364 | 20% {
365 |
366 | transform: rotate3d(0, 0, 1, 15deg);
367 | }
368 |
369 | 40% {
370 |
371 | transform: rotate3d(0, 0, 1, -10deg);
372 | }
373 |
374 | 60% {
375 |
376 | transform: rotate3d(0, 0, 1, 5deg);
377 | }
378 |
379 | 80% {
380 |
381 | transform: rotate3d(0, 0, 1, -5deg);
382 | }
383 |
384 | 100% {
385 |
386 | transform: rotate3d(0, 0, 1, 0deg);
387 | }
388 |
389 | }
390 |
391 | @keyframes swing {
392 |
393 | 20% {
394 |
395 | transform: rotate3d(0, 0, 1, 15deg);
396 | }
397 |
398 | 40% {
399 |
400 | transform: rotate3d(0, 0, 1, -10deg);
401 | }
402 |
403 | 60% {
404 |
405 | transform: rotate3d(0, 0, 1, 5deg);
406 | }
407 |
408 | 80% {
409 |
410 | transform: rotate3d(0, 0, 1, -5deg);
411 | }
412 |
413 | 100% {
414 |
415 | transform: rotate3d(0, 0, 1, 0deg);
416 | }
417 |
418 | }
419 |
420 | @keyframes swing {
421 |
422 | 20% {
423 |
424 | transform: rotate3d(0, 0, 1, 15deg);
425 | }
426 |
427 | 40% {
428 |
429 | transform: rotate3d(0, 0, 1, -10deg);
430 | }
431 |
432 | 60% {
433 |
434 | transform: rotate3d(0, 0, 1, 5deg);
435 | }
436 |
437 | 80% {
438 |
439 | transform: rotate3d(0, 0, 1, -5deg);
440 | }
441 |
442 | 100% {
443 |
444 | transform: rotate3d(0, 0, 1, 0deg);
445 | }
446 |
447 | }
448 |
449 | @keyframes swing {
450 |
451 | 20% {
452 |
453 | transform: rotate3d(0, 0, 1, 15deg);
454 | }
455 |
456 | 40% {
457 |
458 | transform: rotate3d(0, 0, 1, -10deg);
459 | }
460 |
461 | 60% {
462 |
463 | transform: rotate3d(0, 0, 1, 5deg);
464 | }
465 |
466 | 80% {
467 |
468 | transform: rotate3d(0, 0, 1, -5deg);
469 | }
470 |
471 | 100% {
472 |
473 | transform: rotate3d(0, 0, 1, 0deg);
474 | }
475 |
476 | }
477 |
478 | @keyframes swing {
479 |
480 | 20% {
481 |
482 | transform: rotate3d(0, 0, 1, 15deg);
483 | }
484 |
485 | 40% {
486 |
487 | transform: rotate3d(0, 0, 1, -10deg);
488 | }
489 |
490 | 60% {
491 |
492 | transform: rotate3d(0, 0, 1, 5deg);
493 | }
494 |
495 | 80% {
496 |
497 | transform: rotate3d(0, 0, 1, -5deg);
498 | }
499 |
500 | 100% {
501 |
502 | transform: rotate3d(0, 0, 1, 0deg);
503 | }
504 |
505 | }
506 |
--------------------------------------------------------------------------------
/src/core/exportBlock.ts:
--------------------------------------------------------------------------------
1 | import { IPanelDisplay, IImport, IDependence } from './interface';
2 | import {
3 | toString,
4 | existImport,
5 | importString,
6 | parseLoop,
7 | parseStyle,
8 | parseFunction,
9 | parseProps,
10 | parseState,
11 | parseLifeCycles,
12 | replaceState,
13 | parseCondition,
14 | generateCSS,
15 | generateScss,
16 | parseDataSource,
17 | line2Hump,
18 | addAnimation,
19 | traverse,
20 | isObject,
21 | isJSSlot,
22 | } from './utils';
23 |
24 | import { CSS_TYPE, OUTPUT_TYPE, prettierJsOpt, prettierCssOpt, prettierLessOpt, prettierScssOpt, DSL_CONFIG } from './consts';
25 |
26 |
27 | export default function exportMod(schema, option):IPanelDisplay[] {
28 | const {
29 | prettier,
30 | scale,
31 | componentsMap,
32 | folder,
33 | blocksCount,
34 | pagesCount,
35 | blockInPage,
36 | dslConfig = {},
37 | pageGlobalCss,
38 | _,
39 | } = option;
40 |
41 | const isExportGlobalFile = dslConfig.globalCss && blocksCount == 1 && !blockInPage;
42 | const fileName = schema.fileName;
43 | const { cssUnit } = dslConfig;
44 | const rootSchema = schema;
45 |
46 | let folderName;
47 | let filePathName = 'index';
48 | if(schema.componentName == 'Page'){
49 | // 单页面
50 | // if(pagesCount == 1){
51 | // folderName = '';
52 | // }else{
53 | // folderName = 'pages/' + schema.fileName;
54 | // }
55 | // folderName = 'pages/' + schema.fileName;
56 | folderName = '';
57 | if(dslConfig.outputStyle == OUTPUT_TYPE.PROJECT){
58 | filePathName = 'App';
59 | }
60 |
61 | // filePathName = schema.fileName
62 | }else{
63 | folderName = pagesCount == 0 && blocksCount == 1 && dslConfig.outputStyle !== OUTPUT_TYPE.PROJECT? '' : ('components/' + schema.fileName);
64 | }
65 | schema.folderName = folderName;
66 |
67 | const globalCss = pageGlobalCss + '\n' + (schema.css || '');
68 |
69 | // imports
70 | const dependenceList: IDependence[] = []
71 |
72 | // imports mods
73 | const importMods: string[] = [];
74 |
75 | // import css
76 | const importStyles: string[] = [];
77 |
78 | const importsMap = new Map();
79 |
80 | // inline style
81 | const style = {};
82 |
83 | // Global Public Functions
84 | const utils: string[] = [];
85 |
86 | // states
87 | let statesData = null;
88 |
89 | // useState
90 | let useState: string[] = [];
91 |
92 | // calsses
93 | let classes: string[] = [];
94 |
95 | // methods
96 | const methods: string[] = [];
97 |
98 | // life cycles
99 | let lifeCycles: string[] = [];
100 |
101 | // init
102 | const init: string[] = [];
103 |
104 | const cssFileName = `${filePathName}${dslConfig.inlineStyle == CSS_TYPE.MODULE_CLASS ? '.module' : ''}.${dslConfig.cssType || 'css'}`
105 |
106 |
107 | if (dslConfig.inlineStyle !== CSS_TYPE.INLINE_CSS) {
108 | if (isExportGlobalFile) {
109 | importStyles.push(`import './global.css';`);
110 | }
111 | if (dslConfig.inlineStyle == CSS_TYPE.IMPORT_CLASS) {
112 | importStyles.push(`import './${cssFileName}';`);
113 | } else {
114 | importStyles.push(`import styles from './${cssFileName}';`);
115 | }
116 | }
117 |
118 | const collectImports = (componentName) => {
119 | // ignore the empty string
120 | if (!componentName) {
121 | return;
122 | }
123 |
124 | const component = componentsMap[componentName];
125 | if(!component){
126 | return
127 | }
128 | const objSets = importsMap.get(component.packageName);
129 |
130 | if (!objSets) {
131 | const set = new Set();
132 | set.add(component);
133 | importsMap.set(component.packageName, set);
134 | } else {
135 | objSets.add(component);
136 | }
137 |
138 | if(!dependenceList.find(i=>i.package == component.packageName)){
139 | dependenceList.push({
140 | package: component.packageName,
141 | version: component.dependenceVersion || '*',
142 | });
143 | }
144 |
145 | };
146 |
147 |
148 | // generate render xml
149 | /**
150 | *
151 | * @param {*} json
152 | * @param {*} isReplace 是否提取 block
153 | * @returns
154 | */
155 | const generateRender = (json, isReplace = false): string => {
156 | if(typeof json == 'string'){
157 | return json
158 | }
159 | if(Array.isArray(json)){
160 | return (json.map(item=>{
161 | return generateRender(item, isReplace)
162 | })).join('')
163 | }
164 | const componentName = json.componentName;
165 | const type = json.componentName.toLowerCase();
166 | let className = json.props && json.props.className;
167 | let classString = json.classString || '';
168 |
169 | if (className) {
170 | style[className] = parseStyle(json.props.style);
171 | }
172 |
173 | let xml;
174 | let props = '';
175 |
176 | Object.keys(json.props).forEach((key) => {
177 | if (key === 'codeStyle') {
178 | if (json.props[key] && JSON.stringify(json.props[key]) !== '{}') {
179 | props += ` style={${parseProps(json.props[key])}}`;
180 | }
181 | }
182 |
183 | if (
184 | ['className', 'style', 'text', 'src', 'key', 'codeStyle'].indexOf(
185 | key
186 | ) === -1
187 | ) {
188 | props += ` ${key}={${parseProps(json.props[key])}}`;
189 | }
190 |
191 | // fix attr when type is not text
192 | if (type !== 'text' && ['text'].includes(key)) {
193 | props += ` ${key}={${parseProps(json.props[key])}}`;
194 | }
195 |
196 | });
197 |
198 | switch (type) {
199 | case 'text':
200 | let innerText =
201 | parseProps(json.props.text || json.text, true) || '';
202 | if (innerText.match(/this\.props/)) {
203 | innerText = innerText.replace(/this\./, '');
204 | }
205 | xml = `${innerText || ''} `;
206 | break;
207 | case 'image':
208 | let source = parseProps(json.props.src);
209 | source = (source && `src={${source}}`) || '';
210 | xml = ` `;
211 | break;
212 |
213 | case 'page':
214 | case 'block':
215 | case 'component':
216 | if (isReplace) {
217 | const compName = json.fileName;
218 | xml = `<${compName} />`;
219 | // 当前是 Page 模块
220 | const compPath = rootSchema.componentName == 'Page' ? './components' : '..';
221 | if(compName){
222 | importMods.push(`import ${compName} from '${compPath}/${compName}';`);
223 | }
224 | delete style[className]
225 | } else if (json.children && json.children.length) {
226 | xml = `${json.children
227 | .map((node) => {
228 | return generateRender(node, true);
229 | })
230 | .join('')}
`;
231 | } else {
232 | xml = `
`;
233 | }
234 | break;
235 | case 'div':
236 | case 'view':
237 | if (json.children && json.children.length) {
238 | xml = `${json.children
239 | .map((node) => {
240 | return generateRender(node, true);
241 | })
242 | .join('')}
`;
243 | } else {
244 | xml = `
`;
245 | }
246 | break;
247 | default:
248 | if(componentName){
249 | collectImports(componentName);
250 | if (
251 | json.children &&
252 | json.children.length &&
253 | Array.isArray(json.children)
254 | ) {
255 |
256 | xml = `<${componentName} ${classString} ${props}>${json.children
257 | .map((node) => {
258 | return generateRender(node, true);
259 | })
260 | .join('')}${componentName}>`;
261 |
262 | } else if (typeof json.children === 'string') {
263 | xml = `<${componentName} ${classString} ${props} >${json.children}${componentName}>`;
264 | } else {
265 | xml = `<${componentName} ${classString} ${props} />`;
266 | }
267 | }else{
268 | xml = ''
269 | }
270 | }
271 |
272 | if (json.loop) {
273 | const parseLoopData = parseLoop(
274 | json.loop,
275 | json.loopArgs,
276 | xml,
277 | {}
278 | );
279 | xml = parseLoopData.value;
280 |
281 | useState = useState.concat(parseLoopData.hookState);
282 | }
283 |
284 | xml = replaceState(xml);
285 |
286 | if (json.condition) {
287 | xml = parseCondition(json.condition, xml);
288 | }
289 | if (json.loop || json.condition) {
290 | xml = `{${xml}}`;
291 | }
292 | return xml;
293 | };
294 |
295 |
296 | // parse schema
297 | const transformHooks = (json) => {
298 | if(typeof json == 'string'){
299 | return json
300 | }
301 | let result = '';
302 | const blockName = json.fileName || json.id;
303 | const type = json.componentName.toLowerCase();
304 |
305 | // 容器组件处理: state/method/dataSource/lifeCycle
306 | const states: string[] = [];
307 |
308 | if (json.state) {
309 | states.push(`state = ${toString(json.state)};`);
310 | statesData = toString(json.state);
311 | }
312 |
313 | if (json.methods) {
314 | Object.keys(json.methods).forEach((name) => {
315 | const { params, content } = parseFunction(json.methods[name]);
316 | methods.push(`function ${name}(${params}) {${content}}`);
317 | });
318 | }
319 |
320 | if (json.dataSource && Array.isArray(json.dataSource.list)) {
321 | json.dataSource.list.forEach((item) => {
322 | if (typeof item.isInit === 'boolean' && item.isInit) {
323 | init.push(`${item.id}();`);
324 | } else if (typeof item.isInit === 'string') {
325 | init.push(`if (${parseProps(item.isInit)}) { ${item.id}(); }`);
326 | }
327 | const parseDataSourceData = parseDataSource(item);
328 | methods.push(
329 | `const ${parseDataSourceData.functionName} = ()=> ${parseDataSourceData.functionBody}`
330 | );
331 | });
332 |
333 | if (json.dataSource.dataHandler) {
334 | const { params, content } = parseFunction(
335 | json.dataSource.dataHandler
336 | );
337 | methods.push(`const dataHandler = (${params}) => {${content}}`);
338 | init.push(`dataHandler()`);
339 | }
340 | }
341 |
342 | if (json.lifeCycles) {
343 | lifeCycles = parseLifeCycles(json, init);
344 | }
345 |
346 | if (statesData) {
347 | useState.push(parseState(statesData));
348 | }
349 |
350 | const hooksView = generateRender(json, false);
351 | const hasDispatch = hooksView.match('dispatch');
352 |
353 | const classData = `
354 | export default memo((props) => {
355 | ${useState.join('\n')}
356 | ${
357 | hasDispatch
358 | ? 'const { state: { txt }, dispatch} = useContext(IndexContext);'
359 | : ''
360 | }
361 |
362 | ${methods.join('\n')}
363 | ${lifeCycles.join('\n')}
364 | ${
365 | hooksView.match(/^\{true\ \&\& /)
366 | ? `return (${hooksView} )`
367 | : `return (${hooksView})`
368 | }
369 | });
370 | `;
371 | classes.push(classData);
372 |
373 |
374 |
375 | return result;
376 | };
377 |
378 | const transformComponent = (json) => {
379 | if(typeof json == 'string'){
380 | return json
381 | }
382 | let result: string = '';
383 | const type = json.componentName.toLowerCase();
384 |
385 | if (['page', 'block', 'component'].includes(type)) {
386 | // 容器组件处理: state/method/dataSource/lifeCycle/render
387 | const states: string[] = [];
388 | const lifeCycles: string[] = [];
389 | const methods: string[] = [];
390 | const init: string[] = [];
391 |
392 | let render = '';
393 | let classData: string = '';
394 |
395 | if (json.state) {
396 | states.push(`this.state = ${toString(json.state)};`);
397 | }
398 |
399 | if (json.methods) {
400 | Object.keys(json.methods).forEach((name) => {
401 | const { params, content } = parseFunction(json.methods[name]);
402 | methods.push(`${name}(${params}) {${content}}`);
403 | });
404 | }
405 |
406 | if (json.dataSource && Array.isArray(json.dataSource.list)) {
407 | json.dataSource.list.forEach((item) => {
408 | if (typeof item.isInit === 'boolean' && item.isInit) {
409 | init.push(`this.${item.id}();`);
410 | } else if (typeof item.isInit === 'string') {
411 | init.push(`if (${parseProps(item.isInit)}) { this.${item.id}(); }`);
412 | }
413 | const parseDataSourceData = parseDataSource(item);
414 | methods.push(
415 | `${parseDataSourceData.functionName}()${parseDataSourceData.functionBody}`
416 | );
417 | });
418 |
419 | if (json.dataSource.dataHandler) {
420 | const { params, content } = parseFunction(
421 | json.dataSource.dataHandler
422 | );
423 | methods.push(`dataHandler(${params}) {${content}}`);
424 | init.push(`this.dataHandler()`);
425 | }
426 | }
427 |
428 |
429 | if (!json.lifeCycles) {
430 | json.lifeCycles = {};
431 | }
432 |
433 | if (!json.lifeCycles['_constructor']) {
434 | lifeCycles.push(
435 | `constructor(props, context) { super(); ${states.join('\n')} ${init.join('\n')}}`
436 | );
437 | }
438 |
439 | Object.keys(json.lifeCycles).forEach((name) => {
440 | const { params, content } = parseFunction(json.lifeCycles[name]);
441 |
442 | if (name === '_constructor') {
443 | lifeCycles.push(
444 | `constructor(${params}) { super(); ${content} ${states.join('\n')} ${init.join('\n')}}`
445 | );
446 | } else {
447 | lifeCycles.push(`${name}(${params}) {${content}}`);
448 | }
449 | });
450 |
451 | render = generateRender(json, false);
452 |
453 | classData = `
454 | export default class ${json.fileName} extends Component {
455 | ${lifeCycles.join('\n')}
456 | ${methods.join('\n')}
457 | render(){
458 | const state = this.state;
459 | return (${render});}
460 |
461 | }
462 | `;
463 |
464 | classes.push(classData);
465 | } else {
466 | result += generateRender(json);
467 | }
468 |
469 | return result;
470 | };
471 |
472 |
473 | const transform = dslConfig.useHooks
474 | ? transformHooks
475 | : transformComponent;
476 |
477 | // option.utils
478 | if (option.utils) {
479 | Object.keys(option.utils).forEach((name) => {
480 | utils.push(`const ${name} = ${option.utils[name]}`);
481 | });
482 | }
483 |
484 | // parse schema
485 |
486 |
487 | traverse(schema, (node) => {
488 | const traverseProps = (value: any) => {
489 | console.log('traverseProps', value)
490 | if (value === null) {
491 | return null
492 | }
493 | if (Array.isArray(value)) {
494 | return value.map(item => traverseProps(item))
495 | }
496 | if (!isObject(value)) return value
497 | if (isJSSlot(value)) {
498 | value.jsx = generateRender(value.value as unknown)
499 | } else {
500 | Object.keys(value).forEach(key => {
501 | value[key] = traverseProps(value[key])
502 | })
503 | }
504 | return value
505 | }
506 |
507 | traverseProps(node)
508 | });
509 |
510 | // start parse schema
511 | transform(schema);
512 | let indexValue = '';
513 |
514 | const imports: string[] = importString(importsMap);
515 |
516 | if (dslConfig.useHooks) {
517 | // const hooksView = generateRender(schema);
518 | // const hasDispatch = hooksView.match('dispatch');
519 | indexValue = `
520 | 'use strict';
521 | import React, { useState, useEffect, memo } from 'react';
522 |
523 | ${imports.join('\n')}
524 | ${importMods.join('\n')}
525 |
526 | ${importStyles.map((i) => i).join('\n')}
527 | ${utils.join('\n')}
528 |
529 | ${classes.join('\n')}
530 |
531 | `;
532 | } else {
533 | indexValue = `
534 | 'use strict';
535 | import React, { Component} from 'react';
536 |
537 | ${imports.join('\n')}
538 | ${importMods.join('\n')}
539 | ${importStyles.map((i) => i).join('\n')}
540 |
541 | ${utils.join('\n')}
542 | ${classes.join('\n')}
543 | `;
544 | }
545 |
546 | const prefix = dslConfig.inlineStyle
547 | ? ''
548 | : schema.props && schema.props.className;
549 |
550 | // 获取当前 节点 所有 动画参数
551 | const animationKeyframes = addAnimation(schema);
552 |
553 | const panelDisplay: IPanelDisplay[] = [
554 | {
555 | panelName: `${filePathName}.${dslConfig.useTypescript?'tsx': 'jsx'}`,
556 | panelValue: prettier.format(indexValue, prettierJsOpt),
557 | panelType: dslConfig.useTypescript?'tsx': 'jsx',
558 | folder: folderName,
559 | panelDependencies: dependenceList,
560 | },
561 | ];
562 |
563 | // 非内联模式 才引入 index.module.css
564 | if (dslConfig.inlineStyle !== CSS_TYPE.INLINE_CSS) {
565 |
566 | let cssPanelValue = generateCSS(schema.commonStyles, '')
567 | switch (dslConfig.cssType) {
568 | case 'less':
569 | cssPanelValue = prettier.format(
570 | `${cssPanelValue}${generateScss(schema)} ${animationKeyframes}`,
571 | prettierLessOpt
572 | );
573 | break;
574 | case 'scss':
575 | cssPanelValue = prettier.format(
576 | `${cssPanelValue}${generateScss(schema)} ${animationKeyframes}`,
577 | prettierScssOpt
578 | );
579 | break;
580 | default:
581 | cssPanelValue = prettier.format(
582 | `${cssPanelValue}${generateCSS(style, prefix)} ${animationKeyframes}`,
583 | prettierCssOpt
584 | )
585 | }
586 | panelDisplay.push({
587 | panelName: cssFileName,
588 | panelValue: cssPanelValue,
589 | panelType: dslConfig.cssType || 'css',
590 | folder: folderName,
591 | });
592 |
593 | }
594 |
595 | // 只有一个模块时,生成到当前模块
596 | if (isExportGlobalFile && schema.css) {
597 | panelDisplay.push({
598 | panelName: `global.css`,
599 | panelValue: prettier.format(schema.css || '', prettierCssOpt),
600 | panelType: 'css',
601 | folder: folderName,
602 | });
603 | }
604 |
605 | return panelDisplay;
606 | }
607 |
608 |
--------------------------------------------------------------------------------
/src/entry_back.js:
--------------------------------------------------------------------------------
1 | /**
2 | * transform the componentsMap to real Map from compsMap.list as array
3 | * @param {*} compsMap
4 | */
5 | const transComponentsMap = (compsMap = {}) => {
6 | if (!compsMap || !Array.isArray(compsMap.list)) {
7 | return [];
8 | }
9 | const list = compsMap.list;
10 | return list.reduce((obj, comp) => {
11 | const componentName = comp.name;
12 | if (!obj[componentName]) {
13 | if (comp.dependence) {
14 | try {
15 | let dependence = typeof comp.dependence === 'string' ? JSON.parse(comp.dependence) : comp.dependence;
16 | if (dependence) {
17 | comp.packageName = dependence.package;
18 | comp.dependence = dependence;
19 | }
20 | if (!comp.dependenceVersion) {
21 | comp.dependenceVersion = '*';
22 | }
23 | comp.exportName = dependence.export_name;
24 | comp.subName = dependence.sub_name;
25 | if (/^\d/.test(comp.dependenceVersion)) {
26 | comp.dependenceVersion = '^' + comp.dependenceVersion;
27 | }
28 | } catch (e) {
29 | console.log(e);
30 | }
31 | }
32 | obj[componentName] = comp;
33 | }
34 | return obj;
35 | }, {});
36 | };
37 |
38 | module.exports = function(schema, option) {
39 | const { _, prettier } = option;
40 | componentsMap = transComponentsMap(option.componentsMap);
41 | // imports, the key is the package name, the value is a set includes the component objects
42 | const imports = new Map();
43 | const importsExt = [];
44 |
45 | // inline style
46 | const style = {};
47 |
48 | // Global Public Functions
49 | const utils = [];
50 |
51 | // Classes
52 | const classes = [];
53 |
54 | // 1vw = width / 100
55 | const _w = (option.responsive.width / 100) || 750;
56 |
57 | let pageLock = false;
58 |
59 | const isExpression = (value) => {
60 | return /^\{\{.*\}\}$/.test(value);
61 | }
62 |
63 | const toString = (value) => {
64 | if ({}.toString.call(value) === '[object Function]') {
65 | return value.toString();
66 | }
67 | if (typeof value === 'string') {
68 | return value;
69 | }
70 | if (typeof value === 'object') {
71 | return JSON.stringify(value, (key, value) => {
72 | if (typeof value === 'function') {
73 | return value.toString();
74 | } else {
75 | return value;
76 | }
77 | })
78 | }
79 |
80 | return String(value);
81 | };
82 |
83 | // flexDirection -> flex-direction
84 | const parseCamelToLine = (string) => {
85 | return string.split(/(?=[A-Z])/).join('-').toLowerCase();
86 | }
87 |
88 | /**
89 | * constrcut the import string
90 | */
91 | const importString = () => {
92 | const importStrings = [];
93 | const subImports = [];
94 | for (const [ packageName, pkgSet ] of imports) {
95 | const set1 = new Set(), set2 = new Set();
96 | for (const pkg of pkgSet) {
97 | let exportName = pkg.exportName;
98 | let subName = pkg.subName;
99 | let componentName = pkg.name;
100 |
101 | if (pkg.subName) {
102 | subImports.push(`const ${componentName} = ${exportName}.${subName};`);
103 | }
104 | if (componentName !== exportName && !pkg.subName) {
105 | exportName = `${exportName} as ${componentName}`;
106 | }
107 | if (!pkg.dependence.destructuring) {
108 | set1.add(exportName);
109 | } else {
110 | set2.add(exportName);
111 | }
112 | }
113 | const set1Str = [ ...set1 ].join(',');
114 | let set2Str = [ ...set2 ].join(',');
115 | const dot = set1Str && set2Str ? ',' : '';
116 | if (set2Str) {
117 | set2Str = `{${set2Str}}`;
118 | }
119 | importStrings.push(`import ${set1Str} ${dot} ${set2Str} from '${packageName}'`);
120 | }
121 | return importStrings.concat(subImports);
122 | }
123 |
124 | /**
125 | * store the components to the 'imports' map which was used
126 | *
127 | * @param {*} componentName component name like 'Button'
128 | */
129 | const generateImport = (componentName) => {
130 | // ignore the empty string
131 | if (!componentName) {
132 | return;
133 | }
134 | const component = componentsMap[componentName];
135 | if (component) {
136 | const objSets = imports.get(component.packageName);
137 | if (!objSets) {
138 | const set = new Set();
139 | set.add(component);
140 | imports.set(component.packageName, set);
141 | } else {
142 | objSets.add(component);
143 | }
144 | return;
145 | }
146 | };
147 |
148 | // className structure support
149 | const generateLess = (schema, style) => {
150 | let less = '';
151 |
152 | function walk(json) {
153 | if (json.props && json.props.className) {
154 | let className = json.props.className;
155 | less += `.${className} {`;
156 |
157 | for (let key in style[className]) {
158 | less += `${parseCamelToLine(key)}: ${style[className][key]};\n`
159 | }
160 | }
161 | if (json.children && json.children.length > 0 && Array.isArray(json.children)) {
162 | json.children.forEach(child => walk(child));
163 | }
164 |
165 | if (json.props && json.props.className) {
166 | less += '}';
167 | }
168 | }
169 |
170 | walk(schema);
171 |
172 | return less;
173 | };
174 |
175 | const generateCss = (style, toVW) => {
176 | let css = '';
177 | Object.keys(style).map((key) => {
178 | css +=`.${key}{${formatStyle(style[key], toVW)}}`
179 | });
180 | return css;
181 | }
182 |
183 | // box relative style
184 | const boxStyleList = ['fontSize', 'marginTop', 'marginBottom', 'paddingTop', 'paddingBottom', 'height', 'top', 'bottom', 'width', 'maxWidth', 'left', 'right', 'paddingRight', 'paddingLeft', 'marginLeft', 'marginRight', 'lineHeight', 'borderBottomRightRadius', 'borderBottomLeftRadius', 'borderTopRightRadius', 'borderTopLeftRadius', 'borderRadius'];
185 | // no unit style
186 | const noUnitStyles = ['opacity', 'fontWeight'];
187 |
188 | const formatStyle = (style, toVW) => {
189 | const styleData = [];
190 | for (let key in style) {
191 | let value = style[key];
192 | if (boxStyleList.indexOf(key) != -1) {
193 | if (toVW) {
194 | value = (parseInt(value) / _w).toFixed(2);
195 | value = value == 0 ? value : value + 'vw';
196 | } else {
197 | value = (parseInt(value)).toFixed(2);
198 | value = value == 0 ? value : value + 'px';
199 | }
200 | styleData.push(`${_.kebabCase(key)}: ${value}`);
201 | } else if (noUnitStyles.indexOf(key) != -1) {
202 | styleData.push(`${_.kebabCase(key)}: ${parseFloat(value)}`);
203 | } else {
204 | styleData.push(`${_.kebabCase(key)}: ${value}`);
205 | }
206 | }
207 | return styleData.join(';');
208 | }
209 |
210 |
211 | // convert to responsive unit, such as vw
212 | const parseStyle = (styles) => {
213 | for (let style in styles) {
214 | for (let key in styles[style]) {
215 | if (boxStyleList.indexOf(key) > 0) {
216 | styles[style][key] = (parseInt(styles[style][key]) / _w).toFixed(2) + 'vw';
217 | }
218 | }
219 | }
220 |
221 | return styles;
222 | }
223 |
224 | // parse function, return params and content
225 | const parseFunction = (func) => {
226 | const funcString = func.toString();
227 | const params = funcString.match(/\([^\(\)]*\)/)[0].slice(1, -1);
228 | const content = funcString.slice(funcString.indexOf('{') + 1, funcString.lastIndexOf('}'));
229 | return {
230 | params,
231 | content
232 | };
233 | }
234 |
235 | // parse layer props(static values or expression)
236 | const parseProps = (value, isReactNode) => {
237 | if (typeof value === 'string') {
238 | if (isExpression(value)) {
239 | if (isReactNode) {
240 | return value.slice(1, -1);
241 | } else {
242 | return value.slice(2, -2);
243 | }
244 | }
245 |
246 | if (isReactNode) {
247 | return value;
248 | } else {
249 | return `"${value}"`;
250 | }
251 | } else if (typeof value === 'function') {
252 | const {params, content} = parseFunction(value);
253 | return `(${params}) => {${content}}`;
254 | } else {
255 | return JSON.stringify(value);
256 | }
257 | }
258 |
259 | // parse async dataSource
260 | const parseDataSource = (data) => {
261 | const name = data.id;
262 | const {uri, method, params} = data.options;
263 | const action = data.type;
264 | let payload = {};
265 |
266 | switch (action) {
267 | case 'fetch':
268 | if (importsExt.indexOf(`import {fetch} from whatwg-fetch`) === -1) {
269 | importsExt.push(`import {fetch} from 'whatwg-fetch'`);
270 | }
271 | payload = {
272 | method: method
273 | };
274 |
275 | break;
276 | case 'jsonp':
277 | if (importsExt.indexOf(`import {fetchJsonp} from fetch-jsonp`) === -1) {
278 | importsExt.push(`import jsonp from 'fetch-jsonp'`);
279 | }
280 | break;
281 | }
282 |
283 | Object.keys(data.options).forEach((key) => {
284 | if (['uri', 'method', 'params'].indexOf(key) === -1) {
285 | payload[key] = toString(data.options[key]);
286 | }
287 | });
288 |
289 | // params parse should in string template
290 | if (params) {
291 | payload = `${toString(payload).slice(0, -1)} ,body: ${isExpression(params) ? parseProps(params) : toString(params)}}`;
292 | } else {
293 | payload = toString(payload);
294 | }
295 |
296 | let result = `{
297 | ${action}(${parseProps(uri)}, ${toString(payload)})
298 | .then((response) => response.json())
299 | `;
300 |
301 | if (data.dataHandler) {
302 | const { params, content } = parseFunction(data.dataHandler);
303 | result += `.then((${params}) => {${content}})
304 | .catch((e) => {
305 | console.log('error', e);
306 | })
307 | `
308 | }
309 |
310 | result += '}';
311 |
312 | return `${name}() ${result}`;
313 | }
314 |
315 | // parse condition: whether render the layer
316 | const parseCondition = (condition, render) => {
317 | if (typeof condition === 'boolean') {
318 | return `${condition} && ${render}`
319 | } else if (typeof condition === 'string') {
320 | return `${condition.slice(2, -2)} && ${render}`
321 | }
322 | }
323 |
324 | // parse loop render
325 | const parseLoop = (loop, loopArg, render) => {
326 | let data;
327 | let loopArgItem = (loopArg && loopArg[0]) || 'item';
328 | let loopArgIndex = (loopArg && loopArg[1]) || 'index';
329 |
330 | if (Array.isArray(loop)) {
331 | data = toString(loop);
332 | } else if (isExpression(loop)) {
333 | data = loop.slice(2, -2);
334 | }
335 |
336 | // add loop key
337 | const tagEnd = render.match(/^<.+?\s/)[0].length;
338 | render = `${render.slice(0, tagEnd)} key={${loopArgIndex}}${render.slice(tagEnd)}`;
339 |
340 | // remove `this`
341 | const re = new RegExp(`this.${loopArgItem}`, 'g')
342 | render = render.replace(re, loopArgItem);
343 |
344 | return `${data}.map((${loopArgItem}, ${loopArgIndex}) => {
345 | return (${render});
346 | })`;
347 | }
348 |
349 | // generate render xml
350 | const generateRender = (schema) => {
351 | const type = schema.componentName.toLowerCase();
352 | const className = schema.props && schema.props.className || '';
353 | const classString = className ? ` className="${className}"` : '';
354 | if (className) {
355 | style[className] = schema.props.style;
356 | }
357 |
358 | let xml;
359 | let props = '';
360 |
361 | Object.keys(schema.props).forEach((key) => {
362 | if (['className', 'style', 'text', 'src', 'lines'].indexOf(key) === -1) {
363 | props += ` ${key}={${parseProps(schema.props[key])}}`;
364 | }
365 | })
366 | switch(type) {
367 | case 'text':
368 | const innerText = parseProps(schema.props.text, true);
369 | xml = `${innerText} `;
370 | break;
371 | case 'image':
372 | const source = parseProps(schema.props.src);
373 | xml = ` `;
374 | break;
375 | case 'div':
376 | case 'page':
377 | case 'block':
378 | case 'component':
379 | if (schema.children && schema.children.length) {
380 | xml = `${transform(schema.children)}
`;
381 | } else {
382 | xml = `
`;
383 | }
384 | break;
385 | default:
386 | if (schema.children && schema.children.length) {
387 | xml = `<${schema.componentName}${classString}${props}>${transform(schema.children)}${schema.componentName}>`;
388 | } else {
389 | xml = `<${schema.componentName}${classString}${props} />`;
390 | }
391 |
392 | const importString = generateImport(schema.componentName);
393 |
394 | if (importString) {
395 | imports.push(importString);
396 | }
397 | break;
398 | }
399 |
400 | if (schema.loop) {
401 | xml = parseLoop(schema.loop, schema.loopArgs, xml)
402 | }
403 | if (schema.condition) {
404 | xml = parseCondition(schema.condition, xml);
405 | }
406 | if ((schema.loop || schema.condition )&& !schema.isRoot) {
407 | xml = `{${xml}}`;
408 | }
409 |
410 | return xml;
411 | }
412 | // get all layers information
413 | let getAllLayers = function(layers, schema) {
414 | if (schema.hasOwnProperty('children')) {
415 | for (let i of schema.children) {
416 | layers.push(i);
417 | getAllLayers(layers, i);
418 | }
419 | }
420 | };
421 | // trans animation JS Web Animation Api to css
422 | const transAnimation = function(animation) {
423 | let keyFrames = ``;
424 | for (let i of animation.keyframes) {
425 | keyFrames += `
426 | ${((i.offset * 10000) / 100.0).toFixed(0) + '%'} {
427 | ${i.opacity ? 'opacity: '.concat(i.opacity) + ';' : ''}
428 | ${i.transform ? 'transform: '.concat(i.transform) + ';' : ''}
429 | }
430 | `;
431 | }
432 | let keyframes = `
433 | @keyframes ${animation.name} {
434 | ${keyFrames}
435 | }
436 | `;
437 | return keyframes;
438 | };
439 | // get keyframes from all layers
440 | const addAnimation = function (schema) {
441 | let animationRes = ``;
442 | if (schema.animation) {
443 | animationRes += transAnimation(schema.animation);
444 | }
445 | let layers = [];
446 | getAllLayers(layers, schema);
447 | for (let i of layers) {
448 | if (i.animation) {
449 | animationRes += transAnimation(i.animation);
450 | }
451 | }
452 | return animationRes;
453 | }
454 |
455 | // parse schema
456 | const transform = (schema) => {
457 | let result = '';
458 | if (Array.isArray(schema)) {
459 | schema.forEach((layer) => {
460 | result += transform(layer);
461 | });
462 | } else if (typeof schema === 'string') {
463 | result += schema;
464 | } else if (typeof schema === 'object' && typeof schema.componentName === 'string') {
465 | // fix the problem of multiple page tags
466 | let type = schema.componentName.toLowerCase();
467 | let cycleMark = ['block', 'component'].indexOf(type) !== -1;
468 | if (pageLock && cycleMark) {
469 | type = 'div';
470 | cycleMark = false;
471 | }
472 | if (type === 'page') {
473 | if (!pageLock) {
474 | pageLock = true;
475 | cycleMark = true;
476 | } else {
477 | type = 'div';
478 | }
479 | }
480 | if (cycleMark) {
481 | // 容器组件处理: state/method/dataSource/lifeCycle/render
482 | const states = [];
483 | const lifeCycles = [];
484 | const methods = [];
485 | const init = [];
486 | const render = [`render(){ return (`];
487 | let classData = [`class ${schema.componentName}_${classes.length} extends Component {`];
488 |
489 | if (schema.state) {
490 | states.push(`state = ${toString(schema.state)}`);
491 | }
492 |
493 | if (schema.methods) {
494 | Object.keys(schema.methods).forEach((name) => {
495 | const { params, content } = parseFunction(schema.methods[name]);
496 | methods.push(`${name}(${params}) {${content}}`);
497 | });
498 | }
499 |
500 | if (schema.dataSource && Array.isArray(schema.dataSource.list)) {
501 | schema.dataSource.list.forEach((item) => {
502 | if (typeof item.isInit === 'boolean' && item.isInit) {
503 | init.push(`this.${item.id}();`)
504 | } else if (typeof item.isInit === 'string') {
505 | init.push(`if (${parseProps(item.isInit)}) { this.${item.id}(); }`)
506 | }
507 | methods.push(parseDataSource(item));
508 | });
509 |
510 | if (schema.dataSource.dataHandler) {
511 | const { params, content } = parseFunction(schema.dataSource.dataHandler);
512 | methods.push(`dataHandler(${params}) {${content}}`);
513 | init.push(`this.dataHandler()`);
514 | }
515 | }
516 |
517 | if (schema.lifeCycles) {
518 | if (!schema.lifeCycles['_constructor']) {
519 | lifeCycles.push(`constructor(props, context) { super(); ${init.join('\n')}}`);
520 | }
521 |
522 | Object.keys(schema.lifeCycles).forEach((name) => {
523 | const { params, content } = parseFunction(schema.lifeCycles[name]);
524 |
525 | if (name === '_constructor') {
526 | lifeCycles.push(`constructor(${params}) { super(); ${content} ${init.join('\n')}}`);
527 | } else {
528 | lifeCycles.push(`${name}(${params}) {${content}}`);
529 | }
530 | });
531 | }
532 |
533 | render.push(generateRender(schema))
534 | render.push(`);}`);
535 |
536 | classData = classData.concat(states).concat(lifeCycles).concat(methods).concat(render);
537 | classData.push('}');
538 |
539 | classes.push(classData.join('\n'));
540 | } else {
541 | result += generateRender(schema);
542 | }
543 | }
544 |
545 | return result;
546 | };
547 |
548 | if (option.utils) {
549 | Object.keys(option.utils).forEach((name) => {
550 | utils.push(`const ${name} = ${option.utils[name]}`);
551 | });
552 | }
553 |
554 | schema.isRoot = true
555 |
556 | const prettierCssOpt = {
557 | parser: 'css'
558 | }
559 |
560 | // start parse schema
561 | transform(schema);
562 | const animationKeyframes = addAnimation(schema);
563 |
564 | const prettierOpt = {
565 | parser: 'babel',
566 | printWidth: 120,
567 | singleQuote: true
568 | };
569 | let importStrings = importString();
570 | importStrings = importStrings.concat(importsExt);
571 |
572 | return {
573 | panelDisplay: [
574 | {
575 | panelName: `index.jsx`,
576 | panelValue: prettier.format(`
577 | 'use strict';
578 |
579 | import React, { Component } from 'react';
580 | ${importStrings.join('\n')}
581 | import './style.css';
582 |
583 | ${utils.join('\n')}
584 | ${classes.join('\n')}
585 | export default ${schema.componentName}_0;
586 | `, prettierOpt),
587 | panelType: 'js',
588 | },
589 | {
590 | panelName: `style.css`,
591 | panelValue: prettier.format(generateCss(style), { parser: 'css' }) + animationKeyframes,
592 | panelType: 'css'
593 | },
594 | {
595 | panelName: `style.responsive.css`,
596 | panelValue: prettier.format(`${generateCss(style, true)}`, { parser: 'css' }) + animationKeyframes,
597 | panelType: 'css'
598 | }
599 | ],
600 | noTemplate: true
601 | };
602 | }
603 |
--------------------------------------------------------------------------------
/src/core/utils.ts:
--------------------------------------------------------------------------------
1 | import { IImport } from './interface';
2 | const find = require('lodash/find');
3 | const unset = require('lodash/unset');
4 | const set = require('lodash/set');
5 | const get = require('lodash/get');
6 | const camelCase = require('lodash/camelCase');
7 | const kebabCase = require('lodash/kebabCase');
8 | const snakeCase = require('lodash/snakeCase');
9 | const cssParser = require('css/lib/parse');
10 | import { DSL_CONFIG } from './consts'
11 |
12 |
13 | // 从 css 解析样式规则饿
14 | export const getCssRules = (text: string): {
15 | selectors: string,
16 | style: any
17 | }[] => {
18 | if (!cssParser) {
19 | return [];
20 | }
21 | const globalCssResult = cssParser(text, { source: 'global.css' });
22 |
23 | let rules = globalCssResult.stylesheet.rules;
24 | rules = rules.filter((item) => item.type === 'rule');
25 | rules = rules.map((item) => {
26 | let style = {};
27 | for (let dec of item.declarations) {
28 | const property = camelCase(dec.property);
29 | style[property] = dec.value;
30 | }
31 |
32 | return {
33 | selectors: item.selectors[0],
34 | style: style,
35 | };
36 | });
37 |
38 | return rules;
39 | };
40 |
41 | // 提取全局样式
42 | export const getGlobalClassNames = (cssObject, globalCssString) => {
43 | let names: string[] = [];
44 | if (!(globalCssString && cssParser)) {
45 | // 没有全局样式名
46 | return {
47 | names,
48 | style: cssObject,
49 | };
50 | }
51 |
52 | // 解析全局 css 规则
53 | const rules = getCssRules(globalCssString);
54 |
55 | for (let rule of rules) {
56 | // 按顺序提取样式
57 | // 仅提取 . 选择符
58 | const isMatch = find([cssObject], rule.style) && rule.selectors.startsWith('.');
59 | if (isMatch) {
60 | for (let key in rule.style) {
61 | unset(cssObject, key);
62 | }
63 | names.push(rule.selectors.replace('.', ''));
64 | }
65 | }
66 |
67 | return {
68 | names,
69 | style: cssObject,
70 | };
71 | };
72 |
73 | export const isExpression = (value) => {
74 | return /^\{\{.*\}\}$/.test(value);
75 | };
76 |
77 | // eg: hello_world => HelloWorld
78 | export const line2Hump = (str) => {
79 | str = str.replace(/[_|-](\w)/g, (all, letter) => {
80 | return letter.toUpperCase();
81 | });
82 | str = str.charAt(0).toUpperCase() + str.slice(1);
83 | return str;
84 | };
85 |
86 | export const isEmptyObj = (o) => {
87 | if (o !== null && Object.prototype.toString.call(o) === '[object Object]') {
88 | return !Object.keys(o).length;
89 | }
90 | return false;
91 | };
92 |
93 | interface IComp {
94 | list?: {
95 | name: string; packageName: string; dependenceVersion: string; dependence: string, exportName: string;
96 | subName: string;
97 | }[]
98 | };
99 | export const transComponentsMap = (compsMap: IComp = {}) => {
100 | if (!compsMap || !Array.isArray(compsMap.list)) {
101 | return [];
102 | }
103 | const list = compsMap.list;
104 | return list.reduce((obj, comp) => {
105 | const componentName = comp.name;
106 | if (!obj[componentName]) {
107 | if (comp.dependence) {
108 | try {
109 | let dependence = typeof comp.dependence === 'string' ? JSON.parse(comp.dependence) : comp.dependence;
110 | if (dependence) {
111 | comp.packageName = dependence.package;
112 | }
113 | if (!comp.dependenceVersion) {
114 | comp.dependenceVersion = '*';
115 | }
116 | comp.exportName = dependence.export_name;
117 | comp.subName = dependence.sub_name;
118 | if (/^\d/.test(comp.dependenceVersion)) {
119 | comp.dependenceVersion = '^' + comp.dependenceVersion;
120 | }
121 | } catch (e) {
122 | console.log(e);
123 | }
124 | }
125 |
126 | obj[componentName] = comp;
127 | }
128 | return obj;
129 | }, {});
130 | };
131 |
132 | export const toString = (value) => {
133 | if ({}.toString.call(value) === '[object Function]') {
134 | return value.toString();
135 | }
136 | if (typeof value === 'string') {
137 | return value;
138 | }
139 | if (typeof value === 'object') {
140 | return JSON.stringify(value, (key, value) => {
141 | if (typeof value === 'function') {
142 | return value.toString();
143 | } else {
144 | return value;
145 | }
146 | });
147 | }
148 |
149 | return String(value);
150 | };
151 |
152 | export const toUpperCaseStart = (value) => {
153 | return value.charAt(0).toUpperCase() + value.slice(1);
154 | };
155 |
156 |
157 | // 计数器
158 | let counter = {};
159 | const getCounter = (key) => {
160 | counter[key] = (counter[key] || 0) + 1
161 | return counter[key];
162 | }
163 |
164 | export const resetCounter = (key) => {
165 | counter[key] = 0;
166 | }
167 |
168 |
169 | // 是否所有样式相同
170 | function isAllEqual(array) {
171 | if (array.length > 0) {
172 | return !array.some(function (value, index) {
173 | return value !== array[0];
174 | });
175 | } else {
176 | return true;
177 | }
178 | }
179 |
180 | // 获得相同样式
181 | function getMaxSameStyles(array) {
182 | if (array.length < 2) {
183 | return {}
184 | }
185 | let maxStyle = {}
186 | const keys = Object.keys(array[0])
187 | for (let key of keys) {
188 | if (isAllEqual(array.map(item => item[key]))) {
189 | maxStyle[key] = array[0][key]
190 | }
191 | }
192 |
193 | return maxStyle
194 | }
195 |
196 | export const commonStyle = (schema) => {
197 | traverseBrother(schema, function (nodes) {
198 | const sameStyle = getMaxSameStyles(nodes.filter(item => item.props && item.props.style).map(item => item.props.style));
199 | if (Object.keys(sameStyle).length > 3) {
200 | const commonClassName = genStyleClass(
201 | 'common_'+nodes[0].props.className,
202 | DSL_CONFIG.cssStyle
203 | );
204 |
205 | set(schema, `commonStyles.${commonClassName}`, parseStyle(sameStyle))
206 | for (let node of nodes) {
207 | for (let key of Object.keys(sameStyle)) {
208 | unset(node, `props.style.${key}`)
209 | }
210 | node.classnames = node.classnames || []
211 | node.classnames.push(commonClassName)
212 | }
213 | }
214 | })
215 | }
216 |
217 | // 精简样式
218 | export const simpleStyle = (schema) => {
219 |
220 | function getMaxRepeatItem(array) {
221 | let a = {}
222 | let max = 0;
223 | let maxele = null;
224 | for (let i = 0; i < array.length; i++) {
225 | a[array[i]] == undefined ? a[array[i]] = 1 : a[array[i]]++;
226 | if (a[array[i]] > max) {
227 | maxele = array[i];
228 | max = a[array[i]];
229 | }
230 | }
231 | return maxele;
232 | }
233 |
234 | // 统计出现字体最多的,放到根节点
235 | let fontFamilys: string[] = []
236 | traverse(schema, (node) => {
237 | const ft = get(node, 'props.style.fontFamily');
238 | if (ft) {
239 | fontFamilys.push(ft)
240 | }
241 | });
242 |
243 | const rootFont = get(schema, 'props.style.fontFamily') || getMaxRepeatItem(fontFamilys);
244 | if (rootFont) {
245 | traverse(schema, (node) => {
246 | const ft = get(node, 'props.style.fontFamily');
247 | if (ft == rootFont) {
248 | unset(node, 'props.style.fontFamily');
249 | }
250 | });
251 | set(schema, 'props.style.fontFamily', rootFont);
252 | }
253 |
254 | // 删除 font-weight 400 或者 normal
255 | traverse(schema, (node) => {
256 | const removeStyle = (node, styleName, values) => {
257 | const fw = get(node, `props.style.${styleName}`);
258 | if (values.includes(String(fw) || '')) {
259 | unset(node, `props.style.${styleName}`);
260 | }
261 | }
262 | removeStyle(node, 'fontWeight', ['400', 400, 'normal']);
263 | removeStyle(node, 'flexDirection', ['row']);
264 | removeStyle(node, 'textDecoration', ['none']);
265 | });
266 |
267 |
268 |
269 | return schema;
270 | }
271 |
272 | /**
273 | * 处理schema一些常见问题
274 | * @param schema
275 | * 1. 清理 class 空格
276 | * 2. 关键节点命名兜底
277 | */
278 | export const initSchema = (schema) => {
279 | // 重置计数器
280 | resetCounter('page');
281 | resetCounter('block');
282 | resetCounter('component');
283 |
284 | // 清理 class 空格
285 | traverse(schema, (node) => {
286 | if (node && node.props && node.props.className) {
287 | node.props.className = String(node.props.className).trim();
288 | }
289 | node.componentName = node.componentName || 'div'
290 | });
291 |
292 | // 样式名处理:指定命名风格
293 | traverse(schema, (json) => {
294 | if (json.props && json.props.className) {
295 | json.props.className = genStyleClass(
296 | json.props.className,
297 | DSL_CONFIG.cssStyle
298 | );
299 | }
300 | });
301 |
302 | // 关键节点命名兜底
303 | traverse(schema, (json) => {
304 | json.componentName = json.componentName || ''
305 | switch (json.componentName.toLowerCase()) {
306 | case 'page':
307 | json.fileName = line2Hump(json.fileName || `page_${getCounter('page')}`);
308 | break;
309 | case 'block':
310 | json.fileName = line2Hump(json.fileName || `block_${getCounter('block')}`);
311 | break;
312 | case 'component':
313 | json.fileName = line2Hump(json.fileName || `component_${getCounter('component')}`);
314 | break;
315 | default:
316 | break;
317 | }
318 | });
319 |
320 | traverse(schema, (json) => {
321 | if(json.componentName == 'Text'){
322 | delete json.props.lines
323 | }
324 | });
325 | };
326 |
327 | // 遍历节点
328 | export const traverse = (json, callback) => {
329 | if (Array.isArray(json)) {
330 | json.forEach((node) => {
331 | traverse(node, callback)
332 | });
333 | return
334 | }
335 |
336 | // 去除 class 空格
337 | if (json && callback) {
338 | callback(json)
339 | }
340 |
341 | if (
342 | json.children &&
343 | json.children.length > 0 &&
344 | Array.isArray(json.children)
345 | ) {
346 | json.children.forEach((child) => {
347 | traverse(child, callback);
348 | });
349 | }
350 | };
351 |
352 |
353 | // 遍历兄弟节点
354 | export const traverseBrother = (json, callback) => {
355 | if (Array.isArray(json)) {
356 | json.forEach((node) => {
357 | traverseBrother(node, callback)
358 | });
359 | return
360 | }
361 |
362 | if (json && Array.isArray(json.children) && callback) {
363 | callback(json.children)
364 | }
365 |
366 | if (
367 | json.children &&
368 | json.children.length > 0 &&
369 | Array.isArray(json.children)
370 | ) {
371 | json.children.forEach((child) => {
372 | traverseBrother(child, callback);
373 | });
374 | }
375 | };
376 |
377 |
378 | export const genStyleClass = (string, type) => {
379 | let classArray = string.split(' ');
380 | classArray = classArray.filter(name => !!name);
381 | classArray = classArray.map(name => {
382 | switch (type) {
383 | case 'camelCase': return camelCase(name);
384 | case 'kebabCase': return kebabCase(name);
385 | case 'snakeCase': return snakeCase(name);
386 | default:
387 | return camelCase(name);
388 | }
389 | });
390 | return classArray.join(' ')
391 | }
392 |
393 | export const genStyleCode = (styles, key = '') => {
394 | return !/-/.test(key) && key.trim()
395 | ? `${styles}.${key}`
396 | : `${styles}['${key}']`;
397 | };
398 |
399 | export const parseNumberValue = (value) => {
400 | const { cssUnit = 'px', scale, responseWidth } = DSL_CONFIG
401 | value = String(value).replace(/\b[\d\.]+(px|rem|rpx|vw)?\b/, (v) => {
402 | const nv = parseFloat(v);
403 | if (!isNaN(nv) && nv !== 0) {
404 | return toString(nv);
405 | } else {
406 | return 0;
407 | }
408 | });
409 |
410 | if (/^\-?[\d\.]+$/.test(value)) {
411 | value = parseFloat(value);
412 | if (cssUnit == 'rpx') {
413 | value = 750 * value / Number(responseWidth);
414 | value = value == 0 ? value : value + 'rpx';
415 | } else if (cssUnit == 'rem') {
416 | const htmlFontSize = DSL_CONFIG.htmlFontSize || 16;
417 | value = parseFloat((value / htmlFontSize).toFixed(2));
418 | value = value ? `${value}rem` : value;
419 | } else if (cssUnit == 'vw') {
420 | const _w = 750 / scale
421 | value = (100 * parseInt(value) / _w).toFixed(2);
422 | value = value == 0 ? value : value + 'vw';
423 | } else {
424 | value += cssUnit;
425 | }
426 | }
427 | return value;
428 | };
429 |
430 | // convert to responsive unit, such as vw
431 | export const parseStyle = (style) => {
432 | const { scale, cssUnit } = DSL_CONFIG
433 | const resultStyle = {}
434 | for (let key in style) {
435 | switch (key) {
436 | case 'fontSize':
437 | case 'marginTop':
438 | case 'marginBottom':
439 | case 'paddingTop':
440 | case 'paddingBottom':
441 | case 'height':
442 | case 'top':
443 | case 'bottom':
444 | case 'width':
445 | case 'maxWidth':
446 | case 'left':
447 | case 'right':
448 | case 'paddingRight':
449 | case 'paddingLeft':
450 | case 'marginLeft':
451 | case 'marginRight':
452 | case 'lineHeight':
453 | case 'borderBottomRightRadius':
454 | case 'borderBottomLeftRadius':
455 | case 'borderTopRightRadius':
456 | case 'borderTopLeftRadius':
457 | case 'borderRadius':
458 |
459 | if (style[key]) {
460 | const values = String(style[key]).split(' ');
461 | resultStyle[key] = values.map(val => {
462 | if(String(val).endsWith('%')){
463 | return val
464 | }
465 | return parseNumberValue(parseInt(val, 10) * scale)
466 | }).join(' ')
467 | }
468 |
469 | break;
470 | default:
471 | if (style[key] && String(style[key]).includes('px')) {
472 | resultStyle[key] = String(style[key]).replace(/[\d\.]+px/g, (v) => {
473 | return /^[\d\.]+px$/.test(v) ? parseNumberValue(v) : v;
474 | })
475 | }
476 | resultStyle[key] = resultStyle[key] || style[key]
477 | }
478 | }
479 |
480 | return resultStyle;
481 | };
482 |
483 | // parse function, return params and content
484 | export const parseFunction = (func) => {
485 | const funcString = func.toString();
486 | const params = funcString.match(/\([^\(\)]*\)/)[0].slice(1, -1);
487 | const content = funcString.slice(
488 | funcString.indexOf('{') + 1,
489 | funcString.lastIndexOf('}')
490 | );
491 | return {
492 | params,
493 | content,
494 | };
495 | };
496 |
497 | export const toJsString = (str)=>{
498 | return typeof str === 'string' && str.includes("'") ? `\`${str}\`` : `'${str}'`
499 | }
500 | // parse layer props(static values or expression)
501 | export const parseProps = (value, isReactNode = false) => {
502 | if(Array.isArray(value)){
503 | return `[${value.map(item => parseProps(item, isReactNode)).join(',')}]`
504 | }
505 | if (typeof value === 'string') {
506 | if (isExpression(value)) {
507 | if (isReactNode) {
508 | return value.slice(1, -1);
509 | } else {
510 | return value.slice(2, -2);
511 | }
512 | }
513 |
514 | if (isReactNode) {
515 | return value;
516 | } else {
517 | return `${toJsString(value)}`;
518 | }
519 | } else if (typeof value === 'function') {
520 | const { params, content } = parseFunction(value);
521 | return `(${params}) => {${content}}`;
522 | } else if (typeof value === 'object') {
523 | if(isJSSlot(value)){
524 | if(value.params){
525 | return `(${value.params.join(',')}) => { return ${value.jsx}}`
526 | }
527 | return value.jsx
528 | }else{
529 | return `{${ Object.keys(value).map(key => `${key}: ${parseProps(value[key])}`).join(',')}}`
530 | }
531 | } else {
532 | return value;
533 | }
534 | };
535 |
536 | // parse condition: whether render the layer
537 | export const parseCondition = (condition, render) => {
538 | if (typeof condition === 'boolean') {
539 | return `${condition} && ${render}`;
540 | } else if (typeof condition === 'string') {
541 | condition = condition.replace(/this\./, '');
542 | return `${condition.slice(2, -2)} && ${render}`;
543 | }
544 | };
545 |
546 | // flexDirection -> flex-direction
547 | export const parseCamelToLine = (string) => {
548 | return string
549 | .split(/(?=[A-Z])/)
550 | .join('-')
551 | .toLowerCase();
552 | };
553 |
554 | // style obj -> css
555 | export const generateCSS = (style, prefix) => {
556 | let css = '';
557 |
558 | for (let layer in style) {
559 | css += `${prefix && prefix !== layer ? '.' + prefix + ' ' : ''}.${layer} {`;
560 | css += generateCssString(style[layer])
561 | css += '}'
562 | }
563 |
564 | return css;
565 | };
566 |
567 | /**
568 | * (1)定位属性:position display float left top right bottom overflow clear z-index
569 | (2)自身属性:width height padding border margin background
570 | (3)文字样式:font-family font-size font-style font-weight font-varient color
571 | (4)文本属性:text-align vertical-align text-wrap text-transform text-indent text-decoration letter-spacing word-spacing white-space text-overflow
572 | (5)css3中新增属性:content box-shadow border-radius transform……
573 | */
574 | const orderMap = [
575 | "position", "display", "float", "left", "top", "right", "bottom",
576 | "flex-direction", "justify-content", "align-items", "align-self", "overflow", "clear", "z-index",
577 | "width", "height", "max-width", "max-height", "padding", "padding-bottom", "padding-left", "padding-right", "padding-left", "border", "margin", "margin-top", "margin-bottom", "margin-left", "margin-right", "background",
578 | "background-color", "background-image", "background-size",
579 | "font-family", "font-size", "font-style", "font-weight", "font-varient", "line-height", "color", "text-align", "vertical-align", "text-wrap", "text-transform", "text-indent", "text-decoration",
580 | "letter-spacing", "word-spacing", "white-space", "text-overflow",
581 | "content", "box-shadow", "border-radius", "transform"
582 | ]
583 | // genrate css object string
584 | export const generateCssString = (style) => {
585 | let css = '';
586 | let array: any[] = [];
587 |
588 | // 缩写margin
589 | const margin = Object.keys(style).filter(item => item.startsWith("margin"));
590 | if (!style['margin'] && margin.length > 2) {
591 | style["margin"] = `${style["marginTop"] || 0} ${style["marginRight"] || 0} ${style["marginBottom"] || 0} ${style["marginLeft"] || 0}`
592 | delete style["marginTop"];
593 | delete style["marginLeft"];
594 | delete style["marginBottom"];
595 | delete style["marginRight"];
596 | }
597 |
598 | // 缩写 padding
599 | const padding = Object.keys(style).filter(item => item.startsWith("padding"));
600 | if (!style['padding'] && padding.length > 2) {
601 | style["padding"] = `${style["paddingTop"] || 0} ${style["paddingRight"] || 0} ${style["paddingBottom"] || 0} ${style["paddingLeft"] || 0}`
602 | delete style["paddingTop"];
603 | delete style["paddingLeft"];
604 | delete style["paddingBottom"];
605 | delete style["paddingRight"];
606 | }
607 |
608 | for (let key in style) {
609 | const cssKey = parseCamelToLine(key);
610 | const orderIndex = orderMap.indexOf(cssKey);
611 | array.push({
612 | key: cssKey,
613 | value: style[key],
614 | index: orderIndex == -1 ? 100 : orderIndex
615 | })
616 | }
617 |
618 |
619 | array.sort((a, b) => {
620 | return a.index - b.index
621 | })
622 |
623 | css = array.map(item => {
624 | return `${item.key}: ${item.value};`
625 | }).join('');
626 |
627 | return css
628 | }
629 |
630 | // 根据 schema 生成 scss 或者 less
631 | export const generateScss = (schema) => {
632 | let scss = '';
633 |
634 | function walk(json) {
635 | if (json.props.className) {
636 | let className = json.props.className;
637 | scss += `.${className}{`;
638 | scss += `${generateCssString(parseStyle(json.props.style))};`;
639 | }
640 |
641 | if (json.children && json.children.length > 0) {
642 | json.children.forEach((child) => {
643 | if (!['block', 'component', 'page'].includes(child.componentName.toLowerCase())) {
644 | walk(child)
645 | }
646 | });
647 | }
648 |
649 | if (json.props.className) {
650 | scss += '}';
651 | }
652 | }
653 |
654 | walk(schema);
655 |
656 | return scss;
657 | };
658 |
659 |
660 | // parse loop render
661 | export const parseLoop = (loop, loopArg, render, params = {}) => {
662 | let data;
663 | let loopArgItem = (loopArg && loopArg[0]) || 'item';
664 | let loopArgIndex = (loopArg && loopArg[1]) || 'index';
665 |
666 | if (Array.isArray(loop)) {
667 | data = toString(loop);
668 | } else if (isExpression(loop)) {
669 | data = loop.slice(2, -2);
670 | }
671 |
672 | // add loop key
673 | const tagEnd = render.match(/^<.+?\s/)[0].length;
674 | render = `${render.slice(0, tagEnd)} key={${loopArgIndex}}${render.slice(
675 | tagEnd
676 | )}`;
677 |
678 | // remove `this`
679 | const re = new RegExp(`this.${loopArgItem}`, 'g');
680 | render = render.replace(re, loopArgItem);
681 | let stateValue = data;
682 | if (data.match(/this\.state\./)) {
683 | stateValue = `state.${data.split('.').pop()}`;
684 | }
685 |
686 | const formatRender = params['formatRender'] || function (str) { return str };
687 | return {
688 | hookState: [],
689 | value: `${stateValue}.map((${loopArgItem}, ${loopArgIndex}) => {
690 | return (${formatRender(render)});
691 | })`,
692 | };
693 | };
694 |
695 | // parse state
696 | export const parseState = (states) => {
697 | let stateName = 'state';
698 | // hooks state
699 | return `const [${stateName}, set${toUpperCaseStart(
700 | stateName
701 | )}] = useState(${toString(JSON.parse(states)) || null});`;
702 | };
703 |
704 | // replace state
705 | export const replaceState = (render) => {
706 | // remove `this`
707 | let stateName = 'state';
708 | const re = new RegExp(`this.state`, 'g');
709 | return render.replace(re, stateName);
710 | };
711 |
712 | // replace state
713 | export const parseLifeCycles = (schema, init) => {
714 | let lifeCycles: string[] = [];
715 | if (!schema.lifeCycles['_constructor'] && init) {
716 | schema.lifeCycles['_constructor'] = `function _constructor() {}`;
717 | }
718 |
719 | Object.keys(schema.lifeCycles).forEach((name) => {
720 | let { params, content } = parseFunction(schema.lifeCycles[name]);
721 | content = replaceState(content);
722 | switch (name) {
723 | case '_constructor': {
724 | init.push(content);
725 | lifeCycles.unshift(`
726 | // constructor
727 | useState(()=>{
728 | ${init.join('\n')}
729 | })
730 | `);
731 | break;
732 | }
733 | case 'componentDidMount': {
734 | lifeCycles.push(`
735 | // componentDidMount
736 | useEffect(()=>{
737 | ${content}
738 | }, [])
739 | `);
740 | break;
741 | }
742 | case 'componentDidUpdate': {
743 | lifeCycles.push(`
744 | // componentDidUpdate
745 | useEffect(()=>{
746 | ${content}
747 | })
748 | `);
749 | break;
750 | }
751 | case 'componentWillUnMount': {
752 | lifeCycles.push(`
753 | // componentWillUnMount
754 | useEffect(()=>{
755 | return ()=>{
756 | ${content}
757 | }
758 | }, [])
759 | `);
760 | break;
761 | }
762 | }
763 | });
764 | return lifeCycles;
765 | };
766 |
767 | export const existImport = (imports, singleImport) => {
768 | let exist = false;
769 | imports.forEach((item) => {
770 | if (item._import === singleImport) {
771 | exist = true;
772 | }
773 | });
774 | return exist;
775 | };
776 |
777 | // parse async dataSource
778 | export const parseDataSource = (data) => {
779 | const name = data.id;
780 | const { uri, method, params } = data.options;
781 | const action = data.type;
782 | let payload = {};
783 |
784 |
785 | Object.keys(data.options).forEach((key) => {
786 | if (['uri', 'method', 'params'].indexOf(key) === -1) {
787 | payload[key] = toString(data.options[key]);
788 | }
789 | });
790 |
791 | let comma = isEmptyObj(payload) ? '' : ',';
792 | // params parse should in string template
793 | if (params) {
794 | if (method !== 'GET') {
795 | payload = `${toString(payload).slice(0, -1)} ${comma} body: ${isExpression(params) ? parseProps(params) : toString(params)
796 | }}`;
797 | } else {
798 | payload = `${toString(payload).slice(0, -1)}}`;
799 | }
800 | } else {
801 | payload = toString(payload);
802 | }
803 |
804 |
805 | let result = `{
806 | return ${action}(${parseProps(uri)}, ${toString(payload)})
807 | .then((response) => response.json())
808 | `;
809 |
810 | if (data.dataHandler) {
811 | const { params, content } = parseFunction(data.dataHandler);
812 | result += `.then((${params}) => {${content}})
813 | .catch((e) => {
814 | console.log('error', e);
815 | })
816 | `;
817 | }
818 |
819 | result += '}';
820 |
821 | return {
822 | value: `${name}() ${result}`,
823 | functionName: name,
824 | functionBody: result
825 | };
826 | };
827 |
828 | // get children text
829 | export const getText = (schema) => {
830 | let text = '';
831 |
832 | const getChildrenText = (schema) => {
833 | const type = schema.componentName.toLowerCase();
834 | if (type === 'text') {
835 | text += parseProps(schema.props.text || schema.text, true).replace(
836 | /\{/g,
837 | '${'
838 | );
839 | }
840 |
841 | schema.children &&
842 | Array.isArray(schema.children) &&
843 | schema.children.map((item) => {
844 | getChildrenText(item);
845 | });
846 | };
847 |
848 | getChildrenText(schema);
849 |
850 | return text;
851 | };
852 |
853 |
854 | export const transAnimation = function (animation) {
855 | let keyFrames = ``;
856 | for (let i of animation.keyframes) {
857 | keyFrames += `${((i.offset * 10000) / 100.0).toFixed(0) + '%'} {
858 | ${i.opacity ? 'opacity: '.concat(i.opacity) + ';' : ''}
859 | ${i.transform ? 'transform: '.concat(i.transform) + ';' : ''}
860 | }
861 | `;
862 | }
863 | let keyframes = `
864 | @keyframes ${animation.name} {
865 | ${keyFrames}
866 | }
867 | `;
868 | return keyframes;
869 | };
870 |
871 | export const addAnimation = function (schema) {
872 | let animationRes = ``;
873 | traverse(schema, (json) => {
874 | if (json.animation) {
875 | animationRes += transAnimation(json.animation);
876 | }
877 | })
878 | return animationRes;
879 | };
880 |
881 |
882 | /**
883 | * constrcut the import string
884 | */
885 | export const importString = (importsMap) => {
886 | const importStrings: string[] = [];
887 | const subImports: string[] = [];
888 | for (const [packageName, pkgSet] of importsMap) {
889 | const set1 = new Set(), set2 = new Set();
890 | for (const pkg of pkgSet) {
891 | let exportName = pkg.exportName;
892 | let subName = pkg.subName;
893 | let componentName = pkg.name;
894 |
895 | if (pkg.subName) {
896 | subImports.push(`const ${componentName} = ${exportName}.${subName};`);
897 | }
898 | if (!exportName) {
899 | exportName = componentName
900 | }
901 | if (componentName !== exportName && !pkg.subName) {
902 | exportName = `${exportName} as ${componentName}`;
903 | }
904 | if (pkg.dependence && pkg.dependence.destructuring) {
905 | set2.add(exportName);
906 | } else {
907 | set1.add(exportName);
908 | }
909 | }
910 | const set1Str = [...set1].join(',');
911 | let set2Str = [...set2].join(',');
912 | const dot = set1Str && set2Str ? ',' : '';
913 | if (set2Str) {
914 | set2Str = `{${set2Str}}`;
915 | }
916 | importStrings.push(`import ${set1Str} ${dot} ${set2Str} from '${packageName}'`);
917 | }
918 | return importStrings.concat(subImports);
919 | }
920 |
921 | export const isObject = (value: any): value is Record => {
922 | return typeof value == 'object' && Array.isArray(value) === false
923 | }
924 |
925 |
926 | export const isJSSlot = (value: unknown): boolean => {
927 | return isObject(value) && value?.type === 'JSSlot'
928 | }
929 |
930 |
931 | const isRecord = (data: unknown): data is Record => {
932 | return typeof data === 'object' && data !== null;
933 | };
934 |
935 |
--------------------------------------------------------------------------------
/test/data.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "taskId": "0D283120-E934-4A60-8E98-460AF583C288",
3 | "fileName": "Card",
4 | "artboardImg": "https://img.alicdn.com/imgextra/i2/O1CN01ugQAbP1JWWz3cTbfc_!!6000000001036-2-tps-714-390.png",
5 | "rect": {
6 | "x": 0,
7 | "y": 0,
8 | "width": 714,
9 | "height": 390
10 | },
11 | "pluginVersion": "2.3.2",
12 | "componentName": "Page",
13 | "layerProtocols": [
14 | "group"
15 | ],
16 | "name": "编组 9备份 7",
17 | "reference": "sketch",
18 | "restore_id": "48e826d2-dddd-4cf2-bb5d-c4ee106bbc4b",
19 | "props": {
20 | "style": {
21 | "width": "714px",
22 | "height": "390px"
23 | },
24 | "className": "mod"
25 | },
26 | "id": "01b30d10-2d5e-11ec-9614-f1bdff654829",
27 | "children": [
28 | {
29 | "componentName": "Block",
30 | "props": {
31 | "style": {
32 | "display": "flex",
33 | "position": "relative",
34 | "alignItems": "flex-start",
35 | "flexDirection": "row"
36 | },
37 | "className": "block1"
38 | },
39 | "rect": {
40 | "x": 0,
41 | "y": 0,
42 | "width": 714,
43 | "height": 390
44 | },
45 | "children": [
46 | {
47 | "componentName": "div",
48 | "props": {
49 | "style": {
50 | "display": "flex",
51 | "position": "relative",
52 | "alignItems": "flex-start",
53 | "flexDirection": "row"
54 | },
55 | "className": "div2"
56 | },
57 | "rect": {
58 | "x": 0,
59 | "y": 0,
60 | "width": 714,
61 | "height": 390
62 | },
63 | "children": []
64 | }
65 | ]
66 | },
67 | {
68 | "componentName": "Div",
69 | "id": "1657f48a-9b91-4d99-9d4e-d2b6e4309709",
70 | "props": {
71 | "style": {
72 | "display": "flex",
73 | "position": "relative",
74 | "alignItems": "flex-start",
75 | "flexDirection": "row"
76 | },
77 | "className": "container-inner"
78 | },
79 | "rect": {
80 | "x": 0,
81 | "y": 0,
82 | "width": 714,
83 | "height": 390
84 | },
85 | "children": [
86 | {
87 | "componentName": "Block",
88 | "fileName": "Header",
89 | "id": "e1d84884-da62-4696-809b-408bf4ae93e4",
90 | "props": {
91 | "style": {
92 | "display": "flex",
93 | "position": "relative",
94 | "alignItems": "flex-start",
95 | "flexDirection": "row",
96 | "borderRadius": "24px",
97 | "backgroundColor": "#EDEDED"
98 | },
99 | "className": "primary"
100 | },
101 | "rect": {
102 | "x": 0,
103 | "y": 0,
104 | "width": 714,
105 | "height": 390
106 | },
107 | "smart": {
108 | "layerProtocol": {
109 | "group": {
110 | "type": "group"
111 | }
112 | }
113 | },
114 | "selfId": "1D57C450-558D-4B85-877C-ED61FACF8DEA",
115 | "nodeLayerName": "#group#品牌福利",
116 | "children": [
117 | {
118 | "componentName": "Div",
119 | "id": "0039563a-e78f-44b5-8264-8416a4d2baeb",
120 | "props": {
121 | "style": {
122 | "display": "flex",
123 | "alignItems": "center",
124 | "flexDirection": "row",
125 | "marginTop": "80px"
126 | },
127 | "className": "wrapper-inner"
128 | },
129 | "rect": {
130 | "x": 0,
131 | "y": 80,
132 | "width": 714,
133 | "height": 310
134 | },
135 | "smart": {
136 | "layerProtocol": {
137 | "group": {
138 | "type": "group"
139 | },
140 | "layout": {
141 | "type": "list",
142 | "row": 3,
143 | "col": 1
144 | },
145 | "component": {
146 | "type": "slider"
147 | }
148 | },
149 | "nodeIdentification": {
150 | "baseComponent": [
151 | "slider"
152 | ]
153 | },
154 | "nodeCustom": {
155 | "baseComponent": {
156 | "isConfident": true,
157 | "label": "slider",
158 | "score": 0.9958979487419128,
159 | "type": "baseComponent",
160 | "meta": {
161 | "threshold": 0.99
162 | },
163 | "rect": {
164 | "x": 0,
165 | "y": 80,
166 | "width": 714,
167 | "height": 310
168 | },
169 | "id": "0039563a-e78f-44b5-8264-8416a4d2baeb",
170 | "selfId": "BF41D7C0-17A7-4B33-88F6-16132CEEE9C4"
171 | }
172 | }
173 | },
174 | "selfId": "BF41D7C0-17A7-4B33-88F6-16132CEEE9C4",
175 | "nodeLayerName": "#group#编组 3",
176 | "children": [
177 | {
178 | "componentName": "Div",
179 | "id": "e41c0f6e-72ba-4534-873b-2db3b6a133e8",
180 | "props": {
181 | "style": {
182 | "display": "flex",
183 | "position": "relative",
184 | "alignItems": "center",
185 | "flexDirection": "column",
186 | "marginRight": "2px",
187 | "borderBottomLeftRadius": "24px",
188 | "backgroundColor": "#FFFFFF",
189 | "width": "237px",
190 | "height": "310px",
191 | "overflow": "hidden"
192 | },
193 | "className": "item-wrapper-i0"
194 | },
195 | "rect": {
196 | "x": 0,
197 | "y": 80,
198 | "width": 237,
199 | "height": 310
200 | },
201 | "smart": {
202 | "layerProtocol": {
203 | "group": {
204 | "type": "group"
205 | },
206 | "repeat": {
207 | "type": "repeat",
208 | "repeatId": "1634264238383575",
209 | "repeatIndex": "0"
210 | },
211 | "multiStatus": {
212 | "type": "multiStatus",
213 | "protocol": {
214 | "autoDetected": true,
215 | "statusId": "16342642383925341",
216 | "statusIndex": 0,
217 | "statusCount": 3
218 | }
219 | },
220 | "layout": {
221 | "type": "layout",
222 | "position": "left"
223 | }
224 | }
225 | },
226 | "selfId": "62599A25-DD15-4012-9DD6-FF47F667D849",
227 | "nodeLayerName": "#group#1",
228 | "children": [
229 | {
230 | "componentName": "Image",
231 | "id": "01b33425-2d5e-11ec-9614-f1bdff654829",
232 | "props": {
233 | "style": {
234 | "position": "relative",
235 | "marginTop": "12px",
236 | "width": "170px",
237 | "height": "170px"
238 | },
239 | "src": "https://img.alicdn.com/imgextra/i2/O1CN012avgI31PWQaaou5AA_!!6000000001848-2-tps-340-340.png",
240 | "className": "item"
241 | },
242 | "rect": {
243 | "x": 34,
244 | "y": 92,
245 | "width": 170,
246 | "height": 170
247 | },
248 | "selfId": "7E391F47-8B27-49CC-9EC9-682B41BFB396",
249 | "nodeLayerName": "#merge#图片+蒙版"
250 | },
251 | {
252 | "componentName": "Block",
253 | "id": "e8048804-8111-4b2a-8bc7-141410187b19",
254 | "props": {
255 | "style": {
256 | "display": "flex",
257 | "position": "absolute",
258 | "top": "172px",
259 | "alignItems": "center",
260 | "alignSelf": "center",
261 | "flexDirection": "row",
262 | "justifyContent": "center",
263 | "borderWidth": "2px",
264 | "borderStyle": "solid",
265 | "borderRadius": "24px",
266 | "borderColor": "#E1E1E1",
267 | "backgroundColor": "#FFFFFF",
268 | "width": "130px",
269 | "height": "48px"
270 | },
271 | "className": "view"
272 | },
273 | "rect": {
274 | "x": 54,
275 | "y": 252,
276 | "width": 130,
277 | "height": 48
278 | },
279 | "smart": {
280 | "layerProtocol": {
281 | "group": {
282 | "type": "group"
283 | },
284 | "multiStatus": {
285 | "type": "multiStatus",
286 | "protocol": {
287 | "autoDetected": true,
288 | "statusId": "16342642383933936",
289 | "statusIndex": 0,
290 | "statusCount": 1
291 | }
292 | }
293 | }
294 | },
295 | "selfId": "33360FF6-93AA-4F56-8BE3-3F07506769AC",
296 | "nodeLayerName": "#group#编组 3",
297 | "children": [
298 | {
299 | "componentName": "Image",
300 | "id": "01b33423-2d5e-11ec-9614-f1bdff654829",
301 | "props": {
302 | "style": {
303 | "width": "84px",
304 | "height": "42px"
305 | },
306 | "src": "https://img.alicdn.com/imgextra/i3/O1CN01doUzCW22CWODauZhZ_!!6000000007084-2-tps-168-84.png",
307 | "className": "shop-logo"
308 | },
309 | "rect": {
310 | "x": 77,
311 | "y": 255,
312 | "width": 84,
313 | "height": 42
314 | },
315 | "selfId": "4462C8BF-C89F-4060-ADD2-E974A174821B",
316 | "nodeLayerName": "#merge#Bitmap备份"
317 | }
318 | ]
319 | },
320 | {
321 | "componentName": "Text",
322 | "id": "01b35b33-2d5e-11ec-9614-f1bdff654829",
323 | "props": {
324 | "style": {
325 | "position": "relative",
326 | "marginTop": "48px",
327 | "maxWidth": "225px",
328 | "height": "28px",
329 | "overflow": "hidden",
330 | "textOverflow": "ellipsis",
331 | "lineHeight": "28px",
332 | "whiteSpace": "nowrap",
333 | "color": "#111111",
334 | "fontFamily": "PingFang SC",
335 | "fontSize": "24px",
336 | "fontWeight": 500
337 | },
338 | "lines": 1,
339 | "className": "location",
340 | "text": "{{item.title}}"
341 | },
342 | "rect": {
343 | "x": 83,
344 | "y": 310,
345 | "width": 72,
346 | "height": 28
347 | },
348 | "selfId": "638858BB-612F-43BE-A2E2-2C2B8599E1670",
349 | "nodeLayerName": "马歇尔"
350 | },
351 | {
352 | "componentName": "Div",
353 | "id": "128c8f8c-4897-436e-8be3-8f247b2f0efb",
354 | "props": {
355 | "style": {
356 | "display": "flex",
357 | "position": "relative",
358 | "alignItems": "center",
359 | "flexDirection": "row",
360 | "marginTop": "8px",
361 | "height": "30px"
362 | },
363 | "className": "view-1"
364 | },
365 | "rect": {
366 | "x": 39,
367 | "y": 346,
368 | "width": 160,
369 | "height": 30
370 | },
371 | "smart": {
372 | "layerProtocol": {
373 | "group": {
374 | "type": "group"
375 | }
376 | }
377 | },
378 | "selfId": "9BF237F6-0F7F-4C57-864A-1B889307DE90",
379 | "nodeLayerName": "#group#编组 3",
380 | "children": [
381 | {
382 | "componentName": "Text",
383 | "id": "01b35b32-2d5e-11ec-9614-f1bdff654829",
384 | "props": {
385 | "style": {
386 | "marginRight": "6px",
387 | "lineHeight": "26px",
388 | "whiteSpace": "nowrap",
389 | "color": "#ff0036",
390 | "fontFamily": "PingFang SC",
391 | "fontSize": "26px",
392 | "fontWeight": 500
393 | },
394 | "text": "满300送40",
395 | "lines": 1,
396 | "className": "title"
397 | },
398 | "rect": {
399 | "x": 39,
400 | "y": 346,
401 | "width": 130,
402 | "height": 30
403 | },
404 | "selfId": "F84B65C6-9B6C-4929-8420-B670A165FF820",
405 | "nodeLayerName": "满300送40",
406 | "smart": {
407 | "layerProtocol": {
408 | "layout": {
409 | "type": "layout",
410 | "position": "left"
411 | }
412 | }
413 | }
414 | },
415 | {
416 | "componentName": "Image",
417 | "id": "01b35b31-2d5e-11ec-9614-f1bdff654829",
418 | "props": {
419 | "style": {
420 | "width": "24px",
421 | "height": "24px"
422 | },
423 | "src": "https://img.alicdn.com/imgextra/i4/O1CN01KOYI9a1lud45JqE22_!!6000000004879-2-tps-48-48.png",
424 | "className": "icon-right"
425 | },
426 | "rect": {
427 | "x": 175,
428 | "y": 349,
429 | "width": 24,
430 | "height": 24
431 | },
432 | "selfId": "DB023BD4-828C-47DC-A4C0-B9E9C9C4D1D8",
433 | "nodeLayerName": "#merge#编组 3",
434 | "smart": {
435 | "layerProtocol": {
436 | "field": {
437 | "type": "right"
438 | },
439 | "layout": {
440 | "type": "layout",
441 | "position": "right"
442 | }
443 | },
444 | "nodeIdentification": {
445 | "fieldBind": [
446 | "right"
447 | ]
448 | },
449 | "nodeCustom": {
450 | "fieldBind": {
451 | "confidential": 0.793341338634491,
452 | "isConfident": true,
453 | "label": "right",
454 | "type": "fieldBind"
455 | }
456 | }
457 | }
458 | }
459 | ]
460 | }
461 | ],
462 | "loop": "{{this.state.items}}",
463 | "loopArgs": [
464 | "item",
465 | ""
466 | ]
467 | }
468 | ]
469 | }
470 | ],
471 | "state": {
472 | "items": [
473 | {
474 | "title": "标题1"
475 | },
476 | {
477 | "title": "标题2"
478 | },
479 | {
480 | "title": "标题3"
481 | }
482 | ]
483 | }
484 | },
485 | {
486 | "componentName": "Image",
487 | "id": "01b30d11-2d5e-11ec-9614-f1bdff654829",
488 | "props": {
489 | "style": {
490 | "position": "absolute",
491 | "top": "0px",
492 | "left": "0px",
493 | "width": "714px",
494 | "height": "80px"
495 | },
496 | "src": "https://img.alicdn.com/imgextra/i4/O1CN015bxNgd1PWszCyuBBr_!!6000000001849-2-tps-1428-160.png",
497 | "className": "floor-bg"
498 | },
499 | "rect": {
500 | "x": 0,
501 | "y": 0,
502 | "width": 714,
503 | "height": 80
504 | },
505 | "selfId": "317BE8EE-A5A9-46A8-8FFE-99CE20CB221D",
506 | "nodeLayerName": "#merge#编组 4"
507 | }
508 | ],
509 | "condition": "{{this.state.enable}}"
510 | }
511 | ],
512 | "imgcook": {
513 | "restore_id": "48e826d2-dddd-4cf2-bb5d-c4ee106bbc4b",
514 | "dslConfig": {
515 | "globalCss": false,
516 | "inlineStyle": "import",
517 | "componentStyle": "component",
518 | "outputStyle": "project",
519 | "cssUnit": "px",
520 | "cssStyle": "kebabCase",
521 | "dsl": "react-standard",
522 | "dslName": "React 开发规范",
523 | "htmlType": "html静态",
524 | "htmlFontSize": 16
525 | }
526 | },
527 | "dataSource": {
528 | "list": [
529 | {
530 | "id": "id1",
531 | "isInit": true,
532 | "type": "fetch",
533 | "options": {
534 | "method": "GET",
535 | "params": {},
536 | "uri": "https://pre-apistudio.alibaba-inc.com/openapi/mock_api?projectId=5fc611b47f32555337dc5540&api=mtop.alsc.pos.bill.customer.batchqueryanalysis&errorCode=date¶m={%22analysisIds%22:[%22OVERALL_FLOW_OVERVIEW%22,%22INSIGHT_OVERVIEW%22,%22MEMBER_CHANNEL%22,%22CUSTOMER_CHANNEL%22],%22intervalType%22:%22LAST_SEVEN_DAYS%22,%22intervalTime%22:%222021-05-16%22,%22bizChannel%22:%22%E5%85%A8%E9%83%A8%22}"
537 | }
538 | }
539 | ]
540 | },
541 | "css": "/************************************************************\n** 组件全局样式 **\n** 将按照从前到后按顺序提取类名,出码生成多类名 **\n************************************************************/\n\nhtml {\n font-size: 24px;\n}\n\nbody {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans',\n 'Droid Sans', 'Helvetica Neue', 'Microsoft Yahei', sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n* {\n box-sizing: border-box;\n flex-shrink: 0;\n}\n\n#root {\n width: 100vw;\n height: 100vh;\n}\n\n\n.flex-row {\n display: flex;\n flex-direction: row;\n}\n\n.flex-col {\n display: flex;\n flex-direction: column;\n}\n\n.justify-start {\n display: flex;\n justify-content: flex-start;\n}\n\n.justify-center {\n display: flex;\n justify-content: center;\n}\n\n.justify-end {\n display: flex;\n justify-content: flex-end;\n}\n\n.justify-evenly {\n display: flex;\n justify-content: space-evenly;\n}\n\n.justify-around {\n display: flex;\n justify-content: space-around;\n}\n\n.justify-between {\n display: flex;\n justify-content: space-between;\n}\n\n.items-start {\n display: flex;\n align-items: flex-start;\n}\n\n.items-center {\n display: flex;\n align-items: center;\n}\n\n.items-end {\n display: flex;\n align-items: flex-end;\n}\n\n.height-78{\n height: 78px;\n}\n",
542 | "state": {
543 | "enable": true
544 | },
545 | "lifeCycles": {}
546 | }
--------------------------------------------------------------------------------
/test/animation.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "componentName": "Block",
3 | "id": "7adeb880-2028-11ec-82f6-bbadaeddfccc",
4 | "props": {
5 | "style": {
6 | "display": "flex",
7 | "flexDirection": "row",
8 | "alignItems": "flex-start",
9 | "width": "565px",
10 | "height": "623px",
11 | "position": "relative",
12 | "animationIterationCount": 1,
13 | "animationTimingFunction": "linear",
14 | "animationDuration": "1280ms",
15 | "animationName": "swing"
16 | },
17 | "className": "mod"
18 | },
19 | "taskId": "16AF9B5E-69BB-4C18-B31C-1F46A3D1ED7D",
20 | "artboardImg": "https://img.alicdn.com/imgextra/i3/O1CN01gGC3JF1cyRsHOktYN_!!6000000003669-2-tps-490-624.png",
21 | "rect": {
22 | "x": -72,
23 | "y": 0,
24 | "width": 565,
25 | "height": 623
26 | },
27 | "animation": {
28 | "layerid": "8544227E-2107-4EEE-AF40-864F20F9662D",
29 | "name": "swing",
30 | "keyframes": [{
31 | "WebkitTransform": "rotate3d(0, 0, 1, 15deg)",
32 | "transform": "rotate3d(0, 0, 1, 15deg)",
33 | "offset": "0.2",
34 | "easing": "ease"
35 | }, {
36 | "WebkitTransform": "rotate3d(0, 0, 1, -10deg)",
37 | "transform": "rotate3d(0, 0, 1, -10deg)",
38 | "offset": "0.4",
39 | "easing": "ease"
40 | }, {
41 | "WebkitTransform": "rotate3d(0, 0, 1, 5deg)",
42 | "transform": "rotate3d(0, 0, 1, 5deg)",
43 | "offset": "0.6",
44 | "easing": "ease"
45 | }, {
46 | "WebkitTransform": "rotate3d(0, 0, 1, -5deg)",
47 | "transform": "rotate3d(0, 0, 1, -5deg)",
48 | "offset": "0.8",
49 | "easing": "ease"
50 | }, {
51 | "WebkitTransform": "rotate3d(0, 0, 1, 0deg)",
52 | "transform": "rotate3d(0, 0, 1, 0deg)",
53 | "offset": "1",
54 | "easing": "ease"
55 | }],
56 | "timing": {
57 | "duration": 1280,
58 | "iterations": "infinite",
59 | "easing": "linear"
60 | }
61 | },
62 | "pluginVersion": "4.0.22",
63 | "smart": {
64 | "layerProtocol": {
65 | "group": {
66 | "type": "group"
67 | }
68 | }
69 | },
70 | "layerProtocols": ["group"],
71 | "name": "#group#animation-swing#编组 21",
72 | "reference": "sketch",
73 | "restore_id": "5e0484c8-2b4a-497d-afef-00d4cfafcc8b",
74 | "children": [{
75 | "componentName": "View",
76 | "id": "7adf54c7-2028-11ec-82f6-bbadaeddfccc",
77 | "props": {
78 | "style": {
79 | "display": "flex",
80 | "position": "relative",
81 | "alignItems": "flex-start",
82 | "flexDirection": "row",
83 | "justifyContent": "center",
84 | "marginLeft": "94px",
85 | "borderTopLeftRadius": "18px",
86 | "borderTopRightRadius": "18px",
87 | "backgroundImage": "linear-gradient(148deg, #EFEDED 0%, #B4B4B4 76%)",
88 | "width": "438px",
89 | "height": "461px"
90 | },
91 | "className": "primary"
92 | },
93 | "rect": {
94 | "x": 22,
95 | "y": 0,
96 | "width": 438,
97 | "height": 461
98 | },
99 | "selfId": "C3104608-D699-44F8-9C96-5172EFA24BA1",
100 | "nodeLayerName": "矩形",
101 | "children": [{
102 | "componentName": "Picture",
103 | "id": "7adf2db7-2028-11ec-82f6-bbadaeddfccc",
104 | "props": {
105 | "style": {
106 | "position": "absolute",
107 | "bottom": "12px",
108 | "left": "-14px",
109 | "width": "405px",
110 | "height": "310px"
111 | },
112 | "className": "entry-pic",
113 | "source": {
114 | "uri": "https://img.alicdn.com/imgextra/i1/O1CN01iA6RUt1giCHh4uLfX_!!6000000004175-2-tps-810-620.png"
115 | },
116 | "autoScaling": false,
117 | "autoWebp": false
118 | },
119 | "rect": {
120 | "x": 8,
121 | "y": 139,
122 | "width": 405,
123 | "height": 310
124 | },
125 | "selfId": "53BB11EC-E160-4D2D-9691-F801197D986A",
126 | "nodeLayerName": "auto-#merge#"
127 | }, {
128 | "componentName": "Picture",
129 | "id": "7adeb881-2028-11ec-82f6-bbadaeddfccc",
130 | "props": {
131 | "style": {
132 | "position": "relative",
133 | "marginTop": "13px",
134 | "marginRight": "87px",
135 | "width": "201px",
136 | "height": "76px"
137 | },
138 | "className": "action-bg",
139 | "source": {
140 | "uri": "https://img.alicdn.com/imgextra/i4/O1CN01xCglio1fb2Tj4dGI7_!!6000000004024-2-tps-404-152.png"
141 | },
142 | "autoScaling": false,
143 | "autoWebp": false
144 | },
145 | "rect": {
146 | "x": 46,
147 | "y": 13,
148 | "width": 201,
149 | "height": 76
150 | },
151 | "selfId": "A8A1D526-0456-4D5D-A82E-1EFAE0DBAE5F",
152 | "nodeLayerName": "auto-#merge#-autogroup"
153 | }, {
154 | "componentName": "Picture",
155 | "id": "7adf2db5-2028-11ec-82f6-bbadaeddfccc",
156 | "props": {
157 | "style": {
158 | "position": "relative",
159 | "marginTop": "20px",
160 | "width": "106px",
161 | "height": "52px"
162 | },
163 | "className": "shop-logo",
164 | "source": {
165 | "uri": "https://img.alicdn.com/imgextra/i2/O1CN01fRLVpN1koqUi7VnM2_!!6000000004731-2-tps-214-104.png"
166 | },
167 | "autoScaling": false,
168 | "autoWebp": false
169 | },
170 | "rect": {
171 | "x": 334,
172 | "y": 20,
173 | "width": 106,
174 | "height": 52
175 | },
176 | "selfId": "B4121643-E37C-4158-A6FF-9EE461B9E1CE",
177 | "nodeLayerName": "auto-#merge#"
178 | }]
179 | }, {
180 | "componentName": "View",
181 | "id": "7adf54c6-2028-11ec-82f6-bbadaeddfccc",
182 | "props": {
183 | "style": {
184 | "position": "absolute",
185 | "top": "140px",
186 | "right": "28px",
187 | "width": "437px",
188 | "height": "347px",
189 | "overflow": "hidden"
190 | },
191 | "className": "empty"
192 | },
193 | "rect": {
194 | "x": 28,
195 | "y": 140,
196 | "width": 437,
197 | "height": 347
198 | },
199 | "selfId": "053213F4-9555-49FF-BED4-FE1E7E063C3B",
200 | "nodeLayerName": "蒙版",
201 | "condition": true
202 | }, {
203 | "componentName": "Picture",
204 | "id": "7adf54c5-2028-11ec-82f6-bbadaeddfccc",
205 | "props": {
206 | "style": {
207 | "position": "absolute",
208 | "top": "194px",
209 | "left": "113px",
210 | "animationIterationCount": "infinite",
211 | "animationTimingFunction": "linear",
212 | "animationDuration": "1280ms",
213 | "animationName": "swing",
214 | "width": "197px",
215 | "height": "340px"
216 | },
217 | "className": "item-long",
218 | "source": {
219 | "uri": "https://img.alicdn.com/imgextra/i2/O1CN01IcS9wC1I6azO02qbt_!!6000000000844-2-tps-396-682.png"
220 | },
221 | "autoScaling": false,
222 | "autoWebp": false
223 | },
224 | "rect": {
225 | "x": 41,
226 | "y": 194,
227 | "width": 197,
228 | "height": 340
229 | },
230 | "selfId": "4EF0C111-5F9D-4943-B7E7-262BA25239EF",
231 | "nodeLayerName": "#group#animation-swing#位图",
232 | "animation": {
233 | "layerid": "912CEF68-7509-438C-8927-D2A52DD5F9C9",
234 | "name": "swing",
235 | "keyframes": [{
236 | "WebkitTransform": "rotate3d(0, 0, 1, 15deg)",
237 | "transform": "rotate3d(0, 0, 1, 15deg)",
238 | "offset": "0.2",
239 | "easing": "ease"
240 | }, {
241 | "WebkitTransform": "rotate3d(0, 0, 1, -10deg)",
242 | "transform": "rotate3d(0, 0, 1, -10deg)",
243 | "offset": "0.4",
244 | "easing": "ease"
245 | }, {
246 | "WebkitTransform": "rotate3d(0, 0, 1, 5deg)",
247 | "transform": "rotate3d(0, 0, 1, 5deg)",
248 | "offset": "0.6",
249 | "easing": "ease"
250 | }, {
251 | "WebkitTransform": "rotate3d(0, 0, 1, -5deg)",
252 | "transform": "rotate3d(0, 0, 1, -5deg)",
253 | "offset": "0.8",
254 | "easing": "ease"
255 | }, {
256 | "WebkitTransform": "rotate3d(0, 0, 1, 0deg)",
257 | "transform": "rotate3d(0, 0, 1, 0deg)",
258 | "offset": "1",
259 | "easing": "ease"
260 | }],
261 | "timing": {
262 | "duration": 1280,
263 | "iterations": "infinite",
264 | "easing": "linear"
265 | }
266 | }
267 | }, {
268 | "componentName": "Picture",
269 | "id": "7adf54c4-2028-11ec-82f6-bbadaeddfccc",
270 | "props": {
271 | "style": {
272 | "position": "absolute",
273 | "top": "157px",
274 | "left": "172px",
275 | "animationIterationCount": "infinite",
276 | "animationTimingFunction": "ease",
277 | "animationDuration": "1280ms",
278 | "animationName": "swing",
279 | "width": "182px",
280 | "height": "354px"
281 | },
282 | "className": "product-long",
283 | "source": {
284 | "uri": "https://img.alicdn.com/imgextra/i4/O1CN01TC595Q1RWXy7mXO57_!!6000000002119-2-tps-368-712.png"
285 | },
286 | "autoScaling": false,
287 | "autoWebp": false
288 | },
289 | "rect": {
290 | "x": 100,
291 | "y": 157,
292 | "width": 182,
293 | "height": 354
294 | },
295 | "selfId": "9B804B77-22E5-4129-BE58-8DF4EE7F2BE7",
296 | "nodeLayerName": "#group#animation-swing#位图",
297 | "animation": {
298 | "layerid": "39E1B106-2975-4EFA-BF54-B5F06BF5144E",
299 | "name": "swing",
300 | "keyframes": [{
301 | "WebkitTransform": "rotate3d(0, 0, 1, 15deg)",
302 | "transform": "rotate3d(0, 0, 1, 15deg)",
303 | "offset": "0.2",
304 | "easing": "ease"
305 | }, {
306 | "WebkitTransform": "rotate3d(0, 0, 1, -10deg)",
307 | "transform": "rotate3d(0, 0, 1, -10deg)",
308 | "offset": "0.4",
309 | "easing": "ease"
310 | }, {
311 | "WebkitTransform": "rotate3d(0, 0, 1, 5deg)",
312 | "transform": "rotate3d(0, 0, 1, 5deg)",
313 | "offset": "0.6",
314 | "easing": "ease"
315 | }, {
316 | "WebkitTransform": "rotate3d(0, 0, 1, -5deg)",
317 | "transform": "rotate3d(0, 0, 1, -5deg)",
318 | "offset": "0.8",
319 | "easing": "ease"
320 | }, {
321 | "WebkitTransform": "rotate3d(0, 0, 1, 0deg)",
322 | "transform": "rotate3d(0, 0, 1, 0deg)",
323 | "offset": "1",
324 | "easing": "ease"
325 | }],
326 | "timing": {
327 | "duration": 1280,
328 | "iterations": "infinite",
329 | "easing": "ease"
330 | }
331 | }
332 | }, {
333 | "componentName": "Picture",
334 | "id": "7adf54c3-2028-11ec-82f6-bbadaeddfccc",
335 | "props": {
336 | "style": {
337 | "position": "absolute",
338 | "top": "154px",
339 | "right": "173px",
340 | "animationIterationCount": "infinite",
341 | "animationTimingFunction": "ease",
342 | "animationDuration": "1280ms",
343 | "animationName": "swing",
344 | "width": "179px",
345 | "height": "388px"
346 | },
347 | "className": "item-long-1",
348 | "source": {
349 | "uri": "https://img.alicdn.com/imgextra/i3/O1CN01sNPqa11h9DeSojhL8_!!6000000004234-2-tps-362-780.png"
350 | },
351 | "autoScaling": false,
352 | "autoWebp": false
353 | },
354 | "rect": {
355 | "x": 141,
356 | "y": 154,
357 | "width": 179,
358 | "height": 388
359 | },
360 | "selfId": "5689F4E9-F4F3-44F6-8CFB-79E981CF76D9",
361 | "nodeLayerName": "#group#animation-swing#位图",
362 | "animation": {
363 | "layerid": "806CA3E2-2C4C-48CB-8656-341680E278B0",
364 | "name": "swing",
365 | "keyframes": [{
366 | "WebkitTransform": "rotate3d(0, 0, 1, 15deg)",
367 | "transform": "rotate3d(0, 0, 1, 15deg)",
368 | "offset": "0.2",
369 | "easing": "ease"
370 | }, {
371 | "WebkitTransform": "rotate3d(0, 0, 1, -10deg)",
372 | "transform": "rotate3d(0, 0, 1, -10deg)",
373 | "offset": "0.4",
374 | "easing": "ease"
375 | }, {
376 | "WebkitTransform": "rotate3d(0, 0, 1, 5deg)",
377 | "transform": "rotate3d(0, 0, 1, 5deg)",
378 | "offset": "0.6",
379 | "easing": "ease"
380 | }, {
381 | "WebkitTransform": "rotate3d(0, 0, 1, -5deg)",
382 | "transform": "rotate3d(0, 0, 1, -5deg)",
383 | "offset": "0.8",
384 | "easing": "ease"
385 | }, {
386 | "WebkitTransform": "rotate3d(0, 0, 1, 0deg)",
387 | "transform": "rotate3d(0, 0, 1, 0deg)",
388 | "offset": "1",
389 | "easing": "ease"
390 | }],
391 | "timing": {
392 | "duration": 1280,
393 | "iterations": "infinite",
394 | "easing": "ease"
395 | }
396 | }
397 | }, {
398 | "componentName": "Picture",
399 | "id": "7adf54c2-2028-11ec-82f6-bbadaeddfccc",
400 | "props": {
401 | "style": {
402 | "position": "absolute",
403 | "right": "122px",
404 | "bottom": "61px",
405 | "animationIterationCount": "infinite",
406 | "animationTimingFunction": "linear",
407 | "animationDuration": "1280ms",
408 | "animationName": "swing",
409 | "width": "230px",
410 | "height": "406px"
411 | },
412 | "className": "product-long-1",
413 | "source": {
414 | "uri": "https://img.alicdn.com/imgextra/i1/O1CN01weu6uV1gD3Lkir9e0_!!6000000004107-2-tps-462-814.png"
415 | },
416 | "autoScaling": false,
417 | "autoWebp": false
418 | },
419 | "rect": {
420 | "x": 141,
421 | "y": 156,
422 | "width": 230,
423 | "height": 406
424 | },
425 | "selfId": "12D1B83A-4764-4C73-8DE5-4649B4B95008",
426 | "nodeLayerName": "#group#animation-swing#位图",
427 | "animation": {
428 | "layerid": "A77A3610-5F80-4BA7-8A0C-B4AD5D36D6A2",
429 | "name": "swing",
430 | "keyframes": [{
431 | "WebkitTransform": "rotate3d(0, 0, 1, 15deg)",
432 | "transform": "rotate3d(0, 0, 1, 15deg)",
433 | "offset": "0.2",
434 | "easing": "ease"
435 | }, {
436 | "WebkitTransform": "rotate3d(0, 0, 1, -10deg)",
437 | "transform": "rotate3d(0, 0, 1, -10deg)",
438 | "offset": "0.4",
439 | "easing": "ease"
440 | }, {
441 | "WebkitTransform": "rotate3d(0, 0, 1, 5deg)",
442 | "transform": "rotate3d(0, 0, 1, 5deg)",
443 | "offset": "0.6",
444 | "easing": "ease"
445 | }, {
446 | "WebkitTransform": "rotate3d(0, 0, 1, -5deg)",
447 | "transform": "rotate3d(0, 0, 1, -5deg)",
448 | "offset": "0.8",
449 | "easing": "ease"
450 | }, {
451 | "WebkitTransform": "rotate3d(0, 0, 1, 0deg)",
452 | "transform": "rotate3d(0, 0, 1, 0deg)",
453 | "offset": "1",
454 | "easing": "ease"
455 | }],
456 | "timing": {
457 | "duration": 1280,
458 | "iterations": "infinite",
459 | "easing": "linear"
460 | }
461 | }
462 | }, {
463 | "componentName": "Picture",
464 | "id": "7adf54c1-2028-11ec-82f6-bbadaeddfccc",
465 | "props": {
466 | "style": {
467 | "position": "absolute",
468 | "right": "56px",
469 | "bottom": "37px",
470 | "animationIterationCount": "infinite",
471 | "animationTimingFunction": "ease",
472 | "animationDuration": "1280ms",
473 | "animationName": "swing",
474 | "width": "302px",
475 | "height": "417px"
476 | },
477 | "className": "item-long-2",
478 | "source": {
479 | "uri": "https://img.alicdn.com/imgextra/i4/O1CN01F3CHMW1LwkwSVqkE7_!!6000000001364-2-tps-608-838.png"
480 | },
481 | "autoScaling": false,
482 | "autoWebp": false
483 | },
484 | "rect": {
485 | "x": 135,
486 | "y": 169,
487 | "width": 302,
488 | "height": 417
489 | },
490 | "selfId": "501A1B1C-AEF8-452B-A388-C0C85F98B76D",
491 | "nodeLayerName": "#group#animation-swing#位图",
492 | "animation": {
493 | "layerid": "1A6F7BCE-FF17-4BBE-8494-0A0EFC3775C3",
494 | "name": "swing",
495 | "keyframes": [{
496 | "WebkitTransform": "rotate3d(0, 0, 1, 15deg)",
497 | "transform": "rotate3d(0, 0, 1, 15deg)",
498 | "offset": "0.2",
499 | "easing": "ease"
500 | }, {
501 | "WebkitTransform": "rotate3d(0, 0, 1, -10deg)",
502 | "transform": "rotate3d(0, 0, 1, -10deg)",
503 | "offset": "0.4",
504 | "easing": "ease"
505 | }, {
506 | "WebkitTransform": "rotate3d(0, 0, 1, 5deg)",
507 | "transform": "rotate3d(0, 0, 1, 5deg)",
508 | "offset": "0.6",
509 | "easing": "ease"
510 | }, {
511 | "WebkitTransform": "rotate3d(0, 0, 1, -5deg)",
512 | "transform": "rotate3d(0, 0, 1, -5deg)",
513 | "offset": "0.8",
514 | "easing": "ease"
515 | }, {
516 | "WebkitTransform": "rotate3d(0, 0, 1, 0deg)",
517 | "transform": "rotate3d(0, 0, 1, 0deg)",
518 | "offset": "1",
519 | "easing": "ease"
520 | }],
521 | "timing": {
522 | "duration": 1280,
523 | "iterations": "infinite",
524 | "easing": "ease"
525 | }
526 | }
527 | }, {
528 | "componentName": "Picture",
529 | "id": "7adf54c0-2028-11ec-82f6-bbadaeddfccc",
530 | "props": {
531 | "style": {
532 | "position": "absolute",
533 | "right": "0px",
534 | "bottom": "20px",
535 | "animationIterationCount": "infinite",
536 | "animationTimingFunction": "linear",
537 | "animationDuration": "1280ms",
538 | "animationName": "swing",
539 | "width": "392px",
540 | "height": "251px"
541 | },
542 | "className": "entry-pic-1",
543 | "source": {
544 | "uri": "https://img.alicdn.com/imgextra/i4/O1CN01kfFLkC1d8yyub56ck_!!6000000003692-2-tps-786-506.png"
545 | },
546 | "autoScaling": false,
547 | "autoWebp": false
548 | },
549 | "rect": {
550 | "x": 101,
551 | "y": 352,
552 | "width": 392,
553 | "height": 251
554 | },
555 | "selfId": "AA1440EF-37B4-43B6-B7D0-8063F312A7AA",
556 | "nodeLayerName": "#group#animation-swing#位图",
557 | "animation": {
558 | "layerid": "381C715B-62D6-4859-BA05-233F65238D33",
559 | "name": "swing",
560 | "keyframes": [{
561 | "WebkitTransform": "rotate3d(0, 0, 1, 15deg)",
562 | "transform": "rotate3d(0, 0, 1, 15deg)",
563 | "offset": "0.2",
564 | "easing": "ease"
565 | }, {
566 | "WebkitTransform": "rotate3d(0, 0, 1, -10deg)",
567 | "transform": "rotate3d(0, 0, 1, -10deg)",
568 | "offset": "0.4",
569 | "easing": "ease"
570 | }, {
571 | "WebkitTransform": "rotate3d(0, 0, 1, 5deg)",
572 | "transform": "rotate3d(0, 0, 1, 5deg)",
573 | "offset": "0.6",
574 | "easing": "ease"
575 | }, {
576 | "WebkitTransform": "rotate3d(0, 0, 1, -5deg)",
577 | "transform": "rotate3d(0, 0, 1, -5deg)",
578 | "offset": "0.8",
579 | "easing": "ease"
580 | }, {
581 | "WebkitTransform": "rotate3d(0, 0, 1, 0deg)",
582 | "transform": "rotate3d(0, 0, 1, 0deg)",
583 | "offset": "1",
584 | "easing": "ease"
585 | }],
586 | "timing": {
587 | "duration": 1280,
588 | "iterations": "infinite",
589 | "easing": "linear"
590 | }
591 | }
592 | }, {
593 | "componentName": "View",
594 | "id": "ebce8372-c549-402a-b9d5-223f1ced6f15",
595 | "props": {
596 | "style": {
597 | "display": "flex",
598 | "position": "absolute",
599 | "top": "139px",
600 | "right": "18px",
601 | "alignItems": "center",
602 | "flexDirection": "row",
603 | "width": "466px",
604 | "height": "338px"
605 | },
606 | "className": "layer-wrapper"
607 | },
608 | "rect": {
609 | "x": 9,
610 | "y": 139,
611 | "width": 466,
612 | "height": 338
613 | },
614 | "children": [{
615 | "componentName": "Picture",
616 | "id": "7adf2dbb-2028-11ec-82f6-bbadaeddfccc",
617 | "props": {
618 | "style": {
619 | "position": "absolute",
620 | "top": "0px",
621 | "left": "0px",
622 | "width": "466px",
623 | "height": "338px",
624 | "overflow": "hidden"
625 | },
626 | "className": "layer",
627 | "source": {
628 | "uri": "https://img.alicdn.com/imgextra/i4/O1CN010qI7m51VXhQsQqmgF_!!6000000002663-2-tps-932-676.png"
629 | },
630 | "autoScaling": false,
631 | "autoWebp": false
632 | },
633 | "rect": {
634 | "x": 9,
635 | "y": 139,
636 | "width": 466,
637 | "height": 338
638 | },
639 | "selfId": "69F77E0D-8BEA-4891-97AF-133327A096E2",
640 | "nodeLayerName": "蒙版"
641 | }, {
642 | "componentName": "Picture",
643 | "id": "7adf2db9-2028-11ec-82f6-bbadaeddfccc",
644 | "props": {
645 | "style": {
646 | "position": "absolute",
647 | "top": "1px",
648 | "right": "-2px",
649 | "width": "3px",
650 | "height": "309px"
651 | },
652 | "className": "vertical-line",
653 | "source": {
654 | "uri": "https://img.alicdn.com/imgextra/i2/O1CN01LMbnMX1p1RrABGVSW_!!6000000005300-2-tps-6-618.png"
655 | },
656 | "autoScaling": false,
657 | "autoWebp": false
658 | },
659 | "rect": {
660 | "x": 474,
661 | "y": 140,
662 | "width": 3,
663 | "height": 309
664 | },
665 | "selfId": "6E7D2D9E-29BD-4204-9C2A-F3BF7BE3AA07",
666 | "nodeLayerName": "矩形备份 5"
667 | }]
668 | }, {
669 | "componentName": "Picture",
670 | "id": "7adf2dba-2028-11ec-82f6-bbadaeddfccc",
671 | "props": {
672 | "style": {
673 | "position": "absolute",
674 | "top": "138px",
675 | "left": "0px",
676 | "width": "319px",
677 | "height": "3px"
678 | },
679 | "className": "bg",
680 | "source": {
681 | "uri": "https://img.alicdn.com/imgextra/i1/O1CN015WWq7v2AJriRaLXBN_!!6000000008183-2-tps-638-6.png"
682 | },
683 | "autoScaling": false,
684 | "autoWebp": false
685 | },
686 | "rect": {
687 | "x": -72,
688 | "y": 138,
689 | "width": 319,
690 | "height": 3
691 | },
692 | "selfId": "2A9F6011-ADA4-4EAA-8FB3-FBC303A75960",
693 | "nodeLayerName": "矩形"
694 | }, {
695 | "componentName": "Picture",
696 | "id": "7adf2db8-2028-11ec-82f6-bbadaeddfccc",
697 | "props": {
698 | "style": {
699 | "position": "absolute",
700 | "top": "139px",
701 | "left": "81px",
702 | "width": "268px",
703 | "height": "378px",
704 | "overflow": "hidden"
705 | },
706 | "className": "product-long-2",
707 | "source": {
708 | "uri": "https://img.alicdn.com/imgextra/i4/O1CN010QBD6u1TUpihL1m7h_!!6000000002386-2-tps-536-756.png"
709 | },
710 | "autoScaling": false,
711 | "autoWebp": false
712 | },
713 | "rect": {
714 | "x": 9,
715 | "y": 139,
716 | "width": 268,
717 | "height": 378
718 | },
719 | "selfId": "2EBD36FF-20A7-4181-BF79-F9AAE128F5FB",
720 | "nodeLayerName": "蒙版"
721 | }, {
722 | "componentName": "Picture",
723 | "id": "7adf2db6-2028-11ec-82f6-bbadaeddfccc",
724 | "props": {
725 | "style": {
726 | "position": "absolute",
727 | "top": "102px",
728 | "right": "18px",
729 | "width": "466px",
730 | "height": "39px"
731 | },
732 | "className": "background",
733 | "source": {
734 | "uri": "https://img.alicdn.com/imgextra/i3/O1CN01BlvkK31GB3c9nECsj_!!6000000000583-2-tps-934-78.png"
735 | },
736 | "autoScaling": false,
737 | "autoWebp": false
738 | },
739 | "rect": {
740 | "x": 9,
741 | "y": 102,
742 | "width": 466,
743 | "height": 39
744 | },
745 | "selfId": "30B72AB6-491C-456C-9CB6-C07BB4F360BA",
746 | "nodeLayerName": "auto-#merge#"
747 | }, {
748 | "componentName": "View",
749 | "id": "3ad60bf6-00ed-4ff9-a5c9-d9e0e0cd036d",
750 | "props": {
751 | "style": {
752 | "display": "flex",
753 | "position": "absolute",
754 | "right": "11px",
755 | "bottom": "0px",
756 | "alignItems": "flex-start",
757 | "flexDirection": "row"
758 | },
759 | "className": "wrapper"
760 | },
761 | "rect": {
762 | "x": -46,
763 | "y": 416,
764 | "width": 528,
765 | "height": 207
766 | },
767 | "smart": {
768 | "layerProtocol": {
769 | "group": {
770 | "type": "group"
771 | }
772 | }
773 | },
774 | "selfId": "06ABB0FC-1ACA-49BD-BA81-059B3803CDA6",
775 | "nodeLayerName": "#group#编组 25",
776 | "children": [{
777 | "componentName": "View",
778 | "id": "3ba4ccc0-19d9-40bf-82d5-9741bb39c495",
779 | "props": {
780 | "style": {
781 | "display": "flex",
782 | "position": "relative",
783 | "alignItems": "center",
784 | "flexDirection": "row",
785 | "marginTop": "17px",
786 | "marginLeft": "46px",
787 | "backgroundSize": "contain",
788 | "backgroundImage": "url(https://img.alicdn.com/imgextra/i2/O1CN01ofNLoD1YmIuIHhBl1_!!6000000003101-2-tps-964-380.png)",
789 | "height": "190px"
790 | },
791 | "className": "wrapper-inner"
792 | },
793 | "rect": {
794 | "x": 0,
795 | "y": 433,
796 | "width": 482,
797 | "height": 190
798 | },
799 | "children": [{
800 | "componentName": "View",
801 | "id": "7adf2db3-2028-11ec-82f6-bbadaeddfccc",
802 | "props": {
803 | "style": {
804 | "display": "flex",
805 | "position": "relative",
806 | "alignItems": "flex-start",
807 | "flexDirection": "row",
808 | "justifyContent": "center",
809 | "backgroundColor": "#141414",
810 | "width": "482px",
811 | "height": "176px",
812 | "overflow": "hidden"
813 | },
814 | "className": "group"
815 | },
816 | "rect": {
817 | "x": 0,
818 | "y": 440,
819 | "width": 482,
820 | "height": 176
821 | },
822 | "selfId": "4713C36B-F068-4139-9A6A-26AD0DA10119",
823 | "nodeLayerName": "蒙版",
824 | "children": [{
825 | "componentName": "Picture",
826 | "id": "7adf2db1-2028-11ec-82f6-bbadaeddfccc",
827 | "props": {
828 | "style": {
829 | "position": "absolute",
830 | "right": "12px",
831 | "bottom": "0px",
832 | "width": "174px",
833 | "height": "119px"
834 | },
835 | "className": "entry-pic-2",
836 | "source": {
837 | "uri": "https://img.alicdn.com/imgextra/i3/O1CN01ZwPA581LWeMp5HThX_!!6000000001307-2-tps-350-242.png"
838 | },
839 | "autoScaling": false,
840 | "autoWebp": false
841 | },
842 | "rect": {
843 | "x": 296,
844 | "y": 497,
845 | "width": 174,
846 | "height": 119
847 | },
848 | "selfId": "FC5FE3BD-C457-4882-905B-F270FB282964",
849 | "nodeLayerName": "路径 13"
850 | }, {
851 | "componentName": "View",
852 | "id": "c2501631-04b5-4698-830d-9e7f73fc0c38",
853 | "props": {
854 | "style": {
855 | "display": "flex",
856 | "flexDirection": "row",
857 | "justifyContent": "center",
858 | "alignItems": "center",
859 | "marginTop": 2,
860 | "width": "159px",
861 | "height": "40px",
862 | "lineHeight": "26px",
863 | "position": "absolute",
864 | "top": "110px",
865 | "left": "29px",
866 | "zIndex": "10",
867 | "backgroundImage": "url(https://img.alicdn.com/imgextra/i2/O1CN01A6AUU31FroypE1Fw8_!!6000000000541-2-tps-318-80.png)",
868 | "backgroundSize": "contain",
869 | "whiteSpace": "nowrap"
870 | },
871 | "className": "view"
872 | },
873 | "rect": {
874 | "x": 29,
875 | "y": 550,
876 | "width": 159,
877 | "height": 40
878 | },
879 | "smart": {
880 | "layerProtocol": {
881 | "group": {
882 | "type": "group"
883 | }
884 | }
885 | },
886 | "selfId": "052B0605-F6D2-47D4-BEE0-D3ED6AEF9E1E",
887 | "nodeLayerName": "#group#编组 7",
888 | "children": [{
889 | "componentName": "Text",
890 | "id": "7adedf94-2028-11ec-82f6-bbadaeddfccc",
891 | "props": {
892 | "style": {
893 | "marginTop": "-2px",
894 | "color": "#141414",
895 | "fontFamily": "PingFang SC",
896 | "fontSize": "26px",
897 | "fontWeight": 400
898 | },
899 | "text": "剩",
900 | "lines": 1,
901 | "className": "title"
902 | },
903 | "rect": {
904 | "x": 46,
905 | "y": 552,
906 | "width": 26,
907 | "height": 34
908 | },
909 | "selfId": "21A7BBD8-6A4D-4E94-8309-24422FE7EF260",
910 | "nodeLayerName": "剩3次机会",
911 | "smart": {
912 | "layerProtocol": {
913 | "layout": {
914 | "type": "layout",
915 | "position": "left"
916 | }
917 | }
918 | }
919 | }, {
920 | "componentName": "Text",
921 | "id": "7adedf93-2028-11ec-82f6-bbadaeddfccc",
922 | "props": {
923 | "style": {
924 | "marginTop": "-2px",
925 | "color": "#141414",
926 | "fontFamily": "PingFang SC",
927 | "fontSize": "26px",
928 | "fontWeight": 600
929 | },
930 | "text": "3",
931 | "lines": 1,
932 | "className": "num"
933 | },
934 | "rect": {
935 | "x": 72,
936 | "y": 552,
937 | "width": 16,
938 | "height": 34
939 | },
940 | "selfId": "21A7BBD8-6A4D-4E94-8309-24422FE7EF261",
941 | "nodeLayerName": "剩3次机会",
942 | "smart": {
943 | "layerProtocol": {
944 | "layout": {
945 | "type": "layout",
946 | "position": "middle"
947 | }
948 | }
949 | }
950 | }, {
951 | "componentName": "Text",
952 | "id": "7adedf92-2028-11ec-82f6-bbadaeddfccc",
953 | "props": {
954 | "style": {
955 | "marginTop": "-2px",
956 | "color": "#141414",
957 | "fontFamily": "PingFang SC",
958 | "fontSize": "26px",
959 | "fontWeight": 400
960 | },
961 | "text": "次机会",
962 | "lines": 1,
963 | "className": "caption"
964 | },
965 | "rect": {
966 | "x": 88,
967 | "y": 552,
968 | "width": 78,
969 | "height": 34
970 | },
971 | "selfId": "21A7BBD8-6A4D-4E94-8309-24422FE7EF262",
972 | "nodeLayerName": "剩3次机会",
973 | "smart": {
974 | "layerProtocol": {
975 | "layout": {
976 | "type": "layout",
977 | "position": "right"
978 | }
979 | }
980 | }
981 | }]
982 | }, {
983 | "componentName": "Picture",
984 | "id": "7adf2db2-2028-11ec-82f6-bbadaeddfccc",
985 | "props": {
986 | "style": {
987 | "position": "relative",
988 | "marginTop": "17px",
989 | "width": "367px",
990 | "height": "32px"
991 | },
992 | "className": "bg-1",
993 | "source": {
994 | "uri": "https://img.alicdn.com/imgextra/i3/O1CN01X12MfA1etWqs7cVTJ_!!6000000003929-2-tps-734-64.png"
995 | },
996 | "autoScaling": false,
997 | "autoWebp": false
998 | },
999 | "rect": {
1000 | "x": 54,
1001 | "y": 457,
1002 | "width": 367,
1003 | "height": 32
1004 | },
1005 | "selfId": "060F3E04-18B4-4DDA-8920-2ECC73E2998A",
1006 | "nodeLayerName": "auto-#merge#"
1007 | }]
1008 | }]
1009 | }, {
1010 | "componentName": "Picture",
1011 | "id": "7adf2db0-2028-11ec-82f6-bbadaeddfccc",
1012 | "props": {
1013 | "style": {
1014 | "position": "absolute",
1015 | "top": "0px",
1016 | "left": "0px",
1017 | "width": "174px",
1018 | "height": "119px"
1019 | },
1020 | "className": "entry-pic-3",
1021 | "source": {
1022 | "uri": "https://img.alicdn.com/imgextra/i4/O1CN01VJPeDg24GIwJBQY71_!!6000000007363-2-tps-350-242.png"
1023 | },
1024 | "autoScaling": false,
1025 | "autoWebp": false
1026 | },
1027 | "rect": {
1028 | "x": -46,
1029 | "y": 416,
1030 | "width": 174,
1031 | "height": 119
1032 | },
1033 | "selfId": "22FB7A39-BB83-4147-AEBC-C9AE4279A312",
1034 | "nodeLayerName": "路径 13备份"
1035 | }, {
1036 | "componentName": "View",
1037 | "id": "71020ced-1bfa-4c20-a99f-45e9b1806899",
1038 | "props": {
1039 | "style": {
1040 | "display": "flex",
1041 | "position": "absolute",
1042 | "top": "90px",
1043 | "right": "39px",
1044 | "alignItems": "flex-start",
1045 | "flexDirection": "column",
1046 | "borderWidth": "2px",
1047 | "borderStyle": "solid",
1048 | "borderRadius": "47px",
1049 | "borderColor": "rgba(0,0,0,0.34)",
1050 | "backgroundColor": "rgba(255,255,255,0.10)",
1051 | "width": "405px",
1052 | "height": "94px"
1053 | },
1054 | "className": "wrapper-inner-1"
1055 | },
1056 | "rect": {
1057 | "x": 38,
1058 | "y": 506,
1059 | "width": 405,
1060 | "height": 94
1061 | },
1062 | "smart": {
1063 | "layerProtocol": {
1064 | "group": {
1065 | "type": "group"
1066 | }
1067 | }
1068 | },
1069 | "selfId": "BC8E5221-E691-488C-B245-248F49695067",
1070 | "nodeLayerName": "#group#编组 7",
1071 | "children": [{
1072 | "componentName": "View",
1073 | "id": "03836e10-ebae-4ec0-a420-5af2481aef32",
1074 | "props": {
1075 | "style": {
1076 | "display": "flex",
1077 | "position": "absolute",
1078 | "top": "10px",
1079 | "alignItems": "center",
1080 | "alignSelf": "center",
1081 | "flexDirection": "row",
1082 | "width": "382px",
1083 | "height": "74px"
1084 | },
1085 | "className": "button-bg-wrapper"
1086 | },
1087 | "rect": {
1088 | "x": 50,
1089 | "y": 516,
1090 | "width": 382,
1091 | "height": 74
1092 | },
1093 | "children": [{
1094 | "componentName": "Picture",
1095 | "id": "7adf06a8-2028-11ec-82f6-bbadaeddfccc",
1096 | "props": {
1097 | "style": {
1098 | "position": "absolute",
1099 | "top": "0px",
1100 | "left": "0px",
1101 | "width": "382px",
1102 | "height": "74px",
1103 | "overflow": "hidden"
1104 | },
1105 | "className": "button-bg",
1106 | "source": {
1107 | "uri": "https://img.alicdn.com/imgextra/i2/O1CN01WFD5Ao1LAfM5bJvDk_!!6000000001259-2-tps-764-148.png"
1108 | },
1109 | "autoScaling": false,
1110 | "autoWebp": false
1111 | },
1112 | "rect": {
1113 | "x": 50,
1114 | "y": 516,
1115 | "width": 382,
1116 | "height": 74
1117 | },
1118 | "selfId": "A773A2B6-568B-476E-BC37-B7A76AABC0F5",
1119 | "nodeLayerName": "蒙版"
1120 | }, {
1121 | "componentName": "Picture",
1122 | "id": "7adf06a6-2028-11ec-82f6-bbadaeddfccc",
1123 | "props": {
1124 | "style": {
1125 | "position": "absolute",
1126 | "top": "0px",
1127 | "left": "0px",
1128 | "width": "382px",
1129 | "height": "49px",
1130 | "overflow": "hidden"
1131 | },
1132 | "className": "background-1",
1133 | "source": {
1134 | "uri": "https://img.alicdn.com/imgextra/i4/O1CN01AlJf431gFnjCoaXHg_!!6000000004113-2-tps-764-100.png"
1135 | },
1136 | "autoScaling": false,
1137 | "autoWebp": false
1138 | },
1139 | "rect": {
1140 | "x": 50,
1141 | "y": 516,
1142 | "width": 382,
1143 | "height": 49
1144 | },
1145 | "selfId": "24FC61D3-2330-4387-951D-64906995AD9E",
1146 | "nodeLayerName": "蒙版 2"
1147 | }, {
1148 | "componentName": "Picture",
1149 | "id": "7adf06a3-2028-11ec-82f6-bbadaeddfccc",
1150 | "props": {
1151 | "style": {
1152 | "position": "absolute",
1153 | "top": "16px",
1154 | "right": "150px",
1155 | "width": "79px",
1156 | "height": "38px"
1157 | },
1158 | "className": "large-icon",
1159 | "source": {
1160 | "uri": "https://img.alicdn.com/imgextra/i4/O1CN01mlQkrx1XIFIgOoBNq_!!6000000002900-2-tps-160-80.png"
1161 | },
1162 | "autoScaling": false,
1163 | "autoWebp": false
1164 | },
1165 | "rect": {
1166 | "x": 203,
1167 | "y": 532,
1168 | "width": 79,
1169 | "height": 38
1170 | },
1171 | "selfId": "4503B205-6877-471B-9475-9F04E4AECAFC",
1172 | "nodeLayerName": "抽奖"
1173 | }]
1174 | }]
1175 | }]
1176 | }],
1177 | "imgcook": {
1178 | "restore_id": "5e0484c8-2b4a-497d-afef-00d4cfafcc8b",
1179 | "functions": [{
1180 | "content": "export default function created() {\n\n}",
1181 | "name": "created",
1182 | "type": "lifeCycles"
1183 | }, {
1184 | "content": "export default function mounted() {\n\n}",
1185 | "name": "mounted",
1186 | "type": "lifeCycles"
1187 | }],
1188 | "dataConfig": {
1189 | "schemaLaunchConfigId": "self"
1190 | },
1191 | "defaultReadonlyFiles": ["src/mobile/index.js", "src/mobile/actionsIndex.js", "src/mobile/builtinActions/created.js", "src/mobile/builtinActions/mounted.js", "src/mobile/mod.js", "src/mobile/mod.css", "src/mock.json"],
1192 | "genSettings": {
1193 | "exportClassName": false,
1194 | "appendRpx": true,
1195 | "hasAutoCommit": false
1196 | },
1197 | "devSettings": {
1198 | "autoSync": true,
1199 | "fileLock": false
1200 | }
1201 | }
1202 | }
--------------------------------------------------------------------------------