diff --git a/package-lock.json b/package-lock.json index 3687a7ea..f8234b61 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1214,8 +1214,9 @@ "dev": true }, "@exabyte-io/esse.js": { - "version": "git+https://github.com/Exabyte-io/esse.git#6f9515988dd2ae589bc74a6096cc743b5dba3225", - "from": "git+https://github.com/Exabyte-io/esse.git#update/SOF-6535", + "version": "2023.7.28-0", + "resolved": "https://registry.npmjs.org/@exabyte-io/esse.js/-/esse.js-2023.7.28-0.tgz", + "integrity": "sha512-B+0LF2GDKO3qb910lOvWS3YpusltJL5KdNqdjO//ljZ677fmH89VgMr82BM8jAhIEx5Uo6bZZ/Fwdsl+oYsUMg==", "requires": { "@babel/cli": "7.16.0", "@babel/core": "7.16.0", diff --git a/src/utils/yaml.js b/src/utils/yaml.js index eaa51e3f..1ea148cb 100644 --- a/src/utils/yaml.js +++ b/src/utils/yaml.js @@ -183,11 +183,62 @@ export const includeType = new yaml.Type("!include", { }, }); +/** + * !flatten YAML tag for flattening arrays + * See the tests for example usage. + */ +export const flattenType = new yaml.Type("!flatten", { + kind: "sequence", + construct(data) { + try { + return data.flat(); + } catch (e) { + return data; + } + }, +}); + +/** + * !readFile YAML tag for including file contents as a string. + * See the tests for example usage. + */ +export const readFileType = new yaml.Type("!readFile", { + kind: "scalar", + construct(data) { + try { + return fs.readFileSync(path.resolve(data), "utf8"); + } catch (e) { + return data; + } + }, +}); + +/** + * !concatString YAML tag for concatenating strings. + * See the tests for example usage. + */ +export const concatStringType = new yaml.Type("!concatString", { + kind: "sequence", + resolve(data) { + return data.every((d) => lodash.isString(d)); + }, + construct(data) { + try { + return "".concat(...data); + } catch (e) { + return data; + } + }, +}); + export const JsYamlTypes = { include: includeType, parameter: parameterType, combine: combineType, esse: esseType, + flatten: flattenType, + readFile: readFileType, + concatString: concatStringType, }; export const JsYamlAllSchemas = yaml.DEFAULT_SCHEMA.extend([ @@ -195,4 +246,7 @@ export const JsYamlAllSchemas = yaml.DEFAULT_SCHEMA.extend([ combineType, esseType, includeType, + flattenType, + readFileType, + concatStringType, ]); diff --git a/tests/enums.js b/tests/enums.js index 83bc91ed..cb343f90 100644 --- a/tests/enums.js +++ b/tests/enums.js @@ -5,3 +5,6 @@ export const YAML_COMBINE_FILE = path.resolve(FIXTURES_DIR, "yaml_combine_tag.ym export const YAML_PARAMETER_FILE = path.resolve(FIXTURES_DIR, "yaml_parameter_tag.yml"); export const YAML_ESSE_FILE = path.resolve(FIXTURES_DIR, "yaml_esse_tag.yml"); export const YAML_INCLUDE_FILE = path.resolve(FIXTURES_DIR, "yaml_include_tag.yml"); +export const YAML_FLATTEN_FILE = path.resolve(FIXTURES_DIR, "yaml_flatten_tag.yml"); +export const YAML_READFILE_FILE = path.resolve(FIXTURES_DIR, "yaml_readFile_tag.yml"); +export const YAML_CONCAT_STRING_FILE = path.resolve(FIXTURES_DIR, "yaml_concatString_tag.yml"); diff --git a/tests/fixtures/test_content.txt b/tests/fixtures/test_content.txt new file mode 100644 index 00000000..770b738d --- /dev/null +++ b/tests/fixtures/test_content.txt @@ -0,0 +1,2 @@ +Example text +with linebreaks. diff --git a/tests/fixtures/yaml_concatString_tag.yml b/tests/fixtures/yaml_concatString_tag.yml new file mode 100644 index 00000000..7189fbca --- /dev/null +++ b/tests/fixtures/yaml_concatString_tag.yml @@ -0,0 +1,10 @@ +# concatenate three strings +case1: !concatString + - "Hello " + - world + - "!" +# return a string if there is only a single item +case2: !concatString + - Hello +# return an empty string if the array is empty +case3: !concatString [] diff --git a/tests/fixtures/yaml_flatten_tag.yml b/tests/fixtures/yaml_flatten_tag.yml new file mode 100644 index 00000000..21be0374 --- /dev/null +++ b/tests/fixtures/yaml_flatten_tag.yml @@ -0,0 +1,5 @@ +# convert an array of arrays into a flattened array +case1: !flatten + - [a, b, c] + - d + - [e, f] diff --git a/tests/fixtures/yaml_readFile_tag.yml b/tests/fixtures/yaml_readFile_tag.yml new file mode 100644 index 00000000..db69653a --- /dev/null +++ b/tests/fixtures/yaml_readFile_tag.yml @@ -0,0 +1,2 @@ +# read contents of a file into a string +case1: !readFile "tests/fixtures/test_content.txt" diff --git a/tests/utils/yaml.combine.tests.js b/tests/utils/yaml.combine.tests.js index 04065f50..e4da8936 100644 --- a/tests/utils/yaml.combine.tests.js +++ b/tests/utils/yaml.combine.tests.js @@ -10,7 +10,12 @@ import { YAML_COMBINE_FILE } from "../enums"; const combineSchema = yaml.DEFAULT_SCHEMA.extend([combineType, esseType]); describe("YAML tag: !combine", () => { - const yamlFixture = fs.readFileSync(YAML_COMBINE_FILE, "utf8"); + let yamlFixture; + + before(() => { + yamlFixture = fs.readFileSync(YAML_COMBINE_FILE, "utf8"); + }); + it("should correctly parse a custom !combine tag with forEach and config keys", () => { const parsed = yaml.load(yamlFixture, { schema: combineSchema }); const expectedResult = [ diff --git a/tests/utils/yaml.concatString.tests.js b/tests/utils/yaml.concatString.tests.js new file mode 100644 index 00000000..df7201c4 --- /dev/null +++ b/tests/utils/yaml.concatString.tests.js @@ -0,0 +1,30 @@ +import { expect } from "chai"; +import fs from "fs"; +import yaml from "js-yaml"; + +import { concatStringType } from "../../src/utils/yaml"; +import { YAML_CONCAT_STRING_FILE } from "../enums"; + +const concatStringSchema = yaml.DEFAULT_SCHEMA.extend([concatStringType]); + +describe("YAML tag: !concatString", () => { + const yamlFixture = fs.readFileSync(YAML_CONCAT_STRING_FILE, "utf8"); + + it("should concatenate two strings", () => { + const parsed = yaml.load(yamlFixture, { schema: concatStringSchema }); + const expected = "Hello world!"; + expect(parsed.case1).to.be.eql(expected); + }); + + it("should return a string if there is only a single item", () => { + const parsed = yaml.load(yamlFixture, { schema: concatStringSchema }); + const expected = "Hello"; + expect(parsed.case2).to.be.eql(expected); + }); + + it("should return an empty string if the array is empty", () => { + const parsed = yaml.load(yamlFixture, { schema: concatStringSchema }); + const expected = ""; + expect(parsed.case3).to.be.eql(expected); + }); +}); diff --git a/tests/utils/yaml.flatten.tests.js b/tests/utils/yaml.flatten.tests.js new file mode 100644 index 00000000..01bb851b --- /dev/null +++ b/tests/utils/yaml.flatten.tests.js @@ -0,0 +1,18 @@ +import { expect } from "chai"; +import fs from "fs"; +import yaml from "js-yaml"; + +import { flattenType } from "../../src/utils/yaml"; +import { YAML_FLATTEN_FILE } from "../enums"; + +const flattenSchema = yaml.DEFAULT_SCHEMA.extend([flattenType]); + +describe("YAML tag: !flatten", () => { + const yamlFixture = fs.readFileSync(YAML_FLATTEN_FILE, "utf8"); + + it("should convert an array of arrays into a flattened array", () => { + const parsed = yaml.load(yamlFixture, { schema: flattenSchema }); + const expected = ["a", "b", "c", "d", "e", "f"]; + expect(parsed.case1).to.be.eql(expected); + }); +}); diff --git a/tests/utils/yaml.readFile.tests.js b/tests/utils/yaml.readFile.tests.js new file mode 100644 index 00000000..0d6ed074 --- /dev/null +++ b/tests/utils/yaml.readFile.tests.js @@ -0,0 +1,19 @@ +import { expect } from "chai"; +import fs from "fs"; +import yaml from "js-yaml"; + +import { readFileType } from "../../src/utils/yaml"; +import { YAML_READFILE_FILE } from "../enums"; + +const readFileSchema = yaml.DEFAULT_SCHEMA.extend([readFileType]); + +describe("YAML tag: !readFile", () => { + const yamlFixture = fs.readFileSync(YAML_READFILE_FILE, "utf8"); + + it("should read contents of a file into a string", () => { + const parsed = yaml.load(yamlFixture, { schema: readFileSchema }); + const expected = "Example text\nwith linebreaks.\n"; + expect(parsed.case1).to.be.a("string"); + expect(parsed.case1).to.be.eql(expected); + }); +});