Skip to content

Commit

Permalink
strings
Browse files Browse the repository at this point in the history
  • Loading branch information
pyramation committed Apr 13, 2024
1 parent 54ff075 commit 4853238
Show file tree
Hide file tree
Showing 7 changed files with 219 additions and 11 deletions.
29 changes: 29 additions & 0 deletions __tests__/__snapshots__/array-newlines.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`handles nested arrays with inlineArrayLimit 1`] = `
"{
matrix: [[1, 2], [3, 4]]
}"
`;

exports[`serializes arrays with newlines when length exceeds the inlineArrayLimit with space set 1`] = `
"{
numbers: [
1,
2,
3,
4,
5
]
}"
`;

exports[`serializes arrays without newlines when length equals the inlineArrayLimit 1`] = `
"{
numbers: [1, 2, 3, 4, 5]
}"
`;

exports[`serializes arrays without newlines when length exceeds the inlineArrayLimit 1`] = `"{numbers: [1, 2, 3, 4, 5]}"`;

exports[`serializes arrays without newlines when length is below the inlineArrayLimit 1`] = `"{numbers: [1, 2, 3]}"`;
2 changes: 1 addition & 1 deletion __tests__/__snapshots__/stringify.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ exports[`serializes objects with keys starting with $ correctly 1`] = `"{$id: 1,
exports[`serializes simple objects without quotes on keys where possible 1`] = `"{id: 1, name: 'Alice', isActive: true}"`;
exports[`switches to backticks when single quotes are in the string 1`] = `"{message: \`It's a wonderful day!\`}"`;
exports[`switches to backticks when single quotes are in the string 1`] = `"{message: 'It\\'s a wonderful day!'}"`;
exports[`uses double quotes when backticks and single quotes are present 1`] = `"{quote: "\`This\` is 'awesome'!"}"`;
Expand Down
3 changes: 3 additions & 0 deletions __tests__/__snapshots__/strings.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`handles strings with newlines and other special chars 1`] = `"{title: 'AIOZ Network is a DePIN for Web3 AI, Storage and Streaming.\\n\\nAIOZ empowers a faster, secure and decentralized future.\\n\\nPowered by a global network of DePINs, AIOZ rewards you for sharing your computational resources for storing, transcoding, and streaming digital media content and powering decentralized AI computation.', description: 'AIOZ Network is a DePIN for Web3 AI, Storage and Streaming.\\n\\t\\rAIOZ empowers a faster, secure and decentralized future.\\n\\nPowered by a global network of DePINs, AIOZ rewards you for sharing your computational resources for storing, transcoding, and streaming digital media content and powering decentralized AI computation.'}"`;
61 changes: 61 additions & 0 deletions __tests__/array-newlines.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { jsStringify } from '../src';

it('serializes arrays without newlines when length is below the inlineArrayLimit', () => {
const obj = {
numbers: [1, 2, 3]
};
const options = {
inlineArrayLimit: 3
};
const output = jsStringify(obj, options);
expect(output).toMatchSnapshot();
});

it('serializes arrays without newlines when length exceeds the inlineArrayLimit', () => {
const obj = {
numbers: [1, 2, 3, 4, 5]
};
const options = {
inlineArrayLimit: 3
};
const output = jsStringify(obj, options);
expect(output).toMatchSnapshot();
});
it('serializes arrays with newlines when length exceeds the inlineArrayLimit with space set', () => {
const obj = {
numbers: [1, 2, 3, 4, 5]
};
const options = {
inlineArrayLimit: 3,
space: 2
};
const output = jsStringify(obj, options);
expect(output).toMatchSnapshot();
});

it('serializes arrays without newlines when length equals the inlineArrayLimit', () => {
const obj = {
numbers: [1, 2, 3, 4, 5]
};
const options = {
inlineArrayLimit: 5,
space: 2
};
const output = jsStringify(obj, options);
expect(output).toMatchSnapshot();
});

it('handles nested arrays with inlineArrayLimit', () => {
const obj = {
matrix: [
[1, 2],
[3, 4]
]
};
const options = {
inlineArrayLimit: 2, // Applies to inner arrays
space: 2
};
const output = jsStringify(obj, options);
expect(output).toMatchSnapshot();
});
77 changes: 77 additions & 0 deletions __tests__/strings.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { jsStringify, chooseQuotes } from '../src';

it('handles strings with newlines and other special chars', () => {
const obj = {
"title": "AIOZ Network is a DePIN for Web3 AI, Storage and Streaming.\n\nAIOZ empowers a faster, secure and decentralized future.\n\nPowered by a global network of DePINs, AIOZ rewards you for sharing your computational resources for storing, transcoding, and streaming digital media content and powering decentralized AI computation.",
"description": "AIOZ Network is a DePIN for Web3 AI, Storage and Streaming.\n\t\rAIOZ empowers a faster, secure and decentralized future.\n\nPowered by a global network of DePINs, AIOZ rewards you for sharing your computational resources for storing, transcoding, and streaming digital media content and powering decentralized AI computation."
};
const options = {};
const output = jsStringify(obj, options);
expect(output).toMatchSnapshot();
});

