-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #62 from drdevelop/feat/dynamic_schema
Feat/dynamic schema #60
- Loading branch information
Showing
5 changed files
with
185 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
--- | ||
nav: | ||
title: schema表单 | ||
group: 进阶使用 | ||
title: 服务端动态维护schema | ||
order: 6 | ||
toc: content | ||
--- | ||
|
||
## schema转换成字符串存入服务端 | ||
|
||
```tsx | ||
/** | ||
* title: 调用stringifySchema方法将schema对象转成字符串 | ||
*/ | ||
import React, { useState } from 'react'; | ||
import { Form, Button } from 'antd' | ||
import SchemaForm, { stringifySchema } from 'antd-pro-schema-form'; | ||
|
||
export default () => { | ||
const [form] = Form.useForm(); | ||
const [schemaStr, setSchemaStr] = useState(); | ||
|
||
const schema = [{ | ||
fieldName: 'schema', | ||
label: 'Schema', | ||
type: 'textarea', | ||
mapStateToSchema(globalState) { // 这种方式stringify后的parse无法还原函数,只有箭头函数才行 | ||
return { data: globalState }; | ||
} | ||
}]; | ||
|
||
const onSubmit = () => { | ||
const schemaObj = new Function(`return (${form.getFieldsValue().schema})`)(); | ||
setSchemaStr(stringifySchema(schemaObj)); // 转换schema对象为字符串 | ||
}; | ||
|
||
return ( | ||
<> | ||
<SchemaForm form={form} schema={schema} /> | ||
<Button type="primary" onClick={onSubmit}> | ||
一键提取服务端可存储的schema | ||
</Button> | ||
<div style={{ color: 'red' }}>服务端schema:</div> | ||
<div>{schemaStr}</div> | ||
</> | ||
) | ||
} | ||
``` | ||
|
||
|
||
## 将服务端schema字符串格式转换成对象模式 | ||
|
||
```tsx | ||
/** | ||
* title: 调用parseSchema方法将schema字符串转成SchemaForm可识别的对象schema格式 | ||
*/ | ||
import React, { useState, useMemo } from 'react'; | ||
import { Form, Button } from 'antd' | ||
import SchemaForm, { parseSchema } from 'antd-pro-schema-form'; | ||
|
||
export default () => { | ||
const [form] = Form.useForm(); | ||
|
||
const [parsedSchema, setParsedSchema] = useState(); | ||
const schema = [{ | ||
fieldName: 'schema', | ||
label: '服务端Schema', | ||
type: 'textarea', | ||
}]; | ||
|
||
const onSubmit = () => { | ||
setParsedSchema(parseSchema(form.getFieldValue('schema'))); | ||
} | ||
|
||
return ( | ||
<> | ||
<h2>输入服务端schema字符串:</h2> | ||
<SchemaForm form={form} schema={schema} /> | ||
<Button type="primary" onClick={onSubmit}> | ||
一键解析服务端的schema字符串并渲染 | ||
</Button> | ||
<h2>解析后的schema渲染后的表单: </h2> | ||
{ parsedSchema && <SchemaForm schema={parsedSchema} /> } | ||
</> | ||
) | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import { Schema } from '../core/types'; | ||
import { isFunction, isRegExp } from './helper'; | ||
|
||
function replacer(key: string, value: any) { | ||
if (isFunction(value)) { | ||
const fnStr = value.toString().replaceAll('\n', ''); | ||
// case1: { a: () => 1 } | ||
// case2: { a() {} } | ||
// case3: { a: function() {} } | ||
// case4: { a: function() { return () => 1 }} | ||
return ( | ||
/^\s?\([^;]*?\)\s?=>/.test(fnStr) || /^\s?function/.test(fnStr) | ||
? fnStr | ||
: 'function ' + fnStr | ||
); | ||
} | ||
if (isRegExp(value)) { | ||
return value.toString(); | ||
} | ||
return value; | ||
} | ||
|
||
export function stringifySchema(schema: Schema<any>) { | ||
try { | ||
return JSON.stringify(schema, replacer, 2).replaceAll('\\n', '\n'); | ||
} catch (err) { | ||
console.error('stringify error', err); | ||
return schema; | ||
} | ||
} | ||
|
||
function reviver(key: string, value: any) { | ||
try { | ||
// eslint-disable-next-line | ||
const computedVal = new Function(`return (${value})`)(); | ||
if (isFunction(computedVal) || isRegExp(computedVal)) { | ||
return computedVal; | ||
} else { | ||
return value; | ||
} | ||
} catch (err) { | ||
return value; | ||
} | ||
} | ||
|
||
// TODO: XSS defense | ||
/** | ||
* parse schema from server | ||
* !!!Don't use ToC scene,Because you will definitely encounter css attacks, | ||
* Unless you do some encode for schema str | ||
*/ | ||
export function parseSchema(schema: string) { | ||
try { | ||
return JSON.parse(schema, reviver); | ||
} catch (err) { | ||
console.error('parse error', err); | ||
return schema; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import React from 'react'; | ||
import SchemaForm, { stringifySchema, parseSchema } from '../../src'; | ||
import { render, screen } from '@testing-library/react'; | ||
import '@testing-library/jest-dom'; | ||
|
||
it('stringify schema', () => { | ||
// eslint-disable-next-line | ||
// @ts-ignore | ||
// eslint-disable-next-line | ||
expect(stringifySchema({a: 1})).toBe( | ||
// eslint-disable-next-line | ||
`{ | ||
"a": 1 | ||
}`, | ||
); | ||
}); | ||
|
||
function TestComponent() { | ||
const schema = parseSchema(` | ||
[ { "fieldName": "schema", "label": "schema", "type": "textarea" } ] | ||
`); | ||
return <SchemaForm schema={schema} />; | ||
} | ||
|
||
it('parse schema', () => { | ||
render(<TestComponent />); | ||
expect(screen.getByText('schema')).toBeInTheDocument(); | ||
}); |