Skip to content

Commit

Permalink
feat: preserve style for all utils
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 committed Apr 17, 2024
1 parent 5feec57 commit d4665b4
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 43 deletions.
10 changes: 5 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
export { parseJSON5 } from "./json5";
export { parseJSON5, stringifyJSON5 } from "./json5";
export type { JSON5ParseOptions, JSON5StringifyOptions } from "./json5";

export { parseJSONC } from "./jsonc";
export { parseJSONC, stringifyJSONC } from "./jsonc";
export type { JSONCParseError, JSONCParseOptions } from "./jsonc";

export { parseYAML, stringifyYAML } from "./yaml";
export type { parseYAMLOptions, stringifyYAMLOptions } from "./yaml";

export { parseTOML, stringifyTOML } from "./toml";
export type { YAMLParseOptions, YAMLStringifyOptions } from "./yaml";

export { parseJSON, stringifyJSON } from "./json";
export type { JSONParseOptions, JSONStringifyOptions } from "./json";

export { parseTOML, stringifyTOML } from "./toml";
31 changes: 24 additions & 7 deletions src/json5.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { getFormat, storeFormat, type FormatOptions } from "./_format";
import parse from "json5/lib/parse.js";
import stringify from "json5/lib/stringify";

// Source: https://github.com/json5/json5

Expand All @@ -14,12 +16,30 @@ export function parseJSON5<T = unknown>(
text: string,
options?: JSON5ParseOptions,
): T {
return parse(text, options?.reviver) as T;
const obj = parse(text, options?.reviver);
storeFormat(text, obj, options);
return obj as T;
}

/**
* Converts a JavaScript value to a [JSON5](https://json5.org/) string.
*
* @param value
* @param options
* @returns The JSON string converted from the JavaScript value.
*/
export function stringifyJSON5(
value: any,
options?: JSON5StringifyOptions,
): string {
const format = getFormat(value, options);
const str = stringify(value, options?.replacer, format.indent);
return format.whitespace.start + str + format.whitespace.end;
}

// --- Types ---

