From: Lady Date: Sat, 25 Nov 2023 18:29:19 +0000 (-0500) Subject: Small improvements to string.js X-Git-Url: https://git.ladys.computer/Pisces/commitdiff_plain/d8f6adb97f102b7163006f9208c09924911e7b4c?ds=inline;hp=9539760b1bf114c7cf5d44c09cb618ca02e08fdb Small improvements to string.js - Correctly set `Matcher::constructor`. - Be safer about property descriptors when defining properties. - Minor refactors. --- diff --git a/string.js b/string.js index 0bd5f9e..e8126d1 100644 --- a/string.js +++ b/string.js @@ -19,11 +19,14 @@ import { stringIteratorFunction, } from "./iterable.js"; import { + defineOwnDataProperty, defineOwnProperties, getOwnPropertyDescriptors, + objectCreate, + setPropertyValues, setPrototype, } from "./object.js"; -import { sameValue, toLength } from "./value.js"; +import { sameValue, toLength, UNDEFINED } from "./value.js"; const RE = RegExp; const { prototype: rePrototype } = RE; @@ -94,7 +97,7 @@ export const { * expression with `^(?:` and `)$` if you don’t want nongreedy * regular expressions to fail when shorter matches are possible. */ - constructor(source, name = undefined, constraint = null) { + constructor(source, name = UNDEFINED, constraint = null) { super( ($) => { if (typeof $ !== "string") { @@ -139,17 +142,19 @@ export const { return defineOwnProperties( setPrototype(this, matcherPrototype), { - lastIndex: { + lastIndex: setPropertyValues(objectCreate(null), { configurable: false, enumerable: false, value: 0, writable: false, - }, - name: { - value: name != null + }), + name: defineOwnDataProperty( + objectCreate(null), + "value", + name != null ? `${name}` : `Matcher(${call(reToString, regExp, [])})`, - }, + ), }, ); } @@ -247,21 +252,31 @@ export const { } }; - const matcherConstructor = defineOwnProperties( + const matcherConstructor = Object.defineProperties( class extends RegExp { constructor(...args) { return new Matcher(...args); } }, { - name: { value: "Matcher" }, - length: { value: 1 }, + name: defineOwnDataProperty( + Object.create(null), + "value", + "Matcher", + ), + length: defineOwnDataProperty(Object.create(null), "value", 1), }, ); const matcherPrototype = defineOwnProperties( matcherConstructor.prototype, getOwnPropertyDescriptors(Matcher.prototype), - { constructor: { value: matcherConstructor } }, + { + constructor: defineOwnDataProperty( + Object.create(null), + "value", + matcherConstructor, + ), + }, ); return { Matcher: matcherConstructor }; @@ -310,12 +325,12 @@ export const { */ export const canonicalNumericIndexString = ($) => { if (typeof $ !== "string") { - return undefined; + return UNDEFINED; } else if ($ === "-0") { return -0; } else { const n = +$; - return $ === `${n}` ? n : undefined; + return $ === `${n}` ? n : UNDEFINED; } }; @@ -395,7 +410,7 @@ export const { export const getCharacter = ($, pos) => { const codepoint = getCodepoint($, pos); return codepoint == null - ? undefined + ? UNDEFINED : stringFromCodepoints(codepoint); }; @@ -408,9 +423,6 @@ export const { */ getCodeUnit, - /** Returns whether the provided value is an integer index string. */ - isIntegerIndexString, - /** * Returns a string created from the provided code units. * @@ -437,7 +449,6 @@ export const { const { fromCharCode } = String; const { charCodeAt, concat } = String.prototype; const { - MAX_SAFE_INTEGER: MAXIMUM_SAFE_INTEGRAL_NUMBER, isInteger: isIntegralNumber, isNaN: isNan, } = Number; @@ -445,27 +456,13 @@ export const { return { getCodeUnit: ($, n) => { const codeUnit = call(charCodeAt, $, [n]); - return isNan(codeUnit) ? undefined : codeUnit; - }, - isIntegerIndexString: ($) => { - const value = canonicalNumericIndexString($); - if (value !== undefined && isIntegralNumber(value)) { - // The provided value is an integral canonical numeric index - // string. - return sameValue(value, 0) || - value > 0 && value <= MAXIMUM_SAFE_INTEGRAL_NUMBER && - value === toLength(value); - } else { - // The provided value is not an integral canonical numeric - // index string. - return false; - } + return isNan(codeUnit) ? UNDEFINED : codeUnit; }, - stringCatenate: defineOwnProperties( + stringCatenate: Object.defineProperties( (...args) => call(concat, "", args), { name: { value: "stringCatenate" }, length: { value: 2 } }, ), - stringFromCodeUnits: defineOwnProperties( + stringFromCodeUnits: Object.defineProperties( (...codeUnits) => { for (let index = 0; index < codeUnits.length; ++index) { // Iterate over each provided code unit and throw if it is @@ -484,7 +481,7 @@ export const { /* do nothing */ } } - return call(fromCharCode, undefined, codeUnits); + return call(fromCharCode, UNDEFINED, codeUnits); }, { name: { value: "stringFromCodeUnits" }, length: { value: 1 } }, ), @@ -521,13 +518,28 @@ export const getLastSubstringIndex = createCallableFunction( { name: "getLastSubstringIndex" }, ); -/** Returns whether the provided value is an array index string. */ +/** Returns whether the provided value is an array index. */ export const isArrayIndexString = ($) => { const value = canonicalNumericIndexString($); - if (value !== undefined) { - // The provided value is a canonical numeric index string. - return sameValue(value, 0) || value > 0 && value < -1 >>> 0 && - value === toLength(value); + if (value !== UNDEFINED) { + // The provided value is a canonical numeric index string; return + // whether it is in range for array indices. + return sameValue(value, 0) || + value === toLength(value) && value > 0 && value < -1 >>> 0; + } else { + // The provided value is not a canonical numeric index string. + return false; + } +}; + +/** Returns whether the provided value is an integer index string. */ +export const isIntegerIndexString = ($) => { + const value = canonicalNumericIndexString($); + if (value !== UNDEFINED) { + // The provided value is a canonical numeric index string; return + // whether it is in range for integer indices. + return sameValue(value, 0) || + value === toLength(value) && value > 0; } else { // The provided value is not a canonical numeric index string. return false; @@ -547,7 +559,7 @@ export const join = (() => { call( arrayJoin, [...$], - [separator === undefined ? "," : `${separator}`], + [separator === UNDEFINED ? "," : `${separator}`], ); return join; })(); diff --git a/string.test.js b/string.test.js index 47a87db..ee0e209 100644 --- a/string.test.js +++ b/string.test.js @@ -110,6 +110,12 @@ describe("Matcher", () => { }); }); + describe("::constructor", () => { + it("[[Get]] returns the same constructor", () => { + assertStrictEquals(new Matcher(/(?:)/su).constructor, Matcher); + }); + }); + describe("::dotAll", () => { it("[[Get]] returns true when the dotAll flag is present", () => { assertStrictEquals(new Matcher(/(?:)/su).dotAll, true);