mirror of
https://github.com/n8n-io/n8n.git
synced 2025-02-21 02:56:40 -08:00
fix: CodeNodeEditor walk cannot read properties of null (#11129)
Some checks are pending
Test Master / install-and-build (push) Waiting to run
Test Master / Unit tests (18.x) (push) Blocked by required conditions
Test Master / Unit tests (20.x) (push) Blocked by required conditions
Test Master / Unit tests (22.4) (push) Blocked by required conditions
Test Master / Lint (push) Blocked by required conditions
Test Master / Notify Slack on failure (push) Blocked by required conditions
Some checks are pending
Test Master / install-and-build (push) Waiting to run
Test Master / Unit tests (18.x) (push) Blocked by required conditions
Test Master / Unit tests (20.x) (push) Blocked by required conditions
Test Master / Unit tests (22.4) (push) Blocked by required conditions
Test Master / Lint (push) Blocked by required conditions
Test Master / Notify Slack on failure (push) Blocked by required conditions
Co-authored-by: Elias Meire <elias@meire.dev>
This commit is contained in:
parent
40dd02f360
commit
d99e0a7c97
|
@ -0,0 +1,44 @@
|
||||||
|
import * as esprima from 'esprima-next';
|
||||||
|
import { walk } from './utils';
|
||||||
|
|
||||||
|
describe('CodeNodeEditor utils', () => {
|
||||||
|
describe('walk', () => {
|
||||||
|
it('should find the correct syntax nodes', () => {
|
||||||
|
const code = `const x = 'a'
|
||||||
|
function f(arg) {
|
||||||
|
arg['b'] = 1
|
||||||
|
return arg
|
||||||
|
}
|
||||||
|
|
||||||
|
const y = f({ a: 'c' })
|
||||||
|
`;
|
||||||
|
const program = esprima.parse(code);
|
||||||
|
const stringLiterals = walk(
|
||||||
|
program,
|
||||||
|
(node) => node.type === esprima.Syntax.Literal && typeof node.value === 'string',
|
||||||
|
);
|
||||||
|
expect(stringLiterals).toEqual([
|
||||||
|
new esprima.Literal('a', "'a'"),
|
||||||
|
new esprima.Literal('b', "'b'"),
|
||||||
|
new esprima.Literal('c', "'c'"),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle null syntax nodes', () => {
|
||||||
|
// ,, in [1,,2] results in a `null` ArrayExpressionElement
|
||||||
|
const code = 'const fn = () => [1,,2]';
|
||||||
|
const program = esprima.parse(code);
|
||||||
|
const arrayExpressions = walk(
|
||||||
|
program,
|
||||||
|
(node) => node.type === esprima.Syntax.ArrayExpression,
|
||||||
|
);
|
||||||
|
expect(arrayExpressions).toEqual([
|
||||||
|
new esprima.ArrayExpression([
|
||||||
|
new esprima.Literal(1, '1'),
|
||||||
|
null,
|
||||||
|
new esprima.Literal(2, '2'),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,29 +1,33 @@
|
||||||
import type * as esprima from 'esprima-next';
|
import * as esprima from 'esprima-next';
|
||||||
import type { Completion } from '@codemirror/autocomplete';
|
import type { Completion } from '@codemirror/autocomplete';
|
||||||
import type { Node } from 'estree';
|
|
||||||
import type { RangeNode } from './types';
|
import type { RangeNode } from './types';
|
||||||
import { sanitizeHtml } from '@/utils/htmlUtils';
|
import { sanitizeHtml } from '@/utils/htmlUtils';
|
||||||
|
import type { Node } from 'estree';
|
||||||
|
|
||||||
export function walk<T extends RangeNode>(
|
export function walk<T extends RangeNode>(
|
||||||
node: Node | esprima.Program,
|
node: Node | esprima.Program,
|
||||||
test: (node: Node) => boolean,
|
test: (node: Node) => boolean,
|
||||||
found: Node[] = [],
|
found: Node[] = [],
|
||||||
) {
|
) {
|
||||||
// @ts-ignore
|
const isProgram = node.type === esprima.Syntax.Program;
|
||||||
if (test(node)) found.push(node);
|
if (!isProgram && test(node)) found.push(node);
|
||||||
|
|
||||||
for (const key in node) {
|
if (isProgram) {
|
||||||
if (!(key in node)) continue;
|
node.body.forEach((n) => walk(n as Node, test, found));
|
||||||
|
} else {
|
||||||
|
for (const key in node) {
|
||||||
|
if (!(key in node)) continue;
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-expect-error Node is not string indexable, but it has many possible properties
|
||||||
const child = node[key];
|
const child = node[key];
|
||||||
|
|
||||||
if (child === null || typeof child !== 'object') continue;
|
if (child === null || typeof child !== 'object') continue;
|
||||||
|
|
||||||
if (Array.isArray(child)) {
|
if (Array.isArray(child)) {
|
||||||
child.forEach((node) => walk(node, test, found));
|
child.filter(Boolean).forEach((n) => walk(n, test, found));
|
||||||
} else {
|
} else {
|
||||||
walk(child, test, found);
|
walk(child, test, found);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue