2020-08-25 23:57:08 +00:00
'use strict' ;
2021-02-26 03:58:33 +00:00
var GetIntrinsic = require ( 'get-intrinsic' ) ;
2020-08-25 23:57:08 +00:00
2024-03-28 02:00:41 +00:00
var $TypeError = require ( 'es-errors/type' ) ;
2020-08-25 23:57:08 +00:00
var $parseInt = GetIntrinsic ( '%parseInt%' ) ;
var inspect = require ( 'object-inspect' ) ;
2022-11-10 10:43:16 +00:00
var regexTester = require ( 'safe-regex-test' ) ;
2021-02-26 03:58:33 +00:00
var callBound = require ( 'call-bind/callBound' ) ;
2020-08-25 23:57:08 +00:00
var every = require ( '../helpers/every' ) ;
var isDigit = regexTester ( /^[0-9]$/ ) ;
var $charAt = callBound ( 'String.prototype.charAt' ) ;
var $strSlice = callBound ( 'String.prototype.slice' ) ;
var IsArray = require ( './IsArray' ) ;
2024-03-28 02:00:41 +00:00
var isInteger = require ( '../helpers/isInteger' ) ;
var isStringOrUndefined = require ( '../helpers/isStringOrUndefined' ) ;
2020-08-25 23:57:08 +00:00
2024-03-28 02:00:41 +00:00
// https://262.ecma-international.org/6.0/#sec-getsubstitution
2020-08-25 23:57:08 +00:00
2024-03-28 02:00:41 +00:00
// eslint-disable-next-line max-statements, max-lines-per-function
2020-08-25 23:57:08 +00:00
module . exports = function GetSubstitution ( matched , str , position , captures , replacement ) {
2024-03-28 02:00:41 +00:00
if ( typeof matched !== 'string' ) {
2020-08-25 23:57:08 +00:00
throw new $TypeError ( 'Assertion failed: `matched` must be a String' ) ;
}
var matchLength = matched . length ;
2024-03-28 02:00:41 +00:00
if ( typeof str !== 'string' ) {
2020-08-25 23:57:08 +00:00
throw new $TypeError ( 'Assertion failed: `str` must be a String' ) ;
}
var stringLength = str . length ;
2024-03-28 02:00:41 +00:00
if ( ! isInteger ( position ) || position < 0 || position > stringLength ) {
2020-08-25 23:57:08 +00:00
throw new $TypeError ( 'Assertion failed: `position` must be a nonnegative integer, and less than or equal to the length of `string`, got ' + inspect ( position ) ) ;
}
2024-03-28 02:00:41 +00:00
if ( ! IsArray ( captures ) || ! every ( captures , isStringOrUndefined ) ) {
2020-08-25 23:57:08 +00:00
throw new $TypeError ( 'Assertion failed: `captures` must be a List of Strings, got ' + inspect ( captures ) ) ;
}
2024-03-28 02:00:41 +00:00
if ( typeof replacement !== 'string' ) {
2020-08-25 23:57:08 +00:00
throw new $TypeError ( 'Assertion failed: `replacement` must be a String' ) ;
}
var tailPos = position + matchLength ;
var m = captures . length ;
var result = '' ;
for ( var i = 0 ; i < replacement . length ; i += 1 ) {
// if this is a $, and it's not the end of the replacement
var current = $charAt ( replacement , i ) ;
var isLast = ( i + 1 ) >= replacement . length ;
var nextIsLast = ( i + 2 ) >= replacement . length ;
if ( current === '$' && ! isLast ) {
var next = $charAt ( replacement , i + 1 ) ;
if ( next === '$' ) {
result += '$' ;
i += 1 ;
} else if ( next === '&' ) {
result += matched ;
i += 1 ;
} else if ( next === '`' ) {
result += position === 0 ? '' : $strSlice ( str , 0 , position - 1 ) ;
i += 1 ;
} else if ( next === "'" ) {
result += tailPos >= stringLength ? '' : $strSlice ( str , tailPos ) ;
i += 1 ;
} else {
var nextNext = nextIsLast ? null : $charAt ( replacement , i + 2 ) ;
if ( isDigit ( next ) && next !== '0' && ( nextIsLast || ! isDigit ( nextNext ) ) ) {
// $1 through $9, and not followed by a digit
var n = $parseInt ( next , 10 ) ;
// if (n > m, impl-defined)
2024-03-28 02:00:41 +00:00
result += n <= m && typeof captures [ n - 1 ] === 'undefined' ? '' : captures [ n - 1 ] ;
2020-08-25 23:57:08 +00:00
i += 1 ;
} else if ( isDigit ( next ) && ( nextIsLast || isDigit ( nextNext ) ) ) {
// $00 through $99
var nn = next + nextNext ;
var nnI = $parseInt ( nn , 10 ) - 1 ;
// if nn === '00' or nn > m, impl-defined
2024-03-28 02:00:41 +00:00
result += nn <= m && typeof captures [ nnI ] === 'undefined' ? '' : captures [ nnI ] ;
2020-08-25 23:57:08 +00:00
i += 2 ;
} else {
result += '$' ;
}
}
} else {
// the final $, or else not a $
result += $charAt ( replacement , i ) ;
}
}
return result ;
} ;