Match-id-8475cbc5c1b5d58f5e0dbbeb95e0267d2ce277e1

This commit is contained in:
* 2022-03-20 15:48:05 +08:00 committed by *
commit 886237cfb7
17 changed files with 122 additions and 73 deletions

View File

@ -10,7 +10,7 @@ module.exports = {
jsxSingleQuote: false, // 在JSX中使用双引号 jsxSingleQuote: false, // 在JSX中使用双引号
trailingComma: 'es5', // 使用尾逗号(对象、数组等) trailingComma: 'es5', // 使用尾逗号(对象、数组等)
bracketSpacing: true, // 对象的括号间增加空格 bracketSpacing: true, // 对象的括号间增加空格
jsxBracketSameLine: false, // 将多行JSX元素的>放在最后一行的末尾 bracketSameLine: false, // 将多行JSX元素的>放在最后一行的末尾
arrowParens: 'avoid', // 在唯一的arrow函数参数周围省略括号 arrowParens: 'avoid', // 在唯一的arrow函数参数周围省略括号
vueIndentScriptAndStyle: false, // 不缩进Vue文件中的<script>和<style>标记内的代码 vueIndentScriptAndStyle: false, // 不缩进Vue文件中的<script>和<style>标记内的代码
endOfLine: 'lf', // 仅限换行(\n endOfLine: 'lf', // 仅限换行(\n

View File

@ -1,25 +0,0 @@
{
"plugins": [
"@babel/plugin-syntax-dynamic-import",
"@babel/plugin-syntax-import-meta",
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-json-strings",
[
"@babel/plugin-proposal-decorators",
{
"legacy": true
}
],
"@babel/plugin-proposal-function-sent",
"@babel/plugin-proposal-export-namespace-from",
"@babel/plugin-proposal-numeric-separator",
"@babel/plugin-proposal-throw-expressions"
],
"env": {
"test": {
"plugins": [
"@babel/plugin-transform-modules-commonjs"
]
}
}
}

View File

@ -2,9 +2,6 @@
module.exports = { module.exports = {
presets: [ presets: [
'@babel/preset-env', '@babel/preset-env',
], '@babel/preset-typescript'
plugins: [ ]
/* eslint-disable-next-line global-require */
[require('./dist/index.js')],
],
}; };

View File

@ -1,10 +1,5 @@
module.exports = { module.exports = {
transform: { transform: {
'\\.(ts|tsx)$': 'ts-jest', '\\.(js|jsx|ts|tsx)$': 'babel-jest',
}, }
globals: {
'ts-jest': {
babelConfig: true,
},
},
}; };

View File

@ -31,7 +31,6 @@
"@babel/plugin-transform-modules-commonjs": "^7.2.0", "@babel/plugin-transform-modules-commonjs": "^7.2.0",
"@babel/preset-env": "^7.16.11", "@babel/preset-env": "^7.16.11",
"@babel/types": "^7.0.0", "@babel/types": "^7.0.0",
"babel-plugin-tester": "^10.1.0", "babel-plugin-tester": "^10.1.0"
"ts-jest": "^26.1.3"
} }
} }

View File

@ -1,9 +1,40 @@
import SyntaxJSX from '@babel/plugin-syntax-jsx'; import SyntaxJSX from '@babel/plugin-syntax-jsx';
import * as BabelCore from '@babel/core'; import * as BabelCore from '@babel/core';
import * as t from '@babel/types'; import * as t from '@babel/types';
import {NodePath} from '@babel/traverse'; import { NodePath } from '@babel/traverse';
import { JSXIdentifier, JSXMemberExpression, JSXNamespacedName } from '@babel/types';
function isHTMLTag(tagName: string) {
return tagName && /^[a-z]/.test(tagName);
}
const horizonJsx = t.memberExpression(t.identifier('Horizon'), t.identifier('jsx'));
function getTagNodeName(tagNode: JSXIdentifier | JSXMemberExpression | JSXNamespacedName) {
let tagName;
if (t.isJSXNamespacedName(tagNode)) {
throw 'horizon jsx doesn\'t support JSX namespace: ' + tagNode;
} else if (t.isJSXIdentifier(tagNode)) {
/*
this -> thisExpression
HTML -> stringLiteral
Others -> Identifier
*/
tagName = tagNode.name === 'this' ?
t.thisExpression() : isHTMLTag(tagNode.name) ?
t.stringLiteral(tagNode.name) :
t.identifier(tagNode.name);
} else if (t.isJSXMemberExpression(tagNode)) {
tagName = t.memberExpression(
getTagNodeName(tagNode.object),
getTagNodeName(tagNode.property),
);
}
return tagName;
}
export default ({ types }: typeof BabelCore) => {
export default ({types}: typeof BabelCore) => {
return { return {
name: 'horizon-jsx-babel-plugin', name: 'horizon-jsx-babel-plugin',
inherits: SyntaxJSX, inherits: SyntaxJSX,
@ -14,12 +45,13 @@ export default ({types}: typeof BabelCore) => {
}, },
JSXElement: { JSXElement: {
exit(path) { exit(path: NodePath<t.JSXElement>) {
const openingElement = path.get('openingElement');
const tagName = getTagNodeName(openingElement.node.name);
path.replaceWith(t.callExpression(horizonJsx, [tagName]));
}, },
}, },
},
}
}; };
}; };

