Skip to content

Commit

Permalink
feat(getLocationForJsonPath): support CLRF (#15)
Browse files Browse the repository at this point in the history
* fix: improve getLocationForJsonPath lookup

* fix: handle nullish items
  • Loading branch information
P0lip authored Jul 8, 2019
1 parent 57c9e2c commit 5ace034
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 4 deletions.
6 changes: 6 additions & 0 deletions src/__tests__/fixtures/spectral-crlf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
openapi: 3.0.0
info:
version: 1.0.0
title: OAS3
paths: {}
6 changes: 6 additions & 0 deletions src/__tests__/fixtures/spectral-lf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
openapi: 3.0.0
info:
version: 1.0.0
title: OAS3
paths: {}
74 changes: 74 additions & 0 deletions src/__tests__/getLocationForJsonPath.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { parseWithPointers } from '../parseWithPointers';

const petStore = fs.readFileSync(join(__dirname, './fixtures/petstore.oas2.yaml'), 'utf-8');
const spectral170 = fs.readFileSync(join(__dirname, './fixtures/spectral-170.yaml'), 'utf-8');
const spectralCRLF = fs.readFileSync(join(__dirname, './fixtures/spectral-crlf.yaml'), 'utf-8');
const spectralLF = fs.readFileSync(join(__dirname, './fixtures/spectral-lf.yaml'), 'utf-8');
const simple = `hello: world
address:
street: 123`;
Expand Down Expand Up @@ -94,4 +96,76 @@ describe('getLocationForJsonPath', () => {
});
});
});

describe('CRLF fixture', () => {
const resultCRLF = parseWithPointers(spectralCRLF);
const resultLF = parseWithPointers(spectralLF);

test.each`
start | end | path | closest
${[0, 0]} | ${[5, 9]} | ${['servers']} | ${true}
${[2, 5]} | ${[4, 13]} | ${['info']} | ${true}
${[2, 5]} | ${[4, 13]} | ${['info', 'server']} | ${true}
${[2, 5]} | ${[4, 13]} | ${['info', 'contact']} | ${true}
${[4, 9]} | ${[4, 13]} | ${['info', 'title']} | ${true}
${[5, 6]} | ${[5, 9]} | ${['paths']} | ${true}
`('should return proper location for given JSONPath $path', ({ start, end, path, closest }) => {
expect(getLocationForJsonPath(resultCRLF, path, closest)).toEqual(
getLocationForJsonPath(resultLF, path, closest)
);
expect(getLocationForJsonPath(resultCRLF, path)).toEqual(getLocationForJsonPath(resultLF, path));
expect(getLocationForJsonPath(resultCRLF, path, closest)).toEqual(
start.length > 0 && end.length > 0
? {
range: {
start: {
character: start[1],
line: start[0],
},
end: {
character: end[1],
line: end[0],
},
},
}
: void 0
);
});
});

describe('shifted fixture', () => {
const result = parseWithPointers(`--- foobar: bar`);

test.each`
start | end | path | closest
${[0, 4]} | ${[0, 15]} | ${['paths']} | ${true}
`('should return proper location for given JSONPath $path', ({ start, end, path, closest }) => {
expect(getLocationForJsonPath(result, path, closest)).toEqual(
start.length > 0 && end.length > 0
? {
range: {
start: {
character: start[1],
line: start[0],
},
end: {
character: end[1],
line: end[0],
},
},
}
: void 0
);
});
});

it('should handle null-ish items', () => {
const result = parseWithPointers(`----~
foo: bar
`);

expect(() => getLocationForJsonPath(result, ['foo'])).not.toThrow();
expect(() => getLocationForJsonPath(result, ['bar'], true)).not.toThrow();
expect(() => getLocationForJsonPath(result, ['null'], true)).not.toThrow();
});
});
16 changes: 12 additions & 4 deletions src/getLocationForJsonPath.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@ export const getLocationForJsonPath: GetLocationForJsonPath<YAMLNode, number[]>
const node = findNodeAtPath(ast, path, closest);
if (node === void 0) return;

return getLoc(lineMap, { start: getStartPosition(node), end: getEndPosition(node) });
return getLoc(lineMap, {
start: getStartPosition(node, lineMap.length > 0 ? lineMap[0] : 0),
end: getEndPosition(node),
});
};

function getStartPosition(node: YAMLNode): number {
function getStartPosition(node: YAMLNode, offset: number): number {
if (node.parent && node.parent.kind === Kind.MAPPING) {
// the parent is a mapping with no value, let's default to the end of node
if (node.parent.value === null) {
Expand All @@ -25,14 +28,18 @@ function getStartPosition(node: YAMLNode): number {
}
}

if (node.parent === null && offset - node.startPosition === 0) {
return 0;
}

return node.startPosition;
}

function getEndPosition(node: YAMLNode): number {
switch (node.kind) {
case Kind.SEQ:
const { items } = node as YAMLSequence;
if (items.length !== 0) {
if (items.length !== 0 && items[items.length - 1] !== null) {
return getEndPosition(items[items.length - 1]);
}
break;
Expand All @@ -49,7 +56,7 @@ function getEndPosition(node: YAMLNode): number {
break;
case Kind.SCALAR:
// the parent is a mapping with no value, let's default to the end of node
if (node.parent.kind === Kind.MAPPING && node.parent.value === null) {
if (node.parent !== null && node.parent.kind === Kind.MAPPING && node.parent.value === null) {
return node.parent.endPosition;
}

Expand Down Expand Up @@ -95,6 +102,7 @@ function findNodeAtPath(node: YAMLNode, path: JsonPath, closest: boolean) {
const getLoc = (lineMap: number[], { start = 0, end = 0 }): ILocation => {
const startLine = lineForPosition(start, lineMap);
const endLine = lineForPosition(end, lineMap);

return {
range: {
start: {
Expand Down

0 comments on commit 5ace034

Please sign in to comment.