Skip to content

Commit 4853238

Browse files
committed
strings
1 parent 54ff075 commit 4853238

7 files changed

+219
-11
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`handles nested arrays with inlineArrayLimit 1`] = `
4+
"{
5+
matrix: [[1, 2], [3, 4]]
6+
}"
7+
`;
8+
9+
exports[`serializes arrays with newlines when length exceeds the inlineArrayLimit with space set 1`] = `
10+
"{
11+
numbers: [
12+
1,
13+
2,
14+
3,
15+
4,
16+
5
17+
]
18+
}"
19+
`;
20+
21+
exports[`serializes arrays without newlines when length equals the inlineArrayLimit 1`] = `
22+
"{
23+
numbers: [1, 2, 3, 4, 5]
24+
}"
25+
`;
26+
27+
exports[`serializes arrays without newlines when length exceeds the inlineArrayLimit 1`] = `"{numbers: [1, 2, 3, 4, 5]}"`;
28+
29+
exports[`serializes arrays without newlines when length is below the inlineArrayLimit 1`] = `"{numbers: [1, 2, 3]}"`;

__tests__/__snapshots__/stringify.test.ts.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ exports[`serializes objects with keys starting with $ correctly 1`] = `"{$id: 1,
5151
5252
exports[`serializes simple objects without quotes on keys where possible 1`] = `"{id: 1, name: 'Alice', isActive: true}"`;
5353
54-
exports[`switches to backticks when single quotes are in the string 1`] = `"{message: \`It's a wonderful day!\`}"`;
54+
exports[`switches to backticks when single quotes are in the string 1`] = `"{message: 'It\\'s a wonderful day!'}"`;
5555
5656
exports[`uses double quotes when backticks and single quotes are present 1`] = `"{quote: "\`This\` is 'awesome'!"}"`;
5757
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
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.'}"`;

__tests__/array-newlines.test.ts

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { jsStringify } from '../src';
2+
3+
it('serializes arrays without newlines when length is below the inlineArrayLimit', () => {
4+
const obj = {
5+
numbers: [1, 2, 3]
6+
};
7+
const options = {
8+
inlineArrayLimit: 3
9+
};
10+
const output = jsStringify(obj, options);
11+
expect(output).toMatchSnapshot();
12+
});
13+
14+
it('serializes arrays without newlines when length exceeds the inlineArrayLimit', () => {
15+
const obj = {
16+
numbers: [1, 2, 3, 4, 5]
17+
};
18+
const options = {
19+
inlineArrayLimit: 3
20+
};
21+
const output = jsStringify(obj, options);
22+
expect(output).toMatchSnapshot();
23+
});
24+
it('serializes arrays with newlines when length exceeds the inlineArrayLimit with space set', () => {
25+
const obj = {
26+
numbers: [1, 2, 3, 4, 5]
27+
};
28+
const options = {
29+
inlineArrayLimit: 3,
30+
space: 2
31+
};
32+
const output = jsStringify(obj, options);
33+
expect(output).toMatchSnapshot();
34+
});
35+
36+
it('serializes arrays without newlines when length equals the inlineArrayLimit', () => {
37+
const obj = {
38+
numbers: [1, 2, 3, 4, 5]
39+
};
40+
const options = {
41+
inlineArrayLimit: 5,
42+
space: 2
43+
};
44+
const output = jsStringify(obj, options);
45+
expect(output).toMatchSnapshot();
46+
});
47+
48+
it('handles nested arrays with inlineArrayLimit', () => {
49+
const obj = {
50+
matrix: [
51+
[1, 2],
52+
[3, 4]
53+
]
54+
};
55+
const options = {
56+
inlineArrayLimit: 2, // Applies to inner arrays
57+
space: 2
58+
};
59+
const output = jsStringify(obj, options);
60+
expect(output).toMatchSnapshot();
61+
});