describe('chooseQuotes', () => {
test('handles strings with no special characters using single quotes', () => {
const str = "Hello world";
expect(chooseQuotes(str, 'single')).toBe("'Hello world'");
});

test('handles strings with no special characters using double quotes', () => {
const str = "Hello world";
expect(chooseQuotes(str, 'double')).toBe('"Hello world"');
});

test('handles strings with no special characters using backticks', () => {
const str = "Hello world";
expect(chooseQuotes(str, 'backtick')).toBe('`Hello world`');
});

test('handles strings with single quotes', () => {
const str = "It's a sunny day";
expect(chooseQuotes(str, 'single')).toBe("'It\\'s a sunny day'");
expect(chooseQuotes(str, 'double')).toBe('"It\'s a sunny day"');
expect(chooseQuotes(str, 'backtick')).toBe('`It\'s a sunny day`');
});

test('handles strings with double quotes', () => {
const str = 'She said, "Hello"';
expect(chooseQuotes(str, 'single')).toBe("'She said, \"Hello\"'");
expect(chooseQuotes(str, 'double')).toBe('"She said, \\"Hello\\""');
expect(chooseQuotes(str, 'backtick')).toBe('`She said, "Hello"`');
});

test('handles strings with backticks', () => {
const str = '`Hello` world';
expect(chooseQuotes(str, 'single')).toBe("'`Hello` world'");
expect(chooseQuotes(str, 'double')).toBe('"`Hello` world"');
expect(chooseQuotes(str, 'backtick')).toBe('`\\`Hello\\` world`');
});

test('handles strings with single and double quotes', () => {
const str = "It's a \"wonderful\" day";
expect(chooseQuotes(str, 'single')).toBe("'It\\'s a \"wonderful\" day'");
expect(chooseQuotes(str, 'double')).toBe('"It\'s a \\"wonderful\\" day"');
expect(chooseQuotes(str, 'backtick')).toBe('`It\'s a "wonderful" day`');
});

test('handles strings with single quotes and backticks', () => {
const str = "It's `great`";
expect(chooseQuotes(str, 'single')).toBe("'It\\'s `great`'");
expect(chooseQuotes(str, 'double')).toBe('"It\'s `great`"');
expect(chooseQuotes(str, 'backtick')).toBe('`It\'s \\`great\\``');
});

test('handles strings with double quotes and backticks', () => {
const str = "`Hello`, he said, \"Good morning!\"";
expect(chooseQuotes(str, 'single')).toBe("'`Hello`, he said, \"Good morning!\"'");
expect(chooseQuotes(str, 'double')).toBe('"`Hello`, he said, \\"Good morning!\\""');
expect(chooseQuotes(str, 'backtick')).toBe('`\\`Hello\\`, he said, "Good morning!"`');
});

test('handles strings with all types of quotes', () => {
const str = "It's `really` a \"wonderful\" day";
expect(chooseQuotes(str, 'single')).toBe("'It\\'s `really` a \"wonderful\" day'");
expect(chooseQuotes(str, 'double')).toBe('"It\'s `really` a \\"wonderful\\" day"');
expect(chooseQuotes(str, 'backtick')).toBe('`It\'s \\`really\\` a "wonderful" day`');
});
});
57 changes: 47 additions & 10 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,54 @@ function isSimpleKey(key: string): boolean {
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key);
}

function chooseQuotes(str: string, preferred: 'single' | 'double'): string {
if (preferred === 'single') {
if (!str.includes('\'')) return `'${str}'`;
else if (!str.includes('`')) return `\`${str}\``;
else if (!str.includes('"')) return `"${str}"`;
} else {
if (!str.includes('"')) return `"${str}"`;
else if (!str.includes('`')) return `\`${str}\``;
else if (!str.includes('\'')) return `'${str}'`;
function escapeStringForSingleQuotes(str: string): string {
// Escape backslashes first
str = str.replace(/\\/g, '\\\\');
// Escape control characters
str = str.replace(/\n/g, '\\n');
str = str.replace(/\r/g, '\\r');
str = str.replace(/\t/g, '\\t');
// Escape only single quotes
str = str.replace(/'/g, "\\'");
return str;
}

function escapeStringForDoubleQuotes(str: string): string {
// Escape backslashes first
str = str.replace(/\\/g, '\\\\');
// Escape control characters
str = str.replace(/\n/g, '\\n');
str = str.replace(/\r/g, '\\r');
str = str.replace(/\t/g, '\\t');
// Escape only double quotes
str = str.replace(/"/g, '\\"');
return str;
}


function escapeStringForBacktickQuotes(str: string): string {
// Escape backslashes first
str = str.replace(/\\/g, '\\\\');
// Escape control characters
str = str.replace(/\n/g, '\\n');
str = str.replace(/\r/g, '\\r');
str = str.replace(/\t/g, '\\t');
// Escape backticks
str = str.replace(/`/g, '\\`');
return str;
}

export function chooseQuotes(str: string, preferred: 'single' | 'double' | 'backtick'): string {
switch (preferred) {
case 'single':
return `'${escapeStringForSingleQuotes(str)}'`;
case 'double':
return `"${escapeStringForDoubleQuotes(str)}"`;
case 'backtick':
return `\`${escapeStringForBacktickQuotes(str)}\``;
default:
throw new Error("Invalid quote type specified.");
}
return JSON.stringify(str); // Fallback: use JSON.stringify to escape the string properly
}

export function jsStringify(obj: any, options?: StringifyOptions): string {
Expand Down
1 change: 1 addition & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ interface StringifyOptions {
space?: number;
replacer?: (this: any, key: string, value: any) => any | null;
quotes?: 'single' | 'double';
inlineArrayLimit?: number;
}
export declare function jsStringify(obj: any, options?: StringifyOptions): string;
export {};

0 comments on commit 4853238

Please sign in to comment.