--- /dev/null
+Copyright (c) 2015-present Greg Hurrell
+
+# MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+{
+ "name": "dented",
+ "version": "0.0.1",
+ "description": "Indenting and dedenting utilities",
+ "main": "src/index.js",
+ "files": [
+ "src/dedent.js",
+ "src/indent.js",
+ "src/index.js"
+ ],
+ "repository": "https://github.com/wincent/dented",
+ "author": "Greg Hurrell <greg@hurrell.net>",
+ "license": "MIT",
+ "private": false
+}
--- /dev/null
+/**
+ * @flow strict
+ */
+
+/**
+ * Tagged template literal function that trims leading and trailing whitespace
+ * and reduces the indent level back to column 0.
+ */
+function dedent(
+ strings /*: Array<string> */,
+ ...interpolations /*: Array<mixed> */
+) {
+ // Insert interpolations in template.
+ const output = strings.reduce((acc, string, i) => {
+ if (i < interpolations.length) {
+ return acc + string + String(interpolations[i]);
+ } else {
+ return acc + string;
+ }
+ }, '');
+
+ // Collapse totally blank lines to empty strings.
+ const lines = output.split('\n').map(line => {
+ if (line.match(/^\s+$/)) {
+ return '';
+ } else {
+ return line;
+ }
+ });
+
+ // Find minimum indent (ignoring empty lines).
+ const minimum = lines.reduce((acc, line) => {
+ const indent = line.match(/^\s+/);
+ if (indent) {
+ const length = indent[0].length;
+ return Math.min(acc, length);
+ }
+ return acc;
+ }, Infinity);
+
+ // Strip out minimum indent from every line.
+ const dedented = lines.map(line =>
+ line.replace(new RegExp(`^${' '.repeat(minimum)}`, 'g'), ''),
+ );
+
+ // Trim first and last line if empty.
+ if (dedented[0] === '') {
+ dedented.shift();
+ }
+ if (dedented[dedented.length - 1] === '') {
+ dedented.pop();
+ }
+ return dedented.join('\n');
+}
+
+module.exports = dedent;
--- /dev/null
+/**
+ * @flow strict
+ */
+
+/**
+ * Indent every line (except for empty lines) by `count` spaces.
+ */
+function indent(text /*: string */, count /*: number */ = 2) {
+ return text
+ .split('\n')
+ .map(line => {
+ if (line.length) {
+ return `${' '.repeat(count)}${line}`;
+ } else {
+ return line;
+ }
+ })
+ .join('\n');
+}
+
+module.exports = indent;
--- /dev/null
+/**
+ * @flow strict
+ */
+
+const dedent = require('./dedent');
+const indent = require('./indent');
+
+module.exports = {
+ dedent,
+ indent,
+};