refactor(dotenv): move stringify() to own file (#3872)

This commit is contained in:
Asher Gomez 2023-11-29 15:34:25 +11:00 committed by GitHub
parent d52b21f673
commit cf27fa4e41
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 126 additions and 121 deletions

View File

@ -173,6 +173,7 @@
*
* @module
*/
export * from "./stringify.ts";
export interface LoadOptions {
/**
@ -448,45 +449,3 @@ function expand(str: string, variablesMap: { [key: string]: string }): string {
return str;
}
}
/**
* @example
* ```ts
* import { stringify } from "https://deno.land/std@$STD_VERSION/dotenv/mod.ts";
*
* const object = { GREETING: "hello world" };
* const string = stringify(object); // GREETING='hello world'
* ```
*
* @param object object to be stringified
* @returns string of object
*/
export function stringify(object: Record<string, string>) {
const lines: string[] = [];
for (const [key, value] of Object.entries(object)) {
let quote;
let escapedValue = value ?? "";
if (key.startsWith("#")) {
console.warn(
`key starts with a '#' indicates a comment and is ignored: '${key}'`,
);
continue;
} else if (escapedValue.includes("\n")) {
// escape inner new lines
escapedValue = escapedValue.replaceAll("\n", "\\n");
quote = `"`;
} else if (escapedValue.match(/\W/)) {
quote = "'";
}
if (quote) {
// escape inner quotes
escapedValue = escapedValue.replaceAll(quote, `\\${quote}`);
escapedValue = `${quote}${escapedValue}${quote}`;
}
const line = `${key}=${escapedValue}`;
lines.push(line);
}
return lines.join("\n");
}

View File

@ -1,6 +1,7 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
import {
assert,
assertEquals,
assertRejects,
assertStrictEquals,
@ -12,10 +13,8 @@ import {
loadSync,
MissingEnvVarsError,
parse,
stringify,
} from "./mod.ts";
import * as path from "../path/mod.ts";
import { assert } from "../assert/assert.ts";
const moduleDir = path.dirname(path.fromFileUrl(import.meta.url));
const testdataDir = path.resolve(moduleDir, "testdata");
@ -608,83 +607,6 @@ Deno.test("expand variables", () => {
);
});
Deno.test("stringify", async (t) => {
await t.step(
"basic",
() =>
assertEquals(
stringify({ "BASIC": "basic" }),
`BASIC=basic`,
),
);
await t.step(
"comment",
() =>
assertEquals(
stringify({ "#COMMENT": "comment" }),
``,
),
);
await t.step(
"single quote",
() =>
assertEquals(
stringify({ "QUOTED_SINGLE": "single quoted" }),
`QUOTED_SINGLE='single quoted'`,
),
);
await t.step(
"multiline",
() =>
assertEquals(
stringify({ "MULTILINE": "hello\nworld" }),
`MULTILINE="hello\\nworld"`,
),
);
await t.step(
"whitespace",
() =>
assertEquals(
stringify({ "WHITESPACE": " whitespace " }),
`WHITESPACE=' whitespace '`,
),
);
await t.step(
"equals",
() =>
assertEquals(
stringify({ "EQUALS": "equ==als" }),
`EQUALS='equ==als'`,
),
);
await t.step(
"number",
() =>
assertEquals(
stringify({ "THE_ANSWER": "42" }),
`THE_ANSWER=42`,
),
);
await t.step(
"undefined",
() =>
assertEquals(
stringify(
{ "UNDEFINED": undefined } as unknown as Record<string, string>,
),
`UNDEFINED=`,
),
);
await t.step(
"null",
() =>
assertEquals(
stringify({ "NULL": null } as unknown as Record<string, string>),
`NULL=`,
),
);
});
//TODO test permissions
Deno.test(

43
dotenv/stringify.ts Normal file
View File

@ -0,0 +1,43 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
/**
* @example
* ```ts
* import { stringify } from "https://deno.land/std@$STD_VERSION/dotenv/stringify.ts";
*
* const object = { GREETING: "hello world" };
* const string = stringify(object); // GREETING='hello world'
* ```
*
* @param object object to be stringified
* @returns string of object
*/
export function stringify(object: Record<string, string>) {
const lines: string[] = [];
for (const [key, value] of Object.entries(object)) {
let quote;
let escapedValue = value ?? "";
if (key.startsWith("#")) {
console.warn(
`key starts with a '#' indicates a comment and is ignored: '${key}'`,
);
continue;
} else if (escapedValue.includes("\n")) {
// escape inner new lines
escapedValue = escapedValue.replaceAll("\n", "\\n");
quote = `"`;
} else if (escapedValue.match(/\W/)) {
quote = "'";
}
if (quote) {
// escape inner quotes
escapedValue = escapedValue.replaceAll(quote, `\\${quote}`);
escapedValue = `${quote}${escapedValue}${quote}`;
}
const line = `${key}=${escapedValue}`;
lines.push(line);
}
return lines.join("\n");
}

81
dotenv/stringify_test.ts Normal file
View File

@ -0,0 +1,81 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
import { assertEquals } from "../assert/mod.ts";
import { stringify } from "./stringify.ts";
Deno.test("stringify", async (t) => {
await t.step(
"basic",
() =>
assertEquals(
stringify({ "BASIC": "basic" }),
`BASIC=basic`,
),
);
await t.step(
"comment",
() =>
assertEquals(
stringify({ "#COMMENT": "comment" }),
``,
),
);
await t.step(
"single quote",
() =>
assertEquals(
stringify({ "QUOTED_SINGLE": "single quoted" }),
`QUOTED_SINGLE='single quoted'`,
),
);
await t.step(
"multiline",
() =>
assertEquals(
stringify({ "MULTILINE": "hello\nworld" }),
`MULTILINE="hello\\nworld"`,
),
);
await t.step(
"whitespace",
() =>
assertEquals(
stringify({ "WHITESPACE": " whitespace " }),
`WHITESPACE=' whitespace '`,
),
);
await t.step(
"equals",
() =>
assertEquals(
stringify({ "EQUALS": "equ==als" }),
`EQUALS='equ==als'`,
),
);
await t.step(
"number",
() =>
assertEquals(
stringify({ "THE_ANSWER": "42" }),
`THE_ANSWER=42`,
),
);
await t.step(
"undefined",
() =>
assertEquals(
stringify(
{ "UNDEFINED": undefined } as unknown as Record<string, string>,
),
`UNDEFINED=`,
),
);
await t.step(
"null",
() =>
assertEquals(
stringify({ "NULL": null } as unknown as Record<string, string>),
`NULL=`,
),
);
});