diff --git a/src/__snapshots__/parser.test.ts.snap b/src/__snapshots__/parser.test.ts.snap index ad0fc65..1f88662 100644 --- a/src/__snapshots__/parser.test.ts.snap +++ b/src/__snapshots__/parser.test.ts.snap @@ -10,6 +10,7 @@ exports[`Parsing Notcl Misc Big mess of markup 1`] = ` "pos": 5, }, { + "pos": 8, "text": "Hello, World!", }, ], @@ -63,6 +64,7 @@ exports[`Parsing Notcl Misc Big mess of markup 1`] = ` "pos": 219, }, { + "pos": 224, "text": "Beware!", }, ], @@ -72,6 +74,7 @@ exports[`Parsing Notcl Misc Big mess of markup 1`] = ` "pos": 238, }, { + "pos": 243, "text": "All text should be quoted, it's clearer that way. & blockquotes already should contain paragraphs. (maybe normalize nested paragraphs)", }, ], diff --git a/src/parser.test.ts b/src/parser.test.ts index d213652..8614271 100644 --- a/src/parser.test.ts +++ b/src/parser.test.ts @@ -52,12 +52,20 @@ b`) expect( parse(String.raw`a\\ b`) - ).toEqual([true, [[{ text: "a\\" }], [{ bare: "b", pos: 4 }]]])); + ).toEqual([true, [[{ text: "a\\", pos: 0 }], [{ bare: "b", pos: 4 }]]])); it("does not split commands on folded newlines with escaped backslashes", () => expect( parse(String.raw`a\\\ b`) - ).toEqual([true, [[{ text: "a\\" }, { bare: "b", pos: 4 }]]])); + ).toEqual([ + true, + [ + [ + { text: "a\\", pos: 0 }, + { bare: "b", pos: 4 }, + ], + ], + ])); it("accepts semicolons as command separators", () => expect(parse("a;b")).toEqual([ @@ -130,13 +138,13 @@ b`) ])); it("accepts empty quotes", () => - expect(parse('""')).toEqual([true, [[{ text: "" }]]])); + expect(parse('""')).toEqual([true, [[{ text: "", pos: 0 }]]])); it("accepts quoted words", () => - expect(parse('"a"')).toEqual([true, [[{ text: "a" }]]])); + expect(parse('"a"')).toEqual([true, [[{ text: "a", pos: 0 }]]])); it("accepts quoted words with spaces", () => - expect(parse('"a b"')).toEqual([true, [[{ text: "a b" }]]])); + expect(parse('"a b"')).toEqual([true, [[{ text: "a b", pos: 0 }]]])); it("allows escaped quotes inside a quote", () => - expect(parse('"a\\"b"')).toEqual([true, [[{ text: 'a"b' }]]])); + expect(parse('"a\\"b"')).toEqual([true, [[{ text: 'a"b', pos: 0 }]]])); it("must close quoted words", () => expect(parse('"a b')).toMatchObject([false, {}])); @@ -145,18 +153,18 @@ b`) expect(parse('""a')).toMatchObject([false, {}])); it("accepts escaped spaces", () => - expect(parse("a\\ b")).toEqual([true, [[{ text: "a b" }]]])); + expect(parse("a\\ b")).toEqual([true, [[{ text: "a b", pos: 0 }]]])); it("treats a non-leading quote as a plain character", () => expect(parse('a"')).toEqual([true, [[{ bare: 'a"', pos: 0 }]]])); it("treats a non-leading brace as a plain character", () => expect(parse("a{")).toEqual([true, [[{ bare: "a{", pos: 0 }]]])); it("treats an escaped quote as a plain character", () => - expect(parse('\\"')).toEqual([true, [[{ text: '"' }]]])); + expect(parse('\\"')).toEqual([true, [[{ text: '"', pos: 0 }]]])); it("treats an escaped brace as a plain character", () => - expect(parse("\\{")).toEqual([true, [[{ text: "{" }]]])); + expect(parse("\\{")).toEqual([true, [[{ text: "{", pos: 0 }]]])); it("treats a quoted brace as a plain character", () => - expect(parse('"{"')).toEqual([true, [[{ text: "{" }]]])); + expect(parse('"{"')).toEqual([true, [[{ text: "{", pos: 0 }]]])); }); describe("backslash interpolation", () => {}); @@ -239,10 +247,7 @@ b`) [ [ { - pieces: [ - { script: [[{ bare: "a", pos: 1 }]] }, - { bare: "b", pos: 3 }, - ], + pieces: [{ script: [[{ bare: "a", pos: 1 }]] }, { bare: "b" }], }, ], ], @@ -254,9 +259,9 @@ b`) [ { pieces: [ - { bare: "a", pos: 0 }, + { bare: "a" }, { script: [[{ bare: "b", pos: 2 }]] }, - { bare: "c", pos: 4 }, + { bare: "c" }, ], }, ], @@ -268,10 +273,7 @@ b`) [ [ { - pieces: [ - { bare: "a", pos: 0 }, - { script: [[{ bare: "b", pos: 2 }]] }, - ], + pieces: [{ bare: "a" }, { script: [[{ bare: "b", pos: 2 }]] }], }, ], ], diff --git a/src/parser.ts b/src/parser.ts index 5b0a299..90c8cde 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -36,10 +36,10 @@ function bareWordTmpl(charRegex: RegExp) { Bracket, Regex(charRegex) .expects("CHAR") - .map(([text], index) => ({ bare: text, pos: index })) + .map(([text]) => ({ bare: text })) ) ) - ).map(([, pieces]) => SimplifyWord(pieces)); + ).map(([, pieces], pos) => SimplifyWord(pieces, pos)); } const QuotedWord = Sequence( @@ -55,7 +55,7 @@ const QuotedWord = Sequence( ) ), Regex(/"/y).expects('"') -).map(([, pieces]) => SimplifyWord(pieces)); +).map(([, pieces], pos) => SimplifyWord(pieces, pos)); const Brace: Pattern = Sequence( Regex(/\{/y).expects("{"), diff --git a/src/words.ts b/src/words.ts index c4884c8..5c8f5b7 100644 --- a/src/words.ts +++ b/src/words.ts @@ -101,7 +101,8 @@ function IsTextPiece(piece: InterpolatedPiece | undefined): piece is TextPiece { } export function SimplifyWord( - pieces: InterpolatedPiece[] + pieces: InterpolatedPiece[], + sourcePosition?: SourcePos ): InterpolatedWord | BareWord | TextWord | HtmlWord { const consolidated: InterpolatedPiece[] = []; for (const piece of pieces) { @@ -114,9 +115,9 @@ export function SimplifyWord( } if (consolidated.length == 0) { - return { text: "" }; + return { text: "", pos: sourcePosition }; } else if (consolidated.length == 1 && IsTextPiece(consolidated[0])) { - return consolidated[0]; + return { ...consolidated[0], pos: sourcePosition }; } else { return { pieces: consolidated }; }