From d16072a33439749f2e12ed85954c7721161db8cc Mon Sep 17 00:00:00 2001 From: Vincent LE GOFF Date: Thu, 4 Apr 2019 12:00:24 +0200 Subject: [PATCH] TOML: Full support of inline table (#320) --- toml/README.md | 14 +++++--- toml/parser.ts | 63 ++++++++++++++++++++++++++++++++-- toml/parser_test.ts | 22 +++++++++++- toml/testdata/inlineTable.toml | 5 ++- 4 files changed, 95 insertions(+), 9 deletions(-) diff --git a/toml/README.md b/toml/README.md index a1acd7466d..b19974b2eb 100644 --- a/toml/README.md +++ b/toml/README.md @@ -22,7 +22,7 @@ TypeScript side is a bit different. - :heavy_check_mark: [Local Date](https://github.com/toml-lang/toml#local-date) - :exclamation: [Local Time](https://github.com/toml-lang/toml#local-time) - :heavy_check_mark: [Table](https://github.com/toml-lang/toml#table) -- :exclamation: [Inline Table](https://github.com/toml-lang/toml#inline-table) +- :heavy_check_mark: [Inline Table](https://github.com/toml-lang/toml#inline-table) - :exclamation: [Array of Tables](https://github.com/toml-lang/toml#array-of-tables) :exclamation: _Supported with warnings see [Warning](#Warning)._ @@ -45,12 +45,18 @@ Because local time does not exist in JavaScript, the local time is stored as a s #### Inline Table -Inline tables are supported but nested inline property name are **not**. See below: +Inline tables are supported. See below: ```toml -animal = { type = { name = "pug" } } # Supported +animal = { type = { name = "pug" } } +# Output animal = { type.name = "pug" } -# not supported. Will output { "animal" : {"type.name":"pug"} } +# Output { animal : { type : { name : "pug" } } +animal.as.leaders = "tosin" +# Output { animal: { as: { leaders: "tosin" } } } +"tosin.abasi" = "guitarist" +# Output +"tosin.abasi" : "guitarist" ``` #### Array of Tables diff --git a/toml/parser.ts b/toml/parser.ts index d8acc608be..09203775a4 100644 --- a/toml/parser.ts +++ b/toml/parser.ts @@ -238,7 +238,6 @@ class Parser { .replace(result[2], ":"); dataString = dataString.replace(ogVal, newVal); } - // TODO : unflat if necessary return JSON.parse(dataString); } @@ -271,6 +270,38 @@ class Parser { const reg = /\d{4}-\d{2}-\d{2}/; return reg.test(dateStr); } + _parseDeclarationName(declaration: string): string[] { + const out = []; + let acc = []; + let inLitteral = false; + for (let i = 0; i < declaration.length; i++) { + const c = declaration[i]; + switch (c) { + case ".": + if (!inLitteral) { + out.push(acc.join("")); + acc = []; + } else { + acc.push(c); + } + break; + case `"`: + if (inLitteral) { + inLitteral = false; + } else { + inLitteral = true; + } + break; + default: + acc.push(c); + break; + } + } + if (acc.length !== 0) { + out.push(acc.join("")); + } + return out; + } _parseLines(): void { for (let i = 0; i < this.tomlLines.length; i++) { const line = this.tomlLines[i]; @@ -301,10 +332,12 @@ class Parser { } if (this._isDeclaration(line)) { let kv = this._processDeclaration(line); + let key = kv.key; + let value = kv.value; if (!this.context.currentGroup) { - this.context.output[kv.key] = kv.value; + this.context.output[key] = value; } else { - this.context.currentGroup.objValues[kv.key] = kv.value; + this.context.currentGroup.objValues[key] = value; } } } @@ -317,9 +350,33 @@ class Parser { this._groupToOutput(); } } + _cleanOutput(): void { + this._propertyClean(this.context.output); + } + _propertyClean(obj: object): void { + const keys = Object.keys(obj); + for (let i = 0; i < keys.length; i++) { + let k = keys[i]; + let v = obj[k]; + let pathDeclaration = this._parseDeclarationName(k); + delete obj[k]; + if (pathDeclaration.length > 1) { + k = pathDeclaration.shift(); + k = k.replace(/"/g, ""); + v = this._unflat(pathDeclaration, v as object); + } else { + k = k.replace(/"/g, ""); + } + obj[k] = v; + if (v instanceof Object) { + this._propertyClean(v); + } + } + } parse(): object { this._sanitize(); this._parseLines(); + this._cleanOutput(); return this.context.output; } } diff --git a/toml/parser_test.ts b/toml/parser_test.ts index 104428b25e..77bf9dc97d 100644 --- a/toml/parser_test.ts +++ b/toml/parser_test.ts @@ -181,6 +181,20 @@ test({ fn() { const expected = { inlinetable: { + nile: { + also: { + malevolant: { + creation: { + drum: { + kit: "Tama" + } + } + } + }, + derek: { + roddy: "drummer" + } + }, name: { first: "Tom", last: "Preston-Werner" @@ -189,10 +203,16 @@ test({ x: 1, y: 2 }, - animal: { + dog: { type: { name: "pug" } + }, + "tosin.abasi": "guitarist", + animal: { + as: { + leaders: "tosin" + } } } }; diff --git a/toml/testdata/inlineTable.toml b/toml/testdata/inlineTable.toml index 1a7e55c526..203cb16db7 100644 --- a/toml/testdata/inlineTable.toml +++ b/toml/testdata/inlineTable.toml @@ -1,4 +1,7 @@ [inlinetable] name = { first = "Tom", last = "Preston-Werner" } point = { x = 1, y = 2 } -animal = { type = { name = "pug" } } \ No newline at end of file +dog = { type = { name = "pug" } } +animal.as.leaders = "tosin" +"tosin.abasi" = "guitarist" +nile = { derek.roddy = "drummer", also = { malevolant.creation = { drum.kit = "Tama" } } } \ No newline at end of file