summaryrefslogtreecommitdiff
path: root/mod.ts
diff options
context:
space:
mode:
authornetop://ウィビ <paul@webb.page>2026-04-11 14:39:25 -0700
committernetop://ウィビ <paul@webb.page>2026-04-11 14:39:25 -0700
commitdb69b25e856fb448a2118d3adffc33c1e41bab0f (patch)
treec420967b7977e858c9003766210c6128546606cf /mod.ts
initial commitHEADprimary
Diffstat (limited to 'mod.ts')
-rw-r--r--mod.ts122
1 files changed, 122 insertions, 0 deletions
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 ***/