diff --git a/README.md b/README.md index ba293f0..8ac4b17 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,9 @@ yarn add @stoplight/yaml ### Usage -- **[parseWithPointers](https://stoplightio.github.io/yaml/globals.html#parsewithpointers)**: Parses YAML into JSON and also returns a source map that includes a JSON path pointer for every property in the result (with line information). +- **[getJsonPathForPosition](https://stoplightio.github.io/yaml/globals.html#getjsonpathforposition)**: Computes JSON path for given position. +- **[getLocationForJsonPath](https://stoplightio.github.io/yaml/globals.html#getlocationforjsonpath)**: Retrieves location of node matching given JSON path. +- **[parseWithPointers](https://stoplightio.github.io/yaml/globals.html#parsewithpointers)**: Parses YAML into JSON and also returns diagnostics as well as full ast with line information. ```ts // basic example of parseWithPointers @@ -27,7 +29,23 @@ import { parseWithPointers } from "@stoplight/yaml"; const result = parseWithPointers("foo: bar"); console.log(result.data); // => the {foo: "bar"} JS object -console.log(result.pointers); // => the source map with a single "#/foo" pointer that has position info for the foo property +``` + +```ts +// basic example of getJsonPathForPosition and getLocationForJsonPath +import { getJsonPathForPosition, getLocationForJsonPath, parseWithPointers } from "@stoplight/yaml"; + +const result = parseWithPointers(`hello: world +address: + street: 123` +); + +const path = getJsonPathForPosition(result, { line: 2, character: 7 }); // line and character are 0-based +console.log(path); // -> ["address", "street"]; + +const position = getLocationForJsonPath(result, ['address']); +console.log(position.range.start); // { line: 1, character: 8 } line and character are 0-based +console.log(position.range.end); // { line: 2, character: 15 } line and character are 0-based ``` ### Contributing diff --git a/src/__tests__/parseWithPointers.spec.ts b/src/__tests__/parseWithPointers.spec.ts index 977bbe4..d227d10 100644 --- a/src/__tests__/parseWithPointers.spec.ts +++ b/src/__tests__/parseWithPointers.spec.ts @@ -43,45 +43,91 @@ describe('yaml parser', () => { expect(result.data).toEqual(HugeJSON); }); - test('report errors', () => { - const result = parseWithPointers( - `prop1: true + describe('report errors', () => { + test('unknown tags', () => { + const result = parseWithPointers(`function: !!js/function > + function foobar() { + return 'Wow! JS-YAML Rocks!'; + } + +test: !!css > + function boom() {} +`); + + expect(result).toHaveProperty('diagnostics', [ + { + code: 'YAMLException', + message: 'unknown tag ', + range: { + end: { + character: 25, + line: 0, + }, + start: { + character: 10, + line: 0, + }, + }, + severity: DiagnosticSeverity.Error, + }, + { + code: 'YAMLException', + message: 'unknown tag ', + range: { + end: { + character: 13, + line: 5, + }, + start: { + character: 6, + line: 5, + }, + }, + severity: DiagnosticSeverity.Error, + }, + ]); + }); + + test('invalid mapping', () => { + const result = parseWithPointers( + `prop1: true prop2: true inner 1 val: 2` - ); + ); - expect(result.diagnostics).toEqual([ - { - severity: DiagnosticSeverity.Error, - message: 'bad indentation of a mapping entry', - code: 'YAMLException', - range: { - start: { - character: 5, - line: 2, - }, - end: { - character: 5, - line: 2, + expect(result.diagnostics).toEqual([ + { + severity: DiagnosticSeverity.Error, + message: 'bad indentation of a mapping entry', + code: 'YAMLException', + range: { + start: { + character: 5, + line: 3, + }, + end: { + character: 5, + line: 3, + }, }, }, - }, - { - severity: DiagnosticSeverity.Error, - message: 'incomplete explicit mapping pair; a key node is missed', - code: 'YAMLException', - range: { - start: { - character: 7, - line: 2, - }, - end: { - character: 7, - line: 2, + { + severity: DiagnosticSeverity.Error, + message: 'incomplete explicit mapping pair; a key node is missed', + code: 'YAMLException', + range: { + start: { + character: 7, + line: 3, + }, + end: { + character: 7, + line: 3, + }, }, }, - }, - ]); + ]); + }); }); }); diff --git a/src/parseWithPointers.ts b/src/parseWithPointers.ts index d9b6973..e781c73 100644 --- a/src/parseWithPointers.ts +++ b/src/parseWithPointers.ts @@ -81,6 +81,14 @@ const computeLineMap = (input: string) => { return lineMap; }; +function getLineLength(lineMap: number[], line: number) { + if (line === 0) { + return Math.max(0, lineMap[0] - 1); + } + + return Math.max(0, lineMap[line] - lineMap[line - 1] - 1); +} + const transformErrors = (errors: YAMLException[], lineMap: number[]): IDiagnostic[] => { const validations: IDiagnostic[] = []; for (const error of errors) { @@ -90,12 +98,12 @@ const transformErrors = (errors: YAMLException[], lineMap: number[]): IDiagnosti severity: error.isWarning ? DiagnosticSeverity.Warning : DiagnosticSeverity.Error, range: { start: { - line: error.mark.line - 1, + line: error.mark.line, character: error.mark.column, }, end: { - line: error.mark.line - 1, - character: error.mark.toLineEnd ? lineMap[error.mark.line - 1] : error.mark.column, + line: error.mark.line, + character: error.mark.toLineEnd ? getLineLength(lineMap, error.mark.line) : error.mark.column, }, }, };