Skip to content

Commit edc186d

Browse files
Merge branch 'bugfix/LF-2530/support-quoted-variable-names' into 'master'
Support quoted variable names See merge request lfor/fhirpath.js!26
2 parents 25ea062 + 8bf1ba2 commit edc186d

File tree

5 files changed

+63
-29
lines changed

5 files changed

+63
-29
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
This log documents significant changes for each release. This project follows
44
[Semantic Versioning](http://semver.org/).
55

6+
## [3.16.4] - 2025-01-24
7+
### Fixed
8+
- Bug where single-quoted variable names were not supported.
9+
610
## [3.16.3] - 2025-01-21
711
### Fixed
812
- Bug with async boolean expressions (when an operator takes an async value as

package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "fhirpath",
3-
"version": "3.16.3",
3+
"version": "3.16.4",
44
"description": "A FHIRPath engine",
55
"main": "src/fhirpath.js",
66
"types": "src/fhirpath.d.ts",

src/fhirpath.js

+50-25
Original file line numberDiff line numberDiff line change
@@ -254,11 +254,19 @@ engine.TypeSpecifier = function(ctx, parentData, node) {
254254
};
255255

256256
engine.ExternalConstantTerm = function(ctx, parentData, node) {
257-
var extConstant = node.children[0];
258-
var identifier = extConstant.children[0];
259-
var varName = engine.Identifier(ctx, parentData, identifier)[0];
257+
let varName;
258+
const extConstant = node.children[0];
259+
// externalConstant(variable name) is defined in the grammar as:
260+
// '%' ( identifier | STRING )
261+
if (extConstant.terminalNodeText.length === 2) {
262+
// if the variable name is a STRING
263+
varName = getStringLiteralVal(extConstant.terminalNodeText[1]);
264+
} else {
265+
// otherwise, it is an identifier
266+
varName = getIdentifierVal(extConstant.children[0].text);
267+
}
260268

261-
var value;
269+
let value;
262270
// Check the user-defined environment variables first as the user can override
263271
// the "context" variable like we do in unit tests. In this case, the user
264272
// environment variable can replace the system environment variable in "processedVars".
@@ -315,28 +323,36 @@ engine.LiteralTerm = function(ctx, parentData, node) {
315323
};
316324

317325
engine.StringLiteral = function(ctx, parentData, node) {
318-
// Remove the beginning and ending quotes.
319-
var rtn = node.text.replace(/(^'|'$)/g, "");
320-
rtn = rtn.replace(/\\(u\d{4}|.)/g, function(match, submatch) {
321-
switch(match) {
322-
case '\\r':
323-
return '\r';
324-
case '\\n':
325-
return "\n";
326-
case '\\t':
327-
return '\t';
328-
case '\\f':
329-
return '\f';
330-
default:
331-
if (submatch.length > 1)
332-
return String.fromCharCode('0x'+submatch.slice(1));
333-
else
334-
return submatch;
335-
}
336-
});
337-
return [rtn];
326+
return [getStringLiteralVal(node.text)];
338327
};
339328

329+
/**
330+
* Removes the beginning and ending single-quotes and replaces string escape
331+
* sequences.
332+
* @param {string} str - string literal
333+
* @return {string}
334+
*/
335+
function getStringLiteralVal(str) {
336+
return str.replace(/(^'|'$)/g, "")
337+
.replace(/\\(u\d{4}|.)/g, function(match, submatch) {
338+
switch(match) {
339+
case '\\r':
340+
return '\r';
341+
case '\\n':
342+
return "\n";
343+
case '\\t':
344+
return '\t';
345+
case '\\f':
346+
return '\f';
347+
default:
348+
if (submatch.length > 1)
349+
return String.fromCharCode('0x'+submatch.slice(1));
350+
else
351+
return submatch;
352+
}
353+
});
354+
}
355+
340356
engine.BooleanLiteral = function(ctx, parentData, node) {
341357
if(node.text === "true") {
342358
return [true];
@@ -372,9 +388,18 @@ engine.NumberLiteral = function(ctx, parentData, node) {
372388
};
373389

374390
engine.Identifier = function(ctx, parentData, node) {
375-
return [node.text.replace(/(^`|`$)/g, "")];
391+
return [getIdentifierVal(node.text)];
376392
};
377393

394+
/**
395+
* Removes the beginning and ending back-quotes.
396+
* @param {string} str - identifier string
397+
* @return {string}
398+
*/
399+
function getIdentifierVal(str) {
400+
return str.replace(/(^`|`$)/g, "");
401+
}
402+
378403
engine.InvocationTerm = function(ctx, parentData, node) {
379404
return engine.doEval(ctx,parentData, node.children[0]);
380405
};

test/cases/8_variables.yaml

+6-1
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,16 @@ tests:
3131
- desc: 'Undefined variable'
3232
expression: '%a'
3333
error: true
34-
- desc: 'Escaped variables'
34+
- desc: 'Back-quoted variable name'
3535
expression: '%`a.b() - 1` - 2'
3636
variables:
3737
"a.b() - 1": 5
3838
result: [3]
39+
- desc: 'Single-quoted variable name'
40+
expression: "%'a.b() - 1' - 3"
41+
variables:
42+
"a.b() - 1": 5
43+
result: [2]
3944

4045
subject:
4146
n1: 1

0 commit comments

Comments
 (0)