From 18ea310bc8bb0b66a5605ea96acce3e3cc80d5e2 Mon Sep 17 00:00:00 2001 From: phillipc Date: Fri, 20 Dec 2024 21:45:24 +0100 Subject: [PATCH 001/190] configure typescript add some types --- .gitignore | 1 + packages/bind/src/applyBindings.ts | 22 ++++---- packages/bind/src/bindingContext.ts | 12 ++-- packages/computed/src/computed.ts | 4 +- .../observable/src/dependencyDetection.ts | 4 +- .../src/ComponentProvider.ts | 11 +++- .../provider.native/src/NativeProvider.ts | 10 ++-- packages/provider/src/Provider.ts | 12 +++- packages/utils/src/object.ts | 2 +- packages/utils/src/options.ts | 55 +++++++++++-------- tsconfig.json | 15 ++++- 11 files changed, 91 insertions(+), 57 deletions(-) diff --git a/.gitignore b/.gitignore index 272f1e3f2..affa0ff14 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ coverage/ package-lock.json .vscode +yarn.lock diff --git a/packages/bind/src/applyBindings.ts b/packages/bind/src/applyBindings.ts index 016986bd5..50b05a5a7 100644 --- a/packages/bind/src/applyBindings.ts +++ b/packages/bind/src/applyBindings.ts @@ -46,12 +46,12 @@ function getBindingProvider () { return options.bindingProviderInstance.instance || options.bindingProviderInstance } -function isProviderForNode (provider, node) { +function isProviderForNode (provider, node : HTMLElement) { const nodeTypes = provider.FOR_NODE_TYPES || [1, 3, 8] return nodeTypes.includes(node.nodeType) } -function asProperHandlerClass (handler, bindingKey) { +function asProperHandlerClass (handler, bindingKey?) { if (!handler) { return } return handler.isBindingHandlerClass ? handler : LegacyBindingHandler.getOrCreateFor(bindingKey, handler) @@ -104,12 +104,12 @@ function applyBindingsToDescendantsInternal (bindingContext, elementOrVirtualEle bindingEvent.notify(elementOrVirtualElement, bindingEvent.childrenComplete) } -function hasBindings (node) { +function hasBindings (node : HTMLElement) : boolean { const provider = getBindingProvider() return isProviderForNode(provider, node) && provider.nodeHasBindings(node) } -function nodeOrChildHasBindings (node) { +function nodeOrChildHasBindings (node : HTMLElement) : boolean { return hasBindings(node) || [...node.childNodes].some(c => nodeOrChildHasBindings(c)) } @@ -174,7 +174,7 @@ function * topologicalSortBindings (bindings, $component) { for (const result of results) { yield result } } -function applyBindingsToNodeInternal (node, sourceBindings, bindingContext, asyncBindingsApplied) { +function applyBindingsToNodeInternal (node : HTMLElement, sourceBindings : any, bindingContext : any, asyncBindingsApplied : any) { const bindingInfo = domData.getOrSet(node, boundElementDomDataKey, {}) // Prevent multiple applyBindings calls for the same node, except when a binding value is specified const alreadyBound = bindingInfo.alreadyBound @@ -327,7 +327,7 @@ function applyBindingsToNodeInternal (node, sourceBindings, bindingContext, asyn * @param {Object} bindings * @param {[Promise]} nodeAsyncBindingPromises */ -function triggerDescendantsComplete (node, bindings, nodeAsyncBindingPromises) { +function triggerDescendantsComplete (node : HTMLElement, bindings : Object, nodeAsyncBindingPromises : any) { /** descendantsComplete ought to be an instance of the descendantsComplete * binding handler. */ const hasBindingHandler = bindingEvent.descendantsComplete in bindings @@ -345,20 +345,20 @@ function triggerDescendantsComplete (node, bindings, nodeAsyncBindingPromises) { } -function getBindingContext (viewModelOrBindingContext, extendContextCallback) { +function getBindingContext (viewModelOrBindingContext, extendContextCallback?) { return viewModelOrBindingContext && (viewModelOrBindingContext instanceof bindingContext) ? viewModelOrBindingContext : new bindingContext(viewModelOrBindingContext, undefined, undefined, extendContextCallback) } -export function applyBindingAccessorsToNode (node, bindings, viewModelOrBindingContext, asyncBindingsApplied) { +export function applyBindingAccessorsToNode (node : HTMLElement, bindings : any, viewModelOrBindingContext :any, asyncBindingsApplied : any) { if (node.nodeType === 1) { // If it's an element, workaround IE <= 8 HTML parsing weirdness virtualElements.normaliseVirtualElementDomStructure(node) } return applyBindingsToNodeInternal(node, bindings, getBindingContext(viewModelOrBindingContext), asyncBindingsApplied) } -export function applyBindingsToNode (node, bindings, viewModelOrBindingContext) { +export function applyBindingsToNode (node : HTMLElement, bindings : any, viewModelOrBindingContext : any) { const asyncBindingsApplied = new Set() const bindingContext = getBindingContext(viewModelOrBindingContext) const bindingAccessors = getBindingProvider().makeBindingAccessors(bindings, bindingContext, node) @@ -366,7 +366,7 @@ export function applyBindingsToNode (node, bindings, viewModelOrBindingContext) return new BindingResult({asyncBindingsApplied, rootNode: node, bindingContext}) } -export function applyBindingsToDescendants (viewModelOrBindingContext, rootNode) { +export function applyBindingsToDescendants (viewModelOrBindingContext : any, rootNode : HTMLElement) { const asyncBindingsApplied = new Set() if (rootNode.nodeType === 1 || rootNode.nodeType === 8) { const bindingContext = getBindingContext(viewModelOrBindingContext) @@ -376,7 +376,7 @@ export function applyBindingsToDescendants (viewModelOrBindingContext, rootNode) return new BindingResult({asyncBindingsApplied, rootNode}) } -export function applyBindings (viewModelOrBindingContext, rootNode, extendContextCallback) { +export function applyBindings (viewModelOrBindingContext : any, rootNode : HTMLElement, extendContextCallback : any) { const asyncBindingsApplied = new Set() // If jQuery is loaded after Knockout, we won't initially have access to it. So save it here. if (!options.jQuery === undefined && options.jQuery) { diff --git a/packages/bind/src/bindingContext.ts b/packages/bind/src/bindingContext.ts index c34c14551..da2dc598a 100644 --- a/packages/bind/src/bindingContext.ts +++ b/packages/bind/src/bindingContext.ts @@ -19,9 +19,13 @@ export const contextSubscribeSymbol = Symbol('Knockout Context Subscription') // Unique stub to indicate inheritance. const inheritParentIndicator = Symbol('Knockout Parent Indicator') +export interface BindingContextSetting { + exportDependencies?: boolean; +} + // The bindingContext constructor is only called directly to create the root context. For child // contexts, use bindingContext.createChildContext or bindingContext.extend. -export function bindingContext (dataItemOrAccessor, parentContext, dataItemAlias, extendCallback, settings) { +export function bindingContext (dataItemOrAccessor, parentContext, dataItemAlias, extendCallback, settings? : BindingContextSetting) { const self = this const shouldInheritData = dataItemOrAccessor === inheritParentIndicator const realDataItemOrAccessor = shouldInheritData ? undefined : dataItemOrAccessor @@ -157,20 +161,20 @@ Object.assign(bindingContext.prototype, { } }) -export function storedBindingContextForNode (node) { +export function storedBindingContextForNode (node : HTMLElement) { const bindingInfo = domData.get(node, boundElementDomDataKey) return bindingInfo && bindingInfo.context } // Retrieving binding context from arbitrary nodes -export function contextFor (node) { +export function contextFor (node : HTMLElement) { // We can only do something meaningful for elements and comment nodes (in particular, not text nodes, as IE can't store domdata for them) if (node && (node.nodeType === 1 || node.nodeType === 8)) { return storedBindingContextForNode(node) } } -export function dataFor (node) { +export function dataFor (node : HTMLElement) { var context = contextFor(node) return context ? context.$data : undefined } diff --git a/packages/computed/src/computed.ts b/packages/computed/src/computed.ts index df8bdca27..6e8d7bf2c 100644 --- a/packages/computed/src/computed.ts +++ b/packages/computed/src/computed.ts @@ -39,7 +39,7 @@ const DISPOSED_STATE = { _options: null } -export function computed (evaluatorFunctionOrOptions, evaluatorFunctionTarget, options) { +export function computed (evaluatorFunctionOrOptions, evaluatorFunctionTarget?, options?) { if (typeof evaluatorFunctionOrOptions === 'object') { // Single-parameter syntax - everything is on this "options" param options = evaluatorFunctionOrOptions @@ -544,7 +544,7 @@ export function isPureComputed (instance) { return isComputed(instance) && instance[computedState] && instance[computedState].pure } -export function pureComputed (evaluatorFunctionOrOptions, evaluatorFunctionTarget) { +export function pureComputed (evaluatorFunctionOrOptions, evaluatorFunctionTarget?) { if (typeof evaluatorFunctionOrOptions === 'function') { return computed(evaluatorFunctionOrOptions, evaluatorFunctionTarget, {'pure': true}) } else { diff --git a/packages/observable/src/dependencyDetection.ts b/packages/observable/src/dependencyDetection.ts index f093172fb..ca900c89a 100644 --- a/packages/observable/src/dependencyDetection.ts +++ b/packages/observable/src/dependencyDetection.ts @@ -20,7 +20,7 @@ function getId () { return ++lastId } -export function begin (options) { +export function begin (options?) { outerFrames.push(currentFrame) currentFrame = options } @@ -36,7 +36,7 @@ export function registerDependency (subscribable) { } } -export function ignore (callback, callbackTarget, callbackArgs) { +export function ignore (callback, callbackTarget?, callbackArgs?) { try { begin() return callback.apply(callbackTarget, callbackArgs || []) diff --git a/packages/provider.component/src/ComponentProvider.ts b/packages/provider.component/src/ComponentProvider.ts index 3aca65c4a..8c387b463 100644 --- a/packages/provider.component/src/ComponentProvider.ts +++ b/packages/provider.component/src/ComponentProvider.ts @@ -28,20 +28,25 @@ export default class ComponentProvider extends Provider { * Convert to * @param {HTMLElement} node */ - preprocessNode (node) { + preprocessNode (node : HTMLElement) { if (node.tagName === 'SLOT') { const parent = node.parentNode const slotName = node.getAttribute('name') || '' const openNode = document.createComment(`ko slot: "${slotName}"`) const closeNode = document.createComment('/ko') + + if(!parent) + throw Error("Missing parent node") + parent.insertBefore(openNode, node) parent.insertBefore(closeNode, node) parent.removeChild(node) + return [openNode, closeNode] } } - nodeHasBindings (node) { + nodeHasBindings (node : HTMLElement) : boolean { return Boolean(this.getComponentNameForNode(node)) } @@ -68,7 +73,7 @@ export default class ComponentProvider extends Provider { getComponentParams (node, context) { const parser = new Parser(node, context, this.globals) const paramsString = (node.getAttribute('params') || '').trim() - const accessors = parser.parse(paramsString, context, node) + const accessors = parser.parse(paramsString, context, undefined, node) if (!accessors || Object.keys(accessors).length === 0) { return { $raw: {} } } diff --git a/packages/provider.native/src/NativeProvider.ts b/packages/provider.native/src/NativeProvider.ts index 29aea7c70..aeecd39f1 100644 --- a/packages/provider.native/src/NativeProvider.ts +++ b/packages/provider.native/src/NativeProvider.ts @@ -19,7 +19,7 @@ export default class NativeProvider extends Provider { get FOR_NODE_TYPES () { return [ 1, 3 ] } get preemptive () { return true } - nodeHasBindings (node) { + nodeHasBindings (node : HTMLElement) { if (!node[NATIVE_BINDINGS]) { return false } return Object.keys(node[NATIVE_BINDINGS] || {}) .some(key => key.startsWith('ko-')) @@ -29,7 +29,7 @@ export default class NativeProvider extends Provider { * There can be only one preprocessor; when there are native bindings, * prevent re-entrance (and likely XSS) from the `{{ }}` provider. */ - preprocessNode (node) { + preprocessNode (node : HTMLElement) { return node[NATIVE_BINDINGS] ? node : null } @@ -47,7 +47,7 @@ export default class NativeProvider extends Provider { * Return as valueAccessor function all the entries matching `ko-*` * @param {HTMLElement} node */ - getBindingAccessors (node) { + getBindingAccessors (node : HTMLElement) { const bindings = Object.entries(node[NATIVE_BINDINGS] || {}) .filter(this.onlyBindings) if (!bindings.length) { return null } @@ -60,7 +60,7 @@ export default class NativeProvider extends Provider { * @param {string} name * @param {any} value */ - static addValueToNode (node, name, value) { + static addValueToNode (node : HTMLElement, name, value) { const obj = node[NATIVE_BINDINGS] || (node[NATIVE_BINDINGS] = {}) obj[name] = value } @@ -70,7 +70,7 @@ export default class NativeProvider extends Provider { * @param {HTMLElement} node * @return {object} the stored values */ - static getNodeValues (node) { + static getNodeValues (node : HTMLElement) { return node[NATIVE_BINDINGS] } } diff --git a/packages/provider/src/Provider.ts b/packages/provider/src/Provider.ts index c35cd7a8f..2ba18ae4e 100644 --- a/packages/provider/src/Provider.ts +++ b/packages/provider/src/Provider.ts @@ -27,8 +27,8 @@ export default class Provider { this.globals = globals } get preemptive () { return false } - nodeHasBindings (/* node */) {} - getBindingAccessors (/* node, context */) {} + nodeHasBindings (node) {} + getBindingAccessors (node, context) {} /** * Preprocess a given node. @@ -38,6 +38,10 @@ export default class Provider { preprocessNode (node) {} postProcess (/* node */) {} + bindingHandlers : BindingHandlerObject + globals : any | undefined + _overloadInstance : any | undefined + /** For legacy binding provider assignments to * ko.bindingProvider.instance = ... */ get instance () { return this._overloadInstance || this } @@ -86,6 +90,8 @@ export default class Provider { class LegacyProvider extends Provider { get FOR_NODE_TYPES () { return [1, 3, 8] } + providerObject : any + constructor (providerObject, parentProvider) { super() Object.assign(this, {providerObject}) @@ -105,7 +111,7 @@ class LegacyProvider extends Provider { : this.getBindingsAndMakeAccessors(node, context) } - nodeHasBindings (node) { + nodeHasBindings (node : HTMLElement) : boolean { return this.providerObject.nodeHasBindings(node) } diff --git a/packages/utils/src/object.ts b/packages/utils/src/object.ts index c5c0a777a..936c32cb3 100644 --- a/packages/utils/src/object.ts +++ b/packages/utils/src/object.ts @@ -35,7 +35,7 @@ export function objectForEach (obj, action) { } } -export function objectMap (source, mapping, thisArg) { +export function objectMap (source, mapping, thisArg? : any) { if (!source) { return source } if (arguments.length > 2) { mapping = mapping.bind(thisArg) } var target = {} diff --git a/packages/utils/src/options.ts b/packages/utils/src/options.ts index 5897f691b..0b6f2fe17 100644 --- a/packages/utils/src/options.ts +++ b/packages/utils/src/options.ts @@ -1,64 +1,71 @@ +declare var jQuery : any + + // // This becomes ko.options // -- // // This is the root 'options', which must be extended by others. +class OptionsClass { + [key: string]: any; + + deferUpdates: boolean = false -const options = { - deferUpdates: false, - - useOnlyNativeEvents: false, + useOnlyNativeEvents: boolean = false - protoProperty: '__ko_proto__', + protoProperty: string = '__ko_proto__' // Modify the default attribute from `data-bind`. - defaultBindingAttribute: 'data-bind', + defaultBindingAttribute: string = 'data-bind' // Enable/disable ', '') return memoization.parseMemoText(commentHtml) diff --git a/packages/utils/src/array.ts b/packages/utils/src/array.ts index 0ba64b735..1f5047c2f 100644 --- a/packages/utils/src/array.ts +++ b/packages/utils/src/array.ts @@ -22,7 +22,7 @@ export function arrayFirst (array, predicate, predicateOwner) { .find(predicate, predicateOwner) } -export function arrayMap (array = [], mapping, thisArg) { +export function arrayMap (array = [], mapping, thisArg?) { if (arguments.length > 2) { mapping = mapping.bind(thisArg) } return array === null ? [] : Array.from(array, mapping) } diff --git a/packages/utils/src/memoization.ts b/packages/utils/src/memoization.ts index 923b9ca77..dd4126a00 100644 --- a/packages/utils/src/memoization.ts +++ b/packages/utils/src/memoization.ts @@ -40,7 +40,7 @@ export function unmemoize (memoId, callbackParams) { } export function unmemoizeDomNodeAndDescendants (domNode, extraCallbackParamsArray) { - var memos = [] + var memos = new Array() findMemoNodes(domNode, memos) for (var i = 0, j = memos.length; i < j; i++) { var node = memos[i].domNode diff --git a/packages/utils/src/tasks.ts b/packages/utils/src/tasks.ts index f7c36f87b..cc4054530 100644 --- a/packages/utils/src/tasks.ts +++ b/packages/utils/src/tasks.ts @@ -6,7 +6,11 @@ import options from './options' import { deferError } from './error' -var taskQueue = [], +interface HTMLScriptElementOld extends HTMLScriptElement { + onreadystatechange: any; +} + +var taskQueue = new Array(), taskQueueLength = 0, nextHandle = 1, nextIndexToProcess = 0, @@ -24,11 +28,13 @@ if (w && w.MutationObserver && !(w.navigator && w.navigator.standalone)) { // IE 6-10 // From https://github.com/YuzuJS/setImmediate * Copyright (c) 2012 Barnesandnoble.com, llc, Donavon West, and Domenic Denicola * License: MIT options.taskScheduler = function (callback) { - var script = document.createElement('script') + var script : HTMLScriptElementOld | null = document.createElement('script') as HTMLScriptElementOld script.onreadystatechange = function () { - script.onreadystatechange = null - document.documentElement.removeChild(script) - script = null + if(script) { + script.onreadystatechange = null + document.documentElement.removeChild(script) + script = null + } callback() } document.documentElement.appendChild(script) @@ -69,7 +75,7 @@ function processTasks () { function scheduledProcess () { processTasks() - // Reset the queue + // Reset the queue nextIndexToProcess = taskQueueLength = taskQueue.length = 0 } diff --git a/tsconfig.json b/tsconfig.json index 10d73f7e2..0ac212306 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,11 +9,17 @@ "importHelpers": true, "strict": true, "baseUrl": ".", - "noImplicitAny": false, /*Disable some typing feature from ts to detect first steps to a strong typed version*/ + "noEmit": true, + /*Disable some typing feature from ts to detect first steps to a strong typed version*/ + "noImplicitAny": false, "noImplicitThis": false, "noImplicitOverride": false, "noImplicitReturns": false, "noUncheckedIndexedAccess": false, + "strictPropertyInitialization": false, + "strictBindCallApply": false, + "strictFunctionTypes": false, + /* END Disabling */ "paths": { "@tko/utils/helpers/jasmine-13-helper": [ "packages/utils/helpers/jasmine-13-helper.ts" @@ -32,6 +38,6 @@ "node_modules", "builds", "docs", - "packages/**/dist/*" + "tools" ] } From 2b994e401e9a6d8dc73ea7abd445686c37e70248 Mon Sep 17 00:00:00 2001 From: phillipc Date: Thu, 2 Jan 2025 11:12:56 +0100 Subject: [PATCH 003/190] add some global types switch d.ts-version for jasmine (the project used jasmine 1.3) --- global.d.ts | 31 +++++++++++++++++++ package.json | 3 +- .../spec/componentBindingBehaviors.ts | 1 - packages/binding.foreach/spec/eachBehavior.ts | 2 ++ packages/provider/src/BindingHandlerObject.ts | 2 +- packages/utils.parser/spec/parserBehaviors.ts | 2 +- .../utils.parser/spec/preparserBehavior.ts | 1 + packages/utils/helpers/jasmine-13-helper.ts | 19 ++++++++---- packages/utils/src/dom/virtualElements.ts | 4 +-- packages/utils/src/ie.ts | 2 +- 10 files changed, 54 insertions(+), 13 deletions(-) create mode 100644 global.d.ts diff --git a/global.d.ts b/global.d.ts new file mode 100644 index 000000000..27da0213d --- /dev/null +++ b/global.d.ts @@ -0,0 +1,31 @@ +export { }; + +declare global { + + var testNode: HTMLElement; + + interface Window { + // Below just informs IDE and/or TS-compiler (it's set in `.js` file). + DEBUG: boolean + amdRequire: any + require: any + jQuery: JQuery + jQueryInstance: JQuery + } + + //Jasmine and Mocha define duplicated functions, is a problem for the type system + //This namespace merges the jasmine namespace to correct same tsc warnings + namespace jasmine { + var updateInterval: number + function resolve(promise: Promise) + function prepareTestNode() + function nodeText(node) + var Clock: Clock + function getEnv(): any; + + var FakeTimer: any + var undefined: undefined + var browserSupportsProtoAssignment: any + var ieVersion: any + } +} \ No newline at end of file diff --git a/package.json b/package.json index 62494b4f8..09cca0d3b 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,8 @@ ] }, "devDependencies": { - "@types/jasmine": "^3.10.18", + "@types/jasmine": "^1.3.7", + "@types/jquery": "^3.5.32", "@types/mocha": "^10.0.10", "chai": "^4.5.0", "electron": "^33.2.1", diff --git a/packages/binding.component/spec/componentBindingBehaviors.ts b/packages/binding.component/spec/componentBindingBehaviors.ts index 3953d0c84..27c8074ee 100644 --- a/packages/binding.component/spec/componentBindingBehaviors.ts +++ b/packages/binding.component/spec/componentBindingBehaviors.ts @@ -43,7 +43,6 @@ import { useMockForTasks } from '@tko/utils/helpers/jasmine-13-helper' -declare var testNode : HTMLElement describe('Components: Component binding', function () { var testComponentName = 'test-component', diff --git a/packages/binding.foreach/spec/eachBehavior.ts b/packages/binding.foreach/spec/eachBehavior.ts index 0410c3608..90d5667e2 100644 --- a/packages/binding.foreach/spec/eachBehavior.ts +++ b/packages/binding.foreach/spec/eachBehavior.ts @@ -34,6 +34,8 @@ import { import $ from 'jquery' +import { assert } from "chai" + beforeEach(function () { var provider = new MultiProvider({ providers: [new DataBindProvider(), new VirtualProvider()] diff --git a/packages/provider/src/BindingHandlerObject.ts b/packages/provider/src/BindingHandlerObject.ts index 12d97a04d..edfdc230c 100644 --- a/packages/provider/src/BindingHandlerObject.ts +++ b/packages/provider/src/BindingHandlerObject.ts @@ -4,7 +4,7 @@ import { } from '@tko/utils' export default class BindingHandlerObject { - set (nameOrObject, value) { + set (nameOrObject, value?) { if (typeof nameOrObject === 'string') { this[nameOrObject] = value } else if (typeof nameOrObject === 'object') { diff --git a/packages/utils.parser/spec/parserBehaviors.ts b/packages/utils.parser/spec/parserBehaviors.ts index fa2982c8d..3c2977977 100644 --- a/packages/utils.parser/spec/parserBehaviors.ts +++ b/packages/utils.parser/spec/parserBehaviors.ts @@ -24,7 +24,7 @@ import { Parser } from '../dist'; -import { assert} from "chai" +import { assert } from "chai" function ctxStub (ctx?) { return { diff --git a/packages/utils.parser/spec/preparserBehavior.ts b/packages/utils.parser/spec/preparserBehavior.ts index 72e80b1a7..43375e22a 100644 --- a/packages/utils.parser/spec/preparserBehavior.ts +++ b/packages/utils.parser/spec/preparserBehavior.ts @@ -4,6 +4,7 @@ import { } from '@tko/provider.databind' import parseObjectLiteral from '../dist/preparse' +import {expect} from "chai" describe('Expression Rewriting', function () { var preProcessBindings diff --git a/packages/utils/helpers/jasmine-13-helper.ts b/packages/utils/helpers/jasmine-13-helper.ts index 0c34cbae9..289e8ff2b 100644 --- a/packages/utils/helpers/jasmine-13-helper.ts +++ b/packages/utils/helpers/jasmine-13-helper.ts @@ -1,8 +1,14 @@ +/// +/// + + /* * Configure the Jasmine testing framework. */ /* globals runs, waitsFor, jasmine */ + + import { arrayMap, arrayFilter, ieVersion, selectExtensions, hasOwnProperty } from '../dist/' @@ -15,13 +21,14 @@ window.amdRequire = window.require; // window.jQuery with 'undefined' on IE < 9 window.jQueryInstance = window.jQuery; -// export var testNode; + +//export var testNode; jasmine.updateInterval = 500; /* Some helper functions for jasmine on the browser */ -jasmine.resolve = function (promise) { +jasmine.resolve = function (promise : Promise) { let complete = false runs(() => promise.then((result) => { complete = result || true })) waitsFor(() => complete) @@ -31,7 +38,7 @@ jasmine.prepareTestNode = function() { // The bindings specs make frequent use of this utility function to set up // a clean new DOM node they can execute code against var existingNode = document.getElementById("testNode"); - if (existingNode !== null) + if (existingNode !== null && existingNode.parentNode) existingNode.parentNode.removeChild(existingNode); window.testNode = document.createElement("div"); window.testNode.id = "testNode"; @@ -90,7 +97,7 @@ var matchers = { }, toHaveOwnProperties (expectedProperties) { - var ownProperties = []; + var ownProperties = new Array(); for (var prop in this.actual) { if (hasOwnProperty(this.actual, prop)) { ownProperties.push(prop); @@ -168,7 +175,7 @@ var matchers = { // jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) { var scheduledFunc; - var funcsToRun = []; + var funcsToRun = new Array(); for (var timeoutKey in this.scheduledFunctions) { scheduledFunc = this.scheduledFunctions[timeoutKey]; if (scheduledFunc != jasmine.undefined && @@ -180,7 +187,7 @@ jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMil } if (funcsToRun.length > 0) { - funcsToRun.sort(function(a, b) { + funcsToRun.sort(function(a : any, b : any) { return a.runAtMillis - b.runAtMillis; }); diff --git a/packages/utils/src/dom/virtualElements.ts b/packages/utils/src/dom/virtualElements.ts index 96d250ad8..83c3b411d 100644 --- a/packages/utils/src/dom/virtualElements.ts +++ b/packages/utils/src/dom/virtualElements.ts @@ -20,7 +20,7 @@ import { tagNameLower } from './info' import * as domData from './data' import options from '../options' -var commentNodesHaveTextProperty = options.document && options.document.createComment('test').text === '' +var commentNodesHaveTextProperty = options.document && options.document.createComment('test').textContent === '' export var startCommentRegex = commentNodesHaveTextProperty ? /^$/ : /^\s*ko(?:\s+([\s\S]+))?\s*$/ export var endCommentRegex = commentNodesHaveTextProperty ? /^$/ : /^\s*\/ko\s*$/ @@ -43,7 +43,7 @@ const matchedEndCommentDataKey = '__ko_matchedEndComment__' export function getVirtualChildren (startComment, allowUnbalanced) { var currentNode = startComment var depth = 1 - var children = [] + var children = new Array() while (currentNode = currentNode.nextSibling) { if (isEndComment(currentNode)) { domData.set(currentNode, matchedEndCommentDataKey, true) diff --git a/packages/utils/src/ie.ts b/packages/utils/src/ie.ts index 0616909f8..5ed6b0954 100644 --- a/packages/utils/src/ie.ts +++ b/packages/utils/src/ie.ts @@ -15,7 +15,7 @@ const ieVersion = options.document && (function () { if (!version) { const userAgent = window.navigator.userAgent // Detect IE 10/11 - return ua.match(/MSIE ([^ ]+)/) || ua.match(/rv:([^ )]+)/) + return userAgent.match(/MSIE ([^ ]+)/) || userAgent.match(/rv:([^ )]+)/) } return version > 4 ? version : undefined }()) From 2b40fa02385902bbee7e27cae7143c9624344212 Mon Sep 17 00:00:00 2001 From: phillipc Date: Thu, 2 Jan 2025 16:21:09 +0100 Subject: [PATCH 004/190] fix: check text/textcontent for comments / add test --- packages/utils/spec/utilsDomBehaviors.ts | 13 +++++++++++-- packages/utils/src/dom/virtualElements.ts | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/utils/spec/utilsDomBehaviors.ts b/packages/utils/spec/utilsDomBehaviors.ts index 71b5dd229..27362c26e 100644 --- a/packages/utils/spec/utilsDomBehaviors.ts +++ b/packages/utils/spec/utilsDomBehaviors.ts @@ -1,13 +1,22 @@ import '../helpers/jasmine-13-helper' import * as utils from '../dist' -import { registerEventHandler } from '../dist' +import { registerEventHandler, virtualElements } from '../dist' import options from '../dist/options' var ko = ko || {} ko.utils = utils ko.options = options +describe('startCommentRegex', function () { + + it('only ie8 has a text property at comment nodes', function () { + const reg : RegExp = virtualElements.startCommentRegex + expect(reg.source).not.toContain('' +var commentNodesHaveTextProperty = options.document && ("text" in options.document.createComment('test')) //in case of IE8.. export var startCommentRegex = commentNodesHaveTextProperty ? /^$/ : /^\s*ko(?:\s+([\s\S]+))?\s*$/ export var endCommentRegex = commentNodesHaveTextProperty ? /^$/ : /^\s*\/ko\s*$/ From f10540604bbec10c64d77c023c519fdad4763aee Mon Sep 17 00:00:00 2001 From: phillipc Date: Fri, 3 Jan 2025 09:45:59 +0100 Subject: [PATCH 005/190] fix some typescript warnings --- global.d.ts | 16 ++++++++++++++ .../spec/componentBindingBehaviors.ts | 2 ++ packages/computed/spec/asyncBehaviors.ts | 4 ++-- .../spec/customElementBehaviors.ts | 4 ++-- packages/utils/spec/taskBehaviors.ts | 22 +++++++++---------- 5 files changed, 33 insertions(+), 15 deletions(-) diff --git a/global.d.ts b/global.d.ts index 27da0213d..26f3500f7 100644 --- a/global.d.ts +++ b/global.d.ts @@ -1,8 +1,13 @@ +/// +/// + + export { }; declare global { var testNode: HTMLElement; + var jQueryInstance : JQuery interface Window { // Below just informs IDE and/or TS-compiler (it's set in `.js` file). @@ -27,5 +32,16 @@ declare global { var undefined: undefined var browserSupportsProtoAssignment: any var ieVersion: any + + interface Matchers { + + toContainText(expected: string, ignoreSpaces: boolean) : boolean; + toHaveOwnProperties(expectedProperties : any) : boolean; + toThrowContaining(expected : any): boolean; + } + + interface Spy { + reset() : any + } } } \ No newline at end of file diff --git a/packages/binding.component/spec/componentBindingBehaviors.ts b/packages/binding.component/spec/componentBindingBehaviors.ts index 27c8074ee..9b7fbaab4 100644 --- a/packages/binding.component/spec/componentBindingBehaviors.ts +++ b/packages/binding.component/spec/componentBindingBehaviors.ts @@ -44,6 +44,8 @@ import { } from '@tko/utils/helpers/jasmine-13-helper' + + describe('Components: Component binding', function () { var testComponentName = 'test-component', testComponentBindingValue, diff --git a/packages/computed/spec/asyncBehaviors.ts b/packages/computed/spec/asyncBehaviors.ts index 9a5e438f3..8eba3dbd5 100644 --- a/packages/computed/spec/asyncBehaviors.ts +++ b/packages/computed/spec/asyncBehaviors.ts @@ -96,7 +96,7 @@ describe('Throttled dependent observables', function () { // Now wait for throttle timeout waitsFor(function () { return notifiedValues.length > 0 - }, 300) + }, "Timeout", 300) runs(function () { expect(asyncDepObs()).toEqual('New value') expect(notifiedValues.length).toEqual(1) @@ -131,7 +131,7 @@ describe('Throttled dependent observables', function () { // Now wait for throttle timeout waitsFor(function () { return evaluationCount > 1 - }, 300) + }, "Timeout", 300) runs(function () { expect(evaluationCount).toEqual(2) // Finally, it's evaluated expect(asyncDepObs()).toEqual('D') diff --git a/packages/provider.component/spec/customElementBehaviors.ts b/packages/provider.component/spec/customElementBehaviors.ts index ca247b37e..1030f2fab 100644 --- a/packages/provider.component/spec/customElementBehaviors.ts +++ b/packages/provider.component/spec/customElementBehaviors.ts @@ -196,7 +196,7 @@ describe('Components: Custom elements', function () { }) it('Is possible to pass literal values', function () { - var suppliedParams = [] + var suppliedParams = new Array() components.register('test-component', { template: 'Ignored', viewModel: function (params) { @@ -221,7 +221,7 @@ describe('Components: Custom elements', function () { }) it('Supplies an empty params object (with empty $raw) if a custom element has no params attribute', function () { - var suppliedParams = [] + var suppliedParams = new Array components.register('test-component', { template: 'Ignored', viewModel: function (params) { suppliedParams.push(params) } diff --git a/packages/utils/spec/taskBehaviors.ts b/packages/utils/spec/taskBehaviors.ts index e18182904..26e7c73c6 100644 --- a/packages/utils/spec/taskBehaviors.ts +++ b/packages/utils/spec/taskBehaviors.ts @@ -38,7 +38,7 @@ describe('Tasks', function () { }) it('Should run scheduled tasks in the order they were scheduled', function () { - var runValues = [] + var runValues : any = [] var func = function (value) { runValues.push(value) } @@ -69,7 +69,7 @@ describe('Tasks', function () { }) it('Should process newly scheduled tasks during task processing', function () { - var runValues = [] + var runValues = new Array var func = function (value) { runValues.push(value) tasks.schedule(function () { @@ -85,7 +85,7 @@ describe('Tasks', function () { }) it('Should keep correct state if a task throws an exception', function () { - var runValues = [] + var runValues = new Array var func = function (value) { runValues.push(value) } @@ -104,7 +104,7 @@ describe('Tasks', function () { }) it('Should stop recursive task processing after a fixed number of iterations', function () { - var runValues = [] + var runValues = new Array var func = function () { runValues.push('x') tasks.schedule(function () {}) @@ -123,7 +123,7 @@ describe('Tasks', function () { }) it('Should not stop non-recursive task processing', function () { - var runValues = [] + var runValues = new Array var func = function () { runValues.push('x') } @@ -163,7 +163,7 @@ describe('Tasks', function () { }) it('Should do nothing if task has already run', function () { - var runValues = [] + var runValues = new Array var func = function (value) { runValues.push(value) } @@ -184,7 +184,7 @@ describe('Tasks', function () { }) it('Should work correctly after a task throws an exception', function () { - var runValues = [], handle + var runValues = new Array, handle var func = function (value) { runValues.push(value) } @@ -210,7 +210,7 @@ describe('Tasks', function () { describe('runEarly', function () { it('Should run tasks early', function () { - var runValues = [] + var runValues = new Array var func = function (value) { runValues.push(value) } @@ -225,7 +225,7 @@ describe('Tasks', function () { }) it('Should run tasks early during task processing', function () { - var runValues = [] + var runValues = new Array var func = function (value) { runValues.push(value) } @@ -248,7 +248,7 @@ describe('Tasks', function () { }) it('Should stop recursive task processing after a fixed number of iterations', function () { - var runValues = [] + var runValues = new Array var func = function () { runValues.push('x') tasks.schedule(function () {}) @@ -271,7 +271,7 @@ describe('Tasks', function () { }) it('Should keep correct state if a task throws an exception', function () { - var runValues = [] + var runValues = new Array var func = function (value) { runValues.push(value) } From 11fd46eb8f2e5c9d76ebad0e9f0a684fd2cd1854 Mon Sep 17 00:00:00 2001 From: phillipc Date: Fri, 3 Jan 2025 12:34:11 +0100 Subject: [PATCH 006/190] fix some types: 1) [] => new Array 2) childNodes => children 3) extend some global type-defs --- Makefile | 3 + global.d.ts | 12 +- .../spec/arrayToDomEditDetectionBehaviors.ts | 26 ++-- .../bind/spec/bindingAttributeBehaviors.ts | 58 ++++---- .../bind/spec/bindingDependencyBehaviors.ts | 38 ++--- packages/bind/src/applyBindings.ts | 4 +- packages/bind/src/arrayToDomNodeChildren.ts | 14 +- packages/bind/src/bindingContext.ts | 2 +- .../spec/componentBindingBehaviors.ts | 102 ++++++------- packages/binding.core/spec/attrBehaviors.ts | 43 +++--- .../binding.core/spec/checkedBehaviors.ts | 136 ++++++++++-------- packages/binding.core/spec/cssBehaviors.ts | 52 +++---- .../spec/enableDisableBehaviors.ts | 19 ++- packages/binding.core/spec/htmlBehaviors.ts | 16 +-- .../spec/selectedOptionsBehaviors.ts | 2 +- packages/binding.core/spec/styleBehaviors.ts | 38 ++--- .../binding.core/spec/textInputBehaviors.ts | 136 +++++++++--------- packages/binding.core/src/options.ts | 2 +- packages/binding.core/src/selectedOptions.ts | 2 +- packages/binding.foreach/spec/eachBehavior.ts | 6 +- packages/binding.foreach/src/foreach.ts | 20 +-- .../src/ConditionalBindingHandler.ts | 4 +- .../binding.template/spec/foreachBehaviors.ts | 8 +- packages/computed/spec/asyncBehaviors.ts | 14 +- .../spec/computedObservableBehaviors.ts | 6 +- .../computed/spec/pureComputedBehaviors.ts | 8 +- packages/computed/src/computed.ts | 4 +- packages/lifecycle/src/LifeCycle.ts | 2 +- .../spec/observableArrayBehaviors.ts | 32 ++--- .../observableArrayChangeTrackingBehaviors.ts | 4 +- .../observable/spec/observableBehaviors.ts | 26 ++-- .../observable/spec/subscribableBehaviors.ts | 2 +- .../observable/src/dependencyDetection.ts | 2 +- .../src/observableArray.changeTracking.ts | 8 +- packages/observable/src/observableArray.ts | 2 +- packages/observable/src/subscribable.ts | 2 +- .../src/BindingStringProvider.ts | 2 +- .../spec/customElementBehaviors.ts | 2 +- packages/provider.multi/src/MultiProvider.ts | 6 +- .../spec/defaultLoaderBehaviors.ts | 2 +- .../spec/loaderRegistryBehaviors.ts | 8 +- packages/utils.jsx/spec/jsxBehaviors.ts | 16 +-- packages/utils.jsx/src/JsxObserver.ts | 8 +- packages/utils.jsx/src/jsxClean.ts | 2 +- .../utils.parser/spec/identifierBehaviors.ts | 4 +- .../utils.parser/spec/namespaceBehaviors.ts | 14 +- packages/utils.parser/src/Arguments.ts | 2 +- packages/utils.parser/src/Node.ts | 4 +- packages/utils.parser/src/Parameters.ts | 2 +- packages/utils.parser/src/Parser.ts | 10 +- packages/utils.parser/src/preparse.ts | 6 +- packages/utils/spec/taskBehaviors.ts | 2 +- packages/utils/spec/utilsBehaviors.ts | 2 +- packages/utils/src/array.ts | 12 +- packages/utils/src/dom/disposal.ts | 8 +- packages/utils/src/dom/manipulation.ts | 2 +- packages/utils/src/object.ts | 2 +- packages/utils/src/options.ts | 2 +- 58 files changed, 507 insertions(+), 466 deletions(-) diff --git a/Makefile b/Makefile index 0567498cf..64e11e283 100644 --- a/Makefile +++ b/Makefile @@ -32,6 +32,9 @@ ci: lint: $(NPX) standard +tsc: + $(NPX) tsc + docker-build: $(DOCKER) build . --tag tko diff --git a/global.d.ts b/global.d.ts index 26f3500f7..5e45346f0 100644 --- a/global.d.ts +++ b/global.d.ts @@ -35,9 +35,15 @@ declare global { interface Matchers { - toContainText(expected: string, ignoreSpaces: boolean) : boolean; - toHaveOwnProperties(expectedProperties : any) : boolean; - toThrowContaining(expected : any): boolean; + toContainText(expected: string, ignoreSpaces: boolean) : boolean + toHaveOwnProperties(expectedProperties : any) : boolean + toHaveTexts (expectedTexts : any) : boolean + toHaveValues (expectedValues : any) : boolean + toHaveCheckedStates (expectedValues : any) : boolean + toThrowContaining(expected : any) : boolean + toEqualOneOf (expectedPossibilities : any) : boolean + toContainHtml (expectedHtml : any, postProcessCleanedHtml : any) : boolean + toHaveSelectedValues(expectedValues : any) : boolean } interface Spy { diff --git a/packages/bind/spec/arrayToDomEditDetectionBehaviors.ts b/packages/bind/spec/arrayToDomEditDetectionBehaviors.ts index fd8f9ba3d..7f243deac 100644 --- a/packages/bind/spec/arrayToDomEditDetectionBehaviors.ts +++ b/packages/bind/spec/arrayToDomEditDetectionBehaviors.ts @@ -52,7 +52,7 @@ describe('Array to DOM node children mapping', function () { setDomNodeChildrenFromArrayMapping(testNode, ['A', 'B'], mapping) expect(mappingInvocations).toEqual(['A', 'B']) - mappingInvocations = [] + mappingInvocations = new Array() setDomNodeChildrenFromArrayMapping(testNode, ['A', 'A2', 'B'], mapping) expect(mappingInvocations).toEqual(['A2']) }) @@ -77,7 +77,7 @@ describe('Array to DOM node children mapping', function () { }) it('Should insert added nodes at the corresponding place in the DOM', function () { - var mappingInvocations = [] + var mappingInvocations = new Array() var mapping = function (arrayItem) { mappingInvocations.push(arrayItem) var output = document.createElement('DIV') @@ -89,14 +89,14 @@ describe('Array to DOM node children mapping', function () { expect(arrayMap(testNode.childNodes, function (x) { return x.innerHTML })).toEqual(['A', 'B']) expect(mappingInvocations).toEqual(['A', 'B']) - mappingInvocations = [] + mappingInvocations = new Array() setDomNodeChildrenFromArrayMapping(testNode, ['first', 'A', 'middle1', 'middle2', 'B', 'last'], mapping) expect(arrayMap(testNode.childNodes, function (x) { return x.innerHTML })).toEqual(['first', 'A', 'middle1', 'middle2', 'B', 'last']) expect(mappingInvocations).toEqual(['first', 'middle1', 'middle2', 'last']) }) it('Should remove deleted nodes from the DOM', function () { - var mappingInvocations = [] + var mappingInvocations = new Array() var mapping = function (arrayItem) { mappingInvocations.push(arrayItem) var output = document.createElement('DIV') @@ -108,7 +108,7 @@ describe('Array to DOM node children mapping', function () { expect(arrayMap(testNode.childNodes, function (x) { return x.innerHTML })).toEqual(['first', 'A', 'middle1', 'middle2', 'B', 'last']) expect(mappingInvocations).toEqual(['first', 'A', 'middle1', 'middle2', 'B', 'last']) - mappingInvocations = [] + mappingInvocations = new Array() setDomNodeChildrenFromArrayMapping(testNode, ['A', 'B'], mapping) expect(arrayMap(testNode.childNodes, function (x) { return x.innerHTML })).toEqual(['A', 'B']) expect(mappingInvocations).toEqual([]) @@ -117,7 +117,7 @@ describe('Array to DOM node children mapping', function () { it('Should tolerate DOM nodes being removed manually, before the corresponding array entry is removed', function () { // Represents https://github.com/SteveSanderson/knockout/issues/413 // Ideally, people wouldn't be mutating the generated DOM manually. But this didn't error in v2.0, so we should try to avoid introducing a break. - var mappingInvocations = [] + var mappingInvocations = new Array() var mapping = function (arrayItem) { mappingInvocations.push(arrayItem) var output = document.createElement('DIV') @@ -139,7 +139,7 @@ describe('Array to DOM node children mapping', function () { }) it('Should handle sequences of mixed insertions and deletions', function () { - var mappingInvocations = [], countCallbackInvocations = 0 + var mappingInvocations = new Array(), countCallbackInvocations = 0 var mapping = function (arrayItem) { mappingInvocations.push(arrayItem) var output = document.createElement('DIV') @@ -156,19 +156,19 @@ describe('Array to DOM node children mapping', function () { expect(mappingInvocations).toEqual(['A']) expect(countCallbackInvocations).toEqual(mappingInvocations.length) - mappingInvocations = [], countCallbackInvocations = 0 + mappingInvocations = new Array(), countCallbackInvocations = 0 setDomNodeChildrenFromArrayMapping(testNode, ['B'], mapping, null, callback) // Delete and replace single item expect(arrayMap(testNode.childNodes, function (x) { return x.innerHTML })).toEqual(['B']) expect(mappingInvocations).toEqual(['B']) expect(countCallbackInvocations).toEqual(mappingInvocations.length) - mappingInvocations = [], countCallbackInvocations = 0 + mappingInvocations = new Array(), countCallbackInvocations = 0 setDomNodeChildrenFromArrayMapping(testNode, ['A', 'B', 'C'], mapping, null, callback) // Add at beginning and end expect(arrayMap(testNode.childNodes, function (x) { return x.innerHTML })).toEqual(['A', 'B', 'C']) expect(mappingInvocations).toEqual(['A', 'C']) expect(countCallbackInvocations).toEqual(mappingInvocations.length) - mappingInvocations = [], countCallbackInvocations = 0 + mappingInvocations = new Array(), countCallbackInvocations = 0 setDomNodeChildrenFromArrayMapping(testNode, ['C', 'B', 'A'], mapping, null, callback) // Move items expect(arrayMap(testNode.childNodes, function (x) { return x.innerHTML })).toEqual(['C', 'B', 'A']) expect(mappingInvocations).toEqual([]) @@ -176,7 +176,7 @@ describe('Array to DOM node children mapping', function () { // Check that observable items can be added and unwrapped in the mapping function and will update the DOM. // Also check that observables accessed in the callback function do not update the DOM. - mappingInvocations = [], countCallbackInvocations = 0 + mappingInvocations = new Array(), countCallbackInvocations = 0 var observable = Observable(1), callbackObservable = Observable(1) var callback2 = function (arrayItem, nodes) { callbackObservable() @@ -188,14 +188,14 @@ describe('Array to DOM node children mapping', function () { expect(countCallbackInvocations).toEqual(mappingInvocations.length) // Change the value of the mapped observable and verify that the DOM is updated - mappingInvocations = [], countCallbackInvocations = 0 + mappingInvocations = new Array(), countCallbackInvocations = 0 observable(2) expect(arrayMap(testNode.childNodes, function (x) { return x.innerHTML })).toEqual(['2', 'null', 'B']) expect(mappingInvocations).toEqual([observable]) expect(countCallbackInvocations).toEqual(mappingInvocations.length) // Change the value of the callback observable and verify that the DOM wasn't updated - mappingInvocations = [], countCallbackInvocations = 0 + mappingInvocations = new Array(), countCallbackInvocations = 0 callbackObservable(2) expect(mappingInvocations.length).toEqual(0) expect(countCallbackInvocations).toEqual(0) diff --git a/packages/bind/spec/bindingAttributeBehaviors.ts b/packages/bind/spec/bindingAttributeBehaviors.ts index 67c641334..57e266da2 100644 --- a/packages/bind/spec/bindingAttributeBehaviors.ts +++ b/packages/bind/spec/bindingAttributeBehaviors.ts @@ -286,7 +286,7 @@ describe('Binding attribute syntax', function () { }) it('Should invoke registered handlers\'s init() then update() methods passing binding data', function () { - var methodsInvoked = [] + var methodsInvoked = new Array() bindingHandlers.test = { init: function (element, valueAccessor, allBindings) { methodsInvoked.push('init') @@ -309,7 +309,7 @@ describe('Binding attribute syntax', function () { }) it('Should invoke each handlers\'s init() and update() before running the next one', function () { - var methodsInvoked = [] + var methodsInvoked = new Array() bindingHandlers.test1 = bindingHandlers.test2 = { init: function (element, valueAccessor) { methodsInvoked.push('init' + valueAccessor()) @@ -351,8 +351,8 @@ describe('Binding attribute syntax', function () { "
456
" applyBindings(null, testNode) - expect(testNode.childNodes[0].childNodes[0].innerHTML).toEqual('456') - expect(testNode.childNodes[1].innerHTML).toEqual('123') + expect(testNode.children[0].children[0].innerHTML).toEqual('456') + expect(testNode.children[1].innerHTML).toEqual('123') }) it('Should not be allowed to have multiple bindings on the same element that claim to control descendant bindings', function () { @@ -386,12 +386,12 @@ describe('Binding attribute syntax', function () { var vm = { sub: {} } applyBindings(vm, testNode) expect(testNode).toContainText('my value') - expect(contextFor(testNode.childNodes[0].childNodes[0].childNodes[0]).$customProp).toEqual('my value') - expect(contextFor(testNode.childNodes[0].childNodes[0]).$customProp).toBeUndefined() // Should not affect original binding context + expect(contextFor(testNode.children[0].children[0].children[0]).$customProp).toEqual('my value') + expect(contextFor(testNode.children[0].children[0]).$customProp).toBeUndefined() // Should not affect original binding context // value of $data and $parent should be unchanged in extended context - expect(contextFor(testNode.childNodes[0].childNodes[0].childNodes[0]).$data).toEqual(vm.sub) - expect(contextFor(testNode.childNodes[0].childNodes[0].childNodes[0]).$parent).toEqual(vm) + expect(contextFor(testNode.children[0].children[0].children[0]).$data).toEqual(vm.sub) + expect(contextFor(testNode.children[0].children[0].children[0]).$parent).toEqual(vm) }) it('Binding contexts should inherit any custom properties from ancestor binding contexts', function () { @@ -414,27 +414,27 @@ describe('Binding attribute syntax', function () { if (typeof Symbol('') !== 'symbol') { // Test for shim allowedProperties.push('_subscribable') } - objectForEach(contextFor(testNode.childNodes[0].childNodes[0]), + objectForEach(contextFor(testNode.children[0].children[0]), (prop) => expect(allowedProperties).toContain(prop)) }) it('Should be able to retrieve the binding context associated with any node', function () { testNode.innerHTML = "
" - applyBindings({ name: 'Bert' }, testNode.childNodes[0]) + applyBindings({ name: 'Bert' }, testNode.children[0]) - expect(testNode.childNodes[0].childNodes[0]).toContainText('Bert') + expect(testNode.children[0].children[0]).toContainText('Bert') // Can't get binding context for unbound nodes expect(dataFor(testNode)).toBeUndefined() expect(contextFor(testNode)).toBeUndefined() // Can get binding context for directly bound nodes - expect(dataFor(testNode.childNodes[0]).name).toEqual('Bert') - expect(contextFor(testNode.childNodes[0]).$data.name).toEqual('Bert') + expect(dataFor(testNode.children[0]).name).toEqual('Bert') + expect(contextFor(testNode.children[0]).$data.name).toEqual('Bert') // Can get binding context for descendants of directly bound nodes - expect(dataFor(testNode.childNodes[0].childNodes[0]).name).toEqual('Bert') - expect(contextFor(testNode.childNodes[0].childNodes[0]).$data.name).toEqual('Bert') + expect(dataFor(testNode.children[0].children[0]).name).toEqual('Bert') + expect(contextFor(testNode.children[0].children[0]).$data.name).toEqual('Bert') // Also test that a non-node object returns nothing and doesn't crash expect(dataFor({})).toBeUndefined() @@ -456,14 +456,14 @@ describe('Binding attribute syntax', function () { applyBindings(vm, testNode) // All of the bound nodes return the viewmodel - expect(dataFor(testNode.childNodes[0])).toBe(vm) - expect(dataFor(testNode.childNodes[0].childNodes[0])).toBe(vm) - expect(dataFor(testNode.childNodes[0].childNodes[1])).toBe(vm) - expect(contextFor(testNode.childNodes[0].childNodes[1]).$data).toBe(vm) + expect(dataFor(testNode.children[0])).toBe(vm) + expect(dataFor(testNode.children[0].children[0])).toBe(vm) + expect(dataFor(testNode.children[0].children[1])).toBe(vm) + expect(contextFor(testNode.children[0].children[1]).$data).toBe(vm) // The unbound child node returns undefined - expect(dataFor(testNode.childNodes[0].childNodes[1].childNodes[0])).toBeUndefined() - expect(contextFor(testNode.childNodes[0].childNodes[1].childNodes[0])).toBeUndefined() + expect(dataFor(testNode.children[0].children[1].children[0])).toBeUndefined() + expect(contextFor(testNode.children[0].children[1].children[0])).toBeUndefined() }) it('Should return the context object for nodes specifically bound, but override with general binding', function () { @@ -471,16 +471,16 @@ describe('Binding attribute syntax', function () { testNode.innerHTML = '
' var vm1 = { name: 'specific' } - applyBindingsToNode(testNode.childNodes[0], { text: vm1.name }, vm1) + applyBindingsToNode(testNode.children[0], { text: vm1.name }, vm1) expect(testNode).toContainText(vm1.name) - expect(dataFor(testNode.childNodes[0])).toBe(vm1) - expect(contextFor(testNode.childNodes[0]).$data).toBe(vm1) + expect(dataFor(testNode.children[0])).toBe(vm1) + expect(contextFor(testNode.children[0]).$data).toBe(vm1) var vm2 = { name: 'general' } applyBindings(vm2, testNode) expect(testNode).toContainText(vm2.name) - expect(dataFor(testNode.childNodes[0])).toBe(vm2) - expect(contextFor(testNode.childNodes[0]).$data).toBe(vm2) + expect(dataFor(testNode.children[0])).toBe(vm2) + expect(contextFor(testNode.children[0]).$data).toBe(vm2) }) it('Should not be allowed to use containerless binding syntax for bindings other than whitelisted ones', function () { @@ -715,8 +715,8 @@ describe('Binding attribute syntax', function () { it(`Should allow delegation with applyBindingsToNode`, () => { testNode.innerHTML = `` - let read = false - let write = false + let read = 'false' + let write = 'false' bindingHandlers.myBinding = { init: function(element, valueAccessor, allBindings, data, context) { @@ -804,7 +804,7 @@ describe('Binding attribute syntax', function () { var callbacks = 0, callback = function (nodes, data) { expect(nodes.length).toEqual(1) - expect(nodes[0]).toEqual(testNode.childNodes[0].childNodes[0]) + expect(nodes[0]).toEqual(testNode.children[0].children[0]) expect(data).toEqual(vm) callbacks++ }, diff --git a/packages/bind/spec/bindingDependencyBehaviors.ts b/packages/bind/spec/bindingDependencyBehaviors.ts index 9944728c7..3b68aa2ac 100644 --- a/packages/bind/spec/bindingDependencyBehaviors.ts +++ b/packages/bind/spec/bindingDependencyBehaviors.ts @@ -47,7 +47,7 @@ describe('Binding dependencies', function () { it('If the binding handler depends on an observable, invokes the init handler once and the update handler whenever a new value is available', function () { var observable = new observableConstructor(); - var initPassedValues = [], updatePassedValues = []; + var initPassedValues = new Array(), updatePassedValues = new Array(); bindingHandlers.test = { init: function (element, valueAccessor) { initPassedValues.push(valueAccessor()()); }, update: function (element, valueAccessor) { updatePassedValues.push(valueAccessor()()); } @@ -91,7 +91,7 @@ describe('Binding dependencies', function () { expect(observable.getSubscriptionsCount()).toEqual(1); - testNode.parentNode.removeChild(testNode); + testNode.parentNode?.removeChild(testNode); observable('B'); // Force re-evaluation expect(observable.getSubscriptionsCount()).toEqual(0); @@ -99,7 +99,7 @@ describe('Binding dependencies', function () { it('If the binding attribute involves an observable, re-invokes the bindings if the observable notifies a change', function () { var observable = new observableConstructor({ message: 'hello' }); - var passedValues = []; + var passedValues = new Array(); bindingHandlers.test = { update: function (element, valueAccessor) { passedValues.push(valueAccessor()); } }; testNode.innerHTML = "
"; @@ -320,15 +320,15 @@ describe('Binding dependencies', function () { // Change the childprop which is not an observable so should not change the bound element vm.childprop = 'new child'; - expect(testNode.childNodes[0]).toContainText('child'); + expect(testNode.children[0]).toContainText('child'); // Update callback observable and check that the binding wasn't updated callbackObservable(2); - expect(testNode.childNodes[0]).toContainText('child'); + expect(testNode.children[0]).toContainText('child'); // Update the bound observable and verify that the binding is now updated bindingObservable(2); - expect(testNode.childNodes[0]).toContainText('new child'); + expect(testNode.children[0]).toContainText('new child'); expect(callbacks).toEqual(2); }); @@ -359,7 +359,7 @@ describe('Binding dependencies', function () { vm.callback = callbackSpy2; vm.observable('new value'); - expect(testNode.childNodes[0]).toContainText('new value'); + expect(testNode.children[0]).toContainText('new value'); expect(callbackSpy1).not.toHaveBeenCalled(); expect(callbackSpy2).toHaveBeenCalled(); }); @@ -375,26 +375,26 @@ describe('Binding dependencies', function () { applyBindings(vm, testNode); expect(vm.getSubscriptionsCount()).toEqual(1); - expect(testNode.childNodes[0].childNodes[0].value).toEqual('My prop value'); + expect(testNode.children[0].children[0].value).toEqual('My prop value'); // a change to the input value should be written to the model - testNode.childNodes[0].childNodes[0].value = 'some user-entered value'; - triggerEvent(testNode.childNodes[0].childNodes[0], 'change'); + testNode.children[0].children[0].value = 'some user-entered value'; + triggerEvent(testNode.children[0].children[0], 'change'); expect(vm().someProp).toEqual('some user-entered value'); // a click should use correct view model - triggerEvent(testNode.childNodes[0].childNodes[1], 'click'); + triggerEvent(testNode.children[0].children[1], 'click'); expect(clickedVM).toEqual(vm()); // set the view-model to a new object vm({ someProp: observableConstructor('My new prop value'), checkVM: checkVM }); - expect(testNode.childNodes[0].childNodes[0].value).toEqual('My new prop value'); + expect(testNode.children[0].children[0].value).toEqual('My new prop value'); // a change to the input value should be written to the new model - testNode.childNodes[0].childNodes[0].value = 'some new user-entered value'; - triggerEvent(testNode.childNodes[0].childNodes[0], 'change'); + testNode.children[0].children[0].value = 'some new user-entered value'; + triggerEvent(testNode.children[0].children[0], 'change'); expect(vm().someProp()).toEqual('some new user-entered value'); // a click should use correct view model - triggerEvent(testNode.childNodes[0].childNodes[1], 'click'); + triggerEvent(testNode.children[0].children[1], 'click'); expect(clickedVM).toEqual(vm()); // clear the element and the view-model (shouldn't be any errors) and the subscription should be cleared @@ -449,7 +449,7 @@ describe('Binding dependencies', function () { expect(vm.getSubscriptionsCount()).toEqual(1); // remove the element and re-set the view-model; the subscription should be cleared - testNode.parentNode.removeChild(testNode); + testNode.parentNode?.removeChild(testNode); vm(null); expect(vm.getSubscriptionsCount()).toEqual(0); }); @@ -527,7 +527,7 @@ describe('Binding dependencies', function () { expect(testNode).toContainText('vm1'); var parentContext = contextFor(testNode), - childContext = contextFor(testNode.childNodes[0].childNodes[0]); + childContext = contextFor(testNode.children[0].children[0]); expect(parentContext.$data).toEqual('vm1'); expect(parentContext.$rawData).toBe(vm1); @@ -577,7 +577,7 @@ describe('Binding dependencies', function () { describe('Order', function () { var bindingOrder; beforeEach(function () { - bindingOrder = []; + bindingOrder = new Array(); function makeBinding (name) { return { init: function () { bindingOrder.push(name); } }; @@ -625,7 +625,7 @@ describe('Binding dependencies', function () { bindingHandlers.test1.after = ['test3']; bindingHandlers.test2.after = ['test1']; bindingHandlers.test3.after = ['test4', 'test2']; - bindingHandlers.test4.after = []; + bindingHandlers.test4.after = new Array(); testNode.innerHTML = "
"; expect(function () { diff --git a/packages/bind/src/applyBindings.ts b/packages/bind/src/applyBindings.ts index 06c12c742..b966268f6 100644 --- a/packages/bind/src/applyBindings.ts +++ b/packages/bind/src/applyBindings.ts @@ -143,10 +143,10 @@ function applyBindingsToNodeAndDescendantsInternal (bindingContext, nodeVerified function * topologicalSortBindings (bindings, $component) { - const results = [] + const results = new Array() // Depth-first sort const bindingsConsidered = {} // A temporary record of which bindings are already in 'result' - const cyclicDependencyStack = [] // Keeps track of a depth-search so that, if there's a cycle, we know which bindings caused it + const cyclicDependencyStack = new Array() // Keeps track of a depth-search so that, if there's a cycle, we know which bindings caused it objectForEach(bindings, function pushBinding (bindingKey) { if (!bindingsConsidered[bindingKey]) { diff --git a/packages/bind/src/arrayToDomNodeChildren.ts b/packages/bind/src/arrayToDomNodeChildren.ts index 2a7de26cb..6f61e1cf9 100644 --- a/packages/bind/src/arrayToDomNodeChildren.ts +++ b/packages/bind/src/arrayToDomNodeChildren.ts @@ -23,7 +23,7 @@ import { computed } from '@tko/computed' function mapNodeAndRefreshWhenChanged (containerNode, mapping, valueToMap, callbackAfterAddingNodes, index) { // Map this array value inside a dependentObservable so we re-map when any dependency changes - var mappedNodes = [] + var mappedNodes = new Array() var dependentObservable = computed(function () { var newMappedNodes = mapping(valueToMap, index, fixUpContinuousNodeArray(mappedNodes, containerNode)) || [] @@ -55,15 +55,15 @@ export function setDomNodeChildrenFromArrayMapping (domNode, array, mapping, opt let isFirstExecution = !lastMappingResult // Build the new mapping result - var newMappingResult = [] + var newMappingResult = new Array() var lastMappingResultIndex = 0 var newMappingResultIndex = 0 - var nodesToDelete = [] - var itemsToProcess = [] - var itemsForBeforeRemoveCallbacks = [] - var itemsForMoveCallbacks = [] - var itemsForAfterAddCallbacks = [] + var nodesToDelete = new Array() + var itemsToProcess = new Array() + var itemsForBeforeRemoveCallbacks = new Array() + var itemsForMoveCallbacks = new Array() + var itemsForAfterAddCallbacks = new Array() var mapData let countWaitingForRemove = 0 diff --git a/packages/bind/src/bindingContext.ts b/packages/bind/src/bindingContext.ts index da2dc598a..3316596db 100644 --- a/packages/bind/src/bindingContext.ts +++ b/packages/bind/src/bindingContext.ts @@ -65,7 +65,7 @@ export function bindingContext (dataItemOrAccessor, parentContext, dataItemAlias self[contextAncestorBindingInfo] = parentContext[contextAncestorBindingInfo] } } else { - self.$parents = [] + self.$parents = new Array() self.$root = dataItem } diff --git a/packages/binding.component/spec/componentBindingBehaviors.ts b/packages/binding.component/spec/componentBindingBehaviors.ts index 9b7fbaab4..4852c9a17 100644 --- a/packages/binding.component/spec/componentBindingBehaviors.ts +++ b/packages/binding.component/spec/componentBindingBehaviors.ts @@ -124,8 +124,8 @@ describe('Components: Component binding', function () { testTemplate.appendChild(document.createElement('div')) testTemplate.appendChild(document.createTextNode(' ')) testTemplate.appendChild(document.createElement('span')) - testTemplate.childNodes[0].innerHTML = 'hello' - testTemplate.childNodes[2].innerHTML = 'world' + testTemplate.children[0].innerHTML = 'hello' + testTemplate.children[2-1].innerHTML = 'world' //-1 for skipping text node components.register(testComponentName, { template: testTemplate }) // Bind using just the component name since we're not setting any params @@ -133,10 +133,10 @@ describe('Components: Component binding', function () { // See the template asynchronously shows up jasmine.Clock.tick(1) - expect(testNode.childNodes[0]).toContainHtml('
hello
world') + expect(testNode.children[0]).toContainHtml('
hello
world') // Also be sure it's a clone - expect(testNode.childNodes[0].childNodes[0]).not.toBe(testTemplate[0]) + expect(testNode.children[0].children[0]).not.toBe(testTemplate[0]) }) it('Passes params and componentInfo (with prepopulated element and templateNodes) to the component\'s viewmodel factory', function () { @@ -156,7 +156,7 @@ describe('Components: Component binding', function () { expect(this.createViewModel).toBe(componentConfig.viewModel.createViewModel) expect(this.template).toBeDefined() - componentInfo.element.childNodes[0].setAttribute('data-bind', 'text: someValue') + componentInfo.element.children[0].setAttribute('data-bind', 'text: someValue') return { someValue: 'From the viewmodel' } } } @@ -176,7 +176,7 @@ describe('Components: Component binding', function () { applyBindings(outerViewModel, testNode) jasmine.Clock.tick(1) - expect(testNode.childNodes[0]).toContainHtml('
some parameter value
') + expect(testNode.children[0]).toContainHtml('
some parameter value
') }) it('Injects and binds the component synchronously if it is flagged as synchronous and loads synchronously', function () { @@ -188,7 +188,7 @@ describe('Components: Component binding', function () { // Notice the absence of any 'jasmine.Clock.tick' call here. This is synchronous. applyBindings(outerViewModel, testNode) - expect(testNode.childNodes[0]).toContainHtml('
123
') + expect(testNode.children[0]).toContainHtml('
123
') }) it('Injects and binds the component synchronously if it is flagged as synchronous and already cached, even if it previously loaded asynchronously', function () { @@ -218,14 +218,14 @@ describe('Components: Component binding', function () { // First injection is async, because the loader completes asynchronously applyBindings({ testList: testList }, testNode) - expect(testNode.childNodes[0]).toContainText('') + expect(testNode.children[0]).toContainText('') jasmine.Clock.tick(0) - expect(testNode.childNodes[0]).toContainText('first') + expect(testNode.children[0]).toContainText('first') // Second (cached) injection is synchronous, because the component config says so. // Notice the absence of any 'jasmine.Clock.tick' call here. This is synchronous. testList.push('second') - expect(testNode.childNodes[0]).toContainText('firstsecond', /* ignoreSpaces */ true) // Ignore spaces because old-IE is inconsistent + expect(testNode.children[0]).toContainText('firstsecond', /* ignoreSpaces */ true) // Ignore spaces because old-IE is inconsistent }) it('Creates a binding context with the correct parent', function () { @@ -235,7 +235,7 @@ describe('Components: Component binding', function () { applyBindings(outerViewModel, testNode) jasmine.Clock.tick(1) - expect(testNode.childNodes[0]).toContainText('Parent is outer view model: true') + expect(testNode.children[0]).toContainText('Parent is outer view model: true') }) it('Creates a binding context with $componentTemplateNodes giving the original child nodes', function () { @@ -246,7 +246,7 @@ describe('Components: Component binding', function () { applyBindings(outerViewModel, testNode) jasmine.Clock.tick(1) - expect(testNode.childNodes[0]).toContainHtml('startoriginal child nodesend') + expect(testNode.children[0]).toContainHtml('startoriginal child nodesend') }) it('Creates a binding context with $component to reference the closest component viewmodel', function () { @@ -272,12 +272,12 @@ describe('Components: Component binding', function () { applyBindings(outerViewModel, testNode) jasmine.Clock.tick(1) - expect(testNode.childNodes[0]).toContainText('In child context 123, inside component with property 456. Now in sub-component with property 789.', /* ignoreSpaces */ true) // Ignore spaces because old-IE is inconsistent + expect(testNode.children[0]).toContainText('In child context 123, inside component with property 456. Now in sub-component with property 789.', /* ignoreSpaces */ true) // Ignore spaces because old-IE is inconsistent }) it('Passes nonobservable params to the component', function () { // Set up a component that logs its constructor params - var receivedParams = [] + var receivedParams = new Array() components.register(testComponentName, { viewModel: function (params) { receivedParams.push(params) }, template: 'Ignored' @@ -295,7 +295,7 @@ describe('Components: Component binding', function () { it('Passes through observable params without unwrapping them (so a given component instance can observe them changing)', function () { // Set up a component that logs its constructor params - var receivedParams = [] + var receivedParams = new Array() components.register(testComponentName, { viewModel: function (params) { receivedParams.push(params) @@ -356,7 +356,8 @@ describe('Components: Component binding', function () { jasmine.Clock.tick(1) // See it appeared, and the expected subscriptions were registered - var firstAlphaTemplateNode = testNode.firstChild.firstChild, + expect(testNode.firstChild).not.toBeNull(); + var firstAlphaTemplateNode = testNode.firstChild?.firstChild as HTMLElement, alphaViewModelInstance = dataFor(firstAlphaTemplateNode) expect(firstAlphaTemplateNode.className).toBe('alpha') expect(testNode).toContainText('Alpha value is 123.') @@ -372,7 +373,8 @@ describe('Components: Component binding', function () { expect(testNode).toContainText('Alpha value is 234.') expect(testComponentBindingValue.name.getSubscriptionsCount()).toBe(1) expect(testComponentParams.suppliedValue.getSubscriptionsCount()).toBe(1) - expect(testNode.firstChild.firstChild).toBe(firstAlphaTemplateNode) // Same node + expect(testNode.firstChild).not.toBeNull(); + expect(testNode.firstChild?.firstChild).toBe(firstAlphaTemplateNode) // Same node expect(domData.get(firstAlphaTemplateNode, 'TestValue')).toBe('Hello') // Not cleaned expect(alphaViewModelInstance.alphaWasDisposed).not.toBe(true) @@ -432,7 +434,8 @@ describe('Components: Component binding', function () { jasmine.Clock.tick(1) // See it appeared, and the expected subscriptions were registered - var firstAlphaTemplateNode = testNode.firstChild.firstChild, + expect(testNode.firstChild).not.toBeNull(); + var firstAlphaTemplateNode = testNode.firstChild?.firstChild as HTMLElement, alphaViewModelInstance = dataFor(firstAlphaTemplateNode) expect(firstAlphaTemplateNode.className).toBe('alpha') expect(testNode).toContainText('Alpha value is 123.') @@ -480,7 +483,8 @@ describe('Components: Component binding', function () { applyBindings({ someObservable: someObservable }, testNode) jasmine.Clock.tick(1) - var firstTemplateNode = testNode.firstChild.firstChild, + expect(testNode.firstChild).not.toBeNull(); + var firstTemplateNode = testNode.firstChild?.firstChild, firstViewModelInstance = dataFor(firstTemplateNode) expect(firstViewModelInstance instanceof testViewModel).toBe(true) expect(testNode).toContainText('Value is First.') @@ -498,7 +502,7 @@ describe('Components: Component binding', function () { expect(domData.get(firstTemplateNode, 'TestValue')).toBe(undefined) // New viewmodel is a new instance - var secondViewModelInstance = dataFor(testNode.firstChild.firstChild) + var secondViewModelInstance = dataFor(testNode.firstChild?.firstChild) expect(secondViewModelInstance instanceof testViewModel).toBe(true) expect(secondViewModelInstance).not.toBe(firstViewModelInstance) }) @@ -527,36 +531,36 @@ describe('Components: Component binding', function () { testNode.innerHTML = '
' applyBindings({ outer: outerObservable }, testNode) jasmine.Clock.tick(1) - expect(testNode.childNodes[0].childNodes[0].value).toEqual('inner1') + expect(testNode.children[0].children[0].value).toEqual('inner1') expect(outerObservable.getSubscriptionsCount()).toBe(1) expect(innerObservable.getSubscriptionsCount()).toBe(1) expect(constructorCallCount).toBe(1) // See we can mutate the inner value and see the result show up innerObservable('inner2') - expect(testNode.childNodes[0].childNodes[0].value).toEqual('inner2') + expect(testNode.children[0].children[0].value).toEqual('inner2') expect(outerObservable.getSubscriptionsCount()).toBe(1) expect(innerObservable.getSubscriptionsCount()).toBe(1) expect(constructorCallCount).toBe(1) // See that we can mutate the observable from within the component - testNode.childNodes[0].childNodes[0].value = 'inner3' - triggerEvent(testNode.childNodes[0].childNodes[0], 'change') + testNode.children[0].children[0].value = 'inner3' + triggerEvent(testNode.children[0].children[0], 'change') expect(innerObservable()).toEqual('inner3') // See we can mutate the outer value and see the result show up (cleaning subscriptions to the old inner value) var newInnerObservable = observable('newinner') outerObservable({ inner: newInnerObservable }) jasmine.Clock.tick(1) // modifying the outer observable causes the component to reload, which happens asynchronously - expect(testNode.childNodes[0].childNodes[0].value).toEqual('newinner') + expect(testNode.children[0].children[0].value).toEqual('newinner') expect(outerObservable.getSubscriptionsCount()).toBe(1) expect(innerObservable.getSubscriptionsCount()).toBe(0) expect(newInnerObservable.getSubscriptionsCount()).toBe(1) expect(constructorCallCount).toBe(2) // See that we can mutate the new observable from within the component - testNode.childNodes[0].childNodes[0].value = 'newinner2' - triggerEvent(testNode.childNodes[0].childNodes[0], 'change') + testNode.children[0].children[0].value = 'newinner2' + triggerEvent(testNode.children[0].children[0], 'change') expect(newInnerObservable()).toEqual('newinner2') expect(innerObservable()).toEqual('inner3') // original one hasn't changed @@ -580,7 +584,8 @@ describe('Components: Component binding', function () { // Bind an instance of the component; grab its viewmodel applyBindings(outerViewModel, testNode) jasmine.Clock.tick(1) - var firstTemplateNode = testNode.firstChild.firstChild, + expect(testNode.firstChild).not.toBeNull(); + var firstTemplateNode = testNode.firstChild?.firstChild, viewModelInstance = dataFor(firstTemplateNode) expect(viewModelInstance instanceof TestViewModel).toBe(true) expect(viewModelInstance.wasDisposed).not.toBe(true) @@ -626,7 +631,7 @@ describe('Components: Component binding', function () { } // Define four separate components so we can switch between them - var constructorCallLog = [] + var constructorCallLog = new Array() function testViewModel1 (params) { constructorCallLog.push([1, params]) } function testViewModel2 (params) { constructorCallLog.push([2, params]) } function testViewModel3 (params) { constructorCallLog.push([3, params]) } @@ -649,7 +654,8 @@ describe('Components: Component binding', function () { // Even if we wait a while, it's not yet loaded, because we're still waiting for the module jasmine.Clock.tick(10) expect(constructorCallLog.length).toBe(0) - expect(testNode.firstChild.childNodes.length).toBe(0) + expect(testNode.firstChild).not.toBeNull(); + expect(testNode.firstChild?.childNodes.length).toBe(0) // In the meantime, switch to requesting component 2 and then 3 testComponentBindingValue.name('component-2') @@ -661,7 +667,7 @@ describe('Components: Component binding', function () { requireCallbacks['module-1'](testViewModel1) jasmine.Clock.tick(1) // ... even if we wait a bit longer expect(constructorCallLog.length).toBe(0) - expect(testNode.firstChild.childNodes.length).toBe(0) + expect(testNode.firstChild?.childNodes.length).toBe(0) // Now if component 3 finishes loading, it's the current one, so we instantiate and bind to it. // Notice this happens synchronously (at least, relative to the time now), because the completion @@ -669,7 +675,7 @@ describe('Components: Component binding', function () { requireCallbacks['module-3'](testViewModel3) expect(constructorCallLog).toEqual([ [3, testComponentParams] ]) expect(testNode).toContainText('Component 3 template') - var viewModelInstance = dataFor(testNode.firstChild.firstChild) + var viewModelInstance = dataFor(testNode.firstChild?.firstChild) expect(viewModelInstance instanceof testViewModel3).toBe(true) expect(viewModelInstance.wasDisposed).not.toBe(true) @@ -722,7 +728,7 @@ describe('Components: Component binding', function () { var callbacks = 0 outerViewModel.callback = function (nodes, data) { expect(nodes.length).toEqual(1) - expect(nodes[0]).toEqual(testNode.childNodes[0].childNodes[0]) + expect(nodes[0]).toEqual(testNode.children[0].children[0]) expect(data).toEqual(testComponentParams) callbacks++ } @@ -731,13 +737,13 @@ describe('Components: Component binding', function () { expect(callbacks).toEqual(0) jasmine.Clock.tick(1) - expect(testNode.childNodes[0]).toContainHtml('
some parameter value
') + expect(testNode.children[0]).toContainHtml('
some parameter value
') expect(callbacks).toEqual(1) }) describe('Component `bindingHandlers`', function () { it('overloads existing and provides new bindings', function () { - const calls = [] + const calls = new Array() testNode.innerHTML = `` class ViewModel { @@ -913,9 +919,9 @@ describe('Components: Component binding', function () { ViewModel.register('test-component') applyBindings(outerViewModel, testNode) expect(testNode.children[0].innerHTML).toEqual('xyz') - expect(testNode.childNodes[0] instanceof HTMLElement).toBeTruthy() - expect(testNode.childNodes[0].childNodes[0] instanceof HTMLElement).toBeTruthy() - expect(testNode.childNodes[0].childNodes[1] instanceof HTMLElement).toBeTruthy() + expect(testNode.children[0] instanceof HTMLElement).toBeTruthy() + expect(testNode.children[0].children[0] instanceof HTMLElement).toBeTruthy() + expect(testNode.children[0].children[1] instanceof HTMLElement).toBeTruthy() }) it('inserts partials from `children`', function () { @@ -992,8 +998,8 @@ describe('Components: Component binding', function () { applyBindings(outerViewModel, testNode) expect(seen.x).toEqual(x) expect(seen.y()).toEqual(x) - expect(testNode.childNodes[0] instanceof HTMLElement).toBeTruthy() - expect(testNode.childNodes[0].childNodes[0] instanceof HTMLElement).toBeTruthy() + expect(testNode.children[0] instanceof HTMLElement).toBeTruthy() + expect(testNode.children[0].children[0] instanceof HTMLElement).toBeTruthy() }) it('binds context for ViewModel::template', () => { @@ -1004,7 +1010,7 @@ describe('Components: Component binding', function () { } ViewModel.register('test-component') applyBindings(outerViewModel, testNode) - expect(dataFor(testNode.childNodes[0])).toEqual(outerViewModel) + expect(dataFor(testNode.children[0])).toEqual(outerViewModel) }) it('binds context for ViewModel.template', () => { @@ -1015,7 +1021,7 @@ describe('Components: Component binding', function () { } ViewModel.register('test-component') applyBindings(outerViewModel, testNode) - expect(dataFor(testNode.childNodes[0])).toEqual(outerViewModel) + expect(dataFor(testNode.children[0])).toEqual(outerViewModel) }) }) // /jsx @@ -1330,8 +1336,8 @@ describe('Components: Component binding', function () { applyBindings(outerViewModel, testNode) expect(testNode.innerText).toEqual('text') - expect(testNode.childNodes[0] instanceof HTMLElement).toBeTruthy() - expect(testNode.childNodes[0].childNodes[0] instanceof HTMLElement).toBeTruthy() + expect(testNode.children[0] instanceof HTMLElement).toBeTruthy() + expect(testNode.children[0].children[0] instanceof HTMLElement).toBeTruthy() obs('téx†') expect(testNode.innerText).toEqual('téx†') @@ -1370,8 +1376,8 @@ describe('Components: Component binding', function () { applyBindings(outerViewModel, testNode) expect(testNode.innerText).toEqual('') - expect(testNode.childNodes[0] instanceof HTMLElement).toBeTruthy() - expect(testNode.childNodes[0].childNodes[0] instanceof HTMLElement).toBeTruthy() + expect(testNode.children[0] instanceof HTMLElement).toBeTruthy() + expect(testNode.children[0].children[0] instanceof HTMLElement).toBeTruthy() arr(['abcdef']) expect(testNode.innerHTML).toEqual( @@ -1421,8 +1427,8 @@ describe('Components: Component binding', function () { applyBindings(outerViewModel, testNode) expect(testNode.innerText).toEqual('') - expect(testNode.childNodes[0] instanceof HTMLElement).toBeTruthy() - expect(testNode.childNodes[0].childNodes[0] instanceof HTMLElement).toBeTruthy() + expect(testNode.children[0] instanceof HTMLElement).toBeTruthy() + expect(testNode.children[0].children[0] instanceof HTMLElement).toBeTruthy() //
r
arr([{elementName: 'div', children: ['r'], attributes: {x: 1}}, 'text']) diff --git a/packages/binding.core/spec/attrBehaviors.ts b/packages/binding.core/spec/attrBehaviors.ts index 542ae5e0e..8172d1286 100644 --- a/packages/binding.core/spec/attrBehaviors.ts +++ b/packages/binding.core/spec/attrBehaviors.ts @@ -33,8 +33,8 @@ describe('Binding: Attr', function () { var model = { myValue: 'first value' } testNode.innerHTML = "
" applyBindings(model, testNode) - expect(testNode.childNodes[0].getAttribute('firstAttribute')).toEqual('first value') - expect(testNode.childNodes[0].getAttribute('second-attribute')).toEqual('true') + expect(testNode.children[0].getAttribute('firstAttribute')).toEqual('first value') + expect(testNode.children[0].getAttribute('second-attribute')).toEqual('true') }) it('Should be able to set namespaced attribute values', function () { @@ -50,39 +50,40 @@ describe('Binding: Attr', function () { ].join('') applyBindings(model, testNode) - var anchor = testNode.childNodes[0]/* svg */.childNodes[0]/* g */.childNodes[0]/* a */ - expect(anchor.getAttributeNode('xlink:href').value).toEqual('first value') - expect(anchor.getAttributeNode('xlink:href').namespaceURI).toEqual('http://www.w3.org/1999/xlink') + var anchor = testNode.children[0]/* svg */.children[0]/* g */.children[0]/* a */ + var href = anchor.getAttributeNode('xlink:href') + expect(href?.value).toEqual('first value') + expect(href?.namespaceURI).toEqual('http://www.w3.org/1999/xlink') }) it('Should be able to set \"name\" attribute, even on IE6-7', function () { var myValue = observable('myName') testNode.innerHTML = "" applyBindings({ myValue: myValue }, testNode) - expect(testNode.childNodes[0].name).toEqual('myName') - if (testNode.childNodes[0].outerHTML) { // Old Firefox doesn't support outerHTML - expect(testNode.childNodes[0].outerHTML).toMatch('name="?myName"?') + expect(testNode.children[0].name).toEqual('myName') + if (testNode.children[0].outerHTML) { // Old Firefox doesn't support outerHTML + expect(testNode.children[0].outerHTML).toMatch('name="?myName"?') } - expect(testNode.childNodes[0].getAttribute('name')).toEqual('myName') + expect(testNode.children[0].getAttribute('name')).toEqual('myName') // Also check we can remove it (which, for a name attribute, means setting it to an empty string) myValue(false) - expect(testNode.childNodes[0].name).toEqual('') - if (testNode.childNodes[0].outerHTML) { // Old Firefox doesn't support outerHTML - expect(testNode.childNodes[0].outerHTML).toNotMatch('name="?([^">]+)') + expect(testNode.children[0].name).toEqual('') + if (testNode.children[0].outerHTML) { // Old Firefox doesn't support outerHTML + expect(testNode.children[0].outerHTML).toNotMatch('name="?([^">]+)') } - expect(testNode.childNodes[0].getAttribute('name')).toEqual('') + expect(testNode.children[0].getAttribute('name')).toEqual('') }) it('Should respond to changes in an observable value', function () { var model = { myprop: observable('initial value') } testNode.innerHTML = "
" applyBindings(model, testNode) - expect(testNode.childNodes[0].getAttribute('someAttrib')).toEqual('initial value') + expect(testNode.children[0].getAttribute('someAttrib')).toEqual('initial value') // Change the observable; observe it reflected in the DOM model.myprop('new value') - expect(testNode.childNodes[0].getAttribute('someAttrib')).toEqual('new value') + expect(testNode.children[0].getAttribute('someAttrib')).toEqual('new value') }) it('Should remove the attribute if the value is strictly false, null, or undefined', function () { @@ -91,21 +92,21 @@ describe('Binding: Attr', function () { applyBindings(model, testNode) arrayForEach([false, null, undefined], function (testValue) { model.myprop('nonempty value') - expect(testNode.childNodes[0].getAttribute('someAttrib')).toEqual('nonempty value') + expect(testNode.children[0].getAttribute('someAttrib')).toEqual('nonempty value') model.myprop(testValue) - expect(testNode.childNodes[0].getAttribute('someAttrib')).toEqual(null) + expect(testNode.children[0].getAttribute('someAttrib')).toEqual(null) }) }) it('Should be able to set class attribute and access it using className property', function () { var model = { myprop: observable('newClass') } testNode.innerHTML = "
" - expect(testNode.childNodes[0].className).toEqual('oldClass') + expect(testNode.children[0].className).toEqual('oldClass') applyBindings(model, testNode) - expect(testNode.childNodes[0].className).toEqual('newClass') + expect(testNode.children[0].className).toEqual('newClass') // Should be able to clear class also model.myprop(undefined) - expect(testNode.childNodes[0].className).toEqual('') - expect(testNode.childNodes[0].getAttribute('class')).toEqual(null) + expect(testNode.children[0].className).toEqual('') + expect(testNode.children[0].getAttribute('class')).toEqual(null) }) }) diff --git a/packages/binding.core/spec/checkedBehaviors.ts b/packages/binding.core/spec/checkedBehaviors.ts index 865fcbd3f..ce4f7428b 100644 --- a/packages/binding.core/spec/checkedBehaviors.ts +++ b/packages/binding.core/spec/checkedBehaviors.ts @@ -38,32 +38,34 @@ describe('Binding: Checked', function () { it('Triggering a click should toggle a checkbox\'s checked state before the event handler fires', function () { // This isn't strictly to do with the checked binding, but if this doesn't work, the rest of the specs aren't meaningful testNode.innerHTML = "" + var input = testNode.children[0] as HTMLInputElement var clickHandlerFireCount = 0, expectedCheckedStateInHandler - registerEventHandler(testNode.childNodes[0], 'click', function () { + registerEventHandler(input, 'click', function () { clickHandlerFireCount++ - expect(testNode.childNodes[0].checked).toEqual(expectedCheckedStateInHandler) + expect(input.checked).toEqual(expectedCheckedStateInHandler) }) - expect(testNode.childNodes[0].checked).toEqual(false) + expect(input.checked).toEqual(false) expectedCheckedStateInHandler = true - triggerEvent(testNode.childNodes[0], 'click') - expect(testNode.childNodes[0].checked).toEqual(true) + triggerEvent(input, 'click') + expect(input.checked).toEqual(true) expect(clickHandlerFireCount).toEqual(1) expectedCheckedStateInHandler = false - triggerEvent(testNode.childNodes[0], 'click') - expect(testNode.childNodes[0].checked).toEqual(false) + triggerEvent(input, 'click') + expect(input.checked).toEqual(false) expect(clickHandlerFireCount).toEqual(2) }) it('Should be able to control a checkbox\'s checked state', function () { var myobservable = observable(true) testNode.innerHTML = "" + var input = testNode.children[0] as HTMLInputElement applyBindings({ someProp: myobservable }, testNode) - expect(testNode.childNodes[0].checked).toEqual(true) + expect(input.checked).toEqual(true) myobservable(false) - expect(testNode.childNodes[0].checked).toEqual(false) + expect(input.checked).toEqual(false) }) it('Should update observable properties on the underlying model when the checkbox click event fires', function () { @@ -71,7 +73,7 @@ describe('Binding: Checked', function () { testNode.innerHTML = "" applyBindings({ someProp: myobservable }, testNode) - triggerEvent(testNode.childNodes[0], 'click') + triggerEvent(testNode.children[0], 'click') expect(myobservable()).toEqual(true) }) @@ -83,14 +85,14 @@ describe('Binding: Checked', function () { applyBindings({ someProp: myobservable }, testNode) // Multiple events only cause one notification... - triggerEvent(testNode.childNodes[0], 'click') - triggerEvent(testNode.childNodes[0], 'change') - triggerEvent(testNode.childNodes[0], 'change') + triggerEvent(testNode.children[0], 'click') + triggerEvent(testNode.children[0], 'change') + triggerEvent(testNode.children[0], 'change') expect(timesNotified).toEqual(1) // ... until the checkbox value actually changes - triggerEvent(testNode.childNodes[0], 'click') - triggerEvent(testNode.childNodes[0], 'change') + triggerEvent(testNode.children[0], 'click') + triggerEvent(testNode.children[0], 'change') expect(timesNotified).toEqual(2) }) @@ -99,7 +101,7 @@ describe('Binding: Checked', function () { testNode.innerHTML = "" applyBindings(model, testNode) - triggerEvent(testNode.childNodes[0], 'click') + triggerEvent(testNode.children[0], 'click') expect(model.someProp).toEqual(true) }) @@ -108,19 +110,22 @@ describe('Binding: Checked', function () { testNode.innerHTML = "" applyBindings({ someProp: myobservable }, testNode) - expect(testNode.childNodes[0].checked).toEqual(false) + var input = testNode.children[0] as HTMLInputElement + + expect(input.checked).toEqual(false) myobservable('This Radio Button Value') - expect(testNode.childNodes[0].checked).toEqual(true) + expect(input.checked).toEqual(true) }) it('Should set an observable model property to this radio button\'s value when checked', function () { var myobservable = observable('another value') testNode.innerHTML = "" applyBindings({ someProp: myobservable }, testNode) - + expect(myobservable()).toEqual('another value') - testNode.childNodes[0].click() + var input = testNode.children[0] as HTMLInputElement + input.click() expect(myobservable()).toEqual('this radio button value') }) @@ -132,10 +137,10 @@ describe('Binding: Checked', function () { applyBindings({ someProp: myobservable }, testNode) // Multiple events only cause one notification... - triggerEvent(testNode.childNodes[0], 'click') - triggerEvent(testNode.childNodes[0], 'change') - triggerEvent(testNode.childNodes[0], 'click') - triggerEvent(testNode.childNodes[0], 'change') + triggerEvent(testNode.children[0], 'click') + triggerEvent(testNode.children[0], 'change') + triggerEvent(testNode.children[0], 'click') + triggerEvent(testNode.children[0], 'change') expect(timesNotified).toEqual(1) // ... until you click something with a different value @@ -149,7 +154,7 @@ describe('Binding: Checked', function () { testNode.innerHTML = "" applyBindings(model, testNode) - triggerEvent(testNode.childNodes[0], 'click') + triggerEvent(testNode.children[0], 'click') expect(model.someProp).toEqual('this radio button value') }) @@ -177,16 +182,16 @@ describe('Binding: Checked', function () { var model = { myObservableArray: observableArray(['Unrelated value']) } testNode.innerHTML = "" applyBindings(model, testNode) - - expect(testNode.childNodes[0].checked).toEqual(false) + var input = testNode.children[0] as HTMLInputElement + expect(input.checked).toEqual(false) // Put the value in the array; observe the checkbox reflect this model.myObservableArray.push('My value') - expect(testNode.childNodes[0].checked).toEqual(true) + expect(input.checked).toEqual(true) // Remove the value from the array; observe the checkbox reflect this model.myObservableArray.remove('My value') - expect(testNode.childNodes[0].checked).toEqual(false) + expect(input.checked).toEqual(false) }) it('When a checkbox is bound to a computed array, the checkbox and the computed observable should update each other', function () { @@ -211,7 +216,7 @@ describe('Binding: Checked', function () { expect(testNode).toHaveCheckedStates([true, false]) // Binding removes an item from the observable - triggerEvent(testNode.childNodes[0], 'click') + triggerEvent(testNode.children[0], 'click') expect(testNode).toHaveCheckedStates([false, false]) expect(myObservable()).toEqual([]) }) @@ -221,9 +226,10 @@ describe('Binding: Checked', function () { testNode.innerHTML = "" applyBindings({ someProp: myObservable }, testNode) - expect(testNode.childNodes[0].checked).toEqual(true) + var input = testNode.children[0] as HTMLInputElement + expect(input.checked).toEqual(true) myObservable('another value') - expect(testNode.childNodes[0].checked).toEqual(false) + expect(input.checked).toEqual(false) }) it('When the radio button \'value\' attribute is set via attr binding, should set initial checked state correctly (checked before attr)', function () { @@ -231,9 +237,10 @@ describe('Binding: Checked', function () { testNode.innerHTML = "" applyBindings({ someProp: myobservable }, testNode) - expect(testNode.childNodes[0].checked).toEqual(true) + var input = testNode.children[0] as HTMLInputElement + expect(input.checked).toEqual(true) myobservable('another value') - expect(testNode.childNodes[0].checked).toEqual(false) + expect(input.checked).toEqual(false) }) it('When the bound observable is updated in a subscription in response to a radio click, view and model should stay in sync', function () { @@ -308,16 +315,16 @@ describe('Binding: Checked', function () { applyBindings(model, testNode) // Checkbox initial state is determined by whether the value is in the array - expect(testNode.childNodes[0]).toHaveCheckedStates([true, false]) + expect(testNode.children[0]).toHaveCheckedStates([true, false]) // Checking the checkbox puts it in the array - triggerEvent(testNode.childNodes[0].childNodes[1], 'click') - expect(testNode.childNodes[0]).toHaveCheckedStates([true, true]) + triggerEvent(testNode.children[0].childNodes[1], 'click') + expect(testNode.children[0]).toHaveCheckedStates([true, true]) expect(model.values).toEqual([object1, object2]) // Unchecking the checkbox removes it from the array - triggerEvent(testNode.childNodes[0].childNodes[1], 'click') - expect(testNode.childNodes[0]).toHaveCheckedStates([true, false]) + triggerEvent(testNode.children[0].childNodes[1], 'click') + expect(testNode.children[0]).toHaveCheckedStates([true, false]) expect(model.values).toEqual([object1]) }) @@ -329,32 +336,32 @@ describe('Binding: Checked', function () { applyBindings(model, testNode) expect(model.values()).toEqual([1]) - expect(testNode.childNodes[0]).toHaveCheckedStates([true, false]) + expect(testNode.children[0]).toHaveCheckedStates([true, false]) // Update the value observable of the checked item; should update the selected values and leave checked values unchanged object1.id(3) expect(model.values()).toEqual([3]) - expect(testNode.childNodes[0]).toHaveCheckedStates([true, false]) + expect(testNode.children[0]).toHaveCheckedStates([true, false]) // Update the value observable of the unchecked item; should do nothing object2.id(4) expect(model.values()).toEqual([3]) - expect(testNode.childNodes[0]).toHaveCheckedStates([true, false]) + expect(testNode.children[0]).toHaveCheckedStates([true, false]) // Update the value observable of the unchecked item to the current model value; should set to checked object2.id(3) expect(model.values()).toEqual([3]) - expect(testNode.childNodes[0]).toHaveCheckedStates([true, true]) + expect(testNode.children[0]).toHaveCheckedStates([true, true]) // Update the value again; should leave checked and replace item in the selected values (other checkbox should be unchecked) object2.id(4) expect(model.values()).toEqual([4]) - expect(testNode.childNodes[0]).toHaveCheckedStates([false, true]) + expect(testNode.children[0]).toHaveCheckedStates([false, true]) // Revert to original value; should update value in selected values object2.id(2) expect(model.values()).toEqual([2]) - expect(testNode.childNodes[0]).toHaveCheckedStates([false, true]) + expect(testNode.children[0]).toHaveCheckedStates([false, true]) }) it('When node is removed, subscription to observable bound to \'' + binding + '\' is disposed', function () { @@ -362,11 +369,12 @@ describe('Binding: Checked', function () { testNode.innerHTML = "" applyBindings(model, testNode) + var input = testNode.children[0] as HTMLInputElement expect(model.values).toEqual([1]) - expect(testNode.childNodes[0].checked).toEqual(true) + expect(input.checked).toEqual(true) expect(model.checkedValue.getSubscriptionsCount()).toBeGreaterThan(0) - removeNode(testNode.childNodes[0]) + removeNode(input) expect(model.checkedValue.getSubscriptionsCount()).toEqual(0) }) @@ -376,6 +384,7 @@ describe('Binding: Checked', function () { "" applyBindings({ someProp: myobservable }, testNode) + expect(myobservable()).toEqual(false) // Check initial state @@ -399,32 +408,32 @@ describe('Binding: Checked', function () { applyBindings(model, testNode) expect(model.value()).toEqual(1) - expect(testNode.childNodes[0]).toHaveCheckedStates([true, false]) + expect(testNode.children[0]).toHaveCheckedStates([true, false]) // Update the value observable of the checked item; should update the selected value and leave checked values unchanged object1.id(3) expect(model.value()).toEqual(3) - expect(testNode.childNodes[0]).toHaveCheckedStates([true, false]) + expect(testNode.children[0]).toHaveCheckedStates([true, false]) // Update the value observable of the unchecked item; should do nothing object2.id(4) expect(model.value()).toEqual(3) - expect(testNode.childNodes[0]).toHaveCheckedStates([true, false]) + expect(testNode.children[0]).toHaveCheckedStates([true, false]) // Update the value observable of the unchecked item to the current model value; should set to checked object2.id(3) expect(model.value()).toEqual(3) - expect(testNode.childNodes[0]).toHaveCheckedStates([true, true]) + expect(testNode.children[0]).toHaveCheckedStates([true, true]) // Update the value again; should leave checked and replace selected value (other button should be unchecked) object2.id(4) expect(model.value()).toEqual(4) - expect(testNode.childNodes[0]).toHaveCheckedStates([false, true]) + expect(testNode.children[0]).toHaveCheckedStates([false, true]) // Revert to original value; should update selected value object2.id(2) expect(model.value()).toEqual(2) - expect(testNode.childNodes[0]).toHaveCheckedStates([false, true]) + expect(testNode.children[0]).toHaveCheckedStates([false, true]) }) if (binding === 'checkedValue') { @@ -467,32 +476,32 @@ describe('Binding: Checked', function () { applyBindings(model, testNode) expect(model.value()).toEqual(1) - expect(testNode.childNodes[0]).toHaveCheckedStates([true, false]) + expect(testNode.children[0]).toHaveCheckedStates([true, false]) // Update the value observable of the checked item; should update the selected values and leave checked values unchanged object1.id(3) expect(model.value()).toEqual(3) - expect(testNode.childNodes[0]).toHaveCheckedStates([true, false]) + expect(testNode.children[0]).toHaveCheckedStates([true, false]) // Update the value observable of the unchecked item; should do nothing object2.id(4) expect(model.value()).toEqual(3) - expect(testNode.childNodes[0]).toHaveCheckedStates([true, false]) + expect(testNode.children[0]).toHaveCheckedStates([true, false]) // Update the value observable of the unchecked item to the current model value; should set to checked object2.id(3) expect(model.value()).toEqual(3) - expect(testNode.childNodes[0]).toHaveCheckedStates([true, true]) + expect(testNode.children[0]).toHaveCheckedStates([true, true]) // Update the value again; should leave checked and replace selected value (other button should be unchecked) object2.id(4) expect(model.value()).toEqual(4) - expect(testNode.childNodes[0]).toHaveCheckedStates([false, true]) + expect(testNode.children[0]).toHaveCheckedStates([false, true]) // Revert to original value; should update selected value object2.id(2) expect(model.value()).toEqual(2) - expect(testNode.childNodes[0]).toHaveCheckedStates([false, true]) + expect(testNode.children[0]).toHaveCheckedStates([false, true]) }) } @@ -501,14 +510,15 @@ describe('Binding: Checked', function () { testNode.innerHTML = "" applyBindings({ someProp: myobservable }, testNode) + var input = testNode.children[0] as HTMLInputElement // ignores 'undefined' value and treats checkbox value as true/false - expect(testNode.childNodes[0].checked).toEqual(true) + expect(input.checked).toEqual(true) myobservable(false) - expect(testNode.childNodes[0].checked).toEqual(false) + expect(input.checked).toEqual(false) - triggerEvent(testNode.childNodes[0], 'click') + triggerEvent(input, 'click') expect(myobservable()).toEqual(true) - triggerEvent(testNode.childNodes[0], 'click') + triggerEvent(input, 'click') expect(myobservable()).toEqual(false) }) }) diff --git a/packages/binding.core/spec/cssBehaviors.ts b/packages/binding.core/spec/cssBehaviors.ts index edf49d02e..5d20eb66a 100644 --- a/packages/binding.core/spec/cssBehaviors.ts +++ b/packages/binding.core/spec/cssBehaviors.ts @@ -34,11 +34,11 @@ describe('Binding: CSS classes', function () { testNode.innerHTML = "
Hallo
" applyBindings({ someModelProperty: observable1, anotherModelProperty: observable2 }, testNode) - expect(testNode.childNodes[0].className).toEqual('unrelatedClass1 unrelatedClass2 anotherRule') + expect(testNode.children[0].className).toEqual('unrelatedClass1 unrelatedClass2 anotherRule') observable1(true) - expect(testNode.childNodes[0].className).toEqual('unrelatedClass1 unrelatedClass2 anotherRule myRule') + expect(testNode.children[0].className).toEqual('unrelatedClass1 unrelatedClass2 anotherRule myRule') observable2(false) - expect(testNode.childNodes[0].className).toEqual('unrelatedClass1 unrelatedClass2 myRule') + expect(testNode.children[0].className).toEqual('unrelatedClass1 unrelatedClass2 myRule') }) it('Should give the element a single CSS class without a leading space when the specified value is true', function () { @@ -46,9 +46,9 @@ describe('Binding: CSS classes', function () { testNode.innerHTML = "
Hallo
" applyBindings({ someModelProperty: observable1 }, testNode) - expect(testNode.childNodes[0].className).toEqual('') + expect(testNode.children[0].className).toEqual('') observable1(true) - expect(testNode.childNodes[0].className).toEqual('myRule') + expect(testNode.children[0].className).toEqual('myRule') }) it('Should toggle multiple CSS classes if specified as a single string separated by spaces', function () { @@ -56,11 +56,11 @@ describe('Binding: CSS classes', function () { testNode.innerHTML = "
Hallo
" applyBindings({ someModelProperty: observable1 }, testNode) - expect(testNode.childNodes[0].className).toEqual('unrelatedClass1') + expect(testNode.children[0].className).toEqual('unrelatedClass1') observable1(true) - expect(testNode.childNodes[0].className).toEqual('unrelatedClass1 myRule _another-Rule123') + expect(testNode.children[0].className).toEqual('unrelatedClass1 myRule _another-Rule123') observable1(false) - expect(testNode.childNodes[0].className).toEqual('unrelatedClass1') + expect(testNode.children[0].className).toEqual('unrelatedClass1') }) it('Should set/change dynamic CSS class(es) if string is specified', function () { @@ -68,15 +68,15 @@ describe('Binding: CSS classes', function () { testNode.innerHTML = "
Hallo
" applyBindings({ someModelProperty: observable1 }, testNode) - expect(testNode.childNodes[0].className).toEqual('unrelatedClass1') + expect(testNode.children[0].className).toEqual('unrelatedClass1') observable1('my-Rule') - expect(testNode.childNodes[0].className).toEqual('unrelatedClass1 my-Rule') + expect(testNode.children[0].className).toEqual('unrelatedClass1 my-Rule') observable1('another_Rule my-Rule') - expect(testNode.childNodes[0].className).toEqual('unrelatedClass1 another_Rule my-Rule') + expect(testNode.children[0].className).toEqual('unrelatedClass1 another_Rule my-Rule') observable1(undefined) - expect(testNode.childNodes[0].className).toEqual('unrelatedClass1') + expect(testNode.children[0].className).toEqual('unrelatedClass1') observable1(' ') - expect(testNode.childNodes[0].className).toEqual('unrelatedClass1') + expect(testNode.children[0].className).toEqual('unrelatedClass1') }) it('Should work with any arbitrary class names', function () { @@ -85,9 +85,9 @@ describe('Binding: CSS classes', function () { testNode.innerHTML = "
Something
" applyBindings({ someModelProperty: observable1 }, testNode) - expect(testNode.childNodes[0].className).toEqual('') + expect(testNode.children[0].className).toEqual('') observable1(true) - expect(testNode.childNodes[0].className).toEqual('complex/className complex.className') + expect(testNode.children[0].className).toEqual('complex/className complex.className') }) // Ensure CSS binding supports SVG, where applicable. @@ -109,9 +109,9 @@ describe('Binding: CSS classes', function () { var myObservable = observable() testNode.innerHTML = "" applyBindings({someModelProperty: myObservable}, testNode) - expect(testNode.childNodes[0].getAttribute('class')).toEqual('Y') + expect(testNode.children[0].getAttribute('class')).toEqual('Y') myObservable(true) - expect(testNode.childNodes[0].getAttribute('class')).toEqual('Y x') + expect(testNode.children[0].getAttribute('class')).toEqual('Y x') } }) @@ -120,13 +120,13 @@ describe('Binding: CSS classes', function () { var observable1 = observable({}) testNode.innerHTML = "
Hallo
" applyBindings({ someModelProperty: observable1 }, testNode) - expect(testNode.childNodes[0].className).toEqual('unrelatedClass1') + expect(testNode.children[0].className).toEqual('unrelatedClass1') observable1('my-Rule') - expect(testNode.childNodes[0].className).toEqual('unrelatedClass1 my-Rule') + expect(testNode.children[0].className).toEqual('unrelatedClass1 my-Rule') observable1(null) - expect(testNode.childNodes[0].className).toEqual('unrelatedClass1') + expect(testNode.children[0].className).toEqual('unrelatedClass1') observable1('my-Rule') - expect(testNode.childNodes[0].className).toEqual('unrelatedClass1 my-Rule') + expect(testNode.children[0].className).toEqual('unrelatedClass1 my-Rule') }) it('Should be aliased as class as well as css', function () { @@ -142,17 +142,17 @@ describe('Binding: CSS classes', function () { testNode.innerHTML = "
" applyBindings({ booleanProp: booleanProp, stringProp: stringProp }, testNode) - expect(testNode.childNodes[0].className).toEqual('unrelatedClass') + expect(testNode.children[0].className).toEqual('unrelatedClass') booleanProp(true) - expect(testNode.childNodes[0].className).toEqual('unrelatedClass staticClass') + expect(testNode.children[0].className).toEqual('unrelatedClass staticClass') stringProp('dynamicClass') - expect(testNode.childNodes[0].className).toEqual('unrelatedClass staticClass dynamicClass') + expect(testNode.children[0].className).toEqual('unrelatedClass staticClass dynamicClass') booleanProp(false) - expect(testNode.childNodes[0].className).toEqual('unrelatedClass dynamicClass') + expect(testNode.children[0].className).toEqual('unrelatedClass dynamicClass') stringProp(null) - expect(testNode.childNodes[0].className).toEqual('unrelatedClass') + expect(testNode.children[0].className).toEqual('unrelatedClass') }) }) diff --git a/packages/binding.core/spec/enableDisableBehaviors.ts b/packages/binding.core/spec/enableDisableBehaviors.ts index 243a0ca16..23adbb70a 100644 --- a/packages/binding.core/spec/enableDisableBehaviors.ts +++ b/packages/binding.core/spec/enableDisableBehaviors.ts @@ -29,10 +29,10 @@ describe('Binding: Enable/Disable', function () { var myObservable = observable() testNode.innerHTML = "" applyBindings({ myModelProperty: myObservable }, testNode) - - expect(testNode.childNodes[0].disabled).toEqual(true) + var input = testNode.children[0] as HTMLInputElement + expect(input.disabled).toEqual(true) myObservable(1) - expect(testNode.childNodes[0].disabled).toEqual(false) + expect(input.disabled).toEqual(false) }) it('Disable means the node is enabled only when the value is false', function () { @@ -40,22 +40,27 @@ describe('Binding: Enable/Disable', function () { testNode.innerHTML = "" applyBindings({ myModelProperty: myObservable }, testNode) - expect(testNode.childNodes[0].disabled).toEqual(false) + var input = testNode.children[0] as HTMLInputElement + expect(input.disabled).toEqual(false) myObservable(1) - expect(testNode.childNodes[0].disabled).toEqual(true) + expect(input.disabled).toEqual(true) }) it('Enable should unwrap observables implicitly', function () { var myObservable = observable(false) testNode.innerHTML = "" applyBindings({ myModelProperty: myObservable }, testNode) - expect(testNode.childNodes[0].disabled).toEqual(true) + + var input = testNode.children[0] as HTMLInputElement + expect(input.disabled).toEqual(true) }) it('Disable should unwrap observables implicitly', function () { var myObservable = observable(false) testNode.innerHTML = "" applyBindings({ myModelProperty: myObservable }, testNode) - expect(testNode.childNodes[0].disabled).toEqual(false) + + var input = testNode.children[0] as HTMLInputElement + expect(input.disabled).toEqual(false) }) }) diff --git a/packages/binding.core/spec/htmlBehaviors.ts b/packages/binding.core/spec/htmlBehaviors.ts index 5b8994d72..c032b3035 100644 --- a/packages/binding.core/spec/htmlBehaviors.ts +++ b/packages/binding.core/spec/htmlBehaviors.ts @@ -27,20 +27,20 @@ describe('Binding: HTML', function () { var model = { textProp: 'My HTML-containing value' } testNode.innerHTML = "" applyBindings(model, testNode) - expect(testNode.childNodes[0].innerHTML.toLowerCase()).toEqual(model.textProp.toLowerCase()) - expect(testNode.childNodes[0].childNodes[1].innerHTML).toEqual('HTML-containing') + expect((testNode.childNodes[0] as HTMLElement).innerHTML.toLowerCase()).toEqual(model.textProp.toLowerCase()) + expect((testNode.childNodes[0].childNodes[1] as HTMLElement).innerHTML).toEqual('HTML-containing') }) it('Should assign an empty string as value if the model value is null', function () { testNode.innerHTML = "" applyBindings(null, testNode) - expect(testNode.childNodes[0].innerHTML).toEqual('') + expect(testNode.children[0].innerHTML).toEqual('') }) it('Should assign an empty string as value if the model value is undefined', function () { testNode.innerHTML = "" applyBindings(null, testNode) - expect(testNode.childNodes[0].innerHTML).toEqual('') + expect(testNode.children[0].innerHTML).toEqual('') }) it('Should be able to write arbitrary HTML, even if it is not semantically correct', function () { @@ -50,7 +50,7 @@ describe('Binding: HTML', function () { var model = { textProp: "

hello

this isn't semantically correct

" } testNode.innerHTML = "

" applyBindings(model, testNode) - expect(testNode.childNodes[0]).toContainHtml(model.textProp) + expect(testNode.children[0]).toContainHtml(model.textProp) }) it('Should be able to write arbitrary HTML, including elements into tables', function () { @@ -62,10 +62,10 @@ describe('Binding: HTML', function () { applyBindings(model, testNode) // Accept either of the following outcomes - there may or may not be an implicitly added . - var tr = testNode.childNodes[0].childNodes[0] - if (tr.tagName == 'TBODY') { tr = tr.childNodes[0] } + var tr = testNode.children[0].children[0] + if (tr.tagName == 'TBODY') { tr = tr.children[0] } - var td = tr.childNodes[0] + var td = tr.children[0] expect(tr.tagName).toEqual('TR') expect(td.tagName).toEqual('TD') diff --git a/packages/binding.core/spec/selectedOptionsBehaviors.ts b/packages/binding.core/spec/selectedOptionsBehaviors.ts index 72bae0b98..dc0471ca9 100644 --- a/packages/binding.core/spec/selectedOptionsBehaviors.ts +++ b/packages/binding.core/spec/selectedOptionsBehaviors.ts @@ -131,7 +131,7 @@ describe('Binding: Selected Options', function () { }) it('Should not change the scroll position when updating the view', function () { - var selection = observableArray(), data = [] + var selection = observableArray(), data = new Array() for (var i = 1; i < 101; i++) { data.push({ code: '0000' + i, name: 'Item ' + i }) } diff --git a/packages/binding.core/spec/styleBehaviors.ts b/packages/binding.core/spec/styleBehaviors.ts index bd51d3931..011200473 100644 --- a/packages/binding.core/spec/styleBehaviors.ts +++ b/packages/binding.core/spec/styleBehaviors.ts @@ -31,51 +31,55 @@ describe('Binding: CSS style', function () { var myObservable = new observable('red') testNode.innerHTML = "
Hallo
" applyBindings({ colorValue: myObservable }, testNode) - - expect(testNode.childNodes[0].style.backgroundColor).toEqualOneOf(['red', '#ff0000']) // Opera returns style color values in #rrggbb notation, unlike other browsers + var divEl = testNode.children[0] as HTMLDivElement + expect(divEl.style.backgroundColor).toEqualOneOf(['red', '#ff0000']) // Opera returns style color values in #rrggbb notation, unlike other browsers myObservable('green') - expect(testNode.childNodes[0].style.backgroundColor).toEqualOneOf(['green', '#008000']) + expect(divEl.style.backgroundColor).toEqualOneOf(['green', '#008000']) myObservable(undefined) - expect(testNode.childNodes[0].style.backgroundColor).toEqual('') + expect(divEl.style.backgroundColor).toEqual('') }) it('Should be able to apply the numeric value to a style and have it converted to px', function () { // See https://github.com/knockout/knockout/issues/231 testNode.innerHTML = "
" applyBindings(null, testNode) - expect(testNode.childNodes[0].style.width).toBe('10px') + var divEl = testNode.children[0] as HTMLDivElement + expect(divEl.style.width).toBe('10px') }) it('Should give the element the specified CSS style value', function () { var myObservable = observable('red') testNode.innerHTML = "
Hallo
" applyBindings({ colorValue: myObservable }, testNode) - - expect(testNode.childNodes[0].style.backgroundColor).toEqualOneOf(['red', '#ff0000']) // Opera returns style color values in #rrggbb notation, unlike other browsers + var divEl = testNode.children[0] as HTMLDivElement + expect(divEl.style.backgroundColor).toEqualOneOf(['red', '#ff0000']) // Opera returns style color values in #rrggbb notation, unlike other browsers myObservable('green') - expect(testNode.childNodes[0].style.backgroundColor).toEqualOneOf(['green', '#008000']) + expect(divEl.style.backgroundColor).toEqualOneOf(['green', '#008000']) myObservable(undefined) - expect(testNode.childNodes[0].style.backgroundColor).toEqual('') + expect(divEl.style.backgroundColor).toEqual('') }) it('Should be able to apply the numeric value to a style that doesn\'t accept pixels', function () { testNode.innerHTML = "
" applyBindings(null, testNode) - expect(testNode.childNodes[0].style.zIndex).toEqualOneOf(['10', 10]) + var divEl = testNode.children[0] as HTMLDivElement + expect(divEl.style.zIndex).toEqualOneOf(['10', 10]) }) it('Should be able to apply the numeric value zero to a style', function () { // Represents https://github.com/knockout/knockout/issues/972 testNode.innerHTML = "
" applyBindings(null, testNode) - expect(testNode.childNodes[0].style.width).toBe('0px') + var divEl = testNode.children[0] as HTMLDivElement + expect(divEl.style.width).toBe('0px') }) it('Should be able to use "false" to remove a style', function () { // Verifying that the fix for 972 doesn't break this existing behavior testNode.innerHTML = "
" applyBindings(null, testNode) - expect(testNode.childNodes[0].style.width).toBe('') + var divEl = testNode.children[0] as HTMLDivElement + expect(divEl.style.width).toBe('') }) it('Should properly respond to changes in the observable, adding px when appropriate', function () { @@ -83,15 +87,17 @@ describe('Binding: CSS style', function () { testNode.innerHTML = "
" applyBindings({width: width}, testNode) - expect(testNode.childNodes[0].style.width).toBe('') + + var divEl = testNode.children[0] as HTMLDivElement + expect(divEl.style.width).toBe('') width(10) - expect(testNode.childNodes[0].style.width).toBe('10px') + expect(divEl.style.width).toBe('10px') width(20) - expect(testNode.childNodes[0].style.width).toBe('20px') + expect(divEl.style.width).toBe('20px') width(false) - expect(testNode.childNodes[0].style.width).toBe('') + expect(divEl.style.width).toBe('') }) }) diff --git a/packages/binding.core/spec/textInputBehaviors.ts b/packages/binding.core/spec/textInputBehaviors.ts index 091337a6c..80ee0e417 100644 --- a/packages/binding.core/spec/textInputBehaviors.ts +++ b/packages/binding.core/spec/textInputBehaviors.ts @@ -39,51 +39,51 @@ describe('Binding: TextInput', function () { it('Should assign the value to the node', function () { testNode.innerHTML = "" applyBindings(null, testNode) - expect(testNode.childNodes[0].value).toEqual('123') + expect(testNode.children[0].value).toEqual('123') }) it('Should treat null values as empty strings', function () { testNode.innerHTML = "" applyBindings({ myProp: observable(0) }, testNode) - expect(testNode.childNodes[0].value).toEqual('0') + expect(testNode.children[0].value).toEqual('0') }) it('Should assign an empty string as value if the model value is null', function () { testNode.innerHTML = "" applyBindings(null, testNode) - expect(testNode.childNodes[0].value).toEqual('') + expect(testNode.children[0].value).toEqual('') }) it('Should assign an empty string as value if the model value is undefined', function () { testNode.innerHTML = "" applyBindings(null, testNode) - expect(testNode.childNodes[0].value).toEqual('') + expect(testNode.children[0].value).toEqual('') }) it('For observable values, should unwrap the value and update on change', function () { var myObservable = observable(123) testNode.innerHTML = "" applyBindings({ someProp: myObservable }, testNode) - expect(testNode.childNodes[0].value).toEqual('123') + expect(testNode.children[0].value).toEqual('123') myObservable(456) - expect(testNode.childNodes[0].value).toEqual('456') + expect(testNode.children[0].value).toEqual('456') }) it('For observable values, should update on change if new value is \'strictly\' different from previous value', function () { var myObservable = observable('+123') testNode.innerHTML = "" applyBindings({ someProp: myObservable }, testNode) - expect(testNode.childNodes[0].value).toEqual('+123') + expect(testNode.children[0].value).toEqual('+123') myObservable(123) - expect(testNode.childNodes[0].value).toEqual('123') + expect(testNode.children[0].value).toEqual('123') }) it('For writeable observable values, should catch the node\'s onchange and write values back to the observable', function () { var myObservable = observable(123) testNode.innerHTML = "" applyBindings({ someProp: myObservable }, testNode) - testNode.childNodes[0].value = 'some user-entered value' - triggerEvent(testNode.childNodes[0], 'change') + testNode.children[0].value = 'some user-entered value' + triggerEvent(testNode.children[0], 'change') expect(myObservable()).toEqual('some user-entered value') }) @@ -106,25 +106,25 @@ describe('Binding: TextInput', function () { applyBindings({ valueForEditing: valueForEditing }, testNode) // set initial valid value - testNode.childNodes[0].value = '1234' - triggerEvent(testNode.childNodes[0], 'change') + testNode.children[0].value = '1234' + triggerEvent(testNode.children[0], 'change') expect(validValue()).toEqual('1234') expect(isValid()).toEqual(true) - expect(testNode.childNodes[0].value).toEqual('1234') + expect(testNode.children[0].value).toEqual('1234') // set to an invalid value - testNode.childNodes[0].value = '1234a' - triggerEvent(testNode.childNodes[0], 'change') + testNode.children[0].value = '1234a' + triggerEvent(testNode.children[0], 'change') expect(validValue()).toEqual('1234') expect(isValid()).toEqual(false) - expect(testNode.childNodes[0].value).toEqual('1234a') + expect(testNode.children[0].value).toEqual('1234a') // set to a valid value where the current value of the writeable computed is the same as the written value - testNode.childNodes[0].value = '1234' - triggerEvent(testNode.childNodes[0], 'change') + testNode.children[0].value = '1234' + triggerEvent(testNode.children[0], 'change') expect(validValue()).toEqual('1234') expect(isValid()).toEqual(true) - expect(testNode.childNodes[0].value).toEqual('1234') + expect(testNode.children[0].value).toEqual('1234') }) it('Should ignore node changes when bound to a read-only observable', function () { @@ -133,11 +133,11 @@ describe('Binding: TextInput', function () { testNode.innerHTML = "" applyBindings(vm, testNode) - expect(testNode.childNodes[0].value).toEqual('zzz') + expect(testNode.children[0].value).toEqual('zzz') // Change the input value and trigger change event; verify that the view model wasn't changed - testNode.childNodes[0].value = 'yyy' - triggerEvent(testNode.childNodes[0], 'change') + testNode.children[0].value = 'yyy' + triggerEvent(testNode.children[0], 'change') expect(vm.prop).toEqual(computedValue) expect(computedValue()).toEqual('zzz') }) @@ -146,27 +146,27 @@ describe('Binding: TextInput', function () { var model = { modelProperty123: 456 } testNode.innerHTML = "" applyBindings(model, testNode) - expect(testNode.childNodes[0].value).toEqual('456') + expect(testNode.children[0].value).toEqual('456') - testNode.childNodes[0].value = 789 - triggerEvent(testNode.childNodes[0], 'change') + testNode.children[0].value = 789 + triggerEvent(testNode.children[0], 'change') expect(model.modelProperty123).toEqual('789') }) it('Should support alias "textinput"', function () { testNode.innerHTML = "" applyBindings(null, testNode) - expect(testNode.childNodes[0].value).toEqual('123') + expect(testNode.children[0].value).toEqual('123') }) it('Should write to non-observable property values using "textinput" alias', function () { var model = { modelProperty123: 456 } testNode.innerHTML = "" applyBindings(model, testNode) - expect(testNode.childNodes[0].value).toEqual('456') + expect(testNode.children[0].value).toEqual('456') - testNode.childNodes[0].value = 789 - triggerEvent(testNode.childNodes[0], 'change') + testNode.children[0].value = 789 + triggerEvent(testNode.children[0], 'change') expect(model.modelProperty123).toEqual('789') }) @@ -182,13 +182,13 @@ describe('Binding: TextInput', function () { "" + "" applyBindings(model, testNode) - expect(testNode.childNodes[0].value).toEqual('666') - expect(testNode.childNodes[1].value).toEqual('666') - expect(testNode.childNodes[2].value).toEqual('666') + expect(testNode.children[0].value).toEqual('666') + expect(testNode.children[1].value).toEqual('666') + expect(testNode.children[2].value).toEqual('666') // .property - testNode.childNodes[0].value = 667 - triggerEvent(testNode.childNodes[0], 'change') + testNode.children[0].value = 667 + triggerEvent(testNode.children[0], 'change') expect(mySetter.set).toEqual('667') // ["property"] @@ -197,8 +197,8 @@ describe('Binding: TextInput', function () { expect(mySetter.set).toEqual('668') // ['property'] - testNode.childNodes[0].value = 669 - triggerEvent(testNode.childNodes[0], 'change') + testNode.children[0].value = 669 + triggerEvent(testNode.children[0], 'change') expect(mySetter.set).toEqual('669') }) @@ -211,11 +211,11 @@ describe('Binding: TextInput', function () { // Set up a text box whose value is linked to the subproperty of the observable's current value testNode.innerHTML = "" applyBindings(model, testNode) - expect(testNode.childNodes[0].value).toEqual('original value') + expect(testNode.children[0].value).toEqual('original value') model.myprop({ subproperty: newSubproperty }) // Note that myprop (and hence its subproperty) is changed *after* the bindings are applied - testNode.childNodes[0].value = 'Some new value' - triggerEvent(testNode.childNodes[0], 'change') + testNode.children[0].value = 'Some new value' + triggerEvent(testNode.children[0], 'change') // Verify that the change was written to the *new* subproperty, not the one referenced when the bindings were first established expect(newSubproperty()).toEqual('Some new value') @@ -226,17 +226,17 @@ describe('Binding: TextInput', function () { var myObservable = observable(123) testNode.innerHTML = "" applyBindings({ someProp: myObservable }, testNode) - expect(testNode.childNodes[0].value).toEqual('123') + expect(testNode.children[0].value).toEqual('123') - testNode.childNodes[0].value = 'some user-entered value' // setting the value triggers the propertychange event on IE + testNode.children[0].value = 'some user-entered value' // setting the value triggers the propertychange event on IE if (!jasmine.ieVersion || jasmine.ieVersion >= 9) { - triggerEvent(testNode.childNodes[0], 'input') + triggerEvent(testNode.children[0], 'input') } if (jasmine.ieVersion === 9) { // IE 9 responds to the event asynchronously (see #1788) waitsFor(function () { return myObservable() === 'some user-entered value' - }, 50) + }, "Timeout", 50) } else { expect(myObservable()).toEqual('some user-entered value') } @@ -246,12 +246,12 @@ describe('Binding: TextInput', function () { var myobservable = observable(123) testNode.innerHTML = "" applyBindings({ someProp: myobservable }, testNode) - expect(testNode.childNodes[0].value).toEqual('123') + expect(testNode.children[0].value).toEqual('123') - testNode.childNodes[0].focus() - testNode.childNodes[0].value = 'some user-entered value' - testNode.childNodes[1].focus() // focus on a different input to blur the previous one - triggerEvent(testNode.childNodes[0], 'blur') + testNode.children[0].focus() + testNode.children[0].value = 'some user-entered value' + testNode.children[1].focus() // focus on a different input to blur the previous one + triggerEvent(testNode.children[0], 'blur') expect(myobservable()).toEqual('some user-entered value') }) @@ -261,13 +261,13 @@ describe('Binding: TextInput', function () { testNode.innerHTML = "" applyBindings(model, testNode) - testNode.childNodes[0].value = '1234' - triggerEvent(testNode.childNodes[0], 'change') + testNode.children[0].value = '1234' + triggerEvent(testNode.children[0], 'change') expect(model.writtenValue).toEqual('1234') // trigger change event with the same value model.writtenValue = undefined - triggerEvent(testNode.childNodes[0], 'change') + triggerEvent(testNode.children[0], 'change') expect(model.writtenValue).toBeUndefined() }) @@ -281,17 +281,17 @@ describe('Binding: TextInput', function () { applyBindings(model, testNode) // No user change; verify that model isn't changed (note that the view's value may be different) - triggerEvent(testNode.childNodes[0], 'blur') + triggerEvent(testNode.children[0], 'blur') expect(model.writtenValue()).toEqual(originalValue) // A change by the user is written to the model - testNode.childNodes[0].value = '1234' - triggerEvent(testNode.childNodes[0], 'change') + testNode.children[0].value = '1234' + triggerEvent(testNode.children[0], 'change') expect(model.writtenValue()).toEqual('1234') // A change from the model; the model isn't updated even if the view's value is different model.writtenValue(originalValue) - triggerEvent(testNode.childNodes[0], 'blur') + triggerEvent(testNode.children[0], 'blur') expect(model.writtenValue()).toEqual(originalValue) }) @@ -315,8 +315,8 @@ describe('Binding: TextInput', function () { var myObservable = observable('123') testNode.innerHTML = "" applyBindings({ someProp: myObservable }, testNode) - triggerEvent(testNode.childNodes[0], 'keydown') - testNode.childNodes[0].value = 'some user-entered value' + triggerEvent(testNode.children[0], 'keydown') + testNode.children[0].value = 'some user-entered value' expect(myObservable()).toEqual('123') // observable is not changed yet jasmine.Clock.tick(20) @@ -327,12 +327,12 @@ describe('Binding: TextInput', function () { var myObservable = observable('123') testNode.innerHTML = "" applyBindings({ someProp: myObservable }, testNode) - triggerEvent(testNode.childNodes[0], 'keydown') - testNode.childNodes[0].value = 'some user-entered value' + triggerEvent(testNode.children[0], 'keydown') + testNode.children[0].value = 'some user-entered value' // Notification of previous value (unchanged) is ignored myObservable.valueHasMutated() - expect(testNode.childNodes[0].value).toEqual('some user-entered value') + expect(testNode.children[0].value).toEqual('some user-entered value') // Observable is updated to new element value jasmine.Clock.tick(20) @@ -343,12 +343,12 @@ describe('Binding: TextInput', function () { var myObservable = observable('123') testNode.innerHTML = "" applyBindings({ someProp: myObservable }, testNode) - triggerEvent(testNode.childNodes[0], 'keydown') - testNode.childNodes[0].value = 'some user-entered value' + triggerEvent(testNode.children[0], 'keydown') + testNode.children[0].value = 'some user-entered value' // New value is written to input element myObservable('some value from the server') - expect(testNode.childNodes[0].value).toEqual('some value from the server') + expect(testNode.children[0].value).toEqual('some value from the server') // New value remains when event is processed jasmine.Clock.tick(20) @@ -360,17 +360,17 @@ describe('Binding: TextInput', function () { testNode.innerHTML = "" applyBindings(model, testNode) - triggerEvent(testNode.childNodes[0], 'keydown') - testNode.childNodes[0].value = 'some user-entered value' - triggerEvent(testNode.childNodes[0], 'change') + triggerEvent(testNode.children[0], 'keydown') + testNode.children[0].value = 'some user-entered value' + triggerEvent(testNode.children[0], 'change') expect(model.someProp).toEqual('some user-entered value') // it's changed immediately - expect(testNode.childNodes[0]._ko_textInputProcessedEvent).toEqual('change') // using the change event + expect(testNode.children[0]._ko_textInputProcessedEvent).toEqual('change') // using the change event // even after a delay, the keydown event isn't processed model.someProp = undefined jasmine.Clock.tick(20) expect(model.someProp).toBeUndefined() - expect(testNode.childNodes[0]._ko_textInputProcessedEvent).toEqual('change') + expect(testNode.children[0]._ko_textInputProcessedEvent).toEqual('change') }) }) } diff --git a/packages/binding.core/src/options.ts b/packages/binding.core/src/options.ts index 7fd206253..5e038eaf7 100644 --- a/packages/binding.core/src/options.ts +++ b/packages/binding.core/src/options.ts @@ -41,7 +41,7 @@ export var options = { arrayToDomNodeChildrenOptions = {}, captionValue, filteredArray, - previousSelectedValues = [] + previousSelectedValues = new Array() if (!valueAllowUnset) { if (multiple) { diff --git a/packages/binding.core/src/selectedOptions.ts b/packages/binding.core/src/selectedOptions.ts index 0068e58d6..6d61b60cc 100644 --- a/packages/binding.core/src/selectedOptions.ts +++ b/packages/binding.core/src/selectedOptions.ts @@ -13,7 +13,7 @@ export var selectedOptions = { init: function (element, valueAccessor, allBindings) { registerEventHandler(element, 'change', function () { - var value = valueAccessor(), valueToWrite = [] + var value = valueAccessor(), valueToWrite = new Array() arrayForEach(element.getElementsByTagName('option'), function (node) { if (node.selected) { valueToWrite.push(selectExtensions.readValue(node)) } }) diff --git a/packages/binding.foreach/spec/eachBehavior.ts b/packages/binding.foreach/spec/eachBehavior.ts index 90d5667e2..7f3fbdd97 100644 --- a/packages/binding.foreach/spec/eachBehavior.ts +++ b/packages/binding.foreach/spec/eachBehavior.ts @@ -182,7 +182,7 @@ describe('each binding', function () { describe('is empty/conditional', function () { it('sets `elseChainSatisfied` to false for an empty array', function () { var div = $("
") - var obs = [] + var obs = new Array() var view = {obs: obs} applyBindings(view, div[0]) assert.equal(domData.get(div[0], 'conditional').elseChainSatisfied(), false) @@ -485,7 +485,7 @@ describe('observable array changes', function () { var itemNumber = 100 div = $("
") applyBindings(view, div[0]) - var arr = [], i + var arr = new Array(), i for (i = 0; i != itemNumber; ++i) { arr.push({ id: Math.floor(Math.random() * itemNumber), testHtml: 'Item ' + i + '' }) } @@ -511,7 +511,7 @@ describe('observable array changes', function () { var itemNumber = 100 div = $("
") applyBindings(view, div[0]) - var arr = [], i + var arr = new Array(), i for (i = 0; i != itemNumber; ++i) { arr.push({ id: Math.floor(Math.random() * itemNumber), testHtml: 'Item ' + i + '' }) } diff --git a/packages/binding.foreach/src/foreach.ts b/packages/binding.foreach/src/foreach.ts index 1c1b11475..e4e3f3254 100644 --- a/packages/binding.foreach/src/foreach.ts +++ b/packages/binding.foreach/src/foreach.ts @@ -100,11 +100,11 @@ export class ForEachBinding extends AsyncBindingHandler { ;['afterAdd', 'beforeRemove', 'afterQueueFlush', 'beforeQueueFlush'] .forEach(p => { this[p] = settings[p] || this.allBindings.get(p) }) - this.changeQueue = [] - this.firstLastNodesList = [] - this.indexesToDelete = [] + this.changeQueue = new Array() + this.firstLastNodesList = new Array() + this.indexesToDelete = new Array() this.rendering_queued = false - this.pendingDeletes = [] + this.pendingDeletes = new Array() // Expose the conditional so that if the `foreach` data is empty, successive // 'else' bindings will appear. @@ -229,7 +229,7 @@ export class ForEachBinding extends AsyncBindingHandler { } this.endQueueFlush() - this.changeQueue = [] + this.changeQueue = new Array() // Update the conditional exposed on the domData if (isEmpty !== !this.isNotEmpty()) { @@ -297,8 +297,8 @@ export class ForEachBinding extends AsyncBindingHandler { var valuesToAdd = changeItem.isBatch ? changeItem.values : [changeItem.value] var referenceElement = this.getLastNodeBeforeIndex(index) // gather all childnodes for a possible batch insertion - const allChildNodes = [] - const asyncBindingResults = [] + const allChildNodes = new Array() + const asyncBindingResults = new Array() var children for (var i = 0, len = valuesToAdd.length; i < len; ++i) { @@ -336,7 +336,7 @@ export class ForEachBinding extends AsyncBindingHandler { } getNodesForIndex (index) { - let result = [] + let result = new Array() let ptr = this.firstLastNodesList[index].first let last = this.firstLastNodesList[index].last result.push(ptr) @@ -480,7 +480,7 @@ export class ForEachBinding extends AsyncBindingHandler { } if (pd.data && pd.data[PENDING_DELETE_INDEX_SYM] !== undefined) { delete pd.data[PENDING_DELETE_INDEX_SYM] } } - this.pendingDeletes = [] + this.pendingDeletes = new Array() } // We batch our deletion of item indexes in our parallel array. @@ -491,7 +491,7 @@ export class ForEachBinding extends AsyncBindingHandler { for (let i = this.indexesToDelete.length - 1; i >= 0; --i) { this.firstLastNodesList.splice(this.indexesToDelete[i], 1) } - this.indexesToDelete = [] + this.indexesToDelete = new Array() } updateIndexes (fromIndex) { diff --git a/packages/binding.if/src/ConditionalBindingHandler.ts b/packages/binding.if/src/ConditionalBindingHandler.ts index 751fa0912..79673bdf5 100644 --- a/packages/binding.if/src/ConditionalBindingHandler.ts +++ b/packages/binding.if/src/ConditionalBindingHandler.ts @@ -107,8 +107,8 @@ export default class ConditionalBindingHandler extends AsyncBindingHandler { */ cloneIfElseNodes (element, hasElse) { const children = virtualElements.childNodes(element) - const ifNodes = [] - const elseNodes = [] + const ifNodes = new Array() + const elseNodes = new Array() let target = ifNodes for (var i = 0, j = children.length; i < j; ++i) { diff --git a/packages/binding.template/spec/foreachBehaviors.ts b/packages/binding.template/spec/foreachBehaviors.ts index 77363dbf4..3b2acdbb9 100644 --- a/packages/binding.template/spec/foreachBehaviors.ts +++ b/packages/binding.template/spec/foreachBehaviors.ts @@ -192,7 +192,7 @@ describe('Binding: Foreach', function () { it('Should be able to supply afterAdd and beforeRemove callbacks', function () { testNode.innerHTML = "
" var someItems = observableArray(['first child']) - var afterAddCallbackData = [], beforeRemoveCallbackData = [] + var afterAddCallbackData = new Array(), beforeRemoveCallbackData = new Array() applyBindings({ someItems: someItems, myAfterAdd: function (elem, index, value) { afterAddCallbackData.push({ elem: elem, value: value, currentParentClone: elem.parentNode.cloneNode(true) }) }, @@ -219,7 +219,7 @@ describe('Binding: Foreach', function () { expect(testNode.childNodes[0]).toContainHtml('first childadded child') // Remove another item - beforeRemoveCallbackData = [] + beforeRemoveCallbackData = new Array() someItems.shift() expect(beforeRemoveCallbackData.length).toEqual(1) expect(beforeRemoveCallbackData[0].elem).toContainText('added child') @@ -230,7 +230,7 @@ describe('Binding: Foreach', function () { // Try adding the item back; it should be added and not confused with the removed item testNode.childNodes[0].innerHTML = '' // Actually remove *removed* nodes to check that they are not added back in - afterAddCallbackData = [] + afterAddCallbackData = new Array() someItems.push('added child') expect(testNode.childNodes[0]).toContainHtml('added child') expect(afterAddCallbackData.length).toEqual(1) @@ -281,7 +281,7 @@ describe('Binding: Foreach', function () { // Now perform a foreach binding, and see that afterRender gets the output from the preprocessor and bindings testNode.innerHTML = "
[$data]
" var someItems = observableArray(['Alpha', 'Beta']), - callbackReceivedArrayValues = [] + callbackReceivedArrayValues = new Array() applyBindings({ someItems: someItems, callback: function (nodes, arrayValue) { diff --git a/packages/computed/spec/asyncBehaviors.ts b/packages/computed/spec/asyncBehaviors.ts index 8eba3dbd5..89f07ead5 100644 --- a/packages/computed/spec/asyncBehaviors.ts +++ b/packages/computed/spec/asyncBehaviors.ts @@ -31,7 +31,7 @@ describe('Throttled observables', function () { it('Should notify subscribers asynchronously after writes stop for the specified timeout duration', function () { var observable = koObservable('A').extend({ throttle: 100 }) - var notifiedValues = [] + var notifiedValues = new Array() observable.subscribe(function (value) { notifiedValues.push(value) }) @@ -56,7 +56,7 @@ describe('Throttled observables', function () { // Wait until after timeout waitsFor(function () { return notifiedValues.length > 0 - }, 300) + }, "Timeout", 300) runs(function () { expect(notifiedValues.length).toEqual(1) expect(notifiedValues[0]).toEqual('F') @@ -72,7 +72,7 @@ describe('Throttled dependent observables', function () { var asyncDepObs = koComputed(function () { return underlying() }).extend({ throttle: 100 }) - var notifiedValues = [] + var notifiedValues = new Array() asyncDepObs.subscribe(function (value) { notifiedValues.push(value) }) @@ -709,7 +709,7 @@ describe('Rate-limited', function () { onePointOne = koComputed(one).extend({rateLimit: 100}), two = koObservable(false), three = koComputed(function () { return onePointOne() || two() }), - threeNotifications = [] + threeNotifications = new Array() three.subscribe(function (val) { threeNotifications.push(val) @@ -718,7 +718,7 @@ describe('Rate-limited', function () { // The loop shows that the same steps work continuously for (var i = 0; i < 3; i++) { expect(onePointOne() || two() || three()).toEqual(false) - threeNotifications = [] + threeNotifications = new Array() one(true) expect(threeNotifications).toEqual([]) @@ -853,7 +853,7 @@ describe('Deferred', function () { var one = koObservable(false).extend({rateLimit: 100}), two = koObservable(false), three = koComputed(function () { return one() || two() }), - threeNotifications = [] + threeNotifications = new Array() three.subscribe(function (val) { threeNotifications.push(val) @@ -862,7 +862,7 @@ describe('Deferred', function () { // The loop shows that the same steps work continuously for (var i = 0; i < 3; i++) { expect(one() || two() || three()).toEqual(false) - threeNotifications = [] + threeNotifications = new Array() one(true) expect(threeNotifications).toEqual([]) diff --git a/packages/computed/spec/computedObservableBehaviors.ts b/packages/computed/spec/computedObservableBehaviors.ts index ca26bc0d0..1cc5b0e4b 100644 --- a/packages/computed/spec/computedObservableBehaviors.ts +++ b/packages/computed/spec/computedObservableBehaviors.ts @@ -241,7 +241,7 @@ describe('Dependent Observable', function () { it('Should notify "spectator" subscribers about changes', function () { var obs = new observable() var comp = computed(() => obs()) - var notifiedValues = [] + var notifiedValues = new Array() comp.subscribe(function (value) { notifiedValues.push(value) }, null, 'spectate') @@ -264,7 +264,7 @@ describe('Dependent Observable', function () { }) it('Should only update once when each dependency changes, even if evaluation calls the dependency multiple times', function () { - var notifiedValues = [] + var notifiedValues = new Array() var observableInstance = new observable() var dependantObservable = computed(function () { return observableInstance() * observableInstance() }) dependantObservable.subscribe(function (value) { notifiedValues.push(value) }) @@ -563,7 +563,7 @@ describe('Dependent Observable', function () { }) it('Should expose a "notify" extender that can configure a computed to notify on all changes', function () { - var notifiedValues = [] + var notifiedValues = new Array() var observableInstance = observable(1) var computedInstance = computed(function () { return observableInstance() }) computedInstance.subscribe(function (value) { notifiedValues.push(value) }) diff --git a/packages/computed/spec/pureComputedBehaviors.ts b/packages/computed/spec/pureComputedBehaviors.ts index 11228d749..91b712fc1 100644 --- a/packages/computed/spec/pureComputedBehaviors.ts +++ b/packages/computed/spec/pureComputedBehaviors.ts @@ -102,7 +102,7 @@ describe('Pure Computed', function () { var obs = new observable('A') var computed = pureComputed(obs) var computed2 = pureComputed(computed) - var notifiedValues = [] + var notifiedValues = new Array() computed.subscribe(function (value) { notifiedValues.push(value) @@ -164,7 +164,7 @@ describe('Pure Computed', function () { it('Should awaken and perform dependency detection when subscribed to', function () { var data = observable('A'), computedInstance = pureComputed(data), - notifiedValues = [] + notifiedValues = new Array() // Subscribe to computed; the dependency should now be tracked computedInstance.subscribe(function (value) { notifiedValues.push(value) }) @@ -226,7 +226,7 @@ describe('Pure Computed', function () { var timesEvaluated = 0, data = observable('A'), computedInstance = pureComputed(function () { ++timesEvaluated; return data() }), - notifiedValues = [], + notifiedValues = new Array(), subscribeFunc = function (value) { notifiedValues.push(value) }, subscription @@ -444,7 +444,7 @@ describe('Pure Computed', function () { var data, dataPureComputed function subscribeAndUpdate (computedInstance, newDataValue, expectedNotifiedValues) { - var notifiedValues = [] + var notifiedValues = new Array() computedInstance.subscribe(function (value) { notifiedValues.push(value) }) data(newDataValue) diff --git a/packages/computed/src/computed.ts b/packages/computed/src/computed.ts index 6e8d7bf2c..c9951e29c 100644 --- a/packages/computed/src/computed.ts +++ b/packages/computed/src/computed.ts @@ -189,7 +189,7 @@ computed.fn = { getDependencies () { const dependencyTracking = this[computedState].dependencyTracking - const dependentObservables = [] + const dependentObservables = new Array() objectForEach(dependencyTracking, function (id, dependency) { dependentObservables[dependency._order] = dependency._target @@ -463,7 +463,7 @@ var pureComputedOverrides = { } } else { // First put the dependencies in order - var dependenciesOrder = [] + var dependenciesOrder = new Array() objectForEach(state.dependencyTracking, function (id, dependency) { dependenciesOrder[dependency._order] = id }) diff --git a/packages/lifecycle/src/LifeCycle.ts b/packages/lifecycle/src/LifeCycle.ts index 20a3b018f..fb956cbd8 100644 --- a/packages/lifecycle/src/LifeCycle.ts +++ b/packages/lifecycle/src/LifeCycle.ts @@ -86,7 +86,7 @@ export default class LifeCycle { dispose () { const subscriptions = this[SUBSCRIPTIONS] || [] subscriptions.forEach(s => s.dispose()) - this[SUBSCRIPTIONS] = [] + this[SUBSCRIPTIONS] = new Array() this[ANCHOR_NODE] = null } diff --git a/packages/observable/spec/observableArrayBehaviors.ts b/packages/observable/spec/observableArrayBehaviors.ts index ee5610dd1..a0cae2d83 100644 --- a/packages/observable/spec/observableArrayBehaviors.ts +++ b/packages/observable/spec/observableArrayBehaviors.ts @@ -8,11 +8,11 @@ describe('Observable Array', function () { beforeEach(function () { testObservableArray = observableArray([1, 2, 3]) - notifiedValues = [] + notifiedValues = new Array() testObservableArray.subscribe(function (value) { notifiedValues.push(value ? value.slice(0) : value) }) - beforeNotifiedValues = [] + beforeNotifiedValues = new Array() testObservableArray.subscribe(function (value) { beforeNotifiedValues.push(value ? value.slice(0) : value) }, null, 'beforeChange') @@ -140,7 +140,7 @@ describe('Observable Array', function () { it('Should notify subscribers on remove by value', function () { testObservableArray(['Alpha', 'Beta', 'Gamma']) - notifiedValues = [] + notifiedValues = new Array() var removed = testObservableArray.remove('Beta') expect(removed).toEqual(['Beta']) expect(notifiedValues).toEqual([['Alpha', 'Gamma']]) @@ -148,7 +148,7 @@ describe('Observable Array', function () { it('Should notify subscribers on remove by predicate', function () { testObservableArray(['Alpha', 'Beta', 'Gamma']) - notifiedValues = [] + notifiedValues = new Array() var removed = testObservableArray.remove(function (value) { return value == 'Beta' }) expect(removed).toEqual(['Beta']) expect(notifiedValues).toEqual([['Alpha', 'Gamma']]) @@ -156,7 +156,7 @@ describe('Observable Array', function () { it('Should notify subscribers on remove multiple by value', function () { testObservableArray(['Alpha', 'Beta', 'Gamma']) - notifiedValues = [] + notifiedValues = new Array() var removed = testObservableArray.removeAll(['Gamma', 'Alpha']) expect(removed).toEqual(['Alpha', 'Gamma']) expect(notifiedValues).toEqual([['Beta']]) @@ -164,7 +164,7 @@ describe('Observable Array', function () { it('Should clear observable array entirely if you pass no args to removeAll()', function () { testObservableArray(['Alpha', 'Beta', 'Gamma']) - notifiedValues = [] + notifiedValues = new Array() var removed = testObservableArray.removeAll() expect(removed).toEqual(['Alpha', 'Beta', 'Gamma']) expect(notifiedValues).toEqual([[]]) @@ -172,7 +172,7 @@ describe('Observable Array', function () { it('Should notify "beforeChange" subscribers before remove', function () { testObservableArray(['Alpha', 'Beta', 'Gamma']) - beforeNotifiedValues = [] + beforeNotifiedValues = new Array() var removed = testObservableArray.remove('Beta') expect(removed).toEqual(['Beta']) expect(beforeNotifiedValues).toEqual([['Alpha', 'Beta', 'Gamma']]) @@ -180,7 +180,7 @@ describe('Observable Array', function () { it('Should not notify subscribers on remove by value with no match', function () { testObservableArray(['Alpha', 'Beta', 'Gamma']) - notifiedValues = [] + notifiedValues = new Array() var removed = testObservableArray.remove('Delta') expect(removed).toEqual([]) expect(notifiedValues).toEqual([]) @@ -188,7 +188,7 @@ describe('Observable Array', function () { it('Should not notify "beforeChange" subscribers before remove by value with no match', function () { testObservableArray(['Alpha', 'Beta', 'Gamma']) - beforeNotifiedValues = [] + beforeNotifiedValues = new Array() var removed = testObservableArray.remove('Delta') expect(removed).toEqual([]) expect(beforeNotifiedValues).toEqual([]) @@ -197,7 +197,7 @@ describe('Observable Array', function () { it('Should modify original array on remove', function () { var originalArray = ['Alpha', 'Beta', 'Gamma'] testObservableArray(originalArray) - notifiedValues = [] + notifiedValues = new Array() testObservableArray.remove('Beta') expect(originalArray).toEqual(['Alpha', 'Gamma']) }) @@ -205,7 +205,7 @@ describe('Observable Array', function () { it('Should modify original array on removeAll', function () { var originalArray = ['Alpha', 'Beta', 'Gamma'] testObservableArray(originalArray) - notifiedValues = [] + notifiedValues = new Array() testObservableArray.removeAll() expect(originalArray).toEqual([]) }) @@ -213,7 +213,7 @@ describe('Observable Array', function () { it('Should remove matching observable items', function () { var x = observable(), y = observable() testObservableArray([x, y]) - notifiedValues = [] + notifiedValues = new Array() var removed = testObservableArray.remove(y) expect(testObservableArray()).toEqual([x]) expect(removed).toEqual([y]) @@ -222,7 +222,7 @@ describe('Observable Array', function () { it('Should throw an exception if matching array item moved or removed during "remove"', function () { testObservableArray(['Alpha', 'Beta', 'Gamma']) - notifiedValues = [] + notifiedValues = new Array() expect(function () { testObservableArray.remove(function (value) { if (value === 'Beta') { @@ -236,14 +236,14 @@ describe('Observable Array', function () { it('Should notify subscribers on replace', function () { testObservableArray(['Alpha', 'Beta', 'Gamma']) - notifiedValues = [] + notifiedValues = new Array() testObservableArray.replace('Beta', 'Delta') expect(notifiedValues).toEqual([['Alpha', 'Delta', 'Gamma']]) }) it('Should notify "beforeChange" subscribers before replace', function () { testObservableArray(['Alpha', 'Beta', 'Gamma']) - beforeNotifiedValues = [] + beforeNotifiedValues = new Array() testObservableArray.replace('Beta', 'Delta') expect(beforeNotifiedValues).toEqual([['Alpha', 'Beta', 'Gamma']]) }) @@ -297,7 +297,7 @@ describe('Observable Array', function () { it('Should return a new sorted array from "sorted"', function () { // set some unsorted values so we can see that the new array is sorted testObservableArray([ 5, 7, 3, 1 ]) - notifiedValues = [] + notifiedValues = new Array() var newArray = testObservableArray.sorted() expect(newArray).toEqual([ 1, 3, 5, 7 ]) diff --git a/packages/observable/spec/observableArrayChangeTrackingBehaviors.ts b/packages/observable/spec/observableArrayChangeTrackingBehaviors.ts index 9549c7236..bc6361592 100644 --- a/packages/observable/spec/observableArrayChangeTrackingBehaviors.ts +++ b/packages/observable/spec/observableArrayChangeTrackingBehaviors.ts @@ -13,8 +13,8 @@ function captureCompareArraysCalls (callback) { callLog.push(Array.prototype.slice.call(arguments, 0)) return origCompareArrays.apply(this, arguments) }, - // aliases = [], - callLog = [] + // aliases = new Array(), + callLog = new Array() trackArrayChanges.compareArrays = interceptedCompareArrays diff --git a/packages/observable/spec/observableBehaviors.ts b/packages/observable/spec/observableBehaviors.ts index 69734c76e..afc60c134 100644 --- a/packages/observable/spec/observableBehaviors.ts +++ b/packages/observable/spec/observableBehaviors.ts @@ -97,7 +97,7 @@ describe('Observable', function () { it('Should notify subscribers about each new value', function () { var instance = observable() - var notifiedValues = [] + var notifiedValues = new Array() instance.subscribe(function (value) { notifiedValues.push(value) }) @@ -110,7 +110,7 @@ describe('Observable', function () { it('Should notify "spectator" subscribers about each new value', function () { var instance = observable() - var notifiedValues = [] + var notifiedValues = new Array() instance.subscribe(function (value) { notifiedValues.push(value) }, null, 'spectate') @@ -122,7 +122,7 @@ describe('Observable', function () { it('Should be able to tell it that its value has mutated, at which point it notifies subscribers', function () { var instance = observable() - var notifiedValues = [] + var notifiedValues = new Array() instance.subscribe(function (value) { notifiedValues.push(value.childProperty) }) @@ -140,7 +140,7 @@ describe('Observable', function () { it('Should notify "beforeChange" subscribers before each new value', function () { var instance = observable() - var notifiedValues = [] + var notifiedValues = new Array() instance.subscribe(function (value) { notifiedValues.push(value) }, null, 'beforeChange') @@ -155,7 +155,7 @@ describe('Observable', function () { it('Should be able to tell it that its value will mutate, at which point it notifies "beforeChange" subscribers', function () { var instance = observable() - var notifiedValues = [] + var notifiedValues = new Array() instance.subscribe(function (value) { notifiedValues.push(value ? value.childProperty : value) }, null, 'beforeChange') @@ -177,7 +177,7 @@ describe('Observable', function () { it('Should ignore writes when the new value is primitive and strictly equals the old value', function () { var instance = observable() - var notifiedValues = [] + var notifiedValues = new Array() instance.subscribe(notifiedValues.push, notifiedValues) for (var i = 0; i < 3; i++) { @@ -193,7 +193,7 @@ describe('Observable', function () { it('Should ignore writes when both the old and new values are strictly null', function () { var instance = observable(null) - var notifiedValues = [] + var notifiedValues = new Array() instance.subscribe(notifiedValues.push, notifiedValues) instance(null) expect(notifiedValues).toEqual([]) @@ -201,7 +201,7 @@ describe('Observable', function () { it('Should ignore writes when both the old and new values are strictly undefined', function () { var instance = observable(undefined) - var notifiedValues = [] + var notifiedValues = new Array() instance.subscribe(notifiedValues.push, notifiedValues) instance(undefined) expect(notifiedValues).toEqual([]) @@ -212,7 +212,7 @@ describe('Observable', function () { // all objects as new values. To override this, set an "equalityComparer" callback var constantObject = {} var instance = observable(constantObject) - var notifiedValues = [] + var notifiedValues = new Array() instance.subscribe(notifiedValues.push, notifiedValues) instance(constantObject) expect(notifiedValues).toEqual([constantObject]) @@ -220,7 +220,7 @@ describe('Observable', function () { it('Should notify subscribers of a change even when an identical primitive is written if you\'ve set the equality comparer to null', function () { var instance = observable('A') - var notifiedValues = [] + var notifiedValues = new Array() instance.subscribe(notifiedValues.push, notifiedValues) // No notification by default @@ -239,7 +239,7 @@ describe('Observable', function () { return !(a && b) ? a === b : a.id == b.id } - var notifiedValues = [] + var notifiedValues = new Array() instance.subscribe(notifiedValues.push, notifiedValues) instance({ id: 1 }) @@ -272,7 +272,7 @@ describe('Observable', function () { it('Should expose a "notify" extender that can configure the observable to notify on all writes, even if the value is unchanged', function () { var instance = observable() - var notifiedValues = [] + var notifiedValues = new Array() instance.subscribe(notifiedValues.push, notifiedValues) instance(123) @@ -295,7 +295,7 @@ describe('Observable', function () { it('Should be possible to replace notifySubscribers with a custom handler', function () { var instance = observable(123) - var interceptedNotifications = [] + var interceptedNotifications = new Array() instance.subscribe(function () { throw new Error('Should not notify subscribers by default once notifySubscribers is overridden') }) instance.notifySubscribers = function (newValue, eventName) { interceptedNotifications.push({ eventName: eventName || 'None', value: newValue }) diff --git a/packages/observable/spec/subscribableBehaviors.ts b/packages/observable/spec/subscribableBehaviors.ts index b84f1671c..21ca95882 100644 --- a/packages/observable/spec/subscribableBehaviors.ts +++ b/packages/observable/spec/subscribableBehaviors.ts @@ -119,7 +119,7 @@ describe('Subscribable', function () { it('Should be possible to replace notifySubscribers with a custom handler', function () { var instance = new subscribable() - var interceptedNotifications = [] + var interceptedNotifications = new Array() instance.subscribe(function () { throw new Error('Should not notify subscribers by default once notifySubscribers is overridden') }) instance.notifySubscribers = function (newValue, eventName) { interceptedNotifications.push({ eventName: eventName, value: newValue }) diff --git a/packages/observable/src/dependencyDetection.ts b/packages/observable/src/dependencyDetection.ts index ca900c89a..867bd1741 100644 --- a/packages/observable/src/dependencyDetection.ts +++ b/packages/observable/src/dependencyDetection.ts @@ -6,7 +6,7 @@ // import { isSubscribable } from './subscribableSymbol' -const outerFrames = [] +const outerFrames = new Array() let currentFrame let lastId = 0 diff --git a/packages/observable/src/observableArray.changeTracking.ts b/packages/observable/src/observableArray.changeTracking.ts index 795e48562..404c3ba84 100644 --- a/packages/observable/src/observableArray.changeTracking.ts +++ b/packages/observable/src/observableArray.changeTracking.ts @@ -80,12 +80,12 @@ export function trackArrayChanges (target, options) { // Each time the array changes value, capture a clone so that on the next // change it's possible to produce a diff - var previousContents = [].concat(target.peek() === undefined ? [] : target.peek()) + var previousContents = new Array().concat(target.peek() === undefined ? [] : target.peek()) cachedDiff = null arrayChangeSubscription = target.subscribe(function (currentContents) { let changes // Make a copy of the current contents and ensure it's an array - currentContents = [].concat(currentContents || []) + currentContents = new Array().concat(currentContents || []) // Compute the diff and issue notifications, but only if someone is listening if (target.hasSubscriptionsForEvent(arrayChangeEventName)) { @@ -121,7 +121,7 @@ export function trackArrayChanges (target, options) { if (!trackingChanges || pendingNotifications) { return } - var diff = [], + var diff = new Array(), arrayLength = rawArray.length, argsLength = args.length, offset = 0 @@ -153,7 +153,7 @@ export function trackArrayChanges (target, options) { endDeleteIndex = argsLength === 1 ? arrayLength : Math.min(startIndex + (args[1] || 0), arrayLength), endAddIndex = startIndex + argsLength - 2, endIndex = Math.max(endDeleteIndex, endAddIndex), - additions = [], deletions = [] + additions = new Array(), deletions = new Array() for (let index = startIndex, argsIndex = 2; index < endIndex; ++index, ++argsIndex) { if (index < endDeleteIndex) { deletions.push(pushDiff('deleted', rawArray[index], index)) } if (index < endAddIndex) { additions.push(pushDiff('added', args[argsIndex], index)) } diff --git a/packages/observable/src/observableArray.ts b/packages/observable/src/observableArray.ts index 1fd248a62..0d5d39620 100644 --- a/packages/observable/src/observableArray.ts +++ b/packages/observable/src/observableArray.ts @@ -30,7 +30,7 @@ export function isObservableArray (instance) { observableArray.fn = { remove (valueOrPredicate) { var underlyingArray = this.peek() - var removedValues = [] + var removedValues = new Array() var predicate = typeof valueOrPredicate === 'function' && !isObservable(valueOrPredicate) ? valueOrPredicate : function (value) { return value === valueOrPredicate } for (var i = 0; i < underlyingArray.length; i++) { var value = underlyingArray[i] diff --git a/packages/observable/src/subscribable.ts b/packages/observable/src/subscribable.ts index 0101b39de..9a1abdd76 100644 --- a/packages/observable/src/subscribable.ts +++ b/packages/observable/src/subscribable.ts @@ -56,7 +56,7 @@ var ko_subscribable_fn = { } if (!this._subscriptions[event]) { - this._subscriptions[event] = [] + this._subscriptions[event] = new Array() } this._subscriptions[event].push(subscriptionInstance) diff --git a/packages/provider.bindingstring/src/BindingStringProvider.ts b/packages/provider.bindingstring/src/BindingStringProvider.ts index 598028fe0..2a05e1284 100644 --- a/packages/provider.bindingstring/src/BindingStringProvider.ts +++ b/packages/provider.bindingstring/src/BindingStringProvider.ts @@ -23,7 +23,7 @@ export default class BindingStringProvider extends Provider { const handler = this.bindingHandlers.get(handlerName) if (handler && handler.preprocess) { - const bindingsAddedByHandler = [] + const bindingsAddedByHandler = new Array() const chainFn = (...args) => bindingsAddedByHandler.push(args) value = handler.preprocess(value, key, chainFn) for (const [key, value] of bindingsAddedByHandler) { diff --git a/packages/provider.component/spec/customElementBehaviors.ts b/packages/provider.component/spec/customElementBehaviors.ts index 1030f2fab..542e4a45b 100644 --- a/packages/provider.component/spec/customElementBehaviors.ts +++ b/packages/provider.component/spec/customElementBehaviors.ts @@ -234,7 +234,7 @@ describe('Components: Custom elements', function () { }) it('Supplies an empty params object (with empty $raw) if a custom element has an empty whitespace params attribute', function () { - var suppliedParams = [] + var suppliedParams = new Array() components.register('test-component', { template: 'Ignored', viewModel: function (params) { suppliedParams.push(params) } diff --git a/packages/provider.multi/src/MultiProvider.ts b/packages/provider.multi/src/MultiProvider.ts index 277198b65..078722258 100644 --- a/packages/provider.multi/src/MultiProvider.ts +++ b/packages/provider.multi/src/MultiProvider.ts @@ -10,8 +10,8 @@ export default class MultiProvider extends Provider { super(params) const providers = params.providers || [] this.nodeTypeMap = {} - this.nodeTypes = [] - this.providers = [] + this.nodeTypes = new Array() + this.providers = new Array() providers.forEach(p => this.addProvider(p)) } @@ -25,7 +25,7 @@ export default class MultiProvider extends Provider { provider.globals = this.globals const nodeTypeMap = this.nodeTypeMap for (const nodeType of provider.FOR_NODE_TYPES) { - if (!nodeTypeMap[nodeType]) { nodeTypeMap[nodeType] = [] } + if (!nodeTypeMap[nodeType]) { nodeTypeMap[nodeType] = new Array() } nodeTypeMap[nodeType].push(provider) } this.nodeTypes = Object.keys(this.nodeTypeMap).map(k => parseInt(k, 10)) diff --git a/packages/utils.component/spec/defaultLoaderBehaviors.ts b/packages/utils.component/spec/defaultLoaderBehaviors.ts index d67a01725..f7dc81552 100644 --- a/packages/utils.component/spec/defaultLoaderBehaviors.ts +++ b/packages/utils.component/spec/defaultLoaderBehaviors.ts @@ -88,7 +88,7 @@ describe('Components: Default loader', function () { var templateProviderCallback, viewModelProviderCallback, createViewModelFunction = function () {}, - domNodeArray = [], + domNodeArray = new Array(), didResolveDefinition = false, config = { template: { diff --git a/packages/utils.component/spec/loaderRegistryBehaviors.ts b/packages/utils.component/spec/loaderRegistryBehaviors.ts index cad2b0da1..a70c91b5f 100644 --- a/packages/utils.component/spec/loaderRegistryBehaviors.ts +++ b/packages/utils.component/spec/loaderRegistryBehaviors.ts @@ -90,7 +90,7 @@ describe('Components: Loader registry', function () { }) it("issues a PEBKAC when a component name does not have a dash", function () { - const logs = [] + const logs = new Array() const orlog = console.log console.log = (v) => logs.push(v) @@ -103,7 +103,7 @@ describe('Components: Loader registry', function () { }) it("does not issue a PEBCAK when `ignoreCustomElementWarning` is true", function () { - const logs = [] + const logs = new Array() const orlog = console.log console.log = (v) => logs.push(v) @@ -351,9 +351,9 @@ describe('Components: Loader registry', function () { it('Only commences a single loading process, even if multiple requests arrive before loading has completed', function () { // Set up a mock AMD environment that logs calls - var someModuleTemplate = [], + var someModuleTemplate = new Array(), someComponentModule = { template: someModuleTemplate }, - requireCallLog = [] + requireCallLog = new Array() this.restoreAfter(window, 'require') window.require = function (modules, callback) { requireCallLog.push(modules.slice(0)) diff --git a/packages/utils.jsx/spec/jsxBehaviors.ts b/packages/utils.jsx/spec/jsxBehaviors.ts index 735c003df..5f5695644 100644 --- a/packages/utils.jsx/spec/jsxBehaviors.ts +++ b/packages/utils.jsx/spec/jsxBehaviors.ts @@ -66,7 +66,7 @@ class JsxTestObserver extends JsxObserver { */ function jsxToNode (jsx, xmlns?, node = document.createElement('div')) : HTMLElement { new JsxTestObserver(jsx, node, null, xmlns) - return node.childNodes[0] as HTMLElement + return node.children[0] as HTMLElement } describe('jsx', function () { @@ -225,8 +225,8 @@ describe('jsx', function () { assert.instanceOf(node.childNodes[0], SVGElement) assert.lengthOf(node.childNodes, 2) obs({ elementName: 'rect', children: [], attributes: {} }) - assert.equal(node.childNodes[1].tagName, 'rect') - assert.instanceOf(node.childNodes[1], SVGElement) + assert.equal(node.children[1].tagName, 'rect') + assert.instanceOf(node.children[1], SVGElement) assert.equal(node.outerHTML, '') }) @@ -957,7 +957,7 @@ describe('jsx', function () { }) describe('$context', () => { - function testContext (jsxConvertible, nodeToTest = n => n.childNodes[0]) { + function testContext (jsxConvertible, nodeToTest = n => n.children[0]) { const parent = document.createElement('div') const view = {} options.bindingProviderInstance = new VirtualProvider() @@ -994,7 +994,7 @@ describe('jsx', function () { children: [ { elementName: 'y', children: [], attributes: {} } ], attributes: {} } - testContext(jsx, n => n.childNodes[0].childNodes[0]) + testContext(jsx, n => n.children[0].children[0]) }) it('applies to observable jsx children', () => { @@ -1005,7 +1005,7 @@ describe('jsx', function () { ), attributes: {} } - testContext(jsx, n => n.childNodes[0].childNodes[0]) + testContext(jsx, n => n.children[0].children[0]) }) it('applies to jsx children that are observable', () => { @@ -1016,14 +1016,14 @@ describe('jsx', function () { ], attributes: {} }) - testContext(jsx, n => n.childNodes[0].childNodes[0]) + testContext(jsx, n => n.children[0].children[0]) }) it('applies to observables when they are updated', () => { const obs = observable() testContext(obs, n => { obs({ elementName: 'x', children: [], attributes: {} }) - return n.childNodes[0] + return n.children[0] }) }) }) diff --git a/packages/utils.jsx/src/JsxObserver.ts b/packages/utils.jsx/src/JsxObserver.ts index 1d5e67d69..8d81dc73f 100644 --- a/packages/utils.jsx/src/JsxObserver.ts +++ b/packages/utils.jsx/src/JsxObserver.ts @@ -153,8 +153,8 @@ export class JsxObserver extends LifeCycle { * - sorted by index in ascending order */ observableArrayChange (changes) { - let adds = [] - let dels = [] + let adds = new Array() + let dels = new Array() for (const index in changes) { const change = changes[index] if (change.status === 'added') { @@ -186,7 +186,7 @@ export class JsxObserver extends LifeCycle { const observer = new JsxObserver(jsx, parentNode, nextNode, xmlns, this.noInitialBinding) nodeArrayOrObservable = [observer] } else if (typeof jsx !== 'string' && isIterable(jsx)) { - nodeArrayOrObservable = [] + nodeArrayOrObservable = new Array() for (const child of jsx) { nodeArrayOrObservable.unshift( this.injectNode(child, nextNode)) @@ -230,7 +230,7 @@ export class JsxObserver extends LifeCycle { getSubscriptionsForNode (node) { if (!this.subscriptionsForNode.has(node)) { - const subscriptions = [] + const subscriptions = new Array() this.subscriptionsForNode.set(node, subscriptions) return subscriptions } diff --git a/packages/utils.jsx/src/jsxClean.ts b/packages/utils.jsx/src/jsxClean.ts index 17359dc7a..96762adfd 100644 --- a/packages/utils.jsx/src/jsxClean.ts +++ b/packages/utils.jsx/src/jsxClean.ts @@ -4,7 +4,7 @@ import { const DELAY_MS = 25 const MAX_CLEAN_AT_ONCE = 1000 -const cleanNodeQueue = [] +const cleanNodeQueue = new Array() let cleanNodeTimeoutID = null export function queueCleanNode (node) { diff --git a/packages/utils.parser/spec/identifierBehaviors.ts b/packages/utils.parser/spec/identifierBehaviors.ts index 81c4ea55a..f6f485f60 100644 --- a/packages/utils.parser/spec/identifierBehaviors.ts +++ b/packages/utils.parser/spec/identifierBehaviors.ts @@ -29,6 +29,8 @@ import { Identifier, Arguments } from '../dist' +import { assert } from "chai" + describe('Identifier', function () { function testLookup (identifier, $data) { const ctx = new bindingContext($data) @@ -102,7 +104,7 @@ describe('Identifier', function () { }) it('does nothing with empty array references', function () { - var refs = [], + var refs = new Array(), ident = new Identifier({}, 'x', refs) assert.equal(ident.dereference('1', {}), 1) }) diff --git a/packages/utils.parser/spec/namespaceBehaviors.ts b/packages/utils.parser/spec/namespaceBehaviors.ts index bea9cfd8c..97e6b1ef8 100644 --- a/packages/utils.parser/spec/namespaceBehaviors.ts +++ b/packages/utils.parser/spec/namespaceBehaviors.ts @@ -24,6 +24,8 @@ import { Parser } from '../dist'; +import { assert } from "chai" + function ctxStub (ctx) { return { lookup (v) { return ctx ? ctx[v] : null } } } @@ -71,7 +73,7 @@ describe('Parser Namespace', function () { var model = { onClick: function () { clickCalled = true } } node.innerHTML = "" applyBindings(model, node) - triggerEvent(node.childNodes[0], 'click') + triggerEvent(node.children[0], 'click') assert.ok(clickCalled) }) @@ -80,9 +82,9 @@ describe('Parser Namespace', function () { node.innerHTML = "
Hallo
"; applyBindings({ someModelProperty: observable1 }, node); - assert.equal(node.childNodes[0].className, ''); + assert.equal(node.children[0].className, ''); observable1(true); - assert.equal(node.childNodes[0].className, 'myRule'); + assert.equal(node.children[0].className, 'myRule'); }) it('Should set style with style.stylename', function () { @@ -90,12 +92,12 @@ describe('Parser Namespace', function () { node.innerHTML = "
Hallo
"; applyBindings({ colorValue: myObservable }, node); - assert.include(['red', '#ff0000'], node.childNodes[0].style.backgroundColor) + assert.include(['red', '#ff0000'], node.children[0].style.backgroundColor) // Opera returns style color values in #rrggbb notation, unlike other browsers myObservable('green'); - assert.include(['green', '#008000'], node.childNodes[0].style.backgroundColor) + assert.include(['green', '#008000'], node.children[0].style.backgroundColor) myObservable(undefined); - assert.equal(node.childNodes[0].style.backgroundColor, ''); + assert.equal(node.children[0].style.backgroundColor, ''); }) }) }) diff --git a/packages/utils.parser/src/Arguments.ts b/packages/utils.parser/src/Arguments.ts index 2679a9152..06ea4fc04 100644 --- a/packages/utils.parser/src/Arguments.ts +++ b/packages/utils.parser/src/Arguments.ts @@ -8,7 +8,7 @@ export default class Arguments { } get_value (parent, context, globals, node) { - var deReffedArgs = [] + var deReffedArgs = new Array() for (var i = 0, j = this.args.length; i < j; ++i) { deReffedArgs.push(Node.value_of(this.args[i], context, globals, node)) } diff --git a/packages/utils.parser/src/Node.ts b/packages/utils.parser/src/Node.ts index e6396b971..109354fc9 100644 --- a/packages/utils.parser/src/Node.ts +++ b/packages/utils.parser/src/Node.ts @@ -92,8 +92,8 @@ export default class Node { */ static create_root (nodes, debug=false) { // shunting yard algorithm with output to an abstact syntax tree of Nodes - const out = [] - const ops = [] + const out = new Array() + const ops = new Array() for (let i = 0; i < nodes.length; i += 2) { out.push(nodes[i]) // next value const op = nodes[i+1] diff --git a/packages/utils.parser/src/Parameters.ts b/packages/utils.parser/src/Parameters.ts index 91a259a63..6344f04e5 100644 --- a/packages/utils.parser/src/Parameters.ts +++ b/packages/utils.parser/src/Parameters.ts @@ -32,7 +32,7 @@ export default class Parameters { static nodeTreeToNames (node) { // left-associative series of commas produces a tree with children only on the lhs, so we can extract the leaves with a simplified depth-first traversal - const names = [] + const names = new Array() while (node) { if (node instanceof Identifier) { names.push(node.token) diff --git a/packages/utils.parser/src/Parser.ts b/packages/utils.parser/src/Parser.ts index 03ef59e8a..39b117352 100644 --- a/packages/utils.parser/src/Parser.ts +++ b/packages/utils.parser/src/Parser.ts @@ -315,7 +315,7 @@ export default class Parser { } array () { - let array = [] + let array = new Array() let ch = this.ch if (ch === '[') { @@ -407,7 +407,7 @@ export default class Parser { */ filter () { let ch = this.next() - let args = [] + let args = new Array() let nextFilter = function (v) { return v } let name = this.name() @@ -466,7 +466,7 @@ export default class Parser { */ expression (filterable: string | bool = false, allowMultipleValues: bool = true) { let op - let nodes = [] + let nodes = new Array() let ch = this.white() while (ch) { @@ -577,7 +577,7 @@ export default class Parser { * */ funcArguments () { - let args = [] + let args = new Array() let ch = this.next('(') while (ch) { @@ -648,7 +648,7 @@ export default class Parser { dereferences () { let ch = this.white() - let dereferences = [] + let dereferences = new Array() let deref while (ch) { diff --git a/packages/utils.parser/src/preparse.ts b/packages/utils.parser/src/preparse.ts index 1f03ebf13..a38b859cd 100644 --- a/packages/utils.parser/src/preparse.ts +++ b/packages/utils.parser/src/preparse.ts @@ -51,10 +51,10 @@ export default function parseObjectLiteral (objectLiteralString) { str += '\n,' // Split into tokens - var result = [] + var result = new Array() var toks = str.match(bindingToken) var key - var values = [] + var values = new Array() var depth = 0 if (toks.length <= 1) { return [] } @@ -71,7 +71,7 @@ export default function parseObjectLiteral (objectLiteralString) { 'unknown': key || values.join('') }) key = depth = 0 - values = [] + values = new Array() continue } // Simply skip the colon that separates the name and value diff --git a/packages/utils/spec/taskBehaviors.ts b/packages/utils/spec/taskBehaviors.ts index 26e7c73c6..57ab355a2 100644 --- a/packages/utils/spec/taskBehaviors.ts +++ b/packages/utils/spec/taskBehaviors.ts @@ -38,7 +38,7 @@ describe('Tasks', function () { }) it('Should run scheduled tasks in the order they were scheduled', function () { - var runValues : any = [] + var runValues : any = new Array() var func = function (value) { runValues.push(value) } diff --git a/packages/utils/spec/utilsBehaviors.ts b/packages/utils/spec/utilsBehaviors.ts index d96ae4222..a9d9d0fa8 100644 --- a/packages/utils/spec/utilsBehaviors.ts +++ b/packages/utils/spec/utilsBehaviors.ts @@ -75,7 +75,7 @@ describe('arrayRemoveItem', function () { }) it('Should do nothing for empty arrays', function () { - var input = [] + var input = new Array() ko.utils.arrayRemoveItem(input, 'a') expect(input).toEqual([]) }) diff --git a/packages/utils/src/array.ts b/packages/utils/src/array.ts index 1f5047c2f..965a25911 100644 --- a/packages/utils/src/array.ts +++ b/packages/utils/src/array.ts @@ -22,7 +22,7 @@ export function arrayFirst (array, predicate, predicateOwner) { .find(predicate, predicateOwner) } -export function arrayMap (array = [], mapping, thisArg?) { +export function arrayMap (array = new Array(), mapping, thisArg?) { if (arguments.length > 2) { mapping = mapping.bind(thisArg) } return array === null ? [] : Array.from(array, mapping) } @@ -36,7 +36,7 @@ export function arrayRemoveItem (array, itemToRemove) { } } -export function arrayGetDistinctValues (array = []) { +export function arrayGetDistinctValues (array = new Array()) { const seen = new Set() if (array === null) { return [] } return (isArray(array) ? array : [...array]) @@ -73,7 +73,7 @@ export function makeArray (arrayLikeObject) { export function range (min, max) { min = typeof min === 'function' ? min() : min max = typeof max === 'function' ? max() : max - var result = [] + var result = new Array() for (var i = min; i <= max; i++) { result.push(i) } return result } @@ -114,7 +114,7 @@ export function compareArrays (oldArray, newArray, options) { function compareSmallArrayToBigArray (smlArray, bigArray, statusNotInSml, statusNotInBig, options) { var myMin = Math.min, myMax = Math.max, - editDistanceMatrix = [], + editDistanceMatrix = new Array(), smlIndex, smlIndexMax = smlArray.length, bigIndex, bigIndexMax = bigArray.length, compareRange = (bigIndexMax - smlIndexMax) || 1, @@ -124,7 +124,7 @@ function compareSmallArrayToBigArray (smlArray, bigArray, statusNotInSml, status for (smlIndex = 0; smlIndex <= smlIndexMax; smlIndex++) { lastRow = thisRow - editDistanceMatrix.push(thisRow = []) + editDistanceMatrix.push(thisRow = new Array()) bigIndexMaxForRow = myMin(bigIndexMax, smlIndex + compareRange) bigIndexMinForRow = myMax(0, smlIndex - 1) for (bigIndex = bigIndexMinForRow; bigIndex <= bigIndexMaxForRow; bigIndex++) { @@ -143,7 +143,7 @@ function compareSmallArrayToBigArray (smlArray, bigArray, statusNotInSml, status } } - var editScript = [], meMinusOne, notInSml = [], notInBig = [] + var editScript = new Array(), meMinusOne, notInSml = new Array(), notInBig = new Array() for (smlIndex = smlIndexMax, bigIndex = bigIndexMax; smlIndex || bigIndex;) { meMinusOne = editDistanceMatrix[smlIndex][bigIndex] - 1 if (bigIndex && meMinusOne === editDistanceMatrix[smlIndex][bigIndex - 1]) { diff --git a/packages/utils/src/dom/disposal.ts b/packages/utils/src/dom/disposal.ts index 4a6a6fa15..a67b4fb19 100644 --- a/packages/utils/src/dom/disposal.ts +++ b/packages/utils/src/dom/disposal.ts @@ -18,7 +18,7 @@ var cleanableNodeTypesWithDescendants = { 1: true, 9: true } function getDisposeCallbacksCollection (node, createIfNotFound) { var allDisposeCallbacks = domData.get(node, domDataKey) if ((allDisposeCallbacks === undefined) && createIfNotFound) { - allDisposeCallbacks = [] + allDisposeCallbacks = new Array() domData.set(node, domDataKey, allDisposeCallbacks) } return allDisposeCallbacks @@ -54,8 +54,8 @@ function cleanSingleNode (node) { } } -function cleanNodesInList (nodeList, onlyComments) { - const cleanedNodes = [] +function cleanNodesInList (nodeList, onlyComments?) { + const cleanedNodes = new Array() let lastCleanedNode for (var i = 0; i < nodeList.length; i++) { if (!onlyComments || nodeList[i].nodeType === 8) { @@ -100,7 +100,7 @@ export function removeNode (node) { } // Expose supplemental node cleaning functions. -export const otherNodeCleanerFunctions = [] +export const otherNodeCleanerFunctions = new Array() export function addCleaner (fn) { otherNodeCleanerFunctions.push(fn) diff --git a/packages/utils/src/dom/manipulation.ts b/packages/utils/src/dom/manipulation.ts index 6e0fc0f2e..634d27e11 100644 --- a/packages/utils/src/dom/manipulation.ts +++ b/packages/utils/src/dom/manipulation.ts @@ -20,7 +20,7 @@ export function moveCleanedNodesToContainerElement (nodes) { } export function cloneNodes (nodesArray, shouldCleanNodes) { - for (var i = 0, j = nodesArray.length, newNodesArray = []; i < j; i++) { + for (var i = 0, j = nodesArray.length, newNodesArray = new Array(); i < j; i++) { var clonedNode = nodesArray[i].cloneNode(true) newNodesArray.push(shouldCleanNodes ? cleanNode(clonedNode) : clonedNode) } diff --git a/packages/utils/src/object.ts b/packages/utils/src/object.ts index 936c32cb3..31206bd05 100644 --- a/packages/utils/src/object.ts +++ b/packages/utils/src/object.ts @@ -51,7 +51,7 @@ export function getObjectOwnProperty (obj, propName) { } export function clonePlainObjectDeep (obj, seen) { - if (!seen) { seen = [] } + if (!seen) { seen = new Array() } if (!obj || typeof obj !== 'object' || obj.constructor !== Object || diff --git a/packages/utils/src/options.ts b/packages/utils/src/options.ts index 0b6f2fe17..62cc4c282 100644 --- a/packages/utils/src/options.ts +++ b/packages/utils/src/options.ts @@ -61,7 +61,7 @@ class OptionsClass { // Overload getBindingHandler to have a custom lookup function. getBindingHandler (key) : any { return null; } - cleanExternalData (/* node, callback */) {} + cleanExternalData (node, callback?) {} } const options = new OptionsClass() From 4b0b47fcd1b69cb98b0c36c1e959962c4797143c Mon Sep 17 00:00:00 2001 From: phillipc Date: Fri, 3 Jan 2025 21:44:33 +0100 Subject: [PATCH 007/190] Readme) some updates for the current stack --- README.md | 61 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index f0ff49445..23e91da06 100644 --- a/README.md +++ b/README.md @@ -35,51 +35,41 @@ It's available as `@tko/build.knockout`, and over CDN: | Command | Effect | | ------- | ------ | | $ `git clone git@github.com:knockout/tko` | Clone the repository. | -| $ `npm install -g yarn` | Ensure yarn is globally available | -| $ `yarn` | Install local node packages and link tko modules | -| $ `make` | **Currently TKO use a make file** | -| $ `yarn test` | Run all tests. See below. | -| $ `yarn watch` | Run all tests and watch for changes. See below. | -| $ `yarn build` | Build tko\[.module\]\[.es6\]\[.min\].js files, where `.es6` version has not been transpiled | +| $ `npm install` | Ensure that all packages available | +| $ `make` | **Currently TKO use a make file** / no scripts at package.json | +| $ `make test` | Run all tests with electron. See below. | +| $ `make test-headless` | Run all tests with chromium. See below. | | $ `lerna publish` | Bump versions and publish to npm registry | -Checkout `package.json => scripts` for more commands that can be executed with `yarn {command}`. +Checkout the `Makefile` for more commands that can be executed with `make {command}`. -In each individual `packages/*/` directory, you can also run (presuming `rollup` and `karma` are installed globally): +In each individual `packages/*/` directory, you can also run: | Command | Effect | | --- | --- | | $ `karma COMMAND ../../karma.conf.js [--once]` | Test the local package, where COMMAND is e.g. `start` or `run` | -| $ `rollup -c ../../rollup.config.js` | Build the package into the local `dist/` | -#### Testing with `yarn test` and `yarn watch` - -### NEW +### Testing Start tests with electron: `make test` Start tests with headless-chrome: `make test-headless` -### OLD - -The `yarn test` and `yarn watch` commands can be used in the root directory, where it will run across all tests, or alternatively in any `packages/*/` directory to run tests -specific to that package. +The test setup has naturally grown and been ported from knockout.js. Some tests use Jasmine 1.3, newer ones use Mocha, Chai and Sinon. Karma is used as test runner rather as test pipeline -Optional arguments to `yarn test` include: +Other options: -- `--sauce` — use Sauce Labs to test a variety of platforms; requires an account at Sauce Labs and `SAUCE_USERNAME` and `SAUCE_ACCESS_KEY` to be set in the environment. -- `--noStartConnect` — Do not start a new Sauce Connect proxy instance for every -test; requires that Sauce Connect be already running. +- `make ci` — use Sauce Labs to test a variety of platforms; requires an account at Sauce Labs and `SAUCE_USERNAME` and `SAUCE_ACCESS_KEY` to be set in the environment. -#### `visual.html` +#### `visual.html` (possibly outdated) -Note that running `karma` or `rollup` will create a `visual.html` file that shows the proportional size of imports into each package. +Note that running `karma` will create a `visual.html` file that shows the proportional size of imports into each package. -### Objectives +## Objectives TKO aims to become a base for future versions of Knockout. The objectives include: -- Modularization into ES6 and separate projects, with compilation using an ES6 compiler like [Rollup](http://rollupjs.org/). This solves several problems with Knockout, including: +- Modularization into ES6 and separate projects, with compilation using an ES6 compiler like [Esbuild](https://esbuild.github.io/). This solves several problems with Knockout, including: - Some folks want to roll-their-own with e.g. removing components - Compilation is now with Closure compiler, which is actually transliterating – meaning the *debug* and *minified* versions have different code paths (mostly in the form of things exposed in *debug* being missing in the *minified* version) - The compilation of Knockout is just concatenation, leading to difficulties with maintainance, severance, and replacement @@ -90,6 +80,27 @@ TKO aims to become a base for future versions of Knockout. The objectives inclu - What should be simple plugins (e.g. binding handlers or providers) are complex, including: - Built-ins have first-class access to quite a bit of good Knockout code, but plugins generally have second-class access and often have to duplicate Knockout internals - Quality plugins have lots of boilerplate for compilation, release, documentation, and testing +- Type-safe with Typescript +- CSP compliant +- JSX/TSX support + +## Overview of the development stack + +- **make** -> Build tasks +- **npm** -> Node Package Manager +- **esbuild** -> ts/js compiler and bundler +- **lerna** -> mono-repo build-chain + +--- + +- Test-Runner -> Karma +- Test-Environment -> electron and headless-chrome +- TDD/BDD-Frameworks -> + - Jasmine 1.3 + - Mocha + Chai + - sinon (Mocks) +- Testing-Cloud-Service -> sauce +- standard -> Code-Style (outdated for typescript) ## Some WSL tricks @@ -122,6 +133,6 @@ MIT license - [http://www.opensource.org/licenses/mit-license.php.](http://www.o
- Browser Stack + Browser Stack
From 4a25a08ebaa90d89b02e9e6a3b105b677a92d96a Mon Sep 17 00:00:00 2001 From: mcselle Date: Fri, 3 Jan 2025 17:22:28 +0100 Subject: [PATCH 008/190] Observable Typings ... --- global.d.ts | 46 +++++++++++++++++++ .../binding.template/spec/foreachBehaviors.ts | 2 +- packages/observable/src/observable.ts | 2 +- packages/observable/src/observableArray.ts | 39 ++++++++-------- packages/utils.parser/spec/filterBehaviors.ts | 2 + packages/utils.parser/src/Parser.ts | 41 +++++++++++------ packages/utils.parser/src/Ternary.ts | 4 +- packages/utils/src/error.ts | 2 +- 8 files changed, 102 insertions(+), 36 deletions(-) diff --git a/global.d.ts b/global.d.ts index 5e45346f0..be8d041d3 100644 --- a/global.d.ts +++ b/global.d.ts @@ -4,11 +4,56 @@ export { }; + declare global { + export type Observable = { + (): T; // Getter + (value: T): void; // Setter + subscribe(callback: (newValue: T) => void): Subscription; + }; + + export type Subscription = { + dispose(): void; // Unsubscribe method + }; + + export type ObservableArray = Observable & { + remove (valueOrPredicate: any): any[] + removeAll (arrayOfValues: undefined): any + destroy (valueOrPredicate: any): void + destroyAll (arrayOfValues: undefined): any + indexOf (item: any): number + replace (oldItem: any, newItem: any): void + sorted (compareFn: ((a: any, b: any) => number) | undefined): any[] + reversed (): any[] + [Symbol.iterator]: Generator + + // Array-specific methods + push(...items: T[]): number; + pop(): T | undefined; + unshift(...items: T[]): number; + shift(): T | undefined; + splice(start: number, deleteCount?: number, ...items: T[]): T[]; + slice(start?: number, end?: number): T[]; + // remove(item: T): T[]; + // remove(predicate: (item: T) => boolean): T[]; + // removeAll(): T[]; + // removeAll(items: T[]): T[]; + // destroy(item: T): void; + // destroy(predicate: (item: T) => boolean): void; + // destroyAll(): void; + // destroyAll(items: T[]): void; + // replace(oldItem: T, newItem: T): void; + // indexOf(item: T): number; + // sorted(compareFn?: (a: T, b: T) => number): T[]; + // filter(predicate: (item: T) => boolean): T[]; + // map(callback: (item: T) => U): U[]; + }; + var testNode: HTMLElement; var jQueryInstance : JQuery + interface Window { // Below just informs IDE and/or TS-compiler (it's set in `.js` file). DEBUG: boolean @@ -44,6 +89,7 @@ declare global { toEqualOneOf (expectedPossibilities : any) : boolean toContainHtml (expectedHtml : any, postProcessCleanedHtml : any) : boolean toHaveSelectedValues(expectedValues : any) : boolean + toContainHtml(expectedValues:any):boolean } interface Spy { diff --git a/packages/binding.template/spec/foreachBehaviors.ts b/packages/binding.template/spec/foreachBehaviors.ts index 3b2acdbb9..19ed3b8f8 100644 --- a/packages/binding.template/spec/foreachBehaviors.ts +++ b/packages/binding.template/spec/foreachBehaviors.ts @@ -75,7 +75,7 @@ describe('Binding: Foreach', function () { testNode.innerHTML = "
" // Apply some DOM Data to the SPAN - var span = testNode.childNodes[0].childNodes[0] + var span = testNode.childNodes[0].childNodes[0] as HTMLSpanElement expect(span.tagName).toEqual('SPAN') domData.set(span, 'mydata', 123) diff --git a/packages/observable/src/observable.ts b/packages/observable/src/observable.ts index cd4087d5f..7bbe7c6ff 100644 --- a/packages/observable/src/observable.ts +++ b/packages/observable/src/observable.ts @@ -11,7 +11,7 @@ import { deferUpdates } from './defer' import { subscribable, defaultEvent, LATEST_VALUE } from './subscribable' import { valuesArePrimitiveAndEqual } from './extenders' -export function observable (initialValue?: any) { +export function observable (initialValue?: any) :Observable { function Observable () { if (arguments.length > 0) { // Write diff --git a/packages/observable/src/observableArray.ts b/packages/observable/src/observableArray.ts index 0d5d39620..2661d9cce 100644 --- a/packages/observable/src/observableArray.ts +++ b/packages/observable/src/observableArray.ts @@ -10,28 +10,27 @@ import { observable, isObservable } from './observable' import { trackArrayChanges } from './observableArray.changeTracking' -export function observableArray (initialValues) { +export function observableArray (initialValues: (null | undefined)[] | {}[] | (string | { elementName: string; attributes: {}; children: string[][] })[] | ({ name: string; id: Observable } | { name: Observable; id: number })[] | { name: string; job: string }[] | ({ name: string; _destroy: boolean } | { name: string; _destroy?: undefined })[] | { x: string }[] | { x: number }[] | { childprop: string }[] | { x: Observable }[] | ({ childProp: string; _destroy?: undefined } | { childProp: string; _destroy: boolean })[] | { children: ObservableArray }[] | { itemProp: string }[] | ({ name: Observable } | { name: string })[] | ({ personName: string } | { personName: Observable })[] | { obsVal: Observable }[] | ({ someProp: number; _destroy?: undefined } | { someProp: number; _destroy: string } | { someProp: number; _destroy: Observable })[] | { preferredTemplate: number; someProperty: string }[] | undefined): ObservableArray { initialValues = initialValues || [] if (typeof initialValues !== 'object' || !('length' in initialValues)) { throw new Error('The argument passed when initializing an observable array must be an array, or null, or undefined.') } - var result = observable(initialValues) - Object.setPrototypeOf(result, observableArray.fn) + var result = Object.setPrototypeOf(observable(initialValues), observableArray.fn) as ObservableArray trackArrayChanges(result) // ^== result.extend({ trackArrayChanges: true }) overwriteLengthPropertyIfSupported(result, { get: () => result().length }) return result } -export function isObservableArray (instance) { +export function isObservableArray (instance: { remove: any; push: any }) { return isObservable(instance) && typeof instance.remove === 'function' && typeof instance.push === 'function' } observableArray.fn = { - remove (valueOrPredicate) { + remove (valueOrPredicate: any): any[] { var underlyingArray = this.peek() var removedValues = new Array() - var predicate = typeof valueOrPredicate === 'function' && !isObservable(valueOrPredicate) ? valueOrPredicate : function (value) { return value === valueOrPredicate } + var predicate = typeof valueOrPredicate === 'function' && !isObservable(valueOrPredicate) ? valueOrPredicate : function (value: any) { return value === valueOrPredicate } for (var i = 0; i < underlyingArray.length; i++) { var value = underlyingArray[i] if (predicate(value)) { @@ -52,7 +51,7 @@ observableArray.fn = { return removedValues }, - removeAll (arrayOfValues) { + removeAll (arrayOfValues: undefined): any { // If you passed zero args, we remove everything if (arrayOfValues === undefined) { var underlyingArray = this.peek() @@ -66,14 +65,14 @@ observableArray.fn = { if (!arrayOfValues) { return [] } - return this['remove'](function (value) { + return this['remove'](function (value: any) { return arrayIndexOf(arrayOfValues, value) >= 0 }) }, - destroy (valueOrPredicate) { + destroy (valueOrPredicate: any): void { var underlyingArray = this.peek() - var predicate = typeof valueOrPredicate === 'function' && !isObservable(valueOrPredicate) ? valueOrPredicate : function (value) { return value === valueOrPredicate } + var predicate = typeof valueOrPredicate === 'function' && !isObservable(valueOrPredicate) ? valueOrPredicate : function (value: any) { return value === valueOrPredicate } this.valueWillMutate() for (var i = underlyingArray.length - 1; i >= 0; i--) { var value = underlyingArray[i] @@ -84,7 +83,7 @@ observableArray.fn = { this.valueHasMutated() }, - destroyAll (arrayOfValues) { + destroyAll (arrayOfValues: undefined): any { // If you passed zero args, we destroy everything if (arrayOfValues === undefined) { return this.destroy(function () { return true }) } @@ -92,16 +91,16 @@ observableArray.fn = { if (!arrayOfValues) { return [] } - return this.destroy(function (value) { + return this.destroy(function (value: any) { return arrayIndexOf(arrayOfValues, value) >= 0 }) }, - indexOf (item) { + indexOf (item: any): number { return arrayIndexOf(this(), item) }, - replace (oldItem, newItem) { + replace (oldItem: any, newItem: any): void { var index = this.indexOf(oldItem) if (index >= 0) { this.valueWillMutate() @@ -110,25 +109,27 @@ observableArray.fn = { } }, - sorted (compareFn) { + sorted (compareFn: ((a: any, b: any) => number) | undefined): any[] { return [...this()].sort(compareFn) }, - reversed () { + reversed (): any[] { return [...this()].reverse() }, - [Symbol.iterator]: function * () { + [Symbol.iterator]: function * (): Generator { yield * this() } } + + Object.setPrototypeOf(observableArray.fn, observable.fn) // Populate ko.observableArray.fn with read/write functions from native arrays // Important: Do not add any additional functions here that may reasonably be used to *read* data from the array // because we'll eval them without causing subscriptions, so ko.computed output could end up getting stale -arrayForEach(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function (methodName) { +arrayForEach(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function (methodName: string | number) { observableArray.fn[methodName] = function () { // Use "peek" to avoid creating a subscription in any computed that we're executing in the context of // (for consistency with mutating regular observables) @@ -143,7 +144,7 @@ arrayForEach(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], f }) // Populate ko.observableArray.fn with read-only functions from native arrays -arrayForEach(['slice'], function (methodName) { +arrayForEach(['slice'], function (methodName: string | number) { observableArray.fn[methodName] = function () { var underlyingArray = this() return underlyingArray[methodName].apply(underlyingArray, arguments) diff --git a/packages/utils.parser/spec/filterBehaviors.ts b/packages/utils.parser/spec/filterBehaviors.ts index e2180a9b9..21b373c23 100644 --- a/packages/utils.parser/spec/filterBehaviors.ts +++ b/packages/utils.parser/spec/filterBehaviors.ts @@ -12,6 +12,8 @@ import { Parser } from '../dist'; +import { assert } from "chai" + function ctxStub (o) { return { lookup (p) { return o[p] } } } describe('filters', function () { diff --git a/packages/utils.parser/src/Parser.ts b/packages/utils.parser/src/Parser.ts index 39b117352..77fc03d4f 100644 --- a/packages/utils.parser/src/Parser.ts +++ b/packages/utils.parser/src/Parser.ts @@ -29,6 +29,13 @@ const escapee = { t: '\t' } +type InnerFilterType = (value: any, ignored: any, context: any, globals: any, node: any) => any + +type FilterType = (InnerFilterType) & { + precedence:number +} + + /** * Construct a new Parser instance with new Parser(node, context) * @param {Node} node The DOM element from which we parsed the @@ -37,6 +44,11 @@ const escapee = { * @param {object} globals An object containing any desired globals. */ export default class Parser { + ch: any + at: any + text: any + currentContextGlobals: [context:object, globals:object, node:any] + white () { var ch = this.ch while (ch && ch <= ' ') { @@ -75,7 +87,7 @@ export default class Parser { return ch }; - next (c) { + next (c?:string) { if (c && c !== this.ch) { this.error("Expected '" + c + "' but got '" + this.ch + "'") } @@ -248,7 +260,7 @@ export default class Parser { readString (delim) { let string = '' let nodes = [''] - let plusOp = operators['+'] + let plusOp:any = operators['+'] let hex let i let uffff @@ -304,9 +316,9 @@ export default class Parser { string () { var ch = this.ch if (ch === '"') { - return this.readString('"').join('') + return this.readString('"')?.join('') } else if (ch === "'") { - return this.readString("'").join('') + return this.readString("'")?.join('') } else if (ch === '`') { return Node.create_root(this.readString('`')) } @@ -405,14 +417,17 @@ export default class Parser { * e.g. * */ - filter () { + filter (): FilterType + { let ch = this.next() let args = new Array() - let nextFilter = function (v) { return v } + + + let nextFilter: ((any) => any) | InnerFilterType = function (v) { return v }; let name = this.name() if (!options.filters[name]) { - options.onError('Cannot find filter by the name of: ' + name) + options.onError(new Error('Cannot find filter by the name of: ' + name)) } ch = this.white() @@ -464,7 +479,7 @@ export default class Parser { * @returns a function that computes the value of the expression * when called or a primitive. */ - expression (filterable: string | bool = false, allowMultipleValues: bool = true) { + expression (filterable: string | boolean = false, allowMultipleValues: boolean = true) { let op let nodes = new Array() let ch = this.white() @@ -559,7 +574,7 @@ export default class Parser { * @returns an expression that cannot contain multiple values separated by commas. * @see {@link Parser.expression} */ - singleValueExpression (filterable: bool | string) { + singleValueExpression (filterable: boolean | string = false) { return this.expression(filterable, false) } @@ -716,9 +731,9 @@ export default class Parser { bindings[key[0]] = bindings[key[0]] || {} if (key.length !== 2) { - options.onError('Binding ' + key + ' should have two parts (a.b).') + options.onError(new Error('Binding ' + key + ' should have two parts (a.b).')) } else if (bindings[key[0]].constructor !== Object) { - options.onError('Binding ' + key[0] + '.' + key[1] + ' paired with a non-object.') + options.onError(new Error('Binding ' + key[0] + '.' + key[1] + ' paired with a non-object.')) } ch = this.next(':') @@ -730,7 +745,7 @@ export default class Parser { // on.x, now we're seeing on: { 'abc' }. expr = this.singleValueExpression(true) if (typeof expr !== 'object' || expr.constructor !== Object) { - options.onError('Expected plain object for ' + key + ' value.') + options.onError(new Error('Expected plain object for ' + key + ' value.')) } else { extend(bindings[key], expr) } @@ -817,7 +832,7 @@ export default class Parser { } return result } catch (e) { - options.onError(e) + options.onError(e as Error) } } diff --git a/packages/utils.parser/src/Ternary.ts b/packages/utils.parser/src/Ternary.ts index 717727093..5d5009354 100644 --- a/packages/utils.parser/src/Ternary.ts +++ b/packages/utils.parser/src/Ternary.ts @@ -2,7 +2,9 @@ import Node from './Node' export default class Ternary { - constructor (yes, no) { + yes: any + no: any + constructor (yes?, no?) { Object.assign(this, {yes, no}) } diff --git a/packages/utils/src/error.ts b/packages/utils/src/error.ts index 971286dec..397b48f20 100644 --- a/packages/utils/src/error.ts +++ b/packages/utils/src/error.ts @@ -11,7 +11,7 @@ export function catchFunctionErrors (delegate) { try { return delegate(...args) } catch (err) { - options.onError(err) + options.onError(err as Error) } } } From 1081dfb4216f69902ffe256b895d56beb1032bd3 Mon Sep 17 00:00:00 2001 From: mcselle Date: Tue, 7 Jan 2025 14:37:31 +0100 Subject: [PATCH 009/190] Fixed TSC errors in utils --- global.d.ts | 6 ++- packages/utils/index.ts | 2 +- .../utils/spec/domNodeDisposalBehaviors.ts | 6 +-- packages/utils/spec/memoizationBehaviors.ts | 2 +- packages/utils/spec/onErrorBehaviors.ts | 6 +-- .../utils/spec/parseHtmlFragmentBehavior.ts | 8 ++-- packages/utils/spec/utilsBehaviors.ts | 9 +++- packages/utils/src/array.ts | 4 +- packages/utils/src/dom/data.ts | 4 +- packages/utils/src/dom/event.ts | 4 +- packages/utils/src/dom/fixes.ts | 4 +- packages/utils/src/dom/info.ts | 10 ++-- packages/utils/src/dom/manipulation.ts | 46 +++++++++++-------- packages/utils/src/dom/virtualElements.ts | 6 +-- packages/utils/src/ie.ts | 6 ++- packages/utils/src/options.ts | 2 +- 16 files changed, 74 insertions(+), 51 deletions(-) diff --git a/global.d.ts b/global.d.ts index be8d041d3..f0d144b09 100644 --- a/global.d.ts +++ b/global.d.ts @@ -51,7 +51,7 @@ declare global { }; var testNode: HTMLElement; - var jQueryInstance : JQuery + var jQueryInstance : JQueryStatic interface Window { @@ -61,11 +61,15 @@ declare global { require: any jQuery: JQuery jQueryInstance: JQuery + testDivTemplate:HTMLElement + templateOutput:HTMLElement } //Jasmine and Mocha define duplicated functions, is a problem for the type system //This namespace merges the jasmine namespace to correct same tsc warnings namespace jasmine { + + function getGlobal():any; var updateInterval: number function resolve(promise: Promise) function prepareTestNode() diff --git a/packages/utils/index.ts b/packages/utils/index.ts index 30f979941..b60c98e40 100644 --- a/packages/utils/index.ts +++ b/packages/utils/index.ts @@ -1,2 +1,2 @@ export * from './src' -export { default } from './src' +export { options as default } from './src' \ No newline at end of file diff --git a/packages/utils/spec/domNodeDisposalBehaviors.ts b/packages/utils/spec/domNodeDisposalBehaviors.ts index d7abca0d2..de5b9420a 100644 --- a/packages/utils/spec/domNodeDisposalBehaviors.ts +++ b/packages/utils/spec/domNodeDisposalBehaviors.ts @@ -104,8 +104,8 @@ describe('DOM node disposal', function () { }) it('Should continue cleaning if a cleaned node is removed in a handler', function () { - var childNode = document.createElement("DIV"); - var childNode2 = document.createElement("DIV"); + var childNode :Node = document.createElement("DIV"); + var childNode2:Node = document.createElement("DIV"); var removeChildSpy = jasmine.createSpy('removeChildSpy') .andCallFake(function() { testNode.removeChild(childNode); @@ -141,7 +141,7 @@ describe('DOM node disposal', function () { childSpy.reset(); // Test by removing a comment node - var childNode = document.createComment("ko comment"); + var childNode = document.createComment("ko comment") as Node; testNode.appendChild(childNode); testNode.appendChild(childNode2); addDisposeCallback(childNode, removeChildSpy); diff --git a/packages/utils/spec/memoizationBehaviors.ts b/packages/utils/spec/memoizationBehaviors.ts index bafb2c92a..66ab28c2e 100644 --- a/packages/utils/spec/memoizationBehaviors.ts +++ b/packages/utils/spec/memoizationBehaviors.ts @@ -1,7 +1,7 @@ import { memoization } from '../dist' -import {} from "jasmine" +//import { } from "karma-jasmine"; function parseMemoCommentHtml (commentHtml) { commentHtml = commentHtml.replace('', '') diff --git a/packages/utils/spec/onErrorBehaviors.ts b/packages/utils/spec/onErrorBehaviors.ts index 1b1835fd9..4daeed58a 100644 --- a/packages/utils/spec/onErrorBehaviors.ts +++ b/packages/utils/spec/onErrorBehaviors.ts @@ -15,9 +15,9 @@ describe('onError handler', function () { koOnErrorCount++ } - function ensureNodeExistsAndIsEmpty (id, tagName, type) { + function ensureNodeExistsAndIsEmpty (id:string, tagName?:string, type?:string):HTMLElement { var existingNode = document.getElementById(id) - if (existingNode != null) { existingNode.parentNode.removeChild(existingNode) } + if (existingNode != null) { existingNode.parentNode?.removeChild(existingNode) } var resultNode = document.createElement(tagName || 'div') resultNode.id = id if (type) { resultNode.setAttribute('type', type) } @@ -37,7 +37,7 @@ describe('onError handler', function () { // Don't spam the console, since these were triggered deliberately // Annoyingly, Phantom interprets this return value backwardly, treating 'false' // to mean 'suppress', when browsers all use 'true' to mean 'suppress'. - var isPhantom = !!window._phantom + var isPhantom = !!(window as any)._phantom return !isPhantom } }) diff --git a/packages/utils/spec/parseHtmlFragmentBehavior.ts b/packages/utils/spec/parseHtmlFragmentBehavior.ts index 359efd8cb..04d0dc768 100644 --- a/packages/utils/spec/parseHtmlFragmentBehavior.ts +++ b/packages/utils/spec/parseHtmlFragmentBehavior.ts @@ -48,7 +48,7 @@ describe('Parse HTML fragment', function () { // Early out if Simple HTML parser is known to fail for this data. if (!supportsTemplateTag) { if (!jQueryInstance && data.simpleParserFails) { return } - if (jQueryInstance && jQueryInstance.fn.jquery[0] < 3 && + if (jQueryInstance && parseFloat(jQueryInstance.fn.jquery[0]) < 3 && data.OldjQueryFails) { return } } @@ -72,9 +72,9 @@ describe('Parse HTML fragment', function () { var html = '
' var parsedNodes1 = parseHtmlFragment(html, document) var parsedNodes2 = parseHtmlFragment(html, document) - expect(parsedNodes1).toNotEqual(parsedNodes2) - expect(parsedNodes1[0]).toNotEqual(parsedNodes2[0]) + expect(parsedNodes1).not.toEqual(parsedNodes2) + expect(parsedNodes1[0]).not.toEqual(parsedNodes2[0]) // We need to test for deep inequality - expect(parsedNodes1[0].children[0]).toNotEqual(parsedNodes2[0].children[0]) + expect(parsedNodes1[0].children[0]).not.toEqual(parsedNodes2[0].children[0]) }) }) diff --git a/packages/utils/spec/utilsBehaviors.ts b/packages/utils/spec/utilsBehaviors.ts index a9d9d0fa8..d8d0c58ee 100644 --- a/packages/utils/spec/utilsBehaviors.ts +++ b/packages/utils/spec/utilsBehaviors.ts @@ -359,7 +359,7 @@ describe('Function.bind', function () { expect(actual[0]).toEqualOneOf([undefined, global]) expect(actual[1]).toEqual('b') - bound = fn.bind() + bound = fn.bind(null) actual = bound('b') expect(actual[0]).toEqualOneOf([undefined, global]) @@ -446,7 +446,12 @@ describe('cloneNodes', function () { }) it('stringifies recursive objects', () => { - const recursive = { b: 1, c: 1 } + type Recursive = { + b:number; + c:number; + a?:Recursive; + }; + const recursive: Recursive = { b: 1, c: 1 } recursive.a = recursive const expectObj = { b: 1, c: 1, a: '...' } diff --git a/packages/utils/src/array.ts b/packages/utils/src/array.ts index 965a25911..50a8ed795 100644 --- a/packages/utils/src/array.ts +++ b/packages/utils/src/array.ts @@ -6,7 +6,7 @@ const {isArray} = Array -export function arrayForEach (array, action, thisArg) { +export function arrayForEach (array, action, thisArg?) { if (arguments.length > 2) { action = action.bind(thisArg) } for (let i = 0, j = array.length; i < j; ++i) { action(array[i], i, array) @@ -17,7 +17,7 @@ export function arrayIndexOf (array, item) { return (isArray(array) ? array : [...array]).indexOf(item) } -export function arrayFirst (array, predicate, predicateOwner) { +export function arrayFirst (array, predicate, predicateOwner?) { return (isArray(array) ? array : [...array]) .find(predicate, predicateOwner) } diff --git a/packages/utils/src/dom/data.ts b/packages/utils/src/dom/data.ts index 7c15be946..a66aef5e2 100644 --- a/packages/utils/src/dom/data.ts +++ b/packages/utils/src/dom/data.ts @@ -15,7 +15,7 @@ let uniqueId = 0 * on the node. See https://github.com/knockout/knockout/issues/2141 */ const modern = { - getDataForNode (node, createIfNotFound) { + getDataForNode (node : Node, createIfNotFound: boolean) { let dataForNode = node[dataStoreSymbol] if (!dataForNode && createIfNotFound) { dataForNode = node[dataStoreSymbol] = {} @@ -37,7 +37,7 @@ const modern = { * use a separate data storage and link to it from the node using a string key. */ const IE = { - getDataforNode (node, createIfNotFound) { + getDataForNode (node: Node, createIfNotFound: boolean) { let dataStoreKey = node[dataStoreKeyExpandoPropertyName] const hasExistingDataStore = dataStoreKey && (dataStoreKey !== 'null') && dataStore[dataStoreKey] if (!hasExistingDataStore) { diff --git a/packages/utils/src/dom/event.ts b/packages/utils/src/dom/event.ts index 7ac9ed771..8f0044a7a 100644 --- a/packages/utils/src/dom/event.ts +++ b/packages/utils/src/dom/event.ts @@ -81,8 +81,8 @@ export function triggerEvent (element, eventType) { } else if (typeof document.createEvent === 'function') { if (typeof element.dispatchEvent === 'function') { var eventCategory = knownEventTypesByEventName[eventType] || 'HTMLEvents' - var event = document.createEvent(eventCategory) - event.initEvent(eventType, true, true, options.global, 0, 0, 0, 0, 0, false, false, false, false, 0, element) + var event = document.createEvent(eventCategory); + (event as any).initEvent(eventType, true, true, options.global, 0, 0, 0, 0, 0, false, false, false, false, 0, element) element.dispatchEvent(event) } else { throw new Error("The supplied element doesn't support dispatchEvent") } } else if (useClickWorkaround && element.click) { diff --git a/packages/utils/src/dom/fixes.ts b/packages/utils/src/dom/fixes.ts index 3e85d872a..953a0bd80 100644 --- a/packages/utils/src/dom/fixes.ts +++ b/packages/utils/src/dom/fixes.ts @@ -47,12 +47,12 @@ export function fixUpContinuousNodeArray (continuousNodeArray, parentNode) { export function setOptionNodeSelectionState (optionNode, isSelected) { // IE6 sometimes throws "unknown error" if you try to write to .selected directly, whereas Firefox struggles with setAttribute. Pick one based on browser. - if (ieVersion < 7) { optionNode.setAttribute('selected', isSelected) } else { optionNode.selected = isSelected } + if ((ieVersion as any) < 7) { optionNode.setAttribute('selected', isSelected) } else { optionNode.selected = isSelected } } export function forceRefresh (node) { // Workaround for an IE9 rendering bug - https://github.com/SteveSanderson/knockout/issues/209 - if (ieVersion >= 9) { + if ((ieVersion as any) >= 9) { // For text nodes and comment nodes (most likely virtual elements), we will have to refresh the container var elem = node.nodeType == 1 ? node : node.parentNode if (elem.style) { elem.style.zoom = elem.style.zoom } diff --git a/packages/utils/src/dom/info.ts b/packages/utils/src/dom/info.ts index 80689f285..6f0b16f07 100644 --- a/packages/utils/src/dom/info.ts +++ b/packages/utils/src/dom/info.ts @@ -3,15 +3,17 @@ // import { arrayFirst } from '../array' -export function domNodeIsContainedBy (node, containedByNode) { +export function domNodeIsContainedBy (node : Node, containedByNode: Node) { if (node === containedByNode) { return true } if (node.nodeType === 11) { return false } // Fixes issue #1162 - can't use node.contains for document fragments on IE8 if (containedByNode.contains) { return containedByNode.contains(node.nodeType !== 1 ? node.parentNode : node) } if (containedByNode.compareDocumentPosition) { return (containedByNode.compareDocumentPosition(node) & 16) == 16 } - while (node && node != containedByNode) { - node = node.parentNode + + let parentNode: Node | null = node; + while (parentNode && parentNode != containedByNode) { + parentNode = parentNode.parentNode } - return !!node + return !!parentNode } export function domNodeIsAttachedToDocument (node) { diff --git a/packages/utils/src/dom/manipulation.ts b/packages/utils/src/dom/manipulation.ts index 634d27e11..f8a9a2f95 100644 --- a/packages/utils/src/dom/manipulation.ts +++ b/packages/utils/src/dom/manipulation.ts @@ -6,60 +6,68 @@ import { makeArray } from '../array' import { ieVersion } from '../ie' import { cleanNode, removeNode } from './disposal' -export function moveCleanedNodesToContainerElement (nodes) { +export function moveCleanedNodesToContainerElement (nodes : ArrayLike) { // Ensure it's a real array, as we're about to reparent the nodes and // we don't want the underlying collection to change while we're doing that. - var nodesArray = makeArray(nodes) - var templateDocument = (nodesArray[0] && nodesArray[0].ownerDocument) || document + const nodesArray = makeArray(nodes) as Node[] + const templateDocument = (nodesArray[0] && nodesArray[0].ownerDocument) || document - var container = templateDocument.createElement('div') - for (var i = 0, j = nodesArray.length; i < j; i++) { + const container = templateDocument.createElement('div') + for (let i = 0, j = nodesArray.length; i < j; i++) { container.appendChild(cleanNode(nodesArray[i])) } return container } -export function cloneNodes (nodesArray, shouldCleanNodes) { - for (var i = 0, j = nodesArray.length, newNodesArray = new Array(); i < j; i++) { - var clonedNode = nodesArray[i].cloneNode(true) +export function cloneNodes (nodesArray : ArrayLike , shouldCleanNodes?: boolean) { + const newNodesArray = new Array(); + + for (let i = 0; i < nodesArray.length; i++) { + const clonedNode = nodesArray[i].cloneNode(true) newNodesArray.push(shouldCleanNodes ? cleanNode(clonedNode) : clonedNode) } + return newNodesArray } -export function setDomNodeChildren (domNode, childNodes) { +export function setDomNodeChildren (domNode: Node, childNodes:ArrayLike) { emptyDomNode(domNode) if (childNodes) { - for (var i = 0, j = childNodes.length; i < j; i++) { domNode.appendChild(childNodes[i]) } + for (let i = 0; i < childNodes.length; i++) { + domNode.appendChild(childNodes[i]) + } } } -export function replaceDomNodes (nodeToReplaceOrNodeArray, newNodesArray) { - var nodesToReplaceArray = nodeToReplaceOrNodeArray.nodeType ? [nodeToReplaceOrNodeArray] : nodeToReplaceOrNodeArray +export function replaceDomNodes (nodeToReplaceOrNodeArray:Node[] | Node, newNodesArray:Node[]) { + let nodesToReplaceArray = Array.isArray(nodeToReplaceOrNodeArray) ? nodeToReplaceOrNodeArray: [nodeToReplaceOrNodeArray] if (nodesToReplaceArray.length > 0) { - var insertionPoint = nodesToReplaceArray[0] - var parent = insertionPoint.parentNode - for (var i = 0, j = newNodesArray.length; i < j; i++) { parent.insertBefore(newNodesArray[i], insertionPoint) } - for (i = 0, j = nodesToReplaceArray.length; i < j; i++) { + const insertionPoint = nodesToReplaceArray[0] + const parent = insertionPoint.parentNode + + for (let i = 0; i < newNodesArray.length; i++) { + parent?.insertBefore(newNodesArray[i], insertionPoint) + } + for (let i = 0; i < nodesToReplaceArray.length; i++) { removeNode(nodesToReplaceArray[i]) } } } -export function setElementName (element, name) { +export function setElementName (element : any, name: string) { element.name = name // Workaround IE 6/7 issue // - https://github.com/SteveSanderson/knockout/issues/197 // - http://www.matts411.com/post/setting_the_name_attribute_in_ie_dom/ - if (ieVersion <= 7) { + if ((ieVersion as any) <= 7) { try { element.mergeAttributes(document.createElement(""), false) } catch (e) {} // For IE9 with doc mode "IE9 Standards" and browser mode "IE9 Compatibility View" } } -export function emptyDomNode (domNode) { +export function emptyDomNode (domNode: Node) { while (domNode.firstChild) { removeNode(domNode.firstChild) } diff --git a/packages/utils/src/dom/virtualElements.ts b/packages/utils/src/dom/virtualElements.ts index ea247554f..b3a738069 100644 --- a/packages/utils/src/dom/virtualElements.ts +++ b/packages/utils/src/dom/virtualElements.ts @@ -40,7 +40,7 @@ function isUnmatchedEndComment (node) { const matchedEndCommentDataKey = '__ko_matchedEndComment__' -export function getVirtualChildren (startComment, allowUnbalanced) { +export function getVirtualChildren (startComment, allowUnbalanced?) { var currentNode = startComment var depth = 1 var children = new Array() @@ -59,7 +59,7 @@ export function getVirtualChildren (startComment, allowUnbalanced) { return null } -function getMatchingEndComment (startComment, allowUnbalanced) { +function getMatchingEndComment (startComment, allowUnbalanced?) { var allVirtualChildren = getVirtualChildren(startComment, allowUnbalanced) if (allVirtualChildren) { if (allVirtualChildren.length > 0) { return allVirtualChildren[allVirtualChildren.length - 1].nextSibling } @@ -70,7 +70,7 @@ function getMatchingEndComment (startComment, allowUnbalanced) { function getUnbalancedChildTags (node) { // e.g., from
OK
Another, returns: Another // from
OK
, returns: - var childNode = node.firstChild, captureRemaining = null + var childNode = node.firstChild, captureRemaining:any = null if (childNode) { do { if (captureRemaining) // We already hit an unbalanced node and are now just scooping up all subsequent nodes diff --git a/packages/utils/src/ie.ts b/packages/utils/src/ie.ts index 5ed6b0954..8251d86e7 100644 --- a/packages/utils/src/ie.ts +++ b/packages/utils/src/ie.ts @@ -4,7 +4,10 @@ import options from './options' const ieVersion = options.document && (function () { - var version = 3, div = options.document.createElement('div'), iElems = div.getElementsByTagName('i') + + let version = 3; + const div = options.document.createElement('div'); + const iElems = div.getElementsByTagName('i') // Keep constructing conditional HTML blocks until we hit one that resolves to an empty fragment while ( @@ -18,6 +21,7 @@ const ieVersion = options.document && (function () { return userAgent.match(/MSIE ([^ ]+)/) || userAgent.match(/rv:([^ )]+)/) } return version > 4 ? version : undefined + }()) const isIe6 = ieVersion === 6 diff --git a/packages/utils/src/options.ts b/packages/utils/src/options.ts index 62cc4c282..a33675b49 100644 --- a/packages/utils/src/options.ts +++ b/packages/utils/src/options.ts @@ -33,7 +33,7 @@ class OptionsClass { // jQuery will be automatically set to globalThis.jQuery in applyBindings // if it is (strictly equal to) undefined. Set it to false or null to // disable automatically setting jQuery. - jQuery: any = globalThis.jQuery + jQuery: any = globalThis.jQueryInstance Promise: PromiseConstructor = globalThis.Promise From b4f4e981aee1599677973a87df6a6d337677b487 Mon Sep 17 00:00:00 2001 From: mcselle Date: Tue, 7 Jan 2025 16:00:47 +0100 Subject: [PATCH 010/190] Utils.Parser fixed tsc error --- global.d.ts | 13 ++++++++----- packages/utils.parser/src/Arguments.ts | 3 +++ packages/utils.parser/src/Expression.ts | 3 +++ packages/utils.parser/src/Identifier.ts | 10 +++++++--- packages/utils.parser/src/Node.ts | 11 ++++++++--- packages/utils.parser/src/Parameters.ts | 8 +++++--- packages/utils.parser/src/Parser.ts | 2 +- packages/utils.parser/src/operators.ts | 13 ++++++++++++- packages/utils/src/object.ts | 2 +- 9 files changed, 48 insertions(+), 17 deletions(-) diff --git a/global.d.ts b/global.d.ts index f0d144b09..a3b91cc69 100644 --- a/global.d.ts +++ b/global.d.ts @@ -51,16 +51,15 @@ declare global { }; var testNode: HTMLElement; - var jQueryInstance : JQueryStatic - + var jQueryInstance: JQueryStatic; interface Window { // Below just informs IDE and/or TS-compiler (it's set in `.js` file). DEBUG: boolean amdRequire: any require: any - jQuery: JQuery - jQueryInstance: JQuery + jQuery: JQueryStatic + jQueryInstance: JQueryStatic testDivTemplate:HTMLElement templateOutput:HTMLElement } @@ -68,7 +67,7 @@ declare global { //Jasmine and Mocha define duplicated functions, is a problem for the type system //This namespace merges the jasmine namespace to correct same tsc warnings namespace jasmine { - + var Spec:any; function getGlobal():any; var updateInterval: number function resolve(promise: Promise) @@ -96,6 +95,10 @@ declare global { toContainHtml(expectedValues:any):boolean } + interface Clock{ + mockScheduler:any + } + interface Spy { reset() : any } diff --git a/packages/utils.parser/src/Arguments.ts b/packages/utils.parser/src/Arguments.ts index 06ea4fc04..1c8ed5fbc 100644 --- a/packages/utils.parser/src/Arguments.ts +++ b/packages/utils.parser/src/Arguments.ts @@ -2,6 +2,9 @@ import Node from './Node' export default class Arguments { + private parser: any + private args: any + constructor (parser, args) { this.parser = parser this.args = args diff --git a/packages/utils.parser/src/Expression.ts b/packages/utils.parser/src/Expression.ts index 496dfe451..ac2c7442f 100644 --- a/packages/utils.parser/src/Expression.ts +++ b/packages/utils.parser/src/Expression.ts @@ -2,6 +2,9 @@ import Node from './Node' export default class Expression { + private nodes: any + root: any + constructor (nodes) { this.nodes = nodes this.root = Node.create_root(nodes) diff --git a/packages/utils.parser/src/Identifier.ts b/packages/utils.parser/src/Identifier.ts index 34553c05b..77904b200 100644 --- a/packages/utils.parser/src/Identifier.ts +++ b/packages/utils.parser/src/Identifier.ts @@ -1,7 +1,7 @@ import Node from './Node' import Arguments from './Arguments' - +import Parser from './Parser' import { hasOwnProperty, isObjectLike } from '@tko/utils' import { @@ -13,7 +13,11 @@ import { } from './identifierExpressions' export default class Identifier { - constructor (parser, token, dereferences) { + token: string + dereferences: any + parser: Parser + + constructor (parser: Parser, token: string, dereferences: any[]) { this.token = token this.dereferences = dereferences this.parser = parser @@ -106,7 +110,7 @@ export default class Identifier { set_value (new_value, $context, globals) { const $data = $context.$data || {} const refs = this.dereferences || [] - let leaf = this.token + let leaf:any = this.token let i, n, root if (isObjectLike($data) && leaf in $data) { diff --git a/packages/utils.parser/src/Node.ts b/packages/utils.parser/src/Node.ts index 109354fc9..d174d2ef2 100644 --- a/packages/utils.parser/src/Node.ts +++ b/packages/utils.parser/src/Node.ts @@ -11,6 +11,11 @@ import { const IS_EXPR_OR_IDENT = Symbol('Node - Is Expression Or Identifier') export default class Node { + lhs: any + op: any + rhs: any + + constructor (lhs, op, rhs) { this.lhs = lhs this.op = op @@ -49,8 +54,8 @@ export default class Node { * Note that for a lambda, we do not evaluate the RHS expression until * the lambda is called. */ - get_value (notused, context, globals, node) { - var node = this + get_value (notused, context, globals, node: Node ) { + var node:Node = this ; if (node.op === LAMBDA) { return (...args) => { @@ -77,7 +82,7 @@ export default class Node { static get isExpressionOrIdentifierSymbol () { return IS_EXPR_OR_IDENT } get [IS_EXPR_OR_IDENT] () { return true } - static value_of (item, context, globals, node) { + static value_of (item, context?, globals?, node? : Node) { if (item && item[Node.isExpressionOrIdentifierSymbol]) { return item.get_value(item, context, globals, node) } diff --git a/packages/utils.parser/src/Parameters.ts b/packages/utils.parser/src/Parameters.ts index 6344f04e5..6f4d5ae19 100644 --- a/packages/utils.parser/src/Parameters.ts +++ b/packages/utils.parser/src/Parameters.ts @@ -4,24 +4,26 @@ import Expression from './Expression' import Identifier from './Identifier' export default class Parameters { + #names: any[] + constructor (parser, node) { // convert a node of comma-separated Identifiers to Parameters if (node instanceof Expression) { node = node.root } try { - this.names = Parameters.nodeTreeToNames(node) + this.#names = Parameters.nodeTreeToNames(node) } catch (e) { parser.error(e) } } extendContext (context, args) { - if (!this.names) { + if (!this.#names) { return context } else { const newValues = {} - this.names.forEach((name, index) => { + this.#names.forEach((name, index) => { newValues[name] = args[index] }) return context.extend(newValues) diff --git a/packages/utils.parser/src/Parser.ts b/packages/utils.parser/src/Parser.ts index 77fc03d4f..b38a70796 100644 --- a/packages/utils.parser/src/Parser.ts +++ b/packages/utils.parser/src/Parser.ts @@ -207,7 +207,7 @@ export default class Parser { } object () { - let key + let key:string let object = {} let ch = this.ch diff --git a/packages/utils.parser/src/operators.ts b/packages/utils.parser/src/operators.ts index f618fe5b9..61bc9368e 100644 --- a/packages/utils.parser/src/operators.ts +++ b/packages/utils.parser/src/operators.ts @@ -15,7 +15,18 @@ function unwrapOrCall (a, b) { return b } -const operators = { +type OperatorFunction = (a: any, b: any, ...args: any[]) => any; + + +interface OperatorWithProperties extends OperatorFunction{ + earlyOut?: (a: any) => any; + precedence?:number; +} + +interface Operators{ + [key: string]:OperatorWithProperties; +} +const operators:Operators = { // unary '@': unwrapOrCall, '#': (a, b) => () => unwrap(b), // Convert to read-only. diff --git a/packages/utils/src/object.ts b/packages/utils/src/object.ts index 31206bd05..496d7045d 100644 --- a/packages/utils/src/object.ts +++ b/packages/utils/src/object.ts @@ -50,7 +50,7 @@ export function getObjectOwnProperty (obj, propName) { return hasOwnProperty(obj, propName) ? obj[propName] : undefined } -export function clonePlainObjectDeep (obj, seen) { +export function clonePlainObjectDeep (obj, seen?: any[]) { if (!seen) { seen = new Array() } if (!obj || typeof obj !== 'object' || From b47a40ae66d7380e204c8001d5be7239ca424214 Mon Sep 17 00:00:00 2001 From: mcselle Date: Tue, 7 Jan 2025 16:02:30 +0100 Subject: [PATCH 011/190] Fixed Typo --- packages/utils.parser/src/operators.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils.parser/src/operators.ts b/packages/utils.parser/src/operators.ts index 61bc9368e..8dc27ccf4 100644 --- a/packages/utils.parser/src/operators.ts +++ b/packages/utils.parser/src/operators.ts @@ -99,7 +99,7 @@ operators['--'].precedence = 16 operators['&-'].precedence = 16 // exponent -operators['**'].precedent = 15 +operators['**'].precedence = 15 // mul/div/remainder operators['%'].precedence = 14 From 8b53a0ee6ea4d30de3f4a819896644c875c8bad4 Mon Sep 17 00:00:00 2001 From: Auge Date: Thu, 9 Jan 2025 12:04:33 +0100 Subject: [PATCH 012/190] fix tsc error --- global.d.ts | 1054 ++++++++++++++++- .../spec/arrayToDomEditDetectionBehaviors.ts | 2 - .../bind/spec/bindingAttributeBehaviors.ts | 8 +- packages/bind/src/arrayToDomNodeChildren.ts | 4 +- tsconfig.json | 4 +- 5 files changed, 1056 insertions(+), 16 deletions(-) diff --git a/global.d.ts b/global.d.ts index a3b91cc69..7638a0d81 100644 --- a/global.d.ts +++ b/global.d.ts @@ -1,7 +1,6 @@ /// /// - export { }; @@ -12,11 +11,11 @@ declare global { (value: T): void; // Setter subscribe(callback: (newValue: T) => void): Subscription; }; - + export type Subscription = { dispose(): void; // Unsubscribe method }; - + export type ObservableArray = Observable & { remove (valueOrPredicate: any): any[] removeAll (arrayOfValues: undefined): any @@ -27,7 +26,7 @@ declare global { sorted (compareFn: ((a: any, b: any) => number) | undefined): any[] reversed (): any[] [Symbol.iterator]: Generator - + // Array-specific methods push(...items: T[]): number; pop(): T | undefined; @@ -49,10 +48,10 @@ declare global { // filter(predicate: (item: T) => boolean): T[]; // map(callback: (item: T) => U): U[]; }; - + var testNode: HTMLElement; var jQueryInstance: JQueryStatic; - + interface Window { // Below just informs IDE and/or TS-compiler (it's set in `.js` file). DEBUG: boolean @@ -103,4 +102,1045 @@ declare global { reset() : any } } -} \ No newline at end of file + export as namespace ko; + +//#region subscribables/subscribable.js + +export type SubscriptionCallback = (this: TTarget, val: T) => void; +export type MaybeSubscribable = T | Subscribable; + +export interface Subscription { + dispose(): void; + disposeWhenNodeIsRemoved(node: Node): void; +} + +type Flatten = T extends Array ? U : T; + +export interface SubscribableFunctions extends Function { + init>(instance: S): void; + + notifySubscribers(valueToWrite?: T, event?: string): void; + + subscribe(callback: SubscriptionCallback>, TTarget>, callbackTarget: TTarget, event: "arrayChange"): Subscription; + + subscribe(callback: SubscriptionCallback, callbackTarget: TTarget, event: "beforeChange" | "spectate" | "awake"): Subscription; + subscribe(callback: SubscriptionCallback, callbackTarget: TTarget, event: "asleep"): Subscription; + subscribe(callback: SubscriptionCallback, callbackTarget?: TTarget, event?: "change"): Subscription; + subscribe(callback: SubscriptionCallback, callbackTarget: TTarget, event: string): Subscription; + + extend(requestedExtenders: ObservableExtenderOptions): this; + extend>(requestedExtenders: ObservableExtenderOptions): S; + + getSubscriptionsCount(event?: string): number; +} + +export interface Subscribable extends SubscribableFunctions { } + +export const subscribable: { + new (): Subscribable; + fn: SubscribableFunctions; +}; + +export function isSubscribable(instance: any): instance is Subscribable; + +//#endregion + +//#region subscribables/observable.js + +export type MaybeObservable = T | Observable; + +export interface ObservableFunctions extends Subscribable { + equalityComparer(a: T, b: T): boolean; + peek(): T; + valueHasMutated(): void; + valueWillMutate(): void; +} + +export interface Observable extends ObservableFunctions { + (): T; + (value: T): any; +} +export function observable(value: T): Observable; +export function observable(value: null): Observable +/** No initial value provided, so implicitly includes `undefined` as a possible value */ +export function observable(): Observable +export module observable { + export const fn: ObservableFunctions; +} + +export function isObservable(instance: any): instance is Observable; + +export function isWriteableObservable(instance: any): instance is Observable; +export function isWritableObservable(instance: any): instance is Observable; + +//#endregion + +//#region subscribables/observableArray.js + +export type MaybeObservableArray = T[] | ObservableArray; + +export interface ObservableArrayFunctions extends ObservableFunctions { + //#region observableArray/generalFunctions + /** + * Returns the index of the first occurrence of a value in an array. + * @param searchElement The value to locate in the array. + * @param fromIndex The array index at which to begin the search. If fromIndex is omitted, the search starts at index 0. + */ + indexOf(searchElement: T, fromIndex?: number): number; + + /** + * Returns a section of an array. + * @param start The beginning of the specified portion of the array. + * @param end The end of the specified portion of the array. If omitted, all items after start are included + */ + slice(start: number, end?: number): T[]; + + /** + * Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements. + * @param start The zero-based location in the array from which to start removing elements. + * @param deleteCount The number of elements to remove. Defaults to removing everything after `start` + * @param items Elements to insert into the array in place of the deleted elements. + */ + splice(start: number, deleteCount?: number, ...items: T[]): T[]; + + /** + * Removes the last value from the array and returns it. + */ + pop(): T; + /** + * Adds a new item to the end of array. + * @param items Items to be added + */ + push(...items: T[]): number; + /** + * Removes the first value from the array and returns it. + */ + shift(): T; + /** + * Inserts a new item at the beginning of the array. + * @param items Items to be added + */ + unshift(...items: T[]): number; + + /** + * Reverses the order of the array and returns the observableArray. + * Modifies the underlying array. + */ + reverse(): this; + + /** + * Sorts the array contents and returns the observableArray. + * Modifies the underlying array. + */ + sort(compareFunction?: (left: T, right: T) => number): this; + //#endregion + + //#region observableArray/koSpecificFunctions + /** + * Returns a reversed copy of the array. + * Does not modify the underlying array. + */ + reversed(): T[]; + + /** + * Returns a reversed copy of the array. + * Does not modify the underlying array. + */ + sorted(compareFunction?: (left: T, right: T) => number): T[]; + /** + * Replaces the first value that equals oldItem with newItem + * @param oldItem Item to be replaced + * @param newItem Replacing item + */ + replace(oldItem: T, newItem: T): void; + + /** + * Removes all values that equal item and returns them as an array. + * @param item The item to be removed + */ + remove(item: T): T[]; + /** + * Removes all values and returns them as an array. + * @param removeFunction A function used to determine true if item should be removed and fasle otherwise + */ + remove(removeFunction: (item: T) => boolean): T[]; + + /** + * Removes all values and returns them as an array. + */ + removeAll(): T[]; + /** + * Removes all values that equal any of the supplied items + * @param items Items to be removed + */ + removeAll(items: T[]): T[]; + + // Ko specific Usually relevant to Ruby on Rails developers only + /** + * Finds any objects in the array that equal someItem and gives them a special property called _destroy with value true. + * Usually only relevant to Ruby on Rails development + * @param item Items to be marked with the property. + */ + destroy(item: T): void; + /** + * Finds any objects in the array filtered by a function and gives them a special property called _destroy with value true. + * Usually only relevant to Ruby on Rails development + * @param destroyFunction A function used to determine which items should be marked with the property. + */ + destroy(destroyFunction: (item: T) => boolean): void; + + /** + * Gives a special property called _destroy with value true to all objects in the array. + * Usually only relevant to Ruby on Rails development + */ + destroyAll(): void; + /** + * Finds any objects in the array that equal supplied items and gives them a special property called _destroy with value true. + * Usually only relevant to Ruby on Rails development + * @param items + */ + destroyAll(items: T[]): void; + //#endregion +} + +export interface ObservableArray extends Observable, ObservableArrayFunctions { + (value: T[] | null | undefined): this; +} + +export function observableArray(): ObservableArray; +export function observableArray(initialValue: T[]): ObservableArray; +export module observableArray { + export const fn: ObservableArrayFunctions; +} + +export function isObservableArray(instance: any): instance is ObservableArray; + +//#endregion + +//#region subscribables/dependendObservable.js + +export type ComputedReadFunction = Subscribable | Observable | Computed | ((this: TTarget) => T); +export type ComputedWriteFunction = (this: TTarget, val: T) => void; +export type MaybeComputed = T | Computed; + +export interface ComputedFunctions extends Subscribable { + // It's possible for a to be undefined, since the equalityComparer is run on the initial + // computation with undefined as the first argument. This is user-relevant for deferred computeds. + equalityComparer(a: T | undefined, b: T): boolean; + peek(): T; + dispose(): void; + isActive(): boolean; + getDependenciesCount(): number; + getDependencies(): Subscribable[]; +} + +export interface Computed extends ComputedFunctions { + (): T; + (value: T): this; +} + +export interface PureComputed extends Computed { } + +export interface ComputedOptions { + read?: ComputedReadFunction; + write?: ComputedWriteFunction; + owner?: TTarget; + pure?: boolean; + deferEvaluation?: boolean; + disposeWhenNodeIsRemoved?: Node; + disposeWhen?: () => boolean; +} + +export function computed(options: ComputedOptions): Computed; +export function computed(evaluator: ComputedReadFunction): Computed; +export function computed(evaluator: ComputedReadFunction, evaluatorTarget: TTarget): Computed; +export function computed(evaluator: ComputedReadFunction, evaluatorTarget: TTarget, options: ComputedOptions): Computed; +export module computed { + export const fn: ComputedFunctions; +} + +export function pureComputed(options: ComputedOptions): PureComputed; +export function pureComputed(evaluator: ComputedReadFunction): PureComputed; +export function pureComputed(evaluator: ComputedReadFunction, evaluatorTarget: TTarget): PureComputed; + +export function isComputed(instance: any): instance is Computed; +export function isPureComputed(instance: any): instance is PureComputed; + +//#endregion + +//#region subscribables/dependencyDetection.js + +export interface ComputedContext { + getDependenciesCount(): number; + getDependencies(): Subscribable[]; + isInitial(): boolean; + registerDependency(subscribable: Subscribable): void; +} + +export const computedContext: ComputedContext; + +/** + * Executes a function and returns the result, while disabling depdendency tracking + * @param callback - the function to execute without dependency tracking + * @param callbackTarget - the `this` binding for `callback` + * @param callbackArgs - the args to provide to `callback` + */ +export function ignoreDependencies( + callback: (this: Target, ...args: Args) => Return, + callbackTarget?: Target, + callbackArgs?: Args +): Return; + +//#endregion + +//#region subscribables/extenders.js + +export type RateLimitMethod = (callback: () => void, timeout: number, options: any) => (() => void); + +export interface RateLimitOptions { + timeout: number; + method?: "notifyAtFixedRate" | "notifyWhenChangesStop" | RateLimitMethod; + [option: string]: any; +} + +export interface ExtendersOptions { + trackArrayChanges: true | utils.CompareArraysOptions; + throttle: number; + rateLimit: number | RateLimitOptions; + deferred: true; + notify: "always" | any; +} + +export interface Extender { + (target: T, options: O): T; +} + +type AsExtenders = { [P in keyof T]: Extender } + +export interface Extenders extends AsExtenders> { + [name: string]: Extender; +} + +export interface ObservableExtenderOptions extends Partial> { } + +export const extenders: Extenders; + +//#endregion + +//#region subscribables/mappingHelpers.js + +export type Unwrapped = T extends ko.ObservableArray + ? Unwrapped[] + : T extends ko.Subscribable + ? ( + R extends ko.Subscribable + ? unknown + : R extends Record + ? { [P in keyof R]: Unwrapped} + : R + ) + : T extends Date | RegExp | Function + ? T + : T extends Record + ? { [P in keyof T]: Unwrapped } + : T + +export function toJS(rootObject: T): Unwrapped; +export function toJSON(rootObject: any, replacer?: Function, space?: number): string; + +//#endregion + +//#region subscribables/observableUtils.js + +export function when(predicate: ComputedReadFunction, callback: SubscriptionCallback, context?: TTarget): Subscription; +export function when(predicate: ComputedReadFunction): Promise; + +//#endregion + +//#region binding/bindingAttributeSyntax.js + +export type BindingAccessors = { [name: string]: Function; }; + +export interface AllBindings { + (): any; + + get(name: string): any; + get(name: string): T; + + has(name: string): boolean; +} +export type BindingHandlerControlsDescendant = { controlsDescendantBindings: boolean; } +export type BindingHandlerAddBinding = (name: string, value: any) => void; +export interface BindingHandler { + after?: string[]; + init?: (element: any, valueAccessor: () => T, allBindings: AllBindings, viewModel: any, bindingContext: BindingContext) => void | BindingHandlerControlsDescendant; + update?: (element: any, valueAccessor: () => T, allBindings: AllBindings, viewModel: any, bindingContext: BindingContext) => void; + options?: any; + preprocess?: (value: string | undefined, name: string, addBinding: BindingHandlerAddBinding) => string | undefined | void; +} + +export interface BindingHandlers { + [name: string]: BindingHandler; +} + +export interface BindingContext { + ko: any; // typeof ko; + + [name: string]: any; + + $parent?: any; + $parents: any[]; + $root: any; + $data: T; + $rawData: T | Observable; + $index?: Observable; + $parentContext?: BindingContext; + + $component?: any; + + extend(properties: object): BindingContext; + extend(properties: (self: BindingContext) => object): BindingContext; + + createChildContext(dataItem: T | Observable, dataItemAlias?: string, extendCallback?: BindingContextExtendCallback): BindingContext; + createChildContext(accessor: () => T | Observable, dataItemAlias?: string, extendCallback?: BindingContextExtendCallback): BindingContext; + createChildContext(dataItem: T | Observable, options: BindingChildContextOptions): BindingContext; + createChildContext(accessor: () => T | Observable, options: BindingChildContextOptions): BindingContext; +} + +export interface BindingChildContextOptions { + as?: string; + extend?: BindingContextExtendCallback; + noChildContext?: boolean; +} + +export function applyBindings(bindingContext: T | BindingContext): void; +export function applyBindings(bindingContext: T | BindingContext, rootNode: Node, extendCallback?: BindingContextExtendCallback): void; +export function applyBindingsToDescendants(bindingContext: T | BindingContext, rootNode?: Node): void; +export function applyBindingsToNode(node: Node, bindings: object | (() => object), viewModel: T | BindingContext): void; +export function applyBindingAccessorsToNode(node: Node, bindings: BindingAccessors | (() => BindingAccessors), viewModel: T | BindingContext): void; + +export function dataFor(node: Node): T; +export function contextFor(node: Node): BindingContext; + +export const bindingHandlers: BindingHandlers; +export function getBindingHandler(handler: string): BindingHandler; + +export type BindingContextExtendCallback = (self: BindingContext, parentContext: BindingContext | null, dataItem: T) => void; + +export module bindingEvent { + export function subscribe(node: Node, event: "childrenComplete" | "descendantsComplete", callback: (node: Node) => void, callbackContext?: any): Subscription; + export function startPossiblyAsyncContentBinding(node: Element, bindingContext: BindingContext): BindingContext; +} + +//#endregion + +//#region binding/bindingProvider.js + +export interface BindingOptions { + valueAccessors?: boolean; + bindingParams?: boolean; +} + +export interface IBindingProvider { + nodeHasBindings(node: Node): boolean; + getBindings?(node: Node, bindingContext: BindingContext): object; + getBindingAccessors(node: Node, bindingContext: BindingContext): BindingAccessors; + preprocessNode?(node: Node): Node[] | undefined; +} + +export class bindingProvider implements IBindingProvider { + nodeHasBindings(node: Node): boolean; + + getBindings(node: Node, bindingContext: BindingContext): object; + getBindingAccessors(node: Node, bindingContext: BindingContext): BindingAccessors; + + getBindingsString(node: Node, bindingContext?: BindingContext): string; + + parseBindingsString(bindingsString: string, bindingContext: BindingContext, node: Node): object; + parseBindingsString(bindingsString: string, bindingContext: BindingContext, node: Node, options: BindingOptions): object | BindingAccessors; + + static instance: IBindingProvider; +} + +//#endregion + +//#region binding/expressionRewriting.js +export module expressionRewriting { + export interface KeyValue { + key?: string; + value?: string; + unknown?: string; + } + + export interface TwoWayBindings { + [name: string]: boolean | string; + } + + export const bindingRewriteValidators: any[]; + + export function parseObjectLiteral(objectLiteralString: string): KeyValue[]; + + export function preProcessBindings(bindingsString: string, bindingOptions?: BindingOptions): string; + export function preProcessBindings(keyValueArray: KeyValue[], bindingOptions?: BindingOptions): string; + + export const _twoWayBindings: TwoWayBindings; +} + +//#endregion + +//#region binding/selectExtensions.js + +export module selectExtensions { + export function readValue(element: HTMLElement): any; + export function writeValue(element: HTMLElement, value?: any, allowUnset?: boolean): void; +} + +//#endregion + +//#region binding/defaultBindings/ + +export interface BindingHandlers { + // Controlling text and appearance + visible: { + update(element: HTMLElement, valueAccessor: () => MaybeSubscribable): void; + }; + hidden: { + update(element: HTMLElement, valueAccessor: () => MaybeSubscribable): void; + }; + text: { + init(): BindingHandlerControlsDescendant; + update(element: Node, valueAccessor: () => MaybeSubscribable): void; + }; + html: { + init(): BindingHandlerControlsDescendant; + update(element: Node, valueAccessor: () => MaybeSubscribable): void; + }; + class: { + update(element: HTMLElement, valueAccessor: () => MaybeSubscribable): void; + }; + css: { + update(element: HTMLElement, valueAccessor: () => MaybeSubscribable): void; + }; + style: { + update(element: HTMLElement, valueAccessor: () => MaybeSubscribable): void; + }; + attr: { + update(element: HTMLElement, valueAccessor: () => MaybeSubscribable): void; + }; + + // Control Flow + foreach: { + init(element: Node, valueAccessor: () => MaybeSubscribable, allBindings: AllBindings, viewModel: any, bindingContext: BindingContext): BindingHandlerControlsDescendant; + }; + if: { + init(element: Node, valueAccessor: () => MaybeSubscribable, allBindings: AllBindings, viewModel: any, bindingContext: BindingContext): BindingHandlerControlsDescendant; + }; + ifnot: { + init(element: Node, valueAccessor: () => MaybeSubscribable, allBindings: AllBindings, viewModel: any, bindingContext: BindingContext): BindingHandlerControlsDescendant; + }; + with: { + init(element: Node, valueAccessor: () => MaybeSubscribable, allBindings: AllBindings, viewModel: any, bindingContext: BindingContext): BindingHandlerControlsDescendant; + }; + let: { + init(element: Node, valueAccessor: () => MaybeSubscribable, allBindings: AllBindings, viewModel: any, bindingContext: BindingContext): BindingHandlerControlsDescendant; + }; + using: { + init(element: Node, valueAccessor: () => MaybeSubscribable, allBindings: AllBindings, viewModel: any, bindingContext: BindingContext): BindingHandlerControlsDescendant; + }; + + // Working with form fields + event: { + init(element: HTMLElement, valueAccessor: () => object, allBindings: AllBindings, viewModel: any, bindingContext: BindingContext): void; + }; + click: { + init(element: HTMLElement, valueAccessor: () => Function, allBindings: AllBindings, viewModel: any, bindingContext: BindingContext): void; + }; + submit: { + init(element: HTMLElement, valueAccessor: () => Function, allBindings: AllBindings, viewModel: any, bindingContext: BindingContext): void; + }; + enable: { + update(element: HTMLElement, valueAccessor: () => MaybeSubscribable): void; + }; + disable: { + update(element: HTMLElement, valueAccessor: () => MaybeSubscribable): void; + }; + value: { + after: string[]; + init(element: HTMLElement, valueAccessor: () => MaybeSubscribable, allBindings: AllBindings): void; + update(...args: any[]): void; // Keep for backwards compatibility with code that may have wrapped value binding + }; + textInput: { + init(element: HTMLElement, valueAccessor: () => MaybeSubscribable, allBindings: AllBindings): void; + }; + textinput: { + preprocess(value: string | undefined, name: string, addBinding: BindingHandlerAddBinding): void; + }; + hasfocus: { + init(element: HTMLElement, valueAccessor: () => MaybeSubscribable, allBindings: AllBindings): void; + update(element: HTMLElement, valueAccessor: () => MaybeSubscribable): void; + }; + hasFocus: { + init(element: HTMLElement, valueAccessor: () => MaybeSubscribable, allBindings: AllBindings): void; + update(element: HTMLElement, valueAccessor: () => MaybeSubscribable): void; + }; + checked: { + after: string[]; + init(element: HTMLElement, valueAccessor: () => MaybeSubscribable, allBindings: AllBindings): void; + }; + checkedValue: { + update(element: HTMLElement, valueAccessor: () => MaybeSubscribable): void; + }; + options: { + init(element: HTMLElement): BindingHandlerControlsDescendant; + update(element: HTMLElement, valueAccessor: () => MaybeSubscribable, allBindings: AllBindings): void; + }; + selectedOptions: { + after: string[]; + init(element: HTMLElement, valueAccessor: () => MaybeSubscribable, allBindings: AllBindings): void; + update(element: HTMLElement, valueAccessor: () => MaybeSubscribable): void; + }; + uniqueName: { + init(element: HTMLElement, valueAccessor: () => boolean): void; + }; +} + +export interface VirtualElementsAllowedBindings { + text: boolean; + foreach: boolean; + if: boolean; + ifnot: boolean; + with: boolean; + let: boolean; + using: boolean; +} + +//#endregion + +//#region binding/editDetection/compareArrays.js + +export module utils { + export interface ArrayChange { + status: "added" | "deleted" | "retained"; + value: T; + index: number; + moved?: number; + } + + export type ArrayChanges = ArrayChange[]; + + export interface CompareArraysOptions { + dontLimitMoves?: boolean; + sparse?: boolean; + } + + export function compareArrays(a: T[], b: T[]): ArrayChanges; + export function compareArrays(a: T[], b: T[], dontLimitMoves: boolean): ArrayChanges; + export function compareArrays(a: T[], b: T[], options: CompareArraysOptions): ArrayChanges; +} + +//#endregion + +//#region binding/editDetection/arrayToDomNodeChildren.js + +export module utils { + export type MappingFunction = (valueToMap: T, index: number, nodes: Node[]) => Node[]; + export type MappingAfterAddFunction = (arrayEntry: T, nodes: Node[], index: Observable) => Node[]; + export type MappingHookFunction = (nodes: Node[], index: number, arrayEntry: T) => void; + + export interface MappingOptions { + dontLimitMoves?: boolean; + beforeMove?: MappingHookFunction; + beforeRemove?: MappingHookFunction; + afterAdd?: MappingHookFunction; + afterMove?: MappingHookFunction; + afterRemove?: MappingHookFunction; + } + + export function setDomNodeChildrenFromArrayMapping(domNode: Node, array: T[], mapping: MappingFunction, options?: MappingOptions, callbackAfterAddingNodes?: MappingAfterAddFunction): void; +} + +//#endregion + +//#region templating/templating.js + +export interface TemplateOptions { + afterRender?: (elements: Node[], dataItem: T) => void; + templateEngine?: templateEngine; +} + +export interface TemplateForeachOptions extends TemplateOptions, utils.MappingOptions { + as?: string; + includeDestroyed?: boolean; +} + +export interface BindingTemplateOptions extends TemplateOptions, utils.MappingOptions { + name?: string | ((val: any) => string); + nodes?: Node[]; + + if?: boolean; + ifnot?: boolean; + + data?: any; + foreach?: any[]; + + as?: string; + includeDestroyed?: boolean; +} + +export interface BindingHandlers { + template: { + init(element: Node, valueAccessor: () => MaybeSubscribable): BindingHandlerControlsDescendant; + update(element: Node, valueAccessor: () => MaybeSubscribable, allBindings: AllBindings, viewModel: any, bindingContext: BindingContext): void; + }; +} +export interface VirtualElementsAllowedBindings { + template: boolean; +} + +export function renderTemplate(template: string | Node | (() => string | Node)): string; +export function renderTemplate(template: string | Node | (() => string | Node), dataOrBindingContext: T | BindingContext | null | undefined, options?: TemplateOptions | null | undefined): string; +export function renderTemplate(template: string | Node | (() => string | Node), dataOrBindingContext: T | BindingContext | null | undefined, options: TemplateOptions | null | undefined, targetNodeOrNodeArray: Node | Node[], renderMode?: "replaceChildren" | "replaceNode" | "ignoreTargetNode"): Computed; + +export function setTemplateEngine(templateEngine: templateEngine | undefined): void; + +//#endregion + +//#region templating/templateEngine.js + +export abstract class templateEngine { + allowTemplateRewriting: boolean; + + abstract renderTemplateSource(templateSource: TemplateSource, bindingContext: BindingContext, options: TemplateOptions, templateDocument?: Document): Node[]; + createJavaScriptEvaluatorBlock(script: string): string; + + makeTemplateSource(template: string | Node, templateDocument?: Document): TemplateSource; + + renderTemplate(template: string | Node, bindingContext: BindingContext, options: TemplateOptions, templateDocument?: Document): Node[]; + + isTemplateRewritten(template: string | Node, templateDocument?: Document): boolean; + + rewriteTemplate(template: string | Node, rewriterCallback: (val: string) => string, templateDocument?: Document): void; +} + +//#endregion + +//#region templating/templateSources.js + +export interface TemplateSource { + text(): string; + text(valueToWrite: string): void; + + data(key: string): any; + data(key: string): T; + data(key: string, valueToWrite: T): void; + + nodes?: { + (): Node; + (valueToWrite: Node): void; + }; +} + +export module templateSources { + export class domElement implements TemplateSource { + constructor(element: Node); + + text(): string; + text(valueToWrite: string): void; + + data(key: string): any; + data(key: string): T; + data(key: string, valueToWrite: T): void; + + nodes(): Node; + nodes(valueToWrite: Node): void; + } + + export class anonymousTemplate extends domElement { + constructor(element: Node); + } +} + +//#endregion + +//#region templating/native/nativeTemplateEngine.js + +export class nativeTemplateEngine extends templateEngine { + renderTemplateSource(templateSource: TemplateSource, bindingContext: BindingContext, options: TemplateOptions, templateDocument?: Document): Node[]; +} + +//#endregion + +//#region templating/jquery.tmpl/jqueryTmplTemplateEngine.js + +export class jqueryTmplTemplateEngine extends templateEngine { + renderTemplateSource(templateSource: TemplateSource, bindingContext: BindingContext, options: TemplateOptions, templateDocument?: Document): Node[]; + createJavaScriptEvaluatorBlock(script: string): string; + addTemplate(templateName: string, templateMarkup: string): void; +} + +//#endregion + +//#region components/componentBinding.js + +export interface BindingHandlers { + component: { + init(element: Node, valueAccessor: () => MaybeSubscribable<{ name: any; params: any; }>, allBindings: AllBindings, viewModel: any, bindingContext: BindingContext): BindingHandlerControlsDescendant; + }; +} +export interface VirtualElementsAllowedBindings { + component: boolean; +} + +//#endregion + +//#region components/customElements.js + +export module components { + export function getComponentNameForNode(node: Node): string; +} + +//#endregion + +//#region components/defaultLoader.js + +export module components { + export interface ViewModelConstructor { + new(params?: ViewModelParams): ViewModel; + } + + export interface ViewModel { + dispose?: () => void; + koDescendantsComplete?: (node: Node) => void; + } + + export interface ViewModelParams { + [name: string]: any; + } + + export interface ComponentInfo { + element: Node; + templateNodes: Node[]; + } + + export type CreateViewModel = (params: ViewModelParams, componentInfo: ComponentInfo) => ViewModel; + + export interface Component { + template: Node[]; + createViewModel?: CreateViewModel; + } + + export interface ViewModelStatic { + instance: any; + } + export interface ViewModelFactory { + createViewModel: CreateViewModel; + } + export interface TemplateElement { + element: string | Node; + } + + export type ViewModelConfig = ViewModelConstructor | ViewModelStatic | ViewModelFactory; + export type TemplateConfig = string | Node[] | DocumentFragment | TemplateElement; + export interface RequireConfig { + require: string; + } + export interface Config { + require?: string; + viewModel?: RequireConfig | ViewModelConfig | any; + template?: RequireConfig | TemplateConfig | any; + synchronous?: boolean; + } + + export function register(componentName: string, config: Config | object): void; + export function unregister(componentName: string): void; + export function isRegistered(componentName: string): boolean; + + export interface Loader { + getConfig?(componentName: string, callback: (config: Config | object) => void): void; + loadComponent?(componentName: string, config: Config | object, callback: (component: Component | null) => void): void; + loadTemplate?(componentName: string, config: TemplateConfig | any, callback: (resolvedTemplate: Node[] | null) => void): void; + loadViewModel?(componentName: string, config: ViewModelConfig | any, callback: (resolvedViewModel: CreateViewModel | null) => void): void; + } + + export const loaders: Loader[]; + + export interface DefaultLoader extends Loader { + getConfig(componentName: string, callback: (config: Config | object) => void): void; + loadComponent(componentName: string, config: Config, callback: (component: Component) => void): void; + loadTemplate(componentName: string, config: TemplateConfig, callback: (resolvedTemplate: Node[]) => void): void; + loadViewModel(componentName: string, config: ViewModelConfig, callback: (resolvedViewModel: CreateViewModel) => void): void; + } + + export const defaultLoader: DefaultLoader; +} + +//#endregion + +//#region components/loaderRegistry.js + +export module components { + export function get(componentName: string, callback: (definition: Component, config: Config) => void): string; + export function clearCachedDefinition(componentName: string): void; +} + +//#endregion + +//#region virtualElements.js + +export interface VirtualElementsAllowedBindings { + [name: string]: boolean; +} + +export module virtualElements { + export const allowedBindings: VirtualElementsAllowedBindings; + + export function childNodes(node: Node): Node[]; + export function emptyNode(node: Node): void; + export function firstChild(node: Node): Node; + export function insertAfter(node: Node, nodeToInsert: Node, insertAfterNode: Node): void; + export function nextSibling(node: Node): Node; + export function prepend(node: Node, nodeToPrepend: Node): void; + export function setDomNodeChildren(node: Node, childNodes: Node[]): void; +} + +//#endregion + +//#region memoization.js + +export module memoization { + export function memoize(callback: (val: any) => void): Node[]; + export function unmemoize(memoId: string, callbackParams: any[]): void; + export function unmemoizeDomNodeAndDescendants(domNode: Node, extraCallbackParamsArray: any[]): void; + export function parseMemoText(memoText: string): string; +} + +//#endregion + +//#region options.js + +export interface Options { + deferUpdates: boolean; + useOnlyNativeEvents: boolean; + createChildContextWithAs: boolean; + foreachHidesDestroyed: boolean; +} + +export const options: Options; + +//#endregion + +//#region tasks.js + +export module tasks { + export var scheduler: (callback: () => any) => void; + + export function schedule(callback: () => any): number; + export function cancel(handle: number): void; + + export function runEarly(): void; +} + +//#endregion + +//#region utils.js + +export module utils { + export interface PostJsonOptions { + params?: object; + includeFields?: string[]; + submitter?: (form: HTMLFormElement) => void; + } + + export function addOrRemoveItem(array: MaybeObservableArray, value: T, included?: boolean): T[]; + + export function arrayForEach(array: T[], action: (item: T, index: number) => void, actionOwner?: any): void; + export function arrayFirst(array: T[], predicate: (item: T, index: number) => boolean, predicateOwner?: any): T; + export function arrayFilter(array: T[], predicate: (item: T, index: number) => boolean, predicateOwner?: any): T[]; + export function arrayGetDistinctValues(array: T[]): T[]; + export function arrayIndexOf(array: MaybeObservableArray, item: T): number; + export function arrayMap(array: T[], mapping: (item: T, index: number) => U, mappingOwner?: any): U[]; + export function arrayPushAll(array: MaybeObservableArray, valuesToPush: T[]): T[]; + export function arrayRemoveItem(array: MaybeObservableArray, itemToRemove: T): void; + + export function extend(target: T, source: U): T & U; + + export const fieldsIncludedWithJsonPost: Array; + + export function getFormFields(form: HTMLFormElement, fieldName: string | RegExp): any[]; + + export function objectForEach(obj: object, action: (key: string, value: any) => void): void; + export function objectForEach(obj: { [key: string]: T }, action: (key: string, value: T) => void): void; + + export function peekObservable(value: MaybeSubscribable): T; + + export function postJson(urlOrForm: string | HTMLFormElement, data: MaybeSubscribable, options?: PostJsonOptions): void; + + export function parseJson(jsonString: string): any; + export function parseJson(jsonString: string): T; + + export function range(min: MaybeSubscribable, max: MaybeSubscribable): number[]; + + export function registerEventHandler(element: Element, eventType: string, handler: EventListener): void; + + export function setTextContent(element: Node, textContent: MaybeSubscribable): void; + + export function stringifyJson(data: MaybeSubscribable, replacer?: Function, space?: string | number): string; + + export function toggleDomNodeCssClass(node: Element, className: string, shouldHaveClass?: boolean): void; + + export function triggerEvent(element: Element, eventType: string): void; + + export function unwrapObservable(value: MaybeSubscribable): T; +} + +export function unwrap(value: MaybeSubscribable): T; + +export function onError(error: Error): void; + +//#endregion + +//#region utils.domData.js + +export module utils { + export module domData { + export function get(node: Node, key: string): T; + + export function set(node: Node, key: string, value: T): void; + + export function clear(node: Node): boolean; + } +} + +//#endregion + +//#region utils.domNodeDisposal.js + +export module utils { + export module domNodeDisposal { + export function addDisposeCallback(node: Node, callback: (node: Node) => void): void; + export function removeDisposeCallback(node: Node, callback: (node: Node) => void): void; + export function cleanExternalData(node: Node): void; + } +} + +export function cleanNode(node: Node): typeof node; +export function removeNode(node: Node): void; + +//#endregion + +//#region utils.domManipulation.js + +export module utils { + export function parseHtmlFragment(html: string, documentContext?: Document): Node[]; + export function setHtml(node: Node, html: MaybeSubscribable): void; +} + +//#endregion + +//#region version.js + +export const version: string; + +//#endregion + +} diff --git a/packages/bind/spec/arrayToDomEditDetectionBehaviors.ts b/packages/bind/spec/arrayToDomEditDetectionBehaviors.ts index 7f243deac..5787495c6 100644 --- a/packages/bind/spec/arrayToDomEditDetectionBehaviors.ts +++ b/packages/bind/spec/arrayToDomEditDetectionBehaviors.ts @@ -13,8 +13,6 @@ import { import '@tko/utils/helpers/jasmine-13-helper' -import {} from "jasmine" - declare var testNode : any function copyDomNodeChildren (domNode : HTMLElement) { diff --git a/packages/bind/spec/bindingAttributeBehaviors.ts b/packages/bind/spec/bindingAttributeBehaviors.ts index 57e266da2..6d46e2b33 100644 --- a/packages/bind/spec/bindingAttributeBehaviors.ts +++ b/packages/bind/spec/bindingAttributeBehaviors.ts @@ -164,7 +164,7 @@ describe('Binding attribute syntax', function () { this.after(function () { options.onError = saved_obe }) - options.onError = function (spec) { + options.onError = function (spec: any) { obe_calls++ expect(spec.during).toEqual('init') expect(spec.errorCaptured.message).toMatch(/Message: A moth!$/) @@ -189,7 +189,7 @@ describe('Binding attribute syntax', function () { this.after(function () { options.onError = saved_obe }) - options.onError = function (spec) { + options.onError = function (spec: any) { obe_calls++ expect(spec.during).toEqual('update') expect(spec.errorCaptured.message).toMatch(/A beetle!$/) @@ -217,7 +217,7 @@ describe('Binding attribute syntax', function () { options.onError = saved_obe }) - options.onError = function (spec) { + options.onError = function (spec: any) { obe_calls++ expect(spec.during).toEqual('update') expect(spec.errorCaptured.message).toMatch(/Observable: 42$/) @@ -266,7 +266,7 @@ describe('Binding attribute syntax', function () { var oxy = koObservable() this.after(function () { options.set('onError', undefined) }) options.set('onError', function (err) { - expect(err.message.indexOf('turtle')).toNotEqual(-1) + expect(err.message.indexOf('turtle')).not.toEqual(-1) // Check for the `spec` properties expect(err.bindingKey).toEqual('test') oe_calls++ diff --git a/packages/bind/src/arrayToDomNodeChildren.ts b/packages/bind/src/arrayToDomNodeChildren.ts index 6f61e1cf9..487a0e82b 100644 --- a/packages/bind/src/arrayToDomNodeChildren.ts +++ b/packages/bind/src/arrayToDomNodeChildren.ts @@ -23,8 +23,8 @@ import { computed } from '@tko/computed' function mapNodeAndRefreshWhenChanged (containerNode, mapping, valueToMap, callbackAfterAddingNodes, index) { // Map this array value inside a dependentObservable so we re-map when any dependency changes - var mappedNodes = new Array() - var dependentObservable = computed(function () { + const mappedNodes = new Array() + const dependentObservable = computed(function () { var newMappedNodes = mapping(valueToMap, index, fixUpContinuousNodeArray(mappedNodes, containerNode)) || [] // On subsequent evaluations, just replace the previously-inserted DOM nodes diff --git a/tsconfig.json b/tsconfig.json index 0ac212306..0fa681f64 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,6 @@ { "compileOnSave": false, + "declaration": true, "compilerOptions": { "downlevelIteration": true, "target": "ES6", @@ -11,7 +12,7 @@ "baseUrl": ".", "noEmit": true, /*Disable some typing feature from ts to detect first steps to a strong typed version*/ - "noImplicitAny": false, + "noImplicitAny": false, "noImplicitThis": false, "noImplicitOverride": false, "noImplicitReturns": false, @@ -19,6 +20,7 @@ "strictPropertyInitialization": false, "strictBindCallApply": false, "strictFunctionTypes": false, + "skipLibCheck": true, /* END Disabling */ "paths": { "@tko/utils/helpers/jasmine-13-helper": [ From 4c954676178c78f96bce4a2610a6fd3c90c04621 Mon Sep 17 00:00:00 2001 From: phillipc Date: Thu, 9 Jan 2025 21:17:24 +0100 Subject: [PATCH 013/190] TS) fix wrong jasmine imports fix method signature --- packages/bind/spec/arrayToDomEditDetectionBehaviors.ts | 2 -- packages/binding.template/src/templating.ts | 2 +- packages/provider.multi/spec/MultiProviderBehaviors.ts | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/bind/spec/arrayToDomEditDetectionBehaviors.ts b/packages/bind/spec/arrayToDomEditDetectionBehaviors.ts index 7f243deac..5787495c6 100644 --- a/packages/bind/spec/arrayToDomEditDetectionBehaviors.ts +++ b/packages/bind/spec/arrayToDomEditDetectionBehaviors.ts @@ -13,8 +13,6 @@ import { import '@tko/utils/helpers/jasmine-13-helper' -import {} from "jasmine" - declare var testNode : any function copyDomNodeChildren (domNode : HTMLElement) { diff --git a/packages/binding.template/src/templating.ts b/packages/binding.template/src/templating.ts index e16cbabff..f336ea44e 100644 --- a/packages/binding.template/src/templating.ts +++ b/packages/binding.template/src/templating.ts @@ -155,7 +155,7 @@ function resolveTemplateName (template, data, context) { } } -export function renderTemplate (template, dataOrBindingContext, options, targetNodeOrNodeArray, renderMode, afterBindingCallback) { +export function renderTemplate (template, dataOrBindingContext, options, targetNodeOrNodeArray, renderMode?, afterBindingCallback?) { options = options || {} if ((options.templateEngine || _templateEngine) === undefined) { throw new Error('Set a template engine before calling renderTemplate') } renderMode = renderMode || 'replaceChildren' diff --git a/packages/provider.multi/spec/MultiProviderBehaviors.ts b/packages/provider.multi/spec/MultiProviderBehaviors.ts index e0b3b0c2a..9848b4099 100644 --- a/packages/provider.multi/spec/MultiProviderBehaviors.ts +++ b/packages/provider.multi/spec/MultiProviderBehaviors.ts @@ -3,7 +3,6 @@ import { MultiProvider } from '../dist' -import {} from "jasmine" import { assert } from "chai" describe('MultiProvider Behavior', function () { From 5c1be03abaf247d4199a21f44343bd633b29039e Mon Sep 17 00:00:00 2001 From: phillipc Date: Thu, 9 Jan 2025 21:41:33 +0100 Subject: [PATCH 014/190] ts) add assertion --- packages/utils.parser/spec/filterBehaviors.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/utils.parser/spec/filterBehaviors.ts b/packages/utils.parser/spec/filterBehaviors.ts index 21b373c23..f8fb7d22f 100644 --- a/packages/utils.parser/spec/filterBehaviors.ts +++ b/packages/utils.parser/spec/filterBehaviors.ts @@ -91,7 +91,7 @@ describe('filters', function () { }) describe('root', () => { - let _testRoot = null + let _testRoot : any = null options.filters.setRoot = function (v) { _testRoot = this } @@ -107,7 +107,8 @@ describe('filters', function () { const ourRoot = ctxStub({v: 'tt'}) const p = new Parser().parse('b: v | uppercase | setRoot', ourRoot) p.b() - assert.strictEqual(_testRoot.lookup, ourRoot.lookup) + assert.notEqual(_testRoot, null) + assert.strictEqual(_testRoot?.lookup, ourRoot.lookup) }) }) }) From 5838247af4003ccd337b471d598a7dfa31d00254 Mon Sep 17 00:00:00 2001 From: mcselle Date: Thu, 9 Jan 2025 17:04:02 +0100 Subject: [PATCH 015/190] fixing tsc errors --- packages/bind/src/bindingContext.ts | 2 +- packages/lifecycle/src/LifeCycle.ts | 2 +- packages/observable/src/observable.ts | 4 +- packages/utils.jsx/spec/jsxBehaviors.ts | 2 +- packages/utils.jsx/src/JsxObserver.ts | 47 ++++++++++------ packages/utils.jsx/src/jsxClean.ts | 2 +- .../utils.parser/spec/namespaceBehaviors.ts | 2 - packages/utils.parser/spec/parserBehaviors.ts | 55 +++---------------- .../spec/preprocessingBehavior.ts | 2 + 9 files changed, 47 insertions(+), 71 deletions(-) diff --git a/packages/bind/src/bindingContext.ts b/packages/bind/src/bindingContext.ts index 3316596db..ff19de2bb 100644 --- a/packages/bind/src/bindingContext.ts +++ b/packages/bind/src/bindingContext.ts @@ -25,7 +25,7 @@ export interface BindingContextSetting { // The bindingContext constructor is only called directly to create the root context. For child // contexts, use bindingContext.createChildContext or bindingContext.extend. -export function bindingContext (dataItemOrAccessor, parentContext, dataItemAlias, extendCallback, settings? : BindingContextSetting) { +export function bindingContext (dataItemOrAccessor, parentContext?, dataItemAlias?, extendCallback?, settings? : BindingContextSetting) { const self = this const shouldInheritData = dataItemOrAccessor === inheritParentIndicator const realDataItemOrAccessor = shouldInheritData ? undefined : dataItemOrAccessor diff --git a/packages/lifecycle/src/LifeCycle.ts b/packages/lifecycle/src/LifeCycle.ts index fb956cbd8..eca225e79 100644 --- a/packages/lifecycle/src/LifeCycle.ts +++ b/packages/lifecycle/src/LifeCycle.ts @@ -73,7 +73,7 @@ export default class LifeCycle { this.addDisposable({ dispose }) } - anchorTo (nodeOrLifeCycle) { + anchorTo (nodeOrLifeCycle:Node|LifeCycle) { if ('addDisposable' in nodeOrLifeCycle) { nodeOrLifeCycle.addDisposable(this) this[ANCHOR_NODE] = null // re-anchor on `anchorTo` calls diff --git a/packages/observable/src/observable.ts b/packages/observable/src/observable.ts index 7bbe7c6ff..ccce613a5 100644 --- a/packages/observable/src/observable.ts +++ b/packages/observable/src/observable.ts @@ -11,7 +11,7 @@ import { deferUpdates } from './defer' import { subscribable, defaultEvent, LATEST_VALUE } from './subscribable' import { valuesArePrimitiveAndEqual } from './extenders' -export function observable (initialValue?: any) :Observable { +export function observable(initialValue?: any):Observable{ function Observable () { if (arguments.length > 0) { // Write @@ -144,7 +144,7 @@ observable.fn[protoProperty] = observable // isObservable will be `true`. observable.observablePrototypes = new Set([observable]) -export function isObservable (instance) { +export function isObservable (instance:any): instance is Observable { const proto = typeof instance === 'function' && instance[protoProperty] if (proto && !observable.observablePrototypes.has(proto)) { throw Error('Invalid object that looks like an observable; possibly from another Knockout instance') diff --git a/packages/utils.jsx/spec/jsxBehaviors.ts b/packages/utils.jsx/spec/jsxBehaviors.ts index e8cfd3d18..9daf67a08 100644 --- a/packages/utils.jsx/spec/jsxBehaviors.ts +++ b/packages/utils.jsx/spec/jsxBehaviors.ts @@ -378,7 +378,7 @@ describe('jsx', function () { // The JSX preprocessor can generate sparse arrays with e.g. //
{/* thing */}
const parent = document.createElement('div') - const jsx = new Array() + const jsx: string[] = [] jsx[0] = 'a' jsx[1] = 'b' const jo = new JsxTestObserver(jsx, parent) diff --git a/packages/utils.jsx/src/JsxObserver.ts b/packages/utils.jsx/src/JsxObserver.ts index dcd08700a..295e3248d 100644 --- a/packages/utils.jsx/src/JsxObserver.ts +++ b/packages/utils.jsx/src/JsxObserver.ts @@ -47,15 +47,30 @@ function isIterable (v) { * @property {object} attributes */ +interface Changes { + index: number; + status: string; + value: any +} + /** * Observe a variety of possible cases from JSX, modifying the * `parentNode` at `insertBefore` with the result. */ export class JsxObserver extends LifeCycle { + adoptedInsertBefore: boolean + noInitialBinding: boolean + insertBefore: Node|null + parentNode:HTMLElement|Comment|HTMLTemplateElement + parentNodeTarget: Comment | ParentNode | null + subscriptionsForNode: any + nodeArrayOrObservableAtIndex: any + xmlns: any + /** * @param {any} jsxOrObservable take a long list of permutations */ - constructor (jsxOrObservable, parentNode, insertBefore = null, xmlns, noInitialBinding) { + constructor (jsxOrObservable, parentNode:HTMLElement|Comment|HTMLTemplateElement, insertBefore:Node | null = null, xmlns, noInitialBinding) { super() const parentNodeIsComment = parentNode.nodeType === 8 @@ -69,7 +84,7 @@ export class JsxObserver extends LifeCycle { if (!insertBefore) { const insertAt = parentNodeIsComment ? parentNode.nextSibling : null insertBefore = this.createComment('O') - parentNodeTarget.insertBefore(insertBefore, insertAt) + parentNodeTarget?.insertBefore(insertBefore, insertAt) } else { this.adoptedInsertBefore = true } @@ -103,12 +118,9 @@ export class JsxObserver extends LifeCycle { this.noInitialBinding = false } - /** - * @param {HMTLElement|Comment|HTMLTemplateElement} parentNode - */ - getParentTarget (parentNode) { + getParentTarget (parentNode:HTMLElement|Comment|HTMLTemplateElement): Comment | ParentNode | null { if ('content' in parentNode) { return parentNode.content } - if (parentNode.nodeType === 8) { return parentNode.parentNode } + if (parentNode.nodeType === 8) { return (parentNode as Comment).parentNode } return parentNode } @@ -118,7 +130,7 @@ export class JsxObserver extends LifeCycle { const ib = this.insertBefore const insertBeforeIsChild = ib && this.parentNodeTarget === ib.parentNode if (insertBeforeIsChild && !this.adoptedInsertBefore) { - this.parentNodeTarget.removeChild(ib) + this.parentNodeTarget?.removeChild(ib) } this.removeAllPriorNodes() Object.assign(this, { @@ -133,7 +145,7 @@ export class JsxObserver extends LifeCycle { this.subscriptionsForNode.clear() } - createInitialAdditions (possibleIterable) { + createInitialAdditions (possibleIterable):Changes[] { const status = 'added' if (typeof possibleIterable === 'object' && possibleIterable !== null && @@ -152,9 +164,10 @@ export class JsxObserver extends LifeCycle { * - to the new array indexes for adds * - sorted by index in ascending order */ - observableArrayChange (changes) { - let adds = new Array() - let dels = new Array() + observableArrayChange (changes:Changes[]) { + let adds:[number,any][] = [] + let dels:[number,any][] = [] + for (const index in changes) { const change = changes[index] if (change.status === 'added') { @@ -163,6 +176,7 @@ export class JsxObserver extends LifeCycle { dels.unshift([change.index, change.value]) } } + dels.forEach(change => this.delChange(...change)) adds.forEach(change => this.addChange(...change)) } @@ -173,7 +187,7 @@ export class JsxObserver extends LifeCycle { * @param {int} index * @param {string|object|Array|Observable.string|Observable.Array|Observable.object} jsx */ - addChange (index, jsx) { + addChange (index: number, jsx:string|object|Array|Observable|Observable|Observable) { this.nodeArrayOrObservableAtIndex.splice(index, 0, this.injectNode(jsx, this.lastNodeFor(index))) } @@ -192,7 +206,7 @@ export class JsxObserver extends LifeCycle { this.injectNode(child, nextNode)) } } else { - const $context = contextFor(this.parentNode) + const $context = contextFor(this.parentNode as HTMLElement) const isInsideTemplate = 'content' in this.parentNode const shouldApplyBindings = $context && !isInsideTemplate && !this.noInitialBinding @@ -203,7 +217,7 @@ export class JsxObserver extends LifeCycle { } for (const node of nodeArrayOrObservable) { - this.parentNodeTarget.insertBefore(node, nextNode) + this.parentNodeTarget?.insertBefore(node, nextNode) if (shouldApplyBindings && this.canApplyBindings(node)) { applyBindings($context, node) } @@ -213,6 +227,7 @@ export class JsxObserver extends LifeCycle { return nodeArrayOrObservable } + /** * True when Node is a type suitable for applyBindings i.e. a HTMLElement * or a Comment. @@ -222,7 +237,7 @@ export class JsxObserver extends LifeCycle { return node.nodeType === 1 || node.nodeType === 8 } - delChange (index) { + delChange (index:number, _:any) { this.removeNodeArrayOrObservable( this.nodeArrayOrObservableAtIndex[index]) this.nodeArrayOrObservableAtIndex.splice(index, 1) diff --git a/packages/utils.jsx/src/jsxClean.ts b/packages/utils.jsx/src/jsxClean.ts index 96762adfd..10b508b2d 100644 --- a/packages/utils.jsx/src/jsxClean.ts +++ b/packages/utils.jsx/src/jsxClean.ts @@ -5,7 +5,7 @@ import { const DELAY_MS = 25 const MAX_CLEAN_AT_ONCE = 1000 const cleanNodeQueue = new Array() -let cleanNodeTimeoutID = null +let cleanNodeTimeoutID:NodeJS.Timeout|null = null export function queueCleanNode (node) { cleanNodeQueue.push(node) diff --git a/packages/utils.parser/spec/namespaceBehaviors.ts b/packages/utils.parser/spec/namespaceBehaviors.ts index 97e6b1ef8..b8ab6872b 100644 --- a/packages/utils.parser/spec/namespaceBehaviors.ts +++ b/packages/utils.parser/spec/namespaceBehaviors.ts @@ -40,8 +40,6 @@ describe('Parser Namespace', function () { assert.deepEqual(p.on(), expect) } - it.skip('Should call bindings with a period e.g. x.y') // ? - it('namespace.attr returns an object', function () { trial({v: 't'}, 'on.p: v', { p: 't' }) }) diff --git a/packages/utils.parser/spec/parserBehaviors.ts b/packages/utils.parser/spec/parserBehaviors.ts index 3c2977977..70ba69ef9 100644 --- a/packages/utils.parser/spec/parserBehaviors.ts +++ b/packages/utils.parser/spec/parserBehaviors.ts @@ -463,17 +463,6 @@ describe('unary operations', function () { assert.equal(bindings.neg(), 3) }) - it.skip('negates an expression eg !(a || b)' - /*, function () { - var binding = 'ne: !(a || b)', - context = { a: observable(true), b: observable(false) }, - bindings = makeBindings(binding, context); - assert.equal(bindings.ne(), false) - context.a(false) - assert.equal(bindings.ne(), true) - } */ - ) - describe('lambdas (=>)', function () { it('evaluates the expression when called', function () { var binding = 'x: => y(true)', @@ -683,15 +672,6 @@ describe('anonymous functions', function () { function b () { new Parser(null, {}).parse(binding) } assert.throws(b, 'Anonymous functions are no longer') }) - - it.skip('parses a function () { return v }', function () { - var binding = 'x: function () { return v() }', - val = observable(125), - context = { v: function () { return val(val() + 1) } }, - bindings = makeBindings(binding, context); - assert.equal(typeof bindings.x()(), '126') - assert.equal(val(), 126); - }) }) describe('array accessors - []', function () { @@ -764,17 +744,6 @@ describe('array accessors - []', function () { assert.deepEqual(bindings.neg(), [1, o, 'z', 'E', 'aOc']) }) - it('unwraps Identifier/Expression contents' - /*, function () { - var binding = "arr: [a, a && b]", - context = { a: observable(true), b: observable(false) }, - bindings = makeBindings(binding, context); - assert.equal(bindings.arr()[0], true) - assert.equal(bindings.arr()[1], false) - context.b(true) - assert.equal(bindings.arr()[1], true) - } */ - ) }) describe('Virtual elements', function () { @@ -878,6 +847,10 @@ describe('ES6-style interpolated strings', function () { }) }) +interface ExtendedObservable{ + P?: any; +} + describe('compound expressions', function () { var d = 42, e = [9, 8], @@ -922,7 +895,7 @@ describe('compound expressions', function () { }, context, $context, - obs = observable({ + obs:Observable & ExtendedObservable = observable({ d: d }); @@ -976,14 +949,6 @@ describe('compound expressions', function () { expect_equal('u', undefined) }) - it.skip("throws 'missing'", function () { - /* It's up to the BindingContext instance to decide whether to - throw on a missing property */ - assert.throws(function () { - new Parser(null).parse('v: missing', $context).v() - }, 'not found') - }) - it("returns undefined when 'r' is not on u", function () { expect_equal('u.r', undefined) // undefined expect_equal('u.r.q', undefined) // undefined @@ -998,12 +963,12 @@ describe('compound expressions', function () { }) it("gets 'brick' from x.y[0]()()[1].yf2b", function () { - var expect = x.y[0]()()[1].yf2b; + var expect = (x.y[0]()as any)()[1].yf2b; expect_equal('x.y[0]()()[1].yf2b', expect) }) it("gets 'air' from x . y [ 0 ] ( ) ( ) [ 0 ] . yf2a", function () { - var expect = x.y[0]()()[0].yf2a; + var expect = (x.y[0]() as any)()[0].yf2a; expect_equal('\n\r\t x\n\r\t .\n\r\t y\n\r\t [\n\r\t 0' + '\n\r\t ]\n\r\t (\n\r\t )\n\r\t (\n\r\t )\n\r\t [' + '\n\r\t 0\n\r\t ]\n\r\t .\n\r\t yf2a', expect) @@ -1055,7 +1020,7 @@ describe('compound expressions', function () { }) describe('function expressions', function () { - function R () { return arguments } + function R (...args:any[]) { return arguments } function R0 () { return arguments[0] } function B () { return { self: this, args: arguments } } beforeEach(function () { context = { R: R, B: B, R0: R0 } }) @@ -1093,9 +1058,5 @@ describe('compound expressions', function () { '1i3' ) }) - - it.skip('calls functions with .bind', function () { - expect_deep_equal("B.bind('x')()", { self: 'x', args: [] }) - }) }) }); // compound functions diff --git a/packages/utils.parser/spec/preprocessingBehavior.ts b/packages/utils.parser/spec/preprocessingBehavior.ts index 451f7d385..fd461b998 100644 --- a/packages/utils.parser/spec/preprocessingBehavior.ts +++ b/packages/utils.parser/spec/preprocessingBehavior.ts @@ -2,6 +2,8 @@ import { DataBindProvider } from '@tko/provider.databind' +import { expect } from 'chai' + describe('Binding preprocessing', function () { var bindingHandlers, preProcessBindings From 309b9f9125cc3e191459a2098dbdb41c3924b0bb Mon Sep 17 00:00:00 2001 From: mcselle Date: Thu, 9 Jan 2025 17:16:44 +0100 Subject: [PATCH 016/190] functionrewrite fix --- .../utils.functionrewrite/spec/functionRewriteBehavior.ts | 2 ++ packages/utils.functionrewrite/src/functionRewrite.ts | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/utils.functionrewrite/spec/functionRewriteBehavior.ts b/packages/utils.functionrewrite/spec/functionRewriteBehavior.ts index 983c78d37..92f56bd0a 100644 --- a/packages/utils.functionrewrite/spec/functionRewriteBehavior.ts +++ b/packages/utils.functionrewrite/spec/functionRewriteBehavior.ts @@ -3,6 +3,8 @@ import { functionRewrite } from '../dist' +import { assert } from "chai"; + describe('Function Rewrite Provider', function () { describe('replaceFunctionStrings', function () { const tryExpect = { diff --git a/packages/utils.functionrewrite/src/functionRewrite.ts b/packages/utils.functionrewrite/src/functionRewrite.ts index beec270bc..937b679f0 100644 --- a/packages/utils.functionrewrite/src/functionRewrite.ts +++ b/packages/utils.functionrewrite/src/functionRewrite.ts @@ -6,7 +6,7 @@ const FUNCTION_REX = /\bfunction\s*\(([^)]*)\)\s*\{\s*(?:(return\s)?([^}]+?)[;\s]*)?\}/g -export default function functionRewrite (bindingString) { +export default function functionRewrite (bindingString:string):string { return bindingString .replace(FUNCTION_REX, (match, args, returnKeyword, rv) => { if (rv && !returnKeyword) { @@ -19,3 +19,5 @@ export default function functionRewrite (bindingString) { return out }) } + +functionRewrite.silent = false; \ No newline at end of file From 26b3f73c6325ef988189cfc5f46f92005ba48cef Mon Sep 17 00:00:00 2001 From: mcselle Date: Fri, 10 Jan 2025 09:35:14 +0100 Subject: [PATCH 017/190] more tsc fixes --- packages/utils.component/src/registry.ts | 2 +- packages/utils/src/array.ts | 2 +- packages/utils/src/dom/html.ts | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/utils.component/src/registry.ts b/packages/utils.component/src/registry.ts index 066ec9bff..13ce0cb2d 100644 --- a/packages/utils.component/src/registry.ts +++ b/packages/utils.component/src/registry.ts @@ -135,5 +135,5 @@ export var registry = { _getFirstResultFromLoaders: getFirstResultFromLoaders, - loaders: [] + loaders: new Array() } diff --git a/packages/utils/src/array.ts b/packages/utils/src/array.ts index 50a8ed795..6ed21b4f2 100644 --- a/packages/utils/src/array.ts +++ b/packages/utils/src/array.ts @@ -66,7 +66,7 @@ export function addOrRemoveItem (array, value, included) { } } -export function makeArray (arrayLikeObject) { +export function makeArray (arrayLikeObject:ArrayLike):T[] { return Array.from(arrayLikeObject) } diff --git a/packages/utils/src/dom/html.ts b/packages/utils/src/dom/html.ts index 990233260..0eae524d4 100644 --- a/packages/utils/src/dom/html.ts +++ b/packages/utils/src/dom/html.ts @@ -43,7 +43,7 @@ function getWrap (tags) { return (m && lookup[m[1]]) || none } -function simpleHtmlParse (html, documentContext) { +function simpleHtmlParse (html: string, documentContext) { documentContext || (documentContext = document) var windowContext = documentContext['parentWindow'] || documentContext['defaultView'] || window @@ -78,20 +78,20 @@ function simpleHtmlParse (html, documentContext) { return makeArray(div.lastChild.childNodes) } -function templateHtmlParse (html, documentContext) { +function templateHtmlParse (html: string, documentContext): ChildNode[] { if (!documentContext) { documentContext = document } - var template = documentContext.createElement('template') + var template = documentContext.createElement('template') as HTMLTemplateElement template.innerHTML = html return makeArray(template.content.childNodes) } -function jQueryHtmlParse (html, documentContext) { +function jQueryHtmlParse (html: string, documentContext: any) { // jQuery's "parseHTML" function was introduced in jQuery 1.8.0 and is a documented public API. if (jQueryInstance.parseHTML) { return jQueryInstance.parseHTML(html, documentContext) || [] // Ensure we always return an array and never null } else { // For jQuery < 1.8.0, we fall back on the undocumented internal "clean" function. - var elems = jQueryInstance.clean([html], documentContext) + var elems = (jQueryInstance as any).clean([html], documentContext) // As of jQuery 1.7.1, jQuery parses the HTML by appending it to some dummy parent nodes held in an in-memory document fragment. // Unfortunately, it never clears the dummy parent nodes from the document fragment, so it leaks memory over time. @@ -118,7 +118,7 @@ function jQueryHtmlParse (html, documentContext) { * @param {Object} documentContext That owns the executing code. * @return {[DOMNode]} Parsed DOM Nodes */ -export function parseHtmlFragment (html, documentContext) { +export function parseHtmlFragment (html: string , documentContext?: object): Node[] { // Prefer