133 lines
5.2 KiB
JavaScript
133 lines
5.2 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.parseSyml = exports.stringifySyml = exports.PreserveOrdering = void 0;
|
|
const js_yaml_1 = require("js-yaml");
|
|
const syml_1 = require("./grammars/syml");
|
|
const simpleStringPattern = /^(?![-?:,\][{}#&*!|>'"%@` \t\r\n]).([ \t]*(?![,\][{}:# \t\r\n]).)*$/;
|
|
// The following keys will always be stored at the top of the object, in the
|
|
// specified order. It's not fair but life isn't fair either.
|
|
const specialObjectKeys = [`__metadata`, `version`, `resolution`, `dependencies`, `peerDependencies`, `dependenciesMeta`, `peerDependenciesMeta`, `binaries`];
|
|
class PreserveOrdering {
|
|
constructor(data) {
|
|
this.data = data;
|
|
}
|
|
}
|
|
exports.PreserveOrdering = PreserveOrdering;
|
|
function stringifyString(value) {
|
|
if (value.match(simpleStringPattern)) {
|
|
return value;
|
|
}
|
|
else {
|
|
return JSON.stringify(value);
|
|
}
|
|
}
|
|
function isRemovableField(value) {
|
|
if (typeof value === `undefined`)
|
|
return true;
|
|
if (typeof value === `object` && value !== null && !Array.isArray(value))
|
|
return Object.keys(value).every(key => isRemovableField(value[key]));
|
|
return false;
|
|
}
|
|
function stringifyValue(value, indentLevel, newLineIfObject) {
|
|
if (value === null)
|
|
return `null\n`;
|
|
if (typeof value === `number` || typeof value === `boolean`)
|
|
return `${value.toString()}\n`;
|
|
if (typeof value === `string`)
|
|
return `${stringifyString(value)}\n`;
|
|
if (Array.isArray(value)) {
|
|
if (value.length === 0)
|
|
return `[]\n`;
|
|
const indent = ` `.repeat(indentLevel);
|
|
const serialized = value.map(sub => {
|
|
return `${indent}- ${stringifyValue(sub, indentLevel + 1, false)}`;
|
|
}).join(``);
|
|
return `\n${serialized}`;
|
|
}
|
|
if (typeof value === `object` && value) {
|
|
const [data, sort] = value instanceof PreserveOrdering
|
|
? [value.data, false]
|
|
: [value, true];
|
|
const indent = ` `.repeat(indentLevel);
|
|
const keys = Object.keys(data);
|
|
if (sort) {
|
|
keys.sort((a, b) => {
|
|
const aIndex = specialObjectKeys.indexOf(a);
|
|
const bIndex = specialObjectKeys.indexOf(b);
|
|
if (aIndex === -1 && bIndex === -1)
|
|
return a < b ? -1 : a > b ? +1 : 0;
|
|
if (aIndex !== -1 && bIndex === -1)
|
|
return -1;
|
|
if (aIndex === -1 && bIndex !== -1)
|
|
return +1;
|
|
return aIndex - bIndex;
|
|
});
|
|
}
|
|
const fields = keys.filter(key => {
|
|
return !isRemovableField(data[key]);
|
|
}).map((key, index) => {
|
|
const value = data[key];
|
|
const stringifiedKey = stringifyString(key);
|
|
const stringifiedValue = stringifyValue(value, indentLevel + 1, true);
|
|
const recordIndentation = index > 0 || newLineIfObject
|
|
? indent
|
|
: ``;
|
|
// Yaml 1.2 spec says that keys over 1024 characters need to be prefixed with ? and the : goes in a new line
|
|
const keyPart = stringifiedKey.length > 1024
|
|
? `? ${stringifiedKey}\n${recordIndentation}:`
|
|
: `${stringifiedKey}:`;
|
|
const valuePart = stringifiedValue.startsWith(`\n`)
|
|
? stringifiedValue
|
|
: ` ${stringifiedValue}`;
|
|
return `${recordIndentation}${keyPart}${valuePart}`;
|
|
}).join(indentLevel === 0 ? `\n` : ``) || `\n`;
|
|
if (!newLineIfObject) {
|
|
return `${fields}`;
|
|
}
|
|
else {
|
|
return `\n${fields}`;
|
|
}
|
|
}
|
|
throw new Error(`Unsupported value type (${value})`);
|
|
}
|
|
function stringifySyml(value) {
|
|
try {
|
|
const stringified = stringifyValue(value, 0, false);
|
|
return stringified !== `\n` ? stringified : ``;
|
|
}
|
|
catch (error) {
|
|
if (error.location)
|
|
error.message = error.message.replace(/(\.)?$/, ` (line ${error.location.start.line}, column ${error.location.start.column})$1`);
|
|
throw error;
|
|
}
|
|
}
|
|
exports.stringifySyml = stringifySyml;
|
|
stringifySyml.PreserveOrdering = PreserveOrdering;
|
|
function parseViaPeg(source) {
|
|
if (!source.endsWith(`\n`))
|
|
source += `\n`;
|
|
return (0, syml_1.parse)(source);
|
|
}
|
|
const LEGACY_REGEXP = /^(#.*(\r?\n))*?#\s+yarn\s+lockfile\s+v1\r?\n/i;
|
|
function parseViaJsYaml(source) {
|
|
if (LEGACY_REGEXP.test(source))
|
|
return parseViaPeg(source);
|
|
const value = (0, js_yaml_1.safeLoad)(source, {
|
|
schema: js_yaml_1.FAILSAFE_SCHEMA,
|
|
json: true,
|
|
});
|
|
// Empty files are parsed as `undefined` instead of an empty object
|
|
// Empty files with 2 newlines or more are `null` instead
|
|
if (value === undefined || value === null)
|
|
return {};
|
|
if (typeof value !== `object`)
|
|
throw new Error(`Expected an indexed object, got a ${typeof value} instead. Does your file follow Yaml's rules?`);
|
|
if (Array.isArray(value))
|
|
throw new Error(`Expected an indexed object, got an array instead. Does your file follow Yaml's rules?`);
|
|
return value;
|
|
}
|
|
function parseSyml(source) {
|
|
return parseViaJsYaml(source);
|
|
}
|
|
exports.parseSyml = parseSyml;
|