From 7ea99bb7a0bb16426333ed30540d7853870874ef Mon Sep 17 00:00:00 2001 From: Eric Koleda Date: Mon, 23 Sep 2024 17:55:09 -0400 Subject: [PATCH] Initial version --- json5/.coda-pack.json | 3 + json5/pack.ts | 135 +++++++++++++++++++++++++++++++++++++++ json5/tests/pack_test.ts | 26 ++++++++ package-lock.json | 17 +++++ package.json | 1 + 5 files changed, 182 insertions(+) create mode 100644 json5/.coda-pack.json create mode 100644 json5/pack.ts create mode 100644 json5/tests/pack_test.ts diff --git a/json5/.coda-pack.json b/json5/.coda-pack.json new file mode 100644 index 0000000..19abfed --- /dev/null +++ b/json5/.coda-pack.json @@ -0,0 +1,3 @@ +{ + "packId": 34513 +} \ No newline at end of file diff --git a/json5/pack.ts b/json5/pack.ts new file mode 100644 index 0000000..0a79bd3 --- /dev/null +++ b/json5/pack.ts @@ -0,0 +1,135 @@ +import * as coda from "@codahq/packs-sdk"; +import JSON5 from "json5"; + +const OneDaySecs = 24 * 60 * 60; + +export const pack = coda.newPack(); + +const JSON5Param = coda.makeParameter({ + type: coda.ParameterType.String, + name: "json5", + description: "The JSON5 contents as a string.", +}); + +const SpacesParam = coda.makeParameter({ + type: coda.ParameterType.Number, + name: "spaces", + description: "The number of spaces to indent by. Default: no indenting.", + optional: true, +}); + +pack.addFormula({ + name: "FormatJSON5", + description: "Formats JSON5 content using the options provided.", + parameters: [ + JSON5Param, + SpacesParam, + coda.makeParameter({ + type: coda.ParameterType.String, + name: "quote", + description: "Which quote to use around strings. Default: single quote (').", + optional: true, + autocomplete: [ + { display: `Single quote (')`, value: `'` }, + { display: `Double quote (")`, value: `"` }, + ], + }), + ], + resultType: coda.ValueType.String, + cacheTtlSecs: OneDaySecs, + examples: [ + { params: [`{a: 1, b: "foo"}`], result: `{a:1,b:'foo'}` }, + { + params: [`{a: 1, b: "foo"}`, 2], + result: trimIndent(` + { + a: 1, + b: 'foo', + } + `), + }, + { params: [`{a: 1, b: "foo"}`, 0, '"'], result: `{a:1,b:"foo"}` }, + ], + execute: async function (args, context) { + let [json5, space, quote] = args; + let value = parse(json5); + return JSON5.stringify(value, {space, quote}); + }, +}); + +pack.addFormula({ + name: "IsValidJSON5", + description: "Returns true if the content is valid JSON5, false otherwise.", + parameters: [ + JSON5Param, + ], + resultType: coda.ValueType.Boolean, + cacheTtlSecs: OneDaySecs, + examples: [ + { params: [`{a: 1}`], result: true }, + { params: [`{a: 1`, ], result: false }, + ], + execute: async function (args, context) { + let [json5] = args; + try { + JSON5.parse(json5); + } catch (e) { + if (e.toString().startsWith("SyntaxError")) { + return false; + } + throw e; + } + return true; + }, +}); + +pack.addFormula({ + name: "ToJSON", + description: "Converts a JSON5 string to JSON.", + parameters: [ + JSON5Param, + SpacesParam, + ], + resultType: coda.ValueType.String, + cacheTtlSecs: OneDaySecs, + examples: [ + { params: [`{a: 1, b:'foo'}`], result: `{"a":1,"b":"foo"}` }, + { + params: [`{a:1,b:'foo'}`, 2], + result: trimIndent(` + { + "a": 1, + "b": "foo" + } + `) + }, + ], + execute: async function (args, context) { + let [json5, spaces] = args; + let value = parse(json5); + return JSON.stringify(value, null, spaces); + }, +}); + +function parse(json5: string) { + try { + return JSON5.parse(json5); + } catch (e) { + if (e.toString().startsWith("SyntaxError")) { + throw new coda.UserVisibleError(e); + } + throw e; + } +} + +function trimIndent(str: string) { + let lines = str.split("\n"); + if (lines[0] == "") { + lines = lines.slice(1); + } + if (lines.at(-1) == "") { + lines = lines.slice(0, -1); + } + let indent = lines[0].match(/^\s*/)[0].length; + return lines.map(line => line.substring(indent)).join("\n").trim(); +} \ No newline at end of file diff --git a/json5/tests/pack_test.ts b/json5/tests/pack_test.ts new file mode 100644 index 0000000..171856b --- /dev/null +++ b/json5/tests/pack_test.ts @@ -0,0 +1,26 @@ +import {executeFormulaFromPackDef} from '@codahq/packs-sdk/dist/development'; +import {pack} from '../pack'; +import * as chai from "chai"; +import {assert} from "chai"; +import {describe} from "mocha"; +import {it} from "mocha"; +import chaiAsPromised from "chai-as-promised"; +chai.use(chaiAsPromised); +chai.should(); + +describe("Examples", () => { + for (let formula of pack.formulas) { + describe(formula.name, () => { + for (let [i, example] of formula.examples.entries()) { + it(`Example ${i}`, async () => { + const result = await executeFormulaFromPackDef(pack, formula.name, example.params as any); + if (typeof example.result == "object") { + assert.deepEqual(result, example.result); + } else { + assert.equal(result, example.result); + } + }); + } + }); + } +}); diff --git a/package-lock.json b/package-lock.json index 4192057..df9585a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,6 +31,7 @@ "hsl-to-hex": "^1.0.0", "hue-colors": "^0.5.4", "ical-generator": "^6.0.1", + "json5": "^2.2.3", "jsrsasign": "^10.8.6", "jszip": "^3.10.1", "lodash": "^4.17.21", @@ -14342,6 +14343,17 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -28463,6 +28475,11 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" + }, "jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", diff --git a/package.json b/package.json index 96597a9..ae6f646 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "hsl-to-hex": "^1.0.0", "hue-colors": "^0.5.4", "ical-generator": "^6.0.1", + "json5": "^2.2.3", "jsrsasign": "^10.8.6", "jszip": "^3.10.1", "lodash": "^4.17.21",