diff --git a/.eslintrc.json b/.eslintrc.json index 45d3898e5..640dd7130 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -20,6 +20,8 @@ "@typescript-eslint/triple-slash-reference": "off", "@typescript-eslint/strict-boolean-expressions": "off", "@typescript-eslint/prefer-nullish-coalescing": "off", - "no-void": "off" + "@typescript-eslint/no-non-null-assertion": "off", + "no-void": "off", + "no-labels": "off" } } diff --git a/CHANGELOG.md b/CHANGELOG.md index fc3b74bc2..39e00be10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1 @@ -See Github for changes https://github.com/infernojs/inferno/releases +See GitHub for changes https://github.com/infernojs/inferno/releases diff --git a/documentation/v9-migration.md b/documentation/v9-migration.md new file mode 100644 index 000000000..266775ab5 --- /dev/null +++ b/documentation/v9-migration.md @@ -0,0 +1,13 @@ +# InfernoJS v9.0.0 + +## Breaking changes + +Inferno v9 requires following features to be present in the executing runtime: + +- `Promise` +- `Array.prototype.includes()` +- `Array.prototype.includes()` +- `Object.spread()` + +`options.componentComparator` has been removed +`options.renderComplete` has been removed, same result can be achieved by calling own function after render diff --git a/packages/inferno-router/src/NavLink.ts b/packages/inferno-router/src/NavLink.ts index 241165997..b3074951f 100644 --- a/packages/inferno-router/src/NavLink.ts +++ b/packages/inferno-router/src/NavLink.ts @@ -1,10 +1,10 @@ -import { createComponentVNode, Inferno, VNode } from 'inferno'; +import { createComponentVNode, type Inferno, type VNode } from 'inferno'; import { VNodeFlags } from 'inferno-vnode-flags'; import { Route } from './Route'; -import { ILinkProps, Link } from './Link'; +import { type ILinkProps, Link } from './Link'; import type { Location } from 'history'; -function filter(i) { +function filter(i): any { return i; } @@ -38,27 +38,34 @@ export function NavLink({ isActive: getIsActive, ariaCurrent = 'true', ...rest -}: NavLinkProps & Omit, 'className' | 'style'>): any { +}: NavLinkProps & + Omit< + Inferno.LinkHTMLAttributes, + 'className' | 'style' + >): any { function linkComponent({ location, match }): VNode { - const isActive = Boolean(getIsActive ? getIsActive(match, location) : match); + const isActive = Boolean( + getIsActive ? getIsActive(match, location) : match, + ); - const className = typeof classNameProp === 'function' ? classNameProp(isActive) : classNameProp; + const className = + typeof classNameProp === 'function' + ? classNameProp(isActive) + : classNameProp; - const style = typeof styleProp === 'function' ? styleProp(isActive) : styleProp; + const style = + typeof styleProp === 'function' ? styleProp(isActive) : styleProp; - return createComponentVNode( - VNodeFlags.ComponentFunction, - Link, - { - 'aria-current': (isActive && ariaCurrent) || null, - className: isActive ? [className, activeClassName].filter(filter).join(' ') : className, - onClick, - style: isActive ? {...style, ...activeStyle} : style, - to, - ...rest - }, - ) - ); + return createComponentVNode(VNodeFlags.ComponentFunction, Link, { + 'aria-current': ((isActive && ariaCurrent) || null) as any, + className: isActive + ? [className, activeClassName].filter(filter).join(' ') + : className, + onClick, + style: isActive ? { ...style, ...activeStyle } : style, + to, + ...rest, + }); } return createComponentVNode(VNodeFlags.ComponentClass, Route, { @@ -66,6 +73,6 @@ export function NavLink({ exact, location: linkLocation, path: typeof to === 'object' ? to.pathname : to, - strict + strict, }); } diff --git a/packages/inferno-router/src/Switch.ts b/packages/inferno-router/src/Switch.ts index 16479fbf3..1a48e91da 100644 --- a/packages/inferno-router/src/Switch.ts +++ b/packages/inferno-router/src/Switch.ts @@ -79,7 +79,7 @@ export class Switch extends Component { if (match) { location ??= context.router.route.location; - return createComponentVNode(_child.flags, _child.type, {..._child.props, ...{ location, computedMatch: match }})); + return createComponentVNode(_child.flags, _child.type, {..._child.props, ...{ location, computedMatch: match }}); } return null; diff --git a/packages/inferno-vnode-flags/src/index.ts b/packages/inferno-vnode-flags/src/index.ts index fede7741e..2d3893a37 100644 --- a/packages/inferno-vnode-flags/src/index.ts +++ b/packages/inferno-vnode-flags/src/index.ts @@ -29,7 +29,7 @@ export const enum VNodeFlags { DOMRef = Element | Text | Portal, InUseOrNormalized = InUse | Normalized, ClearInUse = ~InUse, - ComponentKnown = ComponentFunction | ComponentClass + ComponentKnown = ComponentFunction | ComponentClass, } // Combinations are not possible, its bitwise only to reduce vNode size @@ -42,5 +42,5 @@ export const enum ChildFlags { HasKeyedChildren = 1 << 3, HasTextChildren = 1 << 4, - MultipleChildren = HasNonKeyedChildren | HasKeyedChildren + MultipleChildren = HasNonKeyedChildren | HasKeyedChildren, } diff --git a/packages/inferno/src/DOM/events/attachEvent.ts b/packages/inferno/src/DOM/events/attachEvent.ts index c31e3afce..e39b83756 100644 --- a/packages/inferno/src/DOM/events/attachEvent.ts +++ b/packages/inferno/src/DOM/events/attachEvent.ts @@ -1,6 +1,6 @@ import { isFunction } from 'inferno-shared'; -export function attachEvent(dom, eventName, handler) { +export function attachEvent(dom, eventName, handler): void { const previousKey = `$${eventName}`; const previousArgs = dom[previousKey]; diff --git a/packages/inferno/src/DOM/events/delegation.ts b/packages/inferno/src/DOM/events/delegation.ts index 39747f651..12cbb5657 100644 --- a/packages/inferno/src/DOM/events/delegation.ts +++ b/packages/inferno/src/DOM/events/delegation.ts @@ -48,7 +48,7 @@ const attachedEvents = getDelegatedEventObject(null); export const syntheticEvents = getDelegatedEventObject(true); -function updateOrAddSyntheticEvent(name: string, dom) { +function updateOrAddSyntheticEvent(name: string, dom): DelegateEventTypes { let eventsObject = dom.$EV; if (!eventsObject) { @@ -63,7 +63,7 @@ function updateOrAddSyntheticEvent(name: string, dom) { return eventsObject; } -export function unmountSyntheticEvent(name: string, dom) { +export function unmountSyntheticEvent(name: string, dom): void { const eventsObject = dom.$EV; if (eventsObject?.[name]) { @@ -80,10 +80,10 @@ export function unmountSyntheticEvent(name: string, dom) { export function handleSyntheticEvent( name: string, - lastEvent: Function | LinkedEvent | null | false | true, - nextEvent: Function | LinkedEvent | null | false | true, + lastEvent: (() => void) | LinkedEvent | null | false | true, + nextEvent: (() => void) | LinkedEvent | null | false | true, dom, -) { +): void { if (isFunction(nextEvent)) { updateOrAddSyntheticEvent(name, dom)[name] = nextEvent; } else if (isLinkEventObject(nextEvent)) { @@ -97,7 +97,7 @@ export function handleSyntheticEvent( } // TODO: When browsers fully support event.composedPath we could loop it through instead of using parentNode property -function getTargetNode(event) { +function getTargetNode(event): any { return isFunction(event.composedPath) ? event.composedPath()[0] : event.target; diff --git a/packages/inferno/src/DOM/events/linkEvent.ts b/packages/inferno/src/DOM/events/linkEvent.ts index c211de6ff..bf7110f07 100644 --- a/packages/inferno/src/DOM/events/linkEvent.ts +++ b/packages/inferno/src/DOM/events/linkEvent.ts @@ -7,7 +7,10 @@ import { isFunction, isNull } from 'inferno-shared'; * @param {Function} event Function to be called when event occurs * @returns {{data: *, event: Function}} */ -export function linkEvent(data: T, event: (data: T, event: E) => void): LinkedEvent | null { +export function linkEvent( + data: T, + event: (data: T, event: E) => void, +): LinkedEvent | null { if (isFunction(event)) { return { data, event }; } diff --git a/packages/inferno/src/DOM/mounting.ts b/packages/inferno/src/DOM/mounting.ts index cc39b0f4e..d087a0238 100644 --- a/packages/inferno/src/DOM/mounting.ts +++ b/packages/inferno/src/DOM/mounting.ts @@ -1,4 +1,4 @@ -import type { VNode } from '../core/types'; +import type { VNode, ContextObject } from '../core/types'; import { isFunction, isNull, @@ -29,7 +29,6 @@ import { } from './utils/componentUtil'; import { validateKeys } from '../core/validate'; import { mountRef } from '../core/refs'; -import { ContextObject } from "../core/types"; export function mount( vNode: VNode, @@ -109,7 +108,7 @@ function mountPortal( nextNode: Element | null, lifecycle: Array<() => void>, animations: AnimationQueues, -) { +): void { mount( vNode.children as VNode, vNode.ref, @@ -186,7 +185,7 @@ export function mountText( export function mountElement( vNode: VNode, parentDOM: Element | null, - context: unknown, + context: ContextObject, isSVG: boolean, nextNode: Element | null, lifecycle: Array<() => void>, @@ -269,7 +268,7 @@ export function mountElement( export function mountArrayChildren( children, dom: Element | null, - context: Object, + context: ContextObject, isSVG: boolean, nextNode: Element | null, lifecycle: Array<() => void>, @@ -288,12 +287,12 @@ export function mountArrayChildren( export function mountClassComponent( vNode: VNode, parentDOM: Element | null, - context: Object, + context: ContextObject, isSVG: boolean, nextNode: Element | null, lifecycle: Array<() => void>, animations: AnimationQueues, -) { +): void { const instance = createClassComponentInstance( vNode, vNode.type, @@ -323,7 +322,7 @@ export function mountClassComponent( export function mountFunctionalComponent( vNode: VNode, parentDOM: Element | null, - context: Object, + context: ContextObject, isSVG: boolean, nextNode: Element | null, lifecycle, @@ -360,7 +359,7 @@ function addAppearAnimationHook( dom: Element, flags: VNodeFlags, props, -) { +): void { animations.componentDidAppear.push(() => { if (flags & VNodeFlags.ComponentClass) { instanceOrRef.componentDidAppear(dom); @@ -375,7 +374,7 @@ export function mountClassComponentCallbacks( instance, lifecycle: Array<() => void>, animations: AnimationQueues, -) { +): void { mountRef(ref, instance, lifecycle); if (process.env.NODE_ENV !== 'production') { @@ -421,7 +420,7 @@ export function mountFunctionalComponentCallbacks( vNode: VNode, lifecycle: Array<() => void>, animations: AnimationQueues, -) { +): void { const ref = vNode.ref; if (!isNullOrUndef(ref)) { diff --git a/packages/inferno/src/DOM/patching.ts b/packages/inferno/src/DOM/patching.ts index 76c45a0f8..5fbcca602 100644 --- a/packages/inferno/src/DOM/patching.ts +++ b/packages/inferno/src/DOM/patching.ts @@ -1,30 +1,54 @@ -import type { VNode } from '../core/types'; +import type { ContextObject, VNode } from '../core/types'; import { isFunction, isInvalid, isNull, isNullOrUndef } from 'inferno-shared'; import { ChildFlags, VNodeFlags } from 'inferno-vnode-flags'; -import { createVoidVNode, directClone, normalizeRoot } from '../core/implementation'; +import { + createVoidVNode, + directClone, + normalizeRoot, +} from '../core/implementation'; +import type { Component } from './../core/component'; import { mount, mountArrayChildren } from './mounting'; -import { clearDOM, remove, removeAllChildren, unmount, unmountAllChildren } from './unmounting'; import { - AnimationQueues, + clearDOM, + remove, + removeAllChildren, + unmount, + unmountAllChildren, +} from './unmounting'; +import { + type AnimationQueues, appendChild, callAllMoveAnimationHooks, createDerivedState, EMPTY_OBJ, findDOMFromVNode, moveVNodeDOM, - options, removeChild, removeVNodeDOM, replaceChild, - setTextContent + setTextContent, } from './utils/common'; -import { isControlledFormElement, processElement } from './wrappers/processElement'; +import { + isControlledFormElement, + processElement, +} from './wrappers/processElement'; import { patchProp } from './props'; -import { renderFunctionalComponent, renderNewInput } from './utils/componentUtil'; +import { + renderFunctionalComponent, + renderNewInput, +} from './utils/componentUtil'; import { validateKeys } from '../core/validate'; import { mountRef, unmountRef } from '../core/refs'; -function replaceWithNewNode(lastVNode, nextVNode, parentDOM: Element, context: Object, isSVG: boolean, lifecycle: Array<() => void>, animations: AnimationQueues) { +function replaceWithNewNode( + lastVNode, + nextVNode, + parentDOM: Element, + context: ContextObject, + isSVG: boolean, + lifecycle: Array<() => void>, + animations: AnimationQueues, +): void { unmount(lastVNode, animations); if ((nextVNode.flags & lastVNode.flags & VNodeFlags.DOMRef) !== 0) { @@ -32,7 +56,15 @@ function replaceWithNewNode(lastVNode, nextVNode, parentDOM: Element, context: O // Single DOM operation, when we have dom references available replaceChild(parentDOM, nextVNode.dom, lastVNode.dom); } else { - mount(nextVNode, parentDOM, context, isSVG, findDOMFromVNode(lastVNode, true), lifecycle, animations); + mount( + nextVNode, + parentDOM, + context, + isSVG, + findDOMFromVNode(lastVNode, true), + lifecycle, + animations, + ); removeVNodeDOM(lastVNode, parentDOM, animations); } } @@ -41,46 +73,96 @@ export function patch( lastVNode: VNode, nextVNode: VNode, parentDOM: Element, - context: Object, + context: ContextObject, isSVG: boolean, nextNode: Element | null, lifecycle: Array<() => void>, - animations: AnimationQueues -) { + animations: AnimationQueues, +): void { const nextFlags = (nextVNode.flags |= VNodeFlags.InUse); - if (process.env.NODE_ENV !== 'production') { - if (isFunction(options.componentComparator) && lastVNode.flags & nextFlags & VNodeFlags.ComponentClass) { - if ((options.componentComparator as Function)(lastVNode, nextVNode) === false) { - patchClassComponent(lastVNode, nextVNode, parentDOM, context, isSVG, nextNode, lifecycle, animations); - return; - } - } - } - - if (lastVNode.flags !== nextFlags || lastVNode.type !== nextVNode.type || lastVNode.key !== nextVNode.key || nextFlags & VNodeFlags.ReCreate) { + if ( + lastVNode.flags !== nextFlags || + lastVNode.type !== nextVNode.type || + lastVNode.key !== nextVNode.key || + nextFlags & VNodeFlags.ReCreate + ) { if (lastVNode.flags & VNodeFlags.InUse) { - replaceWithNewNode(lastVNode, nextVNode, parentDOM, context, isSVG, lifecycle, animations); + replaceWithNewNode( + lastVNode, + nextVNode, + parentDOM, + context, + isSVG, + lifecycle, + animations, + ); } else { // Last vNode is not in use, it has crashed at application level. Just mount nextVNode and ignore last one - mount(nextVNode, parentDOM, context, isSVG, nextNode, lifecycle, animations); + mount( + nextVNode, + parentDOM, + context, + isSVG, + nextNode, + lifecycle, + animations, + ); } } else if (nextFlags & VNodeFlags.Element) { - patchElement(lastVNode, nextVNode, context, isSVG, nextFlags, lifecycle, animations); + patchElement( + lastVNode, + nextVNode, + context, + isSVG, + nextFlags, + lifecycle, + animations, + ); } else if (nextFlags & VNodeFlags.ComponentClass) { - patchClassComponent(lastVNode, nextVNode, parentDOM, context, isSVG, nextNode, lifecycle, animations); + patchClassComponent( + lastVNode, + nextVNode, + parentDOM, + context, + isSVG, + nextNode, + lifecycle, + animations, + ); } else if (nextFlags & VNodeFlags.ComponentFunction) { - patchFunctionalComponent(lastVNode, nextVNode, parentDOM, context, isSVG, nextNode, lifecycle, animations); + patchFunctionalComponent( + lastVNode, + nextVNode, + parentDOM, + context, + isSVG, + nextNode, + lifecycle, + animations, + ); } else if (nextFlags & VNodeFlags.Text) { patchText(lastVNode, nextVNode); } else if (nextFlags & VNodeFlags.Fragment) { - patchFragment(lastVNode, nextVNode, parentDOM, context, isSVG, lifecycle, animations); + patchFragment( + lastVNode, + nextVNode, + parentDOM, + context, + isSVG, + lifecycle, + animations, + ); } else { patchPortal(lastVNode, nextVNode, context, lifecycle, animations); } } -export function patchSingleTextChild(lastChildren, nextChildren, parentDOM: Element) { +export function patchSingleTextChild( + lastChildren, + nextChildren, + parentDOM: Element, +): void { if (lastChildren !== nextChildren) { if (lastChildren !== '') { (parentDOM.firstChild as Node).nodeValue = nextChildren; @@ -90,7 +172,7 @@ export function patchSingleTextChild(lastChildren, nextChildren, parentDOM: Elem } } -function patchContentEditableChildren(dom, nextChildren) { +function patchContentEditableChildren(dom, nextChildren): void { if (dom.textContent !== nextChildren) { dom.textContent = nextChildren; } @@ -100,11 +182,11 @@ function patchFragment( lastVNode: VNode, nextVNode: VNode, parentDOM: Element, - context: Object, + context: ContextObject, isSVG: boolean, lifecycle: Array<() => void>, - animations: AnimationQueues -) { + animations: AnimationQueues, +): void { const lastChildren = lastVNode.children as VNode[]; let nextChildren = nextVNode.children as any; const lastChildFlags = lastVNode.childFlags; @@ -113,12 +195,16 @@ function patchFragment( // When fragment is optimized for multiple children, check if there is no children and change flag to invalid // This is the only normalization always done, to keep optimization flags API same for fragments and regular elements - if (nextChildFlags & ChildFlags.MultipleChildren && nextChildren.length === 0) { + if ( + nextChildFlags & ChildFlags.MultipleChildren && + nextChildren.length === 0 + ) { nextChildFlags = nextVNode.childFlags = ChildFlags.HasVNodeChildren; nextChildren = nextVNode.children = createVoidVNode(); } - const nextIsSingle: boolean = (nextChildFlags & ChildFlags.HasVNodeChildren) !== 0; + const nextIsSingle: boolean = + (nextChildFlags & ChildFlags.HasVNodeChildren) !== 0; if (lastChildFlags & ChildFlags.MultipleChildren) { const lastLen = lastChildren.length; @@ -126,21 +212,41 @@ function patchFragment( // We need to know Fragment's edge node when if ( // It uses keyed algorithm - (lastChildFlags & ChildFlags.HasKeyedChildren && nextChildFlags & ChildFlags.HasKeyedChildren) || + (lastChildFlags & ChildFlags.HasKeyedChildren && + nextChildFlags & ChildFlags.HasKeyedChildren) || // It transforms from many to single nextIsSingle || // It will append more nodes (!nextIsSingle && (nextChildren as VNode[]).length > lastLen) ) { // When fragment has multiple children there is always at least one vNode - nextNode = (findDOMFromVNode(lastChildren[lastLen - 1], false) as Element).nextSibling as Element | null; + nextNode = (findDOMFromVNode(lastChildren[lastLen - 1], false) as Element) + .nextSibling as Element | null; } } - patchChildren(lastChildFlags, nextChildFlags, lastChildren, nextChildren, parentDOM, context, isSVG, nextNode, lastVNode, lifecycle, animations); + patchChildren( + lastChildFlags, + nextChildFlags, + lastChildren, + nextChildren, + parentDOM, + context, + isSVG, + nextNode, + lastVNode, + lifecycle, + animations, + ); } -function patchPortal(lastVNode: VNode, nextVNode: VNode, context, lifecycle: Array<() => void>, animations: AnimationQueues) { +function patchPortal( + lastVNode: VNode, + nextVNode: VNode, + context, + lifecycle: Array<() => void>, + animations: AnimationQueues, +): void { const lastContainer = lastVNode.ref as Element; const nextContainer = nextVNode.ref as Element; const nextChildren = nextVNode.children as VNode; @@ -150,13 +256,13 @@ function patchPortal(lastVNode: VNode, nextVNode: VNode, context, lifecycle: Arr nextVNode.childFlags, lastVNode.children as VNode, nextChildren, - lastContainer as Element, + lastContainer, context, false, null, lastVNode, lifecycle, - animations + animations, ); nextVNode.dom = lastVNode.dom; @@ -172,12 +278,12 @@ function patchPortal(lastVNode: VNode, nextVNode: VNode, context, lifecycle: Arr export function patchElement( lastVNode: VNode, nextVNode: VNode, - context: Object, + context: ContextObject, isSVG: boolean, nextFlags: VNodeFlags, lifecycle: Array<() => void>, - animations: AnimationQueues -) { + animations: AnimationQueues, +): void { const dom = (nextVNode.dom = lastVNode.dom as Element); const lastProps = lastVNode.props; const nextProps = nextVNode.props; @@ -202,14 +308,35 @@ export function patchElement( const lastValue = lastPropsOrEmpty[prop]; const nextValue = nextPropsOrEmpty[prop]; if (lastValue !== nextValue) { - patchProp(prop, lastValue, nextValue, dom, isSVG, hasControlledValue, lastVNode, animations); + patchProp( + prop, + lastValue, + nextValue, + dom, + isSVG, + hasControlledValue, + lastVNode, + animations, + ); } } } if (lastPropsOrEmpty !== EMPTY_OBJ) { for (const prop in lastPropsOrEmpty) { - if (isNullOrUndef(nextPropsOrEmpty[prop]) && !isNullOrUndef(lastPropsOrEmpty[prop])) { - patchProp(prop, lastPropsOrEmpty[prop], null, dom, isSVG, hasControlledValue, lastVNode, animations); + if ( + isNullOrUndef(nextPropsOrEmpty[prop]) && + !isNullOrUndef(lastPropsOrEmpty[prop]) + ) { + patchProp( + prop, + lastPropsOrEmpty[prop], + null, + dom, + isSVG, + hasControlledValue, + lastVNode, + animations, + ); } } } @@ -245,12 +372,19 @@ export function patchElement( null, lastVNode, lifecycle, - animations + animations, ); } if (isFormElement) { - processElement(nextFlags, nextVNode, dom, nextPropsOrEmpty, false, hasControlledValue); + processElement( + nextFlags, + nextVNode, + dom, + nextPropsOrEmpty, + false, + hasControlledValue, + ); } const nextRef = nextVNode.ref; @@ -262,32 +396,129 @@ export function patchElement( } } -function replaceOneVNodeWithMultipleVNodes(lastChildren, nextChildren, parentDOM, context, isSVG: boolean, lifecycle: Array<() => void>, animations: AnimationQueues) { +function replaceOneVNodeWithMultipleVNodes( + lastChildren, + nextChildren, + parentDOM, + context, + isSVG: boolean, + lifecycle: Array<() => void>, + animations: AnimationQueues, +): void { unmount(lastChildren, animations); - mountArrayChildren(nextChildren, parentDOM, context, isSVG, findDOMFromVNode(lastChildren, true), lifecycle, animations); + mountArrayChildren( + nextChildren, + parentDOM, + context, + isSVG, + findDOMFromVNode(lastChildren, true), + lifecycle, + animations, + ); removeVNodeDOM(lastChildren, parentDOM, animations); } +function commonChildrenSwitch( + lastChildren, + nextChildren, + parentDOM: Element, + context: ContextObject, + isSVG: boolean, + nextNode: Element | null, + lifecycle: Array<() => void>, + animations: AnimationQueues, + parentVNode: VNode, + nextChildFlags: + | ChildFlags.UnknownChildren + | ChildFlags.HasNonKeyedChildren + | ChildFlags.HasKeyedChildren + | ChildFlags.MultipleChildren, + lastChildFlags: + | ChildFlags.UnknownChildren + | ChildFlags.HasNonKeyedChildren + | ChildFlags.HasKeyedChildren + | ChildFlags.MultipleChildren, +): void { + const lastLength = lastChildren.length | 0; + const nextLength = nextChildren.length | 0; + + // Fast path's for both algorithms + if (lastLength === 0) { + if (nextLength > 0) { + mountArrayChildren( + nextChildren, + parentDOM, + context, + isSVG, + nextNode, + lifecycle, + animations, + ); + } + } else if (nextLength === 0) { + removeAllChildren(parentDOM, parentVNode, lastChildren, animations); + } else if ( + nextChildFlags === ChildFlags.HasKeyedChildren && + lastChildFlags === ChildFlags.HasKeyedChildren + ) { + patchKeyedChildren( + lastChildren, + nextChildren, + parentDOM, + context, + isSVG, + lastLength, + nextLength, + nextNode, + parentVNode, + lifecycle, + animations, + ); + } else { + patchNonKeyedChildren( + lastChildren, + nextChildren, + parentDOM, + context, + isSVG, + lastLength, + nextLength, + nextNode, + lifecycle, + animations, + ); + } +} + function patchChildren( lastChildFlags: ChildFlags, nextChildFlags: ChildFlags, lastChildren, nextChildren, parentDOM: Element, - context: Object, + context: ContextObject, isSVG: boolean, nextNode: Element | null, parentVNode: VNode, lifecycle: Array<() => void>, - animations: AnimationQueues -) { + animations: AnimationQueues, +): void { switch (lastChildFlags) { case ChildFlags.HasVNodeChildren: switch (nextChildFlags) { case ChildFlags.HasVNodeChildren: - patch(lastChildren, nextChildren, parentDOM, context, isSVG, nextNode, lifecycle, animations); + patch( + lastChildren, + nextChildren, + parentDOM, + context, + isSVG, + nextNode, + lifecycle, + animations, + ); break; case ChildFlags.HasInvalidChildren: remove(lastChildren, parentDOM, animations); @@ -297,14 +528,30 @@ function patchChildren( setTextContent(parentDOM, nextChildren); break; default: - replaceOneVNodeWithMultipleVNodes(lastChildren, nextChildren, parentDOM, context, isSVG, lifecycle, animations); + replaceOneVNodeWithMultipleVNodes( + lastChildren, + nextChildren, + parentDOM, + context, + isSVG, + lifecycle, + animations, + ); break; } break; case ChildFlags.HasInvalidChildren: switch (nextChildFlags) { case ChildFlags.HasVNodeChildren: - mount(nextChildren, parentDOM, context, isSVG, nextNode, lifecycle, animations); + mount( + nextChildren, + parentDOM, + context, + isSVG, + nextNode, + lifecycle, + animations, + ); break; case ChildFlags.HasInvalidChildren: break; @@ -312,7 +559,15 @@ function patchChildren( setTextContent(parentDOM, nextChildren); break; default: - mountArrayChildren(nextChildren, parentDOM, context, isSVG, nextNode, lifecycle, animations); + mountArrayChildren( + nextChildren, + parentDOM, + context, + isSVG, + nextNode, + lifecycle, + animations, + ); break; } break; @@ -323,14 +578,30 @@ function patchChildren( break; case ChildFlags.HasVNodeChildren: clearDOM(parentDOM, lastChildren, animations); - mount(nextChildren, parentDOM, context, isSVG, nextNode, lifecycle, animations); + mount( + nextChildren, + parentDOM, + context, + isSVG, + nextNode, + lifecycle, + animations, + ); break; case ChildFlags.HasInvalidChildren: clearDOM(parentDOM, lastChildren, animations); break; default: clearDOM(parentDOM, lastChildren, animations); - mountArrayChildren(nextChildren, parentDOM, context, isSVG, nextNode, lifecycle, animations); + mountArrayChildren( + nextChildren, + parentDOM, + context, + isSVG, + nextNode, + lifecycle, + animations, + ); break; } break; @@ -342,36 +613,48 @@ function patchChildren( break; case ChildFlags.HasVNodeChildren: removeAllChildren(parentDOM, parentVNode, lastChildren, animations); - mount(nextChildren, parentDOM, context, isSVG, nextNode, lifecycle, animations); + mount( + nextChildren, + parentDOM, + context, + isSVG, + nextNode, + lifecycle, + animations, + ); break; case ChildFlags.HasInvalidChildren: removeAllChildren(parentDOM, parentVNode, lastChildren, animations); break; default: - const lastLength = lastChildren.length | 0; - const nextLength = nextChildren.length | 0; - - // Fast path's for both algorithms - if (lastLength === 0) { - if (nextLength > 0) { - mountArrayChildren(nextChildren, parentDOM, context, isSVG, nextNode, lifecycle, animations); - } - } else if (nextLength === 0) { - removeAllChildren(parentDOM, parentVNode, lastChildren, animations); - } else if (nextChildFlags === ChildFlags.HasKeyedChildren && lastChildFlags === ChildFlags.HasKeyedChildren) { - patchKeyedChildren(lastChildren, nextChildren, parentDOM, context, isSVG, lastLength, nextLength, nextNode, parentVNode, lifecycle, animations); - } else { - patchNonKeyedChildren(lastChildren, nextChildren, parentDOM, context, isSVG, lastLength, nextLength, nextNode, lifecycle, animations); - } + commonChildrenSwitch( + lastChildren, + nextChildren, + parentDOM, + context, + isSVG, + nextNode, + lifecycle, + animations, + parentVNode, + nextChildFlags, + lastChildFlags, + ); break; } break; } } -function createDidUpdate(instance, lastProps, lastState, snapshot, lifecycle) { +function createDidUpdate( + instance: Component, + lastProps, + lastState, + snapshot, + lifecycle, +): void { lifecycle.push(() => { - instance.componentDidUpdate(lastProps, lastState, snapshot); + instance.componentDidUpdate!(lastProps, lastState, snapshot); }); } @@ -385,18 +668,26 @@ export function updateClassComponent( force: boolean, nextNode: Element | null, lifecycle: Array<() => void>, - animations: AnimationQueues -) { + animations: AnimationQueues, +): void { const lastState = instance.state; const lastProps = instance.props; const usesNewAPI = Boolean(instance.$N); const hasSCU = isFunction(instance.shouldComponentUpdate); if (usesNewAPI) { - nextState = createDerivedState(instance, nextProps, nextState !== lastState ? {...lastState, ...nextState} : nextState); + nextState = createDerivedState( + instance, + nextProps, + nextState !== lastState ? { ...lastState, ...nextState } : nextState, + ); } - if (force || !hasSCU || (hasSCU && (instance.shouldComponentUpdate as Function)(nextProps, nextState, context))) { + if ( + force || + !hasSCU || + (hasSCU && instance.shouldComponentUpdate(nextProps, nextState, context)) + ) { if (!usesNewAPI && isFunction(instance.componentWillUpdate)) { instance.componentWillUpdate(nextProps, nextState, context); } @@ -411,7 +702,16 @@ export function updateClassComponent( snapshot = instance.getSnapshotBeforeUpdate(lastProps, lastState); } - patch(instance.$LI, nextInput, parentDOM, instance.$CX, isSVG, nextNode, lifecycle, animations); + patch( + instance.$LI, + nextInput, + parentDOM, + instance.$CX, + isSVG, + nextNode, + lifecycle, + animations, + ); // Don't update Last input, until patch has been successfully executed instance.$LI = nextInput; @@ -434,8 +734,8 @@ function patchClassComponent( isSVG: boolean, nextNode: Element | null, lifecycle: Array<() => void>, - animations: AnimationQueues -) { + animations: AnimationQueues, +): void { const instance = (nextVNode.children = lastVNode.children); // If Component has crashed, ignore it to stay functional if (isNull(instance)) { @@ -459,12 +759,23 @@ function patchClassComponent( instance.$BR = false; } if (!isNull(instance.$PS)) { - nextState = {...nextState, ...instance.$PS}; + nextState = { ...nextState, ...instance.$PS }; instance.$PS = null; } } - updateClassComponent(instance, nextState, nextProps, parentDOM, context, isSVG, false, nextNode, lifecycle, animations); + updateClassComponent( + instance, + nextState, + nextProps, + parentDOM, + context, + isSVG, + false, + nextNode, + lifecycle, + animations, + ); if (lastRef !== nextRef) { unmountRef(lastRef); @@ -480,8 +791,8 @@ function patchFunctionalComponent( isSVG: boolean, nextNode: Element | null, lifecycle: Array<() => void>, - animations: AnimationQueues -) { + animations: AnimationQueues, +): void { let shouldUpdate: boolean = true; const nextProps = nextVNode.props || EMPTY_OBJ; const nextRef = nextVNode.ref; @@ -493,13 +804,24 @@ function patchFunctionalComponent( shouldUpdate = nextRef.onComponentShouldUpdate(lastProps, nextProps); } - if (shouldUpdate !== false) { + if (shouldUpdate) { if (nextHooksDefined && isFunction(nextRef.onComponentWillUpdate)) { nextRef.onComponentWillUpdate(lastProps, nextProps); } - const nextInput = normalizeRoot(renderFunctionalComponent(nextVNode, context)); + const nextInput = normalizeRoot( + renderFunctionalComponent(nextVNode, context), + ); - patch(lastInput, nextInput, parentDOM, context, isSVG, nextNode, lifecycle, animations); + patch( + lastInput, + nextInput, + parentDOM, + context, + isSVG, + nextNode, + lifecycle, + animations, + ); nextVNode.children = nextInput; if (nextHooksDefined && isFunction(nextRef.onComponentDidUpdate)) { nextRef.onComponentDidUpdate(lastProps, nextProps); @@ -509,7 +831,7 @@ function patchFunctionalComponent( } } -function patchText(lastVNode: VNode, nextVNode: VNode) { +function patchText(lastVNode: VNode, nextVNode: VNode): void { const nextText = nextVNode.children as string; const dom = (nextVNode.dom = lastVNode.dom); @@ -522,15 +844,18 @@ function patchNonKeyedChildren( lastChildren, nextChildren, dom, - context: Object, + context: ContextObject, isSVG: boolean, lastChildrenLength: number, nextChildrenLength: number, nextNode: Element | null, lifecycle: Array<() => void>, - animations: AnimationQueues -) { - const commonLength = lastChildrenLength > nextChildrenLength ? nextChildrenLength : lastChildrenLength; + animations: AnimationQueues, +): void { + const commonLength = + lastChildrenLength > nextChildrenLength + ? nextChildrenLength + : lastChildrenLength; let i = 0; let nextChild; let lastChild; @@ -543,7 +868,16 @@ function patchNonKeyedChildren( nextChild = nextChildren[i] = directClone(nextChild); } - patch(lastChild, nextChild, dom, context, isSVG, nextNode, lifecycle, animations); + patch( + lastChild, + nextChild, + dom, + context, + isSVG, + nextNode, + lifecycle, + animations, + ); lastChildren[i] = nextChild; } if (lastChildrenLength < nextChildrenLength) { @@ -573,8 +907,8 @@ function patchKeyedChildren( outerEdge: Element | null, parentVNode: VNode, lifecycle: Array<() => void>, - animations: AnimationQueues -) { + animations: AnimationQueues, +): void { let aEnd = aLength - 1; let bEnd = bLength - 1; let j: number = 0; @@ -584,14 +918,22 @@ function patchKeyedChildren( let nextNode; // Step 1 - // tslint:disable-next-line outer: { // Sync nodes with the same key at the beginning. while (aNode.key === bNode.key) { if (bNode.flags & VNodeFlags.InUse) { b[j] = bNode = directClone(bNode); } - patch(aNode, bNode, dom, context, isSVG, outerEdge, lifecycle, animations); + patch( + aNode, + bNode, + dom, + context, + isSVG, + outerEdge, + lifecycle, + animations, + ); a[j] = bNode; ++j; if (j > aEnd || j > bEnd) { @@ -609,7 +951,16 @@ function patchKeyedChildren( if (bNode.flags & VNodeFlags.InUse) { b[bEnd] = bNode = directClone(bNode); } - patch(aNode, bNode, dom, context, isSVG, outerEdge, lifecycle, animations); + patch( + aNode, + bNode, + dom, + context, + isSVG, + outerEdge, + lifecycle, + animations, + ); a[aEnd] = bNode; aEnd--; bEnd--; @@ -624,7 +975,8 @@ function patchKeyedChildren( if (j > aEnd) { if (j <= bEnd) { nextPos = bEnd + 1; - nextNode = nextPos < bLength ? findDOMFromVNode(b[nextPos], true) : outerEdge; + nextNode = + nextPos < bLength ? findDOMFromVNode(b[nextPos], true) : outerEdge; while (j <= bEnd) { bNode = b[j]; @@ -640,7 +992,22 @@ function patchKeyedChildren( remove(a[j++], dom, animations); } } else { - patchKeyedChildrenComplex(a, b, context, aLength, bLength, aEnd, bEnd, j, dom, isSVG, outerEdge, parentVNode, lifecycle, animations); + patchKeyedChildrenComplex( + a, + b, + context, + aLength, + bLength, + aEnd, + bEnd, + j, + dom, + isSVG, + outerEdge, + parentVNode, + lifecycle, + animations, + ); } } @@ -658,8 +1025,8 @@ function patchKeyedChildrenComplex( outerEdge: Element | null, parentVNode: VNode, lifecycle: Array<() => void>, - animations: AnimationQueues -) { + animations: AnimationQueues, +): void { let aNode: VNode; let bNode: VNode; let nextPos: number = 0; @@ -669,7 +1036,7 @@ function patchKeyedChildrenComplex( const aLeft: number = aEnd - j + 1; const bLeft: number = bEnd - j + 1; const sources = new Int32Array(bLeft + 1); - // Keep track if its possible to remove whole DOM using textContent = ''; + // Keep track if it is possible to remove whole DOM using textContent = ''; let canRemoveWholeContent: boolean = aLeft === aLength; let moved: boolean = false; let pos: number = 0; @@ -698,7 +1065,16 @@ function patchKeyedChildrenComplex( if (bNode.flags & VNodeFlags.InUse) { b[j] = bNode = directClone(bNode); } - patch(aNode, bNode, dom, context, isSVG, outerEdge, lifecycle, animations); + patch( + aNode, + bNode, + dom, + context, + isSVG, + outerEdge, + lifecycle, + animations, + ); ++patched; break; } @@ -742,7 +1118,16 @@ function patchKeyedChildrenComplex( if (bNode.flags & VNodeFlags.InUse) { b[j] = bNode = directClone(bNode); } - patch(aNode, bNode, dom, context, isSVG, outerEdge, lifecycle, animations); + patch( + aNode, + bNode, + dom, + context, + isSVG, + outerEdge, + lifecycle, + animations, + ); ++patched; } else if (!canRemoveWholeContent) { remove(aNode, dom, animations); @@ -755,9 +1140,17 @@ function patchKeyedChildrenComplex( // fast-path: if nothing patched remove all old and add all new if (canRemoveWholeContent) { removeAllChildren(dom, parentVNode, a, animations); - mountArrayChildren(b, dom, context, isSVG, outerEdge, lifecycle, animations); + mountArrayChildren( + b, + dom, + context, + isSVG, + outerEdge, + lifecycle, + animations, + ); } else if (moved) { - const seq = lis_algorithm(sources); + const seq = lisAlgorithm(sources); j = seq.length - 1; for (i = bLeft - 1; i >= 0; i--) { if (sources[i] === 0) { @@ -767,14 +1160,28 @@ function patchKeyedChildrenComplex( b[pos] = bNode = directClone(bNode); } nextPos = pos + 1; - mount(bNode, dom, context, isSVG, nextPos < bLength ? findDOMFromVNode(b[nextPos], true) : outerEdge, lifecycle, animations); + mount( + bNode, + dom, + context, + isSVG, + nextPos < bLength ? findDOMFromVNode(b[nextPos], true) : outerEdge, + lifecycle, + animations, + ); } else if (j < 0 || i !== seq[j]) { pos = i + bStart; bNode = b[pos]; nextPos = pos + 1; // --- the DOM-node is moved by a call to insertAppend - moveVNodeDOM(parentVNode, bNode, dom, nextPos < bLength ? findDOMFromVNode(b[nextPos], true) : outerEdge, animations); + moveVNodeDOM( + parentVNode, + bNode, + dom, + nextPos < bLength ? findDOMFromVNode(b[nextPos], true) : outerEdge, + animations, + ); } else { j--; } @@ -794,7 +1201,15 @@ function patchKeyedChildrenComplex( b[pos] = bNode = directClone(bNode); } nextPos = pos + 1; - mount(bNode, dom, context, isSVG, nextPos < bLength ? findDOMFromVNode(b[nextPos], true) : outerEdge, lifecycle, animations); + mount( + bNode, + dom, + context, + isSVG, + nextPos < bLength ? findDOMFromVNode(b[nextPos], true) : outerEdge, + lifecycle, + animations, + ); } } } @@ -805,7 +1220,7 @@ let p: Int32Array; let maxLen = 0; // https://en.wikipedia.org/wiki/Longest_increasing_subsequence -function lis_algorithm(arr: Int32Array): Int32Array { +function lisAlgorithm(arr: Int32Array): Int32Array { let arrI = 0; let i = 0; let j = 0; diff --git a/packages/inferno/src/DOM/props.ts b/packages/inferno/src/DOM/props.ts index 80bb5c008..4dc3a5d26 100644 --- a/packages/inferno/src/DOM/props.ts +++ b/packages/inferno/src/DOM/props.ts @@ -4,22 +4,30 @@ import { isNull, isNullOrUndef, isString, warning } from 'inferno-shared'; import { handleSyntheticEvent, syntheticEvents } from './events/delegation'; import { ChildFlags, VNodeFlags } from 'inferno-vnode-flags'; import { isSameInnerHTML } from './utils/innerHTML'; -import { AnimationQueues, isLastValueSameLinkEvent, normalizeEventName } from './utils/common'; -import { addFormElementEventHandlers, isControlledFormElement, processElement } from './wrappers/processElement'; +import { + type AnimationQueues, + isLastValueSameLinkEvent, + normalizeEventName, +} from './utils/common'; +import { + addFormElementEventHandlers, + isControlledFormElement, + processElement, +} from './wrappers/processElement'; import { unmount, unmountAllChildren } from './unmounting'; import { attachEvent } from './events/attachEvent'; import { isLinkEventObject } from './events/linkEvent'; -function wrapLinkEvent(nextValue) { +function wrapLinkEvent(nextValue): (e) => void { // This variable makes sure there is no "this" context in callback const ev = nextValue.event; - return function (e) { + return function (e): void { ev(nextValue.data, e); }; } -export function patchEvent(name: string, lastValue, nextValue, dom) { +export function patchEvent(name: string, lastValue, nextValue, dom): void { if (isLinkEventObject(nextValue)) { if (isLastValueSameLinkEvent(lastValue, nextValue)) { return; @@ -31,7 +39,7 @@ export function patchEvent(name: string, lastValue, nextValue, dom) { // We are assuming here that we come from patchProp routine // -nextAttrValue cannot be null or undefined -function patchStyle(lastAttrValue, nextAttrValue, dom) { +function patchStyle(lastAttrValue, nextAttrValue, dom): void { if (isNullOrUndef(nextAttrValue)) { dom.removeAttribute('style'); return; @@ -66,9 +74,15 @@ function patchStyle(lastAttrValue, nextAttrValue, dom) { } } -function patchDangerInnerHTML(lastValue, nextValue, lastVNode, dom, animations: AnimationQueues) { - const lastHtml = (lastValue && lastValue.__html) || ''; - const nextHtml = (nextValue && nextValue.__html) || ''; +function patchDangerInnerHTML( + lastValue, + nextValue, + lastVNode, + dom, + animations: AnimationQueues, +): void { + const lastHtml = lastValue?.__html || ''; + const nextHtml = nextValue?.__html || ''; if (lastHtml !== nextHtml) { if (!isNullOrUndef(nextHtml) && !isSameInnerHTML(dom, nextHtml)) { @@ -86,16 +100,23 @@ function patchDangerInnerHTML(lastValue, nextValue, lastVNode, dom, animations: } } +function patchDomProp(nextValue: unknown, dom: Element, prop: string): void { + const value = isNullOrUndef(nextValue) ? '' : nextValue; + if (dom[prop] !== value) { + dom[prop] = value; + } +} + export function patchProp( - prop, - lastValue, - nextValue, + prop: string, + lastValue: any, + nextValue: any, dom: Element, isSVG: boolean, hasControlledValue: boolean, lastVNode: VNode | null, - animations: AnimationQueues -) { + animations: AnimationQueues, +): void { switch (prop) { case 'children': case 'childrenType': @@ -136,10 +157,7 @@ export function patchProp( if (hasControlledValue && prop === 'value') { break; } - const value = isNullOrUndef(nextValue) ? '' : nextValue; - if (dom[prop] !== value) { - dom[prop] = value; - } + patchDomProp(nextValue, dom, prop); break; case 'style': patchStyle(lastValue, nextValue, dom); @@ -160,8 +178,16 @@ export function patchProp( dom.setAttributeNS(namespaces[prop], prop, nextValue); } else { if (process.env.NODE_ENV !== 'production') { - if (prop === 'href' && isString(nextValue) && nextValue.indexOf('javascript:') === 0) { - warning('Rendering links with javascript: URLs is not recommended. Use event handlers instead if you can. Inferno was passed "' + nextValue + '".'); + if ( + prop === 'href' && + isString(nextValue) && + nextValue.indexOf('javascript:') === 0 + ) { + warning( + 'Rendering links with javascript: URLs is not recommended. Use event handlers instead if you can. Inferno was passed "' + + nextValue + + '".', + ); } } dom.setAttribute(prop, nextValue); @@ -170,7 +196,14 @@ export function patchProp( } } -export function mountProps(vNode, flags, props, dom, isSVG, animations: AnimationQueues) { +export function mountProps( + vNode, + flags, + props, + dom, + isSVG, + animations: AnimationQueues, +): void { let hasControlledValue: boolean = false; const isFormElement = (flags & VNodeFlags.FormElement) > 0; if (isFormElement) { @@ -181,7 +214,16 @@ export function mountProps(vNode, flags, props, dom, isSVG, animations: Animatio } for (const prop in props) { // do not add a hasOwnProperty check here, it affects performance - patchProp(prop, null, props[prop], dom, isSVG, hasControlledValue, null, animations); + patchProp( + prop, + null, + props[prop], + dom, + isSVG, + hasControlledValue, + null, + animations, + ); } if (isFormElement) { processElement(flags, vNode, dom, props, true, hasControlledValue); diff --git a/packages/inferno/src/DOM/rendering.ts b/packages/inferno/src/DOM/rendering.ts index 45a0bd862..19d7f12d5 100644 --- a/packages/inferno/src/DOM/rendering.ts +++ b/packages/inferno/src/DOM/rendering.ts @@ -21,7 +21,6 @@ import { callAll, callAllAnimationHooks, EMPTY_OBJ, - options, renderCheck, } from './utils/common'; import { type DelegateEventTypes } from './events/delegation'; @@ -52,6 +51,7 @@ if (hasDocumentAvailable) { } } +// noinspection JSUnusedAssignment export function renderInternal( input: VNode | InfernoNode, parentDOM: ParentDOM, @@ -124,9 +124,6 @@ export function renderInternal( if (isFunction(callback)) { callback(); } - if (isFunction(options.renderComplete)) { - options.renderComplete(rootInput, parentDOM as any); - } } export function render( diff --git a/packages/inferno/src/DOM/unmounting.ts b/packages/inferno/src/DOM/unmounting.ts index 96b1dacd3..39f921c8c 100644 --- a/packages/inferno/src/DOM/unmounting.ts +++ b/packages/inferno/src/DOM/unmounting.ts @@ -110,7 +110,7 @@ export function unmount(vNode, animations: AnimationQueues): void { export function unmountAllChildren( children: VNode[], animations: AnimationQueues, -) { +): void { for (let i = 0, len = children.length; i < len; ++i) { unmount(children[i], animations); } @@ -131,7 +131,7 @@ export function clearDOM( parentDOM, children: VNode[], animations: AnimationQueues, -) { +): void { if (animations.componentWillDisappear.length > 0) { // Wait until animations are finished before removing actual dom nodes // Be aware that the element could be removed by a later operation @@ -150,7 +150,7 @@ export function removeAllChildren( vNode: VNode, children, animations: AnimationQueues, -) { +): void { unmountAllChildren(children, animations); if (vNode.flags & VNodeFlags.Fragment) { @@ -168,7 +168,8 @@ function addDisappearAnimationHook( flags: VNodeFlags, props, ): void { - animations.componentWillDisappear.push((callback: Function) => { + // @ts-expect-error TODO: Here is something weird check this behavior + animations.componentWillDisappear.push((callback) => { if (flags & VNodeFlags.ComponentClass) { instanceOrRef.componentWillDisappear(dom, callback); } else if (flags & VNodeFlags.ComponentFunction) { diff --git a/packages/inferno/src/DOM/utils/common.ts b/packages/inferno/src/DOM/utils/common.ts index bead65029..62f6b207c 100644 --- a/packages/inferno/src/DOM/utils/common.ts +++ b/packages/inferno/src/DOM/utils/common.ts @@ -2,15 +2,9 @@ import type { Inferno, InfernoNode, LinkedEvent, - ParentDOM, VNode, } from './../../core/types'; -import { - isFunction, - isNull, - isNullOrUndef, - isUndefined, -} from 'inferno-shared'; +import { isFunction, isNull, isNullOrUndef, isUndefined } from 'inferno-shared'; import { ChildFlags, VNodeFlags } from 'inferno-vnode-flags'; import { isLinkEventObject } from '../events/linkEvent'; @@ -331,16 +325,10 @@ export const renderCheck = { }; export const options: { - componentComparator: ((lastVNode: VNode, nextVNode: VNode) => boolean) | null; createVNode: ((vNode: VNode) => void) | null; - renderComplete: - | ((rootInput: VNode | InfernoNode, parentDOM: ParentDOM) => void) - | null; reactStyles?: boolean; } = { - componentComparator: null, createVNode: null, - renderComplete: null, }; export function setTextContent(dom: Element, children): void { diff --git a/packages/inferno/src/DOM/utils/componentUtil.ts b/packages/inferno/src/DOM/utils/componentUtil.ts index 73d31ad00..b2639e9b5 100644 --- a/packages/inferno/src/DOM/utils/componentUtil.ts +++ b/packages/inferno/src/DOM/utils/componentUtil.ts @@ -1,22 +1,32 @@ -import type { VNode } from './../../core/types'; +import type { ContextObject, InfernoNode, VNode } from './../../core/types'; +import type { Component } from './../../core/component'; import { isFunction, isNull, warning } from 'inferno-shared'; import { createDerivedState, EMPTY_OBJ, getComponentName } from './common'; import { VNodeFlags } from 'inferno-vnode-flags'; import { normalizeRoot } from '../../core/implementation'; -function warnAboutOldLifecycles(component) { +function warnAboutOldLifecycles(component: any): void { const oldLifecycles: string[] = []; // Don't warn about react polyfilled components. - if (component.componentWillMount && component.componentWillMount.__suppressDeprecationWarning !== true) { + if ( + component.componentWillMount && + component.componentWillMount.__suppressDeprecationWarning !== true + ) { oldLifecycles.push('componentWillMount'); } - if (component.componentWillReceiveProps && component.componentWillReceiveProps.__suppressDeprecationWarning !== true) { + if ( + component.componentWillReceiveProps && + component.componentWillReceiveProps.__suppressDeprecationWarning !== true + ) { oldLifecycles.push('componentWillReceiveProps'); } - if (component.componentWillUpdate && component.componentWillUpdate.__suppressDeprecationWarning !== true) { + if ( + component.componentWillUpdate && + component.componentWillUpdate.__suppressDeprecationWarning !== true + ) { oldLifecycles.push('componentWillUpdate'); } @@ -30,8 +40,10 @@ function warnAboutOldLifecycles(component) { } } -export function renderNewInput(instance, props, context) { - const nextInput = normalizeRoot(instance.render(props, instance.state, context)); +export function renderNewInput(instance, props, context): VNode { + const nextInput = normalizeRoot( + instance.render(props, instance.state, context), + ); let childContext = context; if (isFunction(instance.getChildContext)) { @@ -42,17 +54,28 @@ export function renderNewInput(instance, props, context) { return nextInput; } -export function createClassComponentInstance(vNode: VNode, Component, props, context: Object, isSVG: boolean, lifecycle: Array<() => void>) { - const instance = new Component(props, context); - const usesNewAPI = (instance.$N = Boolean(Component.getDerivedStateFromProps || instance.getSnapshotBeforeUpdate)); +export function createClassComponentInstance( + vNode: VNode, + ComponentCtr, + props, + context: ContextObject, + isSVG: boolean, + lifecycle: Array<() => void>, +): Component { + const instance = new ComponentCtr(props, context); + const usesNewAPI = (instance.$N = Boolean( + ComponentCtr.getDerivedStateFromProps || instance.getSnapshotBeforeUpdate, + )); instance.$SVG = isSVG; instance.$L = lifecycle; if (process.env.NODE_ENV !== 'production') { - if ((instance as any).getDerivedStateFromProps) { + if (instance.getDerivedStateFromProps) { warning( - `${getComponentName(instance)} getDerivedStateFromProps() is defined as an instance method and will be ignored. Instead, declare it as a static method.` + `${getComponentName( + instance, + )} getDerivedStateFromProps() is defined as an instance method and will be ignored. Instead, declare it as a static method.`, ); } if (usesNewAPI) { @@ -60,7 +83,7 @@ export function createClassComponentInstance(vNode: VNode, Component, props, con } } - vNode.children = instance as any; + vNode.children = instance; instance.$BS = false; instance.context = context; if (instance.props === EMPTY_OBJ) { @@ -71,7 +94,7 @@ export function createClassComponentInstance(vNode: VNode, Component, props, con instance.$BR = true; instance.componentWillMount(); - const pending = instance.$PS as any; + const pending = instance.$PS; if (!isNull(pending)) { const state = instance.state; @@ -97,7 +120,12 @@ export function createClassComponentInstance(vNode: VNode, Component, props, con return instance; } -export function renderFunctionalComponent(vNode: VNode, context) { +export function renderFunctionalComponent( + vNode: VNode, + context: ContextObject, +): InfernoNode { const props = vNode.props || EMPTY_OBJ; - return vNode.flags & VNodeFlags.ForwardRef ? vNode.type.render(props, vNode.ref, context) : vNode.type(props, context); + return vNode.flags & VNodeFlags.ForwardRef + ? vNode.type.render(props, vNode.ref, context) + : vNode.type(props, context); } diff --git a/packages/inferno/src/DOM/utils/innerHTML.ts b/packages/inferno/src/DOM/utils/innerHTML.ts index c55b86baf..2766060ab 100644 --- a/packages/inferno/src/DOM/utils/innerHTML.ts +++ b/packages/inferno/src/DOM/utils/innerHTML.ts @@ -1,6 +1,6 @@ export function isSameInnerHTML(dom: Element, innerHTML: string): boolean { - const tempdom = document.createElement('i'); + const temp = document.createElement('i'); - tempdom.innerHTML = innerHTML; - return tempdom.innerHTML === dom.innerHTML; + temp.innerHTML = innerHTML; + return temp.innerHTML === dom.innerHTML; } diff --git a/packages/inferno/src/core/component.ts b/packages/inferno/src/core/component.ts index fb63fe165..1e807a6fd 100644 --- a/packages/inferno/src/core/component.ts +++ b/packages/inferno/src/core/component.ts @@ -72,7 +72,7 @@ function queueStateChanges( } } -function callSetStateCallbacks(component) { +function callSetStateCallbacks(component): void { const queue = component.$QU; for (let i = 0; i < queue.length; ++i) { @@ -82,7 +82,7 @@ function callSetStateCallbacks(component) { component.$QU = null; } -export function rerender() { +export function rerender(): void { let component; microTaskPending = false; @@ -131,11 +131,15 @@ function applyState(component: Component, force: boolean): void { component.$PS = null; } } -export type ComponentType

