From 78c4b98ffab0915f8d457572509de3ea465a0269 Mon Sep 17 00:00:00 2001 From: Alex Rudenko Date: Fri, 18 Nov 2022 10:54:16 +0100 Subject: [PATCH] feat: parse source map (#386) This PR adds a helper for parsing a source map from a recording. --- src/main.ts | 7 ++++++- src/stringify.ts | 24 ++++++++++++++++++++++-- test/stringify.test.ts | 12 +++++++++++- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/main.ts b/src/main.ts index a1527bfc..ca0fb0b8 100644 --- a/src/main.ts +++ b/src/main.ts @@ -21,7 +21,12 @@ export * from './Schema.js'; export * as Schema from './Schema.js'; export * from './SchemaUtils.js'; export { StringifyExtension } from './StringifyExtension.js'; -export { stringify, stringifyStep, StringifyOptions } from './stringify.js'; +export { + stringify, + stringifyStep, + StringifyOptions, + parseSourceMap, +} from './stringify.js'; export { LineWriter } from './LineWriter.js'; export { RunnerExtension } from './RunnerExtension.js'; export { createRunner, Runner } from './Runner.js'; diff --git a/src/stringify.ts b/src/stringify.ts index ae349d4c..300a7944 100644 --- a/src/stringify.ts +++ b/src/stringify.ts @@ -27,6 +27,13 @@ export interface StringifyOptions { indentation?: string; } +const SOURCE_MAP_PREFIX = '//# recorderSourceMap='; + +/** + * The format is [version, [lineNo, length], [lineNo, length] ... [lineNo, length]]. + */ +export type SourceMap = Array; + /** * Stringifes an entire recording. The following hooks are invoked with the `flow` parameter containing the entire flow: * - `beforeAllSteps` (once) @@ -47,7 +54,6 @@ export async function stringify( await ext.beforeAllSteps?.(out, flow); - // version, [lineNo, length], [lineNo, length] ... const sourceMap: Array = [1]; for (const step of flow.steps) { const firstLine = out.getSize(); @@ -59,7 +65,7 @@ export async function stringify( } await ext.afterAllSteps?.(out, flow); - out.appendLine('//# recorderSourceMap=' + vlq.encode(sourceMap)); + out.appendLine(SOURCE_MAP_PREFIX + vlq.encode(sourceMap)); return out.toString(); } @@ -92,3 +98,17 @@ export async function stringifyStep( return out.toString(); } + +/** + * Extracts a source map from a text. + */ +export function parseSourceMap(text: string): SourceMap | undefined { + const lines = text.split('\n'); + for (let i = lines.length - 1; i >= 0; i--) { + const line = lines[i] as string; + if (line.trim().startsWith(SOURCE_MAP_PREFIX)) { + return vlq.decode(line.trim().substring(SOURCE_MAP_PREFIX.length)); + } + } + return; +} diff --git a/test/stringify.test.ts b/test/stringify.test.ts index 2bcd9828..989904c3 100644 --- a/test/stringify.test.ts +++ b/test/stringify.test.ts @@ -14,7 +14,7 @@ limitations under the License. */ -import { stringify } from '../src/stringify.js'; +import { parseSourceMap, stringify } from '../src/stringify.js'; import { assert } from 'chai'; import { StringifyExtension } from '../src/StringifyExtension.js'; import { Step, StepType, UserFlow } from '../src/Schema.js'; @@ -275,4 +275,14 @@ describe('stringify', () => { vlq.decode(sourceMapLine?.split('//# recorderSourceMap=').pop() as string) ); }); + + it('should parse a source map', async () => { + const sourceMap = parseSourceMap(` + test + test + test + //# recorderSourceMap=CCG + `); + assert.deepStrictEqual(sourceMap, [1, 1, 3]); + }); });