mh-two-thousand-and-two
2024-04-12 7fc6dbf547b8899d949b67cdec36b96a7d1701c7
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
'use strict';
 
var $TypeError = require('es-errors/type');
 
var regexTester = require('safe-regex-test');
var every = require('../helpers/every');
 
var inspect = require('object-inspect');
 
var Get = require('./Get');
var IsArray = require('./IsArray');
var min = require('./min');
var StringIndexOf = require('./StringIndexOf');
var StringToNumber = require('./StringToNumber');
var substring = require('./substring');
var ToString = require('./ToString');
var Type = require('./Type');
 
var isInteger = require('../helpers/isInteger');
var isStringOrUndefined = require('../helpers/isStringOrUndefined');
var isPrefixOf = require('../helpers/isPrefixOf');
 
var startsWithDollarDigit = regexTester(/^\$[0-9]/);
var startsWithDollarTwoDigit = regexTester(/^\$[0-9][0-9]/);
 
// http://www.ecma-international.org/ecma-262/14.0/#sec-getsubstitution
 
// eslint-disable-next-line max-statements, max-params, max-lines-per-function
module.exports = function GetSubstitution(matched, str, position, captures, namedCaptures, replacementTemplate) {
    if (typeof matched !== 'string') {
        throw new $TypeError('Assertion failed: `matched` must be a String');
    }
 
    if (typeof str !== 'string') {
        throw new $TypeError('Assertion failed: `str` must be a String');
    }
 
    if (!isInteger(position) || position < 0) {
        throw new $TypeError('Assertion failed: `position` must be a nonnegative integer, got ' + inspect(position));
    }
 
    if (!IsArray(captures) || !every(captures, isStringOrUndefined)) {
        throw new $TypeError('Assertion failed: `captures` must be a possibly-empty List of Strings or `undefined`, got ' + inspect(captures));
    }
 
    if (typeof namedCaptures !== 'undefined' && Type(namedCaptures) !== 'Object') {
        throw new $TypeError('Assertion failed: `namedCaptures` must be `undefined` or an Object');
    }
 
    if (typeof replacementTemplate !== 'string') {
        throw new $TypeError('Assertion failed: `replacementTemplate` must be a String');
    }
 
    var stringLength = str.length; // step 1
 
    if (position > stringLength) {
        throw new $TypeError('Assertion failed: position > stringLength, got ' + inspect(position)); // step 2
    }
 
    var templateRemainder = replacementTemplate; // step 3
 
    var result = ''; // step 4
 
    while (templateRemainder !== '') { // step 5
        // 5.a NOTE: The following steps isolate ref (a prefix of templateRemainder), determine refReplacement (its replacement), and then append that replacement to result.
 
        var ref, refReplacement, capture;
        if (isPrefixOf('$$', templateRemainder)) { // step 5.b
            ref = '$$'; // step 5.b.i
            refReplacement = '$'; // step 5.b.ii
        } else if (isPrefixOf('$`', templateRemainder)) { // step 5.c
            ref = '$`'; // step 5.c.i
            refReplacement = substring(str, 0, position); // step 5.c.ii
        } else if (isPrefixOf('$&', templateRemainder)) { // step 5.d
            ref = '$&'; // step 5.d.i
            refReplacement = matched; // step 5.d.ii
        } else if (isPrefixOf('$\'', templateRemainder)) { // step 5.e
            ref = '$\''; // step 5.e.i
            var matchLength = matched.length; // step 5.e.ii
            var tailPos = position + matchLength; // step 5.e.iii
            refReplacement = substring(str, min(tailPos, stringLength)); // step 5.e.iv
            // 5.e.v NOTE: tailPos can exceed stringLength only if this abstract operation was invoked by a call to the intrinsic @@replace method of %RegExp.prototype% on an object whose "exec" property is not the intrinsic %RegExp.prototype.exec%.
        } else if (startsWithDollarDigit(templateRemainder)) { // step 5.f
            var digitCount = startsWithDollarTwoDigit(templateRemainder) ? 2 : 1; // step 5.f.i
 
            ref = substring(templateRemainder, 0, 1 + digitCount); // step 5.f.ii
 
            var digits = substring(templateRemainder, 1, 1 + digitCount); // step 5.f.iii
 
            var index = StringToNumber(digits); // step 5.f.iv
 
            if (index < 0 || index > 99) {
                throw new $TypeError('Assertion failed: `index` must be >= 0 and <= 99'); // step 5.f.v
            }
 
            var captureLen = captures.length; // step 5.f.vi
 
            if (1 <= index && index <= captureLen) { // step 5.f.vii
                capture = captures[index - 1]; // step 5.f.vii.1
 
                if (typeof capture === 'undefined') { // step 5.f.vii.2
                    refReplacement = ''; // step 5.f.vii.2.a
                } else { // step 5.f.vii.3
                    refReplacement = capture; // step 5.f.vii.3.a
                }
            } else { // step 5.f.viii
                refReplacement = ref; // step 5.f.viii.1
            }
        } else if (isPrefixOf('$<', templateRemainder)) { // step 5.g
            var gtPos = StringIndexOf(templateRemainder, '>', 0); // step 5.g.i
            if (gtPos === -1 || typeof namedCaptures === 'undefined') { // step 5.g.ii
                ref = '$<'; // step 5.g.ii.1
                refReplacement = ref; // step 5.g.ii.2
            } else { // step 5.g.iii
                ref = substring(templateRemainder, 0, gtPos + 1); // step 5.g.iii.1
                var groupName = substring(templateRemainder, 2, gtPos); // step 5.g.iii.2
                if (Type(namedCaptures) !== 'Object') {
                    throw new $TypeError('Assertion failed: Type(namedCaptures) is not Object'); // step 5.g.iii.3
                }
                capture = Get(namedCaptures, groupName); // step 5.g.iii.4
                if (typeof capture === 'undefined') { // step 5.g.iii.5
                    refReplacement = ''; // step 5.g.iii.5.a
                } else { // step 5.g.iii.6
                    refReplacement = ToString(capture); // step 5.g.iii.6.a
                }
            }
        } else { // step 5.h
            ref = substring(templateRemainder, 0, 1); // step 5.h.i
            refReplacement = ref; // step 5.h.ii
        }
 
        var refLength = ref.length; // step 5.i
 
        templateRemainder = substring(templateRemainder, refLength); // step 5.j
 
        result += refReplacement; // step 5.k
    }
 
    return result; // step 6
};