@stoplight/json
Advanced tools
Comparing version 1.6.0 to 1.7.0
@@ -1,1 +0,2 @@ | ||
export declare const encodePointerFragment: (value: string) => string; | ||
import { Segment } from '@stoplight/types/parsers'; | ||
export declare const encodePointerFragment: (value: Segment) => Segment; |
@@ -5,4 +5,4 @@ "use strict"; | ||
exports.encodePointerFragment = (value) => { | ||
return _utils_1.replaceInString(_utils_1.replaceInString(value, '~', '~0'), '/', '~1'); | ||
return typeof value === 'number' ? value : _utils_1.replaceInString(_utils_1.replaceInString(value, '~', '~0'), '/', '~1'); | ||
}; | ||
//# sourceMappingURL=encodePointerFragment.js.map |
{ | ||
"name": "@stoplight/json", | ||
"version": "1.6.0", | ||
"version": "1.7.0", | ||
"description": "Useful functions when working with JSON.", | ||
@@ -28,4 +28,4 @@ "keywords": [ | ||
"@stoplight/fast-safe-stringify": "2.1.2", | ||
"@stoplight/types": "3.x.x", | ||
"jsonc-parser": "2.0.3", | ||
"@stoplight/types": "4.0.x", | ||
"jsonc-parser": "https://github.com/stoplightio/node-jsonc-parser.git#f45703496d842937ec822683550067dfe68d898e", | ||
"lodash": "4.x.x" | ||
@@ -32,0 +32,0 @@ }, |
@@ -1,2 +0,6 @@ | ||
import { SourceMapParser } from '@stoplight/types/parsers'; | ||
export declare const parseWithPointers: SourceMapParser; | ||
import { IDiagnostic } from '@stoplight/types/diagnostics'; | ||
import { IParserASTResult, IParserResult } from '@stoplight/types/parsers'; | ||
import { Node, ParseOptions } from 'jsonc-parser'; | ||
import { IJsonASTNode } from './types'; | ||
export declare const parseWithPointers: <T = any>(value: string, options?: ParseOptions) => IParserResult<T, IJsonASTNode, Map<number, number>>; | ||
export declare function parseTree<T>(text: string, errors: IDiagnostic[] | undefined, options: ParseOptions): IParserASTResult<T, Node, Map<number, number>>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const validations_1 = require("@stoplight/types/validations"); | ||
const diagnostics_1 = require("@stoplight/types/diagnostics"); | ||
const jsonc_parser_1 = require("jsonc-parser"); | ||
const encodePointerFragment_1 = require("./encodePointerFragment"); | ||
exports.parseWithPointers = (value) => { | ||
const parsed = { | ||
data: {}, | ||
pointers: {}, | ||
validations: [], | ||
exports.parseWithPointers = (value, options = { disallowComments: true }) => { | ||
const diagnostics = []; | ||
const { ast, data, lineMap } = parseTree(value, diagnostics, options); | ||
return { | ||
data, | ||
diagnostics, | ||
ast, | ||
lineMap, | ||
}; | ||
if (!value || !value.trim().length) | ||
return parsed; | ||
const validations = []; | ||
return Object.assign({}, parse(value, validations, { | ||
disallowComments: true, | ||
}), { validations }); | ||
}; | ||
function toPointer(fragments) { | ||
return ['', ...fragments.filter(item => item !== '')].join('/'); | ||
} | ||
function parse(text, errors = [], options) { | ||
let currentProperty = null; | ||
let currentParent = []; | ||
let currentLineNumber = 1; | ||
const offsets = []; | ||
const previousParents = []; | ||
const previousPointers = []; | ||
const pointers = { | ||
'': { | ||
start: { | ||
line: 1, | ||
}, | ||
end: { | ||
line: 0, | ||
}, | ||
}, | ||
}; | ||
function onValue(value) { | ||
if (Array.isArray(currentParent)) { | ||
const index = currentParent.push(value) - 1; | ||
if (previousParents.length > 0) { | ||
pointers[toPointer([...previousPointers.slice(0, previousPointers.length - 1), index])] = { | ||
start: { | ||
line: currentLineNumber, | ||
}, | ||
end: { | ||
line: typeof value !== 'object' ? currentLineNumber : 0, | ||
}, | ||
}; | ||
} | ||
function parseTree(text, errors = [], options) { | ||
const lineMap = new Map([[0, 0]]); | ||
let currentLineNumber = 0; | ||
let currentOffset = 0; | ||
let lastErrorEndOffset = -1; | ||
let currentParent = { type: 'array', offset: -1, length: -1, children: [], parent: void 0 }; | ||
let currentParsedProperty = null; | ||
let currentParsedParent = []; | ||
const previousParsedParents = []; | ||
function ensurePropertyComplete(endOffset) { | ||
if (currentParent.type === 'property') { | ||
currentParent.length = endOffset - currentParent.offset; | ||
currentParent = currentParent.parent; | ||
} | ||
else if (currentProperty) { | ||
currentParent[currentProperty] = value; | ||
pointers[toPointer(previousPointers)] = { | ||
start: { | ||
line: currentLineNumber, | ||
}, | ||
end: { | ||
line: typeof value !== 'object' ? currentLineNumber : 0, | ||
}, | ||
}; | ||
} | ||
} | ||
function onComplexValueEnd(value) { | ||
const previousPointersCopy = [...previousPointers]; | ||
if (value === currentParent) { | ||
previousPointersCopy.pop(); | ||
function calculateRange(offset, length) { | ||
const startColumn = offset - currentOffset; | ||
return { | ||
startColumn, | ||
startLine: currentLineNumber, | ||
endColumn: startColumn + length, | ||
endLine: currentLineNumber, | ||
}; | ||
} | ||
function onValue(valueNode) { | ||
currentParent.children.push(valueNode); | ||
return valueNode; | ||
} | ||
function onParsedValue(value) { | ||
if (Array.isArray(currentParsedParent)) { | ||
currentParsedParent.push(value); | ||
} | ||
const pointer = pointers[toPointer(previousPointersCopy)]; | ||
if (pointer && pointer.end.line === 0) { | ||
pointer.end.line = currentLineNumber; | ||
else if (currentParsedProperty) { | ||
currentParsedParent[currentParsedProperty] = value; | ||
} | ||
} | ||
function onParsedComplexBegin(value) { | ||
onParsedValue(value); | ||
previousParsedParents.push(currentParsedParent); | ||
currentParsedParent = value; | ||
currentParsedProperty = null; | ||
} | ||
function onParsedComplexEnd() { | ||
currentParsedParent = previousParsedParents.pop(); | ||
} | ||
const visitor = { | ||
onObjectBegin: () => { | ||
const object = {}; | ||
onValue(object); | ||
if (Array.isArray(currentParent) && previousPointers.length > 0) { | ||
if (previousPointers[previousPointers.length - 1] === '') { | ||
previousPointers[previousPointers.length - 1] = 0; | ||
} | ||
else { | ||
previousPointers[previousPointers.length - 1] = Number(previousPointers[previousPointers.length - 1]) + 1; | ||
} | ||
} | ||
previousPointers.push(''); | ||
previousParents.push(currentParent); | ||
currentParent = object; | ||
currentProperty = null; | ||
onObjectBegin: (offset) => { | ||
currentParent = onValue(Object.assign({ type: 'object', offset, length: -1, parent: currentParent, children: [] }, calculateRange(offset - 1, -1))); | ||
onParsedComplexBegin({}); | ||
}, | ||
onObjectProperty: (name) => { | ||
currentProperty = name; | ||
previousPointers[previousPointers.length - 1] = encodePointerFragment_1.encodePointerFragment(name); | ||
onObjectProperty: (name, offset, length) => { | ||
currentParent = onValue({ type: 'property', offset, length: -1, parent: currentParent, children: [] }); | ||
currentParent.children.push({ type: 'string', value: name, offset, length, parent: currentParent }); | ||
currentParsedProperty = name; | ||
}, | ||
onObjectEnd: () => { | ||
onComplexValueEnd(currentParent); | ||
previousPointers.pop(); | ||
currentParent = previousParents.pop(); | ||
onObjectEnd: (offset, length) => { | ||
currentParent.length = offset + length - currentParent.offset; | ||
currentParent.endColumn = offset - currentOffset; | ||
currentParent.endLine = currentLineNumber; | ||
currentParent = currentParent.parent; | ||
ensurePropertyComplete(offset + length); | ||
onParsedComplexEnd(); | ||
}, | ||
onArrayBegin: () => { | ||
const array = []; | ||
onValue(array); | ||
previousPointers.push(''); | ||
previousParents.push(currentParent); | ||
currentParent = array; | ||
currentProperty = null; | ||
onArrayBegin: (offset, length) => { | ||
currentParent = onValue(Object.assign({ type: 'array', offset, length: -1, parent: currentParent, children: [] }, calculateRange(offset - 1, -1))); | ||
onParsedComplexBegin([]); | ||
}, | ||
onArrayEnd: () => { | ||
onComplexValueEnd(currentParent); | ||
previousPointers.pop(); | ||
currentParent = previousParents.pop(); | ||
onArrayEnd: (offset, length) => { | ||
currentParent.length = offset + length - currentParent.offset; | ||
currentParent.endColumn = offset - currentOffset; | ||
currentParent.endLine = currentLineNumber; | ||
currentParent = currentParent.parent; | ||
ensurePropertyComplete(offset + length); | ||
onParsedComplexEnd(); | ||
}, | ||
onLiteralValue: onValue, | ||
onLiteralValue: (value, offset, length) => { | ||
onValue(Object.assign({ type: getLiteralNodeType(value), offset, | ||
length, parent: currentParent, value }, calculateRange(offset, length))); | ||
ensurePropertyComplete(offset + length); | ||
onParsedValue(value); | ||
}, | ||
onSeparator: (sep, offset, length) => { | ||
if (currentParent.type === 'property') { | ||
if (sep === ':') { | ||
currentParent.colonOffset = offset; | ||
} | ||
else if (sep === ',') { | ||
ensurePropertyComplete(offset); | ||
} | ||
} | ||
}, | ||
onError: (error, offset, length) => { | ||
const startColumn = offset - offsets[currentLineNumber - 2]; | ||
const range = calculateRange(offset, length); | ||
lastErrorEndOffset = offset + length; | ||
errors.push({ | ||
errorCode: error, | ||
name: jsonc_parser_1.printParseErrorCode(error), | ||
severity: validations_1.ValidationSeverity.Error, | ||
severityLabel: validations_1.ValidationSeverityLabel.Error, | ||
location: { | ||
range: { | ||
start: { | ||
line: currentLineNumber, | ||
column: startColumn, | ||
character: range.startColumn, | ||
line: range.startLine, | ||
}, | ||
end: { | ||
line: currentLineNumber, | ||
column: startColumn + length, | ||
character: range.endColumn, | ||
line: range.startLine, | ||
}, | ||
}, | ||
offset, | ||
length, | ||
message: jsonc_parser_1.printParseErrorCode(error), | ||
severity: diagnostics_1.DiagnosticSeverity.Error, | ||
code: error, | ||
}); | ||
}, | ||
onNewLine(lineNumber, offset, length) { | ||
onLineBreak: (lineNumber, offset) => { | ||
lineMap.set(lineNumber, offset); | ||
currentLineNumber = lineNumber; | ||
offsets.push(offset); | ||
currentOffset = offset; | ||
if (lastErrorEndOffset !== -1 && offset > lastErrorEndOffset) { | ||
errors[errors.length - 1].range.end.line = lineNumber - 1; | ||
errors[errors.length - 1].range.end.character = offset - lastErrorEndOffset; | ||
lastErrorEndOffset = -1; | ||
} | ||
}, | ||
}; | ||
visit(text, visitor, options); | ||
jsonc_parser_1.visit(text, visitor, options); | ||
const result = currentParent.children[0]; | ||
if (result) { | ||
delete result.parent; | ||
} | ||
return { | ||
pointers, | ||
data: currentParent[0], | ||
ast: result, | ||
data: currentParsedParent[0], | ||
lineMap, | ||
}; | ||
} | ||
function visit(text, visitor, options) { | ||
const _scanner = jsonc_parser_1.createScanner(text, false); | ||
let lineNumber = 1; | ||
function toNoArgVisit(visitFunction) { | ||
return visitFunction ? () => visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength()) : () => true; | ||
exports.parseTree = parseTree; | ||
function getLiteralNodeType(value) { | ||
switch (typeof value) { | ||
case 'boolean': | ||
return 'boolean'; | ||
case 'number': | ||
return 'number'; | ||
case 'string': | ||
return 'string'; | ||
default: | ||
return 'null'; | ||
} | ||
function toOneArgVisit(visitFunction) { | ||
return visitFunction | ||
? (arg) => visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength()) | ||
: () => true; | ||
} | ||
const onObjectBegin = toNoArgVisit(visitor.onObjectBegin); | ||
const onObjectProperty = toOneArgVisit(visitor.onObjectProperty); | ||
const onObjectEnd = toNoArgVisit(visitor.onObjectEnd); | ||
const onArrayBegin = toNoArgVisit(visitor.onArrayBegin); | ||
const onArrayEnd = toNoArgVisit(visitor.onArrayEnd); | ||
const onLiteralValue = toOneArgVisit(visitor.onLiteralValue); | ||
const onSeparator = toOneArgVisit(visitor.onSeparator); | ||
const onComment = toNoArgVisit(visitor.onComment); | ||
const onError = toOneArgVisit(visitor.onError); | ||
const onNewLine = toOneArgVisit(visitor.onNewLine); | ||
const disallowComments = options && options.disallowComments; | ||
const allowTrailingComma = options && options.allowTrailingComma; | ||
function scanNext() { | ||
while (true) { | ||
const token = _scanner.scan(); | ||
switch (_scanner.getTokenError()) { | ||
case 4: | ||
handleError(14); | ||
break; | ||
case 5: | ||
handleError(15); | ||
break; | ||
case 3: | ||
handleError(13); | ||
break; | ||
case 1: | ||
if (!disallowComments) { | ||
handleError(11); | ||
} | ||
break; | ||
case 2: | ||
handleError(12); | ||
break; | ||
case 6: | ||
handleError(16); | ||
break; | ||
} | ||
switch (token) { | ||
case 12: | ||
case 13: | ||
if (disallowComments) { | ||
handleError(10); | ||
} | ||
else { | ||
onComment(); | ||
} | ||
break; | ||
case 16: | ||
handleError(1); | ||
break; | ||
case 15: | ||
break; | ||
case 14: | ||
onNewLine(++lineNumber); | ||
break; | ||
default: | ||
return token; | ||
} | ||
} | ||
} | ||
function handleError(error, skipUntilAfter = [], skipUntil = []) { | ||
onError(error); | ||
if (skipUntilAfter.length + skipUntil.length > 0) { | ||
let token = _scanner.getToken(); | ||
while (token !== 17) { | ||
if (skipUntilAfter.indexOf(token) !== -1) { | ||
scanNext(); | ||
break; | ||
} | ||
else if (skipUntil.indexOf(token) !== -1) { | ||
break; | ||
} | ||
token = scanNext(); | ||
} | ||
} | ||
} | ||
function parseString(isValue) { | ||
const value = _scanner.getTokenValue(); | ||
if (isValue) { | ||
onLiteralValue(value); | ||
} | ||
else { | ||
onObjectProperty(value); | ||
} | ||
scanNext(); | ||
return true; | ||
} | ||
function parseLiteral() { | ||
switch (_scanner.getToken()) { | ||
case 11: | ||
let value = 0; | ||
try { | ||
value = JSON.parse(_scanner.getTokenValue()); | ||
if (typeof value !== 'number') { | ||
handleError(2); | ||
value = 0; | ||
} | ||
} | ||
catch (e) { | ||
handleError(2); | ||
} | ||
onLiteralValue(value); | ||
break; | ||
case 7: | ||
onLiteralValue(null); | ||
break; | ||
case 8: | ||
onLiteralValue(true); | ||
break; | ||
case 9: | ||
onLiteralValue(false); | ||
break; | ||
default: | ||
return false; | ||
} | ||
scanNext(); | ||
return true; | ||
} | ||
function parseProperty() { | ||
if (_scanner.getToken() !== 10) { | ||
handleError(3, [], [2, 5]); | ||
return false; | ||
} | ||
parseString(false); | ||
if (_scanner.getToken() === 6) { | ||
onSeparator(':'); | ||
scanNext(); | ||
if (!parseValue()) { | ||
handleError(4, [], [2, 5]); | ||
} | ||
} | ||
else { | ||
handleError(5, [], [2, 5]); | ||
} | ||
return true; | ||
} | ||
function parseObject() { | ||
onObjectBegin(); | ||
scanNext(); | ||
let needsComma = false; | ||
while (_scanner.getToken() !== 2 && _scanner.getToken() !== 17) { | ||
if (_scanner.getToken() === 5) { | ||
if (!needsComma) { | ||
handleError(4, [], []); | ||
} | ||
onSeparator(','); | ||
scanNext(); | ||
if (_scanner.getToken() === 2 && allowTrailingComma) { | ||
break; | ||
} | ||
} | ||
else if (needsComma) { | ||
handleError(6, [], []); | ||
} | ||
if (!parseProperty()) { | ||
handleError(4, [], [2, 5]); | ||
} | ||
needsComma = true; | ||
} | ||
onObjectEnd(); | ||
if (_scanner.getToken() !== 2) { | ||
handleError(7, [2], []); | ||
} | ||
else { | ||
scanNext(); | ||
} | ||
return true; | ||
} | ||
function parseArray() { | ||
onArrayBegin(); | ||
scanNext(); | ||
let needsComma = false; | ||
while (_scanner.getToken() !== 4 && _scanner.getToken() !== 17) { | ||
if (_scanner.getToken() === 5) { | ||
if (!needsComma) { | ||
handleError(4, [], []); | ||
} | ||
onSeparator(','); | ||
scanNext(); | ||
if (_scanner.getToken() === 4 && allowTrailingComma) { | ||
break; | ||
} | ||
} | ||
else if (needsComma) { | ||
handleError(6, [], []); | ||
} | ||
if (!parseValue()) { | ||
handleError(4, [], [4, 5]); | ||
} | ||
needsComma = true; | ||
} | ||
onArrayEnd(); | ||
if (_scanner.getToken() !== 4) { | ||
handleError(8, [4], []); | ||
} | ||
else { | ||
scanNext(); | ||
} | ||
return true; | ||
} | ||
function parseValue() { | ||
switch (_scanner.getToken()) { | ||
case 3: | ||
return parseArray(); | ||
case 1: | ||
return parseObject(); | ||
case 10: | ||
return parseString(true); | ||
default: | ||
return parseLiteral(); | ||
} | ||
} | ||
scanNext(); | ||
if (_scanner.getToken() === 17) { | ||
return true; | ||
} | ||
if (!parseValue()) { | ||
handleError(4, [], []); | ||
return false; | ||
} | ||
if (_scanner.getToken() !== 17) { | ||
handleError(9, [], []); | ||
} | ||
return true; | ||
} | ||
//# sourceMappingURL=parseWithPointers.js.map |
@@ -1,1 +0,1 @@ | ||
export declare const pathToPointer: (path: string[]) => string; | ||
export declare const pathToPointer: (path: import("@stoplight/types").Segment[]) => string; |
@@ -1,1 +0,1 @@ | ||
export declare const pointerToPath: (pointer: string) => string[]; | ||
export declare const pointerToPath: (pointer: string) => import("@stoplight/types/parsers").Segment[]; |
@@ -21,3 +21,3 @@ "use strict"; | ||
if (ptr.length === 0 || ptr[0] !== '#') { | ||
throw new URIError('Invalid JSON Pointer syntax; URI fragment idetifiers must begin with a hash.'); | ||
throw new URIError('Invalid JSON Pointer syntax; URI fragment identifiers must begin with a hash.'); | ||
} | ||
@@ -24,0 +24,0 @@ if (ptr.length === 1) { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
HTTP dependency
Supply chain riskContains a dependency which resolves to a remote HTTP URL which could be used to inject untrusted code and reduce overall package reliability.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
63
49413
498
1
1
+ Added@stoplight/types@4.0.0(transitive)
- Removed@stoplight/types@3.1.0(transitive)
- Removedjsonc-parser@2.0.3(transitive)
Updated@stoplight/types@4.0.x