From 2cca78f2f42ea147a3ce328260aa3cbc0fef8a84 Mon Sep 17 00:00:00 2001 From: Sergiy Yavorsky Date: Fri, 25 Dec 2020 02:24:48 -0800 Subject: [PATCH] assure consistent source referencing/clonning --- README.md | 4 +-- src/transforms/align.ts | 3 +- src/transforms/indent.ts | 17 ++++------ src/util.ts | 13 +++++++- tests/unit/transforms-align.spec.ts | 13 ++++++++ tests/unit/transforms-indent.spec.ts | 20 ++++++------ tests/unit/transforms.spec.ts | 21 ++++++++++++ tests/unit/util.spec.ts | 48 ++++++++++++++++++++++++++++ 8 files changed, 115 insertions(+), 24 deletions(-) create mode 100644 tests/unit/transforms.spec.ts diff --git a/README.md b/README.md index becc7ced8..edca97d8b 100644 --- a/README.md +++ b/README.md @@ -167,7 +167,7 @@ examples ## Stringifier -The stringifier is an important piece used by other tools updating the source code. It goes over `Block.source[].tokens` and assembles them back to a string. It might be used with various transforms applied to the parsed data before strngifying. +The stringifier is an important piece used by other tools updating the source code. It goes over `Block.source[].tokens` and assembles them back to a string. It might be used with various transforms applied to the parsed data before stringifying. ```js const { parse, stringify, transforms: {flow, align, indent} } = require('./lib/'); @@ -201,7 +201,7 @@ console.log(stringify(transform(parsed[0]))); ``` examples -- [using standard formats](https://syavorsky.github.io/comment-parser/#stringify-formatting) +- [format comments](https://syavorsky.github.io/comment-parser/#stringify-formatting) [suggest more examples](https://github.com/syavorsky/comment-parser/issues/new?title=example+suggestion%3A+...&labels=example,stringifier) diff --git a/src/transforms/align.ts b/src/transforms/align.ts index e1cbd99f8..d9c54aab3 100644 --- a/src/transforms/align.ts +++ b/src/transforms/align.ts @@ -1,5 +1,6 @@ import { Transform } from './index'; import { Markers, Tokens, Block, Line } from '../primitives'; +import { rewireSource } from '../util'; interface Width { start: number; @@ -76,6 +77,6 @@ export default function align(): Transform { return ({ source, ...fields }: Block): Block => { w = source.reduce(getWidth, { ...zeroWidth }); - return { ...fields, source: source.map(update) }; + return rewireSource({ ...fields, source: source.map(update) }); }; } diff --git a/src/transforms/indent.ts b/src/transforms/indent.ts index 15a82b7d7..18541d6dc 100644 --- a/src/transforms/indent.ts +++ b/src/transforms/indent.ts @@ -1,5 +1,6 @@ import { Transform } from './index'; import { Block, Line } from '../primitives'; +import { rewireSource } from '../util'; const pull = (offset: number) => (str) => str.slice(offset); const push = (offset: number) => { @@ -17,15 +18,11 @@ export default function indent(pos: number): Transform { return shift(start); }; - const update = (line: Line): Line => { - line.tokens.start = pad(line.tokens.start); - return line; - }; - - return ({ description, tags, source, problems }: Block): Block => ({ - description, - problems, - tags, - source: source.map(update), + const update = (line: Line): Line => ({ + ...line, + tokens: { ...line.tokens, start: pad(line.tokens.start) }, }); + + return ({ source, ...fields }: Block): Block => + rewireSource({ ...fields, source: source.map(update) }); } diff --git a/src/util.ts b/src/util.ts index 73932902b..daf0deaea 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,4 +1,4 @@ -import { Block, Tokens, Spec } from './primitives'; +import { Block, Tokens, Spec, Line } from './primitives'; export function isSpace(source: string): boolean { return /^\s+$/.test(source); @@ -54,3 +54,14 @@ export function seedTokens(tokens: Partial = {}): Tokens { ...tokens, }; } + +export function rewireSource(block: Block): Block { + const source = block.source.reduce( + (acc, line) => acc.set(line.number, line), + new Map() + ); + for (const spec of block.tags) { + spec.source = spec.source.map((line) => source.get(line.number)); + } + return block; +} diff --git a/tests/unit/transforms-align.spec.ts b/tests/unit/transforms-align.spec.ts index e4902ff63..a8f0bd2f8 100644 --- a/tests/unit/transforms-align.spec.ts +++ b/tests/unit/transforms-align.spec.ts @@ -58,3 +58,16 @@ test('same line close', () => { expect(out).toBe(source); }); + +test('spec source referencing', () => { + const parsed = getParser()(`/** @tag {type} name Description */`); + const block = align()(parsed[0]); + expect(block.tags[0].source[0] === block.source[0]).toBe(true); +}); + +test('block source clonning', () => { + const parsed = getParser()(`/** @tag {type} name Description */`); + const block = align()(parsed[0]); + parsed[0].source[0].tokens.description = 'test'; + expect(block.source[0].tokens.description).toBe('Description '); +}); diff --git a/tests/unit/transforms-indent.spec.ts b/tests/unit/transforms-indent.spec.ts index 094ee5a1c..bbd02c9a3 100644 --- a/tests/unit/transforms-indent.spec.ts +++ b/tests/unit/transforms-indent.spec.ts @@ -81,15 +81,15 @@ test('force pull', () => { expect(out).toBe(expected.slice(1)); }); -test('no source clonning', () => { - const parsed = getParser()(` - /** - * Description may go - * over few lines followed by @tags - * @param {string} name name parameter - * - * @param {any} value value of any type - */`); +test('spec source referencing', () => { + const parsed = getParser()(`/** @tag {type} name Description */`); + const block = indent(0)(parsed[0]); + expect(block.tags[0].source[0] === block.source[0]).toBe(true); +}); + +test('block source clonning', () => { + const parsed = getParser()(`/** @tag {type} name Description */`); const block = indent(0)(parsed[0]); - expect(block.tags[0].source[0] === block.source[3]).toBe(true); + parsed[0].source[0].tokens.description = 'test'; + expect(block.source[0].tokens.description).toBe('Description '); }); diff --git a/tests/unit/transforms.spec.ts b/tests/unit/transforms.spec.ts new file mode 100644 index 000000000..f97221a6f --- /dev/null +++ b/tests/unit/transforms.spec.ts @@ -0,0 +1,21 @@ +import { flow } from '../../src/transforms/index'; +import { seedBlock } from '../../src/util'; +import { Block } from '../../src/primitives'; + +const t0 = (b: Block): Block => ({ ...b, description: b.description + ' t0' }); +const t1 = (b: Block): Block => ({ ...b, description: b.description + ' t1' }); + +test('multiple', () => { + const block = seedBlock({ description: 'test' }); + expect(flow(t0, t1)(block).description).toBe('test t0 t1'); +}); + +test('one', () => { + const block = seedBlock({ description: 'test' }); + expect(flow(t0)(block).description).toBe('test t0'); +}); + +test('none', () => { + const block = seedBlock({ description: 'test' }); + expect(flow()(block).description).toBe('test'); +}); diff --git a/tests/unit/util.spec.ts b/tests/unit/util.spec.ts index afc94b1f5..44b32e6f7 100644 --- a/tests/unit/util.spec.ts +++ b/tests/unit/util.spec.ts @@ -5,6 +5,7 @@ import { splitLines, splitSpace, seedSpec, + rewireSource, } from '../../src/util'; test.each([ @@ -116,3 +117,50 @@ test('seedSpec overrides', () => { source: [], }); }); + +test('rewireSource', () => { + const source = () => [ + { + number: 42, + source: '/** @my-tag */', + tokens: { + start: '', + delimiter: '/**', + postDelimiter: ' ', + tag: '@my-tag', + postTag: ' ', + name: '', + postName: '', + type: '', + postType: '', + description: '', + end: '*/', + }, + }, + ]; + + const parsed = { + description: '', + tags: [ + { + tag: 'my-tag', + name: '', + type: '', + optional: false, + description: '', + problems: [], + source: source(), + }, + ], + source: source(), + problems: [], + }; + + expect(parsed.source[0] === parsed.tags[0].source[0]).toBe(false); + + rewireSource(parsed); + + expect(parsed.source[0] === parsed.tags[0].source[0]).toBe(true); + parsed.source[0].tokens.name = 'test'; + expect(parsed.tags[0].source[0].tokens.name).toBe('test'); +});