From 9ab3e6c99bd8d827c69675dbdbf228ce9489bef0 Mon Sep 17 00:00:00 2001 From: Zibi Braniecki Date: Thu, 5 Oct 2017 15:31:27 +0200 Subject: [PATCH 1/3] Enforce message element indentation --- fluent/src/parser.js | 57 +++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/fluent/src/parser.js b/fluent/src/parser.js index 946682a72..bd5b399ea 100644 --- a/fluent/src/parser.js +++ b/fluent/src/parser.js @@ -130,33 +130,37 @@ class RuntimeParser { if (ch === '=') { this._index++; - this.skipInlineWS(); - this.skipBlankLines(); this.skipInlineWS(); - val = this.getPattern(); + if (this._source[this._index] === '\n') { + this.skipBlankLines(); + if (this._source[this._index] === ' ') { + this.skipInlineWS(); + val = this.getPattern(); + } + } else { + val = this.getPattern(); + } } else { - this.skipWS(); + this.skipInlineWS(); + this.skipBlankLines(); } ch = this._source[this._index]; - if (ch === '\n') { - this._index++; - this.skipBlankLines(); + if (ch === ' ') { + const lineStart = this._index; this.skipInlineWS(); + ch = this._source[this._index]; - } - if (ch === '.') { - attrs = this.getAttributes(); - } + this._index = lineStart; - if (ch === '#') { - if (attrs !== null) { - throw this.error('Tags cannot be added to a message with attributes.'); + if (ch === '.') { + attrs = this.getAttributes(); + } else if (ch === '#') { + tags = this.getTags(); } - tags = this.getTags(); } if (tags === null && attrs === null && typeof val === 'string') { @@ -214,7 +218,7 @@ class RuntimeParser { this.skipInlineWS(); - if (this._source[ptr] === '\n') { + if (this._source[this._index] === '\n') { this._index += 1; } else { this._index = ptr; @@ -337,6 +341,8 @@ class RuntimeParser { this._index = eol + 1; + this.skipBlankLines(); + if (this._source[this._index] === ' ') { this._index = start; return this.getComplexPattern(); @@ -387,6 +393,7 @@ class RuntimeParser { this._source[this._index] === '*' || this._source[this._index] === '#' || this._source[this._index] === '.') { + this._index = blankLinesEnd; break; } @@ -693,9 +700,12 @@ class RuntimeParser { const attrs = {}; while (this._index < this._length) { - const ch = this._source[this._index]; + if (this._source[this._index] !== ' ') { + break; + } + this.skipInlineWS(); - if (ch !== '.') { + if (this._source[this._index] !== '.') { break; } this._index++; @@ -721,7 +731,7 @@ class RuntimeParser { }; } - this.skipWS(); + this.skipBlankLines(); } return attrs; @@ -737,9 +747,12 @@ class RuntimeParser { const tags = []; while (this._index < this._length) { - const ch = this._source[this._index]; + if (this._source[this._index] !== ' ') { + break; + } + this.skipInlineWS(); - if (ch !== '#') { + if (this._source[this._index] !== '#') { break; } this._index++; @@ -748,7 +761,7 @@ class RuntimeParser { tags.push(symbol.name); - this.skipWS(); + this.skipBlankLines(); } return tags; From bbbc61db99f53698dd78ac8876bbe9303a08856f Mon Sep 17 00:00:00 2001 From: Zibi Braniecki Date: Thu, 5 Oct 2017 20:24:56 +0200 Subject: [PATCH 2/3] Add a test --- .../fixtures_structure/elements_indent.ftl | 13 + .../fixtures_structure/elements_indent.json | 314 ++++++++++++++++++ .../fixtures_structure/elements_indent.json | 16 + 3 files changed, 343 insertions(+) create mode 100644 fluent-syntax/test/fixtures_structure/elements_indent.ftl create mode 100644 fluent-syntax/test/fixtures_structure/elements_indent.json create mode 100644 fluent/test/fixtures_structure/elements_indent.json diff --git a/fluent-syntax/test/fixtures_structure/elements_indent.ftl b/fluent-syntax/test/fixtures_structure/elements_indent.ftl new file mode 100644 index 000000000..4d99f6da9 --- /dev/null +++ b/fluent-syntax/test/fixtures_structure/elements_indent.ftl @@ -0,0 +1,13 @@ +foo = Foo +.attr = Foo Attr + +bar = Bar + .attr1 = Bar Attr 1 +.attr2 = Bar Attr 2 + +baz = Baz +#tag + +qux = Qux + #tag1 +#tag2 diff --git a/fluent-syntax/test/fixtures_structure/elements_indent.json b/fluent-syntax/test/fixtures_structure/elements_indent.json new file mode 100644 index 000000000..bf9ec6988 --- /dev/null +++ b/fluent-syntax/test/fixtures_structure/elements_indent.json @@ -0,0 +1,314 @@ +{ + "type": "Resource", + "body": [ + { + "type": "Message", + "annotations": [], + "id": { + "type": "Identifier", + "name": "foo", + "span": { + "type": "Span", + "start": 0, + "end": 3 + } + }, + "value": { + "type": "Pattern", + "elements": [ + { + "type": "TextElement", + "value": "Foo", + "span": { + "type": "Span", + "start": 6, + "end": 9 + } + } + ], + "span": { + "type": "Span", + "start": 6, + "end": 9 + } + }, + "attributes": [], + "tags": [], + "comment": null, + "span": { + "type": "Span", + "start": 0, + "end": 9 + } + }, + { + "type": "Junk", + "annotations": [ + { + "type": "Annotation", + "code": "E0002", + "args": [], + "message": "Expected an entry start", + "span": { + "type": "Span", + "start": 10, + "end": 10 + } + } + ], + "content": ".attr = Foo Attr\n\n", + "span": { + "type": "Span", + "start": 10, + "end": 28 + } + }, + { + "type": "Message", + "annotations": [], + "id": { + "type": "Identifier", + "name": "bar", + "span": { + "type": "Span", + "start": 28, + "end": 31 + } + }, + "value": { + "type": "Pattern", + "elements": [ + { + "type": "TextElement", + "value": "Bar", + "span": { + "type": "Span", + "start": 34, + "end": 37 + } + } + ], + "span": { + "type": "Span", + "start": 34, + "end": 37 + } + }, + "attributes": [ + { + "type": "Attribute", + "id": { + "type": "Identifier", + "name": "attr1", + "span": { + "type": "Span", + "start": 43, + "end": 48 + } + }, + "value": { + "type": "Pattern", + "elements": [ + { + "type": "TextElement", + "value": "Bar Attr 1", + "span": { + "type": "Span", + "start": 51, + "end": 61 + } + } + ], + "span": { + "type": "Span", + "start": 51, + "end": 61 + } + }, + "span": { + "type": "Span", + "start": 42, + "end": 61 + } + } + ], + "tags": [], + "comment": null, + "span": { + "type": "Span", + "start": 28, + "end": 61 + } + }, + { + "type": "Junk", + "annotations": [ + { + "type": "Annotation", + "code": "E0002", + "args": [], + "message": "Expected an entry start", + "span": { + "type": "Span", + "start": 62, + "end": 62 + } + } + ], + "content": ".attr2 = Bar Attr 2\n\n", + "span": { + "type": "Span", + "start": 62, + "end": 83 + } + }, + { + "type": "Message", + "annotations": [], + "id": { + "type": "Identifier", + "name": "baz", + "span": { + "type": "Span", + "start": 83, + "end": 86 + } + }, + "value": { + "type": "Pattern", + "elements": [ + { + "type": "TextElement", + "value": "Baz", + "span": { + "type": "Span", + "start": 89, + "end": 92 + } + } + ], + "span": { + "type": "Span", + "start": 89, + "end": 92 + } + }, + "attributes": [], + "tags": [], + "comment": null, + "span": { + "type": "Span", + "start": 83, + "end": 92 + } + }, + { + "type": "Junk", + "annotations": [ + { + "type": "Annotation", + "code": "E0002", + "args": [], + "message": "Expected an entry start", + "span": { + "type": "Span", + "start": 93, + "end": 93 + } + } + ], + "content": "#tag\n\n", + "span": { + "type": "Span", + "start": 93, + "end": 99 + } + }, + { + "type": "Message", + "annotations": [], + "id": { + "type": "Identifier", + "name": "qux", + "span": { + "type": "Span", + "start": 99, + "end": 102 + } + }, + "value": { + "type": "Pattern", + "elements": [ + { + "type": "TextElement", + "value": "Qux", + "span": { + "type": "Span", + "start": 105, + "end": 108 + } + } + ], + "span": { + "type": "Span", + "start": 105, + "end": 108 + } + }, + "attributes": [], + "tags": [ + { + "type": "Tag", + "name": { + "type": "Symbol", + "name": "tag1", + "span": { + "type": "Span", + "start": 114, + "end": 118 + } + }, + "span": { + "type": "Span", + "start": 113, + "end": 118 + } + } + ], + "comment": null, + "span": { + "type": "Span", + "start": 99, + "end": 118 + } + }, + { + "type": "Junk", + "annotations": [ + { + "type": "Annotation", + "code": "E0002", + "args": [], + "message": "Expected an entry start", + "span": { + "type": "Span", + "start": 119, + "end": 119 + } + } + ], + "content": "#tag2\n", + "span": { + "type": "Span", + "start": 119, + "end": 125 + } + } + ], + "comment": null, + "span": { + "type": "Span", + "start": 0, + "end": 125 + } +} diff --git a/fluent/test/fixtures_structure/elements_indent.json b/fluent/test/fixtures_structure/elements_indent.json new file mode 100644 index 000000000..ef8bed18f --- /dev/null +++ b/fluent/test/fixtures_structure/elements_indent.json @@ -0,0 +1,16 @@ +{ + "foo": "Foo", + "bar": { + "val": "Bar", + "attrs": { + "attr1": "Bar Attr 1" + } + }, + "baz": "Baz", + "qux": { + "val": "Qux", + "tags": [ + "tag1" + ] + } +} From 141672084b33f89063d2f3d4e30d6e1507f53501 Mon Sep 17 00:00:00 2001 From: Zibi Braniecki Date: Thu, 5 Oct 2017 21:44:09 +0200 Subject: [PATCH 3/3] Address feedback --- fluent/src/parser.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fluent/src/parser.js b/fluent/src/parser.js index bd5b399ea..79b7e620d 100644 --- a/fluent/src/parser.js +++ b/fluent/src/parser.js @@ -139,6 +139,9 @@ class RuntimeParser { val = this.getPattern(); } } else { + // This is a fast-path for the most common + // case of `key = Value` where the value + // is in the same line as the key. val = this.getPattern(); } } else {