Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@
"ajv-errors": "~3.0.0",
"ajv-formats": "~2.1.1",
"es-aggregate-error": "^1.0.7",
"expr-eval-fork": "^3.0.1",
"jsonpath-plus": "^10.3.0",
"lodash": "~4.17.23",
"lodash.topath": "^4.5.2",
"minimatch": "3.1.2",
"nimma": "0.2.3",
"pony-cause": "^1.1.1",
"simple-eval": "1.0.1",
"tslib": "^2.8.1"
},
"devDependencies": {
Expand Down
44 changes: 30 additions & 14 deletions packages/core/src/utils/replacer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Dictionary } from '@stoplight/types';
import _eval from 'simple-eval';
import { Parser, Value } from 'expr-eval-fork';

export type Transformer<V = Record<string, unknown>> = (this: V, ...args: unknown[]) => string;

Expand All @@ -18,28 +18,44 @@ export class Replacer<V extends Record<string, unknown>> {
}

public print(input: string, values: V): string {
return input.replace(this.regex, (substr, identifier, index) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
const parser = new Parser();
const functions = parser.functions as Record<string, (...args: Value[]) => Value>;
functions.toUpperCase = (value: Value): Value => {
return String(value).toUpperCase();
};

functions.concat = (...args: Value[]): Value => {
return args.map(String).join('');
};

Object.entries(this.functions).forEach(([name, fn]) => {
functions[name] = fn.bind(values) as (...args: Value[]) => Value;
});

const context = values as unknown as Record<string, Value>;

return input.replace(this.regex, (_substr, identifier: string, index: number) => {
if (index < 0 || index >= input.length) {
return '';
}

const shouldEvaluate = input[index] === '#';

if (shouldEvaluate) {
return String(
_eval(identifier, {
...Object.entries(this.functions).reduce((fns, [name, fn]) => {
fns[name] = fn.bind(values);
return fns;
}, {}),
...values,
}),
);
const expression = identifier
.trim()
.replace(/(\S+)\.toUpperCase\(\)/g, 'toUpperCase($1)')
.replace(/\s*\+\s*/g, ',')
.replace(/^(.+)$/, 'concat($1)');

return String(parser.evaluate(expression, context));
}

if (!(identifier in values)) {
return '';
}

// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
return String(values[identifier]);
return String(values[identifier as keyof V]);
});
}
}
18 changes: 8 additions & 10 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2984,14 +2984,14 @@ __metadata:
ajv-errors: ~3.0.0
ajv-formats: ~2.1.1
es-aggregate-error: ^1.0.7
expr-eval-fork: ^3.0.1
jsonpath-plus: ^10.3.0
lodash: ~4.17.23
lodash.topath: ^4.5.2
minimatch: 3.1.2
nimma: 0.2.3
nock: ^13.5.4
pony-cause: ^1.1.1
simple-eval: 1.0.1
treeify: ^1.1.0
tslib: ^2.8.1
languageName: unknown
Expand Down Expand Up @@ -6957,6 +6957,13 @@ __metadata:
languageName: node
linkType: hard

"expr-eval-fork@npm:^3.0.1":
version: 3.0.1
resolution: "expr-eval-fork@npm:3.0.1"
checksum: 8841b2a521415cecd15cb860078ffe99678c59ab427a50c033f91426db12dff6450c72bb0a3f8bbe5c7125a83ccfab47209411b46cf0da5acbb4cf97c91eb362
languageName: node
linkType: hard

"ext@npm:^1.1.2":
version: 1.4.0
resolution: "ext@npm:1.4.0"
Expand Down Expand Up @@ -12856,15 +12863,6 @@ __metadata:
languageName: node
linkType: hard

"simple-eval@npm:1.0.1":
version: 1.0.1
resolution: "simple-eval@npm:1.0.1"
dependencies:
jsep: ^1.3.6
checksum: 280207cfe4538c500f6b41e4d88576cf250337b0042bec8f9f5cf025b3a70e07974e522edd01e69d378767dd73068765d4f46ad55db5c94943c8f3585bff95af
languageName: node
linkType: hard

"simple-get@npm:^4.0.0":
version: 4.0.1
resolution: "simple-get@npm:4.0.1"
Expand Down