From db69b25e856fb448a2118d3adffc33c1e41bab0f Mon Sep 17 00:00:00 2001 From: "netop://ウィビ" Date: Sat, 11 Apr 2026 14:39:25 -0700 Subject: initial commit --- mod.ts | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 mod.ts (limited to 'mod.ts') diff --git a/mod.ts b/mod.ts new file mode 100644 index 0000000..2600198 --- /dev/null +++ b/mod.ts @@ -0,0 +1,122 @@ +/* + * SPDX-License-Identifier: MIT + * Copyright © 2015-2025 Desmond Brand + * Copyright © 2026 Paul Anthony Webb (modifications) + * + * Dap is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. + */ + +/*** UTILITY ------------------------------------------ ***/ + +const dedent: Dedent = createDedent({}); + +interface Dedent { + (literals: string): string; + (strings: TemplateStringsArray, ...values: unknown[]): string; + withOptions: CreateDedent; +} + +interface DedentOptions { + alignValues?: boolean; + escapeSpecialCharacters?: boolean; + trimWhitespace?: boolean; +} + +type CreateDedent = (options: DedentOptions) => Dedent; + +/*** EXPORT ------------------------------------------- ***/ + +export default dedent; + +/*** PROGRAM ------------------------------------------ ***/ + +function createDedent(options: DedentOptions): Dedent { + function dedent(literals: string): string; + function dedent(strings: TemplateStringsArray, ...values: unknown[]): string; + + function dedent(strings: TemplateStringsArray | string, ...values: unknown[]) { + const raw = typeof strings === "string" ? + [strings] : + strings.raw; + + const { + alignValues = false, + escapeSpecialCharacters = Array.isArray(strings), + trimWhitespace = true + } = options; + + let result = ""; + + for (let i = 0; i < raw.length; i++) { + let next = raw[i]; + + if (escapeSpecialCharacters) { + next = next + .replace(/\\\n[ \t]*/g, "") + .replace(/\\`/g, "`") + .replace(/\\\$/g, "$") + .replace(/\\\{/g, "{"); + } + + result += next; + + if (i < values.length) { + result += alignValues ? + alignValue(values[i], result) : + values[i]; + } + } + + const lines = result.split("\n"); + let minIndent: number | null = null; + + for (const line of lines) { + const match = line.match(/^(\s+)\S+/); + + if (match) { + const indent = match[1].length; + + minIndent = minIndent === null ? + indent : + Math.min(minIndent, indent); + } + } + + if (minIndent !== null) { + result = lines + .map((line) => (line[0] === " " || line[0] === "\t" ? line.slice(minIndent) : line)) + .join("\n"); + } + + if (trimWhitespace) + result = result.trim(); + + if (escapeSpecialCharacters) + result = result.replace(/\\n/g, "\n"); + + return result; + } + + dedent.withOptions = (newOptions: DedentOptions): Dedent => createDedent({ ...options, ...newOptions }); + + return dedent; +} + +/*** HELPER ------------------------------------------- ***/ + +function alignValue(value: unknown, precedingText: string) { + if (typeof value !== "string" || !value.includes("\n")) + return value; + + const currentLine = precedingText.slice(precedingText.lastIndexOf("\n") + 1); + const indentMatch = currentLine.match(/^(\s+)/); + + if (indentMatch) + return value.replace(/\n/g, `\n${indentMatch[1]}`); + + return value; +} + +/*** adapted from https://github.com/dmnd/dedent ***/ -- cgit v1.2.3