diff --git a/packages/core/src/mods/settingBar/components/json/index.tsx b/packages/core/src/mods/settingBar/components/json/index.tsx index 4371b53..51fa823 100644 --- a/packages/core/src/mods/settingBar/components/json/index.tsx +++ b/packages/core/src/mods/settingBar/components/json/index.tsx @@ -119,6 +119,7 @@ const EditModal: React.FC = (props) => { value={json} width={'100%'} height={'600px'} + language={'json'} onChange={onChangeJson} /> : diff --git a/packages/core/src/mods/settingBar/mods/basic/index.module.less b/packages/core/src/mods/settingBar/mods/basic/index.module.less index 2d50989..6dd7c2b 100644 --- a/packages/core/src/mods/settingBar/mods/basic/index.module.less +++ b/packages/core/src/mods/settingBar/mods/basic/index.module.less @@ -3,3 +3,7 @@ height: 100%; overflow: scroll; } + +.depsInfoModalContent { + padding-top: 20px; +} \ No newline at end of file diff --git a/packages/core/src/mods/settingBar/mods/basic/index.tsx b/packages/core/src/mods/settingBar/mods/basic/index.tsx index f8d101c..42612e3 100644 --- a/packages/core/src/mods/settingBar/mods/basic/index.tsx +++ b/packages/core/src/mods/settingBar/mods/basic/index.tsx @@ -1,11 +1,18 @@ -import React, { useState, useEffect } from 'react'; +import React, { + useState, + useEffect, +} from 'react'; import styles from './index.module.less'; +import { Modal } from 'antd'; import { Cell, Graph } from '@antv/x6'; +import JsonView from 'react-json-view'; import Json from '../../components/json'; import Code from '../../components/code'; import Input from '../../components/input'; +import { safeParse } from '../../../../utils/index'; +import analyzeDeps from '../../../../utils/analyzeDeps'; interface IProps { selectedCell: Cell; @@ -22,7 +29,7 @@ interface IBasicData { const Basic: React.FC = (props) => { const { selectedCell, flowChart } = props; - const [data, setData] = useState(); + const [data, setData] = useState(selectedCell.getData()); const { label, code, trigger, dependencies, configSchema } = data || {}; // life @@ -31,9 +38,12 @@ const Basic: React.FC = (props) => { }, [selectedCell]); // events + const batchUpdate = (newData: { [key: string]: any }): void => { + selectedCell.setData(newData); + setData(Object.assign({}, data, newData)); + }; const commonChange = (key: string, val: string): void => { - selectedCell.setData({ [key]: val }); - setData(Object.assign({}, data, { [key]: val })); + batchUpdate({ [key]: val }); }; const onChangeLabel = (val: string): void => { commonChange('label', val); @@ -43,9 +53,42 @@ const Basic: React.FC = (props) => { commonChange('configSchema', val); selectedCell.trigger('change:configSchema', { configSchema: val }); }; - const onChangeCode = (val: string): void => commonChange('code', val); - const onChangeTrigger = (val: string): void => commonChange('trigger', val); - const onChangeDependencies = (val: string): void => commonChange('dependencies', val); + const onChangeTrigger = (val: string): void => { + commonChange('trigger', val); + }; + const onChangeDependencies = (val: string): void => { + commonChange('dependencies', val); + }; + const onChangeCode = (val: string): void => { + commonChange('code', val); + // NOTE: if code changes, check whether new dependencies are added + const excludeDeps = safeParse(data?.dependencies as string); + analyzeDeps(val, Object.keys(excludeDeps)).then((deps) => { + if (Object.keys(deps).length > 0) { + Modal.info({ + title: '检测到您的代码有新依赖,已为您自动更新', + content: ( +
+ +
+ ), + onOk() { + batchUpdate({ + code: val, + dependencies: JSON.stringify({ ...excludeDeps, ...deps }, null, 2) + }); + }, + }); + } + }); + }; return (
diff --git a/packages/core/src/utils/analyzeDeps.ts b/packages/core/src/utils/analyzeDeps.ts new file mode 100644 index 0000000..c2ae7c4 --- /dev/null +++ b/packages/core/src/utils/analyzeDeps.ts @@ -0,0 +1,49 @@ +import axios from 'axios'; +import { safeGet } from './index'; + +const regex = /import\s([\s\S]*?)\sfrom\s(?:('[@\.\/\-\w]+')|("[@\.\/\-\w]+"))/mg; + +const extractPkgs = (code: string, excludePkgs?: string[]): string[] => { + let matchRet = null; + const pkgNames: string[] = []; + while ((matchRet = regex.exec(code)) != null) { + let pkgName = (matchRet[2] || matchRet[3]); + pkgName = pkgName.slice(1, pkgName.length - 1); + // NOTE: ignore relative path (./ and ../) and excludePkgs + if ( + pkgName.indexOf('./') === -1 && + pkgName.indexOf('../') === -1 && + excludePkgs?.indexOf(pkgName) === -1 + ) { + pkgNames.push(pkgName); + } + } + return pkgNames; +}; + +const getPkgLatestVersion = (pkg: string): Promise => { + return axios.get(`https://registry.npm.taobao.org/${pkg}`) + .then(res => { + return [pkg, safeGet(res, 'data.dist-tags.latest', '*')]; + }).catch(err => { + console.log(`get package ${pkg} info failed, the error is:`, err); + return [pkg, '*']; + }); +}; + +const analyzeDeps = (code: string, excludePkgs?: string[]): Promise<{ [pkgName: string]: string }> => { + const pkgs = extractPkgs(code, excludePkgs); + return Promise + .all(pkgs.map(pkg => getPkgLatestVersion(pkg))) + .then(pkgResults => { + const map: any = {}; + pkgResults.forEach(([pkg, version]) => { + map[pkg] = version; + }); + return map; + }).catch(err => { + console.log('analyze deps failed, the error is:', err); + }); +}; + +export default analyzeDeps;