From fcb4bff7166821746af0267e04fecf2c1a4e4625 Mon Sep 17 00:00:00 2001 From: Armano Date: Tue, 31 Dec 2019 01:51:07 +0100 Subject: [PATCH 1/4] test(typescript-estree): correct storing regexp in snapshots drop usage of JSON parse/stringify in tests --- .cspell.json | 2 +- packages/typescript-estree/package.json | 2 - .../tests/ast-alignment/parse.ts | 9 +- .../tests/ast-alignment/spec.ts | 2 +- .../tests/ast-alignment/utils.ts | 122 +++++------------- .../lib/__snapshots__/javascript.ts.snap | 8 +- .../typescript-estree/tools/test-utils.ts | 94 ++++++++++---- yarn.lock | 12 -- 8 files changed, 112 insertions(+), 139 deletions(-) diff --git a/.cspell.json b/.cspell.json index b3e10009914b..39e8c795e7af 100644 --- a/.cspell.json +++ b/.cspell.json @@ -9,7 +9,7 @@ "**/**/CHANGELOG.md", "**/**/CONTRIBUTORS.md", "**/**/ROADMAP.md", - "**/*.json" + "**/*.{json,snap}" ], "dictionaries": [ "typescript", diff --git a/packages/typescript-estree/package.json b/packages/typescript-estree/package.json index 116293b04650..c4b272ada9b3 100644 --- a/packages/typescript-estree/package.json +++ b/packages/typescript-estree/package.json @@ -55,12 +55,10 @@ "@types/debug": "^4.1.5", "@types/glob": "^7.1.1", "@types/is-glob": "^4.0.1", - "@types/lodash.isplainobject": "^4.0.4", "@types/lodash.unescape": "^4.0.4", "@types/semver": "^6.2.0", "@types/tmp": "^0.1.0", "@typescript-eslint/shared-fixtures": "2.13.0", - "lodash.isplainobject": "4.0.6", "tmp": "^0.1.0", "typescript": "*" }, diff --git a/packages/typescript-estree/tests/ast-alignment/parse.ts b/packages/typescript-estree/tests/ast-alignment/parse.ts index a56efd778f64..42f6e0f68fcb 100644 --- a/packages/typescript-estree/tests/ast-alignment/parse.ts +++ b/packages/typescript-estree/tests/ast-alignment/parse.ts @@ -3,7 +3,6 @@ import { ParserPlugin } from '@babel/parser'; import { codeFrameColumns } from '@babel/code-frame'; import * as parser from '../../src/parser'; -import * as parseUtils from './utils'; function createError( message: string, @@ -92,14 +91,10 @@ export function parse( try { switch (opts.parser) { case '@typescript-eslint/typescript-estree': - result.ast = parseUtils.normalizeNodeTypes( - parseWithTypeScriptESTree(text, opts.jsx), - ); + result.ast = parseWithTypeScriptESTree(text, opts.jsx); break; case '@babel/parser': - result.ast = parseUtils.normalizeNodeTypes( - parseWithBabelParser(text, opts.jsx), - ); + result.ast = parseWithBabelParser(text, opts.jsx); break; default: throw new Error( diff --git a/packages/typescript-estree/tests/ast-alignment/spec.ts b/packages/typescript-estree/tests/ast-alignment/spec.ts index 4c16a4143c8d..9e308b73c643 100644 --- a/packages/typescript-estree/tests/ast-alignment/spec.ts +++ b/packages/typescript-estree/tests/ast-alignment/spec.ts @@ -78,7 +78,7 @@ fixturesToTest.forEach(fixture => { ), ).toEqual( parseUtils.removeLocationDataAndSourceTypeFromProgramNode( - typeScriptESTreeResult.ast, + parseUtils.preprocessTypescriptAST(typeScriptESTreeResult.ast), fixture.ignoreSourceType, ), ); diff --git a/packages/typescript-estree/tests/ast-alignment/utils.ts b/packages/typescript-estree/tests/ast-alignment/utils.ts index 78b7df66fe67..579e7b8487e1 100644 --- a/packages/typescript-estree/tests/ast-alignment/utils.ts +++ b/packages/typescript-estree/tests/ast-alignment/utils.ts @@ -1,90 +1,25 @@ // babel types are something we don't really care about /* eslint-disable @typescript-eslint/no-explicit-any */ -import { AST_NODE_TYPES } from '../../src/ts-estree'; -import isPlainObject from 'lodash.isplainobject'; - -/** - * By default, pretty-format (within Jest matchers) retains the names/types of nodes from the babylon AST, - * quick and dirty way to avoid that is to JSON.stringify and then JSON.parser the - * ASTs before comparing them with pretty-format - * - * @param {Object} ast raw AST - * @returns {Object} normalized AST - */ -export function normalizeNodeTypes(ast: any): any { - return JSON.parse(JSON.stringify(ast)); -} - -/** - * Removes the given keys from the given AST object recursively - * @param root A JavaScript object to remove keys from - * @param keysToOmit Names and predicate functions use to determine what keys to omit from the final object - * @param nodes advance ast modifications - * @returns {Object} formatted object - */ -export function omitDeep( - root: any, - keysToOmit: { key: string; predicate: Function }[], - nodes: Record void> = {}, -): any { - function shouldOmit(keyName: string, val: any): boolean { - if (keysToOmit?.length) { - return keysToOmit.some( - keyConfig => keyConfig.key === keyName && keyConfig.predicate(val), - ); - } - return false; - } - - function visit(node: any, parent: any): void { - if (!node) { - return; - } - - for (const prop in node) { - if (Object.prototype.hasOwnProperty.call(node, prop)) { - if (shouldOmit(prop, node[prop])) { - delete node[prop]; - continue; - } - - const child = node[prop]; - - if (Array.isArray(child)) { - for (const el of child) { - visit(el, node); - } - } else if (isPlainObject(child)) { - visit(child, node); - } - } - } - - if (typeof node.type === 'string' && node.type in nodes) { - nodes[node.type](node, parent); - } - } - - visit(root, null); - return root; -} +import { AST_NODE_TYPES, TSESTree } from '../../src/ts-estree'; +import { omitDeep } from '../../tools/test-utils'; +import * as BabelTypes from '@babel/types'; /** * Common predicates for Babylon AST preprocessing */ const always = (): boolean => true; -const ifNumber = (val: any): boolean => typeof val === 'number'; +const ifNumber = (val: unknown): boolean => typeof val === 'number'; /** * - Babylon wraps the "Program" node in an extra "File" node, normalize this for simplicity for now... * - Remove "start" and "end" values from Babylon nodes to reduce unimportant noise in diffs ("loc" data will still be in * each final AST and compared). * - * @param {Object} ast raw babylon AST - * @returns {Object} processed babylon AST + * @param ast raw babylon AST + * @returns processed babylon AST */ -export function preprocessBabylonAST(ast: any): any { - return omitDeep( +export function preprocessBabylonAST(ast: BabelTypes.File): BabelTypes.File { + return omitDeep( ast.program, [ { @@ -130,7 +65,7 @@ export function preprocessBabylonAST(ast: any): any { /** * Awaiting feedback on Babel issue https://github.com/babel/babel/issues/9231 */ - TSCallSignatureDeclaration(node: any) { + TSCallSignatureDeclaration(node) { if (node.typeAnnotation) { node.returnType = node.typeAnnotation; delete node.typeAnnotation; @@ -143,7 +78,7 @@ export function preprocessBabylonAST(ast: any): any { /** * Awaiting feedback on Babel issue https://github.com/babel/babel/issues/9231 */ - TSConstructSignatureDeclaration(node: any) { + TSConstructSignatureDeclaration(node) { if (node.typeAnnotation) { node.returnType = node.typeAnnotation; delete node.typeAnnotation; @@ -156,7 +91,7 @@ export function preprocessBabylonAST(ast: any): any { /** * Awaiting feedback on Babel issue https://github.com/babel/babel/issues/9231 */ - TSFunctionType(node: any) { + TSFunctionType(node) { if (node.typeAnnotation) { node.returnType = node.typeAnnotation; delete node.typeAnnotation; @@ -169,7 +104,7 @@ export function preprocessBabylonAST(ast: any): any { /** * Awaiting feedback on Babel issue https://github.com/babel/babel/issues/9231 */ - TSConstructorType(node: any) { + TSConstructorType(node) { if (node.typeAnnotation) { node.returnType = node.typeAnnotation; delete node.typeAnnotation; @@ -182,7 +117,7 @@ export function preprocessBabylonAST(ast: any): any { /** * Awaiting feedback on Babel issue https://github.com/babel/babel/issues/9231 */ - TSMethodSignature(node: any) { + TSMethodSignature(node) { if (node.typeAnnotation) { node.returnType = node.typeAnnotation; delete node.typeAnnotation; @@ -196,7 +131,7 @@ export function preprocessBabylonAST(ast: any): any { * We want this node to be different * @see https://github.com/JamesHenry/typescript-estree/issues/109 */ - TSTypeParameter(node: any) { + TSTypeParameter(node) { if (node.name) { node.name = { loc: { @@ -215,7 +150,7 @@ export function preprocessBabylonAST(ast: any): any { }; } }, - ClassProperty(node: any) { + ClassProperty(node) { /** * Babel: ClassProperty + abstract: true * ts-estree: TSAbstractClassProperty @@ -233,7 +168,7 @@ export function preprocessBabylonAST(ast: any): any { node.declare = false; } }, - TSExpressionWithTypeArguments(node: any, parent: any) { + TSExpressionWithTypeArguments(node, parent) { if (parent.type === 'TSInterfaceDeclaration') { node.type = 'TSInterfaceHeritage'; } else if ( @@ -244,7 +179,7 @@ export function preprocessBabylonAST(ast: any): any { } }, // https://github.com/prettier/prettier/issues/5817 - FunctionExpression(node: any, parent: any) { + FunctionExpression(node, parent) { if (parent.typeParameters && parent.type === 'Property') { node.typeParameters = parent.typeParameters; delete parent.typeParameters; @@ -266,17 +201,17 @@ export function preprocessBabylonAST(ast: any): any { * babel: sets optional property as true/undefined * ts-estree: sets optional property as true/false */ - MemberExpression(node: any) { + MemberExpression(node) { if (!node.optional) { node.optional = false; } }, - CallExpression(node: any) { + CallExpression(node) { if (!node.optional) { node.optional = false; } }, - OptionalCallExpression(node: any) { + OptionalCallExpression(node) { if (!node.optional) { node.optional = false; } @@ -286,7 +221,7 @@ export function preprocessBabylonAST(ast: any): any { * babel: sets asserts property as true/undefined * ts-estree: sets asserts property as true/false */ - TSTypePredicate(node: any) { + TSTypePredicate(node) { if (!node.asserts) { node.asserts = false; } @@ -302,9 +237,9 @@ export function preprocessBabylonAST(ast: any): any { * * See: https://github.com/babel/babel/issues/6681 * - * @param {Object} ast the raw AST with a Program node at its top level - * @param {boolean} ignoreSourceType fix for issues with unambiguous type detection - * @returns {Object} the ast with the location data removed from the Program node + * @param ast the raw AST with a Program node at its top level + * @param ignoreSourceType fix for issues with unambiguous type detection + * @returns the ast with the location data removed from the Program node */ export function removeLocationDataAndSourceTypeFromProgramNode( ast: any, @@ -317,3 +252,12 @@ export function removeLocationDataAndSourceTypeFromProgramNode( } return ast; } + +/** + * Returns a raw copy of the typescript AST + * @param ast the AST object + * @returns copy of the AST object + */ +export function preprocessTypescriptAST(ast: T): T { + return omitDeep(ast); +} diff --git a/packages/typescript-estree/tests/lib/__snapshots__/javascript.ts.snap b/packages/typescript-estree/tests/lib/__snapshots__/javascript.ts.snap index a73f908a3623..84f3780a21c2 100644 --- a/packages/typescript-estree/tests/lib/__snapshots__/javascript.ts.snap +++ b/packages/typescript-estree/tests/lib/__snapshots__/javascript.ts.snap @@ -132662,7 +132662,7 @@ Object { "pattern": "foo.", }, "type": "Literal", - "value": Object {}, + "value": /foo\\./, }, "loc": Object { "end": Object { @@ -132859,7 +132859,7 @@ Object { "pattern": "[\\\\u{0000000000000061}-\\\\u{7A}]", }, "type": "Literal", - "value": Object {}, + "value": /\\[\\\\u\\{0000000000000061\\}-\\\\u\\{7A\\}\\]/u, }, "loc": Object { "end": Object { @@ -133253,7 +133253,7 @@ Object { "pattern": "foo", }, "type": "Literal", - "value": Object {}, + "value": /foo/u, }, "loc": Object { "end": Object { @@ -133450,7 +133450,7 @@ Object { "pattern": "foo", }, "type": "Literal", - "value": Object {}, + "value": /foo/y, }, "loc": Object { "end": Object { diff --git a/packages/typescript-estree/tools/test-utils.ts b/packages/typescript-estree/tools/test-utils.ts index b9fcb51cab64..a33769e3076f 100644 --- a/packages/typescript-estree/tools/test-utils.ts +++ b/packages/typescript-estree/tools/test-utils.ts @@ -1,22 +1,6 @@ import * as parser from '../src/parser'; import { TSESTreeOptions } from '../src/parser-options'; -/** - * Returns a raw copy of the given AST - * @param {Object} ast the AST object - * @returns {Object} copy of the AST object - */ -export function getRaw(ast: parser.TSESTree.Program): parser.TSESTree.Program { - return JSON.parse( - JSON.stringify(ast, (key, value) => { - if ((key === 'start' || key === 'end') && typeof value === 'number') { - return undefined; - } - return value; - }), - ); -} - export function parseCodeAndGenerateServices( code: string, config: TSESTreeOptions, @@ -27,24 +11,24 @@ export function parseCodeAndGenerateServices( /** * Returns a function which can be used as the callback of a Jest test() block, * and which performs an assertion on the snapshot for the given code and config. - * @param {string} code The source code to parse - * @param {TSESTreeOptions} config the parser configuration - * @param {boolean} generateServices Flag determining whether to generate ast maps and program or not - * @returns {jest.ProvidesCallback} callback for Jest it() block + * @param code The source code to parse + * @param config the parser configuration + * @param generateServices Flag determining whether to generate ast maps and program or not + * @returns callback for Jest it() block */ export function createSnapshotTestBlock( code: string, config: TSESTreeOptions, generateServices?: true, -): () => void { +): jest.ProvidesCallback { /** - * @returns {Object} the AST object + * @returns the AST object */ function parse(): parser.TSESTree.Program { const ast = generateServices ? parser.parseAndGenerateServices(code, config).ast : parser.parse(code, config); - return getRaw(ast); + return omitDeep(ast); } return (): void => { @@ -84,3 +68,67 @@ export function isJSXFileType(fileType: string): boolean { } return fileType === 'js' || fileType === 'jsx' || fileType === 'tsx'; } + +/** + * Removes the given keys from the given AST object recursively + * @param root A JavaScript object to remove keys from + * @param keysToOmit Names and predicate functions use to determine what keys to omit from the final object + * @param nodes advance ast modifications + * @returns formatted object + */ +export function omitDeep>( + root: T, + keysToOmit: { key: string; predicate: (value: unknown) => boolean }[] = [], + nodes: Record void> = {}, +): T { + function isObjectLike(value: unknown | null): value is T { + return ( + typeof value === 'object' && !(value instanceof RegExp) && value !== null + ); + } + + function shouldOmit(keyName: string, val: unknown): boolean { + if (keysToOmit?.length) { + return keysToOmit.some( + keyConfig => keyConfig.key === keyName && keyConfig.predicate(val), + ); + } + return false; + } + + function visit(oNode: T, parent: T | null): T { + if (!Array.isArray(oNode) && !isObjectLike(oNode)) { + return oNode; + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const node: any = Array.isArray(oNode) ? [...oNode] : { ...oNode }; + + for (const prop in node) { + if (Object.prototype.hasOwnProperty.call(node, prop)) { + if (shouldOmit(prop, node[prop]) || typeof node[prop] === 'undefined') { + delete node[prop]; + continue; + } + + const child = node[prop]; + + if (Array.isArray(child)) { + node[prop] = []; + for (const el of child) { + node[prop].push(visit(el, node)); + } + } else if (isObjectLike(child)) { + node[prop] = visit(child, node); + } + } + } + + if (typeof node.type === 'string' && node.type in nodes) { + nodes[node.type](node, parent); + } + + return node; + } + + return visit(root, null); +} diff --git a/yarn.lock b/yarn.lock index 8ce1cf0d491b..56703239ab25 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1390,13 +1390,6 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.3.tgz#bdfd69d61e464dcc81b25159c270d75a73c1a636" integrity sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A== -"@types/lodash.isplainobject@^4.0.4": - version "4.0.6" - resolved "https://registry.yarnpkg.com/@types/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#757d2dcdecbb32f4452018b285a586776092efd1" - integrity sha512-8G41YFhmOl8Ck6NrwLK5hhnbz6ADfuDJP+zusDnX3PoYhfC60+H/rQE6zmdO4yFzPCPJPY4oGZK2spbXm6gYEA== - dependencies: - "@types/lodash" "*" - "@types/lodash.memoize@^4.1.4": version "4.1.6" resolved "https://registry.yarnpkg.com/@types/lodash.memoize/-/lodash.memoize-4.1.6.tgz#3221f981790a415cab1a239f25c17efd8b604c23" @@ -5487,11 +5480,6 @@ lodash.ismatch@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" integrity sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc= -lodash.isplainobject@4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" - integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= - lodash.map@^4.5.1: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" From 35ed0592a85d4aa5966ccbcbdce00c2753d95991 Mon Sep 17 00:00:00 2001 From: Armano Date: Tue, 31 Dec 2019 01:54:21 +0100 Subject: [PATCH 2/4] chore(typescript-estree): fix typo in comment --- packages/typescript-estree/src/parser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/typescript-estree/src/parser.ts b/packages/typescript-estree/src/parser.ts index 82755ef99079..fb62c090bb79 100644 --- a/packages/typescript-estree/src/parser.ts +++ b/packages/typescript-estree/src/parser.ts @@ -366,7 +366,7 @@ function parseAndGenerateServices( )!; /** - * Determine whatever or not two-way maps of converted AST nodes should be preserved + * Determine if two-way maps of converted AST nodes should be preserved * during the conversion process */ const shouldPreserveNodeMaps = From fc9b72e0891969d9a02eeb56cd4a8b91fb4bdf10 Mon Sep 17 00:00:00 2001 From: Armano Date: Tue, 31 Dec 2019 02:14:43 +0100 Subject: [PATCH 3/4] chore(typescript-estree): correct one invalid type --- packages/typescript-estree/tests/ast-alignment/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/typescript-estree/tests/ast-alignment/utils.ts b/packages/typescript-estree/tests/ast-alignment/utils.ts index 579e7b8487e1..0e705b52c095 100644 --- a/packages/typescript-estree/tests/ast-alignment/utils.ts +++ b/packages/typescript-estree/tests/ast-alignment/utils.ts @@ -18,7 +18,7 @@ const ifNumber = (val: unknown): boolean => typeof val === 'number'; * @param ast raw babylon AST * @returns processed babylon AST */ -export function preprocessBabylonAST(ast: BabelTypes.File): BabelTypes.File { +export function preprocessBabylonAST(ast: BabelTypes.File): any { return omitDeep( ast.program, [ From f224e6ddb7f66cb26e0028cce7d1756da6b90e40 Mon Sep 17 00:00:00 2001 From: Armano Date: Wed, 1 Jan 2020 02:47:24 +0100 Subject: [PATCH 4/4] test(typescript-estree): add recommended changes to omitDeep --- .../tests/ast-alignment/utils.ts | 10 ++-- .../typescript-estree/tools/test-utils.ts | 57 ++++++++++++------- 2 files changed, 42 insertions(+), 25 deletions(-) diff --git a/packages/typescript-estree/tests/ast-alignment/utils.ts b/packages/typescript-estree/tests/ast-alignment/utils.ts index 0e705b52c095..4830a7f1f5a5 100644 --- a/packages/typescript-estree/tests/ast-alignment/utils.ts +++ b/packages/typescript-estree/tests/ast-alignment/utils.ts @@ -1,7 +1,7 @@ // babel types are something we don't really care about /* eslint-disable @typescript-eslint/no-explicit-any */ import { AST_NODE_TYPES, TSESTree } from '../../src/ts-estree'; -import { omitDeep } from '../../tools/test-utils'; +import { deeplyCopy, omitDeep } from '../../tools/test-utils'; import * as BabelTypes from '@babel/types'; /** @@ -131,7 +131,7 @@ export function preprocessBabylonAST(ast: BabelTypes.File): any { * We want this node to be different * @see https://github.com/JamesHenry/typescript-estree/issues/109 */ - TSTypeParameter(node) { + TSTypeParameter(node: any) { if (node.name) { node.name = { loc: { @@ -168,7 +168,7 @@ export function preprocessBabylonAST(ast: BabelTypes.File): any { node.declare = false; } }, - TSExpressionWithTypeArguments(node, parent) { + TSExpressionWithTypeArguments(node, parent: any) { if (parent.type === 'TSInterfaceDeclaration') { node.type = 'TSInterfaceHeritage'; } else if ( @@ -179,7 +179,7 @@ export function preprocessBabylonAST(ast: BabelTypes.File): any { } }, // https://github.com/prettier/prettier/issues/5817 - FunctionExpression(node, parent) { + FunctionExpression(node: any, parent: any) { if (parent.typeParameters && parent.type === 'Property') { node.typeParameters = parent.typeParameters; delete parent.typeParameters; @@ -259,5 +259,5 @@ export function removeLocationDataAndSourceTypeFromProgramNode( * @returns copy of the AST object */ export function preprocessTypescriptAST(ast: T): T { - return omitDeep(ast); + return deeplyCopy(ast); } diff --git a/packages/typescript-estree/tools/test-utils.ts b/packages/typescript-estree/tools/test-utils.ts index a33769e3076f..2a9b2f11ddfa 100644 --- a/packages/typescript-estree/tools/test-utils.ts +++ b/packages/typescript-estree/tools/test-utils.ts @@ -28,7 +28,7 @@ export function createSnapshotTestBlock( const ast = generateServices ? parser.parseAndGenerateServices(code, config).ast : parser.parse(code, config); - return omitDeep(ast); + return deeplyCopy(ast); } return (): void => { @@ -69,24 +69,38 @@ export function isJSXFileType(fileType: string): boolean { return fileType === 'js' || fileType === 'jsx' || fileType === 'tsx'; } +/** + * Returns a raw copy of the typescript AST + * @param ast the AST object + * @returns copy of the AST object + */ +export function deeplyCopy(ast: T): T { + return omitDeep(ast) as T; +} + +type UnknownObject = Record; + +function isObjectLike(value: unknown | null): value is UnknownObject { + return ( + typeof value === 'object' && !(value instanceof RegExp) && value !== null + ); +} + /** * Removes the given keys from the given AST object recursively * @param root A JavaScript object to remove keys from * @param keysToOmit Names and predicate functions use to determine what keys to omit from the final object - * @param nodes advance ast modifications + * @param selectors advance ast modifications * @returns formatted object */ -export function omitDeep>( +export function omitDeep( root: T, keysToOmit: { key: string; predicate: (value: unknown) => boolean }[] = [], - nodes: Record void> = {}, -): T { - function isObjectLike(value: unknown | null): value is T { - return ( - typeof value === 'object' && !(value instanceof RegExp) && value !== null - ); - } - + selectors: Record< + string, + (node: UnknownObject, parent: UnknownObject | null) => void + > = {}, +): UnknownObject { function shouldOmit(keyName: string, val: unknown): boolean { if (keysToOmit?.length) { return keysToOmit.some( @@ -96,12 +110,15 @@ export function omitDeep>( return false; } - function visit(oNode: T, parent: T | null): T { + function visit( + oNode: UnknownObject, + parent: UnknownObject | null, + ): UnknownObject { if (!Array.isArray(oNode) && !isObjectLike(oNode)) { return oNode; } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const node: any = Array.isArray(oNode) ? [...oNode] : { ...oNode }; + + const node = { ...oNode }; for (const prop in node) { if (Object.prototype.hasOwnProperty.call(node, prop)) { @@ -111,24 +128,24 @@ export function omitDeep>( } const child = node[prop]; - if (Array.isArray(child)) { - node[prop] = []; + const value = []; for (const el of child) { - node[prop].push(visit(el, node)); + value.push(visit(el, node)); } + node[prop] = value; } else if (isObjectLike(child)) { node[prop] = visit(child, node); } } } - if (typeof node.type === 'string' && node.type in nodes) { - nodes[node.type](node, parent); + if (typeof node.type === 'string' && node.type in selectors) { + selectors[node.type](node, parent); } return node; } - return visit(root, null); + return visit(root as UnknownObject, null); } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy