Socket
Socket
Sign inDemoInstall

json-e

Package Overview
Dependencies
0
Maintainers
11
Versions
37
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 2.3.1 to 2.3.2

2

package.json
{
"name": "json-e",
"version": "2.3.1",
"version": "2.3.2",
"description": "json parameterization module inspired from json-parameterization",

@@ -5,0 +5,0 @@ "main": "./src/index.js",

@@ -1,6 +0,8 @@

# [JSON-e](https://taskcluster.github.io/json-e)
* [Full documentation](https://taskcluster.github.io/json-e)
JSON-e is a data-structure parameterization system written for embedding
context in JSON objects.
# JSON-e
JSON-e is a data-structure parameterization system for embedding context in
JSON objects.
The central idea is to treat a data structure as a "template" and transform it,

@@ -23,2 +25,4 @@ using another data structure as context, to produce an output data structure.

## JavaScript
The JS module exposes following interface:

@@ -50,2 +54,4 @@

## Python
The Python distribution exposes a `render` function:

@@ -56,5 +62,5 @@

var template = {"a": {"$eval": "foo.bar"}}
var context = {"foo": {"bar": "zoo"}}
print(jsone(template, contxt)) # -> {"a": "zoo"}
template = {"a": {"$eval": "foo.bar"}}
context = {"foo": {"bar": "zoo"}}
print(jsone.render(template, context)) # -> {"a": "zoo"}
```

@@ -65,5 +71,5 @@

```python
var template = {"$eval": "foo(1)"}
var context = {"foo": lambda x: x + 2}
print(jsone(template, contxt)) # -> 3
template = {"$eval": "foo(1)"}
context = {"foo": lambda x: x + 2}
print(jsone.render(template, context)) # -> 3
```

@@ -83,4 +89,4 @@

```yaml
template: {key: [1,2,{key2: 'val', key3: 1}, true], f: false}
context: {}
template: {key: [1,2,{key2: 'val', key3: 1}, true], f: false}
result: {key: [1,2,{key2: 'val', key3: 1}, true], f: false}

@@ -94,4 +100,4 @@ ```

```yaml
template: {message: 'hello ${key}', 'k=${num}': true}
context: {key: 'world', num: 1}
template: {message: 'hello ${key}', 'k=${num}': true}
result: {message: 'hello world', 'k=1': true}

@@ -101,4 +107,5 @@ ```

The bit inside the `${..}` is an expression, and must evaluate to something
that interpolates obviously into a string (so, a string, number, boolean, or
null). The expression syntax is described in more detail below.
that interpolates obviously into a string (so, a string, number, boolean,).
If it is null, then the expression interpolates into an empty string.
The expression syntax is described in more detail below.

@@ -108,5 +115,5 @@ Values interpolate as their JSON literal values:

```yaml
template: ["number: ${num}", "booleans: ${t} ${f}", "null: ${nil}"]
context: {num: 3, t: true, f: false, nil: null}
template: ["number: ${num}", "booleans: ${t} ${f}", "null: ${nil}"]
result: ["number: 3", "booleans: true false", "null: null"]
result: ["number: 3", "booleans: true false", "null: "]
```

@@ -117,4 +124,4 @@

```yaml
template: {"tc_${name}": "${value}"}
context: {name: 'foo', value: 'bar'}
template: {"tc_${name}": "${value}"}
result: {"tc_foo": "bar"}

@@ -139,2 +146,3 @@ ```

```yaml
template: {config: {$eval: 'settings.staging'}}
context:

@@ -146,3 +154,2 @@ settings:

transactionBackend: customerdb
template: {config: {$eval: 'settings.staging'}}
result: {config: {transactionBackend: 'mock'}}

@@ -160,4 +167,4 @@ ```

```yaml
template: {$json: [a, b, {$eval: 'a+b'}, 4]}
context: {a: 1, b: 2}
template: {$json: [a, b, {$eval: 'a+b'}, 4]}
result: '["a", "b", 3, 4]'

@@ -173,4 +180,4 @@ ```

```yaml
template: {key: {$if: 'cond', then: 1}, k2: 3}
context: {cond: true}
template: {key: {$if: 'cond', then: 1}, k2: 3}
result: {key: 1, k2: 3}

@@ -180,4 +187,4 @@ ```

```yaml
template: {$if: 'x > 5', then: 1, else: -1}
context: {x: 10}
template: {$if: 'x > 5', then: 1, else: -1}
result: 1

@@ -187,4 +194,4 @@ ```

```yaml
template: [1, {$if: 'cond', else: 2}, 3]
context: {cond: false}
template: [1, {$if: 'cond', else: 2}, 3]
result: [1,2,3]

@@ -194,4 +201,4 @@ ```

```yaml
template: {key: {$if: 'cond', then: 2}, other: 3}
context: {cond: false}
template: {key: {$if: 'cond', then: 2}, other: 3}
result: {other: 3}

@@ -205,4 +212,4 @@ ```

```yaml
template: {$flatten: [[1, 2], [3, 4], [5]]}
context: {}
template: {$flatten: [[1, 2], [3, 4], [5]]}
result: [1, 2, 3, 4, 5]

@@ -216,4 +223,4 @@ ```

```yaml
template: {$flattenDeep: [[1, [2, [3]]]]}
context: {}
template: {$flattenDeep: [[1, [2, [3]]]]}
result: [1, 2, 3]

@@ -225,9 +232,10 @@ ```

The `$fromNow` operator is a shorthand for the built-in function `fromNow`. It
creates a JSON (ISO 8601) datestamp for a time relative to the current time or,
if `from` is given, from that time. The offset is specified by a sequence of
number/unit pairs in a string. For example:
creates a JSON (ISO 8601) datestamp for a time relative to the current time
(see the `now` builtin, below) or, if `from` is given, relative to that time.
The offset is specified by a sequence of number/unit pairs in a string. For
example:
```yaml
template: {$fromNow: '2 days 1 hour'}
context: {}
template: {$fromNow: '2 days 1 hour'}
result: '2017-01-19T16:27:20.974Z'

@@ -237,4 +245,4 @@ ```

```yaml
template: {$fromNow: '1 hour', from: '2017-01-19T16:27:20.974Z'}
context: {}
template: {$fromNow: '1 hour', from: '2017-01-19T16:27:20.974Z'}
result: '2017-01-19T17:27:20.974Z'

@@ -252,5 +260,5 @@ ```

```yaml
context: {}
template: {$let: {ts: 100, foo: 200},
in: [{$eval: "ts+foo"}, {$eval: "ts-foo"}, {$eval: "ts*foo"}]}
context: {}
result: [300, -100, 20000]

@@ -273,6 +281,6 @@ ```

```yaml
context: {a: 1}
template:
$map: [2, 4, 6]
each(x): {$eval: 'x + a'}
context: {a: 1}
result: [3, 5, 7]

@@ -282,6 +290,6 @@ ```

```yaml
context: {}
template:
$map: {a: 1, b: 2, c: 3}
each(y): {'${y.key}x': {$eval: 'y.val + 1'}}
context: {}
result: {ax: 2, bx: 3, cx: 4}

@@ -302,4 +310,4 @@ ```

```yaml
template: {$merge: [{a: 1, b: 1}, {b: 2, c: 3}, {d: 4}]}
context: {}
template: {$merge: [{a: 1, b: 1}, {b: 2, c: 3}, {d: 4}]}
result: {a: 1, b: 2, c: 3, d: 4}

@@ -314,3 +322,2 @@ ```

```yaml
context: {}
template:

@@ -327,2 +334,3 @@ $mergeDeep:

command: [c]
context: {}
result:

@@ -343,6 +351,6 @@ task:

```yaml
context: {}
template:
$sort: [{a: 2}, {a: 1, b: []}, {a: 3}]
by(x): 'x.a'
context: {}
result: [{a: 1, b: []}, {a: 2}, {a: 3}]

@@ -356,4 +364,4 @@ ```

```yaml
template: {$reverse: [3, 4, 1, 2]}
context: {}
template: {$reverse: [3, 4, 1, 2]}
result: [2, 1, 4, 3]

@@ -368,4 +376,4 @@ ```

```yaml
template: {$$reverse: [3, 2, {$$eval: '2 - 1'}, 0]}
context: {}
template: {$$reverse: [3, 2, {$$eval: '2 - 1'}, 0]}
result: {$reverse: [3, 2, {$eval: '2 - 1'}, 0]}

@@ -381,4 +389,4 @@ ```

```yaml
template: {$if: 'a || b || c || d || e || f', then: "uh oh", else: "falsy" }
context: {a: null, b: [], c: {}, d: "", e: 0, f: false}
template: {$if: 'a || b || c || d || e || f', then: "uh oh", else: "falsy" }
result: "falsy"

@@ -400,3 +408,2 @@ ```

```yaml
context: {}
template:

@@ -407,2 +414,3 @@ - {$eval: "1.3"}

- {$eval: "'\n\t'"}
context: {}
result:

@@ -419,6 +427,6 @@ - 1.3

```yaml
context: {}
template:
- {$eval: '[1, 2, "three"]'}
- {$eval: '{foo: 1, "bar": 2}'}
context: {}
result:

@@ -434,4 +442,4 @@ - [1, 2, "three"]

```yaml
template: {$eval: '[x, z, x+z]'}
context: {x: 'quick', z: 'sort'}
template: {$eval: '[x, z, x+z]'}
reslut: ['quick', 'sort', 'quicksort']

@@ -446,3 +454,2 @@ ```

```yaml
context: {x: 10, z: 20, s: "face", t: "plant"}
template:

@@ -456,2 +463,3 @@ - {$eval: 'x + z'}

- {$eval: '(z / x) ** 2'}
context: {x: 10, z: 20, s: "face", t: "plant"}
result:

@@ -476,3 +484,2 @@ - 30

```yaml
context: {x: -10, z: 10, deep: [1, [3, {a: 5}]]}
template:

@@ -485,2 +492,3 @@ - {$eval: 'x < z'}

- {$eval: 'deep != [1, [3, {a: 5}]]'}
context: {x: -10, z: 10, deep: [1, [3, {a: 5}]]}
result: [true, true, false, false, true, false]

@@ -494,4 +502,4 @@ ```

```yaml
template: {$eval: '!(false || false) && true'}
context: {}
template: {$eval: '!(false || false) && true'}
result: true

@@ -507,4 +515,4 @@ ```

```yaml
template: {$eval: 'v.a + v["b"]'}
context: {v: {a: 'apple', b: 'bananna', c: 'carrot'}}
template: {$eval: 'v.a + v["b"]'}
result: 'applebananna'

@@ -522,3 +530,2 @@ ````

```yaml
context: {array: ['a', 'b', 'c', 'd', 'e'], string: 'abcde'}
template:

@@ -533,2 +540,3 @@ - {$eval: '[array[1], string[1]]'}

- {$eval: '[array[:-3], string[:-3]]'}
context: {array: ['a', 'b', 'c', 'd', 'e'], string: 'abcde'}
result:

@@ -551,3 +559,2 @@ - ['b', 'b']

```yaml
context: {}
template:

@@ -557,2 +564,3 @@ - {$eval: '"foo" in {foo: 1, bar: 2}'}

- {$eval: '"foo" in "foobar"'}
context: {}
result: [true, true, true]

@@ -565,5 +573,5 @@ ```

not JSON data, so they cannot be created in JSON-e, but they can be provided as
built-ins or in the context and called from JSON-e.
built-ins or supplied in the context and called from JSON-e.
#### Built-In Functions and Variables
### Built-In Functions and Variables

@@ -574,46 +582,96 @@ The expression language provides a laundry-list of built-in functions/variables. Library

* `fromNow(offset)` or `fromNow(offset, reference)` -- JSON datestamp for a time relative to the current time or, if given, the reference time
* `now` -- the datestamp at the start of evaluation of the template. This is used implicitly as `from` in all fromNow calls. Override to set a different time.
* `min(a, b, ..)` -- the smallest of the arguments
* `max(a, b, ..)` -- the largest of the arguments
* `sqrt(x)`, `ceil(x)`, `floor(x)`, `abs(x)` -- mathematical functions
* `lowercase(s)`, `uppercase(s)` -- convert string case
* `str(x)` -- convert string, number, boolean, or array to string
* `lstrip(s)`, `rstrip(s)`, `strip(s)` -- strip whitespace from left, right, or both ends of a string
* `len(x)` -- length of a string or array
#### Time
The built-in context value `now` is set to the current time at the start of
evaluation of the template, and used as the default "from" value for `$fromNow`
and the built-in `fromNow()`.
# Development and testing
```yaml
template:
- {$eval: 'now'}
- {$eval: 'fromNow("1 minute")'}
- {$eval: 'fromNow("1 minute", "2017-01-19T16:27:20.974Z")'}
context: {}
result:
- '2017-01-19T16:27:20.974Z',
- '2017-01-19T16:28:20.974Z',
- '2017-01-19T16:28:20.974Z',
```
You should run `npm install` to install the required packages for json-e's
execution and development.
#### Math
You can run `./test.sh` to run json-e's unit tests and the `bundle.js` check.
This is a breakdown of the commands inside the `test.sh` file.
```yaml
template:
# the smallest of the arguments
- {$eval: 'min(1, 3, 5)'}
# the largest of the arguments
- {$eval: 'max(2, 4, 6)'}
# mathematical functions
- {$eval: 'sqrt(16)'}
- {$eval: 'ceil(0.3)'}
- {$eval: 'floor(0.3)'}
- {$eval: 'abs(-0.3)'}
context: {}
result:
- 1
- 6
- 4
- 1
- 0
- 0.3
```
```bash
# Run JavaScript unit tests
npm test
#### Strings
# Run Python unit tests
python setup.py test
# bundle.js check. This section makes sure that
# the demo website's bundle.js file is updated.
mv docs/bundle.js docs/bundle.diff.js
npm run-script build-demo
diff docs/bundle.js docs/bundle.diff.js
```yaml
template:
# convert string case
- {$eval: 'lowercase("Fools!")'}
- {$eval: 'uppercase("Fools!")'}
# convert string, number, boolean, or array to string
- {$eval: 'str(130)'}
# strip whitespace from left, right, or both ends of a string
- {$eval: 'lstrip(" room ")'}
- {$eval: 'rstrip(" room ")'}
- {$eval: 'strip(" room ")'}
context: {}
result:
- "fools!"
- "FOOLS!"
- "130"
- "room "
- " room"
- room
```
You can also run the following command to
update the demo website bundle.js file.
#### Length
```bash
npm run-script build-demo
The `len()` built-in returns the length of a string or array.
```yaml
template: {$eval: 'len([1, 2, 3])'}
context: {}
result: 3
```
## Development Notes
# Development and testing
### Making a Release
## JSON-e development
You should run `npm install` to install the required packages for json-e's
execution and development. For Python, activate a virtualenv and run `pip
install -e .`.
You can run `./test.sh` to run json-e's tests and lint checks.
## Demo development
The demo website is a [Neutrino](https://neutrino.js.org/) app hosted in
`demo/`. Follow the usual Neutrino development process (`yarn install && yarn
start`) there.
The resulting application embeds and enriches this README.
## Making a Release
* Update the version, commit, and tag -- `npm version patch` (or minor or major, depending)

@@ -620,0 +678,0 @@ * Push to release the JS version -- `git push && git push --tags`

@@ -20,3 +20,3 @@ var {BuiltinError} = require('./error');

let builtinError = (builtin, expectation) => new BuiltinError(`${builtin} expects ${expectation}`);
let builtinError = (builtin) => new BuiltinError(`invalid arguments to ${builtin}`);

@@ -87,3 +87,3 @@ module.exports = (context) => {

define('str', builtins, {
argumentTests: ['string|number|boolean|array|null'],
argumentTests: ['string|number|boolean|null'],
invoke: obj => {

@@ -90,0 +90,0 @@ if (obj === null) {

@@ -12,2 +12,15 @@ var interpreter = require('./interpreter');

function checkUndefinedProperties(template, allowed) {
var unknownKeys = '';
var combined = new RegExp(allowed.join('|') + '$');
for (var key of Object.keys(template).sort()) {
if (!combined.test(key)) {
unknownKeys += ' ' + key;
}
}
if (unknownKeys) {
throw new TemplateError(allowed[0].replace('\\', '') + ' has undefined properties:' + unknownKeys);
}
};
let flattenDeep = (a) => {

@@ -31,5 +44,5 @@ return Array.isArray(a) ? [].concat(...a.map(flattenDeep)) : a;

// toString renders null as an empty string, which is not what we want
// if it is null, result should just be appended with empty string
if (v.result === null) {
result += 'null';
result += '';
} else {

@@ -60,2 +73,4 @@ result += v.result.toString();

operators.$flatten = (template, context) => {
checkUndefinedProperties(template, ['\\$flatten']);
let value = render(template['$flatten'], context);

@@ -71,2 +86,4 @@

operators.$flattenDeep = (template, context) => {
checkUndefinedProperties(template, ['\\$flattenDeep']);
let value = render(template['$flattenDeep'], context);

@@ -82,2 +99,4 @@

operators.$fromNow = (template, context) => {
checkUndefinedProperties(template, ['\\$fromNow', 'from']);
let value = render(template['$fromNow'], context);

@@ -95,2 +114,4 @@ let reference = context.now;

operators.$if = (template, context) => {
checkUndefinedProperties(template, ['\\$if', 'then', 'else']);
if (!isString(template['$if'])) {

@@ -106,2 +127,4 @@ throw new TemplateError('$if can evaluate string expressions only');

operators.$json = (template, context) => {
checkUndefinedProperties(template, ['\\$json']);
return JSON.stringify(render(template['$json'], context));

@@ -111,2 +134,4 @@ };

operators.$let = (template, context) => {
checkUndefinedProperties(template, ['\\$let', 'in']);
let variables = render(template['$let'], context);

@@ -118,2 +143,7 @@

throw new TemplateError('$let value must evaluate to an object');
} else {
let match = Object.keys(variables).every((variableName) => /^[a-zA-Z_][a-zA-Z0-9_]*$/.exec(variableName));
if (!match) {
throw new TemplateError('top level keys of $let must follow /[a-zA-Z_][a-zA-Z0-9_]*/');
}
}

@@ -129,2 +159,4 @@

operators.$map = (template, context) => {
EACH_RE = 'each\\(([a-zA-Z_][a-zA-Z0-9_]*)\\)';
checkUndefinedProperties(template, ['\\$map', EACH_RE]);
let value = render(template['$map'], context);

@@ -165,2 +197,4 @@ if (!isArray(value) && !isObject(value)) {

operators.$merge = (template, context) => {
checkUndefinedProperties(template, ['\\$merge']);
let value = render(template['$merge'], context);

@@ -176,2 +210,4 @@

operators.$mergeDeep = (template, context) => {
checkUndefinedProperties(template, ['\\$mergeDeep']);
let value = render(template['$mergeDeep'], context);

@@ -189,3 +225,2 @@

let merge = (l, r) => {
console.log(`merge(${JSON.stringify(l)}, ${JSON.stringify(r)})`);
if (isArray(l) && isArray(r)) {

@@ -199,3 +234,2 @@ return l.concat(r);

res[p] = merge(l[p], r[p]);
console.log(`-> ${JSON.stringify(res[p])}`);
} else {

@@ -209,19 +243,14 @@ res[p] = r[p];

};
console.log(`merging ${JSON.stringify(value)}`);
// start with the first element of the list
return value.reduce(merge, value.shift());
return Object.assign({}, ...value);
};
operators.$reverse = (template, context) => {
checkUndefinedProperties(template, ['\\$reverse']);
let value = render(template['$reverse'], context);
if (!isArray(value) && !isArray(template['$reverse'])) {
if (!isArray(value)) {
throw new TemplateError('$reverse value must evaluate to an array of objects');
}
if (!isArray(value)) {
throw new TemplateError('$reverse requires array as value');
}
return value.reverse();

@@ -231,2 +260,4 @@ };

operators.$sort = (template, context) => {
BY_RE = 'by\\(([a-zA-Z_][a-zA-Z0-9_]*)\\)';
checkUndefinedProperties(template, ['\\$sort', BY_RE]);
let value = render(template['$sort'], context);

@@ -325,7 +356,11 @@ if (!isArray(value)) {

if (value !== deleteMarker) {
if (key.startsWith('$$') && operators.hasOwnProperty(key.substr(1))) {
if (key.startsWith('$$')) {
key = key.substr(1);
} else if (/^\$[a-zA-Z][a-zA-Z0-9]*$/.test(key)) {
throw new TemplateError('$<identifier> is reserved; ues $$<identifier>');
} else {
key = interpolate(key, context);
}
result[interpolate(key, context)] = value;
result[key] = value;
}

@@ -341,3 +376,3 @@ }

}
context = addBuiltins(Object.assign({}, {now: new Date()}, context));
context = addBuiltins(Object.assign({}, {now: fromNow('0 seconds')}, context));
let result = render(template, context);

@@ -344,0 +379,0 @@ if (result === deleteMarker) {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc