feat: amis 添加更多扩展功能 (#10924)

This commit is contained in:
liaoxuezhi 2024-09-18 19:03:49 +08:00 committed by GitHub
parent e0460bf080
commit cb5e5dca5e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 1276 additions and 161 deletions

View File

@ -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';

View File

@ -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__');
// }
// });

View File

@ -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;

View File

@ -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})`
); );

View File

@ -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,

View File

@ -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,

View File

@ -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

View File

@ -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);
} }
/** /**

View File

@ -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,

View File

@ -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}`);

View File

@ -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: '其他'
} }
]; ]);

View File

@ -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}=`);

View File

@ -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() {

View File

@ -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);
}

View File

@ -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
}));
}

View File

@ -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 {

View File

@ -0,0 +1,3 @@
import Menu from './menu/index';
export default Menu;

View File

@ -0,0 +1,3 @@
import Table from './table/index';
export default Table;

View File

@ -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);

View File

@ -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',

View File

@ -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';

View File

@ -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
};

View File

@ -0,0 +1,2 @@
import {withRemoteConfig} from './components/WithRemoteConfig';
export default withRemoteConfig;

View File

@ -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();
}); });

View File

@ -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

View File

@ -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();

View File

@ -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"

View File

@ -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}`;

View File

@ -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
}; };