Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Expression extension framework #4372

Merged
merged 73 commits into from
Jan 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
4dcca35
:zap: Introduce a framework for expression extension
valya Sep 1, 2022
8bed02e
:bulb: Add some inline comments
valya Sep 1, 2022
e621548
:zap: Introduce hash alias for encrypt
valya Sep 2, 2022
a456849
:zap: Introduce a manual granular level approach to shadowing/overrid…
valya Sep 2, 2022
ab9610b
:fire: Cleanup comments
valya Sep 2, 2022
1a1936d
:zap: Introduce a basic method of extension for native functions
valya Sep 2, 2022
a55cbc8
:zap: Add length to StringExtension
valya Sep 5, 2022
56ee445
:zap: Add number type to extension return types
valya Sep 5, 2022
0b1dd25
:zap: Temporarily introduce DateTime with extension
valya Sep 5, 2022
e451d0c
:zap: Cleanup comments
valya Sep 5, 2022
38e6748
:zap: Organize imports
valya Sep 5, 2022
5def027
:recycle: Fix up some typings
valya Sep 5, 2022
0c0d038
:zap: Fix typings
valya Sep 5, 2022
244067f
:recycle: Remove unnecessary resolve of expression
valya Sep 5, 2022
d4f489c
:zap: Extensions Improvement
valya Sep 6, 2022
294fcec
:recycle: Refactor EXPRESSION_EXTENSION_METHODS
valya Sep 6, 2022
5ecea0d
:recycle: Refactor EXPRESSION_EXTENSION_METHODS
valya Sep 6, 2022
c039bae
Merge branch 'n8n-4486' of https://github.com/n8n-io/n8n into n8n-4486
valya Nov 9, 2022
e1e625d
:recycle: Update extraArgs types
valya Sep 6, 2022
38d9e16
:recycle: Fix tests
valya Sep 7, 2022
4d7d335
:recycle: Fix bind type issue
valya Sep 7, 2022
715d076
:recycle: Fixing duration type issue
valya Sep 7, 2022
df70f1b
:recycle: Refactor to allow overrides on native methods
valya Sep 7, 2022
ae507ec
:recycle: Temporarily remove Date Extensions to pass tests
valya Sep 8, 2022
d65b6c6
feat(dt-functions): introduce date expression extensions (#4045)
valya Sep 9, 2022
c4b94bc
:recycle: Refactor extension for native types
valya Sep 9, 2022
6593d16
:fire: Move sayHi method to String Extension class
valya Sep 9, 2022
0df9286
:recycle: Update scope when binding member methods
valya Sep 9, 2022
7e098f1
:white_check_mark: Add String Extension tests
valya Sep 9, 2022
b258e88
feat(dt-functions): introduce array expression extensions (#4044)
valya Sep 9, 2022
76a3235
feat(dt-functions): introduce number expression extensions (#4046)
valya Sep 10, 2022
4698913
Merge branch 'master' into n8n-4486
valya Nov 9, 2022
3f42b64
Fixed up tests
valya Nov 8, 2022
4658226
:fire: Remove remove markdown
valya Sep 11, 2022
44fd645
:recylce: Replace remove-markdown dependencies with implementation
valya Sep 11, 2022
92ebde6
:recycle: Replace remove-markdown dependencies with implementation
valya Sep 11, 2022
b245eb4
Merge branch 'n8n-4486' of https://github.com/n8n-io/n8n into n8n-4486
valya Sep 11, 2022
e41e45a
:white_check_mark: Update tests
valya Sep 12, 2022
9fb3bc1
:recycle: Fix scoping and cleanup
valya Sep 12, 2022
f99a5d2
:recycle: Update comments and errors
valya Sep 12, 2022
dfd7d4c
:recycle: Fix linting errors
valya Sep 12, 2022
da3454c
:heavy_minus_sign: Remove unused dependencies
valya Sep 12, 2022
212dc35
fix: expression extension not working with multiple extensions
valya Nov 9, 2022
574a39f
refactor: change extension transform to be more efficient
valya Oct 17, 2022
f57dab5
test: update most test to work with new extend function
valya Oct 18, 2022
316d5b5
Merge remote-tracking branch 'origin/master' into n8n-4486-implement-…
valya Nov 9, 2022
f4447ee
fix: update and fix type error in config
cstuncsik Oct 19, 2022
a5f6fff
refactor: replace babel with recast
valya Nov 9, 2022
2c6a92b
feat: add hashing functions to string extension
valya Oct 19, 2022
d19e4cc
fix: removed export
valya Oct 19, 2022
dda3579
Merge remote-tracking branch 'origin/master' into n8n-4486-implement-…
valya Oct 19, 2022
f2b21f0
test: add extension parser and transform tests
valya Oct 19, 2022
c67f707
fix: vite tests breaking
valya Oct 20, 2022
f1446a0
refactor: remove commented out code
valya Oct 24, 2022
2379e73
fix: parse dates passed from $json in extend function
valya Oct 24, 2022
34ef71d
refactor: review feedback changes for date extensions
valya Nov 1, 2022
ba83583
refactor: review feedback changes for number extensions
valya Nov 1, 2022
abe4a51
fix: date extension beginningOf test
valya Nov 1, 2022
41754d9
Merge remote-tracking branch 'origin/master' into n8n-4486-implement-…
valya Nov 9, 2022
eb9c291
fix: broken build from merge
valya Nov 9, 2022
1006672
Merge remote-tracking branch 'origin/master' into n8n-4486-implement-…
valya Nov 9, 2022
b5c8119
fix: another merge issue
valya Nov 9, 2022
5a8b553
refactor: address review feedback (remove ignores)
valya Nov 9, 2022
e23cd35
Merge remote-tracking branch 'origin/master' into n8n-4486-implement-…
valya Nov 10, 2022
0dae735
feat: new extension functions and tests
valya Nov 17, 2022
7b0d4a4
feat: non-dot notation functions
valya Nov 28, 2022
25de979
test: most of the other tests
valya Dec 1, 2022
7b5033b
Merge remote-tracking branch 'origin/master' into n8n-4486-implement-…
valya Dec 5, 2022
c31e9f1
fix: toSentenceCase for node versions below 16.6
valya Dec 5, 2022
f3a81bb
feat: add $if and $not expression extensions
valya Dec 12, 2022
c178d67
Merge master
krynble Jan 10, 2023
b03a763
Fix test to work on every timezone
krynble Jan 10, 2023
f00fc43
lint: fix remaining lint issues
valya Jan 10, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Jest: current file",
"program": "${workspaceFolder}/node_modules/.bin/jest",
"args": ["${fileBasenameNoExtension}"],
"console": "integratedTerminal",
"windows": {
"program": "${workspaceFolder}/node_modules/jest/bin/jest"
}
},
{
"name": "Attach to running n8n",
"processId": "${command:PickProcess}",
"request": "attach",
Expand Down
1 change: 1 addition & 0 deletions packages/editor-ui/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"importHelpers": true,
"incremental": false,
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"baseUrl": ".",
"types": ["vitest/globals"],
"paths": {
Expand Down
4 changes: 4 additions & 0 deletions packages/editor-ui/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ const lodashAliases = ['orderBy', 'camelCase', 'cloneDeep', 'isEqual', 'startCas

export default mergeConfig(
defineConfig({
define: {
// This causes test to fail but is required for actually running it
...(process.env.NODE_ENV !== 'test' ? { global: 'globalThis' } : {}),
},
plugins: [
legacy({
targets: ['defaults', 'not IE 11'],
Expand Down
6 changes: 6 additions & 0 deletions packages/workflow/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
"dist/**/*"
],
"devDependencies": {
"@n8n_io/eslint-config": "",
"@types/crypto-js": "^4.1.1",
"@types/express": "^4.17.6",
"@types/jmespath": "^0.15.0",
"@types/lodash.get": "^4.4.6",
Expand All @@ -50,12 +52,16 @@
},
"dependencies": {
"@n8n_io/riot-tmpl": "^2.0.0",
"crypto-js": "^4.1.1",
"jmespath": "^0.16.0",
"js-base64": "^3.7.2",
"lodash.get": "^4.4.2",
"lodash.isequal": "^4.5.0",
"lodash.merge": "^4.6.2",
"lodash.set": "^4.3.2",
"luxon": "~2.3.0",
"recast": "^0.21.5",
"transliteration": "^2.3.5",
"xml2js": "^0.4.23"
}
}
62 changes: 58 additions & 4 deletions packages/workflow/src/Expression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,21 @@ import {
NodeParameterValueType,
WorkflowExecuteMode,
} from './Interfaces';
import { ExpressionError } from './ExpressionError';
import { ExpressionError, ExpressionExtensionError } from './ExpressionError';
import { WorkflowDataProxy } from './WorkflowDataProxy';
import type { Workflow } from './Workflow';

// eslint-disable-next-line import/no-cycle
import { extend, hasExpressionExtension, hasNativeMethod } from './Extensions';
import {
ExpressionChunk,
ExpressionCode,
joinExpression,
splitExpression,
} from './Extensions/ExpressionParser';
import { extendTransform } from './Extensions/ExpressionExtension';
import { extendedFunctions } from './Extensions/ExtendedFunctions';

// Set it to use double curly brackets instead of single ones
tmpl.brackets.set('{{ }}');

Expand Down Expand Up @@ -242,6 +253,11 @@ export class Expression {
data.Boolean = Boolean;
data.Symbol = Symbol;

// expression extensions
data.extend = extend;

Object.assign(data, extendedFunctions);

const constructorValidation = new RegExp(/\.\s*constructor/gm);
if (parameterValue.match(constructorValidation)) {
throw new ExpressionError('Expression contains invalid constructor function call', {
Expand All @@ -252,7 +268,8 @@ export class Expression {
}

// Execute the expression
const returnValue = this.renderExpression(parameterValue, data);
const extendedExpression = this.extendSyntax(parameterValue);
const returnValue = this.renderExpression(extendedExpression, data);
if (typeof returnValue === 'function') {
if (returnValue.name === '$') throw new Error('invalid syntax');
throw new Error('This is a function. Please add ()');
Expand All @@ -267,7 +284,10 @@ export class Expression {
return returnValue;
}

private renderExpression(expression: string, data: IWorkflowDataProxyData): tmpl.ReturnValue {
private renderExpression(
expression: string,
data: IWorkflowDataProxyData,
): tmpl.ReturnValue | undefined {
try {
return tmpl.tmpl(expression, data);
} catch (error) {
Expand All @@ -279,10 +299,43 @@ export class Expression {
}
}
}

return null;
}

extendSyntax(bracketedExpression: string): string {
if (!hasExpressionExtension(bracketedExpression) || hasNativeMethod(bracketedExpression))
return bracketedExpression;

const chunks = splitExpression(bracketedExpression);

const extendedChunks = chunks.map((chunk): ExpressionChunk => {
if (chunk.type === 'code') {
const output = extendTransform(chunk.text);

// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
if (!output?.code) {
throw new ExpressionExtensionError('Failed to extend syntax');
}

let text = output.code;
// We need to cut off any trailing semicolons. These cause issues
// with certain types of expression and cause the whole expression
// to fail.
if (text.trim().endsWith(';')) {
text = text.trim().slice(0, -1);
}

return {
...chunk,
text,
} as ExpressionCode;
}
return chunk;
});

return joinExpression(extendedChunks);
}

/**
* Resolves value of parameter. But does not work for workflow-data.
*
Expand Down Expand Up @@ -439,6 +492,7 @@ export class Expression {
selfData,
);
}

return this.resolveSimpleParameterValue(
value as NodeParameterValue,
siblingParameters,
Expand Down
7 changes: 7 additions & 0 deletions packages/workflow/src/ExpressionError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,10 @@ export class ExpressionError extends ExecutionBaseError {
}
}
}

export class ExpressionExtensionError extends ExpressionError {
constructor(message: string) {
super(message);
this.context.failExecution = true;
}
}
Loading