mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-29 18:48:45 +08:00
feat: amis 添加更多扩展功能 (#10924)
This commit is contained in:
parent
e0460bf080
commit
cb5e5dca5e
@ -14,6 +14,14 @@ import {render as renderAmis, makeTranslator} from 'amis-core';
|
|||||||
import 'amis/lib/minimal';
|
import 'amis/lib/minimal';
|
||||||
|
|
||||||
import 'amis-ui/lib/locale/en-US';
|
import 'amis-ui/lib/locale/en-US';
|
||||||
|
import 'amis-ui/lib/locale/zh-CN';
|
||||||
|
import 'amis-ui/lib/locale/en-US';
|
||||||
|
import 'amis-ui/lib/locale/de-DE';
|
||||||
|
import 'amis-ui/lib/themes/cxd';
|
||||||
|
import 'amis-ui/lib/themes/ang';
|
||||||
|
import 'amis-ui/lib/themes/antd';
|
||||||
|
import 'amis-ui/lib/themes/dark';
|
||||||
|
|
||||||
import 'history';
|
import 'history';
|
||||||
import {attachmentAdpator} from 'amis-core';
|
import {attachmentAdpator} from 'amis-core';
|
||||||
import {pdfUrlLoad} from './loadPdfjsWorker';
|
import {pdfUrlLoad} from './loadPdfjsWorker';
|
||||||
|
@ -55,3 +55,10 @@ global.afterAll(() => {
|
|||||||
console.error = originalError;
|
console.error = originalError;
|
||||||
cleanup();
|
cleanup();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// expect.addSnapshotSerializer({
|
||||||
|
// test: val => typeof val === 'string' && /^[a-z0-9]{12}$/.test(val),
|
||||||
|
// print: val => {
|
||||||
|
// return JSON.stringify('__guid_dynamic_value__');
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
@ -7,9 +7,8 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {findDOMNode} from 'react-dom';
|
import {findDOMNode} from 'react-dom';
|
||||||
import {ClassNamesFn, themeable} from '../theme';
|
import {ClassNamesFn, themeable} from '../theme';
|
||||||
import {autobind, camel, preventDefault} from '../utils';
|
import {autobind, camel, preventDefault, TestIdBuilder} from '../utils';
|
||||||
import {SubPopoverDisplayedID} from './Overlay';
|
import {SubPopoverDisplayedID} from './Overlay';
|
||||||
import type {TestIdBuilder} from 'amis-core';
|
|
||||||
|
|
||||||
export interface Offset {
|
export interface Offset {
|
||||||
x: number;
|
x: number;
|
||||||
|
@ -195,7 +195,8 @@ function rendererToComponent(
|
|||||||
export function registerRenderer(config: RendererConfig): RendererConfig {
|
export function registerRenderer(config: RendererConfig): RendererConfig {
|
||||||
if (!config.test && !config.type) {
|
if (!config.test && !config.type) {
|
||||||
throw new TypeError('please set config.type or config.test');
|
throw new TypeError('please set config.type or config.test');
|
||||||
} else if (!config.type) {
|
} else if (!config.type && config.name !== 'static') {
|
||||||
|
// todo static 目前还没办法不用 test 来实现
|
||||||
console.warn(
|
console.warn(
|
||||||
`config.type is recommended for register renderer(${config.test})`
|
`config.type is recommended for register renderer(${config.test})`
|
||||||
);
|
);
|
||||||
|
@ -39,7 +39,7 @@ export * from './store';
|
|||||||
import * as utils from './utils/helper';
|
import * as utils from './utils/helper';
|
||||||
import {getEnv} from 'mobx-state-tree';
|
import {getEnv} from 'mobx-state-tree';
|
||||||
|
|
||||||
import {RegisterStore, RendererStore} from './store';
|
import {RegisterStore, registerStore, RendererStore} from './store';
|
||||||
import type {IColumn, IColumn2, IRow, IRow2} from './store';
|
import type {IColumn, IColumn2, IRow, IRow2} from './store';
|
||||||
import {
|
import {
|
||||||
setDefaultLocale,
|
setDefaultLocale,
|
||||||
@ -133,6 +133,7 @@ export {
|
|||||||
RendererEnv,
|
RendererEnv,
|
||||||
EnvContext,
|
EnvContext,
|
||||||
RegisterStore,
|
RegisterStore,
|
||||||
|
registerStore,
|
||||||
FormItem,
|
FormItem,
|
||||||
FormItemWrap,
|
FormItemWrap,
|
||||||
FormItemProps,
|
FormItemProps,
|
||||||
|
@ -114,6 +114,7 @@ export {iRendererStore, IIRendererStore};
|
|||||||
export const RegisterStore = function (store: any) {
|
export const RegisterStore = function (store: any) {
|
||||||
allowedStoreList.push(store as any);
|
allowedStoreList.push(store as any);
|
||||||
};
|
};
|
||||||
|
export const registerStore = RegisterStore;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
ServiceStore,
|
ServiceStore,
|
||||||
|
@ -216,6 +216,18 @@ export type ClassName =
|
|||||||
[propName: string]: boolean | undefined | null | string;
|
[propName: string]: boolean | undefined | null | string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type RequestAdaptor = (
|
||||||
|
api: ApiObject,
|
||||||
|
context: any
|
||||||
|
) => ApiObject | Promise<ApiObject>;
|
||||||
|
|
||||||
|
export type ResponseAdaptor = (
|
||||||
|
payload: object,
|
||||||
|
response: fetcherResult,
|
||||||
|
api: ApiObject,
|
||||||
|
context: any
|
||||||
|
) => any;
|
||||||
|
|
||||||
export interface ApiObject extends BaseApiObject {
|
export interface ApiObject extends BaseApiObject {
|
||||||
config?: {
|
config?: {
|
||||||
withCredentials?: boolean;
|
withCredentials?: boolean;
|
||||||
@ -228,16 +240,8 @@ export interface ApiObject extends BaseApiObject {
|
|||||||
body?: PlainObject;
|
body?: PlainObject;
|
||||||
query?: PlainObject;
|
query?: PlainObject;
|
||||||
mockResponse?: PlainObject;
|
mockResponse?: PlainObject;
|
||||||
adaptor?: (
|
adaptor?: ResponseAdaptor;
|
||||||
payload: object,
|
requestAdaptor?: RequestAdaptor;
|
||||||
response: fetcherResult,
|
|
||||||
api: ApiObject,
|
|
||||||
context: any
|
|
||||||
) => any;
|
|
||||||
requestAdaptor?: (
|
|
||||||
api: ApiObject,
|
|
||||||
context: any
|
|
||||||
) => ApiObject | Promise<ApiObject>;
|
|
||||||
/**
|
/**
|
||||||
* api 发送上下文,可以用来传递一些数据给 api 的 adaptor
|
* api 发送上下文,可以用来传递一些数据给 api 的 adaptor
|
||||||
* @readonly
|
* @readonly
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
import omit from 'lodash/omit';
|
import omit from 'lodash/omit';
|
||||||
import {Api, ApiObject, EventTrack, fetcherResult, Payload} from '../types';
|
import {
|
||||||
|
Api,
|
||||||
|
ApiObject,
|
||||||
|
EventTrack,
|
||||||
|
fetcherResult,
|
||||||
|
Payload,
|
||||||
|
RequestAdaptor,
|
||||||
|
ResponseAdaptor
|
||||||
|
} from '../types';
|
||||||
import {FetcherConfig} from '../factory';
|
import {FetcherConfig} from '../factory';
|
||||||
import {tokenize, dataMapping, escapeHtml} from './tpl-builtin';
|
import {tokenize, dataMapping, escapeHtml} from './tpl-builtin';
|
||||||
import {evalExpression} from './tpl';
|
import {evalExpression} from './tpl';
|
||||||
@ -33,6 +41,44 @@ interface ApiCacheConfig extends ApiObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const apiCaches: Array<ApiCacheConfig> = [];
|
const apiCaches: Array<ApiCacheConfig> = [];
|
||||||
|
const requestAdaptors: Array<RequestAdaptor> = [];
|
||||||
|
const responseAdaptors: Array<ResponseAdaptor> = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加全局发送适配器
|
||||||
|
* @param adaptor
|
||||||
|
*/
|
||||||
|
export function addApiRequestAdaptor(adaptor: RequestAdaptor) {
|
||||||
|
requestAdaptors.push(adaptor);
|
||||||
|
return () => removeApiRequestAdaptor(adaptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除全局发送适配器
|
||||||
|
* @param adaptor
|
||||||
|
*/
|
||||||
|
export function removeApiRequestAdaptor(adaptor: RequestAdaptor) {
|
||||||
|
const idx = requestAdaptors.findIndex(i => i === adaptor);
|
||||||
|
~idx && requestAdaptors.splice(idx, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加全局响应适配器
|
||||||
|
* @param adaptor
|
||||||
|
*/
|
||||||
|
export function addApiResponseAdator(adaptor: ResponseAdaptor) {
|
||||||
|
responseAdaptors.push(adaptor);
|
||||||
|
return () => removeApiResponseAdaptor(adaptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除全局响应适配器
|
||||||
|
* @param adaptor
|
||||||
|
*/
|
||||||
|
export function removeApiResponseAdaptor(adaptor: ResponseAdaptor) {
|
||||||
|
const idx = responseAdaptors.findIndex(i => i === adaptor);
|
||||||
|
~idx && responseAdaptors.splice(idx, 1);
|
||||||
|
}
|
||||||
|
|
||||||
const isIE = !!(document as any).documentMode;
|
const isIE = !!(document as any).documentMode;
|
||||||
|
|
||||||
@ -488,13 +534,17 @@ export function wrapFetcher(
|
|||||||
api = buildApi(api, data, options) as ApiObject;
|
api = buildApi(api, data, options) as ApiObject;
|
||||||
(api as ApiObject).context = data;
|
(api as ApiObject).context = data;
|
||||||
|
|
||||||
|
const adaptors = requestAdaptors.concat();
|
||||||
if (api.requestAdaptor) {
|
if (api.requestAdaptor) {
|
||||||
debug('api', 'before requestAdaptor', api);
|
const adaptor = api.requestAdaptor;
|
||||||
|
adaptors.unshift(async (api: ApiObject, context) => {
|
||||||
const originQuery = api.query;
|
const originQuery = api.query;
|
||||||
const originQueryCopy = isPlainObject(api.query)
|
const originQueryCopy = isPlainObject(api.query)
|
||||||
? cloneDeep(api.query)
|
? cloneDeep(api.query)
|
||||||
: api.query;
|
: api.query;
|
||||||
api = (await api.requestAdaptor(api, data)) || api;
|
|
||||||
|
debug('api', 'before requestAdaptor', api);
|
||||||
|
api = (await adaptor.call(api, api, context)) || api;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
api.query !== originQuery ||
|
api.query !== originQuery ||
|
||||||
@ -502,11 +552,22 @@ export function wrapFetcher(
|
|||||||
) {
|
) {
|
||||||
// 如果 api.data 有变化,且是 get 请求,那么需要重新构建 url
|
// 如果 api.data 有变化,且是 get 请求,那么需要重新构建 url
|
||||||
const idx = api.url.indexOf('?');
|
const idx = api.url.indexOf('?');
|
||||||
api.url = `${~idx ? api.url.substring(0, idx) : api.url}?${qsstringify(
|
api.url = `${
|
||||||
api.query
|
~idx ? api.url.substring(0, idx) : api.url
|
||||||
)}`;
|
}?${qsstringify(api.query)}`;
|
||||||
}
|
}
|
||||||
debug('api', 'after requestAdaptor', api);
|
debug('api', 'after requestAdaptor', api);
|
||||||
|
return api;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行所有的发送适配器
|
||||||
|
if (adaptors.length) {
|
||||||
|
api = await adaptors.reduce(async (api, fn) => {
|
||||||
|
let ret: any = await api;
|
||||||
|
ret = (await fn(ret, data)) || ret;
|
||||||
|
return ret as ApiObject;
|
||||||
|
}, Promise.resolve(api));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -589,15 +650,21 @@ export function wrapFetcher(
|
|||||||
return wrappedFetcher;
|
return wrappedFetcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function wrapAdaptor(
|
export async function wrapAdaptor(
|
||||||
promise: Promise<fetcherResult>,
|
promise: Promise<fetcherResult>,
|
||||||
api: ApiObject,
|
api: ApiObject,
|
||||||
context: any
|
context: any
|
||||||
) {
|
) {
|
||||||
|
const adaptors = responseAdaptors.concat();
|
||||||
|
if (api.adaptor) {
|
||||||
const adaptor = api.adaptor;
|
const adaptor = api.adaptor;
|
||||||
return adaptor
|
adaptors.push(
|
||||||
? promise
|
async (
|
||||||
.then(async response => {
|
payload: object,
|
||||||
|
response: fetcherResult,
|
||||||
|
api: ApiObject,
|
||||||
|
context: any
|
||||||
|
) => {
|
||||||
debug('api', 'before adaptor data', (response as any).data);
|
debug('api', 'before adaptor data', (response as any).data);
|
||||||
let result = adaptor((response as any).data, response, api, context);
|
let result = adaptor((response as any).data, response, api, context);
|
||||||
|
|
||||||
@ -606,14 +673,27 @@ export function wrapAdaptor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
debug('api', 'after adaptor data', result);
|
debug('api', 'after adaptor data', result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await adaptors.reduce(async (promise, adaptor) => {
|
||||||
|
let response: any = await promise;
|
||||||
|
let result =
|
||||||
|
adaptor(response.data, response, api, context) ?? response.data;
|
||||||
|
|
||||||
|
if (result?.then) {
|
||||||
|
result = await result;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...response,
|
...response,
|
||||||
data: result
|
data: result
|
||||||
};
|
} as fetcherResult;
|
||||||
})
|
}, promise);
|
||||||
.then(ret => responseAdaptor(ret, api))
|
|
||||||
: promise.then(ret => responseAdaptor(ret, api));
|
return responseAdaptor(response, api);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,7 +30,7 @@ const external = id =>
|
|||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
input: ['./src/index.ts', './src/doc.ts'],
|
input: ['./src/index.ts'],
|
||||||
output: [
|
output: [
|
||||||
{
|
{
|
||||||
...settings,
|
...settings,
|
||||||
@ -45,7 +45,7 @@ export default [
|
|||||||
plugins: getPlugins('cjs')
|
plugins: getPlugins('cjs')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: ['./src/index.ts', './src/doc.ts'],
|
input: ['./src/index.ts'],
|
||||||
output: [
|
output: [
|
||||||
{
|
{
|
||||||
...settings,
|
...settings,
|
||||||
@ -61,6 +61,23 @@ export default [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
function transpileDynamicImportForCJS(options) {
|
||||||
|
return {
|
||||||
|
name: 'transpile-dynamic-import-for-cjs',
|
||||||
|
renderDynamicImport({format, targetModuleId}) {
|
||||||
|
if (format !== 'cjs') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
left: 'Promise.resolve().then(function() {return new Promise(function(fullfill) {require([',
|
||||||
|
right:
|
||||||
|
', "tslib"], function(mod, tslib) {fullfill(tslib.__importStar(mod))})})})'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function getPlugins(format = 'esm') {
|
function getPlugins(format = 'esm') {
|
||||||
const typeScriptOptions = {
|
const typeScriptOptions = {
|
||||||
typescript: require('typescript'),
|
typescript: require('typescript'),
|
||||||
@ -83,6 +100,7 @@ function getPlugins(format = 'esm') {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
transpileDynamicImportForCJS(),
|
||||||
json(),
|
json(),
|
||||||
resolve({
|
resolve({
|
||||||
jsnext: true,
|
jsnext: true,
|
||||||
|
@ -89,26 +89,14 @@ async function main(...params: Array<any>) {
|
|||||||
|
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
outputFile,
|
outputFile,
|
||||||
`/**\n * 公式文档 请运行 \`npm run genDoc\` 自动生成\n */\nexport const doc: ${[
|
`/**\n * 公式文档 请运行 \`npm run genDoc\` 自动生成\n */\n
|
||||||
`{`,
|
import {bulkRegisterFunctionDoc} from './function';
|
||||||
` name: string;`,
|
|
||||||
` description: string;`,
|
bulkRegisterFunctionDoc(${JSON.stringify(result, null, 2).replace(
|
||||||
` example: string;`,
|
|
||||||
` params: {`,
|
|
||||||
` type: string;`,
|
|
||||||
` name: string;`,
|
|
||||||
` description: string | null;`,
|
|
||||||
` }[];`,
|
|
||||||
` returns: {`,
|
|
||||||
` type: string;`,
|
|
||||||
` description: string | null;`,
|
|
||||||
` };`,
|
|
||||||
` namespace: string;`,
|
|
||||||
`}[]`
|
|
||||||
].join('\n')} = ${JSON.stringify(result, null, 2).replace(
|
|
||||||
/\"(\w+)\"\:/g,
|
/\"(\w+)\"\:/g,
|
||||||
(_, key) => `${key}:`
|
(_, key) => `${key}:`
|
||||||
)};`,
|
)});
|
||||||
|
`,
|
||||||
'utf8'
|
'utf8'
|
||||||
);
|
);
|
||||||
console.log(`公式文档生成 > ${outputFile}`);
|
console.log(`公式文档生成 > ${outputFile}`);
|
||||||
|
@ -1,21 +1,10 @@
|
|||||||
/**
|
/**
|
||||||
* 公式文档 请运行 `npm run genDoc` 自动生成
|
* 公式文档 请运行 `npm run genDoc` 自动生成
|
||||||
*/
|
*/
|
||||||
export const doc: {
|
|
||||||
name: string;
|
import {bulkRegisterFunctionDoc} from './function';
|
||||||
description: string;
|
|
||||||
example: string;
|
bulkRegisterFunctionDoc([
|
||||||
params: {
|
|
||||||
type: string;
|
|
||||||
name: string;
|
|
||||||
description: string | null;
|
|
||||||
}[];
|
|
||||||
returns: {
|
|
||||||
type: string;
|
|
||||||
description: string | null;
|
|
||||||
};
|
|
||||||
namespace: string;
|
|
||||||
}[] = [
|
|
||||||
{
|
{
|
||||||
name: 'IF',
|
name: 'IF',
|
||||||
description:
|
description:
|
||||||
@ -1982,4 +1971,4 @@ export const doc: {
|
|||||||
},
|
},
|
||||||
namespace: '其他'
|
namespace: '其他'
|
||||||
}
|
}
|
||||||
];
|
]);
|
||||||
|
@ -26,14 +26,14 @@ export class Evaluator {
|
|||||||
contextStack: Array<(varname: string) => any> = [];
|
contextStack: Array<(varname: string) => any> = [];
|
||||||
|
|
||||||
static defaultFilters: FilterMap = {};
|
static defaultFilters: FilterMap = {};
|
||||||
static setDefaultFilters(filters: FilterMap) {
|
static extendDefaultFilters(filters: FilterMap) {
|
||||||
Evaluator.defaultFilters = {
|
Evaluator.defaultFilters = {
|
||||||
...Evaluator.defaultFilters,
|
...Evaluator.defaultFilters,
|
||||||
...filters
|
...filters
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
static defaultFunctions: FunctionMap = {};
|
static defaultFunctions: FunctionMap = {};
|
||||||
static setDefaultFunctions(funtions: FunctionMap) {
|
static extendDefaultFunctions(funtions: FunctionMap) {
|
||||||
Evaluator.defaultFunctions = {
|
Evaluator.defaultFunctions = {
|
||||||
...Evaluator.defaultFunctions,
|
...Evaluator.defaultFunctions,
|
||||||
...funtions
|
...funtions
|
||||||
@ -2385,6 +2385,10 @@ export class Evaluator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 兼容
|
||||||
|
(Evaluator as any).setDefaultFilters = Evaluator.extendDefaultFilters;
|
||||||
|
(Evaluator as any).setDefaultFunctions = Evaluator.extendDefaultFunctions;
|
||||||
|
|
||||||
export function getCookie(name: string) {
|
export function getCookie(name: string) {
|
||||||
const value = `; ${document.cookie}`;
|
const value = `; ${document.cookie}`;
|
||||||
const parts = value.split(`; ${name}=`);
|
const parts = value.split(`; ${name}=`);
|
||||||
|
@ -33,12 +33,12 @@ export function registerFilter(
|
|||||||
fn: (input: any, ...args: any[]) => any
|
fn: (input: any, ...args: any[]) => any
|
||||||
): void {
|
): void {
|
||||||
filters[name] = fn;
|
filters[name] = fn;
|
||||||
Evaluator.setDefaultFilters(filters);
|
Evaluator.extendDefaultFilters(filters);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function extendsFilters(value: FilterMap) {
|
export function extendsFilters(value: FilterMap) {
|
||||||
Object.assign(filters, value);
|
Object.assign(filters, value);
|
||||||
Evaluator.setDefaultFilters(filters);
|
Evaluator.extendDefaultFilters(filters);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFilters() {
|
export function getFilters() {
|
||||||
|
@ -1,17 +1,16 @@
|
|||||||
import {Evaluator} from './evalutor';
|
import {Evaluator} from './evalutor';
|
||||||
import {FunctionMap, FunctionDocMap, FunctionDocItem} from './types';
|
import {FunctionDocMap, FunctionDocItem} from './types';
|
||||||
|
|
||||||
export const functions: FunctionMap = {};
|
|
||||||
|
|
||||||
export function registerFunction(
|
export function registerFunction(
|
||||||
name: string,
|
name: string,
|
||||||
fn: (input: any, ...args: any[]) => any
|
fn: (this: Evaluator, ...args: Array<any>) => any
|
||||||
): void {
|
): void {
|
||||||
functions[`fn${name}`] = fn;
|
Evaluator.extendDefaultFunctions({
|
||||||
Evaluator.setDefaultFunctions(functions);
|
[`fn${name}`]: fn
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export let functionDocs: FunctionDocMap = {};
|
export const functionDocs: FunctionDocMap = {};
|
||||||
|
|
||||||
export function registerFunctionDoc(groupName: string, item: FunctionDocItem) {
|
export function registerFunctionDoc(groupName: string, item: FunctionDocItem) {
|
||||||
if (functionDocs[groupName]) {
|
if (functionDocs[groupName]) {
|
||||||
@ -20,3 +19,38 @@ export function registerFunctionDoc(groupName: string, item: FunctionDocItem) {
|
|||||||
functionDocs[groupName] = [item];
|
functionDocs[groupName] = [item];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function bulkRegisterFunctionDoc(
|
||||||
|
fnDocs: {
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
example: string;
|
||||||
|
params: {
|
||||||
|
type: string;
|
||||||
|
name: string;
|
||||||
|
description: string | null;
|
||||||
|
}[];
|
||||||
|
returns: {
|
||||||
|
type: string;
|
||||||
|
description: string | null;
|
||||||
|
};
|
||||||
|
namespace: string;
|
||||||
|
}[]
|
||||||
|
) {
|
||||||
|
fnDocs.forEach(item => registerFunctionDoc(item.namespace || 'Others', item));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册公式,并同时注册公式说明
|
||||||
|
* @param name
|
||||||
|
* @param fn
|
||||||
|
* @param fnInfo
|
||||||
|
*/
|
||||||
|
export function registerFormula(
|
||||||
|
name: string,
|
||||||
|
fn: (this: Evaluator, ...args: Array<any>) => any,
|
||||||
|
fnInfo?: FunctionDocItem
|
||||||
|
) {
|
||||||
|
registerFunction(name, fn);
|
||||||
|
fnInfo && registerFunctionDoc(fnInfo.namespace || 'Others', fnInfo);
|
||||||
|
}
|
||||||
|
@ -3,7 +3,12 @@ import {AsyncEvaluator} from './evalutorForAsync';
|
|||||||
import {parse} from './parser';
|
import {parse} from './parser';
|
||||||
import {lexer} from './lexer';
|
import {lexer} from './lexer';
|
||||||
import {registerFilter, filters, getFilters, extendsFilters} from './filter';
|
import {registerFilter, filters, getFilters, extendsFilters} from './filter';
|
||||||
import {registerFunction, registerFunctionDoc, functionDocs} from './function';
|
import {
|
||||||
|
registerFunction,
|
||||||
|
registerFunctionDoc,
|
||||||
|
functionDocs,
|
||||||
|
registerFormula
|
||||||
|
} from './function';
|
||||||
import type {
|
import type {
|
||||||
FilterContext,
|
FilterContext,
|
||||||
ASTNode,
|
ASTNode,
|
||||||
@ -19,9 +24,9 @@ export {
|
|||||||
filters,
|
filters,
|
||||||
getFilters,
|
getFilters,
|
||||||
registerFilter,
|
registerFilter,
|
||||||
|
registerFormula,
|
||||||
registerFunction,
|
registerFunction,
|
||||||
registerFunctionDoc,
|
registerFunctionDoc,
|
||||||
functionDocs,
|
|
||||||
extendsFilters
|
extendsFilters
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -53,5 +58,14 @@ export async function evaluateForAsync(
|
|||||||
return new AsyncEvaluator(data, options).evalute(ast);
|
return new AsyncEvaluator(data, options).evalute(ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
Evaluator.setDefaultFilters(getFilters());
|
Evaluator.extendDefaultFilters(getFilters());
|
||||||
AsyncEvaluator.setDefaultFilters(getFilters());
|
AsyncEvaluator.setDefaultFilters(getFilters());
|
||||||
|
|
||||||
|
export async function getFunctionsDoc() {
|
||||||
|
await import('./doc');
|
||||||
|
|
||||||
|
return Object.entries(functionDocs).map(([k, items]) => ({
|
||||||
|
groupName: k,
|
||||||
|
items
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
@ -5,13 +5,14 @@ export interface FilterMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface FunctionMap {
|
export interface FunctionMap {
|
||||||
[propName: string]: (this: Evaluator, ast: Object, data: any) => any;
|
[propName: string]: (this: Evaluator, ...args: Array<any>) => any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FunctionDocItem {
|
export interface FunctionDocItem {
|
||||||
name: string; // 函数名
|
name: string; // 函数名
|
||||||
example?: string; // 示例
|
example?: string; // 示例
|
||||||
description?: string; // 描述
|
description?: string; // 描述
|
||||||
|
namespace?: string;
|
||||||
[propName: string]: any;
|
[propName: string]: any;
|
||||||
}
|
}
|
||||||
export interface FunctionDocMap {
|
export interface FunctionDocMap {
|
||||||
|
3
packages/amis-ui/src/components/Menu.tsx
Normal file
3
packages/amis-ui/src/components/Menu.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import Menu from './menu/index';
|
||||||
|
|
||||||
|
export default Menu;
|
3
packages/amis-ui/src/components/Table.tsx
Normal file
3
packages/amis-ui/src/components/Table.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import Table from './table/index';
|
||||||
|
|
||||||
|
export default Table;
|
@ -15,15 +15,13 @@ import {
|
|||||||
localeable,
|
localeable,
|
||||||
LocaleProps
|
LocaleProps
|
||||||
} from 'amis-core';
|
} from 'amis-core';
|
||||||
import type {FunctionDocMap} from 'amis-formula/lib/types';
|
|
||||||
|
|
||||||
import {editorFactory} from './plugin';
|
import {editorFactory} from './plugin';
|
||||||
import FuncList from './FuncList';
|
import FuncList from './FuncList';
|
||||||
import VariableList from './VariableList';
|
import VariableList from './VariableList';
|
||||||
import {toast} from '../Toast';
|
import {toast} from '../Toast';
|
||||||
import Switch from '../Switch';
|
import Switch from '../Switch';
|
||||||
import CodeEditor, {FuncGroup, FuncItem, VariableItem} from './CodeEditor';
|
import CodeEditor, {FuncGroup, FuncItem, VariableItem} from './CodeEditor';
|
||||||
import {functionDocs} from 'amis-formula';
|
import {getFunctionsDoc} from 'amis-formula';
|
||||||
import Transition, {
|
import Transition, {
|
||||||
EXITED,
|
EXITED,
|
||||||
ENTERING,
|
ENTERING,
|
||||||
@ -130,49 +128,13 @@ export class FormulaEditor extends React.Component<
|
|||||||
unmounted: boolean = false;
|
unmounted: boolean = false;
|
||||||
editor = React.createRef<any>();
|
editor = React.createRef<any>();
|
||||||
|
|
||||||
static buildDefaultFunctions(
|
|
||||||
doc: Array<{
|
|
||||||
namespace: string;
|
|
||||||
name: string;
|
|
||||||
[propName: string]: any;
|
|
||||||
}>
|
|
||||||
) {
|
|
||||||
const funcs: Array<FuncGroup> = [];
|
|
||||||
|
|
||||||
doc.forEach(item => {
|
|
||||||
const namespace = item.namespace || 'Others';
|
|
||||||
let exists = funcs.find(item => item.groupName === namespace);
|
|
||||||
if (!exists) {
|
|
||||||
exists = {
|
|
||||||
groupName: namespace,
|
|
||||||
items: []
|
|
||||||
};
|
|
||||||
funcs.push(exists);
|
|
||||||
}
|
|
||||||
exists.items.push(item);
|
|
||||||
});
|
|
||||||
|
|
||||||
return funcs;
|
|
||||||
}
|
|
||||||
|
|
||||||
static buildCustomFunctions(map: FunctionDocMap = {}) {
|
|
||||||
return Object.entries(map).map(([k, items]) => ({
|
|
||||||
groupName: k,
|
|
||||||
items
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
static async buildFunctions(
|
static async buildFunctions(
|
||||||
functions?: Array<any>,
|
functions?: Array<any>,
|
||||||
functionsFilter?: (functions: Array<FuncGroup>) => Array<FuncGroup>
|
functionsFilter?: (functions: Array<FuncGroup>) => Array<FuncGroup>
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
const {doc} = await import('amis-formula/lib/doc');
|
const builtInFunctions = await getFunctionsDoc();
|
||||||
const customFunctions = Array.isArray(functions) ? functions : [];
|
const customFunctions = Array.isArray(functions) ? functions : [];
|
||||||
const functionList = [
|
const functionList = [...builtInFunctions, ...customFunctions];
|
||||||
...FormulaEditor.buildDefaultFunctions(doc),
|
|
||||||
...FormulaEditor.buildCustomFunctions(functionDocs),
|
|
||||||
...customFunctions
|
|
||||||
];
|
|
||||||
|
|
||||||
if (functionsFilter) {
|
if (functionsFilter) {
|
||||||
return functionsFilter(functionList);
|
return functionsFilter(functionList);
|
||||||
|
@ -24,7 +24,6 @@ import Modal from '../Modal';
|
|||||||
import PopUp from '../PopUp';
|
import PopUp from '../PopUp';
|
||||||
import FormulaInput from './Input';
|
import FormulaInput from './Input';
|
||||||
import {FuncGroup, VariableItem} from './CodeEditor';
|
import {FuncGroup, VariableItem} from './CodeEditor';
|
||||||
import {functionDocs} from 'amis-formula';
|
|
||||||
|
|
||||||
export const InputSchemaType = [
|
export const InputSchemaType = [
|
||||||
'text',
|
'text',
|
||||||
|
@ -70,7 +70,7 @@ import TableSelection from './TableSelection';
|
|||||||
import TreeSelection from './TreeSelection';
|
import TreeSelection from './TreeSelection';
|
||||||
import AssociatedSelection from './AssociatedSelection';
|
import AssociatedSelection from './AssociatedSelection';
|
||||||
import PullRefresh from './PullRefresh';
|
import PullRefresh from './PullRefresh';
|
||||||
import Table from './table';
|
import Table from './Table';
|
||||||
import SchemaVariableListPicker from './schema-editor/SchemaVariableListPicker';
|
import SchemaVariableListPicker from './schema-editor/SchemaVariableListPicker';
|
||||||
import SchemaVariableList from './schema-editor/SchemaVariableList';
|
import SchemaVariableList from './schema-editor/SchemaVariableList';
|
||||||
import VariableList from './formula/VariableList';
|
import VariableList from './formula/VariableList';
|
||||||
@ -132,7 +132,7 @@ import InputTable from './InputTable';
|
|||||||
import type {InputTableColumnProps} from './InputTable';
|
import type {InputTableColumnProps} from './InputTable';
|
||||||
import ConfirmBox from './ConfirmBox';
|
import ConfirmBox from './ConfirmBox';
|
||||||
import DndContainer from './DndContainer';
|
import DndContainer from './DndContainer';
|
||||||
import Menu from './menu';
|
import Menu from './Menu';
|
||||||
import InputBoxWithSuggestion from './InputBoxWithSuggestion';
|
import InputBoxWithSuggestion from './InputBoxWithSuggestion';
|
||||||
import {CodeMirrorEditor} from './CodeMirror';
|
import {CodeMirrorEditor} from './CodeMirror';
|
||||||
import type CodeMirror from 'codemirror';
|
import type CodeMirror from 'codemirror';
|
||||||
|
@ -12,5 +12,11 @@ import './themes/default';
|
|||||||
import type {SchemaEditorItemPlaceholder} from './components/schema-editor/Common';
|
import type {SchemaEditorItemPlaceholder} from './components/schema-editor/Common';
|
||||||
import {schemaEditorItemPlaceholder} from './components/schema-editor/Common';
|
import {schemaEditorItemPlaceholder} from './components/schema-editor/Common';
|
||||||
import withStore from './withStore';
|
import withStore from './withStore';
|
||||||
|
import withRemoteConfig from './withRemoteConfig';
|
||||||
|
|
||||||
export {schemaEditorItemPlaceholder, SchemaEditorItemPlaceholder, withStore};
|
export {
|
||||||
|
schemaEditorItemPlaceholder,
|
||||||
|
SchemaEditorItemPlaceholder,
|
||||||
|
withStore,
|
||||||
|
withRemoteConfig
|
||||||
|
};
|
||||||
|
2
packages/amis-ui/src/withRemoteConfig.ts
Normal file
2
packages/amis-ui/src/withRemoteConfig.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
import {withRemoteConfig} from './components/WithRemoteConfig';
|
||||||
|
export default withRemoteConfig;
|
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,7 @@ import * as renderer from 'react-test-renderer';
|
|||||||
import {fireEvent, render, waitFor} from '@testing-library/react';
|
import {fireEvent, render, waitFor} from '@testing-library/react';
|
||||||
import '../../../src';
|
import '../../../src';
|
||||||
import {render as amisRender} from '../../../src';
|
import {render as amisRender} from '../../../src';
|
||||||
import {makeEnv} from '../../helper';
|
import {makeEnv, replaceReactAriaIds, wait} from '../../helper';
|
||||||
|
|
||||||
test('doAction:crud reload', async () => {
|
test('doAction:crud reload', async () => {
|
||||||
const notify = jest.fn();
|
const notify = jest.fn();
|
||||||
@ -243,6 +243,8 @@ test('doAction:crud reload', async () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await wait(500);
|
||||||
|
replaceReactAriaIds(container);
|
||||||
expect(container).toMatchSnapshot();
|
expect(container).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -407,6 +409,7 @@ test('doAction:crud reload with data1', async () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
replaceReactAriaIds(container);
|
||||||
expect(container).toMatchSnapshot();
|
expect(container).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -574,5 +577,6 @@ test('doAction:crud reload with data2', async () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
replaceReactAriaIds(container);
|
||||||
expect(container).toMatchSnapshot();
|
expect(container).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
@ -112,6 +112,13 @@ export function replaceReactAriaIds(container: HTMLElement) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
container.querySelectorAll('[data-id]').forEach(el => {
|
||||||
|
const val = el.getAttribute('data-id');
|
||||||
|
if (typeof val === 'string' && /^[a-z0-9]{12}$/.test(val)) {
|
||||||
|
el.removeAttribute('data-id');
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mock IntersectionObserver
|
// Mock IntersectionObserver
|
||||||
|
@ -24,7 +24,6 @@ import {
|
|||||||
import '../../../src';
|
import '../../../src';
|
||||||
import {render as amisRender, clearStoresCache} from '../../../src';
|
import {render as amisRender, clearStoresCache} from '../../../src';
|
||||||
import {makeEnv, replaceReactAriaIds, wait} from '../../helper';
|
import {makeEnv, replaceReactAriaIds, wait} from '../../helper';
|
||||||
import {Select} from 'packages/amis-ui/lib/components/Select';
|
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
cleanup();
|
cleanup();
|
||||||
|
@ -226,7 +226,8 @@
|
|||||||
"\\.svg\\.js$": "<rootDir>/../../__mocks__/svgJsMock.js",
|
"\\.svg\\.js$": "<rootDir>/../../__mocks__/svgJsMock.js",
|
||||||
"^amis\\-core$": "<rootDir>/../amis-core/src/index.tsx",
|
"^amis\\-core$": "<rootDir>/../amis-core/src/index.tsx",
|
||||||
"^amis\\-ui$": "<rootDir>/../amis-ui/src/index.tsx",
|
"^amis\\-ui$": "<rootDir>/../amis-ui/src/index.tsx",
|
||||||
"^amis\\-ui/lib/(.*)$": "<rootDir>/../amis-ui/src/$1"
|
"^amis\\-ui/lib/(.*)$": "<rootDir>/../amis-ui/src/$1",
|
||||||
|
"^amis\\-formula$": "<rootDir>/../amis-formula/src/index.ts"
|
||||||
},
|
},
|
||||||
"setupFilesAfterEnv": [
|
"setupFilesAfterEnv": [
|
||||||
"<rootDir>/../amis-core/__tests__/jest.setup.js"
|
"<rootDir>/../amis-core/__tests__/jest.setup.js"
|
||||||
|
@ -227,7 +227,7 @@ function getPlugins(format = 'esm') {
|
|||||||
return `amis-ui/lib/components/Toast`;
|
return `amis-ui/lib/components/Toast`;
|
||||||
} else if ('NotFound' === name) {
|
} else if ('NotFound' === name) {
|
||||||
return `amis-ui/lib/components/404`;
|
return `amis-ui/lib/components/404`;
|
||||||
} else if ('withStore' === name) {
|
} else if (['withStore', 'withRemoteConfig'].includes(name)) {
|
||||||
return `amis-ui/lib/${name}`;
|
return `amis-ui/lib/${name}`;
|
||||||
} /* else if (name[0].toUpperCase() === name[0]) {
|
} /* else if (name[0].toUpperCase() === name[0]) {
|
||||||
return `amis-ui/lib/components/${name}`;
|
return `amis-ui/lib/components/${name}`;
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
export * from 'amis-core';
|
export * from 'amis-core';
|
||||||
export * from 'amis-ui';
|
export * from 'amis-ui';
|
||||||
import './minimal';
|
import './minimal';
|
||||||
|
import {registerFilter, registerFormula} from 'amis-formula';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
BaseSchema,
|
BaseSchema,
|
||||||
@ -44,5 +45,7 @@ export {
|
|||||||
SchemaExpression,
|
SchemaExpression,
|
||||||
Action,
|
Action,
|
||||||
SchemaType,
|
SchemaType,
|
||||||
EditorAvailableLanguages
|
EditorAvailableLanguages,
|
||||||
|
registerFilter,
|
||||||
|
registerFormula
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user