Skip to content
Merged
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
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ const jsonnet = new Jsonnet();

// Evaluates a simple Jsonnet program into a JSON value
jsonnet.evaluateSnippet(`{a: 1 + 2, b: self.a * 3}`)
.then(json => console.log(JSON.parse(json))); // => { a: 3, b: 9 }
.then(json => console.log(JSON.parse(json))); // => { a: 3, b: 9 }

// Jsonnet programs can use JavaScript values through external variables (std.extVar)
// and native callbacks (std.native).
jsonnet.extCode("x", "4")
.nativeCallback("add", (a, b) => Number(a) + Number(b), "a", "b")
.evaluateSnippet(`std.extVar("x") * std.native("add")(1, 2)`)
.then(json => console.log(JSON.parse(json))); // => 12
.nativeCallback("add", (a, b) => Number(a) + Number(b), "a", "b")
.evaluateSnippet(`std.extVar("x") * std.native("add")(1, 2)`)
.then(json => console.log(JSON.parse(json))); // => 12
```

The library is documented in the TypeScript type definitions at [`types/index.d.ts`](types/index.d.ts), and [HTML documentation](https://hanazuki.github.io/node-jsonnet/) is also available online.
Expand Down
8 changes: 4 additions & 4 deletions examples/example.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ const jsonnet = new Jsonnet();

// Evaluates a simple Jsonnet program into a JSON value
jsonnet.evaluateSnippet(`{a: 1 + 2, b: self.a * 3}`)
.then(json => console.log(JSON.parse(json))); // => { a: 3, b: 9 }
.then(json => console.log(JSON.parse(json))); // => { a: 3, b: 9 }

// Jsonnet programs can use JavaScript values through external variables (std.extVar)
// and native callbacks (std.native).
jsonnet.extCode("x", "4")
.nativeCallback("add", (a, b) => Number(a) + Number(b), "a", "b")
.evaluateSnippet(`std.extVar("x") * std.native("add")(1, 2)`)
.then(json => console.log(JSON.parse(json))); // => 12
.nativeCallback("add", (a, b) => Number(a) + Number(b), "a", "b")
.evaluateSnippet(`std.extVar("x") * std.native("add")(1, 2)`)
.then(json => console.log(JSON.parse(json))); // => 12
8 changes: 4 additions & 4 deletions examples/example.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ const jsonnet = new Jsonnet();

// Evaluates a simple Jsonnet program into a JSON value
jsonnet.evaluateSnippet(`{a: 1 + 2, b: self.a * 3}`)
.then(json => console.log(JSON.parse(json))); // => { a: 3, b: 9 }
.then(json => console.log(JSON.parse(json))); // => { a: 3, b: 9 }

// Jsonnet programs can use JavaScript values through external variables (std.extVar)
// and native callbacks (std.native).
jsonnet.extCode("x", "4")
.nativeCallback("add", (a, b) => Number(a) + Number(b), "a", "b")
.evaluateSnippet(`std.extVar("x") * std.native("add")(1, 2)`)
.then(json => console.log(JSON.parse(json))); // => 12
.nativeCallback("add", (a, b) => Number(a) + Number(b), "a", "b")
.evaluateSnippet(`std.extVar("x") * std.native("add")(1, 2)`)
.then(json => console.log(JSON.parse(json))); // => 12
8 changes: 4 additions & 4 deletions examples/example.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ const jsonnet = new Jsonnet();

// Evaluates a simple Jsonnet program into a JSON value
jsonnet.evaluateSnippet(`{a: 1 + 2, b: self.a * 3}`)
.then(json => console.log(JSON.parse(json))); // => { a: 3, b: 9 }
.then(json => console.log(JSON.parse(json))); // => { a: 3, b: 9 }

// Jsonnet programs can use JavaScript values through external variables (std.extVar)
// and native callbacks (std.native).
jsonnet.extCode("x", "4")
.nativeCallback("add", (a, b) => Number(a) + Number(b), "a", "b")
.evaluateSnippet(`std.extVar("x") * std.native("add")(1, 2)`)
.then(json => console.log(JSON.parse(json))); // => 12
.nativeCallback("add", (a, b) => Number(a) + Number(b), "a", "b")
.evaluateSnippet(`std.extVar("x") * std.native("add")(1, 2)`)
.then(json => console.log(JSON.parse(json))); // => 12
18 changes: 9 additions & 9 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,22 @@ const proto = Jsonnet.prototype;
// Wrapping in async function can prevent it.
const _nativeCallback = proto._nativeCallback;
Object.defineProperty(proto, 'nativeCallback', {
value: function(name, func, ...params) {
const asyncFunc = isAsyncFunction(func)
? func
: async function(...args) { return func.call(this, ...args); }
value: function (name, func, ...params) {
const asyncFunc = isAsyncFunction(func)
? func
: async function (...args) { return func.call(this, ...args); }

return _nativeCallback.call(this, name, asyncFunc, ...params);
return _nativeCallback.call(this, name, asyncFunc, ...params);
},
});

// Accept an object as the sole argument when defining ext/tla.
for(const func of ['extString', 'extCode', 'tlaString', 'tlaCode']) {
for (const func of ['extString', 'extCode', 'tlaString', 'tlaCode']) {
const origFunc = proto[`_${func}`];
Object.defineProperty(proto, func, {
value: function(...params) {
if(params.length == 1) {
for(const [key, value] of Object.entries(params[0])) {
value: function (...params) {
if (params.length == 1) {
for (const [key, value] of Object.entries(params[0])) {
origFunc.call(this, key, value);
}
return this;
Expand Down
44 changes: 22 additions & 22 deletions spec/binding_spec.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
const {Jsonnet, JsonnetError} = require("../");
const { Jsonnet, JsonnetError } = require("../");

describe('binding', () => {
beforeEach(function() {
beforeEach(function () {
jasmine.addMatchers({
toBeJSON: (util) => ({
compare: (actual, expected) => {
const result = {
pass: util.equals(JSON.parse(actual), expected),
}
if(!result.pass) {
if (!result.pass) {
result.message = `Expect '${actual}' to be JSON representing ${JSON.stringify(expected)}.`
}
return result;
Expand All @@ -17,15 +17,15 @@ describe('binding', () => {
});
});

it('has version', async() => {
it('has version', async () => {
expect(Jsonnet.version).toEqual(jasmine.stringMatching(/^v/));
});

it('can evaluate complex JSON', async () => {
const jsonnet = new Jsonnet();

let j = await jsonnet.evaluateSnippet(`[1,"a",true,null,{a:{b:3}}]`);
expect(j).toBeJSON([1,"a",true,null,{a:{b:3}}]);
expect(j).toBeJSON([1, "a", true, null, { a: { b: 3 } }]);
});

it('returns JSON with trailing newline without trailingNewline()', async () => {
Expand Down Expand Up @@ -55,7 +55,7 @@ describe('binding', () => {
expect(j).toBeJSON("str");

j = await jsonnet.evaluateSnippet(`std.extVar("var2")`);
expect(j).toBeJSON({a: [0]});
expect(j).toBeJSON({ a: [0] });
});

it('uses the extVar added most recently for the same name', async () => {
Expand All @@ -69,16 +69,16 @@ describe('binding', () => {

it('supports multiple extVar assignment', async () => {
const jsonnet = new Jsonnet()
.extString({var1: "A", var2: "B"})
.extCode({var3: "{c: [0]}", var4: '"D"'});
.extString({ var1: "A", var2: "B" })
.extCode({ var3: "{c: [0]}", var4: '"D"' });

let j = await jsonnet.evaluateSnippet(
`{a: std.extVar("var1"), b: std.extVar("var2"), c: std.extVar("var3"), d: std.extVar("var4")}`
);
expect(j).toBeJSON({
a: "A",
b: "B",
c: {c: [0]},
c: { c: [0] },
d: "D",
});
});
Expand All @@ -87,7 +87,7 @@ describe('binding', () => {
const jsonnet = new Jsonnet().addJpath(`${__dirname}/fixtures`);

const j = await jsonnet.evaluateFile(`${__dirname}/fixtures/fruits.jsonnet`);
expect(j).toBeJSON([{name: "Kiwi"}, {name: "Orange"}]);
expect(j).toBeJSON([{ name: "Kiwi" }, { name: "Orange" }]);
});

it('Jpath added later takes precedence', async () => {
Expand All @@ -103,13 +103,13 @@ describe('binding', () => {
const jsonnet = new Jsonnet().addJpath(`${__dirname}/fixtures`);

let j = await jsonnet.evaluateFile(`${__dirname}/fixtures/utf8.jsonnet`);
expect(j).toBeJSON({"あ": "あいうえお", "🍔": "🐧"});
expect(j).toBeJSON({ "あ": "あいうえお", "🍔": "🐧"}) ;

j = await jsonnet.evaluateSnippet(`import "utf8.jsonnet"`);
expect(j).toBeJSON({"あ": "あいうえお", "🍔": "🐧"});
expect(j).toBeJSON({ "あ": "あいうえお", "🍔": "🐧"}) ;

j = await jsonnet.evaluateSnippet(`{"あ": "あいうえお", "🍔": "🐧"}`);
expect(j).toBeJSON({"あ": "あいうえお", "🍔": "🐧"});
expect(j).toBeJSON({ "あ": "あいうえお", "🍔": "🐧"}) ;
});

it('handles paths in UTF-8', async () => {
Expand Down Expand Up @@ -141,16 +141,16 @@ describe('binding', () => {

it('supports multiple top-level arguments assignment', async () => {
const jsonnet = new Jsonnet()
.tlaString({var1: "A", var2: "B"})
.tlaCode({var3: "{c: [0]}", var4: '"D"'});
.tlaString({ var1: "A", var2: "B" })
.tlaCode({ var3: "{c: [0]}", var4: '"D"' });

let j = await jsonnet.evaluateSnippet(
`function(var1, var2, var3, var4) {a: var1, b: var2, c: var3, d: var4}`
);
expect(j).toBeJSON({
a: "A",
b: "B",
c: {c: [0]},
c: { c: [0] },
d: "D",
});
});
Expand All @@ -162,7 +162,7 @@ describe('binding', () => {
jsonnet.nativeCallback("concat", (s, t) => s + t, "s", "t");
jsonnet.nativeCallback("isNull", (v) => v === null, "v");
jsonnet.nativeCallback("null", () => null);
jsonnet.nativeCallback("arrayOfObjects", () => [{name: "Kiwi"}, {name: "Orange"}]);
jsonnet.nativeCallback("arrayOfObjects", () => [{ name: "Kiwi" }, { name: "Orange" }]);

let j = await jsonnet.evaluateSnippet(`std.native("double")(4)`);
expect(j).toBeJSON(8);
Expand All @@ -183,21 +183,21 @@ describe('binding', () => {
expect(j).toBeJSON(null);

j = await jsonnet.evaluateSnippet(`std.native("arrayOfObjects")()`);
expect(j).toBeJSON([{name: "Kiwi"}, {name: "Orange"}]);
expect(j).toBeJSON([{ name: "Kiwi" }, { name: "Orange" }]);
});

it('serializes JavaScript objects', async () => {
const jsonnet = new Jsonnet();

jsonnet.nativeCallback("int8array", () => new Int8Array([1,2,3]));
jsonnet.nativeCallback("int8array", () => new Int8Array([1, 2, 3]));
let j = await jsonnet.evaluateSnippet(`std.native("int8array")()`);
expect(j).toBeJSON({0: 1, 1: 2, 2: 3});
expect(j).toBeJSON({ 0: 1, 1: 2, 2: 3 });

jsonnet.nativeCallback("function", () => function(){ return 1; });
jsonnet.nativeCallback("function", () => function () { return 1; });
j = await jsonnet.evaluateSnippet(`std.native("function")()`);
expect(j).toBeJSON(null);

jsonnet.nativeCallback("asyncFunction", () => async function(){ return 1; });
jsonnet.nativeCallback("asyncFunction", () => async function () { return 1; });
j = await jsonnet.evaluateSnippet(`std.native("asyncFunction")()`);
expect(j).toBeJSON(null);

Expand Down
5 changes: 2 additions & 3 deletions spec/example_spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
const fs = require('fs');
const path = require('path');
const cp = require('child_process');
const { promisify } = require('util');
Expand All @@ -12,7 +11,7 @@ const tsExamples = path.join(__dirname, "../examples/*.ts");
const timeout = 10000;

describe('JavaScript examples', () => {
for(const file of glob(jsExamples)) {
for (const file of glob(jsExamples)) {
it(`${file}`, async () => {
await execFile('node', [file], {
cwd: path.join(__dirname, '..'),
Expand All @@ -23,7 +22,7 @@ describe('JavaScript examples', () => {
});

describe('TypeScript examples', () => {
for(const file of glob(tsExamples)) {
for (const file of glob(tsExamples)) {
it(`${file}`, async () => {
await execFile('ts-node', [file], {
cwd: path.join(__dirname, '../examples'),
Expand Down
19 changes: 9 additions & 10 deletions spec/jsonnet_spec.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
const fs = require('fs');
const path = require('path');
const quoteRegExp = str => str.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&');

const {Jsonnet} = require("../");
const { Jsonnet } = require("../");

const suiteDir = path.join(__dirname, '../third_party/jsonnet/test_suite');

Expand All @@ -16,41 +15,41 @@ describe('libjsonnet', () => {
const stackTraceLike = expected => ({
asymmetricMatch: actual => {
const stripped = actual
.replace(/\tstd\.jsonnet:[0-9]*:[0-9-]*/g, "\tstd.jsonnet:<stdlib_position_redacted>");
.replace(/\tstd\.jsonnet:[0-9]*:[0-9-]*/g, "\tstd.jsonnet:<stdlib_position_redacted>");

return stripped === expected
},
jasmineToString: () => expected
});

for (const dirent of fs.readdirSync(suiteDir, {withFileTypes: true})) {
for (const dirent of fs.readdirSync(suiteDir, { withFileTypes: true })) {
const fname = path.basename(dirent.name);
if(!dirent.isFile() || !/\.jsonnet$/.test(fname)) continue;
if (!dirent.isFile() || !/\.jsonnet$/.test(fname)) continue;

it(`process ${fname}`, async () => {

if(/^trace\./.test(fname)) {
if (/^trace\./.test(fname)) {
pending('TODO: Test tracing');
}

const expectsError = /^error\./.test(fname);

const jsonnet = new Jsonnet();
if(/^tla\./.test(dirent.name)) {
if (/^tla\./.test(dirent.name)) {
jsonnet.tlaString('var1', 'test').tlaCode('var2', `{x: 1, y: 2}`);
} else {
jsonnet.extString('var1', 'test').extCode('var2', `{x: 1, y: 2}`);
}

const golden = await fs.promises.readFile(`${fname}.golden`, {encoding: 'utf8'}).catch(() => "true\n");
const golden = await fs.promises.readFile(`${fname}.golden`, { encoding: 'utf8' }).catch(() => "true\n");

const result = jsonnet.evaluateFile(fname)

if(expectsError) {
if (expectsError) {
try {
await result;
fail('Expected to rejected.');
} catch(error) {
} catch (error) {
expect(error.message).toEqual(stackTraceLike(golden));
}
} else {
Expand Down
Loading