= +export type ComponentType

> = | typeof Component

| Inferno.StatelessComponent

; -export abstract class Component

implements IComponent { +export abstract class Component< + P = Record, + S = Record, +> implements IComponent +{ // Public public state: Readonly = null; public props: Readonly<{ children?: InfernoNode }> & Readonly

; @@ -162,7 +166,7 @@ export abstract class Component

implements IComponent { this.context = context || EMPTY_OBJ; // context should not be mutable } - public forceUpdate(callback?: Function) { + public forceUpdate(callback?: (() => void) | undefined): void { if (this.$UN) { return; } @@ -225,7 +229,7 @@ export abstract class Component

implements IComponent { public componentDidAppear?(domNode: Element): void; - public componentWillDisappear?(domNode: Element, callback: Function): void; + public componentWillDisappear?(domNode: Element, callback: () => void): void; public componentWillMove?( parentVNode: VNode, @@ -240,16 +244,14 @@ export abstract class Component

implements IComponent { prevState: Readonly, ): any; - public static defaultProps?: {} | null = null; + public static defaultProps?: Record | null = null; public static getDerivedStateFromProps?(nextProps: any, state: any): any; - // @ts-expect-error TS6133 - public render( - props: Readonly<{ children?: InfernoNode } & P>, - state: Readonly, - context: any, - ): InfernoNode { + /* eslint-disable */ + // @ts-ignore + public render(props: Readonly<{ children?: InfernoNode } & P>, state: Readonly, context: any,): InfernoNode { return null; } + /* eslint-enable */ }