diff --git a/dotenv/mod.ts b/dotenv/mod.ts index 0acd8877c..7d8ed4065 100644 --- a/dotenv/mod.ts +++ b/dotenv/mod.ts @@ -4,6 +4,8 @@ * Parses and loads environment variables from a `.env` file into the current * process, or stringify data into a `.env` file format. * + * Note: The key needs to match the pattern /^[a-zA-Z_][a-zA-Z0-9_]*$/. + * * ```ts no-eval * // Automatically load environment variables from a `.env` file * import "@std/dotenv/load"; @@ -84,6 +86,8 @@ export function loadSync( * Inspired by the node modules {@linkcode https://github.com/motdotla/dotenv | dotenv} * and {@linkcode https://github.com/motdotla/dotenv-expand | dotenv-expand}. * + * Note: The key needs to match the pattern /^[a-zA-Z_][a-zA-Z0-9_]*$/. + * * ## Basic usage * ```sh * # .env diff --git a/dotenv/parse.ts b/dotenv/parse.ts index bdbb345e0..010473786 100644 --- a/dotenv/parse.ts +++ b/dotenv/parse.ts @@ -10,7 +10,9 @@ type LineParseResult = { type CharactersMap = { [key: string]: string }; const RE_KEY_VALUE = - /^\s*(?:export\s+)?(?[a-zA-Z_]+[a-zA-Z0-9_]*?)\s*=[\ \t]*('\n?(?(.|\n)*?)\n?'|"\n?(?(.|\n)*?)\n?"|(?[^\n#]*)) *#*.*$/gm; + /^\s*(?:export\s+)?(?[^\s=#]+?)\s*=[\ \t]*('\n?(?(.|\n)*?)\n?'|"\n?(?(.|\n)*?)\n?"|(?[^\n#]*)) *#*.*$/gm; + +const RE_VALID_KEY = /^[a-zA-Z_][a-zA-Z0-9_]*$/; const RE_EXPAND_VALUE = /(\${(?.+?)(\:-(?.+))?}|(?\w+)(\:-(?.+))?)/g; @@ -57,6 +59,8 @@ function expand(str: string, variablesMap: { [key: string]: string }): string { /** * Parse `.env` file output in an object. * + * Note: The key needs to match the pattern /^[a-zA-Z_][a-zA-Z0-9_]*$/. + * * @example Usage * ```ts * import { parse } from "@std/dotenv/parse"; @@ -79,6 +83,13 @@ export function parse(text: string): Record { const { key, interpolated, notInterpolated, unquoted } = match ?.groups as LineParseResult; + if (!RE_VALID_KEY.test(key)) { + console.warn( + `Ignored the key "${key}" as it is not a valid identifier: The key need to match the pattern /^[a-zA-Z_][a-zA-Z0-9_]*$/.`, + ); + continue; + } + if (unquoted) { keysForExpandCheck.push(key); } diff --git a/dotenv/parse_test.ts b/dotenv/parse_test.ts index 6eb0b1954..90b70993d 100644 --- a/dotenv/parse_test.ts +++ b/dotenv/parse_test.ts @@ -3,11 +3,14 @@ import { assertEquals } from "@std/assert"; import { parse } from "./parse.ts"; import * as path from "@std/path"; +import { assertSpyCall, spy } from "@std/testing/mock"; const moduleDir = path.dirname(path.fromFileUrl(import.meta.url)); const testdataDir = path.resolve(moduleDir, "testdata"); Deno.test("parse()", () => { + using consoleWarnSpy = spy(console, "warn"); + const testDotenv = Deno.readTextFileSync( path.join(testdataDir, "./.env.test"), ); @@ -140,6 +143,12 @@ Deno.test("parse()", () => { "export is ignored", "export at the start of the key is ignored", ); + + assertSpyCall(consoleWarnSpy, 0, { + args: [ + 'Ignored the key "1INVALID" as it is not a valid identifier: The key need to match the pattern /^[a-zA-Z_][a-zA-Z0-9_]*$/.', + ], + }); }); Deno.test("parse() ignores comments", () => {