Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dumping): support lineWidth #24

Merged
merged 3 commits into from
Sep 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,9 @@
"test.watch": "yarn test --watch"
},
"dependencies": {
"@stoplight/types": "^11.0.0",
"@types/js-yaml": "3.12.1",
"@stoplight/types": "^11.1.0",
"lodash": "^4.17.15",
"yaml-ast-parser": "~0.0.43"
"@stoplight/yaml-ast-parser": "0.0.43"
},
"devDependencies": {
"@stoplight/scripts": "3.1.0",
Expand Down
36 changes: 36 additions & 0 deletions src/__tests__/fixtures/merge-keys-with-duplicate-props.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
openapi: 3.0.0

x-format-version: "1.0"

info:
title: Merge key issue
description: https://yaml.org/type/merge.html
version: 1.0.0

x-center: &CENTER
x: 1
y: 2

x-left: &LEFT
x: 0
y: 2

x-big: &BIG
r: 10

x-small: &SMALL
r: 1

x-one:
<<: *CENTER
r: 10
label: center/big
x-two:
<<: [*CENTER, *BIG]
label: center/big
x-three:
<<: [*BIG, *LEFT, *SMALL]
x: 1
label: center/big

paths: {}
72 changes: 72 additions & 0 deletions src/__tests__/parseWithPointers.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import { HugeYAML } from './fixtures/huge-yaml';

const diverse = fs.readFileSync(path.join(__dirname, './fixtures/diverse.yaml'), 'utf-8');
const duplicateMergeKeys = fs.readFileSync(path.join(__dirname, './fixtures/duplicate-merge-keys.yaml'), 'utf-8');
const mergeKeysWithDuplicateProperties = fs.readFileSync(
path.join(__dirname, './fixtures/merge-keys-with-duplicate-props.yaml'),
'utf-8'
);
const spectral481 = fs.readFileSync(path.join(__dirname, './fixtures/spectral-481.yaml'), 'utf-8');

describe('yaml parser', () => {
Expand Down Expand Up @@ -428,6 +432,56 @@ european-cities: &cities
});
});

test('handles overrides #2', () => {
const result = parseWithPointers(mergeKeysWithDuplicateProperties, {
mergeKeys: true,
ignoreDuplicateKeys: false,
});

expect(result.data).toEqual({
openapi: '3.0.0',
'x-format-version': '1.0',
info: {
description: 'https://yaml.org/type/merge.html',
title: 'Merge key issue',
version: '1.0.0',
},
'x-center': {
x: 1,
y: 2,
},
'x-left': {
x: 0,
y: 2,
},
'x-big': {
r: 10,
},
'x-small': {
r: 1,
},
'x-one': {
x: 1,
y: 2,
r: 10,
label: 'center/big',
},
'x-two': {
x: 1,
y: 2,
r: 10,
label: 'center/big',
},
'x-three': {
x: 1,
y: 2,
r: 10,
label: 'center/big',
},
paths: {},
});
});

test('handles duplicate merge keys', () => {
const result = parseWithPointers(duplicateMergeKeys, { mergeKeys: true });

Expand All @@ -440,5 +494,23 @@ european-cities: &cities
t: 4,
});
});

test('does not report duplicate merge keys', () => {
const result = parseWithPointers(duplicateMergeKeys, {
mergeKeys: true,
ignoreDuplicateKeys: false,
});

expect(result.diagnostics).toEqual([]);
});

test('does not report duplicate errors for merged keys', () => {
const result = parseWithPointers(mergeKeysWithDuplicateProperties, {
mergeKeys: true,
ignoreDuplicateKeys: false,
});

expect(result.diagnostics).toEqual([]);
});
});
});
43 changes: 43 additions & 0 deletions src/__tests__/safeStringify.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { safeStringify } from '../safeStringify';