View File

@ -0,0 +1,3 @@
var x = <div></div>;
var y = <Eview.Table></Eview.Table>;
var z = <this></this>;

View File

@ -0,0 +1,3 @@
var x = Horizon.jsx('div');
var y = Horizon.jsx(Eview.Table);
var z = Horizon.jsx(this);

View File

@ -0,0 +1 @@
<div className="123"></div>

View File

@ -0,0 +1,9 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist"
},
"include": [
"src"
]
}

View File

@ -44,7 +44,7 @@ function buildElement(isClone, type, setting, children) {
const props = isClone ? { ...type.props } : {}; const props = isClone ? { ...type.props } : {};
let vNode = isClone ? type.belongClassVNode : getProcessingClassVNode(); let vNode = isClone ? type.belongClassVNode : getProcessingClassVNode();
if (setting !== null) { if (setting !== null && setting !== undefined) {
const keys = Object.keys(setting); const keys = Object.keys(setting);
const keyLength = keys.length; const keyLength = keys.length;
for (let i = 0; i < keyLength; i++) { for (let i = 0; i < keyLength; i++) {
@ -81,5 +81,5 @@ export function cloneElement(element, setting, ...children) {
// 检测结构体是否为合法的Element // 检测结构体是否为合法的Element
export function isValidElement(element) { export function isValidElement(element) {
return (element && element.vtype === TYPE_COMMON_ELEMENT); return !!(element && element.vtype === TYPE_COMMON_ELEMENT);
} }

View File

@ -196,11 +196,11 @@ export function calcStartUpdateVNode(treeRoot: VNode) {
} }
} }
// 得到相等的路径 // 得到相等的路径
let startNodePath = toUpdateNodes[0].path.slice(0, idx); const startNodePath = toUpdateNodes[0].path.slice(0, idx);
let node = treeRoot; let node = treeRoot;
for (let i = 1; i < startNodePath.length; i++) { for (let i = 1; i < startNodePath.length; i++) {
let pathIndex = startNodePath[i]; const pathIndex = Number(startNodePath[i]);
node = getChildByIndex(node, pathIndex); node = getChildByIndex(node, pathIndex);
} }

View File

@ -2,7 +2,13 @@ import type { VNode } from '../Types';
import { FlagUtils } from '../vnode/VNodeFlags'; import { FlagUtils } from '../vnode/VNodeFlags';
import { TYPE_COMMON_ELEMENT, TYPE_FRAGMENT, TYPE_PORTAL } from '../../external/JSXElementType'; import { TYPE_COMMON_ELEMENT, TYPE_FRAGMENT, TYPE_PORTAL } from '../../external/JSXElementType';
import { DomText, DomPortal, Fragment, DomComponent } from '../vnode/VNodeTags'; import { DomText, DomPortal, Fragment, DomComponent } from '../vnode/VNodeTags';
import {updateVNode, createVNodeFromElement, createFragmentVNode, createPortalVNode, createDomTextVNode} from '../vnode/VNodeCreator'; import {
updateVNode,
createVNodeFromElement,
createFragmentVNode,
createPortalVNode,
createDomTextVNode,
} from '../vnode/VNodeCreator';
import { import {
isSameType, isSameType,
getIteratorFn, getIteratorFn,
@ -112,7 +118,7 @@ function getNewNode(parentNode: VNode, newChild: any, oldNode: VNode | null) {
return null; return null;
} }
let resultNode = null; let resultNode: VNode | null = null;
switch (newNodeType) { switch (newNodeType) {
case DiffCategory.TEXT_NODE: { case DiffCategory.TEXT_NODE: {
if (oldNode === null || oldNode.tag !== DomText) { if (oldNode === null || oldNode.tag !== DomText) {
@ -172,9 +178,9 @@ function getNewNode(parentNode: VNode, newChild: any, oldNode: VNode | null) {
} }
function transRightChildrenToArray(child) { function transRightChildrenToArray(child) {
const rightChildrenArray = []; const rightChildrenArray: VNode[] = [];
travelChildren(child, (node) => { travelChildren(child, node => {
rightChildrenArray.push(node); rightChildrenArray.push(node);
}); });
@ -183,11 +189,11 @@ function transRightChildrenToArray(child) {
function transLeftChildrenToMap( function transLeftChildrenToMap(
startChild: VNode, startChild: VNode,
rightEndVNode: VNode | null rightEndVNode: VNode | null,
): Map<string | number, VNode> { ): Map<string | number, VNode> {
const leftChildrenMap: Map<string | number, VNode> = new Map(); const leftChildrenMap: Map<string | number, VNode> = new Map();
travelChildren(startChild, (node) => { travelChildren(startChild, node => {
leftChildrenMap.set(node.key !== null ? node.key : node.eIndex, node); leftChildrenMap.set(node.key !== null ? node.key : node.eIndex, node);
}, node => node === rightEndVNode); }, node => node === rightEndVNode);
@ -221,18 +227,21 @@ function diffArrayNodesHandler(
let prevNewNode: VNode | null = null; let prevNewNode: VNode | null = null;
let oldNode = firstChild; let oldNode = firstChild;
let nextOldNode = null; let nextOldNode: VNode | null = null;
let theLastPosition = 0; let theLastPosition = 0;
// 从左边开始的位置 // 从左边开始的位置
let leftIdx = 0; let leftIdx = 0;
function appendNode(newNode) { function appendNode(newNode: VNode) {
if (prevNewNode === null) { if (prevNewNode === null) {
resultingFirstChild = newNode; resultingFirstChild = newNode;
newNode.cIndex = 0;
} else { } else {
prevNewNode.next = newNode; prevNewNode.next = newNode;
newNode.cIndex = prevNewNode.cIndex + 1;
} }
newNode.path = newNode.parent.path + newNode.cIndex;
prevNewNode = newNode; prevNewNode = newNode;
} }
@ -269,15 +278,13 @@ function diffArrayNodesHandler(
theLastPosition = setVNodeAdditionFlag(newNode, theLastPosition, isComparing); theLastPosition = setVNodeAdditionFlag(newNode, theLastPosition, isComparing);
newNode.eIndex = leftIdx; newNode.eIndex = leftIdx;
newNode.cIndex = leftIdx;
newNode.path = newNode.parent.path + newNode.cIndex;
appendNode(newNode); appendNode(newNode);
oldNode = nextOldNode; oldNode = nextOldNode;
} }
let rightIdx = newChildren.length; let rightIdx = newChildren.length;
let rightEndOldNode; // 老节点中最右边匹配的节点引用 abcde --> abfde 则rightEndOldNode = c; let rightEndOldNode; // 老节点中最右边匹配的节点引用 abcde --> abfde 则rightEndOldNode = c;
let rightNewNode = null; // 最右边匹配的节点引用 abcde --> abfde 则rightNewNode = d; let rightNewNode: VNode | null = null; // 最右边匹配的节点引用 abcde --> abfde 则rightNewNode = d;
// 从后往前新资源的位置还没有到最末端旧的vNode也还没遍历完则可以考虑从后往前开始 // 从后往前新资源的位置还没有到最末端旧的vNode也还没遍历完则可以考虑从后往前开始
if (rightIdx > leftIdx && oldNode !== null) { if (rightIdx > leftIdx && oldNode !== null) {
const rightRemainingOldChildren = transRightChildrenToArray(oldNode); const rightRemainingOldChildren = transRightChildrenToArray(oldNode);
@ -347,7 +354,9 @@ function diffArrayNodesHandler(
let isDirectAdd = false; let isDirectAdd = false;
// TODO: 是否可以扩大至非dom类型节点 // TODO: 是否可以扩大至非dom类型节点
// 如果dom节点在上次添加前没有节点说明本次添加时可以直接添加到最后不需要通过 getSiblingDom 函数找到 before 节点 // 如果dom节点在上次添加前没有节点说明本次添加时可以直接添加到最后不需要通过 getSiblingDom 函数找到 before 节点
if (parentNode.tag === DomComponent && parentNode.oldProps?.children?.length === 0 && rightIdx - leftIdx === newChildren.length) { if (parentNode.tag === DomComponent &&
parentNode.oldProps?.children?.length === 0 &&
rightIdx - leftIdx === newChildren.length) {
isDirectAdd = true; isDirectAdd = true;
} }
for (; leftIdx < rightIdx; leftIdx++) { for (; leftIdx < rightIdx; leftIdx++) {
@ -367,7 +376,7 @@ function diffArrayNodesHandler(
if (rightNewNode) { if (rightNewNode) {
appendNode(rightNewNode); appendNode(rightNewNode);
setVNodesCIndex(rightNewNode, prevNewNode.cIndex + 1); setVNodesCIndex(rightNewNode.next, rightNewNode.cIndex + 1);
} }
return resultingFirstChild; return resultingFirstChild;
@ -380,7 +389,7 @@ function diffArrayNodesHandler(
const eIndexes: Array<number> = []; // 记录 eIndex 值 const eIndexes: Array<number> = []; // 记录 eIndex 值
const result: Array<number> = []; // 记录最长子序列在eIndexes中的 index 值 const result: Array<number> = []; // 记录最长子序列在eIndexes中的 index 值
const preIndex: Array<number> = []; // 贪心算法在替换的过程中会使得数组不正确通过记录preIndex找到正确值 const preIndex: Array<number> = []; // 贪心算法在替换的过程中会使得数组不正确通过记录preIndex找到正确值
const reuseNodes = []; // 记录复用的 VNode const reuseNodes: (VNode | null)[] = []; // 记录复用的 VNode
let i = 0; let i = 0;
let oldNodeFromMap; let oldNodeFromMap;
let last; let last;
@ -394,7 +403,7 @@ function diffArrayNodesHandler(
} }
if (oldNodeFromMap !== null) { if (oldNodeFromMap !== null) {
let eIndex = newNode.eIndex; const eIndex = newNode.eIndex;
eIndexes.push(eIndex); eIndexes.push(eIndex);
last = eIndexes[result[result.length - 1]]; last = eIndexes[result[result.length - 1]];
if (eIndex > last || last === undefined) { // 大的 eIndex直接放在最后 if (eIndex > last || last === undefined) { // 大的 eIndex直接放在最后
@ -455,15 +464,15 @@ function diffArrayNodesHandler(
if (rightNewNode) { if (rightNewNode) {
appendNode(rightNewNode); appendNode(rightNewNode);
setVNodesCIndex(rightNewNode, prevNewNode.cIndex + 1); setVNodesCIndex(rightNewNode.next, rightNewNode.cIndex + 1);
} }
return resultingFirstChild; return resultingFirstChild;
} }
// 设置vNode中的cIndex属性cIndex是节点在children中的位置 // 设置vNode中的cIndex属性cIndex是节点在children中的位置
function setVNodesCIndex(startChild: VNode, startIdx: number) { function setVNodesCIndex(startChild: VNode | null, startIdx: number) {
let node = startChild; let node: VNode | null = startChild;
let idx = startIdx; let idx = startIdx;
while (node !== null) { while (node !== null) {

View File

@ -25,7 +25,7 @@ import {
TYPE_SUSPENSE, TYPE_SUSPENSE,
} from '../../external/JSXElementType'; } from '../../external/JSXElementType';
import { VNode } from './VNode'; import { VNode } from './VNode';
import {JSXElement} from '../Types'; import { JSXElement } from '../Types';
const typeLazyMap = { const typeLazyMap = {
[TYPE_FORWARD_REF]: ForwardRef, [TYPE_FORWARD_REF]: ForwardRef,
@ -187,6 +187,33 @@ export function onlyUpdateChildVNodes(processing: VNode): VNode | null {
return processing.child; return processing.child;
} }
// 当跳过子树更新时父节点path更新时需要更新所有子树path
if (processing.child && processing.path !== processing.child.path.slice(0, processing.path.length)) {
// bfs更新子树path
const queue: VNode[] = [];
const putChildrenIntoQueue = (vNode: VNode) => {
const child = vNode.child;
if (child) {
queue.push(child);
let sibling = child.next;
while (sibling) {
queue.push(sibling);
sibling = sibling.next;
}
}
}
putChildrenIntoQueue(processing.child);
while (queue.length) {
const vNode = queue.shift()!;
vNode.path = vNode.parent.path + vNode.cIndex;
putChildrenIntoQueue(vNode)
}
}
// 子树无需工作 // 子树无需工作
return null; return null;
} }

View File

@ -6,7 +6,7 @@
"scripts": { "scripts": {
"build": " webpack --config ./scripts/webpack/webpack.config.js", "build": " webpack --config ./scripts/webpack/webpack.config.js",
"build-3rdLib": "node ./scripts/gen3rdLib.js", "build-3rdLib": "node ./scripts/gen3rdLib.js",
"build-3rdLib-dev": "node ./scripts/gen3rdLib.js --dev", "build-3rdLib-dev": "npm run build & node ./scripts/gen3rdLib.js --dev",
"debug-test": "yarn test --debug", "debug-test": "yarn test --debug",
"test": "jest --config=jest.config.js", "test": "jest --config=jest.config.js",
"watch-test": "yarn test --watch --dev" "watch-test": "yarn test --watch --dev"

View File

@ -51,7 +51,6 @@
"prefer-object-spread": true, "prefer-object-spread": true,
"typeof-compare": true, "typeof-compare": true,
"cyclomatic-complexity": [true, 20], "cyclomatic-complexity": [true, 20],
"max-file-line-count": [true, 500],
"prefer-readonly": true, "prefer-readonly": true,
"prefer-const": true, "prefer-const": true,
"radix": true, "radix": true,