// file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
import { call, createCallableFunction } from "./function.js";
+import { canonicalNumericIndexString } from "./string.js";
import {
- canonicalNumericIndexString,
lengthOfArraylike,
sameValue,
toIndex,
getOwnPropertyDescriptors,
setPrototype,
} from "./object.js";
+import { sameValue, toLength } from "./value.js";
const RE = RegExp;
const { prototype: rePrototype } = RE;
};
})();
+/**
+ * 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
: 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 whether the provided value is an integer index string. */
+ isIntegerIndexString,
+
+ /**
+ * 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 {
+ MAX_SAFE_INTEGER: MAXIMUM_SAFE_INTEGRAL_NUMBER,
+ isInteger: isIntegralNumber,
+ isNaN: isNan,
+ } = Number;
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;
+ }
+ },
stringCatenate: defineOwnProperties(
(...args) => call(concat, "", args),
{ name: { value: "stringCatenate" }, length: { value: 2 } },
),
+ 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 } },
+ ),
};
})();
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.
*
import {
asciiLowercase,
asciiUppercase,
+ canonicalNumericIndexString,
characters,
codepoints,
codeUnits,
getCodeUnit,
getFirstSubstringIndex,
getLastSubstringIndex,
+ isIntegerIndexString,
join,
Matcher,
rawString,
});
});
+describe("canonicalNumericIndexString", () => {
+ it("[[Call]] returns undefined for nonstrings", () => {
+ assertStrictEquals(canonicalNumericIndexString(1), void {});
+ });
+
+ it("[[Call]] returns undefined for noncanonical strings", () => {
+ assertStrictEquals(canonicalNumericIndexString(""), void {});
+ assertStrictEquals(canonicalNumericIndexString("01"), void {});
+ assertStrictEquals(
+ canonicalNumericIndexString("9007199254740993"),
+ void {},
+ );
+ });
+
+ it('[[Call]] returns -0 for "-0"', () => {
+ assertStrictEquals(canonicalNumericIndexString("-0"), -0);
+ });
+
+ it("[[Call]] returns the corresponding number for canonical strings", () => {
+ assertStrictEquals(canonicalNumericIndexString("0"), 0);
+ assertStrictEquals(canonicalNumericIndexString("-0.25"), -0.25);
+ assertStrictEquals(
+ canonicalNumericIndexString("9007199254740992"),
+ 9007199254740992,
+ );
+ assertStrictEquals(canonicalNumericIndexString("NaN"), 0 / 0);
+ assertStrictEquals(canonicalNumericIndexString("Infinity"), 1 / 0);
+ assertStrictEquals(
+ canonicalNumericIndexString("-Infinity"),
+ -1 / 0,
+ );
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new canonicalNumericIndexString(""));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(canonicalNumericIndexString.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ canonicalNumericIndexString.name,
+ "canonicalNumericIndexString",
+ );
+ });
+ });
+});
+
describe("characters", () => {
it("[[Call]] returns an iterable", () => {
assertStrictEquals(
});
});
+describe("isIntegerIndexString", () => {
+ it("[[Call]] returns false for nonstrings", () => {
+ assertStrictEquals(isIntegerIndexString(1), false);
+ });
+
+ it("[[Call]] returns false for noncanonical strings", () => {
+ assertStrictEquals(isIntegerIndexString(""), false);
+ assertStrictEquals(isIntegerIndexString("01"), false);
+ assertStrictEquals(
+ isIntegerIndexString("9007199254740993"),
+ false,
+ );
+ });
+
+ it("[[Call]] returns false for nonfinite numbers", () => {
+ assertStrictEquals(isIntegerIndexString("NaN"), false);
+ assertStrictEquals(isIntegerIndexString("Infinity"), false);
+ assertStrictEquals(isIntegerIndexString("-Infinity"), false);
+ });
+
+ it("[[Call]] returns false for negative numbers", () => {
+ assertStrictEquals(isIntegerIndexString("-0"), false);
+ assertStrictEquals(isIntegerIndexString("-1"), false);
+ });
+
+ it("[[Call]] returns false for nonintegers", () => {
+ assertStrictEquals(isIntegerIndexString("0.25"), false);
+ assertStrictEquals(isIntegerIndexString("1.1"), false);
+ });
+
+ it("[[Call]] returns false for numbers greater than or equal to 2 ** 53", () => {
+ assertStrictEquals(
+ isIntegerIndexString("9007199254740992"),
+ false,
+ );
+ });
+
+ it("[[Call]] returns true for safe canonical integer strings", () => {
+ assertStrictEquals(isIntegerIndexString("0"), true);
+ assertStrictEquals(isIntegerIndexString("9007199254740991"), true);
+ });
+});
+
describe("join", () => {
it("[[Call]] joins the provided iterator with the provided separartor", () => {
assertStrictEquals(join([1, 2, 3, 4].values(), "☂"), "1☂2☂3☂4");
/** The undefined primitive. */
export const UNDEFINED = undefined;
-/**
- * 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;
- }
-};
-
/**
* Returns the length of the provided arraylike value.
*
})();
export const {
- /** Returns whether the provided value is an integer index string. */
- isIntegerIndexString,
-
/**
* Returns whether the provided values are the same value.
*
const { floor, max, min } = Math;
const {
MAX_SAFE_INTEGER: MAXIMUM_SAFE_INTEGRAL_NUMBER,
- isInteger: isIntegralNumber,
isNaN: isNan,
} = Number;
const { is } = Object;
return {
- 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;
- }
- },
sameValue: (a, b) => is(a, b),
sameValueZero: ($1, $2) => {
const type1 = type($1);
} from "./dev-deps.js";
import {
ASYNC_ITERATOR,
- canonicalNumericIndexString,
HAS_INSTANCE,
IS_CONCAT_SPREADABLE,
- isIntegerIndexString,
ITERATOR,
lengthOfArraylike,
MATCH,
});
});
-describe("canonicalNumericIndexString", () => {
- it("[[Call]] returns undefined for nonstrings", () => {
- assertStrictEquals(canonicalNumericIndexString(1), void {});
- });
-
- it("[[Call]] returns undefined for noncanonical strings", () => {
- assertStrictEquals(canonicalNumericIndexString(""), void {});
- assertStrictEquals(canonicalNumericIndexString("01"), void {});
- assertStrictEquals(
- canonicalNumericIndexString("9007199254740993"),
- void {},
- );
- });
-
- it('[[Call]] returns -0 for "-0"', () => {
- assertStrictEquals(canonicalNumericIndexString("-0"), -0);
- });
-
- it("[[Call]] returns the corresponding number for canonical strings", () => {
- assertStrictEquals(canonicalNumericIndexString("0"), 0);
- assertStrictEquals(canonicalNumericIndexString("-0.25"), -0.25);
- assertStrictEquals(
- canonicalNumericIndexString("9007199254740992"),
- 9007199254740992,
- );
- assertStrictEquals(canonicalNumericIndexString("NaN"), 0 / 0);
- assertStrictEquals(canonicalNumericIndexString("Infinity"), 1 / 0);
- assertStrictEquals(
- canonicalNumericIndexString("-Infinity"),
- -1 / 0,
- );
- });
-
- it("[[Construct]] throws an error", () => {
- assertThrows(() => new canonicalNumericIndexString(""));
- });
-
- describe(".length", () => {
- it("[[Get]] returns the correct length", () => {
- assertStrictEquals(canonicalNumericIndexString.length, 1);
- });
- });
-
- describe(".name", () => {
- it("[[Get]] returns the correct name", () => {
- assertStrictEquals(
- canonicalNumericIndexString.name,
- "canonicalNumericIndexString",
- );
- });
- });
-});
-
-describe("isIntegerIndexString", () => {
- it("[[Call]] returns false for nonstrings", () => {
- assertStrictEquals(isIntegerIndexString(1), false);
- });
-
- it("[[Call]] returns false for noncanonical strings", () => {
- assertStrictEquals(isIntegerIndexString(""), false);
- assertStrictEquals(isIntegerIndexString("01"), false);
- assertStrictEquals(
- isIntegerIndexString("9007199254740993"),
- false,
- );
- });
-
- it("[[Call]] returns false for nonfinite numbers", () => {
- assertStrictEquals(isIntegerIndexString("NaN"), false);
- assertStrictEquals(isIntegerIndexString("Infinity"), false);
- assertStrictEquals(isIntegerIndexString("-Infinity"), false);
- });
-
- it("[[Call]] returns false for negative numbers", () => {
- assertStrictEquals(isIntegerIndexString("-0"), false);
- assertStrictEquals(isIntegerIndexString("-1"), false);
- });
-
- it("[[Call]] returns false for nonintegers", () => {
- assertStrictEquals(isIntegerIndexString("0.25"), false);
- assertStrictEquals(isIntegerIndexString("1.1"), false);
- });
-
- it("[[Call]] returns false for numbers greater than or equal to 2 ** 53", () => {
- assertStrictEquals(
- isIntegerIndexString("9007199254740992"),
- false,
- );
- });
-
- it("[[Call]] returns true for safe canonical integer strings", () => {
- assertStrictEquals(isIntegerIndexString("0"), true);
- assertStrictEquals(isIntegerIndexString("9007199254740991"), true);
- });
-});
-
describe("lengthOfArraylike", () => {
it("[[Call]] returns the length", () => {
assertStrictEquals(