]> Lady’s Gitweb - Pisces/commitdiff
Small improvements to string.js
authorLady <redacted>
Sat, 25 Nov 2023 18:29:19 +0000 (13:29 -0500)
committerLady <redacted>
Sat, 25 Nov 2023 18:29:19 +0000 (13:29 -0500)
- Correctly set `Matcher::constructor`.

- Be safer about property descriptors when defining properties.

- Minor refactors.

string.js
string.test.js

index 0bd5f9e03bc4dc0c9b5622a969757dfd2f78890b..e8126d14fa44be9155723de05b4720403ee327f9 100644 (file)
--- 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;
 })();
index 47a87db4aeefd98060f71242d2141546db30ff3e..ee0e2097328535d6cbd1af583152d62ae74062b2 100644 (file)
@@ -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);
This page took 0.040733 seconds and 4 git commands to generate.