mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-24 11:02:12 -08:00
feat(editor): Add Object
global completions (#5407)
* ✏️ Add i18n info * ⚡ Mount i18n keys * ✏️ Fix typos in tests * ✨ Add `Object` global completion * ✨ Add `Object` global options completions * 🧪 Add tests
This commit is contained in:
parent
d469a98073
commit
d7b3923c2f
|
@ -57,6 +57,15 @@ describe('Top-level completions', () => {
|
|||
expect(found[0].label).toBe('Math');
|
||||
});
|
||||
|
||||
test('should return Object completion for: {{ O| }}', () => {
|
||||
const found = completions('{{ O| }}');
|
||||
|
||||
if (!found) throw new Error('Expected to find completion');
|
||||
|
||||
expect(found).toHaveLength(1);
|
||||
expect(found[0].label).toBe('Object');
|
||||
});
|
||||
|
||||
test('should return dollar completions for: {{ $| }}', () => {
|
||||
expect(completions('{{ $| }}')).toHaveLength(dollarOptions().length);
|
||||
});
|
||||
|
@ -130,6 +139,17 @@ describe('Resolution-based completions', () => {
|
|||
);
|
||||
});
|
||||
|
||||
test('should return completions for Object methods: {{ Object.values({ abc: 123 }).| }}', () => {
|
||||
// @ts-expect-error Spied function is mistyped
|
||||
resolveParameterSpy.mockReturnValueOnce([123]);
|
||||
|
||||
const found = completions('{{ Object.values({ abc: 123 }).| }}');
|
||||
|
||||
if (!found) throw new Error('Expected to find completion');
|
||||
|
||||
expect(found).toHaveLength(natives('array').length + extensions('array').length);
|
||||
});
|
||||
|
||||
test('should return completions for object literal', () => {
|
||||
const object = { a: 1 };
|
||||
|
||||
|
@ -145,7 +165,7 @@ describe('Resolution-based completions', () => {
|
|||
const resolveParameterSpy = vi.spyOn(workflowHelpers, 'resolveParameter');
|
||||
const { $input } = mockProxy;
|
||||
|
||||
test('should return bracket-aware completions for: {{ $input.item.json.str.| }}', () => {
|
||||
test('should return bracket-aware completions for: {{ $input.item.json.str.|() }}', () => {
|
||||
resolveParameterSpy.mockReturnValue($input.item.json.str);
|
||||
|
||||
const found = completions('{{ $input.item.json.str.|() }}');
|
||||
|
@ -156,7 +176,7 @@ describe('Resolution-based completions', () => {
|
|||
expect(found.map((c) => c.label).every((l) => !l.endsWith('()')));
|
||||
});
|
||||
|
||||
test('should return bracket-aware completions for: {{ $input.item.json.num.| }}', () => {
|
||||
test('should return bracket-aware completions for: {{ $input.item.json.num.|() }}', () => {
|
||||
resolveParameterSpy.mockReturnValue($input.item.json.num);
|
||||
|
||||
const found = completions('{{ $input.item.json.num.|() }}');
|
||||
|
|
|
@ -32,6 +32,8 @@ export function datatypeCompletions(context: CompletionContext): CompletionResul
|
|||
|
||||
if (base === 'DateTime') {
|
||||
options = luxonStaticOptions().map(stripExcessParens(context));
|
||||
} else if (base === 'Object') {
|
||||
options = objectGlobalOptions().map(stripExcessParens(context));
|
||||
} else {
|
||||
let resolved: Resolved;
|
||||
|
||||
|
@ -287,6 +289,24 @@ export const luxonStaticOptions = () => {
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Methods defined on the global `Object`.
|
||||
*/
|
||||
export const objectGlobalOptions = () => {
|
||||
return ['assign', 'entries', 'keys', 'values'].map((key) => {
|
||||
const option: Completion = {
|
||||
label: key + '()',
|
||||
type: 'function',
|
||||
};
|
||||
|
||||
const info = i18n.globalObject[key];
|
||||
|
||||
if (info) option.info = info;
|
||||
|
||||
return option;
|
||||
});
|
||||
};
|
||||
|
||||
const regexes = {
|
||||
generalRef: /\$[^$]+\.([^{\s])*/, // $input. or $json. or similar ones
|
||||
selectorRef: /\$\(['"][\S\s]+['"]\)\.([^{\s])*/, // $('nodeName').
|
||||
|
@ -299,6 +319,7 @@ const regexes = {
|
|||
|
||||
mathGlobal: /Math\.([^{\s])*/, // Math.
|
||||
datetimeGlobal: /DateTime\.[^.}]*/, // DateTime.
|
||||
objectGlobal: /Object\.(\w+\(.*\)\.[^{\s]*)?/, // Object. or Object.method(arg).
|
||||
};
|
||||
|
||||
const DATATYPE_REGEX = new RegExp(
|
||||
|
|
|
@ -4,14 +4,13 @@ import { prefixMatch } from './utils';
|
|||
|
||||
/**
|
||||
* Completions offered at the initial position for any char other than `$`.
|
||||
*
|
||||
* Currently only `D...` for `DateTime` and `M...` for `Math`
|
||||
*/
|
||||
export function nonDollarCompletions(context: CompletionContext): CompletionResult | null {
|
||||
const dateTime = /(\s+)D[ateTim]*/;
|
||||
const math = /(\s+)M[ath]*/;
|
||||
const object = /(\s+)O[bject]*/;
|
||||
|
||||
const combinedRegex = new RegExp([dateTime.source, math.source].join('|'));
|
||||
const combinedRegex = new RegExp([dateTime.source, math.source, object.source].join('|'));
|
||||
|
||||
const word = context.matchBefore(combinedRegex);
|
||||
|
||||
|
@ -30,7 +29,10 @@ export function nonDollarCompletions(context: CompletionContext): CompletionResu
|
|||
{
|
||||
label: 'Math',
|
||||
type: 'keyword',
|
||||
info: i18n.rootVars.DateTime,
|
||||
},
|
||||
{
|
||||
label: 'Object',
|
||||
type: 'keyword',
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -368,6 +368,13 @@ export class I18nClass {
|
|||
'$workflow.name': this.baseText('codeNodeEditor.completer.$workflow.name'),
|
||||
};
|
||||
|
||||
globalObject: Record<string, string | undefined> = {
|
||||
assign: this.baseText('codeNodeEditor.completer.globalObject.assign'),
|
||||
entries: this.baseText('codeNodeEditor.completer.globalObject.entries'),
|
||||
keys: this.baseText('codeNodeEditor.completer.globalObject.keys'),
|
||||
values: this.baseText('codeNodeEditor.completer.globalObject.values'),
|
||||
};
|
||||
|
||||
luxonInstance: Record<string, string | undefined> = {
|
||||
// getters
|
||||
isValid: this.baseText('codeNodeEditor.completer.luxon.instanceMethods.isValid'),
|
||||
|
|
|
@ -135,6 +135,10 @@
|
|||
"codeNodeEditor.completer.$workflow.id": "The ID of the workflow",
|
||||
"codeNodeEditor.completer.$workflow.name": "The name of the workflow",
|
||||
"codeNodeEditor.completer.binary": "The item's binary (file) data",
|
||||
"codeNodeEditor.completer.globalObject.assign": "Copy of the object containing all enumerable own properties",
|
||||
"codeNodeEditor.completer.globalObject.entries": "The object's keys and values",
|
||||
"codeNodeEditor.completer.globalObject.keys": "The object's keys",
|
||||
"codeNodeEditor.completer.globalObject.values": "The object's values",
|
||||
"codeNodeEditor.completer.json": "The item's JSON data. When in doubt, use this",
|
||||
"codeNodeEditor.completer.luxon.dateTimeStaticMethods.fromFormat": "Create a DateTime from an input string and format string.",
|
||||
"codeNodeEditor.completer.luxon.dateTimeStaticMethods.fromHTTP": "Create a DateTime from an HTTP header date",
|
||||
|
|
Loading…
Reference in a new issue