feat: upgrade js-yaml package (#403)

* feat: upgraded js-yaml package from v.3 to v.4 with YAML 1.2 support

* feat: removed timestamp type from YAML schema
This commit is contained in:
Yaroslav Shuhailo
2021-10-12 11:52:08 +03:00
committed by GitHub
parent 4cbd04ecae
commit 35fc48c667
25 changed files with 291 additions and 314 deletions

3
.prettierignore Normal file
View File

@@ -0,0 +1,3 @@
coverage/
packages/cli/lib/
packages/core/lib/

View File

@@ -0,0 +1,3 @@
apiDefinitions:
foo: ./foo.yaml
bar: ./bar.yaml

View File

@@ -8,9 +8,9 @@ info:
description: Information about Petstore
license:
name: MIT
url: 'https://opensource.org/licenses/MIT'
url: https://opensource.org/licenses/MIT
servers:
- url: 'http://petstore.swagger.io/v1'
- url: http://petstore.swagger.io/v1
paths:
/pets:
get:
@@ -58,7 +58,7 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Error'
'/pets/{petId}':
/pets/{petId}:
get:
summary: Info for a specific pet
operationId: showPetById
@@ -119,9 +119,9 @@ info:
description: Information about Petstore
license:
name: MIT
url: 'https://opensource.org/licenses/MIT'
url: https://opensource.org/licenses/MIT
servers:
- url: 'http://petstore.swagger.io/v1'
- url: http://petstore.swagger.io/v1
paths:
/pets:
get:
@@ -169,7 +169,7 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Error'
'/pets/{petId}':
/pets/{petId}:
get:
summary: Info for a specific pet
operationId: showPetById
@@ -230,8 +230,8 @@ foo.yaml:
❌ Validation failed with 1 error.
run \`openapi lint --generate-ignore-file\` to add all problems to the ignore file.
bundling foo.yaml...
📦 Created a bundle for foo.yaml at stdout <test>ms.
bundling ./foo.yaml...
📦 Created a bundle for ./foo.yaml at stdout <test>ms.
bar.yaml:
14:7 error spec Property \`summay\` is not expected here.
@@ -239,251 +239,7 @@ bar.yaml:
❌ Validation failed with 3 errors and 1 warning.
run \`openapi lint --generate-ignore-file\` to add all problems to the ignore file.
bundling bar.yaml...
📦 Created a bundle for bar.yaml at stdout <test>ms.
`;
exports[`E2E bundle minimum-number-error 1`] = `
openapi: 3.0.0
info:
version: 1.0.0
title: Swagger Petstore
description: Information about Petstore
license:
name: MIT
url: 'https://opensource.org/licenses/MIT'
servers:
- url: 'http://petstore.swagger.io/v1'
paths:
/pets:
get:
summary: List all pets
operationId: listPets
tags:
- pets
parameters:
- name: limit
in: query
description: How many items to return at one time (max 100)
required: false
schema:
type: integer
format: int
responses:
'200':
description: An paged array of pets
header:
x-next:
description: A link to the next page of responses
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/Pets'
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
post:
summary: Create a pet
operationId: createPets
tags:
- pets
responses:
'201':
description: Null response
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'/pets/{petId}':
get:
summary: Info for a specific pet
operationId: showPetById
tags:
- pets
parameters:
- name: petId
in: path
required: true
description: The id of the pet to retrieve
schema:
type: string
responses:
'200':
description: Expected response to a valid request
content:
application/json:
schema:
$ref: '#/components/schemas/Pets'
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
Error:
required:
- code
- message
properties:
code:
type: integer
format: int32
message:
type: string
Pet:
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
tag:
type: string
Pets:
type: array
items:
$ref: '#/components/schemas/Pet'
openapi: 3.0.0
info:
version: 1.0.0
title: Swagger Petstore
description: Information about Petstore
license:
name: MIT
url: 'https://opensource.org/licenses/MIT'
servers:
- url: 'http://petstore.swagger.io/v1'
paths:
/pets:
get:
summay: List all pets
operationIds: listPets
tags:
- pets
parameters:
- name: limit
in: query
description: How many items to return at one time (max 100)
required: false
schema:
type: integer
format: int
responses:
'200':
description: An paged array of pets
headers:
x-next:
description: A link to the next page of responses
schema:
type: string
content:
application/json:
schema:
$ref: '#/components/schemas/Pets'
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
post:
summary: Create a pet
operationId: createPets
tags:
- pets
responses:
'201':
description: Null response
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'/pets/{petId}':
get:
summary: Info for a specific pet
operationId: showPetById
tags:
- pets
parameters:
- name: petId
in: path
required: true
description: The id of the pet to retrieve
schema:
type: string
responses:
'200':
description: Expected response to a valid request
content:
application/json:
schema:
$ref: '#/components/schemas/Pets'
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
Error:
required:
- code
- message
properties:
code:
type: integer
format: int32
message:
type: string
Pet:
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
tag:
type: string
Pets:
type: array
items:
$ref: '#/components/schemas/Pet'
foo.yaml:
29:11 error spec Property \`header\` is not expected here.
❌ Validation failed with 1 error.
run \`openapi lint --generate-ignore-file\` to add all problems to the ignore file.
bundling foo.yaml...
📦 Created a bundle for foo.yaml at stdout <test>ms.
bar.yaml:
14:7 error spec Property \`summay\` is not expected here.
< ... 3 more problems hidden > increase with \`--max-problems N\`
❌ Validation failed with 3 errors and 1 warning.
run \`openapi lint --generate-ignore-file\` to add all problems to the ignore file.
bundling bar.yaml...
📦 Created a bundle for bar.yaml at stdout <test>ms.
bundling ./bar.yaml...
📦 Created a bundle for ./bar.yaml at stdout <test>ms.
`;

View File

@@ -0,0 +1,2 @@
apiDefinitions:
main: ./openapi.yaml

View File

@@ -0,0 +1,38 @@
openapi: 3.1.0
servers:
- url: https://api.example.com/v1
info:
title: Title
license:
name: Apache 2.0
url: https://www.apache.org/licenses/LICENSE-2.0.html
description: Description
version: 1.0.0
paths:
/my_post:
post:
operationId: my_post
summary: my_post
requestBody:
content:
application/json:
examples:
primitive types:
value:
emptyValue:
multiString: multi string without quotes
spaces in keys: 'spaces in keys'
numberString: '0123456789'
number: 1000
decimal: 12.34
numberWithLeadingZero: 0127
boolean: true
date: 2020-01-01
array:
- 1
- 2
object:
key1: 1
key2: 2

View File

@@ -0,0 +1,47 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`E2E bundle primitive-types 1`] = `
openapi: 3.1.0
servers:
- url: https://api.example.com/v1
info:
title: Title
license:
name: Apache 2.0
url: https://www.apache.org/licenses/LICENSE-2.0.html
description: Description
version: 1.0.0
paths:
/my_post:
post:
operationId: my_post
summary: my_post
requestBody:
content:
application/json:
examples:
primitive types:
value:
emptyValue: null
multiString: multi string without quotes
spaces in keys: spaces in keys
numberString: '0123456789'
number: 1000
decimal: 12.34
numberWithLeadingZero: 127
boolean: true
date: 2020-01-01
array:
- 1
- 2
object:
key1: 1
key2: 2
components: {}
Woohoo! Your OpenAPI definitions are valid. 🎉
bundling ./openapi.yaml...
📦 Created a bundle for ./openapi.yaml at stdout <test>ms.
`;