__tests__/strings.test.ts

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { jsStringify, chooseQuotes } from '../src';
2+
3+
it('handles strings with newlines and other special chars', () => {
4+
const obj = {
5+
"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.",
6+
"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."
7+
};
8+
const options = {};
9+
const output = jsStringify(obj, options);
10+
expect(output).toMatchSnapshot();
11+
});
12+
13+
describe('chooseQuotes', () => {
14+
test('handles strings with no special characters using single quotes', () => {
15+
const str = "Hello world";
16+
expect(chooseQuotes(str, 'single')).toBe("'Hello world'");
17+
});
18+
19+
test('handles strings with no special characters using double quotes', () => {
20+
const str = "Hello world";
21+
expect(chooseQuotes(str, 'double')).toBe('"Hello world"');
22+
});
23+
24+
test('handles strings with no special characters using backticks', () => {
25+
const str = "Hello world";
26+
expect(chooseQuotes(str, 'backtick')).toBe('`Hello world`');
27+
});
28+
29+
test('handles strings with single quotes', () => {
30+
const str = "It's a sunny day";
31+
expect(chooseQuotes(str, 'single')).toBe("'It\\'s a sunny day'");
32+
expect(chooseQuotes(str, 'double')).toBe('"It\'s a sunny day"');
33+
expect(chooseQuotes(str, 'backtick')).toBe('`It\'s a sunny day`');
34+
});
35+
36+
test('handles strings with double quotes', () => {
37+
const str = 'She said, "Hello"';
38+
expect(chooseQuotes(str, 'single')).toBe("'She said, \"Hello\"'");
39+
expect(chooseQuotes(str, 'double')).toBe('"She said, \\"Hello\\""');
40+
expect(chooseQuotes(str, 'backtick')).toBe('`She said, "Hello"`');
41+
});
42+
43+
test('handles strings with backticks', () => {
44+
const str = '`Hello` world';
45+
expect(chooseQuotes(str, 'single')).toBe("'`Hello` world'");
46+
expect(chooseQuotes(str, 'double')).toBe('"`Hello` world"');
47+
expect(chooseQuotes(str, 'backtick')).toBe('`\\`Hello\\` world`');
48+
});
49+
50+
test('handles strings with single and double quotes', () => {
51+
const str = "It's a \"wonderful\" day";
52+
expect(chooseQuotes(str, 'single')).toBe("'It\\'s a \"wonderful\" day'");
53+
expect(chooseQuotes(str, 'double')).toBe('"It\'s a \\"wonderful\\" day"');
54+
expect(chooseQuotes(str, 'backtick')).toBe('`It\'s a "wonderful" day`');
55+
});
56+
57+
test('handles strings with single quotes and backticks', () => {
58+
const str = "It's `great`";
59+
expect(chooseQuotes(str, 'single')).toBe("'It\\'s `great`'");
60+
expect(chooseQuotes(str, 'double')).toBe('"It\'s `great`"');
61+
expect(chooseQuotes(str, 'backtick')).toBe('`It\'s \\`great\\``');
62+
});
63+
64+
test('handles strings with double quotes and backticks', () => {
65+
const str = "`Hello`, he said, \"Good morning!\"";
66+
expect(chooseQuotes(str, 'single')).toBe("'`Hello`, he said, \"Good morning!\"'");
67+
expect(chooseQuotes(str, 'double')).toBe('"`Hello`, he said, \\"Good morning!\\""');
68+
expect(chooseQuotes(str, 'backtick')).toBe('`\\`Hello\\`, he said, "Good morning!"`');
69+
});
70+
71+
test('handles strings with all types of quotes', () => {
72+
const str = "It's `really` a \"wonderful\" day";
73+
expect(chooseQuotes(str, 'single')).toBe("'It\\'s `really` a \"wonderful\" day'");
74+
expect(chooseQuotes(str, 'double')).toBe('"It\'s `really` a \\"wonderful\\" day"');
75+
expect(chooseQuotes(str, 'backtick')).toBe('`It\'s \\`really\\` a "wonderful" day`');
76+
});
77+
});

src/index.ts

+47-10
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,54 @@ function isSimpleKey(key: string): boolean {
99
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key);
1010
}
1111

12-
function chooseQuotes(str: string, preferred: 'single' | 'double'): string {
13-
if (preferred === 'single') {
14-
if (!str.includes('\'')) return `'${str}'`;
15-
else if (!str.includes('`')) return `\`${str}\``;
16-
else if (!str.includes('"')) return `"${str}"`;
17-
} else {
18-
if (!str.includes('"')) return `"${str}"`;
19-
else if (!str.includes('`')) return `\`${str}\``;
20-
else if (!str.includes('\'')) return `'${str}'`;
12+
function escapeStringForSingleQuotes(str: string): string {
13+
// Escape backslashes first
14+
str = str.replace(/\\/g, '\\\\');
15+
// Escape control characters
16+
str = str.replace(/\n/g, '\\n');
17+
str = str.replace(/\r/g, '\\r');
18+
str = str.replace(/\t/g, '\\t');
19+
// Escape only single quotes
20+
str = str.replace(/'/g, "\\'");
21+
return str;
22+
}
23+
24+
function escapeStringForDoubleQuotes(str: string): string {
25+
// Escape backslashes first
26+
str = str.replace(/\\/g, '\\\\');
27+
// Escape control characters
28+
str = str.replace(/\n/g, '\\n');
29+
str = str.replace(/\r/g, '\\r');
30+
str = str.replace(/\t/g, '\\t');
31+
// Escape only double quotes
32+
str = str.replace(/"/g, '\\"');
33+
return str;
34+
}
35+
36+
37+
function escapeStringForBacktickQuotes(str: string): string {
38+
// Escape backslashes first
39+
str = str.replace(/\\/g, '\\\\');
40+
// Escape control characters
41+
str = str.replace(/\n/g, '\\n');
42+
str = str.replace(/\r/g, '\\r');
43+
str = str.replace(/\t/g, '\\t');
44+
// Escape backticks
45+
str = str.replace(/`/g, '\\`');
46+
return str;
47+
}
48+
49+
export function chooseQuotes(str: string, preferred: 'single' | 'double' | 'backtick'): string {
50+
switch (preferred) {
51+
case 'single':
52+
return `'${escapeStringForSingleQuotes(str)}'`;
53+
case 'double':
54+
return `"${escapeStringForDoubleQuotes(str)}"`;
55+
case 'backtick':
56+
return `\`${escapeStringForBacktickQuotes(str)}\``;
57+
default:
58+
throw new Error("Invalid quote type specified.");
2159
}
22-
return JSON.stringify(str); // Fallback: use JSON.stringify to escape the string properly
2360
}
2461

2562
export function jsStringify(obj: any, options?: StringifyOptions): string {

types/index.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ interface StringifyOptions {
22
space?: number;
33
replacer?: (this: any, key: string, value: any) => any | null;
44
quotes?: 'single' | 'double';
5+
inlineArrayLimit?: number;
56
}
67
export declare function jsStringify(obj: any, options?: StringifyOptions): string;
78
export {};

0 commit comments

Comments
 (0)