From 16c49480b5e977450bbea3479861be4528fcdc12 Mon Sep 17 00:00:00 2001 From: Webber Date: Sat, 20 Aug 2022 21:27:47 +0200 Subject: [PATCH] feat: add String.dedent polyfill --- src/dependencies.ts | 6 ++++- src/modules/dedent.ts | 54 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 src/modules/dedent.ts diff --git a/src/dependencies.ts b/src/dependencies.ts index e99510c6..a8e84d4d 100644 --- a/src/dependencies.ts +++ b/src/dependencies.ts @@ -20,9 +20,13 @@ import { Command } from 'https://deno.land/x/cmd@v1.2.0/commander/index.ts'; import { getUnityChangeset as getUnityChangeSet } from 'https://deno.land/x/unity_changeset@2.0.0/src/index.ts'; import { Buffer } from 'https://deno.land/std@0.151.0/io/buffer.ts'; -// Internally managed +// Internally managed packages import waitUntil from './modules/wait-until.ts'; import { core, exec } from './modules/actions/index.ts'; +import { dedent } from './modules/dedent.ts'; + +// Polyfill for https://github.com/tc39/proposal-string-dedent +String.dedent = dedent; class Writable { constructor() { diff --git a/src/modules/dedent.ts b/src/modules/dedent.ts new file mode 100644 index 00000000..bc7c8add --- /dev/null +++ b/src/modules/dedent.ts @@ -0,0 +1,54 @@ +/* eslint-disable unicorn/no-array-reduce,unicorn/explicit-length-check,padding-line-between-statements,github/array-foreach,unicorn/no-array-for-each */ + +// Source: https://github.com/tamino-martinius/node-ts-dedent/blob/master/src/index.ts +export function dedent(template: TemplateStringsArray | string, ...values: unknown[]): string { + let strings = Array.from(typeof template === 'string' ? [template] : template); + + // 1. Remove trailing whitespace. + strings[strings.length - 1] = strings[strings.length - 1].replace(/\r?\n([\t ]*)$/, ''); + + // 2. Find all line breaks to determine the highest common indentation level. + const indentLengths = strings.reduce((arr, str) => { + const matches = str.match(/\n([\t ]+|(?!\s).)/g); + if (matches) { + return arr.concat(matches.map((match) => match.match(/[\t ]/g)?.length ?? 0)); + } + return arr; + }, []); + + // 3. Remove the common indentation from all strings. + if (indentLengths.length) { + const pattern = new RegExp(`\n[\t ]{${Math.min(...indentLengths)}}`, 'g'); + + strings = strings.map((str) => str.replace(pattern, '\n')); + } + + // 4. Remove leading whitespace. + strings[0] = strings[0].replace(/^\r?\n/, ''); + + // 5. Perform interpolation. + let string = strings[0]; + + values.forEach((value, i) => { + // 5.1 Read current indentation level + const indentations = string.match(/(?:^|\n)( *)$/); + const indentation = indentations ? indentations[1] : ''; + let indentedValue = value; + + // 5.2 Add indentation to values with multiline strings + if (typeof value === 'string' && value.includes('\n')) { + indentedValue = String(value) + .split('\n') + .map((str, i) => { + return i === 0 ? str : `${indentation}${str}`; + }) + .join('\n'); + } + + string += indentedValue + strings[i + 1]; + }); + + return string; +} + +export default dedent;