View File

@@ -1,8 +1,9 @@
import { readdirSync, statSync, existsSync } from 'fs';
import { readdirSync, statSync, existsSync, readFileSync } from 'fs';
import { spawnSync } from 'child_process';
import { join } from 'path';
//@ts-ignore
import { toMatchSpecificSnapshot, addSerializer } from './specific-snapshot';
import { parseYaml } from '../packages/core/src/utils'; // not able to import from @redocly/openapi-core
expect.extend({
toMatchExtendedSpecificSnapshot(received, snapshotFile) {
@@ -16,7 +17,6 @@ addSerializer({
});
describe('E2E', () => {
describe('lint', () => {
const folderPath = join(__dirname, 'lint');
const contents = readdirSync(folderPath);
@@ -53,9 +53,13 @@ describe('E2E', () => {
describe('join', () => {
const folderPath = join(__dirname, 'join');
const contents = readdirSync(folderPath);
for (const file of contents) {
const testPath = join(folderPath, file);
if (statSync(testPath).isFile()) continue;
if (statSync(testPath).isFile()) {
continue;
}
const args = [
'--transpile-only',
@@ -64,6 +68,7 @@ describe('E2E', () => {
'foo.yaml',
'bar.yaml'
];
it(file, () => {
const r = spawnSync('ts-node', args, {
cwd: testPath,
@@ -87,18 +92,26 @@ describe('E2E', () => {
describe('bundle', () => {
const folderPath = join(__dirname, 'bundle');
const contents = readdirSync(folderPath);
for (const file of contents) {
const testPath = join(folderPath, file);
if (statSync(testPath).isFile()) continue;
if (statSync(testPath).isFile()) {
continue;
}
const redoclyYamlFile = readFileSync(join(testPath, '.redocly.yaml'), 'utf8');
const redoclyYaml = parseYaml(redoclyYamlFile) as { apiDefinitions: Record<string, string> };
const entryPoints = Object.keys(redoclyYaml.apiDefinitions);
const args = [
'../../../packages/cli/src/index.ts',
'--lint',
'--max-problems=1',
'bundle',
'foo.yaml',
'bar.yaml'
...entryPoints
];
it(file, () => {
const r = spawnSync('ts-node', args, {
cwd: testPath,
@@ -118,5 +131,4 @@ describe('E2E', () => {
});
}
})
});

View File

@@ -9,9 +9,9 @@ info:
description: Test description from md file
license:
name: MIT
url: 'https://opensource.org/licenses/MIT'
url: https://opensource.org/licenses/MIT
servers:
- url: 'https://redocly.com/v1'
- url: https://redocly.com/v1
paths:
/pets:
get:
@@ -30,7 +30,7 @@ paths:
description: example description
tags:
- foo_other
'/pets/{petId}':
/pets/{petId}:
post:
summary: summary example
operationId: exampleBar

View File

@@ -9,9 +9,9 @@ info:
description: Information about API
license:
name: MIT
url: 'https://opensource.org/licenses/MIT'
url: https://opensource.org/licenses/MIT
servers:
- url: 'https://redocly.com/v1'
- url: https://redocly.com/v1
paths:
/pets:
get:
@@ -30,7 +30,7 @@ paths:
description: example description
tags:
- foo_other
'/pets/{petId}':
/pets/{petId}:
post:
summary: summary example
operationId: exampleBar

67
package-lock.json generated
View File

@@ -1064,9 +1064,9 @@
"dev": true
},
"node_modules/@types/js-yaml": {
"version": "3.12.7",
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-3.12.7.tgz",
"integrity": "sha512-S6+8JAYTE1qdsc9HMVsfY7+SgSuUU/Tp6TYTmITW0PZxiyIMvol3Gy//y69Wkhs0ti4py5qgR3uZH6uz/DNzJQ==",
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.3.tgz",
"integrity": "sha512-5t9BhoORasuF5uCPr+d5/hdB++zRFUTMIZOzbNkr+jZh3yQht4HYbRDyj9fY8n2TZT30iW9huzav73x4NikqWg==",
"dev": true
},
"node_modules/@types/json-schema": {
@@ -1496,6 +1496,7 @@
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"dev": true,
"dependencies": {
"sprintf-js": "~1.0.2"
}
@@ -3011,6 +3012,7 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true,
"bin": {
"esparse": "bin/esparse.js",
"esvalidate": "bin/esvalidate.js"
@@ -5384,6 +5386,7 @@
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
"dev": true,
"dependencies": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
@@ -7863,7 +7866,8 @@
"node_modules/sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
"dev": true
},
"node_modules/ssri": {
"version": "6.0.2",
@@ -10058,7 +10062,6 @@
"glob": "^7.1.6",
"glob-promise": "^3.4.0",
"handlebars": "^4.7.6",
"js-yaml": "^3.14.1",
"portfinder": "^1.0.26",
"simple-websocket": "^9.0.0",
"yargs": "17.0.1"
@@ -10083,7 +10086,7 @@
"@types/node": "^14.11.8",
"colorette": "^1.2.0",
"js-levenshtein": "^1.1.6",
"js-yaml": "^3.14.1",
"js-yaml": "^4.1.0",
"lodash.isequal": "^4.5.0",
"minimatch": "^3.0.4",
"node-fetch": "^2.6.1",
@@ -10091,7 +10094,7 @@
},
"devDependencies": {
"@types/js-levenshtein": "^1.1.0",
"@types/js-yaml": "^3.12.4",
"@types/js-yaml": "^4.0.3",
"@types/lodash.isequal": "^4.5.5",
"@types/minimatch": "^3.0.3",
"@types/node-fetch": "^2.5.7",
@@ -10100,6 +10103,22 @@
"engines": {
"node": ">=12.0.0"
}
},
"packages/core/node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
"packages/core/node_modules/js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dependencies": {
"argparse": "^2.0.1"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
}
},
"dependencies": {
@@ -10821,7 +10840,6 @@
"glob": "^7.1.6",
"glob-promise": "^3.4.0",
"handlebars": "^4.7.6",
"js-yaml": "^3.14.1",
"portfinder": "^1.0.26",
"simple-websocket": "^9.0.0",
"typescript": "^4.0.3",
@@ -10833,19 +10851,34 @@
"requires": {
"@redocly/ajv": "^8.6.2",
"@types/js-levenshtein": "^1.1.0",
"@types/js-yaml": "^3.12.4",
"@types/js-yaml": "^4.0.3",
"@types/lodash.isequal": "^4.5.5",
"@types/minimatch": "^3.0.3",
"@types/node": "^14.11.8",
"@types/node-fetch": "^2.5.7",
"colorette": "^1.2.0",
"js-levenshtein": "^1.1.6",
"js-yaml": "^3.14.1",
"js-yaml": "^4.1.0",
"lodash.isequal": "^4.5.0",
"minimatch": "^3.0.4",
"node-fetch": "^2.6.1",
"typescript": "^4.0.5",
"yaml-ast-parser": "0.0.43"
},
"dependencies": {
"argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
"js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"requires": {
"argparse": "^2.0.1"
}
}
}
},
"@sinonjs/commons": {
@@ -10972,9 +11005,9 @@
"dev": true
},
"@types/js-yaml": {
"version": "3.12.7",
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-3.12.7.tgz",
"integrity": "sha512-S6+8JAYTE1qdsc9HMVsfY7+SgSuUU/Tp6TYTmITW0PZxiyIMvol3Gy//y69Wkhs0ti4py5qgR3uZH6uz/DNzJQ==",
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.3.tgz",
"integrity": "sha512-5t9BhoORasuF5uCPr+d5/hdB++zRFUTMIZOzbNkr+jZh3yQht4HYbRDyj9fY8n2TZT30iW9huzav73x4NikqWg==",
"dev": true
},
"@types/json-schema": {
@@ -11364,6 +11397,7 @@
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"dev": true,
"requires": {
"sprintf-js": "~1.0.2"
}
@@ -12628,7 +12662,8 @@
"esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true
},
"esrecurse": {
"version": "4.3.0",
@@ -14504,6 +14539,7 @@
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
"dev": true,
"requires": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
@@ -16508,7 +16544,8 @@
"sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
"dev": true
},
"ssri": {
"version": "6.0.2",

View File

@@ -37,7 +37,6 @@
"@redocly/openapi-core": "^1.0.0-beta.62",
"@types/node": "^14.11.8",
"assert-node-version": "^1.0.3",
"js-yaml": "^3.14.1",
"chokidar": "^3.5.1",
"colorette": "^1.2.0",
"glob": "^7.1.6",

View File

@@ -1,9 +1,10 @@
import { red, blue, yellow, green } from 'colorette';
import * as fs from 'fs';
import * as yaml from 'js-yaml';
import { parseYaml } from '@redocly/openapi-core';
import * as path from 'path';
import { performance } from 'perf_hooks';
const isEqual = require('lodash.isequal');
import { printExecutionTime, pathToFilename, readYaml, writeYaml, exitWithError } from '../../utils';
import { isString, isObject, isEmptyObject } from '../../js-utils';
import {
@@ -71,7 +72,7 @@ function isNotYaml(filename: string) {
function loadFile(fileName: string) {
try {
return yaml.safeLoad(fs.readFileSync(fileName, 'utf8')) as Definition;
return parseYaml(fs.readFileSync(fileName, 'utf8')) as Definition;
} catch (e) {
return exitWithError(e.message);
}

View File

@@ -2,7 +2,6 @@ import { basename, dirname, extname, join, resolve } from 'path';
import { blue, gray, green, red, yellow } from 'colorette';
import { performance } from "perf_hooks";
import * as glob from 'glob-promise';
import * as yaml from 'js-yaml';
import * as fs from 'fs';
import * as path from 'path';
import * as readline from 'readline';
@@ -13,6 +12,8 @@ import {
LintConfig,
ResolveError,
YamlParseError,
parseYaml,
stringifyYaml
} from '@redocly/openapi-core';
import { Totals, outputExtensions } from './types';
@@ -87,7 +88,7 @@ export function dumpBundle(obj: any, format: BundleOutputFormat, dereference?: b
throw e;
}
} else {
return yaml.safeDump(obj, {
return stringifyYaml(obj, {
noRefs: !dereference,
});
}
@@ -131,11 +132,11 @@ export async function promptUser(query: string, hideUserInput = false): Promise<
}
export function readYaml(filename: string) {
return yaml.safeLoad(fs.readFileSync(filename, 'utf-8'), { filename });
return parseYaml(fs.readFileSync(filename, 'utf-8'), { filename });
}
export function writeYaml(data: any, filename: string, noRefs = false) {
const content = yaml.safeDump(data, { noRefs });
const content = stringifyYaml(data, { noRefs });
if (process.env.NODE_ENV === 'test') {
process.stderr.write(content);

View File

@@ -192,7 +192,7 @@ describe('collect refs', () => {
expect(resolvedRefs).toBeDefined();
expect(Array.from(resolvedRefs.keys()).map((ref) => ref.substring(cwd.length + 1)))
expect(Array.from(resolvedRefs.keys()).map((ref) => ref.substring(cwd.length + 1)).sort())
.toMatchInlineSnapshot(`
Array [
"openapi-with-back.yaml::./schemas/type-a.yaml#/",
@@ -201,7 +201,15 @@ describe('collect refs', () => {
]
`);
expect(Array.from(resolvedRefs.values()).map((val) => val.node)).toMatchInlineSnapshot(`
expect(
Array.from(resolvedRefs.values())
.map((val) => val.node)
.sort((firstEl, secondEl) => {
const getKey = (el: any): string => el?.allOf?.type || el?.type || '';
return getKey(firstEl).localeCompare(getKey(secondEl));
})
).toMatchInlineSnapshot(`
Array [
Object {
"allOf": Array [

View File

@@ -1,15 +1,13 @@
import * as yaml from 'js-yaml';
import * as path from 'path';
import { Document, Source } from '../src/resolve';
import { NormalizedProblem } from '../src/walk';
import { Document, Source, NormalizedProblem, parseYaml, stringifyYaml } from '../src';
import { RuleConfig, LintConfig, Plugin } from '../src/config/config';
import { Oas3RuleSet } from '../src/oas-types';
export function parseYamlToDocument(body: string, absoluteRef: string = ''): Document {
return {
source: new Source(absoluteRef, body),
parsed: yaml.safeLoad(body, { filename: absoluteRef }),
parsed: parseYaml(body, { filename: absoluteRef }),
};
}
@@ -41,7 +39,7 @@ export const yamlSerializer = {
return true;
},
print: (val: any) => {
return yaml.safeDump(val);
return stringifyYaml(val);
},
};

View File

@@ -34,7 +34,7 @@
"@types/node": "^14.11.8",
"colorette": "^1.2.0",
"js-levenshtein": "^1.1.6",
"js-yaml": "^3.14.1",
"js-yaml": "^4.1.0",
"lodash.isequal": "^4.5.0",
"minimatch": "^3.0.4",
"node-fetch": "^2.6.1",
@@ -42,7 +42,7 @@
},
"devDependencies": {
"@types/js-levenshtein": "^1.1.0",
"@types/js-yaml": "^3.12.4",
"@types/js-yaml": "^4.0.3",
"@types/lodash.isequal": "^4.5.5",
"@types/minimatch": "^3.0.3",
"@types/node-fetch": "^2.5.7",

View File

@@ -0,0 +1,47 @@
import { parseYaml, stringifyYaml } from '../js-yaml';
const yaml = `
emptyValue:
spaces in keys: spaces in keys
numberString: '0123456789'
number: 1000
decimal: 12.34
boolean: true
date: 2020-01-01
array:
- 1
- 2
object:
key1: 1
key2: 2
`;
const jsObject = {
emptyValue: null,
'spaces in keys': 'spaces in keys',
numberString: '0123456789',
number: 1000,
decimal: 12.34,
boolean: true,
date: '2020-01-01',
array: [1, 2],
object: { key1: 1, key2: 2 },
};
describe('js-yaml', () => {
test('parseYaml', () => {
expect(parseYaml(yaml)).toEqual(jsObject);
});
test('parse and stringify', () => {
expect(parseYaml(stringifyYaml(jsObject))).toEqual(jsObject);
});
test('should throw an error for unsupported types', () => {
expect(() => stringifyYaml({ date: new Date() }))
.toThrow('unacceptable kind of an object to dump [object Date]');
expect(() => stringifyYaml({ foo: () => {} }))
.toThrow('unacceptable kind of an object to dump [object Function]');
});
});

View File

@@ -1,4 +1,4 @@
import * as yaml from 'js-yaml';
import { parseYaml } from '../js-yaml';
import { Document, Source } from '../resolve';
import { Oas3RuleSet } from '../oas-types';
import { RuleConfig, LintConfig, Plugin } from '../config/config';
@@ -6,7 +6,7 @@ import { RuleConfig, LintConfig, Plugin } from '../config/config';
export function parseYamlToDocument(body: string, absoluteRef: string = ''): Document {
return {
source: new Source(absoluteRef, body),
parsed: yaml.safeLoad(body, { filename: absoluteRef }),
parsed: parseYaml(body, { filename: absoluteRef }),
};
}

View File

@@ -1,9 +1,9 @@
import * as fs from 'fs';
import * as path from 'path';
import * as yaml from 'js-yaml';
import { dirname } from 'path';
import { red, blue } from 'colorette';
import { parseYaml, stringifyYaml } from '../js-yaml';
import { notUndefined } from '../utils';
import {
@@ -190,7 +190,7 @@ export class LintConfig {
if (fs.hasOwnProperty('existsSync') && fs.existsSync(ignoreFile)) {
// TODO: parse errors
this.ignore =
(yaml.safeLoad(fs.readFileSync(ignoreFile, 'utf-8')) as Record<
(parseYaml(fs.readFileSync(ignoreFile, 'utf-8')) as Record<
string,
Record<string, Set<string>>
>) || {};
@@ -216,7 +216,7 @@ export class LintConfig {
ignoredRules[ruleId] = Array.from(ignoredRules[ruleId]) as any;
}
}
fs.writeFileSync(ignoreFile, IGNORE_BANNER + yaml.safeDump(mapped));
fs.writeFileSync(ignoreFile, IGNORE_BANNER + stringifyYaml(mapped));
}
addIgnore(problem: NormalizedProblem) {
@@ -384,6 +384,7 @@ export class Config {
apiDefinitions: Record<string, string>;
lint: LintConfig;
resolve: ResolveConfig;
licenseKey?: string;
constructor(public rawConfig: RawConfig, public configFile?: string) {
this.apiDefinitions = rawConfig.apiDefinitions || {};
this.lint = new LintConfig(rawConfig.lint || {}, configFile);

View File

@@ -29,9 +29,11 @@ export {
YamlParseError,
makeDocumentFromString,
} from './resolve';
export { parseYaml, stringifyYaml } from './js-yaml';
export { unescapePointer } from './ref-utils';
export { detectOpenAPI, OasMajorVersion, openAPIMajor, OasVersion } from './oas-types';
export { normalizeVisitors } from './visitors';
export {
WalkContext,
walkDocument,

View File

@@ -0,0 +1,19 @@
// TODO: add a type for "types" https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/js-yaml/index.d.ts
// @ts-ignore
import { JSON_SCHEMA, types, LoadOptions, DumpOptions, load, dump } from 'js-yaml';
const DEFAULT_SCHEMA_WITHOUT_TIMESTAMP = JSON_SCHEMA.extend({
implicit: [types.merge],
explicit: [
types.binary,
types.omap,
types.pairs,
types.set,
],
});
export const parseYaml = (str: string, opts?: LoadOptions): unknown =>
load(str, {schema: DEFAULT_SCHEMA_WITHOUT_TIMESTAMP, ...opts});
export const stringifyYaml = (obj: any, opts?: DumpOptions): string =>
dump(obj, {schema: DEFAULT_SCHEMA_WITHOUT_TIMESTAMP, ...opts});

View File

@@ -1,12 +1,12 @@
import * as fs from 'fs';
import * as path from 'path';
import * as url from 'url';
import * as yaml from 'js-yaml';
import { OasRef } from './typings/openapi';
import { isRef, joinPointer, escapePointer, parseRef, isAbsoluteUrl } from './ref-utils';
import type { YAMLNode, LoadOptions } from 'yaml-ast-parser';
import { NormalizedNodeType, isNamedType } from './types';
import { readFileFromUrl } from './utils';
import { readFileFromUrl, parseYaml } from './utils';
import { ResolveConfig } from './config/config';
export type CollectedRefs = Map<string /* absoluteFilePath */, Document>;
@@ -52,7 +52,7 @@ export class ResolveError extends Error {
}
}
const jsYamlErrorLineColRegexp = /at line (\d+), column (\d+):/;
const jsYamlErrorLineColRegexp = /\((\d+):(\d+)\)$/;
export class YamlParseError extends Error {
col: number;
@@ -79,7 +79,7 @@ export function makeDocumentFromString(sourceString: string, absoluteRef: string
try {
return {
source,
parsed: yaml.safeLoad(sourceString, { filename: absoluteRef }),
parsed: parseYaml(sourceString, { filename: absoluteRef }),
};
} catch (e) {
throw new YamlParseError(e, source);
@@ -133,7 +133,7 @@ export class BaseResolver {
try {
return {
source,
parsed: yaml.safeLoad(source.body, { filename: source.absoluteRef }),
parsed: parseYaml(source.body, { filename: source.absoluteRef }),
};
} catch (e) {
throw new YamlParseError(e, source);

View File

@@ -83,7 +83,7 @@ describe('oas3 boolean-parameter-prefixes', () => {
},
},
],
"message": "Failed to parse: unexpected end of the stream within a single quoted scalar in \\"fixtures/invalid-yaml.yaml\\" at line 2, column 1:",
"message": "Failed to parse: unexpected end of the stream within a single quoted scalar in \\"fixtures/invalid-yaml.yaml\\" (2:1)",
"ruleId": "no-unresolved-refs",
"severity": "error",
"suggest": Array [],
@@ -96,7 +96,7 @@ describe('oas3 boolean-parameter-prefixes', () => {
"source": "foobar.yaml",
},
],
"message": "Can't resolve $ref: unexpected end of the stream within a single quoted scalar in \\"fixtures/invalid-yaml.yaml\\" at line 2, column 1:",
"message": "Can't resolve $ref: unexpected end of the stream within a single quoted scalar in \\"fixtures/invalid-yaml.yaml\\" (2:1)",
"ruleId": "no-unresolved-refs",
"severity": "error",
"suggest": Array [],

View File

@@ -1,5 +1,4 @@
import { Referenced } from './openapi';
//@ts-ignore
import { Schema } from 'js-yaml';
export interface Oas2Definition {

View File

@@ -1,9 +1,12 @@
import * as yaml from 'js-yaml';
import * as fs from 'fs';
import * as minimatch from 'minimatch';
import fetch from 'node-fetch';
import { parseYaml } from './js-yaml';
import { HttpResolveConfig } from './config/config';
export { parseYaml, stringifyYaml } from './js-yaml';
export type StackFrame<T> = {
prev: StackFrame<T> | null;
value: T;
@@ -23,7 +26,8 @@ export type BundleOutputFormat = 'json' | 'yml' | 'yaml';
export async function loadYaml(filename: string) {
const contents = await fs.promises.readFile(filename, 'utf-8');
return yaml.safeLoad(contents);
return parseYaml(contents);
}
export function notUndefined<T>(x: T | undefined): x is T {
@@ -60,4 +64,4 @@ export function match(url: string, pattern: string) {
url = url.replace(/^https?:\/\//, '');
}
return minimatch(url, pattern);
}
}