Skip to content

Commit

Permalink
fix: handle edge case
Browse files Browse the repository at this point in the history
  • Loading branch information
P0lip committed Apr 17, 2019
1 parent 0659cfe commit a3f116a
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 18 deletions.
71 changes: 71 additions & 0 deletions src/__tests__/__snapshots__/parseWithPointers.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,76 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`yaml parser dereferencing anchor refs insane edge case 1`] = `
Array [
Array [
Array [
undefined,
Object {
"test": Array [
undefined,
],
},
Object {
"abc": Object {
"a": null,
"c": undefined,
"foo": 2,
"x": undefined,
},
},
],
Object {
"test": Array [
Array [
undefined,
Object {
"test": Array [
undefined,
],
},
Object {
"abc": Object {
"a": null,
"c": undefined,
"foo": 2,
"x": undefined,
},
},
],
],
},
Object {
"abc": Object {
"a": null,
"c": Array [
undefined,
Object {
"test": Array [
undefined,
],
},
Object {
"abc": Object {
"a": null,
"c": undefined,
"foo": 2,
"x": undefined,
},
},
],
"foo": 2,
"x": Object {
"a": null,
"c": undefined,
"foo": 2,
"x": undefined,
},
},
},
],
]
`;

exports[`yaml parser parse diverse 1`] = `
Object {
"ast": Object {
Expand Down
94 changes: 83 additions & 11 deletions src/__tests__/parseWithPointers.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,26 +141,98 @@ prop2: true
});
});

test('dereferences circular anchor refs', () => {
const result = parseWithPointers(`definitions:
describe('dereferencing anchor refs', () => {
test('ignore valid refs', () => {
const result = parseWithPointers(`austrian-cities: &austrian-cities
- Vienna
- Graz
- Linz
- Salzburg
european-cities:
austria: *austrian-cities
`);
expect(result.data).toEqual({
'austrian-cities': ['Vienna', 'Graz', 'Linz', 'Salzburg'],
'european-cities': {
austria: ['Vienna', 'Graz', 'Linz', 'Salzburg'],
},
});
});

test('support circular refs in mapping', () => {
const result = parseWithPointers(`definitions:
model: &ref
foo:
name: *ref
`);
expect(result.data).toEqual({
definitions: {
model: {
foo: {
name: {
foo: {
name: undefined,

expect(result.data).toEqual({
definitions: {
model: {
foo: {
name: {
foo: {
name: undefined,
},
},
},
},
},
},
});

expect(() => JSON.stringify(result.data)).not.toThrow();
});

expect(() => JSON.stringify(result.data)).not.toThrow();
test('support circular in refs sequences', () => {
const result = parseWithPointers(`- &foo
- test:
- *foo
`);
expect(result.data).toEqual([
[
{
test: [[{ test: [undefined] }]],
},
],
]);

expect(() => JSON.stringify(result.data)).not.toThrow();
});

test('support circular nested refs', () => {
const result = parseWithPointers(`a: &foo
- b: &bar
- true
- c: *bar
- *foo
`);

expect(result.data).toEqual({
a: [
{
b: [true, { c: [true, { c: undefined }, undefined] }, [{ b: [true, { c: undefined }, undefined] }]],
},
],
});

expect(() => JSON.stringify(result.data)).not.toThrow();
});

test('insane edge case', () => {
const result = parseWithPointers(`- &foo
- *foo
- test:
- *foo
- abc: &test
foo: 2
a:
c: *foo
x: *test
`);
expect(result.data).toMatchSnapshot();

expect(() => JSON.stringify(result.data)).not.toThrow();
});
});
});
19 changes: 12 additions & 7 deletions src/parseWithPointers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const walk = (node: YAMLNode | null): unknown => {
return 'valueObject' in node ? node.valueObject : node.value;
case Kind.ANCHOR_REF:
if (node.value !== undefined && isCircularAnchorRef(node as YAMLAnchorReference)) {
node.value = dereferenceAnchor(node.value, node);
node.value = dereferenceAnchor(node.value, (node as YAMLAnchorReference).referencesAnchor);
}

return walk(node.value);
Expand All @@ -75,26 +75,31 @@ const isCircularAnchorRef = (anchorRef: YAMLAnchorReference) => {
return false;
};

const dereferenceAnchor = (node: YAMLNode, parent: YAMLNode): YAMLNode | YAMLNode[] | void => {
const dereferenceAnchor = (node: YAMLNode, anchorId: string): YAMLNode | YAMLNode[] | void => {
if (!node) return node;
if (node === parent) return;
if ('referencesAnchor' in node && (node as YAMLAnchorReference).referencesAnchor === anchorId) return;

switch (node.kind) {
case Kind.MAP:
return {
...node,
mappings: (node as YamlMap).mappings.map(mapping => dereferenceAnchor(mapping, parent) as YAMLNode),
mappings: (node as YamlMap).mappings.map(mapping => dereferenceAnchor(mapping, anchorId) as YAMLNode),
} as YamlMap;
case Kind.SEQ:
return {
...node,
items: (node as YAMLSequence).items.map(item => dereferenceAnchor(item, parent) as YAMLNode),
items: (node as YAMLSequence).items.map(item => dereferenceAnchor(item, anchorId) as YAMLNode),
} as YAMLSequence;
case Kind.MAPPING:
return { ...node, value: dereferenceAnchor(node.value, parent) };
return { ...node, value: dereferenceAnchor(node.value, anchorId) };
case Kind.SCALAR:
return node;
case Kind.ANCHOR_REF:
return { ...node };
if (node.value !== undefined && isCircularAnchorRef(node as YAMLAnchorReference)) {
return;
}

return node;
default:
return node;
}
Expand Down

0 comments on commit a3f116a

Please sign in to comment.