Match-id-4d95f32e780a098aa863161118eff06d7a040b5c
This commit is contained in:
commit
5484fa748a
|
@ -0,0 +1,37 @@
|
||||||
|
version: '2.0'
|
||||||
|
notifications:
|
||||||
|
notifier:
|
||||||
|
espace:
|
||||||
|
'on': false
|
||||||
|
email:
|
||||||
|
'on': false
|
||||||
|
buildspace:
|
||||||
|
log_collect:
|
||||||
|
- config/CI/build/logs
|
||||||
|
fixed: true
|
||||||
|
env:
|
||||||
|
resource:
|
||||||
|
type: docker
|
||||||
|
image: kweecr04.his.huawei.com:80/ecr-build-arm-gzkunpeng/euleros_v2r7spc522_x64_opmt_cs5.0_sz:v5.0
|
||||||
|
class: 4U8G
|
||||||
|
mode: toolbox
|
||||||
|
cache:
|
||||||
|
- type: workspace
|
||||||
|
steps:
|
||||||
|
PRE_BUILD:
|
||||||
|
- checkout:
|
||||||
|
path: horizon-core
|
||||||
|
- gitlab:
|
||||||
|
url: https://szv-y.codehub.huawei.com/CloudSOP/CloudSOP-CI.git
|
||||||
|
branch: $branch
|
||||||
|
path: CI
|
||||||
|
BUILD:
|
||||||
|
- build_execute:
|
||||||
|
command: |
|
||||||
|
npm install yarn -g
|
||||||
|
yarn config set strict-ssl false
|
||||||
|
cd horizon-core
|
||||||
|
yarn
|
||||||
|
yarn run test
|
||||||
|
yarn run build
|
||||||
|
node .cloudbuild/release.js
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const childProcess = require('child_process');
|
||||||
|
|
||||||
|
const version = process.env.releaseVersion;
|
||||||
|
const DIST_PATH = path.resolve(__dirname, '../build/horizon');
|
||||||
|
|
||||||
|
const NPMRC = `registry=https://cmc.centralrepo.rnd.huawei.com/npm
|
||||||
|
@cloudsop:registry=https://cmc.centralrepo.rnd.huawei.com/artifactory/product_npm
|
||||||
|
_auth = Y2xvdWRzb3BhcnRpZmFjdG9yeTpDbG91ZHNvcDY2NiEhIQ
|
||||||
|
always-auth = true
|
||||||
|
email = cloudsop@huawei.com
|
||||||
|
`;
|
||||||
|
if (!version) {
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
if (!/\d+\.\d+\.\d+/.test(version)) {
|
||||||
|
console.log('请输入正确版本号');
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
const exec = (cmd, cwd) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
childProcess.exec(
|
||||||
|
cmd,
|
||||||
|
{
|
||||||
|
cwd,
|
||||||
|
},
|
||||||
|
function (error, stdout, stderr) {
|
||||||
|
if (error) {
|
||||||
|
error && console.log(`Error: ${error}`);
|
||||||
|
reject(error);
|
||||||
|
} else {
|
||||||
|
stdout && console.log(`STDOUT: ${stdout}`);
|
||||||
|
resolve(stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const main = async () => {
|
||||||
|
try {
|
||||||
|
console.log(`==== Horizon Upgrade ${version} ====`);
|
||||||
|
await exec(`npm version ${version}`, DIST_PATH);
|
||||||
|
fs.writeFileSync(path.resolve(DIST_PATH, '.npmrc'), NPMRC);
|
||||||
|
|
||||||
|
console.log('==== Publish new version====');
|
||||||
|
await exec('npm publish', DIST_PATH);
|
||||||
|
process.exit();
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
main();
|
|
@ -0,0 +1,37 @@
|
||||||
|
version: '2.0'
|
||||||
|
notifications:
|
||||||
|
notifier:
|
||||||
|
espace:
|
||||||
|
'on': false
|
||||||
|
email:
|
||||||
|
'on': false
|
||||||
|
buildspace:
|
||||||
|
log_collect:
|
||||||
|
- config/CI/build/logs
|
||||||
|
fixed: true
|
||||||
|
env:
|
||||||
|
resource:
|
||||||
|
type: docker
|
||||||
|
image: kweecr04.his.huawei.com:80/ecr-build-arm-gzkunpeng/euleros_v2r7spc522_x64_opmt_cs5.0_sz:v5.0
|
||||||
|
class: 4U8G
|
||||||
|
mode: toolbox
|
||||||
|
cache:
|
||||||
|
- type: workspace
|
||||||
|
steps:
|
||||||
|
PRE_BUILD:
|
||||||
|
- checkout:
|
||||||
|
path: horizon-core
|
||||||
|
- gitlab:
|
||||||
|
url: https://szv-open.codehub.huawei.com/innersource/shanhai/wutong/react/horizon-test.git
|
||||||
|
branch: one_tree_dev
|
||||||
|
path: horizon-test
|
||||||
|
BUILD:
|
||||||
|
- build_execute:
|
||||||
|
command: |
|
||||||
|
npm install yarn -g
|
||||||
|
yarn config set strict-ssl false
|
||||||
|
cd horizon-core
|
||||||
|
yarn
|
||||||
|
cd ../horizon-test
|
||||||
|
yarn
|
||||||
|
yarn run test
|
|
@ -1,3 +1,6 @@
|
||||||
|
## 0.0.13 (2022-08-02)
|
||||||
|
- **horizonX**: 修复redux兼容器bug
|
||||||
|
|
||||||
## 0.0.12 (2022-07-25)
|
## 0.0.12 (2022-07-25)
|
||||||
- 修复IE兼容性问题,IE环境下Event只读,导致合成事件逻辑报错
|
- 修复IE兼容性问题,IE环境下Event只读,导致合成事件逻辑报错
|
||||||
|
|
||||||
|
|
|
@ -1,38 +1,34 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
presets: [
|
presets: ['@babel/preset-typescript', ['@babel/preset-env', { targets: { node: 'current' } }]],
|
||||||
'@babel/react',
|
|
||||||
'@babel/preset-typescript',
|
|
||||||
['@babel/preset-env', { targets: { node: 'current' } }]
|
|
||||||
],
|
|
||||||
plugins: [
|
plugins: [
|
||||||
['@babel/plugin-proposal-class-properties', { loose: true }],
|
'@babel/plugin-syntax-jsx',
|
||||||
[
|
[
|
||||||
'@babel/plugin-proposal-object-rest-spread',
|
'@babel/plugin-transform-react-jsx',
|
||||||
{ loose: true, useBuiltIns: true },
|
{
|
||||||
|
pragma: 'Horizon.createElement',
|
||||||
|
pragmaFrag: 'Horizon.Fragment',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
['@babel/plugin-transform-template-literals', { loose: true }],
|
['@babel/plugin-proposal-class-properties', { loose: true }],
|
||||||
|
['@babel/plugin-proposal-private-methods', { loose: true }],
|
||||||
|
['@babel/plugin-proposal-private-property-in-object', { loose: true }],
|
||||||
'@babel/plugin-transform-object-assign',
|
'@babel/plugin-transform-object-assign',
|
||||||
'@babel/plugin-transform-literals',
|
|
||||||
'@babel/plugin-transform-arrow-functions',
|
|
||||||
'@babel/plugin-transform-block-scoped-functions',
|
|
||||||
'@babel/plugin-transform-object-super',
|
'@babel/plugin-transform-object-super',
|
||||||
|
['@babel/plugin-proposal-object-rest-spread', { loose: true, useBuiltIns: true }],
|
||||||
|
['@babel/plugin-transform-template-literals', { loose: true }],
|
||||||
|
'@babel/plugin-transform-arrow-functions',
|
||||||
|
'@babel/plugin-transform-literals',
|
||||||
|
'@babel/plugin-transform-for-of',
|
||||||
|
'@babel/plugin-transform-block-scoped-functions',
|
||||||
|
'@babel/plugin-transform-classes',
|
||||||
'@babel/plugin-transform-shorthand-properties',
|
'@babel/plugin-transform-shorthand-properties',
|
||||||
'@babel/plugin-transform-computed-properties',
|
'@babel/plugin-transform-computed-properties',
|
||||||
'@babel/plugin-transform-for-of',
|
|
||||||
['@babel/plugin-transform-spread', { loose: true, useBuiltIns: true }],
|
|
||||||
'@babel/plugin-transform-parameters',
|
'@babel/plugin-transform-parameters',
|
||||||
['@babel/plugin-transform-destructuring', { loose: true, useBuiltIns: true }],
|
['@babel/plugin-transform-spread', { loose: true, useBuiltIns: true }],
|
||||||
['@babel/plugin-transform-block-scoping', { throwIfClosureRequired: false }],
|
['@babel/plugin-transform-block-scoping', { throwIfClosureRequired: false }],
|
||||||
'@babel/plugin-transform-classes',
|
['@babel/plugin-transform-destructuring', { loose: true, useBuiltIns: true }],
|
||||||
'@babel/plugin-transform-runtime',
|
'@babel/plugin-transform-runtime',
|
||||||
'@babel/plugin-proposal-nullish-coalescing-operator',
|
'@babel/plugin-proposal-nullish-coalescing-operator',
|
||||||
'@babel/plugin-proposal-optional-chaining',
|
'@babel/plugin-proposal-optional-chaining',
|
||||||
['@babel/plugin-proposal-private-methods', { 'loose': true }],
|
|
||||||
['@babel/plugin-proposal-private-property-in-object', { 'loose': true }],
|
|
||||||
'@babel/plugin-syntax-jsx',
|
|
||||||
['@babel/plugin-transform-react-jsx', {
|
|
||||||
pragma: 'Horizon.createElement',
|
|
||||||
pragmaFrag: 'Horizon.Fragment'
|
|
||||||
}],
|
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"horizon"
|
"horizon"
|
||||||
],
|
],
|
||||||
"version": "0.0.12",
|
"version": "0.0.13",
|
||||||
"homepage": "",
|
"homepage": "",
|
||||||
"bugs": "",
|
"bugs": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {throwIfTrue} from '../renderer/utils/throwIfTrue';
|
import { throwIfTrue } from '../renderer/utils/throwIfTrue';
|
||||||
import {TYPE_COMMON_ELEMENT, TYPE_PORTAL} from './JSXElementType';
|
import { TYPE_COMMON_ELEMENT, TYPE_PORTAL } from './JSXElementType';
|
||||||
|
|
||||||
import {isValidElement, JSXElement} from './JSXElement';
|
import { isValidElement, JSXElement } from './JSXElement';
|
||||||
|
|
||||||
// 生成key
|
// 生成key
|
||||||
function getItemKey(item: any, index: number): string {
|
function getItemKey(item: any, index: number): string {
|
||||||
|
@ -12,12 +12,7 @@ function getItemKey(item: any, index: number): string {
|
||||||
return '.' + index.toString(36);
|
return '.' + index.toString(36);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapChildrenToArray(
|
function mapChildrenToArray(children: any, arr: Array<any>, prefix: string, callback?: Function): number | void {
|
||||||
children: any,
|
|
||||||
arr: Array<any>,
|
|
||||||
prefix: string,
|
|
||||||
callback?: Function,
|
|
||||||
): number | void {
|
|
||||||
const type = typeof children;
|
const type = typeof children;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
// 继承原有规格,undefined和boolean类型按照null处理
|
// 继承原有规格,undefined和boolean类型按照null处理
|
||||||
|
@ -36,44 +31,27 @@ function mapChildrenToArray(
|
||||||
}
|
}
|
||||||
const vtype = children.vtype;
|
const vtype = children.vtype;
|
||||||
if (vtype === TYPE_COMMON_ELEMENT || vtype === TYPE_PORTAL) {
|
if (vtype === TYPE_COMMON_ELEMENT || vtype === TYPE_PORTAL) {
|
||||||
callMapFun(children, arr, prefix, callback) ;
|
callMapFun(children, arr, prefix, callback);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (Array.isArray(children)) {
|
if (Array.isArray(children)) {
|
||||||
processArrayChildren(children, arr, prefix, callback);
|
processArrayChildren(children, arr, prefix, callback);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
throw new Error(
|
throw new Error('Object is invalid as a Horizon child. ');
|
||||||
'Object is invalid as a Horizon child. '
|
|
||||||
);
|
|
||||||
// No Default
|
// No Default
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function processArrayChildren(
|
function processArrayChildren(children: any, arr: Array<any>, prefix: string, callback: Function) {
|
||||||
children: any,
|
|
||||||
arr: Array<any>,
|
|
||||||
prefix: string,
|
|
||||||
callback: Function,
|
|
||||||
) {
|
|
||||||
for (let i = 0; i < children.length; i++) {
|
for (let i = 0; i < children.length; i++) {
|
||||||
const childItem = children[i];
|
const childItem = children[i];
|
||||||
const nextPrefix = prefix + getItemKey(childItem, i);
|
const nextPrefix = prefix + getItemKey(childItem, i);
|
||||||
mapChildrenToArray(
|
mapChildrenToArray(childItem, arr, nextPrefix, callback);
|
||||||
childItem,
|
|
||||||
arr,
|
|
||||||
nextPrefix,
|
|
||||||
callback,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function callMapFun(
|
function callMapFun(children: any, arr: Array<any>, prefix: string, callback: Function) {
|
||||||
children: any,
|
|
||||||
arr: Array<any>,
|
|
||||||
prefix: string,
|
|
||||||
callback: Function,
|
|
||||||
) {
|
|
||||||
let mappedChild = callback(children);
|
let mappedChild = callback(children);
|
||||||
if (Array.isArray(mappedChild)) {
|
if (Array.isArray(mappedChild)) {
|
||||||
// 维持原有规格,如果callback返回结果是数组,处理函数修改为返回数组item
|
// 维持原有规格,如果callback返回结果是数组,处理函数修改为返回数组item
|
||||||
|
@ -83,9 +61,8 @@ function callMapFun(
|
||||||
if (isValidElement(mappedChild)) {
|
if (isValidElement(mappedChild)) {
|
||||||
const childKey = prefix === '' ? getItemKey(children, 0) : '';
|
const childKey = prefix === '' ? getItemKey(children, 0) : '';
|
||||||
const mappedKey = getItemKey(mappedChild, 0);
|
const mappedKey = getItemKey(mappedChild, 0);
|
||||||
const newKey = prefix + childKey + (mappedChild.key && mappedKey !== getItemKey(children, 0)
|
const newKey =
|
||||||
? '.$' + mappedChild.key
|
prefix + childKey + (mappedChild.key && mappedKey !== getItemKey(children, 0) ? '.$' + mappedChild.key : '');
|
||||||
: '');
|
|
||||||
// 返回一个修改key的children
|
// 返回一个修改key的children
|
||||||
mappedChild = JSXElement(
|
mappedChild = JSXElement(
|
||||||
mappedChild.type,
|
mappedChild.type,
|
||||||
|
@ -93,6 +70,7 @@ function callMapFun(
|
||||||
mappedChild.ref,
|
mappedChild.ref,
|
||||||
mappedChild.belongClassVNode,
|
mappedChild.belongClassVNode,
|
||||||
mappedChild.props,
|
mappedChild.props,
|
||||||
|
mappedChild.src
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
arr.push(mappedChild);
|
arr.push(mappedChild);
|
||||||
|
@ -100,11 +78,7 @@ function callMapFun(
|
||||||
}
|
}
|
||||||
|
|
||||||
// 在 children 里的每个直接子节点上调用一个函数,并将 this 设置为 thisArg
|
// 在 children 里的每个直接子节点上调用一个函数,并将 this 设置为 thisArg
|
||||||
function mapChildren(
|
function mapChildren(children: any, func: Function, context?: any): Array<any> {
|
||||||
children: any,
|
|
||||||
func: Function,
|
|
||||||
context?: any,
|
|
||||||
): Array<any> {
|
|
||||||
if (children === null || children === undefined) {
|
if (children === null || children === undefined) {
|
||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
|
@ -121,27 +95,22 @@ const Children = {
|
||||||
},
|
},
|
||||||
map: mapChildren,
|
map: mapChildren,
|
||||||
// 并非所有元素都会计数,只计数调用callMapFun函数次数
|
// 并非所有元素都会计数,只计数调用callMapFun函数次数
|
||||||
count: (children) => {
|
count: children => {
|
||||||
let n = 0;
|
let n = 0;
|
||||||
mapChildren(children, () => {
|
mapChildren(children, () => {
|
||||||
n++;
|
n++;
|
||||||
});
|
});
|
||||||
return n;
|
return n;
|
||||||
},
|
},
|
||||||
only: (children) => {
|
only: children => {
|
||||||
throwIfTrue(
|
throwIfTrue(!isValidElement(children), 'Horizon.Children.only function received invalid element.');
|
||||||
!isValidElement(children),
|
|
||||||
'Horizon.Children.only function received invalid element.'
|
|
||||||
);
|
|
||||||
return children;
|
return children;
|
||||||
},
|
},
|
||||||
toArray: (children) => {
|
toArray: children => {
|
||||||
const result = [];
|
const result = [];
|
||||||
mapChildrenToArray(children, result, '', child => child);
|
mapChildrenToArray(children, result, '', child => child);
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
|
||||||
Children
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export { Children };
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { TYPE_COMMON_ELEMENT } from './JSXElementType';
|
import { TYPE_COMMON_ELEMENT } from './JSXElementType';
|
||||||
import { getProcessingClassVNode } from '../renderer/GlobalVar';
|
import { getProcessingClassVNode } from '../renderer/GlobalVar';
|
||||||
|
import { Source } from '../renderer/Types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* vtype 节点的类型,这里固定是element
|
* vtype 节点的类型,这里固定是element
|
||||||
|
@ -9,10 +9,11 @@ import { getProcessingClassVNode } from '../renderer/GlobalVar';
|
||||||
* ref ref属性
|
* ref ref属性
|
||||||
* props 其他常规属性
|
* props 其他常规属性
|
||||||
*/
|
*/
|
||||||
export function JSXElement(type, key, ref, vNode, props) {
|
export function JSXElement(type, key, ref, vNode, props, source: Source | null) {
|
||||||
return {
|
return {
|
||||||
// 元素标识符
|
// 元素标识符
|
||||||
vtype: TYPE_COMMON_ELEMENT,
|
vtype: TYPE_COMMON_ELEMENT,
|
||||||
|
src: isDev ? source : null,
|
||||||
|
|
||||||
// 属于元素的内置属性
|
// 属于元素的内置属性
|
||||||
type: type,
|
type: type,
|
||||||
|
@ -26,7 +27,8 @@ export function JSXElement(type, key, ref, vNode, props) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function isValidKey(key) {
|
function isValidKey(key) {
|
||||||
return key !== 'key' && key !== 'ref' && key !== '__source';
|
const keyArray = ['key', 'ref', '__source'];
|
||||||
|
return !keyArray.includes(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mergeDefault(sourceObj, defaultObj) {
|
function mergeDefault(sourceObj, defaultObj) {
|
||||||
|
@ -66,8 +68,15 @@ function buildElement(isClone, type, setting, children) {
|
||||||
if (element && element.defaultProps) {
|
if (element && element.defaultProps) {
|
||||||
mergeDefault(props, element.defaultProps);
|
mergeDefault(props, element.defaultProps);
|
||||||
}
|
}
|
||||||
|
let src: Source | null = null;
|
||||||
|
if (setting?.__source) {
|
||||||
|
src = {
|
||||||
|
fileName: setting.__source.fileName,
|
||||||
|
lineNumber: setting.__source.lineNumber,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return JSXElement(element, key, ref, vNode, props);
|
return JSXElement(element, key, ref, vNode, props, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建Element结构体,供JSX编译时调用
|
// 创建Element结构体,供JSX编译时调用
|
||||||
|
|
|
@ -1,12 +1,5 @@
|
||||||
import { travelVNodeTree } from '../renderer/vnode/VNodeUtils';
|
import { travelVNodeTree } from '../renderer/vnode/VNodeUtils';
|
||||||
import {
|
import { Hook, Reducer, Ref, Effect, CallBack, Memo } from '../renderer/hooks/HookType';
|
||||||
Hook,
|
|
||||||
Reducer,
|
|
||||||
Ref,
|
|
||||||
Effect,
|
|
||||||
CallBack,
|
|
||||||
Memo
|
|
||||||
} from '../renderer/hooks/HookType';
|
|
||||||
import { VNode } from '../renderer/vnode/VNode';
|
import { VNode } from '../renderer/vnode/VNode';
|
||||||
import { launchUpdateFromVNode } from '../renderer/TreeBuilder';
|
import { launchUpdateFromVNode } from '../renderer/TreeBuilder';
|
||||||
import { DomComponent } from '../renderer/vnode/VNodeTags';
|
import { DomComponent } from '../renderer/vnode/VNodeTags';
|
||||||
|
@ -26,7 +19,7 @@ const HookName = {
|
||||||
MemoHook: 'Memo',
|
MemoHook: 'Memo',
|
||||||
RefHook: 'Ref',
|
RefHook: 'Ref',
|
||||||
ReducerHook: 'Reducer',
|
ReducerHook: 'Reducer',
|
||||||
CallbackHook: 'Callback'
|
CallbackHook: 'Callback',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const helper = {
|
export const helper = {
|
||||||
|
@ -45,7 +38,8 @@ export const helper = {
|
||||||
} else if (isRefHook(state)) {
|
} else if (isRefHook(state)) {
|
||||||
return { name: HookName.RefHook, hIndex, value: (state as Ref<any>).current };
|
return { name: HookName.RefHook, hIndex, value: (state as Ref<any>).current };
|
||||||
} else if (isEffectHook(state)) {
|
} else if (isEffectHook(state)) {
|
||||||
const name = state.effectConstant == EffectConstant.LayoutEffect ? HookName.LayoutEffectHook : HookName.EffectHook;
|
const name =
|
||||||
|
state.effectConstant == EffectConstant.LayoutEffect ? HookName.LayoutEffectHook : HookName.EffectHook;
|
||||||
return { name, hIndex, value: (state as Effect).effect };
|
return { name, hIndex, value: (state as Effect).effect };
|
||||||
} else if (isCallbackHook(state)) {
|
} else if (isCallbackHook(state)) {
|
||||||
return { name: HookName.CallbackHook, hIndex, value: (state as CallBack<any>).func };
|
return { name: HookName.CallbackHook, hIndex, value: (state as CallBack<any>).func };
|
||||||
|
@ -86,7 +80,7 @@ export const helper = {
|
||||||
}
|
}
|
||||||
if (hooks && hooks.length !== 0) {
|
if (hooks && hooks.length !== 0) {
|
||||||
const logHookInfo: any[] = [];
|
const logHookInfo: any[] = [];
|
||||||
hooks.forEach((hook) => {
|
hooks.forEach(hook => {
|
||||||
const state = hook.state as Reducer<any, any>;
|
const state = hook.state as Reducer<any, any>;
|
||||||
if (state.trigger && state.isUseState) {
|
if (state.trigger && state.isUseState) {
|
||||||
logHookInfo.push(state.stateValue);
|
logHookInfo.push(state.stateValue);
|
||||||
|
@ -94,20 +88,26 @@ export const helper = {
|
||||||
});
|
});
|
||||||
info['Hooks'] = logHookInfo;
|
info['Hooks'] = logHookInfo;
|
||||||
}
|
}
|
||||||
travelVNodeTree(vNode, (node: VNode) => {
|
travelVNodeTree(
|
||||||
if (node.tag === DomComponent) {
|
vNode,
|
||||||
// 找到组件的第一个dom元素,返回它所在父节点的全部子节点
|
(node: VNode) => {
|
||||||
const dom = node.realNode;
|
if (node.tag === DomComponent) {
|
||||||
info['Nodes'] = dom?.parentNode?.childNodes;
|
// 找到组件的第一个dom元素,返回它所在父节点的全部子节点
|
||||||
return true;
|
const dom = node.realNode;
|
||||||
}
|
info['Nodes'] = dom?.parentNode?.childNodes;
|
||||||
return false;
|
return true;
|
||||||
}, null, vNode, null);
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
vNode,
|
||||||
|
null
|
||||||
|
);
|
||||||
return info;
|
return info;
|
||||||
},
|
},
|
||||||
getElementTag: (element: JSXElement) => {
|
getElementTag: (element: JSXElement) => {
|
||||||
return getElementTag(element);
|
return getElementTag(element);
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export function injectUpdater() {
|
export function injectUpdater() {
|
||||||
|
|
|
@ -15,7 +15,6 @@ function isPromise(obj: any): boolean {
|
||||||
|
|
||||||
type StoreConfig<S extends object, A extends UserActions<S>, C extends UserComputedValues<S>> = {
|
type StoreConfig<S extends object, A extends UserActions<S>, C extends UserComputedValues<S>> = {
|
||||||
state?: S;
|
state?: S;
|
||||||
// options?: { suppressHooks?: boolean };
|
|
||||||
actions?: A;
|
actions?: A;
|
||||||
id?: string;
|
id?: string;
|
||||||
computed?: C;
|
computed?: C;
|
||||||
|
@ -27,18 +26,15 @@ export type ReduxStoreHandler = {
|
||||||
getState: () => any;
|
getState: () => any;
|
||||||
subscribe: (listener: () => void) => () => void;
|
subscribe: (listener: () => void) => () => void;
|
||||||
replaceReducer: (reducer: (state: any, action: { type: string }) => any) => void;
|
replaceReducer: (reducer: (state: any, action: { type: string }) => any) => void;
|
||||||
// _horizonXstore: StoreHandler<any, any, any>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type StoreHandler<S extends object, A extends UserActions<S>, C extends UserComputedValues<S>> = {
|
type StoreHandler<S extends object, A extends UserActions<S>, C extends UserComputedValues<S>> = {
|
||||||
$subscribe: (listener: () => void) => void;
|
$subscribe: (listener: () => void) => void;
|
||||||
$unsubscribe: (listener: () => void) => void;
|
$unsubscribe: (listener: () => void) => void;
|
||||||
$s: S;
|
$s: S;
|
||||||
// $config: StoreConfig<S, A, C>;
|
|
||||||
$queue: QueuedStoreActions<S, A>;
|
$queue: QueuedStoreActions<S, A>;
|
||||||
$a: StoreActions<S, A>;
|
$a: StoreActions<S, A>;
|
||||||
$c: UserComputedValues<S>;
|
$c: UserComputedValues<S>;
|
||||||
// reduxHandler?: ReduxStoreHandler;
|
|
||||||
} & { [K in keyof S]: S[K] } &
|
} & { [K in keyof S]: S[K] } &
|
||||||
{ [K in keyof A]: Action<A[K], S> } &
|
{ [K in keyof A]: Action<A[K], S> } &
|
||||||
{ [K in keyof C]: ReturnType<C[K]> };
|
{ [K in keyof C]: ReturnType<C[K]> };
|
||||||
|
|
|
@ -3,20 +3,16 @@ export { VNode } from './vnode/VNode';
|
||||||
type Trigger<A> = (A) => void;
|
type Trigger<A> = (A) => void;
|
||||||
|
|
||||||
export type UseStateHookType = {
|
export type UseStateHookType = {
|
||||||
useState<S>(
|
useState<S>(initialState: (() => S) | S): [S, Trigger<((S) => S) | S>];
|
||||||
initialState: (() => S) | S
|
|
||||||
): [S, Trigger<((S) => S) | S>];
|
|
||||||
};
|
};
|
||||||
export type UseReducerHookType = {
|
export type UseReducerHookType = {
|
||||||
useReducer<S, P, A>(
|
useReducer<S, P, A>(reducer: (S, A) => S, initArg: P, init?: (P) => S): [S, Trigger<A>];
|
||||||
reducer: (S, A) => S,
|
|
||||||
initArg: P, init?: (P) => S,
|
|
||||||
): [S, Trigger<A>];
|
|
||||||
};
|
};
|
||||||
export type UseContextHookType = { useContext<T>(context: ContextType<T>,): T };
|
export type UseContextHookType = { useContext<T>(context: ContextType<T>): T };
|
||||||
|
|
||||||
export type JSXElement = {
|
export type JSXElement = {
|
||||||
vtype: any;
|
vtype: any;
|
||||||
|
src: any;
|
||||||
type: any;
|
type: any;
|
||||||
key: any;
|
key: any;
|
||||||
ref: any;
|
ref: any;
|
||||||
|
@ -31,8 +27,8 @@ export type ProviderType<T> = {
|
||||||
|
|
||||||
export type ContextType<T> = {
|
export type ContextType<T> = {
|
||||||
vtype: number;
|
vtype: number;
|
||||||
Consumer: ContextType<T>;
|
Consumer: ContextType<T> | null;
|
||||||
Provider: ProviderType<T>;
|
Provider: ProviderType<T> | null;
|
||||||
value: T;
|
value: T;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -50,7 +46,7 @@ export type RefType = {
|
||||||
export interface PromiseType<R> {
|
export interface PromiseType<R> {
|
||||||
then<U>(
|
then<U>(
|
||||||
onFulfill: (value: R) => void | PromiseType<U> | U,
|
onFulfill: (value: R) => void | PromiseType<U> | U,
|
||||||
onReject: (error: any) => void | PromiseType<U> | U,
|
onReject: (error: any) => void | PromiseType<U> | U
|
||||||
): void | PromiseType<U>;
|
): void | PromiseType<U>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,3 +57,8 @@ export interface SuspenseState {
|
||||||
didCapture: boolean; // suspense是否捕获了异常
|
didCapture: boolean; // suspense是否捕获了异常
|
||||||
promiseResolved: boolean; // suspense的promise是否resolve
|
promiseResolved: boolean; // suspense的promise是否resolve
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type Source = {
|
||||||
|
fileName: string;
|
||||||
|
lineNumber: number;
|
||||||
|
};
|
||||||
|
|
|
@ -1,20 +1,18 @@
|
||||||
import type { Hook, Reducer, Trigger, Update } from './HookType';
|
import type { Hook, Reducer, Trigger, Update } from './HookType';
|
||||||
import {
|
import { createHook, getCurrentHook, throwNotInFuncError } from './BaseHook';
|
||||||
createHook,
|
import { launchUpdateFromVNode } from '../TreeBuilder';
|
||||||
getCurrentHook,
|
|
||||||
throwNotInFuncError
|
|
||||||
} from './BaseHook';
|
|
||||||
import {
|
|
||||||
launchUpdateFromVNode
|
|
||||||
} from '../TreeBuilder';
|
|
||||||
import { isSame } from '../utils/compare';
|
import { isSame } from '../utils/compare';
|
||||||
import { setStateChange } from '../render/FunctionComponent';
|
import { setStateChange } from '../render/FunctionComponent';
|
||||||
import { getHookStage, HookStage } from './HookStage';
|
import { getHookStage, HookStage } from './HookStage';
|
||||||
import type { VNode } from '../Types';
|
import type { VNode } from '../Types';
|
||||||
import {getProcessingVNode} from '../GlobalVar';
|
import { getProcessingVNode } from '../GlobalVar';
|
||||||
|
|
||||||
export function useReducerImpl<S, P, A>(reducer: (S, A) =>
|
export function useReducerImpl<S, P, A>(
|
||||||
S, initArg: P, init?: (P) => S, isUseState?: boolean): [S, Trigger<A>] | void {
|
reducer: (S, A) => S,
|
||||||
|
initArg: P,
|
||||||
|
init?: (P) => S,
|
||||||
|
isUseState?: boolean
|
||||||
|
): [S, Trigger<A>] | void {
|
||||||
const stage = getHookStage();
|
const stage = getHookStage();
|
||||||
if (stage === null) {
|
if (stage === null) {
|
||||||
throwNotInFuncError();
|
throwNotInFuncError();
|
||||||
|
@ -53,16 +51,19 @@ function insertUpdate<S, A>(action: A, hook: Hook<S, A>): Update<S, A> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// setState, setReducer触发函数
|
// setState, setReducer触发函数
|
||||||
export function TriggerAction<S, A, T>(vNode: VNode, hook: Hook<S, A>, action: A) {
|
export function TriggerAction<S, A>(vNode: VNode, hook: Hook<S, A>, isUseState: boolean, action: A): void {
|
||||||
const newUpdate = insertUpdate(action, hook);
|
const newUpdate = insertUpdate(action, hook);
|
||||||
|
|
||||||
// 判断是否需要刷新
|
// 判断是否需要刷新
|
||||||
if (!vNode.shouldUpdate) {
|
if (!vNode.shouldUpdate && isUseState) {
|
||||||
const reducerObj = hook.state as Reducer<S, A>;
|
const { stateValue, reducer } = hook.state as Reducer<S, A>;
|
||||||
const { stateValue, reducer } = reducerObj;
|
|
||||||
|
|
||||||
|
if (reducer === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// 在进入render阶段前reducer没有变化,可以复用state值,提升性能
|
// 在进入render阶段前reducer没有变化,可以复用state值,提升性能
|
||||||
newUpdate.state = reducer(stateValue, action);
|
newUpdate.state = reducer(stateValue, action);
|
||||||
|
|
||||||
// 标记为已经计算过,不需要重新计算了
|
// 标记为已经计算过,不需要重新计算了
|
||||||
newUpdate.didCalculated = true;
|
newUpdate.didCalculated = true;
|
||||||
|
|
||||||
|
@ -87,16 +88,17 @@ export function useReducerForInit<S, A>(reducer, initArg, init, isUseState?: boo
|
||||||
}
|
}
|
||||||
|
|
||||||
const hook = createHook();
|
const hook = createHook();
|
||||||
|
const trigger = TriggerAction.bind(null, getProcessingVNode(), hook, isUseState);
|
||||||
// 为hook.state赋值{状态值, 触发函数, reducer, updates更新数组, 是否是useState}
|
// 为hook.state赋值{状态值, 触发函数, reducer, updates更新数组, 是否是useState}
|
||||||
hook.state = {
|
hook.state = {
|
||||||
stateValue: stateValue,
|
stateValue: stateValue,
|
||||||
trigger: TriggerAction.bind(null, getProcessingVNode(), hook),
|
trigger,
|
||||||
reducer,
|
reducer,
|
||||||
updates: null,
|
updates: null,
|
||||||
isUseState
|
isUseState,
|
||||||
} as Reducer<S, A>;
|
} as Reducer<S, A>;
|
||||||
|
|
||||||
return [hook.state.stateValue, hook.state.trigger];
|
return [hook.state.stateValue, trigger];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新hook.state
|
// 更新hook.state
|
||||||
|
@ -136,5 +138,3 @@ function calculateNewState<S, A>(currentHookUpdates: Array<Update<S, A>>, curren
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,19 @@
|
||||||
import type {VNode} from '../Types';
|
import type { Source, VNode } from '../Types';
|
||||||
|
|
||||||
import {mergeDefaultProps} from './LazyComponent';
|
import { mergeDefaultProps } from './LazyComponent';
|
||||||
import {updateVNode, onlyUpdateChildVNodes, createFragmentVNode, createUndeterminedVNode} from '../vnode/VNodeCreator';
|
|
||||||
import {shallowCompare} from '../utils/compare';
|
|
||||||
import {
|
import {
|
||||||
TYPE_FRAGMENT,
|
updateVNode,
|
||||||
TYPE_PROFILER,
|
onlyUpdateChildVNodes,
|
||||||
TYPE_STRICT_MODE,
|
createFragmentVNode,
|
||||||
} from '../../external/JSXElementType';
|
createUndeterminedVNode,
|
||||||
|
} from '../vnode/VNodeCreator';
|
||||||
|
import { shallowCompare } from '../utils/compare';
|
||||||
|
import { TYPE_FRAGMENT, TYPE_PROFILER, TYPE_STRICT_MODE } from '../../external/JSXElementType';
|
||||||
import { markVNodePath } from '../utils/vNodePath';
|
import { markVNodePath } from '../utils/vNodePath';
|
||||||
|
|
||||||
export function bubbleRender() {}
|
export function bubbleRender() {}
|
||||||
|
|
||||||
export function captureMemoComponent(
|
export function captureMemoComponent(processing: VNode, shouldUpdate: boolean): VNode | null {
|
||||||
processing: VNode,
|
|
||||||
shouldUpdate: boolean,
|
|
||||||
): VNode | null {
|
|
||||||
const Component = processing.type;
|
const Component = processing.type;
|
||||||
// 合并 函数组件或类组件 的defaultProps
|
// 合并 函数组件或类组件 的defaultProps
|
||||||
const newProps = mergeDefaultProps(Component, processing.props);
|
const newProps = mergeDefaultProps(Component, processing.props);
|
||||||
|
@ -26,7 +24,7 @@ export function captureMemoComponent(
|
||||||
if (type === TYPE_STRICT_MODE || type === TYPE_FRAGMENT || type === TYPE_PROFILER) {
|
if (type === TYPE_STRICT_MODE || type === TYPE_FRAGMENT || type === TYPE_PROFILER) {
|
||||||
newChild = createFragmentVNode(null, newProps.children);
|
newChild = createFragmentVNode(null, newProps.children);
|
||||||
} else {
|
} else {
|
||||||
newChild = createUndeterminedVNode(type, null, newProps);
|
newChild = createUndeterminedVNode(type, null, newProps, processing.src);
|
||||||
}
|
}
|
||||||
newChild.parent = processing;
|
newChild.parent = processing;
|
||||||
newChild.ref = processing.ref;
|
newChild.ref = processing.ref;
|
||||||
|
|
|
@ -17,10 +17,10 @@ import {
|
||||||
Profiler,
|
Profiler,
|
||||||
MemoComponent,
|
MemoComponent,
|
||||||
} from './VNodeTags';
|
} from './VNodeTags';
|
||||||
import type { VNodeTag } from './VNodeTags';
|
import type {VNodeTag} from './VNodeTags';
|
||||||
import type { RefType, ContextType, SuspenseState } from '../Types';
|
import type {RefType, ContextType, SuspenseState, Source} from '../Types';
|
||||||
import type { Hook } from '../hooks/HookType';
|
import type {Hook} from '../hooks/HookType';
|
||||||
import { InitFlag } from './VNodeFlags';
|
import {InitFlag} from './VNodeFlags';
|
||||||
|
|
||||||
export class VNode {
|
export class VNode {
|
||||||
tag: VNodeTag;
|
tag: VNodeTag;
|
||||||
|
@ -77,8 +77,8 @@ export class VNode {
|
||||||
|
|
||||||
// 根节点数据
|
// 根节点数据
|
||||||
toUpdateNodes: Set<VNode> | null; // 保存要更新的节点
|
toUpdateNodes: Set<VNode> | null; // 保存要更新的节点
|
||||||
delegatedEvents: Set<string>
|
delegatedEvents: Set<string>;
|
||||||
delegatedNativeEvents: Set<string>
|
delegatedNativeEvents: Set<string>;
|
||||||
|
|
||||||
belongClassVNode: VNode | null = null; // 记录JSXElement所属class vNode,处理ref的时候使用
|
belongClassVNode: VNode | null = null; // 记录JSXElement所属class vNode,处理ref的时候使用
|
||||||
|
|
||||||
|
@ -86,6 +86,7 @@ export class VNode {
|
||||||
isStoreChange: boolean;
|
isStoreChange: boolean;
|
||||||
observers: Set<any> | null = null; // 记录这个函数组件/类组件依赖哪些Observer
|
observers: Set<any> | null = null; // 记录这个函数组件/类组件依赖哪些Observer
|
||||||
classComponentWillUnmount: Function | null; // HorizonX会在classComponentWillUnmount中清除对VNode的引入用
|
classComponentWillUnmount: Function | null; // HorizonX会在classComponentWillUnmount中清除对VNode的引入用
|
||||||
|
src: Source | null; // 节点所在代码位置
|
||||||
|
|
||||||
constructor(tag: VNodeTag, props: any, key: null | string, realNode) {
|
constructor(tag: VNodeTag, props: any, key: null | string, realNode) {
|
||||||
this.tag = tag; // 对应组件的类型,比如ClassComponent等
|
this.tag = tag; // 对应组件的类型,比如ClassComponent等
|
||||||
|
@ -116,6 +117,7 @@ export class VNode {
|
||||||
this.isStoreChange = false;
|
this.isStoreChange = false;
|
||||||
this.observers = null;
|
this.observers = null;
|
||||||
this.classComponentWillUnmount = null;
|
this.classComponentWillUnmount = null;
|
||||||
|
this.src = null;
|
||||||
break;
|
break;
|
||||||
case ClassComponent:
|
case ClassComponent:
|
||||||
this.realNode = null;
|
this.realNode = null;
|
||||||
|
@ -130,15 +132,18 @@ export class VNode {
|
||||||
this.isStoreChange = false;
|
this.isStoreChange = false;
|
||||||
this.observers = null;
|
this.observers = null;
|
||||||
this.classComponentWillUnmount = null;
|
this.classComponentWillUnmount = null;
|
||||||
|
this.src = null;
|
||||||
break;
|
break;
|
||||||
case DomPortal:
|
case DomPortal:
|
||||||
this.realNode = null;
|
this.realNode = null;
|
||||||
this.context = null;
|
this.context = null;
|
||||||
|
this.src = null;
|
||||||
break;
|
break;
|
||||||
case DomComponent:
|
case DomComponent:
|
||||||
this.realNode = null;
|
this.realNode = null;
|
||||||
this.changeList = null;
|
this.changeList = null;
|
||||||
this.context = null;
|
this.context = null;
|
||||||
|
this.src = null;
|
||||||
break;
|
break;
|
||||||
case DomText:
|
case DomText:
|
||||||
this.realNode = null;
|
this.realNode = null;
|
||||||
|
@ -150,14 +155,17 @@ export class VNode {
|
||||||
didCapture: false,
|
didCapture: false,
|
||||||
promiseResolved: false,
|
promiseResolved: false,
|
||||||
oldChildStatus: '',
|
oldChildStatus: '',
|
||||||
childStatus: ''
|
childStatus: '',
|
||||||
};
|
};
|
||||||
|
this.src = null;
|
||||||
break;
|
break;
|
||||||
case ContextProvider:
|
case ContextProvider:
|
||||||
|
this.src = null;
|
||||||
this.context = null;
|
this.context = null;
|
||||||
break;
|
break;
|
||||||
case MemoComponent:
|
case MemoComponent:
|
||||||
this.effectList = null;
|
this.effectList = null;
|
||||||
|
this.src = null;
|
||||||
break;
|
break;
|
||||||
case LazyComponent:
|
case LazyComponent:
|
||||||
this.realNode = null;
|
this.realNode = null;
|
||||||
|
@ -165,6 +173,7 @@ export class VNode {
|
||||||
this.isLazyComponent = true;
|
this.isLazyComponent = true;
|
||||||
this.lazyType = null;
|
this.lazyType = null;
|
||||||
this.updates = null;
|
this.updates = null;
|
||||||
|
this.src = null;
|
||||||
break;
|
break;
|
||||||
case Fragment:
|
case Fragment:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -17,14 +17,17 @@ import {
|
||||||
} from './VNodeTags';
|
} from './VNodeTags';
|
||||||
import {
|
import {
|
||||||
TYPE_CONTEXT,
|
TYPE_CONTEXT,
|
||||||
TYPE_FORWARD_REF, TYPE_FRAGMENT,
|
TYPE_FORWARD_REF,
|
||||||
|
TYPE_FRAGMENT,
|
||||||
TYPE_LAZY,
|
TYPE_LAZY,
|
||||||
TYPE_MEMO, TYPE_PROFILER,
|
TYPE_MEMO,
|
||||||
TYPE_PROVIDER, TYPE_STRICT_MODE,
|
TYPE_PROFILER,
|
||||||
|
TYPE_PROVIDER,
|
||||||
|
TYPE_STRICT_MODE,
|
||||||
TYPE_SUSPENSE,
|
TYPE_SUSPENSE,
|
||||||
} from '../../external/JSXElementType';
|
} from '../../external/JSXElementType';
|
||||||
import { VNode } from './VNode';
|
import { VNode } from './VNode';
|
||||||
import { JSXElement } from '../Types';
|
import { JSXElement, Source } from '../Types';
|
||||||
import { markVNodePath } from '../utils/vNodePath';
|
import { markVNodePath } from '../utils/vNodePath';
|
||||||
|
|
||||||
const typeLazyMap = {
|
const typeLazyMap = {
|
||||||
|
@ -56,7 +59,7 @@ export function getLazyVNodeTag(lazyComp: any): string {
|
||||||
} else if (lazyComp !== undefined && lazyComp !== null && typeLazyMap[lazyComp.vtype]) {
|
} else if (lazyComp !== undefined && lazyComp !== null && typeLazyMap[lazyComp.vtype]) {
|
||||||
return typeLazyMap[lazyComp.vtype];
|
return typeLazyMap[lazyComp.vtype];
|
||||||
}
|
}
|
||||||
throw Error('Horizon can\'t resolve the content of lazy');
|
throw Error("Horizon can't resolve the content of lazy");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建processing
|
// 创建processing
|
||||||
|
@ -102,11 +105,10 @@ export function createPortalVNode(portal) {
|
||||||
return vNode;
|
return vNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createUndeterminedVNode(type, key, props) {
|
export function createUndeterminedVNode(type, key, props, source: Source | null): VNode {
|
||||||
let vNodeTag = FunctionComponent;
|
let vNodeTag = FunctionComponent;
|
||||||
let isLazy = false;
|
let isLazy = false;
|
||||||
const componentType = typeof type;
|
const componentType = typeof type;
|
||||||
|
|
||||||
if (componentType === 'function') {
|
if (componentType === 'function') {
|
||||||
if (isClassComponent(type)) {
|
if (isClassComponent(type)) {
|
||||||
vNodeTag = ClassComponent;
|
vNodeTag = ClassComponent;
|
||||||
|
@ -129,6 +131,8 @@ export function createUndeterminedVNode(type, key, props) {
|
||||||
if (isLazy) {
|
if (isLazy) {
|
||||||
vNode.lazyType = type;
|
vNode.lazyType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vNode.src = isDev ? source : null;
|
||||||
return vNode;
|
return vNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,14 +185,12 @@ export function createVNode(tag: VNodeTag | string, ...secondArg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createVNodeFromElement(element: JSXElement): VNode {
|
export function createVNodeFromElement(element: JSXElement): VNode {
|
||||||
const type = element.type;
|
const { type, key, props, src } = element;
|
||||||
const key = element.key;
|
|
||||||
const props = element.props;
|
|
||||||
|
|
||||||
if (type === TYPE_STRICT_MODE || type === TYPE_FRAGMENT || type === TYPE_PROFILER) {
|
if (type === TYPE_STRICT_MODE || type === TYPE_FRAGMENT || type === TYPE_PROFILER) {
|
||||||
return createFragmentVNode(key, props.children);
|
return createFragmentVNode(key, props.children);
|
||||||
} else {
|
} else {
|
||||||
return createUndeterminedVNode(type, key, props);
|
return createUndeterminedVNode(type, key, props, src);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,4 +243,3 @@ export function onlyUpdateChildVNodes(processing: VNode): VNode | null {
|
||||||
// 子树无需工作
|
// 子树无需工作
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,12 +33,13 @@
|
||||||
"@babel/plugin-transform-object-assign": "7.16.7",
|
"@babel/plugin-transform-object-assign": "7.16.7",
|
||||||
"@babel/plugin-transform-object-super": "7.16.7",
|
"@babel/plugin-transform-object-super": "7.16.7",
|
||||||
"@babel/plugin-transform-parameters": "7.16.7",
|
"@babel/plugin-transform-parameters": "7.16.7",
|
||||||
|
"@babel/plugin-transform-react-jsx": "7.16.7",
|
||||||
"@babel/plugin-transform-runtime": "7.16.7",
|
"@babel/plugin-transform-runtime": "7.16.7",
|
||||||
"@babel/plugin-transform-shorthand-properties": "7.16.7",
|
"@babel/plugin-transform-shorthand-properties": "7.16.7",
|
||||||
"@babel/plugin-transform-spread": "7.16.7",
|
"@babel/plugin-transform-spread": "7.16.7",
|
||||||
"@babel/plugin-transform-template-literals": "7.16.7",
|
"@babel/plugin-transform-template-literals": "7.16.7",
|
||||||
|
"@babel/plugin-transform-react-jsx-source": "^7.16.7",
|
||||||
"@babel/preset-env": "7.16.7",
|
"@babel/preset-env": "7.16.7",
|
||||||
"@babel/preset-react": "7.16.7",
|
|
||||||
"@babel/preset-typescript": "7.16.7",
|
"@babel/preset-typescript": "7.16.7",
|
||||||
"@rollup/plugin-babel": "^5.3.1",
|
"@rollup/plugin-babel": "^5.3.1",
|
||||||
"@rollup/plugin-node-resolve": "^13.3.0",
|
"@rollup/plugin-node-resolve": "^13.3.0",
|
||||||
|
|
|
@ -13,25 +13,25 @@ describe('useReducer Hook Test', () => {
|
||||||
return {
|
return {
|
||||||
...intlCar,
|
...intlCar,
|
||||||
logo: 'ford',
|
logo: 'ford',
|
||||||
price: 76
|
price: 76,
|
||||||
};
|
};
|
||||||
case 'bmw':
|
case 'bmw':
|
||||||
return {
|
return {
|
||||||
...intlCar,
|
...intlCar,
|
||||||
logo: 'bmw',
|
logo: 'bmw',
|
||||||
price: 100
|
price: 100,
|
||||||
};
|
};
|
||||||
case 'benz':
|
case 'benz':
|
||||||
return {
|
return {
|
||||||
...intlCar,
|
...intlCar,
|
||||||
logo: 'benz',
|
logo: 'benz',
|
||||||
price: 80
|
price: 80,
|
||||||
};
|
};
|
||||||
default:
|
default:
|
||||||
return {
|
return {
|
||||||
...intlCar,
|
...intlCar,
|
||||||
logo: 'audi',
|
logo: 'audi',
|
||||||
price: 88
|
price: 88,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -56,4 +56,34 @@ describe('useReducer Hook Test', () => {
|
||||||
expect(container.querySelector('p').innerHTML).toBe('audi');
|
expect(container.querySelector('p').innerHTML).toBe('audi');
|
||||||
expect(container.querySelector('#senP').innerHTML).toBe('88');
|
expect(container.querySelector('#senP').innerHTML).toBe('88');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('dispatch只触发一次', () => {
|
||||||
|
let nextId = 1;
|
||||||
|
const reducer = () => {
|
||||||
|
return { data: nextId++ };
|
||||||
|
};
|
||||||
|
const btnRef = Horizon.createRef();
|
||||||
|
const Main = () => {
|
||||||
|
const [{ data }, dispatch] = useReducer(reducer, { data: 0 });
|
||||||
|
const dispatchLogging = () => {
|
||||||
|
console.log('dispatch is called once');
|
||||||
|
dispatch();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<button ref={btnRef} onClick={() => dispatchLogging()}>
|
||||||
|
increment
|
||||||
|
</button>
|
||||||
|
<div>{data}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Horizon.render(<Main />, container);
|
||||||
|
Horizon.act(() => {
|
||||||
|
btnRef.current.click();
|
||||||
|
});
|
||||||
|
expect(nextId).toBe(2);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`Dom Textarea should not incur unnecessary DOM mutations 1`] = `<textarea />`;
|
|
||||||
|
|
||||||
exports[`Dom Textarea should not incur unnecessary DOM mutations 2`] = `<textarea />`;
|
|
|
@ -1,8 +1,17 @@
|
||||||
import * as Horizon from '@cloudsop/horizon/index.ts';
|
import * as Horizon from '@cloudsop/horizon/index.ts';
|
||||||
import { getLogUtils } from '../jest/testUtils';
|
import {getLogUtils} from '../jest/testUtils';
|
||||||
|
|
||||||
describe('Keyboard Event', () => {
|
describe('Keyboard Event', () => {
|
||||||
const LogUtils = getLogUtils();
|
const LogUtils = getLogUtils();
|
||||||
|
const getKeyboardEvent = (type, keyCode, code, charCode) => {
|
||||||
|
return new KeyboardEvent(type, {
|
||||||
|
keyCode: keyCode ?? undefined,
|
||||||
|
code: code ?? undefined,
|
||||||
|
charCode: charCode ?? undefined,
|
||||||
|
bubbles: true,
|
||||||
|
cancelable: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
it('keydown,keypress,keyup的keycode,charcode', () => {
|
it('keydown,keypress,keyup的keycode,charcode', () => {
|
||||||
const node = Horizon.render(
|
const node = Horizon.render(
|
||||||
|
@ -16,26 +25,12 @@ describe('Keyboard Event', () => {
|
||||||
/>,
|
/>,
|
||||||
container,
|
container,
|
||||||
);
|
);
|
||||||
node.dispatchEvent(
|
node.dispatchEvent(getKeyboardEvent('keydown', 50, 'Digit2'));
|
||||||
new KeyboardEvent('keydown', {
|
node.dispatchEvent(getKeyboardEvent('keyup', 50, 'Digit2'));
|
||||||
keyCode: 50,
|
|
||||||
code: 'Digit2',
|
|
||||||
bubbles: true,
|
|
||||||
cancelable: true,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
node.dispatchEvent(
|
|
||||||
new KeyboardEvent('keyup', {
|
|
||||||
keyCode: 50,
|
|
||||||
code: 'Digit2',
|
|
||||||
bubbles: true,
|
|
||||||
cancelable: true,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(LogUtils.getAndClear()).toEqual([
|
expect(LogUtils.getAndClear()).toEqual([
|
||||||
'onKeyDown: keycode: 50,charcode: 0',
|
'onKeyDown: keycode: 50,charcode: 0',
|
||||||
'onKeyUp: keycode: 50,charcode: 0'
|
'onKeyUp: keycode: 50,charcode: 0',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -48,17 +43,10 @@ describe('Keyboard Event', () => {
|
||||||
/>,
|
/>,
|
||||||
container,
|
container,
|
||||||
);
|
);
|
||||||
node.dispatchEvent(
|
node.dispatchEvent(getKeyboardEvent('keypress', undefined, 'Digit2', 50));
|
||||||
new KeyboardEvent('keypress', {
|
|
||||||
charCode: 50,
|
|
||||||
code: 'Digit2',
|
|
||||||
bubbles: true,
|
|
||||||
cancelable: true,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(LogUtils.getAndClear()).toEqual([
|
expect(LogUtils.getAndClear()).toEqual([
|
||||||
'onKeyPress: keycode: 0,charcode: 50'
|
'onKeyPress: keycode: 0,charcode: 50',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -71,15 +59,9 @@ describe('Keyboard Event', () => {
|
||||||
/>,
|
/>,
|
||||||
container,
|
container,
|
||||||
);
|
);
|
||||||
node.dispatchEvent(
|
node.dispatchEvent(getKeyboardEvent('keypress', undefined, undefined, 13));
|
||||||
new KeyboardEvent('keypress', {
|
|
||||||
charCode: 13,
|
|
||||||
bubbles: true,
|
|
||||||
cancelable: true,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
expect(LogUtils.getAndClear()).toEqual([
|
expect(LogUtils.getAndClear()).toEqual([
|
||||||
'onKeyPress: keycode: 0,charcode: 13'
|
'onKeyPress: keycode: 0,charcode: 13',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -98,22 +80,8 @@ describe('Keyboard Event', () => {
|
||||||
/>,
|
/>,
|
||||||
container,
|
container,
|
||||||
);
|
);
|
||||||
node.dispatchEvent(
|
node.dispatchEvent(getKeyboardEvent('keydown', undefined, 'Digit2'));
|
||||||
new KeyboardEvent('keydown', {
|
node.dispatchEvent(getKeyboardEvent('keypress', undefined, 'Digit2', 50));
|
||||||
code: 'Digit2',
|
|
||||||
bubbles: true,
|
|
||||||
cancelable: true,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
node.dispatchEvent(
|
|
||||||
new KeyboardEvent('keypress', {
|
|
||||||
keyCode: 50,
|
|
||||||
code: 'Digit2',
|
|
||||||
bubbles: true,
|
|
||||||
cancelable: true,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
node.dispatchEvent(
|
node.dispatchEvent(
|
||||||
new KeyboardEvent('keyup', {
|
new KeyboardEvent('keyup', {
|
||||||
|
@ -126,7 +94,7 @@ describe('Keyboard Event', () => {
|
||||||
expect(LogUtils.getAndClear()).toEqual([
|
expect(LogUtils.getAndClear()).toEqual([
|
||||||
'onKeyDown: code: Digit2',
|
'onKeyDown: code: Digit2',
|
||||||
'onKeyPress: code: Digit2',
|
'onKeyPress: code: Digit2',
|
||||||
'onKeyUp: code: Digit2'
|
'onKeyUp: code: Digit2',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -149,32 +117,14 @@ describe('Keyboard Event', () => {
|
||||||
/>,
|
/>,
|
||||||
container,
|
container,
|
||||||
);
|
);
|
||||||
|
div.dispatchEvent(getKeyboardEvent('keydown', 40));
|
||||||
|
div.dispatchEvent(getKeyboardEvent('keyup', 40));
|
||||||
|
div.dispatchEvent(getKeyboardEvent('keypress', 40));
|
||||||
|
|
||||||
div.dispatchEvent(
|
|
||||||
new KeyboardEvent('keydown', {
|
|
||||||
keyCode: 40,
|
|
||||||
bubbles: true,
|
|
||||||
cancelable: true,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
div.dispatchEvent(
|
|
||||||
new KeyboardEvent('keyup', {
|
|
||||||
keyCode: 40,
|
|
||||||
bubbles: true,
|
|
||||||
cancelable: true,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
div.dispatchEvent(
|
|
||||||
new KeyboardEvent('keypress', {
|
|
||||||
charCode: 40,
|
|
||||||
bubbles: true,
|
|
||||||
cancelable: true,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
expect(LogUtils.getAndClear()).toEqual([
|
expect(LogUtils.getAndClear()).toEqual([
|
||||||
'keydown handle',
|
'keydown handle',
|
||||||
'keyup handle',
|
'keyup handle',
|
||||||
'keypress handle'
|
'keypress handle',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
export const ActionType = {
|
||||||
|
Pending: 'PENDING',
|
||||||
|
Fulfilled: 'FULFILLED',
|
||||||
|
Rejected: 'REJECTED',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const promise = store => next => action => {
|
||||||
|
//let result = next(action);
|
||||||
|
store._horizonXstore.$queue.dispatch(action);
|
||||||
|
return result;
|
||||||
|
};
|
Loading…
Reference in New Issue