stringIteratorFunction,
} from "./iterable.js";
import {
+ defineOwnDataProperty,
defineOwnProperties,
getOwnPropertyDescriptors,
+ objectCreate,
+ setPropertyValues,
setPrototype,
} from "./object.js";
+import { sameValue, toLength, UNDEFINED } from "./value.js";
const RE = RegExp;
const { prototype: rePrototype } = RE;
* 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") {
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, [])})`,
- },
+ ),
},
);
}
}
};
- 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 };
};
})();
+/**
+ * Returns −0 if the provided argument is "-0"; returns a number
+ * representing the index if the provided argument is a canonical
+ * numeric index string; otherwise, returns undefined.
+ *
+ * There is no clamping of the numeric index, but note that numbers
+ * above 2^53 − 1 are not safe nor valid integer indices.
+ */
+export const canonicalNumericIndexString = ($) => {
+ if (typeof $ !== "string") {
+ return UNDEFINED;
+ } else if ($ === "-0") {
+ return -0;
+ } else {
+ const n = +$;
+ return $ === `${n}` ? n : UNDEFINED;
+ }
+};
+
export const {
/**
* Returns an iterator over the codepoints in the string representation
export const getCharacter = ($, pos) => {
const codepoint = getCodepoint($, pos);
return codepoint == null
- ? undefined
+ ? UNDEFINED
: stringFromCodepoints(codepoint);
};
-/**
- * Returns the code unit at the provided position in the string
- * representation of the provided value according to the algorithm of
- * `String::charAt`, except that out‐of‐bounds values return undefined
- * in place of nan.
- */
export const {
+ /**
+ * Returns the code unit at the provided position in the string
+ * representation of the provided value according to the algorithm of
+ * `String::charAt`, except that out‐of‐bounds values return undefined
+ * in place of nan.
+ */
getCodeUnit,
+ /**
+ * Returns a string created from the provided code units.
+ *
+ * ※ This is effectively an alias for `String.fromCharCode`, but
+ * with the same error behaviour as `String.fromCodePoint`.
+ *
+ * ☡ This function throws an error if provided with an argument which
+ * is not an integral number from 0 to FFFF₁₆ inclusive.
+ */
+ stringFromCodeUnits,
+
/**
* Returns the result of catenating the string representations of the
* provided values, returning a new string according to the algorithm
*/
stringCatenate,
} = (() => {
+ const { fromCharCode } = String;
const { charCodeAt, concat } = String.prototype;
- const { isNaN: isNan } = Number;
+ const {
+ isInteger: isIntegralNumber,
+ isNaN: isNan,
+ } = Number;
return {
getCodeUnit: ($, n) => {
const codeUnit = call(charCodeAt, $, [n]);
- return isNan(codeUnit) ? undefined : codeUnit;
+ return isNan(codeUnit) ? UNDEFINED : codeUnit;
},
- stringCatenate: defineOwnProperties(
+ stringCatenate: Object.defineProperties(
(...args) => call(concat, "", args),
{ name: { value: "stringCatenate" }, length: { value: 2 } },
),
+ stringFromCodeUnits: Object.defineProperties(
+ (...codeUnits) => {
+ for (let index = 0; index < codeUnits.length; ++index) {
+ // Iterate over each provided code unit and throw if it is
+ // out of range.
+ const nextCU = +codeUnits[index];
+ if (
+ !isIntegralNumber(nextCU) || nextCU < 0 || nextCU > 0xFFFF
+ ) {
+ // The code unit is not an integral number between 0 and
+ // 0xFFFF.
+ throw new RangeError(
+ `Piscēs: Code unit out of range: ${nextCU}.`,
+ );
+ } else {
+ // The code unit is acceptable.
+ /* do nothing */
+ }
+ }
+ return call(fromCharCode, UNDEFINED, codeUnits);
+ },
+ { name: { value: "stringFromCodeUnits" }, length: { value: 1 } },
+ ),
};
})();
{ name: "getLastSubstringIndex" },
);
+/** 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
+ // 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;
+ }
+};
+
/**
* Returns the result of joining the provided iterable.
*
call(
arrayJoin,
[...$],
- [separator === undefined ? "," : `${separator}`],
+ [separator === UNDEFINED ? "," : `${separator}`],
);
return join;
})();
name: "rawString",
});
-export const {
- /**
- * Returns a string created from the provided code units.
- *
- * ※ This is effectively an alias for `String.fromCharCode`, but
- * with the same error behaviour as `String.fromCodePoint`.
- *
- * ☡ This function throws an error if provided with an argument which
- * is not an integral number from 0 to FFFF₁₆ inclusive.
- */
- stringFromCodeUnits,
-} = (() => {
- const { fromCharCode } = String;
- const { isInteger: isIntegralNumber } = Number;
-
- return {
- stringFromCodeUnits: defineOwnProperties(
- (...codeUnits) => {
- for (let index = 0; index < codeUnits.length; ++index) {
- // Iterate over each provided code unit and throw if it is
- // out of range.
- const nextCU = +codeUnits[index];
- if (
- !isIntegralNumber(nextCU) || nextCU < 0 || nextCU > 0xFFFF
- ) {
- // The code unit is not an integral number between 0 and
- // 0xFFFF.
- throw new RangeError(
- `Piscēs: Code unit out of range: ${nextCU}.`,
- );
- } else {
- // The code unit is acceptable.
- /* do nothing */
- }
- }
- return call(fromCharCode, undefined, codeUnits);
- },
- { name: { value: "stringFromCodeUnits" }, length: { value: 1 } },
- ),
- };
-})();
-
/**
* Returns a string created from the provided codepoints.
*