describe('safeStringify', () => {
it('should work', () => {
const val = { foo: true };

expect(safeStringify(val)).toEqual(`foo: true
`);
expect(safeStringify('foo: true')).toEqual('foo: true');
});

it('should respect lineWidth for multi-line strings', () => {
const description = `# API information
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.
Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?`;

expect(safeStringify({ description }, { lineWidth: 200 })).toEqual(`description: >-
# API information

Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta
sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.

Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut
enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse
quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
`);
});

it('should use literal block-scalar style if lineWidth is Infinity (or very lengthy)', () => {
const description = `# API information
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.
Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?`.trim();

const val = { description };

expect(safeStringify(val, { lineWidth: Infinity })).toEqual(`description: |-
${description
.split('\n')
.map(part => ` ${part}`)
.join('\n')}
`);
});
});
15 changes: 0 additions & 15 deletions src/__tests__/safeStringify.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/buildJsonPath.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { JsonPath } from '@stoplight/types';
import { Kind, YAMLMapping, YAMLNode, YAMLScalar, YAMLSequence } from 'yaml-ast-parser';
import { Kind, YAMLMapping, YAMLNode, YAMLScalar, YAMLSequence } from '@stoplight/yaml-ast-parser';
import { isObject } from './utils';

export function buildJsonPath(node: YAMLNode) {
Expand Down
2 changes: 1 addition & 1 deletion src/getJsonPathForPosition.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { GetJsonPathForPosition } from '@stoplight/types';
import { Kind, YAMLMapping, YAMLNode, YAMLSequence } from 'yaml-ast-parser';
import { Kind, YAMLMapping, YAMLNode, YAMLSequence } from '@stoplight/yaml-ast-parser';
import { buildJsonPath } from './buildJsonPath';
import { YamlParserResult } from './types';
import { isObject } from './utils';
Expand Down
2 changes: 1 addition & 1 deletion src/getLocationForJsonPath.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { GetLocationForJsonPath, ILocation, JsonPath } from '@stoplight/types';
import { Kind, YAMLMapping, YAMLNode, YAMLSequence } from 'yaml-ast-parser';
import { Kind, YAMLMapping, YAMLNode, YAMLSequence } from '@stoplight/yaml-ast-parser';
import { SpecialMappingKeys } from './consts';
import { lineForPosition } from './lineForPosition';
import { YamlParserResult } from './types';
Expand Down
2 changes: 1 addition & 1 deletion src/parse.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { load as loadAST } from 'yaml-ast-parser';
import { load as loadAST } from '@stoplight/yaml-ast-parser';
import { walkAST } from './parseWithPointers';

export const parse = <T>(value: string): T => walkAST(loadAST(value)) as T;
29 changes: 19 additions & 10 deletions src/parseWithPointers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
YAMLNode,
YAMLScalar,
YAMLSequence,
} from 'yaml-ast-parser';
} from '@stoplight/yaml-ast-parser';
import { buildJsonPath } from './buildJsonPath';
import { SpecialMappingKeys } from './consts';
import { lineForPosition } from './lineForPosition';
Expand Down Expand Up @@ -73,20 +73,29 @@ export const walkAST = (
case Kind.MAP: {
const container = {};
// note, we don't handle null aka '~' keys on purpose
for (const mapping of (node as YamlMap).mappings) {
// typing is broken, value might be null
if (mapping.key.value in container) {
if (options !== void 0 && options.json === false) {
throw new Error('Duplicate YAML mapping key encountered');
}
const seenKeys: string[] = [];
const handleMergeKeys = options !== void 0 && options.mergeKeys === true;
const handleDuplicates = (options !== void 0 && options.json === false) || duplicatedMappingKeys !== void 0;

if (duplicatedMappingKeys !== void 0) {
duplicatedMappingKeys.push(mapping.key);
for (const mapping of (node as YamlMap).mappings) {
const key = mapping.key.value;

if (handleDuplicates && (!handleMergeKeys || key !== SpecialMappingKeys.MergeKey)) {
if (seenKeys.includes(mapping.key.value)) {
if (options !== void 0 && options.json === false) {
throw new Error('Duplicate YAML mapping key encountered');
}

if (duplicatedMappingKeys !== void 0) {
duplicatedMappingKeys.push(mapping.key);
}
} else {
seenKeys.push(key);
}
}

// https://yaml.org/type/merge.html merge keys, not a part of YAML spec
if (options !== void 0 && options.mergeKeys === true && mapping.key.value === SpecialMappingKeys.MergeKey) {
if (handleMergeKeys && key === SpecialMappingKeys.MergeKey) {
Object.assign(container, reduceMergeKeys(walkAST(mapping.value, options, duplicatedMappingKeys)));
} else {
container[mapping.key.value] = walkAST(mapping.value, options, duplicatedMappingKeys);
Expand Down
3 changes: 1 addition & 2 deletions src/safeStringify.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { DumpOptions } from 'js-yaml';
import { safeDump } from 'yaml-ast-parser';
import { DumpOptions, safeDump } from '@stoplight/yaml-ast-parser';

export const safeStringify = (value: any, options?: DumpOptions): string => {
if (!value || typeof value === 'string') return value;
Expand Down
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { IParserResult } from '@stoplight/types';
import { LoadOptions, YAMLNode } from 'yaml-ast-parser';
import { LoadOptions, YAMLNode } from '@stoplight/yaml-ast-parser';

export interface IParseOptions extends LoadOptions {
json?: boolean; // if true, properties can be overridden, otherwise throws
Expand Down
23 changes: 9 additions & 14 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1575,13 +1575,18 @@
typedoc "0.13.x"
typescript-plugin-styled-components "1.0.x"

"@stoplight/types@^11.0.0":
version "11.0.0"
resolved "https://registry.yarnpkg.com/@stoplight/types/-/types-11.0.0.tgz#fd234cfcb1a1cee28ef9642735d9206e009a8fa6"
integrity sha512-Tt8doUE2E5HACigjBHyBpMHS+Td+9tBmGvf4giDH9jK7mS6Q7dyLOeE2QSKyMrslmzd1mRuKBvPhS18g9EEjog==
"@stoplight/types@^11.1.0":
version "11.1.0"
resolved "https://registry.yarnpkg.com/@stoplight/types/-/types-11.1.0.tgz#b29ecd8c8ad27bb564c7820c99f93c27f1d11bf1"
integrity sha512-z4VqnYIDTcj9R0f8AIDitBWkiAKKJ4W/Z5GJz/3fnBZBa/TD9Oak0xHbicXFXUvqTVCv/7D32PjPYiUX6W/EfQ==
dependencies:
"@types/json-schema" "^7.0.3"

"@stoplight/[email protected]":
version "0.0.43"
resolved "https://registry.yarnpkg.com/@stoplight/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz#c39cf86e98e48d73c483be96622b2b622cc56b0c"
integrity sha512-3buZXhav0Uc4pD7QWCTfysDTW0syyf1Nj/F73fgAfhO9+Fd6Q6IVB0k1ApcHFQgIPTHQAq9Lu8+ngvlGIjG6ZQ==

"@storybook/[email protected]":
version "4.0.11"
resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-4.0.11.tgz#4a329172baa8dc75a79af1dab72ed57ca2993440"
Expand Down Expand Up @@ -1977,11 +1982,6 @@
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-23.3.10.tgz#4897974cc317bf99d4fe6af1efa15957fa9c94de"
integrity sha512-DC8xTuW/6TYgvEg3HEXS7cu9OijFqprVDXXiOcdOKZCU/5PJNLZU37VVvmZHdtMiGOa8wAA/We+JzbdxFzQTRQ==

"@types/[email protected]":
version "3.12.1"
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.12.1.tgz#5c6f4a1eabca84792fbd916f0cb40847f123c656"
integrity sha512-SGGAhXLHDx+PK4YLNcNGa6goPf9XRWQNAUUbffkwVGGXIxmDKWyGGL4inzq2sPmExu431Ekb9aEMn9BkPqEYFA==

"@types/json-schema@^7.0.3":
version "7.0.3"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.3.tgz#bdfd69d61e464dcc81b25159c270d75a73c1a636"
Expand Down Expand Up @@ -13407,11 +13407,6 @@ yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9"
integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==

yaml-ast-parser@~0.0.43:
version "0.0.43"
resolved "https://registry.yarnpkg.com/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz#e8a23e6fb4c38076ab92995c5dca33f3d3d7c9bb"
integrity sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==

[email protected], yargs-parser@^10.0.0:
version "10.1.0"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8"
Expand Down