Skip to content

Commit 21ecc4f

Browse files
authored
fix(jmespath): refactor custom function introspection to work with minification (#2384)
* fix(jmespath): preserve inheritance when introspecting methods * docs: document method * chore: update test case * chore: formatting * chore: fix test
1 parent 8145bc1 commit 21ecc4f

File tree

2 files changed

+45
-5
lines changed

2 files changed

+45
-5
lines changed

Diff for: packages/jmespath/src/Functions.ts

+24-2
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,11 @@ import { arityCheck, typeCheck } from './utils.js';
4848
* ```
4949
*/
5050
class Functions {
51+
/**
52+
* A set of all the custom functions available in this and all child classes.
53+
*/
5154
public methods: Set<string> = new Set();
55+
5256
/**
5357
* Get the absolute value of the provided number.
5458
*
@@ -528,14 +532,32 @@ class Functions {
528532
return Object.values(arg);
529533
}
530534

535+
/**
536+
* Lazily introspects the methods of the class instance and all child classes
537+
* to get the names of the methods that correspond to JMESPath functions.
538+
*
539+
* This method is used to get the names of the custom functions that are available
540+
* in the class instance and all child classes. The names of the functions are used
541+
* to create the custom function map that is passed to the JMESPath search function.
542+
*
543+
* The method traverses the inheritance chain going from the leaf class to the root class
544+
* and stops when it reaches the `Functions` class, which is the root class.
545+
*
546+
* In doing so, it collects the names of the methods that start with `func` and adds them
547+
* to the `methods` set. Finally, when the recursion collects back to the current instance,
548+
* it adds the collected methods to the `this.methods` set so that they can be accessed later.
549+
*
550+
* @param scope The scope of the class instance to introspect
551+
*/
531552
public introspectMethods(scope?: Functions): Set<string> {
532553
const prototype = Object.getPrototypeOf(this);
533-
const ownName = prototype.constructor.name;
534554
const methods = new Set<string>();
535-
if (ownName !== 'Functions') {
555+
if (this instanceof Functions) {
536556
for (const method of prototype.introspectMethods(scope)) {
537557
methods.add(method);
538558
}
559+
} else {
560+
return methods;
539561
}
540562

541563
// This block is executed for every class in the inheritance chain

Diff for: packages/jmespath/tests/unit/index.test.ts

+21-3
Original file line numberDiff line numberDiff line change
@@ -351,9 +351,6 @@ describe('Coverage tests', () => {
351351
it('uses the custom function extending the powertools custom functions', () => {
352352
// Prepare
353353
class CustomFunctions extends PowertoolsFunctions {
354-
public constructor() {
355-
super();
356-
}
357354
@PowertoolsFunctions.signature({
358355
argumentsSpecs: [['string']],
359356
})
@@ -384,5 +381,26 @@ describe('Coverage tests', () => {
384381
// Assess
385382
expect(messages).toStrictEqual(['hello world']);
386383
});
384+
385+
it('correctly registers all the custom functions', () => {
386+
// Prepare
387+
class CustomFunctions extends PowertoolsFunctions {
388+
@PowertoolsFunctions.signature({
389+
argumentsSpecs: [['string']],
390+
})
391+
public funcPassThrough(value: string): string {
392+
return value;
393+
}
394+
}
395+
396+
// Act
397+
const customFunctions = new CustomFunctions();
398+
search('pass_through(foo)', { foo: 'bar' }, { customFunctions });
399+
400+
// Assess
401+
expect(customFunctions.methods.size).toBeGreaterThan(
402+
new PowertoolsFunctions().methods.size
403+
);
404+
});
387405
});
388406
});

0 commit comments

Comments
 (0)