You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

154 lines
5.0 KiB

'use strict';
var FREEZING = require('../internals/freezing');
var $ = require('../internals/export');
var makeBuiltIn = require('../internals/make-built-in');
var uncurryThis = require('../internals/function-uncurry-this');
var apply = require('../internals/function-apply');
var anObject = require('../internals/an-object');
var toObject = require('../internals/to-object');
var isCallable = require('../internals/is-callable');
var lengthOfArrayLike = require('../internals/length-of-array-like');
var defineProperty = require('../internals/object-define-property').f;
var createArrayFromList = require('../internals/array-slice');
var WeakMapHelpers = require('../internals/weak-map-helpers');
var cooked = require('../internals/string-cooked');
var parse = require('../internals/string-parse');
var whitespaces = require('../internals/whitespaces');
var DedentMap = new WeakMapHelpers.WeakMap();
var weakMapGet = WeakMapHelpers.get;
var weakMapHas = WeakMapHelpers.has;
var weakMapSet = WeakMapHelpers.set;
var $Array = Array;
var $TypeError = TypeError;
// eslint-disable-next-line es/no-object-freeze -- safe
var freeze = Object.freeze || Object;
// eslint-disable-next-line es/no-object-isfrozen -- safe
var isFrozen = Object.isFrozen;
var min = Math.min;
var charAt = uncurryThis(''.charAt);
var stringSlice = uncurryThis(''.slice);
var split = uncurryThis(''.split);
var exec = uncurryThis(/./.exec);
var NEW_LINE = /([\n\u2028\u2029]|\r\n?)/g;
var LEADING_WHITESPACE = RegExp('^[' + whitespaces + ']*');
var NON_WHITESPACE = RegExp('[^' + whitespaces + ']');
var INVALID_TAG = 'Invalid tag';
var INVALID_OPENING_LINE = 'Invalid opening line';
var INVALID_CLOSING_LINE = 'Invalid closing line';
var dedentTemplateStringsArray = function (template) {
var rawInput = template.raw;
// https://github.com/tc39/proposal-string-dedent/issues/75
if (FREEZING && !isFrozen(rawInput)) throw new $TypeError('Raw template should be frozen');
if (weakMapHas(DedentMap, rawInput)) return weakMapGet(DedentMap, rawInput);
var raw = dedentStringsArray(rawInput);
var cookedArr = cookStrings(raw);
defineProperty(cookedArr, 'raw', {
value: freeze(raw)
});
freeze(cookedArr);
weakMapSet(DedentMap, rawInput, cookedArr);
return cookedArr;
};
var dedentStringsArray = function (template) {
var t = toObject(template);
var length = lengthOfArrayLike(t);
var blocks = $Array(length);
var dedented = $Array(length);
var i = 0;
var lines, common, quasi, k;
if (!length) throw new $TypeError(INVALID_TAG);
for (; i < length; i++) {
var element = t[i];
if (typeof element == 'string') blocks[i] = split(element, NEW_LINE);
else throw new $TypeError(INVALID_TAG);
}
for (i = 0; i < length; i++) {
var lastSplit = i + 1 === length;
lines = blocks[i];
if (i === 0) {
if (lines.length === 1 || lines[0].length > 0) {
throw new $TypeError(INVALID_OPENING_LINE);
}
lines[1] = '';
}
if (lastSplit) {
if (lines.length === 1 || exec(NON_WHITESPACE, lines[lines.length - 1])) {
throw new $TypeError(INVALID_CLOSING_LINE);
}
lines[lines.length - 2] = '';
lines[lines.length - 1] = '';
}
// eslint-disable-next-line sonar/no-redundant-assignments -- false positive, https://github.com/SonarSource/SonarJS/issues/4767
for (var j = 2; j < lines.length; j += 2) {
var text = lines[j];
var lineContainsTemplateExpression = j + 1 === lines.length && !lastSplit;
var leading = exec(LEADING_WHITESPACE, text)[0];
if (!lineContainsTemplateExpression && leading.length === text.length) {
lines[j] = '';
continue;
}
common = commonLeadingIndentation(leading, common);
}
}
var count = common ? common.length : 0;
for (i = 0; i < length; i++) {
lines = blocks[i];
quasi = lines[0];
k = 1;
for (; k < lines.length; k += 2) {
quasi += lines[k] + stringSlice(lines[k + 1], count);
}
dedented[i] = quasi;
}
return dedented;
};
var commonLeadingIndentation = function (a, b) {
if (b === undefined || a === b) return a;
var i = 0;
for (var len = min(a.length, b.length); i < len; i++) {
if (charAt(a, i) !== charAt(b, i)) break;
}
return stringSlice(a, 0, i);
};
var cookStrings = function (raw) {
var i = 0;
var length = raw.length;
var result = $Array(length);
for (; i < length; i++) {
result[i] = parse(raw[i]);
} return result;
};
var makeDedentTag = function (tag) {
return makeBuiltIn(function (template /* , ...substitutions */) {
var args = createArrayFromList(arguments);
args[0] = dedentTemplateStringsArray(anObject(template));
return apply(tag, this, args);
}, '');
};
var cookedDedentTag = makeDedentTag(cooked);
// `String.dedent` method
// https://github.com/tc39/proposal-string-dedent
$({ target: 'String', stat: true, forced: true }, {
dedent: function dedent(templateOrFn /* , ...substitutions */) {
anObject(templateOrFn);
if (isCallable(templateOrFn)) return makeDedentTag(templateOrFn);
return apply(cookedDedentTag, this, arguments);
}
});