export interface JSON5ParseOptions {
export interface JSON5ParseOptions extends FormatOptions {
/**
* A function that alters the behavior of the parsing process, or an array of
* String and Number objects that serve as a allowlist for selecting/filtering
Expand All @@ -30,18 +50,15 @@ export interface JSON5ParseOptions {
reviver?: (this: any, key: string, value: any) => any;
}

export interface JSON5StringifyOptions {
export interface JSON5StringifyOptions extends FormatOptions {
/**
* A function that alters the behavior of the stringification process, or an
* array of String and Number objects that serve as a allowlist for
* selecting/filtering the properties of the value object to be included in
* the JSON5 string. If this value is null or not provided, all properties
* of the object are included in the resulting JSON5 string.
*/
replacer?:
| ((this: any, key: string, value: any) => any)
| (string | number)[]
| null;
replacer?: ((this: any, key: string, value: any) => any) | null;

/**
* A String or Number object that's used to insert white space into the
Expand Down
29 changes: 26 additions & 3 deletions src/jsonc.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { storeFormat, type FormatOptions } from "./_format";
import { parse } from "jsonc-parser";
import { stringifyJSON } from "./json";

// Source: https://github.com/microsoft/node-jsonc-parser

Expand All @@ -7,7 +9,8 @@ import { parse } from "jsonc-parser";
* Converts a [JSONC](https://github.com/microsoft/node-jsonc-parser) string into an object.
*
* @NOTE On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.
* Therefore, always check the errors list to find out if the input was valid.
*
* @NOTE Comments and trailing commas are not preserved after parsing.
*
* @template T The type of the return value.
* @param text The string to parse as JSONC.
Expand All @@ -18,18 +21,38 @@ export function parseJSONC<T = unknown>(
text: string,
options?: JSONCParseOptions,
): T {
return parse(text, options?.errors, options) as T;
const obj = parse(text, options?.errors, options);
storeFormat(text, obj, options);
return obj as T;
}

/**
* Converts a JavaScript value to a [JSONC](https://github.com/microsoft/node-jsonc-parser) string.
*
* @NOTE Comments and trailing commas are not preserved in the output.
*
* @param value
* @param options
* @returns The JSON string converted from the JavaScript value.
*/
export function stringifyJSONC(
value: any,
options?: JSONCStringifyOptions,
): string {
return stringifyJSON(value, options);
}

// --- Types ---

export interface JSONCParseOptions {
export interface JSONCParseOptions extends FormatOptions {
disallowComments?: boolean;
allowTrailingComma?: boolean;
allowEmptyContent?: boolean;
errors?: JSONCParseError[];
}

export interface JSONCStringifyOptions extends FormatOptions {}

export interface JSONCParseError {
error: number;
offset: number;
Expand Down
12 changes: 10 additions & 2 deletions src/toml.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,34 @@
import { getFormat, storeFormat } from "./_format";
import { parse, stringify } from "smol-toml";

// Source: https://github.com/squirrelchat/smol-toml

/**
* Converts a [TOML](https://toml.io/) string into an object.
*
* @NOTE Comments and indentation is not preserved after parsing.
*
* @template T The type of the return value.
* @param text The TOML string to parse.
* @returns The JavaScript value converted from the TOML string.
*/
export function parseTOML<T = unknown>(text: string): T {
return parse(text) as T;
const obj = parse(text);
storeFormat(text, obj, { preserveIndentation: false });
return obj as T;
}

/**
* Converts a JavaScript value to a [TOML](https://toml.io/) string.
*
* @NOTE Comments and indentation is not preserved in the output.
*
* @param value
* @param options
* @returns The YAML string converted from the JavaScript value.
*/
export function stringifyTOML(value: any): string {
return stringify(value);
const format = getFormat(value, { preserveIndentation: false });
const str = stringify(value);
return format.whitespace.start + str + format.whitespace.end;
}
26 changes: 20 additions & 6 deletions src/yaml.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { load, dump } from "js-yaml";
import { type FormatOptions, getFormat, storeFormat } from "./_format";

// Source: https://github.com/nodeca/js-yaml
// Types: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/js-yaml/index.d.ts
Expand All @@ -8,6 +9,8 @@ import { load, dump } from "js-yaml";
*
* @NOTE This function does **not** understand multi-document sources, it throws exception on those.
*
* @NOTE Comments are not preserved after parsing.
*
* @NOTE This function does **not** support schema-specific tag resolution restrictions.
* So, the JSON schema is not as strictly defined in the YAML specification.
* It allows numbers in any notation, use `Null` and `NULL` as `null`, etc.
Expand All @@ -20,28 +23,39 @@ import { load, dump } from "js-yaml";
*/
export function parseYAML<T = unknown>(
text: string,
options?: parseYAMLOptions,
options?: YAMLParseOptions,
): T {
return load(text, options) as T;
const obj = load(text, options);
storeFormat(text, obj, options);
return obj as T;
}

/**
* Converts a JavaScript value to a [YAML](https://yaml.org/) string.
*
* @NOTE Comments are not preserved in the output.
*
* @param value
* @param options
* @returns The YAML string converted from the JavaScript value.
*/
export function stringifyYAML(
value: any,
options?: stringifyYAMLOptions,
options?: YAMLStringifyOptions,
): string {
return dump(value, options);
const format = getFormat(value, { preserveIndentation: false });
const indentSize =
typeof format.indent === "string" ? format.indent.length : format.indent;
const str = dump(value, {
indent: indentSize,
...options,
});
return format.whitespace.start + str.trim() + format.whitespace.end;
}

// --- Types ---

export interface parseYAMLOptions {
export interface YAMLParseOptions extends FormatOptions {
/** string to be used as a file path in error/warning messages. */
filename?: string | undefined;
/** function to call on warning messages. */
Expand All @@ -54,7 +68,7 @@ export interface parseYAMLOptions {
listener?(this: any, eventType: any, state: any): void;
}

export interface stringifyYAMLOptions {
export interface YAMLStringifyOptions extends FormatOptions {
/** indentation width to use (in spaces). */
indent?: number | undefined;
/** when true, will not add an indentation level to array elements */
Expand Down
22 changes: 10 additions & 12 deletions test/fixtures.mjs
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
export const yaml = /* yaml */ `
title: "Example"
title: Example
owner:
name: "Preston-Werner"
dob: 1979-05-27T07:32:00-08:00 # dates
`.trim();
name: Preston-Werner
dob: 1979-05-27T15:32:00.000Z # dates
`;

export const toml = /* toml */ `
title = "Example"
[owner]
name = "Preston-Werner"
dob = 1979-05-27T07:32:00-08:00 # dates
`.trim();
dob = 1979-05-27T07:32:00.000-08:00 # dates
`;

export const json5 = /* json5 */ `
{
title: 'Example',
owner: {
name: 'Preston-Werner',
// dates
dob: '1979-05-27T07:32:00-08:00'
}
dob: '1979-05-27T07:32:00-08:00', // dates
},
}
`.trim();
`;

export const jsonc = /* jsonc */ `
{
Expand All @@ -31,8 +30,7 @@ export const jsonc = /* jsonc */ `
"name": "Preston-Werner",
"dob": "1979-05-27T07:32:00-08:00" // dates
}
}
`.trim();
}`;

export const json = /* json */ `
Expand Down
34 changes: 26 additions & 8 deletions test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,41 +20,59 @@ const expectedObjWithDate = {

describe("confbox", () => {
describe("json5", () => {
it("parse fixture", () => {
it("parse", () => {
expect(confbox.parseJSON5(fixtures.json5)).toMatchObject(expectedObj);
});

it("stringify", () => {
expect(confbox.stringifyJSON5(confbox.parseJSON5(fixtures.json5))).toBe(
fixtures.json5.replace(/\s*\/\/.*/g, ""),
);
});
});

describe("jsonc", () => {
it("parse fixture", () => {
it("parse", () => {
expect(confbox.parseJSONC(fixtures.jsonc)).toMatchObject(expectedObj);
});

it("stringify", () => {
expect(confbox.stringifyJSONC(confbox.parseJSONC(fixtures.jsonc))).toBe(
fixtures.jsonc.replace(/\s*\/\/.*/g, ""),
);
});
});

describe("toml", () => {
it("parse fixture", () => {
it("parse", () => {
expect(confbox.parseTOML(fixtures.toml)).toMatchObject(
expectedObjWithDate,
);
});

it("stringify", () => {
expect(confbox.stringifyTOML(confbox.parseTOML(fixtures.toml))).toBe(
fixtures.toml.replace(/\s*#.*/g, ""),
);
});
});

describe("yaml", () => {
it("parse fixture", () => {
it("parse", () => {
expect(confbox.parseYAML(fixtures.yaml)).toMatchObject(
expectedObjWithDate,
);
});

it("stringify", () => {
expect(
confbox.parseYAML(confbox.stringifyYAML(expectedObjWithDate)),
).toMatchObject(expectedObjWithDate);
expect(confbox.stringifyYAML(confbox.parseYAML(fixtures.yaml))).toBe(
fixtures.yaml.replace(/\s*#.*/g, ""),
);
});
});

describe("json", () => {
it("parse fixture", () => {
it("parse", () => {
expect(confbox.parseJSON(fixtures.json)).toMatchObject(expectedObj);
});

Expand Down

0 comments on commit d4665b4

Please sign in to comment.