stringFromCodeUnits,
stringReplace,
} from "./string.js";
+import { ITERATOR } from "./value.js";
const Buffer = ArrayBuffer;
const View = DataView;
const TypedArray = Object.getPrototypeOf(Uint8Array);
const { prototype: arrayPrototype } = Array;
const { prototype: bufferPrototype } = Buffer;
-const { iterator: iteratorSymbol } = Symbol;
+const { prototype: sharedBufferPrototype } = SharedArrayBuffer;
const { prototype: rePrototype } = RegExp;
const { prototype: typedArrayPrototype } = TypedArray;
const { prototype: viewPrototype } = View;
-const { [iteratorSymbol]: arrayIterator } = arrayPrototype;
+const { [ITERATOR]: arrayIterator } = arrayPrototype;
const {
next: arrayIteratorNext,
-} = Object.getPrototypeOf([][iteratorSymbol]());
+} = Object.getPrototypeOf([][ITERATOR]());
const argumentIterablePrototype = {
- [iteratorSymbol]() {
+ [ITERATOR]() {
return {
next: bind(
arrayIteratorNext,
},
};
const binaryCodeUnitIterablePrototype = {
- [iteratorSymbol]() {
+ [ITERATOR]() {
return {
next: bind(
arrayIteratorNext,
},
};
+const { exec: reExec } = rePrototype;
+const { slice: bufferSlice } = bufferPrototype;
const getBufferByteLength =
Object.getOwnPropertyDescriptor(bufferPrototype, "byteLength").get;
+const { slice: sharedBufferSlice } = sharedBufferPrototype;
+const getSharedBufferByteLength =
+ Object.getOwnPropertyDescriptor(sharedBufferPrototype, "byteLength")
+ .get;
const getTypedArrayBuffer =
Object.getOwnPropertyDescriptor(typedArrayPrototype, "buffer").get;
+const getTypedArrayByteLength =
+ Object.getOwnPropertyDescriptor(typedArrayPrototype, "byteLength")
+ .get;
+const getTypedArrayByteOffset =
+ Object.getOwnPropertyDescriptor(typedArrayPrototype, "byteOffset")
+ .get;
const getViewBuffer =
Object.getOwnPropertyDescriptor(viewPrototype, "buffer").get;
-const { exec: reExec } = rePrototype;
+const getViewByteLength =
+ Object.getOwnPropertyDescriptor(viewPrototype, "byteLength").get;
+const getViewByteOffset =
+ Object.getOwnPropertyDescriptor(viewPrototype, "byteOffset").get;
const {
+ getBigInt64: viewGetInt64,
+ getBigUint64: viewGetUint64,
+ getFloat32: viewGetFloat32,
+ getFloat64: viewGetFloat64,
+ getInt8: viewGetInt8,
+ getInt16: viewGetInt16,
+ getInt32: viewGetInt32,
getUint8: viewGetUint8,
+ getUint16: viewGetUint16,
+ getUint32: viewGetUint32,
+ setFloat32: viewSetFloat32,
+ setFloat64: viewSetFloat64,
setUint8: viewSetUint8,
setUint16: viewSetUint16,
+ setUint32: viewSetUint32,
+ setBigUint64: viewSetUint64,
} = viewPrototype;
/**
* Returns an ArrayBuffer for encoding generated from the provided
* arguments.
*/
-const bufferFromArgs = ($, $s) =>
- $ instanceof Buffer
- ? $
- : $ instanceof View
- ? call(getViewBuffer, $, [])
- : $ instanceof TypedArray
- ? call(getTypedArrayBuffer, $, [])
- : ((string) =>
+const bufferFromArgs = ($, $s) => {
+ try {
+ // Try just getting the array buffer associated with the first
+ // argument and returning it if possible.
+ return toArrayBuffer($);
+ } catch {
+ // There is no array buffer associated with the first argument.
+ //
+ // Construct a string and convert it to an array buffer instead.
+ return ((string) =>
call(
getViewBuffer,
reduce(
),
[],
))(
- typeof $ == "string"
+ typeof $ === "string"
? $
: hasOwnProperty($, "raw")
? rawString(
)
: `${$}`,
);
+ }
+};
/**
* Returns the result of decoding the provided base16 string into an
? code - 87
: -1;
if (result < 0) {
+ // The source contains an invalid character.
throw new RangeError(
`Piscēs: Invalid character in Base64: ${ucsCharacter}.`,
);
} else {
+ // The source contains a valid character with a recognized
+ // mapping.
return result;
}
},
);
const { length } = u4s;
- if (length % 2 == 1) {
+ if (length % 2 === 1) {
// The length is such that an entire letter would be dropped during
// a forgiving decode.
throw new RangeError(
// Every letter contributes at least some bits to the result.
const dataView = new View(new Buffer(floor(length / 2)));
for (let index = 0; index < length - 1;) {
+ // Iterate over the characters and assign their bits to the
+ // buffer.
call(viewSetUint8, dataView, [
floor(index / 2),
(u4s[index] << 4) | u4s[++index, index++],
const u5s = map(
wrmg
? stringReplace(source, /-/gu, "")
- : source.length % 8 == 0
+ : source.length % 8 === 0
? stringReplace(source, /(?:=|={3,4}|={6})$/u, "")
: source,
(ucsCharacter) => {
? code - 48
: code >= 0x41 && code <= 0x48
? code - 55
- : code == 0x49
+ : code === 0x49
? 1 // I
: code >= 0x4A && code <= 0x4B
? code - 56
- : code == 0x4C
+ : code === 0x4C
? 1 // L
: code >= 0x4D && code <= 0x4E
? code - 57
- : code == 0x4F
+ : code === 0x4F
? 0 // O
: code >= 0x50 && code <= 0x54
? code - 58
? code - 59
: code >= 0x61 && code <= 0x68
? code - 87
- : code == 0x69
+ : code === 0x69
? 1 // i
: code >= 0x6A && code <= 0x6B
? code - 88
- : code == 0x6C
+ : code === 0x6C
? 1 // l
: code >= 0x6D && code <= 0x6E
? code - 89
- : code == 0x6F
+ : code === 0x6F
? 0 // o
: code >= 0x70 && code <= 0x74
? code - 90
? code - 24 // digits 2–7 map to 26–31
: -1;
if (result < 0) {
+ // The source contains an invalid character.
throw new RangeError(
`Piscēs: Invalid character in Base32: ${ucsCharacter}.`,
);
} else {
+ // The source contains a valid character with a recognized
+ // mapping.
return result;
}
},
);
const { length } = u5s;
const lengthMod8 = length % 8;
- if (lengthMod8 == 1 || lengthMod8 == 3 || lengthMod8 == 6) {
+ if (lengthMod8 === 1 || lengthMod8 === 3 || lengthMod8 === 6) {
// The length is such that an entire letter would be dropped during
// a forgiving decode.
throw new RangeError(
// Every letter contributes at least some bits to the result.
const dataView = new View(new Buffer(floor(length * 5 / 8)));
for (let index = 0; index < length - 1;) {
+ // Iterate over the characters and assign their bits to the
+ // buffer.
+ //
// The final index is not handled; if the string is not divisible
// by 8, some bits might be dropped. This matches the “forgiving
// decode” behaviour specified by WhatW·G for base64.
const dataIndex = ceil(index * 5 / 8);
const remainder = index % 8;
- if (remainder == 0) {
- call(viewSetUint8, dataView, [
- dataIndex,
- u5s[index] << 3 | u5s[++index] >> 2,
- ]);
- } else if (remainder == 1) {
- call(viewSetUint8, dataView, [
- dataIndex,
- u5s[index] << 6 | u5s[++index] << 1 | u5s[++index] >> 4,
- ]);
- } else if (remainder == 3) {
- call(viewSetUint8, dataView, [
- dataIndex,
- u5s[index] << 4 | u5s[++index] >> 1,
- ]);
- } else if (remainder == 4) {
- call(viewSetUint8, dataView, [
- dataIndex,
- u5s[index] << 7 | u5s[++index] << 2 | u5s[++index] >> 3,
- ]);
- } else { // remainder == 6
- call(viewSetUint8, dataView, [
- dataIndex,
- u5s[index] << 5 | u5s[++index, index++],
- ]);
- }
+ call(viewSetUint8, dataView, [
+ dataIndex,
+ remainder === 0
+ ? u5s[index] << 3 | u5s[++index] >> 2
+ : remainder === 1
+ ? u5s[index] << 6 | u5s[++index] << 1 | u5s[++index] >> 4
+ : remainder === 3
+ ? u5s[index] << 4 | u5s[++index] >> 1
+ : remainder === 4
+ ? u5s[index] << 7 | u5s[++index] << 2 | u5s[++index] >> 3
+ : u5s[index] << 5 | u5s[++index, index++], // remainder === 6
+ ]);
}
return call(getViewBuffer, dataView, []);
}
*/
const decodeBase64 = (source, safe = false) => {
const u6s = map(
- source.length % 4 == 0
+ source.length % 4 === 0
? stringReplace(source, /={1,2}$/u, "")
: source,
(ucsCharacter) => {
? code - 71
: code >= 0x30 && code <= 0x39
? code + 4
- : code == (safe ? 0x2D : 0x2B)
+ : code === (safe ? 0x2D : 0x2B)
? 62
- : code == (safe ? 0x5F : 0x2F)
+ : code === (safe ? 0x5F : 0x2F)
? 63
: -1;
if (result < 0) {
+ // The source contains an invalid character.
throw new RangeError(
`Piscēs: Invalid character in Base64: ${ucsCharacter}.`,
);
} else {
+ // The source contains a valid character with a recognized
+ // mapping.
return result;
}
},
);
const { length } = u6s;
- if (length % 4 == 1) {
+ if (length % 4 === 1) {
// The length is such that an entire letter would be dropped during
// a forgiving decode.
throw new RangeError(
// Every letter contributes at least some bits to the result.
const dataView = new View(new Buffer(floor(length * 3 / 4)));
for (let index = 0; index < length - 1;) {
+ // Iterate over the characters and assign their bits to the
+ // buffer.
+ //
// The final index is not handled; if the string is not divisible
// by 4, some bits might be dropped. This matches the “forgiving
// decode” behaviour specified by WhatW·G for base64.
const dataIndex = ceil(index * 3 / 4);
const remainder = index % 4;
- if (remainder == 0) {
- call(viewSetUint8, dataView, [
- dataIndex,
- u6s[index] << 2 | u6s[++index] >> 4,
- ]);
- } else if (remainder == 1) {
- call(viewSetUint8, dataView, [
- dataIndex,
- u6s[index] << 4 | u6s[++index] >> 2,
- ]);
- } else { // remainder == 2
- call(viewSetUint8, dataView, [
- dataIndex,
- u6s[index] << 6 | u6s[++index, index++],
- ]);
- }
+ call(viewSetUint8, dataView, [
+ dataIndex,
+ remainder === 0
+ ? u6s[index] << 2 | u6s[++index] >> 4
+ : remainder === 1
+ ? u6s[index] << 4 | u6s[++index] >> 2
+ : u6s[index] << 6 | u6s[++index, index++], // remainder === 2
+ ]);
}
return call(getViewBuffer, dataView, []);
}
0x3D,
);
for (let index = 0; index < byteLength;) {
+ // Iterate over the bytes and generate code units for them.
const codeUnitIndex = index * 2;
const datum = call(viewGetUint8, dataView, [index++]);
const u4s = [datum >> 4, datum & 0xF];
for (let u4i = 0; u4i < 2; ++u4i) {
+ // Handle the high four bits, then the low four bits.
const u4 = u4s[u4i];
const result = u4 < 10 ? u4 + 48 : u4 < 16 ? u4 + 55 : -1;
if (result < 0) {
+ // No mapping exists for these four bits.
+ //
+ // ※ This shouldn’t be possible!
throw new RangeError(
`Piscēs: Unexpected Base16 value: ${u4}.`,
);
} else {
+ // A mapping exists for the bits.
resultingCodeUnits[codeUnitIndex + u4i] = result;
}
}
fillByte,
);
for (let index = 0; index < byteLength;) {
+ // Iterate over the bytes and generate code units for them.
const codeUnitIndex = ceil(index * 8 / 5);
const currentIndex = codeUnitIndex + +(
0b01011 & 1 << index % 5 &&
// digits 1, 3, 4 & 6 span multiple bytes
? call(viewGetUint8, dataView, [index])
: 0;
- const u5 = remainder == 0
+ const u5 = remainder === 0
? currentByte >> 3
- : remainder == 1
+ : remainder === 1
? (currentByte & 0b00000111) << 2 | nextByte >> 6
- : remainder == 2
+ : remainder === 2
? (currentByte & 0b00111111) >> 1
- : remainder == 3
+ : remainder === 3
? (currentByte & 0b00000001) << 4 | nextByte >> 4
- : remainder == 4
+ : remainder === 4
? (currentByte & 0b00001111) << 1 | nextByte >> 7
- : remainder == 5
+ : remainder === 5
? (currentByte & 0b01111111) >> 2
- : remainder == 6
+ : remainder === 6
? (currentByte & 0b00000011) << 3 | nextByte >> 5
- : (++index, currentByte & 0b00011111); // remainder == 7
+ : (++index, currentByte & 0b00011111); // remainder === 7
const result = wrmg
? u5 < 10 ? u5 + 48 : u5 < 18
? u5 + 55
? u5 + 24
: -1;
if (result < 0) {
+ // No mapping exists for these five bits.
+ //
+ // ※ This shouldn’t be possible!
throw new RangeError(`Piscēs: Unexpected Base32 value: ${u5}.`);
} else {
+ // A mapping exists for the bits.
resultingCodeUnits[currentIndex] = result;
}
}
0x3D,
);
for (let index = 0; index < byteLength;) {
+ // Iterate over the bytes and generate code units for them.
const codeUnitIndex = ceil(index * 4 / 3);
const currentIndex = codeUnitIndex + +(
- index % 3 == 0 && resultingCodeUnits[codeUnitIndex] != 0x3D
+ index % 3 === 0 && resultingCodeUnits[codeUnitIndex] != 0x3D
); // every third byte handles two letters; this is for the second
const remainder = currentIndex % 4;
const currentByte = call(viewGetUint8, dataView, [index]);
// digits 1 & 2 span multiple bytes
? call(viewGetUint8, dataView, [index])
: 0;
- const u6 = remainder == 0
+ const u6 = remainder === 0
? currentByte >> 2
- : remainder == 1
+ : remainder === 1
? (currentByte & 0b00000011) << 4 | nextByte >> 4
- : remainder == 2
+ : remainder === 2
? (currentByte & 0b00001111) << 2 | nextByte >> 6
- : (++index, currentByte & 0b00111111); // remainder == 3
+ : (++index, currentByte & 0b00111111); // remainder === 3
const result = u6 < 26
? u6 + 65
: u6 < 52
? (safe ? 0x5F : 0x2F)
: -1;
if (result < 0) {
+ // No mapping exists for these six bits.
+ //
+ // ※ This shouldn’t be possible!
throw new RangeError(`Piscēs: Unexpected Base64 value: ${u6}.`);
} else {
+ // A mapping exists for the bits.
resultingCodeUnits[currentIndex] = result;
}
}
*/
const sourceFromArgs = ($, $s) =>
stringReplace(
- typeof $ == "string" ? $ : hasOwnProperty($, "raw")
+ typeof $ === "string" ? $ : hasOwnProperty($, "raw")
? rawString(
$,
...objectCreate(argumentIterablePrototype, {
"",
);
+/**
+ * Returns a slice of the provided value according to the algorithm of
+ * `ArrayBuffer::slice` (or `SharedArrayBuffer::slice`).
+ *
+ * ☡ This function throws if the provided value is not an array buffer.
+ */
+export const arrayBufferSlice = ($, start, end, ...args) =>
+ call(
+ isSharedArrayBuffer($) ? sharedBufferSlice : bufferSlice,
+ $,
+ [
+ start,
+ end,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ],
+ );
+
/**
* Returns an ArrayBuffer generated from the provided base16 string.
*
export const filenameSafeBase64String = ($, ...$s) =>
encodeBase64(bufferFromArgs($, $s), true);
+export const {
+ /**
+ * Returns the signed 8‐bit integral value in the provided array
+ * buffer or array buffer view at the provided byte offset.
+ *
+ * ※ The retrieved value will be big·endian unless a third argument
+ * is specified and truthy.
+ *
+ * ※ This is similar to `DataView::getInt8`, but works on all array
+ * buffers and array buffer views and returns a big·int.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ get8BitSignedIntegralItem,
+
+ /**
+ * Returns the unsigned 8‐bit integral value in the provided array
+ * buffer or array buffer view at the provided byte offset.
+ *
+ * ※ The retrieved value will be big·endian unless a third argument
+ * is specified and truthy.
+ *
+ * ※ This is similar to `DataView::getUint8`, but works on all array
+ * buffers and array buffer views and returns a big·int.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ get8BitUnsignedIntegralItem,
+
+ /**
+ * Returns the signed 16‐bit integral value in the provided array
+ * buffer or array buffer view at the provided byte offset.
+ *
+ * ※ The retrieved value will be big·endian unless a third argument
+ * is specified and truthy.
+ *
+ * ※ This is similar to `DataView::getInt16`, but works on all array
+ * buffers and array buffer views and returns a big·int.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ get16BitSignedIntegralItem,
+
+ /**
+ * Returns the unsigned 16‐bit integral value in the provided array
+ * buffer or array buffer view at the provided byte offset.
+ *
+ * ※ The retrieved value will be big·endian unless a third argument
+ * is specified and truthy.
+ *
+ * ※ This is similar to `DataView::getUint16`, but works on all
+ * array buffers and array buffer views and returns a big·int.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ get16BitUnsignedIntegralItem,
+
+ /**
+ * Returns the 32‐bit floating point value in the provided array
+ * buffer or array buffer view at the provided byte offset.
+ *
+ * ※ The retrieved value will be big·endian unless a third argument
+ * is specified and truthy.
+ *
+ * ※ This is similar to `DataView::getFloat32`, but works on all
+ * array buffers and array buffer views.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ get32BitFloatingPointItem,
+
+ /**
+ * Returns the signed 32‐bit integral value in the provided array
+ * buffer or array buffer view at the provided byte offset.
+ *
+ * ※ The retrieved value will be big·endian unless a third argument
+ * is specified and truthy.
+ *
+ * ※ This is similar to `DataView::getInt32`, but works on all array
+ * buffers and array buffer views and returns a big·int.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ get32BitSignedIntegralItem,
+
+ /**
+ * Returns the unsigned 32‐bit integral value in the provided array
+ * buffer or array buffer view at the provided byte offset.
+ *
+ * ※ The retrieved value will be big·endian unless a third argument
+ * is specified and truthy.
+ *
+ * ※ This is similar to `DataView::getUint32`, but works on all
+ * array buffers and array buffer views and returns a big·int.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ get32BitUnsignedIntegralItem,
+
+ /**
+ * Returns the 64‐bit floating point value in the provided array
+ * buffer or array buffer view at the provided byte offset.
+ *
+ * ※ The retrieved value will be big·endian unless a third argument
+ * is specified and truthy.
+ *
+ * ※ This is similar to `DataView::getFloat64`, but works on all
+ * array buffers and array buffer views.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ get64BitFloatingPointItem,
+
+ /**
+ * Returns the signed 64‐bit integral value in the provided array
+ * buffer or array buffer view at the provided byte offset.
+ *
+ * ※ The retrieved value will be big·endian unless a third argument
+ * is specified and truthy.
+ *
+ * ※ This is similar to `DataView::getBigInt64`, but works on all
+ * array buffers and array buffer views.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ get64BitSignedIntegralItem,
+
+ /**
+ * Returns the unsigned 64‐bit integral value in the provided array
+ * buffer or array buffer view at the provided byte offset.
+ *
+ * ※ The retrieved value will be big·endian unless a third argument
+ * is specified and truthy.
+ *
+ * ※ This is similar to `DataView::getBigUint64`, but works on all
+ * array buffers and array buffer views.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ get64BitUnsignedIntegralItem,
+
+ /**
+ * Sets the 8‐bit integral value in the provided array buffer or
+ * array buffer view at the provided byte offset to the provided
+ * value.
+ *
+ * ※ The value will be set as big·endian unless a fourth argument is
+ * specified and truthy.
+ *
+ * ※ This is similar to `DataView::setInt8`, but works on all array
+ * buffers and array buffer views and accepts both numeric and
+ * big·int values.
+ *
+ * ※ It doesn’t matter whether the provided value is signed or
+ * unsigned, as the algorithm will cast one to the other.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ set8BitIntegralItem,
+
+ /**
+ * Sets the 16‐bit integral value in the provided array buffer or
+ * array buffer view at the provided byte offset to the provided
+ * value.
+ *
+ * ※ The value will be set as big·endian unless a fourth argument is
+ * specified and truthy.
+ *
+ * ※ This is similar to `DataView::setInt16`, but works on all array
+ * buffers and array buffer views and accepts both numeric and
+ * big·int values.
+ *
+ * ※ It doesn’t matter whether the provided value is signed or
+ * unsigned, as the algorithm will cast one to the other.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ set16BitIntegralItem,
+
+ /**
+ * Sets the 32‐bit floating point value in the provided array buffer
+ * or array buffer view at the provided byte offset to the provided
+ * value.
+ *
+ * ※ The value will be set as big·endian unless a fourth argument is
+ * specified and truthy.
+ *
+ * ※ This is similar to `DataView::setFloat32`, but works on all
+ * array buffers and array buffer views.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ set32BitFloatingPointItem,
+
+ /**
+ * Sets the 32‐bit integral value in the provided array buffer or
+ * array buffer view at the provided byte offset to the provided
+ * value.
+ *
+ * ※ The value will be set as big·endian unless a fourth argument is
+ * specified and truthy.
+ *
+ * ※ This is similar to `DataView::setInt32`, but works on all array
+ * buffers and array buffer views and accepts both numeric and
+ * big·int values.
+ *
+ * ※ It doesn’t matter whether the provided value is signed or
+ * unsigned, as the algorithm will cast one to the other.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ set32BitIntegralItem,
+
+ /**
+ * Sets the 64‐bit floating point value in the provided array buffer
+ * or array buffer view at the provided byte offset to the provided
+ * value.
+ *
+ * ※ The value will be set as big·endian unless a fourth argument is
+ * specified and truthy.
+ *
+ * ※ This is similar to `DataView::setFloat64`, but works on all
+ * array buffers and array buffer views.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ set64BitFloatingPointItem,
+
+ /**
+ * Sets the 64‐bit integral value in the provided array buffer or
+ * array buffer view at the provided byte offset to the provided
+ * value.
+ *
+ * ※ The value will be set as big·endian unless a fourth argument is
+ * specified and truthy.
+ *
+ * ※ This is similar to `DataView::setInt32`, but works on all array
+ * buffers and array buffer views.
+ *
+ * ※ It doesn’t matter whether the provided value is signed or
+ * unsigned, as the algorithm will cast one to the other.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array, or if the third argument is not
+ * a big·int.
+ */
+ set64BitIntegralItem,
+} = (() => {
+ const makeBigInt = BigInt;
+ const { asUintN } = BigInt;
+ const makeNumber = Number;
+
+ const viewMap = new WeakMap();
+ const view = ($) => {
+ const buffer = toArrayBuffer($);
+ if (viewMap.has(buffer)) {
+ // A view has already been allocated for this buffer; use it.
+ return viewMap.get(buffer);
+ } else {
+ // No view has been created for this buffer yet.
+ const result = new View(buffer);
+ viewMap.set(buffer, result);
+ return result;
+ }
+ };
+
+ return {
+ get8BitSignedIntegralItem: ($, byteOffset, ...args) =>
+ makeBigInt(
+ call(viewGetInt8, view($), [
+ getByteOffset($) + byteOffset,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ ),
+ get8BitUnsignedIntegralItem: ($, byteOffset, ...args) =>
+ makeBigInt(
+ call(viewGetUint8, view($), [
+ getByteOffset($) + byteOffset,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ ),
+ get16BitSignedIntegralItem: ($, byteOffset, ...args) =>
+ makeBigInt(
+ call(viewGetInt16, view($), [
+ getByteOffset($) + byteOffset,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ ),
+ get16BitUnsignedIntegralItem: ($, byteOffset, ...args) =>
+ makeBigInt(
+ call(viewGetUint16, view($), [
+ getByteOffset($) + byteOffset,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ ),
+ get32BitFloatingPointItem: ($, byteOffset, ...args) =>
+ call(viewGetFloat32, view($), [
+ getByteOffset($) + byteOffset,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ get32BitSignedIntegralItem: ($, byteOffset, ...args) =>
+ makeBigInt(
+ call(viewGetInt32, view($), [
+ getByteOffset($) + byteOffset,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ ),
+ get32BitUnsignedIntegralItem: ($, byteOffset, ...args) =>
+ makeBigInt(
+ call(viewGetUint32, view($), [
+ getByteOffset($) + byteOffset,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ ),
+ get64BitFloatingPointItem: ($, byteOffset, ...args) =>
+ call(viewGetFloat64, view($), [
+ getByteOffset($) + byteOffset,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ get64BitSignedIntegralItem: ($, byteOffset, ...args) =>
+ call(viewGetInt64, view($), [
+ getByteOffset($) + byteOffset,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ get64BitUnsignedIntegralItem: ($, byteOffset, ...args) =>
+ call(viewGetUint64, view($), [
+ getByteOffset($) + byteOffset,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ set8BitIntegralItem: ($, byteOffset, value, ...args) =>
+ call(viewSetUint8, view($), [
+ getByteOffset($) + byteOffset,
+ makeNumber(value),
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ set16BitIntegralItem: ($, byteOffset, value, ...args) =>
+ call(viewSetUint16, view($), [
+ getByteOffset($) + byteOffset,
+ makeNumber(value),
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ set32BitFloatingPointItem: ($, byteOffset, value, ...args) =>
+ call(viewSetFloat32, view($), [
+ getByteOffset($) + byteOffset,
+ value,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ set32BitIntegralItem: ($, byteOffset, value, ...args) =>
+ call(viewSetUint32, view($), [
+ getByteOffset($) + byteOffset,
+ makeNumber(value),
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ set64BitFloatingPointItem: ($, byteOffset, value, ...args) =>
+ call(viewSetFloat64, view($), [
+ getByteOffset($) + byteOffset,
+ value,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ set64BitIntegralItem: ($, byteOffset, value, ...args) =>
+ call(viewSetUint64, view($), [
+ getByteOffset($) + byteOffset,
+ asUintN(64, value),
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ };
+})();
+
+/**
+ * Returns the byte length for the provided array buffer or array
+ * buffer view.
+ *
+ * ☡ This function throws if the provided value is not an array buffer,
+ * data view, or typed array.
+ */
+export const getByteLength = ($) => {
+ try {
+ // Attempt to get the byte length from the provided value as an
+ // `ArrayBuffer`.
+ return call(getBufferByteLength, $, []);
+ } catch {
+ // The provided value is not an `ArrayBuffer`.
+ /* do nothing */
+ }
+ try {
+ // Attempt to get the byte length from the provided value as a
+ // `SharedArrayBuffer`.
+ return call(getSharedBufferByteLength, $, []);
+ } catch {
+ // The provided value is not a `SharedArrayBuffer`.
+ /* do nothing */
+ }
+ try {
+ // Attempt to get the byte length from the provided value as a
+ // data view.
+ return call(getViewByteLength, $, []);
+ } catch {
+ // The provided value is not a data view.
+ /* do nothing */
+ }
+ try {
+ // Attempt to get the byte length from the provided value as a
+ // typed array.
+ return call(getTypedArrayByteLength, $, []);
+ } catch {
+ // The provided value is not a typed array.
+ /* do nothing */
+ }
+ throw new TypeError(`Piscēs: Not an array buffer or view: ${$}.`);
+};
+
+/**
+ * Returns the byte offset for the provided array buffer or array
+ * buffer view.
+ *
+ * ※ This function always returns `0` for array buffers.
+ *
+ * ☡ This function throws if the provided value is not an array buffer,
+ * data view, or typed array.
+ */
+export const getByteOffset = ($) => {
+ if (isArrayBuffer($)) {
+ // The provided value is an array buffer.
+ return 0;
+ } else {
+ try {
+ // Attempt to get the byte offset from the provided value as a
+ // data view.
+ return call(getViewByteOffset, $, []);
+ } catch {
+ // The provided value is not a data view.
+ /* do nothing */
+ }
+ try {
+ // Attempt to get the byte offset from the provided value as a
+ // typed array.
+ return call(getTypedArrayByteOffset, $, []);
+ } catch {
+ // The provided value is not a typed array.
+ /* do nothing */
+ }
+ throw new TypeError(`Piscēs: Not an array buffer or view: ${$}.`);
+ }
+};
+
+/**
+ * Returns whether the provided value is a view on an underlying array
+ * buffer.
+ *
+ * ※ This function returns true for typed arrays and data views.
+ */
+export const { isView: isArrayBufferView } = Buffer;
+
+/**
+ * Returns whether the provided value is an array buffer.
+ *
+ * ※ This function returns true for both `ArrayBuffer`s and
+ * `SharedArrayBuffer`s.
+ */
+export const isArrayBuffer = ($) => {
+ try {
+ // Try to see if the provided argument has array buffer internal
+ // slots and return true if so.
+ return call(getBufferByteLength, $, []), true;
+ } catch {
+ // The provided argument does not have array buffer internal slots.
+ /* do nothing */
+ }
+ try {
+ // Try to see if the provided argument has array buffer internal
+ // slots and return true if so.
+ return call(getSharedBufferByteLength, $, []), true;
+ } catch {
+ // The provided argument does not have array buffer internal slots.
+ /* do nothing */
+ }
+ return false;
+};
+
/**
* Returns whether the provided value is a base16 string.
*
*/
export const isBase16 = ($) => {
if (typeof $ !== "string") {
+ // The provided value is not a string.
return false;
} else {
+ // The provided value is a string.
const source = stringReplace($, /[\t\n\f\r ]+/gu, "");
- return source.length % 2 != 1 &&
- call(reExec, /[^0-9A-F]/iu, [source]) == null;
+ return source.length % 2 !== 1 &&
+ call(reExec, /[^0-9A-F]/iu, [source]) === null;
}
};
*/
export const isBase32 = ($) => {
if (typeof $ !== "string") {
+ // The provided value is not a string.
return false;
} else {
+ // The provided value is a string.
const source = stringReplace($, /[\t\n\f\r ]+/gu, "");
- const trimmed = source.length % 8 == 0
+ const trimmed = source.length % 8 === 0
? stringReplace(source, /(?:=|={3,4}|={6})$/u, "")
: source;
- return trimmed.length % 8 != 1 &&
- call(reExec, /[^2-7A-Z/]/iu, [trimmed]) == null;
+ return trimmed.length % 8 !== 1 &&
+ call(reExec, /[^2-7A-Z/]/iu, [trimmed]) === null;
}
};
*/
export const isBase64 = ($) => {
if (typeof $ !== "string") {
+ // The provided value is not a string.
return false;
} else {
+ // The provided value is a string.
const source = stringReplace($, /[\t\n\f\r ]+/gu, "");
- const trimmed = source.length % 4 == 0
+ const trimmed = source.length % 4 === 0
? stringReplace(source, /={1,2}$/u, "")
: source;
- return trimmed.length % 4 != 1 &&
- call(reExec, /[^0-9A-Za-z+\/]/u, [trimmed]) == null;
+ return trimmed.length % 4 !== 1 &&
+ call(reExec, /[^0-9A-Za-z+\/]/u, [trimmed]) === null;
}
};
*/
export const isFilenameSafeBase64 = ($) => {
if (typeof $ !== "string") {
+ // The provided value is not a string.
return false;
} else {
+ // The provided value is a string.
const source = stringReplace($, /[\t\n\f\r ]+/gu, "");
- const trimmed = source.length % 4 == 0
+ const trimmed = source.length % 4 === 0
? stringReplace(source, /={1,2}$/u, "")
: source;
- return trimmed.length % 4 != 1 &&
- call(reExec, /[^0-9A-Za-z_-]/u, [trimmed]) == null;
+ return trimmed.length % 4 !== 1 &&
+ call(reExec, /[^0-9A-Za-z_-]/u, [trimmed]) === null;
+ }
+};
+
+/** Returns whether the provided value is a shared array buffer. */
+export const isSharedArrayBuffer = ($) => {
+ try {
+ // Try to see if the provided argument has shared array buffer
+ // internal slots and return true if so.
+ return call(getSharedBufferByteLength, $, []), true;
+ } catch {
+ // The provided argument does not have data view internal slots.
+ return false;
+ }
+};
+
+/** Returns whether the provided value is a typed array. */
+export const isTypedArray = ($) => {
+ try {
+ // Try to see if the provided argument has typed array internal
+ // slots and return true if so.
+ return call(getTypedArrayBuffer, $, []), true;
+ } catch {
+ // The provided argument does not have typed array internal slots.
+ return false;
}
};
*/
export const isWRMGBase32 = ($) => {
if (typeof $ !== "string") {
+ // The provided value is not a string.
return false;
} else {
+ // The provided value is a string.
const source = stringReplace($, /[\t\n\f\r ]+/gu, "");
const trimmed = stringReplace(source, /-/gu, "");
- return trimmed.length % 8 != 1 &&
- call(reExec, /[^0-9A-TV-Z]/iu, [trimmed]) == null;
+ return trimmed.length % 8 !== 1 &&
+ call(reExec, /[^0-9A-TV-Z]/iu, [trimmed]) === null;
+ }
+};
+
+/**
+ * Returns the array buffer associated with the provided object.
+ *
+ * ☡ This function throws if the provided object is not a data view or
+ * typed array.
+ */
+export const toArrayBuffer = ($) => {
+ if (isArrayBuffer($)) {
+ // The provided argument has array buffer internal slots.
+ return $;
+ } else {
+ // The provided argument does not have array buffer internal slots.
+ try {
+ // The provided argument has typed array internal slots.
+ return call(getTypedArrayBuffer, $, []);
+ } catch {
+ /* do nothing */
+ }
+ try {
+ // The provided argument has data view internal slots.
+ return call(getViewBuffer, $, []);
+ } catch {
+ /* do nothing */
+ }
+ throw new TypeError(`Piscēs: Not an array buffer or view: ${$}.`);
}
};
it,
} from "./dev-deps.js";
import {
+ arrayBufferSlice,
base16Binary,
base16String,
base32Binary,
base64String,
filenameSafeBase64Binary,
filenameSafeBase64String,
+ get16BitSignedIntegralItem,
+ get16BitUnsignedIntegralItem,
+ get32BitFloatingPointItem,
+ get32BitSignedIntegralItem,
+ get32BitUnsignedIntegralItem,
+ get64BitFloatingPointItem,
+ get64BitSignedIntegralItem,
+ get64BitUnsignedIntegralItem,
+ get8BitSignedIntegralItem,
+ get8BitUnsignedIntegralItem,
+ isArrayBuffer,
+ isArrayBufferView,
isBase16,
isBase32,
isBase64,
isFilenameSafeBase64,
+ isSharedArrayBuffer,
+ isTypedArray,
isWRMGBase32,
+ set16BitIntegralItem,
+ set32BitFloatingPointItem,
+ set32BitIntegralItem,
+ set64BitFloatingPointItem,
+ set64BitIntegralItem,
+ set8BitIntegralItem,
+ toArrayBuffer,
wrmgBase32Binary,
wrmgBase32String,
} from "./binary.js";
}],
]);
+describe("arrayBufferSlice", () => {
+ it("[[Call]] slices an `ArrayBuffer`", () => {
+ const baseBuffer = Uint8Array.from([2, 3, 1, 9, 8, 5]).buffer;
+ assertEquals(
+ new Uint8Array(arrayBufferSlice(baseBuffer, 1, 4)),
+ Uint8Array.from([3, 1, 9]),
+ );
+ });
+
+ it("[[Call]] slices an `SharedArrayBuffer`", () => {
+ const baseBuffer = new SharedArrayBuffer(6);
+ new Uint8Array(baseBuffer).set([2, 3, 1, 9, 8, 5], 0);
+ assertEquals(
+ new Uint8Array(arrayBufferSlice(baseBuffer, 1, 4)),
+ Uint8Array.from([3, 1, 9]),
+ );
+ });
+
+ it("[[Call]] throws for others", () => {
+ [
+ undefined,
+ null,
+ true,
+ Symbol(),
+ 27,
+ 98n,
+ {},
+ [],
+ () => {},
+ new Proxy({}, {}),
+ "string",
+ new DataView(new ArrayBuffer()),
+ new Uint8Array(),
+ ].forEach((value) =>
+ assertThrows(() => arrayBufferSlice(value, 0, 0))
+ );
+ });
+});
+
describe("base16Binary", () => {
it("[[Call]] returns the correct data", () => {
assertEquals(
});
});
+describe("get8BitSignedIntegralItem", () => {
+ it("[[Call]] gets the item", () => {
+ const buffer = Int8Array.from([0, -1, 0]).buffer;
+ assertStrictEquals(get8BitSignedIntegralItem(buffer, 1), -1n);
+ assertStrictEquals(
+ get8BitSignedIntegralItem(new DataView(buffer), 1),
+ -1n,
+ );
+ assertStrictEquals(
+ get8BitSignedIntegralItem(new Uint8Array(buffer), 1),
+ -1n,
+ );
+ });
+});
+
+describe("get8BitUnsignedIntegralItem", () => {
+ it("[[Call]] gets the item", () => {
+ const buffer = Int8Array.from([0, -1, 0]).buffer;
+ assertStrictEquals(get8BitUnsignedIntegralItem(buffer, 1), 255n);
+ assertStrictEquals(
+ get8BitUnsignedIntegralItem(new DataView(buffer), 1),
+ 255n,
+ );
+ assertStrictEquals(
+ get8BitUnsignedIntegralItem(new Int8Array(buffer), 1),
+ 255n,
+ );
+ });
+});
+
+describe("get16BitSignedIntegralItem", () => {
+ it("[[Call]] gets the item", () => {
+ const buffer = Int8Array.from([0, 0, -1, -1, 0, 0]).buffer;
+ assertStrictEquals(get16BitSignedIntegralItem(buffer, 2), -1n);
+ assertStrictEquals(
+ get16BitSignedIntegralItem(new DataView(buffer), 2),
+ -1n,
+ );
+ assertStrictEquals(
+ get16BitSignedIntegralItem(new Uint16Array(buffer), 2),
+ -1n,
+ );
+ });
+});
+
+describe("get16BitUnsignedIntegralItem", () => {
+ it("[[Call]] gets the item", () => {
+ const buffer = Int8Array.from([0, 0, -1, -1, 0, 0]).buffer;
+ assertStrictEquals(
+ get16BitUnsignedIntegralItem(buffer, 2),
+ (1n << 16n) - 1n,
+ );
+ assertStrictEquals(
+ get16BitUnsignedIntegralItem(new DataView(buffer), 2),
+ (1n << 16n) - 1n,
+ );
+ assertStrictEquals(
+ get16BitUnsignedIntegralItem(new Int16Array(buffer), 2),
+ (1n << 16n) - 1n,
+ );
+ });
+});
+
+describe("get32BitFloatingPointItem", () => {
+ it("[[Call]] gets the item", () => {
+ const buffer = new ArrayBuffer(12);
+ const view = new DataView(buffer);
+ view.setFloat32(0, NaN);
+ view.setFloat32(4, -Infinity);
+ view.setFloat32(8, -0);
+ assertStrictEquals(get32BitFloatingPointItem(buffer, 0), NaN);
+ assertStrictEquals(
+ get32BitFloatingPointItem(buffer, 4),
+ -Infinity,
+ );
+ assertStrictEquals(get32BitFloatingPointItem(buffer, 8), -0);
+ assertStrictEquals(
+ get32BitFloatingPointItem(new DataView(buffer), 4),
+ -Infinity,
+ );
+ assertStrictEquals(
+ get32BitFloatingPointItem(new Uint32Array(buffer), 4),
+ -Infinity,
+ );
+ });
+});
+
+describe("get32BitSignedIntegralItem", () => {
+ it("[[Call]] gets the item", () => {
+ const buffer = Int8Array.from(
+ [0, 0, 0, 0, -1, -1, -1, -1, 0, 0, 0, 0],
+ ).buffer;
+ assertStrictEquals(get32BitSignedIntegralItem(buffer, 4), -1n);
+ assertStrictEquals(
+ get32BitSignedIntegralItem(new DataView(buffer), 4),
+ -1n,
+ );
+ assertStrictEquals(
+ get32BitSignedIntegralItem(new Uint32Array(buffer), 4),
+ -1n,
+ );
+ });
+});
+
+describe("get32BitUnsignedIntegralItem", () => {
+ it("[[Call]] gets the item", () => {
+ const buffer = Int8Array.from(
+ [0, 0, 0, 0, -1, -1, -1, -1, 0, 0, 0, 0],
+ ).buffer;
+ assertStrictEquals(
+ get32BitUnsignedIntegralItem(buffer, 4),
+ (1n << 32n) - 1n,
+ );
+ assertStrictEquals(
+ get32BitUnsignedIntegralItem(new DataView(buffer), 4),
+ (1n << 32n) - 1n,
+ );
+ assertStrictEquals(
+ get32BitUnsignedIntegralItem(new Int32Array(buffer), 4),
+ (1n << 32n) - 1n,
+ );
+ });
+});
+
+describe("get64BitFloatingPointItem", () => {
+ it("[[Call]] gets the item", () => {
+ const buffer = new ArrayBuffer(24);
+ const view = new DataView(buffer);
+ view.setFloat64(0, NaN);
+ view.setFloat64(8, -Infinity);
+ view.setFloat64(16, -0);
+ assertStrictEquals(get64BitFloatingPointItem(buffer, 0), NaN);
+ assertStrictEquals(
+ get64BitFloatingPointItem(buffer, 8),
+ -Infinity,
+ );
+ assertStrictEquals(get64BitFloatingPointItem(buffer, 16), -0);
+ assertStrictEquals(
+ get64BitFloatingPointItem(new DataView(buffer), 8),
+ -Infinity,
+ );
+ assertStrictEquals(
+ get64BitFloatingPointItem(new BigUint64Array(buffer), 8),
+ -Infinity,
+ );
+ });
+});
+
+describe("get64BitSignedIntegralItem", () => {
+ it("[[Call]] gets the item", () => {
+ const buffer = Int8Array.from(
+ [0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1],
+ ).buffer;
+ assertStrictEquals(get64BitSignedIntegralItem(buffer, 8), -1n);
+ assertStrictEquals(
+ get64BitSignedIntegralItem(new DataView(buffer), 8),
+ -1n,
+ );
+ assertStrictEquals(
+ get64BitSignedIntegralItem(new BigUint64Array(buffer), 8),
+ -1n,
+ );
+ });
+});
+
+describe("get64BitUnsignedIntegralItem", () => {
+ it("[[Call]] gets the item", () => {
+ const buffer = Int8Array.from(
+ [0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1],
+ ).buffer;
+ assertStrictEquals(
+ get64BitUnsignedIntegralItem(buffer, 8),
+ (1n << 64n) - 1n,
+ );
+ assertStrictEquals(
+ get64BitUnsignedIntegralItem(new DataView(buffer), 8),
+ (1n << 64n) - 1n,
+ );
+ assertStrictEquals(
+ get64BitUnsignedIntegralItem(new BigInt64Array(buffer), 8),
+ (1n << 64n) - 1n,
+ );
+ });
+});
+
+describe("isArrayBuffer", () => {
+ it("[[Call]] returns true for array buffers", () => {
+ assertStrictEquals(
+ isArrayBuffer(new ArrayBuffer()),
+ true,
+ );
+ assertStrictEquals(
+ isArrayBuffer(new SharedArrayBuffer()),
+ true,
+ );
+ });
+
+ it("[[Call]] returns false for others", () => {
+ [
+ undefined,
+ null,
+ true,
+ Symbol(),
+ 27,
+ 98n,
+ {},
+ [],
+ () => {},
+ new Proxy({}, {}),
+ "string",
+ new DataView(new ArrayBuffer()),
+ new Uint8Array(),
+ ].forEach((value) =>
+ assertStrictEquals(isArrayBuffer(value), false)
+ );
+ });
+});
+
+describe("isArrayBufferView", () => {
+ it("[[Call]] returns true for data views", () => {
+ assertStrictEquals(
+ isArrayBufferView(new DataView(new ArrayBuffer())),
+ true,
+ );
+ });
+
+ it("[[Call]] returns true for typed arrays", () => {
+ assertStrictEquals(
+ isArrayBufferView(new Uint8ClampedArray()),
+ true,
+ );
+ assertStrictEquals(isArrayBufferView(new BigInt64Array()), true);
+ });
+
+ it("[[Call]] returns false for others", () => {
+ [
+ undefined,
+ null,
+ true,
+ Symbol(),
+ 27,
+ 98n,
+ {},
+ [],
+ () => {},
+ new Proxy({}, {}),
+ "string",
+ new ArrayBuffer(),
+ new SharedArrayBuffer(),
+ ].forEach((value) =>
+ assertStrictEquals(isArrayBufferView(value), false)
+ );
+ });
+});
+
describe("isBase16", () => {
it("[[Call]] returns true for base64 strings", () => {
for (const { base16 } of data.values()) {
- assert(isBase16(base16));
- assert(isBase16(base16.toLowerCase()));
+ assertStrictEquals(isBase16(base16), true);
+ assertStrictEquals(isBase16(base16.toLowerCase()), true);
}
});
"a",
"abc",
"abcg",
- ].forEach((value) => assert(!isBase16(value)));
+ ].forEach((value) => assertStrictEquals(isBase16(value), false));
});
});
describe("isBase32", () => {
it("[[Call]] returns true for base32 strings", () => {
for (const { base32 } of data.values()) {
- assert(isBase32(base32));
- assert(isBase32(base32.toLowerCase()));
+ assertStrictEquals(isBase32(base32), true);
+ assertStrictEquals(isBase32(base32.toLowerCase()), true);
}
});
"ABC1",
"A=======",
"ABCDEFGHI",
- ].forEach((value) => assert(!isBase32(value)));
+ ].forEach((value) => assertStrictEquals(isBase32(value), false));
});
});
describe("isBase64", () => {
it("[[Call]] returns true for base64 strings", () => {
for (const { base64 } of data.values()) {
- assert(isBase64(base64));
+ assertStrictEquals(isBase64(base64), true);
}
});
"abc_",
"a",
"abc==",
- ].forEach((value) => assert(!isBase64(value)));
+ ].forEach((value) => assertStrictEquals(isBase64(value), false));
});
});
describe("isFilenameSafeBase64", () => {
it("[[Call]] returns true for filename‐safe base64 strings", () => {
for (const { base64 } of data.values()) {
- assert(
+ assertStrictEquals(
isFilenameSafeBase64(
base64.replace("+", "-").replace("/", "_"),
),
+ true,
);
}
});
"abc/",
"a",
"abc==",
- ].forEach((value) => assert(!isFilenameSafeBase64(value)));
+ ].forEach((value) =>
+ assertStrictEquals(isFilenameSafeBase64(value), false)
+ );
+ });
+});
+
+describe("isSharedArrayBuffer", () => {
+ it("[[Call]] returns true for shared array buffers", () => {
+ assertStrictEquals(
+ isSharedArrayBuffer(new SharedArrayBuffer()),
+ true,
+ );
+ });
+
+ it("[[Call]] returns false for others", () => {
+ [
+ undefined,
+ null,
+ true,
+ Symbol(),
+ 27,
+ 98n,
+ {},
+ [],
+ () => {},
+ new Proxy({}, {}),
+ "string",
+ new ArrayBuffer(),
+ new DataView(new ArrayBuffer()),
+ new Uint8Array(),
+ ].forEach((value) =>
+ assertStrictEquals(isSharedArrayBuffer(value), false)
+ );
+ });
+});
+
+describe("isTypedArray", () => {
+ it("[[Call]] returns true for typed arrays", () => {
+ assertStrictEquals(
+ isTypedArray(new Uint8Array()),
+ true,
+ );
+ assertStrictEquals(
+ isTypedArray(new BigInt64Array()),
+ true,
+ );
+ });
+
+ it("[[Call]] returns false for others", () => {
+ [
+ undefined,
+ null,
+ true,
+ Symbol(),
+ 27,
+ 98n,
+ {},
+ [],
+ () => {},
+ new Proxy({}, {}),
+ "string",
+ new ArrayBuffer(),
+ new SharedArrayBuffer(),
+ new DataView(new ArrayBuffer()),
+ ].forEach((value) =>
+ assertStrictEquals(isTypedArray(value), false)
+ );
});
});
describe("isWRMGBase32", () => {
it("[[Call]] returns true for W·R·M·G base32 strings", () => {
for (const { wrmg } of data.values()) {
- assert(isWRMGBase32(wrmg));
- assert(isWRMGBase32(wrmg.toLowerCase()));
- assert(isWRMGBase32(`--${wrmg}--`));
- assert(isWRMGBase32(wrmg.replaceAll(/1/gu, "I")));
- assert(isWRMGBase32(wrmg.replaceAll(/1/gu, "L")));
- assert(isWRMGBase32(wrmg.replaceAll(/0/gu, "O")));
- assert(isWRMGBase32(wrmg.replaceAll(/1/gu, "i")));
- assert(isWRMGBase32(wrmg.replaceAll(/1/gu, "l")));
- assert(isWRMGBase32(wrmg.replaceAll(/0/gu, "o")));
- assert(isWRMGBase32(wrmg.replaceAll(/./gu, ($) => {
- const rand = Math.random();
- return rand < 0.25
- ? $
- : rand < 0.5
- ? `-${$}`
- : rand < 0.75
- ? `${$}-`
- : `-${$}-`;
- })));
+ assertStrictEquals(isWRMGBase32(wrmg), true);
+ assertStrictEquals(isWRMGBase32(wrmg.toLowerCase()), true);
+ assertStrictEquals(isWRMGBase32(`--${wrmg}--`), true);
+ assertStrictEquals(
+ isWRMGBase32(wrmg.replaceAll(/1/gu, "I")),
+ true,
+ );
+ assertStrictEquals(
+ isWRMGBase32(wrmg.replaceAll(/1/gu, "L")),
+ true,
+ );
+ assertStrictEquals(
+ isWRMGBase32(wrmg.replaceAll(/0/gu, "O")),
+ true,
+ );
+ assertStrictEquals(
+ isWRMGBase32(wrmg.replaceAll(/1/gu, "i")),
+ true,
+ );
+ assertStrictEquals(
+ isWRMGBase32(wrmg.replaceAll(/1/gu, "l")),
+ true,
+ );
+ assertStrictEquals(
+ isWRMGBase32(wrmg.replaceAll(/0/gu, "o")),
+ true,
+ );
+ assertStrictEquals(
+ isWRMGBase32(wrmg.replaceAll(/./gu, ($) => {
+ const rand = Math.random();
+ return rand < 0.25
+ ? $
+ : rand < 0.5
+ ? `-${$}`
+ : rand < 0.75
+ ? `${$}-`
+ : `-${$}-`;
+ })),
+ true,
+ );
}
});
"ABCU",
"A",
"ABCDEFGH1",
- ].forEach((value) => assert(!isWRMGBase32(value)));
+ ].forEach((value) =>
+ assertStrictEquals(isWRMGBase32(value), false)
+ );
+ });
+});
+
+describe("set8BitIntegralItem", () => {
+ it("[[Call]] sets the item", () => {
+ const buffer = new ArrayBuffer(3);
+ set8BitIntegralItem(buffer, 1, -1n);
+ set8BitIntegralItem(buffer, 2, (1 << 8) - 1);
+ assertEquals(
+ new Int8Array(buffer),
+ Int8Array.from([0, -1, -1]),
+ );
+ });
+});
+
+describe("set16BitIntegralItem", () => {
+ it("[[Call]] sets the item", () => {
+ const buffer = new ArrayBuffer(6);
+ set16BitIntegralItem(buffer, 2, -1n);
+ set16BitIntegralItem(buffer, 4, (1 << 16) - 1);
+ assertEquals(
+ new Int8Array(buffer),
+ Int8Array.from([0, 0, -1, -1, -1, -1]),
+ );
+ });
+});
+
+describe("set32BitFloatingPointItem", () => {
+ it("[[Call]] sets the item", () => {
+ const buffer = new ArrayBuffer(12);
+ const expected = new ArrayBuffer(12);
+ const view = new DataView(expected);
+ view.setFloat32(0, NaN);
+ set32BitFloatingPointItem(buffer, 0, NaN);
+ view.setFloat32(4, -Infinity);
+ set32BitFloatingPointItem(buffer, 4, -Infinity);
+ view.setFloat32(8, -0);
+ set32BitFloatingPointItem(buffer, 8, -0);
+ assertEquals(
+ new Uint8Array(buffer),
+ new Uint8Array(expected),
+ );
+ });
+});
+
+describe("set32BitIntegralItem", () => {
+ it("[[Call]] sets the item", () => {
+ const buffer = new ArrayBuffer(12);
+ set32BitIntegralItem(buffer, 4, -1n);
+ set32BitIntegralItem(buffer, 8, -1 >>> 0);
+ assertEquals(
+ new Int8Array(buffer),
+ Int8Array.from([0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1]),
+ );
+ });
+});
+
+describe("set64BitFloatingPointItem", () => {
+ it("[[Call]] sets the item", () => {
+ const buffer = new ArrayBuffer(24);
+ const expected = new ArrayBuffer(24);
+ const view = new DataView(expected);
+ view.setFloat64(0, NaN);
+ set64BitFloatingPointItem(buffer, 0, NaN);
+ view.setFloat64(4, -Infinity);
+ set64BitFloatingPointItem(buffer, 4, -Infinity);
+ view.setFloat64(8, -0);
+ set64BitFloatingPointItem(buffer, 8, -0);
+ assertEquals(
+ new Uint8Array(buffer),
+ new Uint8Array(expected),
+ );
+ });
+});
+
+describe("set64BitIntegralItem", () => {
+ it("[[Call]] sets the item", () => {
+ const buffer = new ArrayBuffer(12);
+ set64BitIntegralItem(buffer, 4, -1n);
+ assertEquals(
+ new Int8Array(buffer),
+ Int8Array.from([0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1]),
+ );
+ });
+});
+
+describe("toArrayBuffer", () => {
+ it("[[Call]] returns the argument for array buffers", () => {
+ const buffer = new ArrayBuffer();
+ assertStrictEquals(toArrayBuffer(buffer), buffer);
+ });
+
+ it("[[Call]] returns the buffer for data views", () => {
+ const src = Uint8Array.from([2, 3, 1]);
+ const buffer = toArrayBuffer(new DataView(src.buffer));
+ assert(buffer instanceof ArrayBuffer);
+ assertEquals(new Uint8Array(buffer), src);
+ });
+
+ it("[[Call]] returns the buffer for typed arrays", () => {
+ const src = Uint8Array.from([2, 3, 1]);
+ const buffer = toArrayBuffer(src);
+ assert(buffer instanceof ArrayBuffer);
+ assertEquals(new Uint8Array(buffer), src);
+ });
+
+ it("[[Call]] throws for others", () => {
+ [
+ undefined,
+ null,
+ true,
+ Symbol(),
+ 27,
+ 98n,
+ {},
+ [],
+ () => {},
+ new Proxy({}, {}),
+ "string",
+ ].forEach((value) =>
+ assertThrows(() => {
+ toArrayBuffer(value);
+ })
+ );
});
});
// ♓🌟 Piscēs ∷ collection.js
// ====================================================================
//
-// Copyright © 2020–2022 Lady [@ Lady’s Computer].
+// Copyright © 2020–2023 Lady [@ Lady’s Computer].
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
} from "./numeric.js";
import { sameValue, type } from "./value.js";
+const { prototype: arrayPrototype } = Array;
+
export const {
/** Returns an array of the provided values. */
of: array,
} = Array;
/**
- * Returns -0 if the provided argument is "-0"; returns a number
+ * 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.
*
};
/**
- * Returns the result of catenating the provided arraylikes, returning
- * a new collection according to the algorithm of Array::concat.
+ * Returns the result of catenating the provided arraylikes into a new
+ * collection according to the algorithm of `Array::concat`.
*/
-export const catenate = makeCallable(Array.prototype.concat);
+export const catenate = makeCallable(arrayPrototype.concat);
/**
* Copies the items in the provided object to a new location according
- * to the algorithm of Array::copyWithin.
+ * to the algorithm of `Array::copyWithin`.
*/
-export const copyWithin = makeCallable(Array.prototype.copyWithin);
+export const copyWithin = makeCallable(arrayPrototype.copyWithin);
/**
- * Fills the provided object with the provided value using the
- * algorithm of Array::fill.
+ * Fills the provided object with the provided value according to the
+ * algorithm of `Array::fill`.
*/
-export const fill = makeCallable(Array.prototype.fill);
+export const fill = makeCallable(arrayPrototype.fill);
/**
* Returns the result of filtering the provided object with the
- * provided callback, using the algorithm of Array::filter.
+ * provided callback, according to the algorithm of `Array::filter`.
*/
-export const filter = makeCallable(Array.prototype.filter);
+export const filter = makeCallable(arrayPrototype.filter);
/**
* Returns the first index in the provided object whose value satisfies
- * the provided callback using the algorithm of Array::findIndex.
+ * the provided callback according to the algorithm of
+ * `Array::findIndex`.
*/
-export const findIndex = makeCallable(Array.prototype.findIndex);
+export const findIndex = makeCallable(arrayPrototype.findIndex);
/**
* Returns the first indexed entry in the provided object whose value
/**
* Returns the first indexed value in the provided object which
- * satisfies the provided callback, using the algorithm of Array::find.
+ * satisfies the provided callback, according to the algorithm of
+ * `Array::find`.
*/
-export const findItem = makeCallable(Array.prototype.find);
+export const findItem = makeCallable(arrayPrototype.find);
/**
* Returns the result of flatmapping the provided value with the
- * provided callback using the algorithm of Array::flatMap.
+ * provided callback according to the algorithm of `Array::flatMap`.
*/
-export const flatmap = makeCallable(Array.prototype.flatMap);
+export const flatmap = makeCallable(arrayPrototype.flatMap);
/**
- * Returns the result of flattening the provided object using the
- * algorithm of Array::flat.
+ * Returns the result of flattening the provided object according to
+ * the algorithm of `Array::flat`.
*/
-export const flatten = makeCallable(Array.prototype.flat);
+export const flatten = makeCallable(arrayPrototype.flat);
/**
* Returns the first index of the provided object with a value
* equivalent to the provided value according to the algorithm of
- * Array::indexOf.
+ * `Array::indexOf`.
*/
-export const getFirstIndex = makeCallable(Array.prototype.indexOf);
+export const getFirstIndex = makeCallable(arrayPrototype.indexOf);
/**
- * Returns the item on the provided object at the provided index using
- * the algorithm of Array::at.
+ * Returns the item on the provided object at the provided index
+ * according to the algorithm of `Array::at`.
*/
-export const getItem = makeCallable(Array.prototype.at);
+export const getItem = makeCallable(arrayPrototype.at);
/**
* Returns the last index of the provided object with a value
* equivalent to the provided value according to the algorithm of
- * Array::lastIndexOf.
+ * `Array::lastIndexOf`.
*/
-export const getLastIndex = makeCallable(Array.prototype.lastIndexOf);
+export const getLastIndex = makeCallable(arrayPrototype.lastIndexOf);
/**
* Returns whether every indexed value in the provided object satisfies
- * the provided function, using the algorithm of Array::every.
+ * the provided function, according to the algorithm of `Array::every`.
*/
-export const hasEvery = makeCallable(Array.prototype.every);
+export const hasEvery = makeCallable(arrayPrototype.every);
/**
* Returns whether the provided object has an indexed value which
- * satisfies the provided function, using the algorithm of Array::some.
+ * satisfies the provided function, according to the algorithm of
+ * `Array::some`.
*/
-export const hasSome = makeCallable(Array.prototype.some);
+export const hasSome = makeCallable(arrayPrototype.some);
/**
* Returns whether the provided object has an indexed value equivalent
- * to the provided value according to the algorithm of Array::includes.
+ * to the provided value according to the algorithm of
+ * `Array::includes`.
*
- * > ☡ This algorithm treats missing values as `undefined` rather than
- * > skipping them.
+ * ※ This algorithm treats missing values as `undefined` rather than
+ * skipping them.
*/
-export const includes = makeCallable(Array.prototype.includes);
+export const includes = makeCallable(arrayPrototype.includes);
/**
* Returns an iterator over the indexed entries in the provided value
- * according to the algorithm of Array::entries.
+ * according to the algorithm of `Array::entries`.
*/
-export const indexedEntries = makeCallable(Array.prototype.entries);
+export const indexedEntries = makeCallable(arrayPrototype.entries);
/**
* Returns an iterator over the indices in the provided value according
- * to the algorithm of Array::keys.
+ * to the algorithm of `Array::keys`.
*/
-export const indices = makeCallable(Array.prototype.keys);
+export const indices = makeCallable(arrayPrototype.keys);
/** Returns whether the provided value is an array index string. */
export const isArrayIndexString = ($) => {
* - It requires the `length` property to be an integer index.
*
* - It requires the object to be concat‐spreadable, meaning it must
- * either be an array or have `[Symbol.isConcatSpreadable]` be true.
+ * either be an array or have `.[Symbol.isConcatSpreadable]` be true.
*/
export const isCollection = ($) => {
if (!(type($) === "object" && "length" in $)) {
/**
* Returns an iterator over the items in the provided value according
- * to the algorithm of Array::values.
+ * to the algorithm of `Array::values`.
*/
-export const items = makeCallable(Array.prototype.values);
+export const items = makeCallable(arrayPrototype.values);
/**
* Returns the length of the provided arraylike object.
/**
* Returns the result of mapping the provided value with the provided
- * callback using the algorithm of Array::map.
+ * callback according to the algorithm of `Array::map`.
*/
-export const map = makeCallable(Array.prototype.map);
+export const map = makeCallable(arrayPrototype.map);
-/** Pops from the provided value using the algorithm of Array::pop. */
-export const pop = makeCallable(Array.prototype.pop);
+/**
+ * Pops from the provided value according to the algorithm of
+ * `Array::pop`.
+ */
+export const pop = makeCallable(arrayPrototype.pop);
/**
- * Pushes onto the provided value using the algorithm of Array::push.
+ * Pushes onto the provided value according to the algorithm of
+ * `Array::push`.
*/
-export const push = makeCallable(Array.prototype.push);
+export const push = makeCallable(arrayPrototype.push);
/**
* Returns the result of reducing the provided value with the provided
- * callback, using the algorithm of Array::reduce.
+ * callback, according to the algorithm of `Array::reduce`.
*/
-export const reduce = makeCallable(Array.prototype.reduce);
+export const reduce = makeCallable(arrayPrototype.reduce);
/**
- * Reverses the provided value using the algorithm of Array::reverse.
+ * Reverses the provided value according to the algorithm of
+ * `Array::reverse`.
*/
-export const reverse = makeCallable(Array.prototype.reverse);
+export const reverse = makeCallable(arrayPrototype.reverse);
-/** Shifts the provided value using the algorithm of Array::shift. */
-export const shift = makeCallable(Array.prototype.shift);
+/**
+ * Shifts the provided value according to the algorithm of
+ * `Array::shift`.
+ */
+export const shift = makeCallable(arrayPrototype.shift);
/**
- * Returns a slice of the provided value using the algorithm of
- * Array::slice.
+ * Returns a slice of the provided value according to the algorithm of
+ * `Array::slice`.
*/
-export const slice = makeCallable(Array.prototype.slice);
+export const slice = makeCallable(arrayPrototype.slice);
/**
- * Sorts the provided value in‐place using the algorithm of
- * Array::sort.
+ * Sorts the provided value in‐place according to the algorithm of
+ * `Array::sort`.
*/
-export const sort = makeCallable(Array.prototype.sort);
+export const sort = makeCallable(arrayPrototype.sort);
/**
- * Splices into and out of the provided value using the algorithm of
- * Array::splice.
+ * Splices into and out of the provided value according to the
+ * algorithm of `Array::splice`.
*/
-export const splice = makeCallable(Array.prototype.splice);
+export const splice = makeCallable(arrayPrototype.splice);
/**
* Returns the result of converting the provided value to an array
};
/**
- * Unshifts the provided value using the algorithm of Array::unshift.
+ * Unshifts the provided value according to the algorithm of
+ * `Array::unshift`.
*/
-export const unshift = makeCallable(Array.prototype.unshift);
+export const unshift = makeCallable(arrayPrototype.unshift);
// ♓🌟 Piscēs ∷ function.js
// ====================================================================
//
-// Copyright © 2022 Lady [@ Lady’s Computer].
+// Copyright © 2022‐2023 Lady [@ Lady’s Computer].
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
+import { ITERATOR } from "./value.js";
+
export const {
/**
* Creates a bound function from the provided function using the
* provided this value and arguments list.
*
- * ☡ As with call and construct, the arguments must be passed as an
- * array.
+ * ☡ As with `call` and `construct`, the arguments must be passed as
+ * an array.
*/
bind,
* first argument as the `this` value and the remaining arguments
* passed through.
*
- * ※ This is effectively an alias for Function.prototype.call.bind.
+ * ※ This is effectively an alias for `Function::call.bind`.
*/
makeCallable,
} = (() => {
defineProperty: defineOwnProperty,
getPrototypeOf: getPrototype,
} = Object;
- const { iterator: iteratorSymbol } = Symbol;
- const { [iteratorSymbol]: arrayIterator } = Array.prototype;
+ const { [ITERATOR]: arrayIterator } = Array.prototype;
const {
next: arrayIteratorNext,
- } = getPrototype([][iteratorSymbol]());
+ } = getPrototype([][ITERATOR]());
const argumentIterablePrototype = {
- [iteratorSymbol]() {
+ [ITERATOR]() {
return {
next: callBind(
arrayIteratorNext,
};
})();
-/**
- * Calls the provided function with the provided this value and
- * arguments list.
- *
- * ☡ This is an alias for Reflect.apply—the arguments must be passed
- * as an array.
- */
-export const call = Reflect.apply;
+export const {
+ /**
+ * Calls the provided function with the provided this value and
+ * arguments list.
+ *
+ * ☡ This is an alias for `Reflect.apply`—the arguments must be
+ * passed as an arraylike.
+ */
+ apply: call,
-/**
- * Constructs the provided function with the provided arguments list
- * and new target.
- *
- * ☡ This is an alias for Reflect.construct—the arguments must be
- * passed as an array.
- */
-export const construct = Reflect.construct;
+ /**
+ * Constructs the provided function with the provided arguments list
+ * and new target.
+ *
+ * ☡ This is an alias for `Reflect.construct`—the arguments must be
+ * passed as an arraylike.
+ */
+ construct,
+} = Reflect;
/**
* Returns the provided value.
export const isConstructor = ($) => {
// The provided value is an object.
try {
+ // Try constructing a new object with the provided value as its
+ // `new.target`. This will throw if the provided value is not a
+ // constructor.
construct(
function () {},
[],
$,
- ); // will throw if $ is not a constructor
+ );
return true;
} catch {
+ // The provided value was not a constructor.
return false;
}
};
// ♓🌟 Piscēs ∷ iri.js
// ====================================================================
//
-// Copyright © 2020, 2022 Lady [@ Lady’s Computer].
+// Copyright © 2020, 2022–2023 Lady [@ Lady’s Computer].
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
stringStartsWith,
substring,
} from "./string.js";
+import { ITERATOR } from "./value.js";
const sub·delims = rawString`[!\$&'()*+,;=]`;
const gen·delims = rawString`[:/?#\[\]@]`;
removeDotSegments,
} = (() => {
const TE = TextEncoder;
- const { iterator: iteratorSymbol } = Symbol;
const { toString: numberToString } = Number.prototype;
const { encode: teEncode } = TE.prototype;
- const { [iteratorSymbol]: arrayIterator } = Array.prototype;
+ const { [ITERATOR]: arrayIterator } = Array.prototype;
const {
next: arrayIteratorNext,
- } = Object.getPrototypeOf([][iteratorSymbol]());
+ } = Object.getPrototypeOf([][ITERATOR]());
const {
next: generatorIteratorNext,
} = Object.getPrototypeOf(function* () {}.prototype);
- const { [iteratorSymbol]: stringIterator } = String.prototype;
+ const { [ITERATOR]: stringIterator } = String.prototype;
const {
next: stringIteratorNext,
- } = Object.getPrototypeOf(""[iteratorSymbol]());
+ } = Object.getPrototypeOf(""[ITERATOR]());
const iriCharacterIterablePrototype = {
- [iteratorSymbol]() {
+ [ITERATOR]() {
return {
next: bind(
stringIteratorNext,
},
};
const iriGeneratorIterablePrototype = {
- [iteratorSymbol]() {
+ [ITERATOR]() {
return {
next: bind(generatorIteratorNext, this.generator(), []),
};
},
};
const iriSegmentIterablePrototype = {
- [iteratorSymbol]() {
+ [ITERATOR]() {
return {
next: bind(
arrayIteratorNext,
// ♓🌟 Piscēs ∷ numeric.js
// ====================================================================
//
-// Copyright © 2022 Lady [@ Lady’s Computer].
+// Copyright © 2022–2023 Lady [@ Lady’s Computer].
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
/**
* ln(10).
*
- * ※ This is an alias for Math.LN10.
+ * ※ This is an alias for `Math.LN10`.
*/
LN10,
/**
* ln(2).
*
- * ※ This is an alias for Math.LN2.
+ * ※ This is an alias for `Math.LN2`.
*/
LN2,
/**
* log10(ℇ).
*
- * ※ This is an alias for Math.LOG10E.
+ * ※ This is an alias for `Math.LOG10E`.
*/
LOG10E: LOG10ℇ,
/**
* log2(ℇ).
*
- * ※ This is an alias for Math.LOG2E.
+ * ※ This is an alias for `Math.LOG2E`.
*/
LOG2E: LOG2ℇ,
/**
- * sqrt(.5).
+ * sqrt(½).
*
- * ※ This is an alias for Math.SQRT1_2.
+ * ※ This is an alias for `Math.SQRT1_2`.
*/
SQRT1_2: RECIPROCAL_SQRT2,
/**
* sqrt(2).
*
- * ※ This is an alias for Math.SQRT2.
+ * ※ This is an alias for `Math.SQRT2`.
*/
SQRT2,
/**
* Returns the arccos of the provided value.
*
- * ※ This is an alias for Math.acos.
+ * ※ This is an alias for `Math.acos`.
*
* ☡ This function does not allow big·int arguments.
*/
/**
* Returns the arccosh of the provided value.
*
- * ※ This is an alias for Math.acosh.
+ * ※ This is an alias for `Math.acosh`.
*
* ☡ This function does not allow big·int arguments.
*/
/**
* Returns the arcsin of the provided value.
*
- * ※ This is an alias for Math.asin.
+ * ※ This is an alias for `Math.asin`.
*
* ☡ This function does not allow big·int arguments.
*/
/**
* Returns the arcsinh of the provided value.
*
- * ※ This is an alias for Math.asinh.
+ * ※ This is an alias for `Math.asinh`.
*
* ☡ This function does not allow big·int arguments.
*/
/**
* Returns the arctan of the provided value.
*
- * ※ This is an alias for Math.atan.
+ * ※ This is an alias for `Math.atan`.
*
* ☡ This function does not allow big·int arguments.
*/
/**
* Returns the arctanh of the provided value.
*
- * ※ This is an alias for Math.atanh.
+ * ※ This is an alias for `Math.atanh`.
*
* ☡ This function does not allow big·int arguments.
*/
/**
* Returns the cube root of the provided value.
*
- * ※ This is an alias for Math.cbrt.
+ * ※ This is an alias for `Math.cbrt`.
*
* ☡ This function does not allow big·int arguments.
*/
/**
* Returns the ceiling of the provided value.
*
- * ※ This is an alias for Math.ceil.
+ * ※ This is an alias for `Math.ceil`.
*
* ☡ This function does not allow big·int arguments.
*/
/**
* Returns the cos of the provided value.
*
- * ※ This is an alias for Math.cos.
+ * ※ This is an alias for `Math.cos`.
*
* ☡ This function does not allow big·int arguments.
*/
/**
* Returns the cosh of the provided value.
*
- * ※ This is an alias for Math.cosh.
+ * ※ This is an alias for `Math.cosh`.
*
* ☡ This function does not allow big·int arguments.
*/
/**
* Returns the Euler number raised to the provided value.
*
- * ※ This is an alias for Math.exp.
+ * ※ This is an alias for `Math.exp`.
*
* ☡ This function does not allow big·int arguments.
*/
/**
* Returns the Euler number raised to the provided value, minus one.
*
- * ※ This is an alias for Math.expm1.
+ * ※ This is an alias for `Math.expm1`.
*
* ☡ This function does not allow big·int arguments.
*/
/**
* Returns the floor of the provided value.
*
- * ※ This is an alias for Math.floor.
+ * ※ This is an alias for `Math.floor`.
*
* ☡ This function does not allow big·int arguments.
*/
* Returns the square root of the sum of the squares of the provided
* arguments.
*
- * ※ This is an alias for Math.hypot.
+ * ※ This is an alias for `Math.hypot`.
*
* ☡ This function does not allow big·int arguments.
*/
/**
* Returns the ln of the provided value.
*
- * ※ This is an alias for Math.log.
+ * ※ This is an alias for `Math.log`.
*
* ☡ This function does not allow big·int arguments.
*/
/**
* Returns the log10 of the provided value.
*
- * ※ This is an alias for Math.log10.
+ * ※ This is an alias for `Math.log10`.
*
* ☡ This function does not allow big·int arguments.
*/
/**
* Returns the ln of one plus the provided value.
*
- * ※ This is an alias for Math.log1p.
+ * ※ This is an alias for `Math.log1p`.
*
* ☡ This function does not allow big·int arguments.
*/
/**
* Returns the log2 of the provided value.
*
- * ※ This is an alias for Math.log2.
+ * ※ This is an alias for `Math.log2`.
*
* ☡ This function does not allow big·int arguments.
*/
/**
* Returns a pseudo·random value in the range [0, 1).
*
- * ※ This is an alias for Math.random.
+ * ※ This is an alias for `Math.random`.
*/
random: rand,
/**
* Returns the round of the provided value.
*
- * ※ This is an alias for Math.round.
+ * ※ This is an alias for `Math.round`.
*
* ☡ This function does not allow big·int arguments.
*/
/**
* Returns the sinh of the provided value.
*
- * ※ This is an alias for Math.sinh.
+ * ※ This is an alias for `Math.sinh`.
*
* ☡ This function does not allow big·int arguments.
*/
/**
* Returns the square root of the provided value.
*
- * ※ This is an alias for Math.sqrt.
+ * ※ This is an alias for `Math.sqrt`.
*
* ☡ This function does not allow big·int arguments.
*/
/**
* Returns the tan of the provided value.
*
- * ※ This is an alias for Math.tan.
+ * ※ This is an alias for `Math.tan`.
*
* ☡ This function does not allow big·int arguments.
*/
/**
* Returns the tanh of the provided value.
*
- * ※ This is an alias for Math.tanh.
+ * ※ This is an alias for `Math.tanh`.
*
* ☡ This function does not allow big·int arguments.
*/
/**
* Returns the trunc of the provided value.
*
- * ※ This is an alias for Math.trunc.
+ * ※ This is an alias for `Math.trunc`.
*
* ☡ This function does not allow big·int arguments.
*/
/**
* The mathematical constant π.
*
- * ※ This is an alias for Math.PI.
+ * ※ This is an alias for `Math.PI`.
*/
PI: Π,
/**
* The Euler number.
*
- * ※ This is an alias for Math.E.
+ * ※ This is an alias for `Math.E`.
*/
E: ℇ,
} = Math;
/**
* The largest number value less than infinity.
*
- * ※ This is an alias for Number.MAX_VALUE.
+ * ※ This is an alias for `Number.MAX_VALUE`.
*/
MAX_VALUE: MAXIMUM_NUMBER,
/**
* 2**53 - 1.
*
- * ※ This is an alias for Number.MAX_SAFE_INTEGER.
+ * ※ This is an alias for `Number.MAX_SAFE_INTEGER`.
*/
MAX_SAFE_INTEGER: MAXIMUM_SAFE_INTEGRAL_NUMBER,
/**
* The smallest number value greater than negative infinity.
*
- * ※ This is an alias for Number.MIN_VALUE.
+ * ※ This is an alias for `Number.MIN_VALUE`.
*/
MIN_VALUE: MINIMUM_NUMBER,
/**
* -(2**53 - 1).
*
- * ※ This is an alias for Number.MIN_SAFE_INTEGER.
+ * ※ This is an alias for `Number.MIN_SAFE_INTEGER`.
*/
MIN_SAFE_INTEGER: MINIMUM_SAFE_INTEGRAL_NUMBER,
/**
* Negative infinity.
*
- * ※ This is an alias for Number.NEGATIVE_INFINITY.
+ * ※ This is an alias for `Number.NEGATIVE_INFINITY`.
*/
NEGATIVE_INFINITY,
/**
* Nan.
*
- * ※ This is an alias for Number.NaN.
+ * ※ This is an alias for `Number.NaN`.
*/
NaN: NAN,
/**
* Positive infinity.
*
- * ※ This is an alias for Number.POSITIVE_INFINITY.
+ * ※ This is an alias for `Number.POSITIVE_INFINITY`.
*/
POSITIVE_INFINITY,
/**
* The difference between 1 and the smallest number greater than 1.
*
- * ※ This is an alias for Number.EPSILON.
+ * ※ This is an alias for `Number.EPSILON`.
*/
EPSILON: Ε,
/**
* Returns whether the provided value is a finite number.
*
- * ※ This is an alias for Number.isFinite.
+ * ※ This is an alias for `Number.isFinite`.
*/
isFinite: isFiniteNumber,
/**
* Returns whether the provided value is an integral number.
*
- * ※ This is an alias for Number.isInteger.
+ * ※ This is an alias for `Number.isInteger`.
*/
isInteger: isIntegralNumber,
/**
* Returns whether the provided value is nan.
*
- * ※ This is an alias for Number.isNaN.
+ * ※ This is an alias for `Number.isNaN`.
*/
isNaN: isNan,
/**
* Returns whether the provided value is a safe integral number.
*
- * ※ This is an alias for Number.isSafeInteger.
+ * ※ This is an alias for `Number.isSafeInteger`.
*/
isSafeInteger: isSafeIntegralNumber,
} = Number;
/**
* Returns the magnitude (absolute value) of the provided value.
*
- * ※ Unlike Math.abs, this function can take big·int arguments.
+ * ※ Unlike `Math.abs`, this function can take big·int arguments.
*/
export const abs = ($) => {
const n = toNumeric($);
/**
* Returns the arctangent of the dividend of the provided values.
*
- * ※ Unlike Math.atan2, this function can take big·int arguments.
+ * ※ Unlike `Math.atan2`, this function can take big·int arguments.
* However, the result will always be a number.
*/
atan2,
/**
- * Returns the number of leading zeroes in the 32‐bit representation of
- * the provided value.
+ * Returns the number of leading zeroes in the 32‐bit representation
+ * of the provided value.
*
- * ※ Unlike Math.clz32, this function accepts either number or big·int
- * values.
+ * ※ Unlike `Math.clz32`, this function accepts either number or
+ * big·int values.
*/
clz32,
* Returns the 32‐bit float which best approximate the provided
* value.
*
- * ※ Unlike Math.fround, this function can take big·int arguments.
+ * ※ Unlike `Math.fround`, this function can take big·int arguments.
* However, the result will always be a number.
*/
toFloat32,
clz32: ($) => {
const n = toNumeric($);
return clz32(
- typeof n === "bigint" ? toNumber(toUintN(32, n)) : n,
+ typeof n === "bigint"
+ ? toNumber(toUnsignedIntegralNumeric(32, n))
+ : n,
);
},
toFloat32: ($) => fround(toNumber($)),
* Returns the highest value of the provided arguments, or negative
* infinity if no argument is provided.
*
- * ※ Unlike Math.max, this function accepts either number or big·int
+ * ※ Unlike `Math.max`, this function accepts either number or big·int
* values. All values must be of the same type, or this function will
* throw an error.
*
* Returns the lowest value of the provided arguments, or positive
* infinity if no argument is provided.
*
- * ※ Unlike Math.min, this function accepts either number or big·int
+ * ※ Unlike `Math.min`, this function accepts either number or big·int
* values. All values must be of the same type, or this function will
* throw an error.
*
* signed) zero.
*
* For big·ints, the return value of this function is 0n if the
- * provided value is 0n, -1n if the provided value is negative, and +1n
+ * provided value is 0n, −1n if the provided value is negative, and +1n
* otherwise.
*
- * For numbers, the return value is nan, -0, or +0 if the provided
- * value is nan, -0, or +0, respectively, and -1 if the provided value
+ * For numbers, the return value is nan, −0, or +0 if the provided
+ * value is nan, −0, or +0, respectively, and −1 if the provided value
* is negative and +1 if the provided value is positive otherwise. Note
- * that positive and negative infinity will return +1 and -1
+ * that positive and negative infinity will return +1 and −1
* respectively.
*
- * ※ Unlike Math.sign, this function accepts either number or big·int
- * values.
+ * ※ Unlike `Math.sign`, this function accepts either number or
+ * big·int values.
*/
export const sgn = ($) => {
const n = toNumeric($);
*
* ※ This method is safe to use with numbers.
*
- * ※ This is effectively an alias for BigInt.
+ * ※ This is effectively an alias for `BigInt`.
*/
export const { toBigInt } = (() => {
const makeBigInt = BigInt;
};
})();
-export const {
- /**
- * Returns the result of converting the provided value to fit within
- * the provided number of bits as a signed integer.
- *
- * ※ Unlike BigInt.asIntN, this function accepts both big·int and
- * number values.
- *
- * ☡ The first argument, the number of bits, must be a number.
- */
- toIntN,
-
- /**
- * Returns the result of converting the provided value to fit within
- * the provided number of bits as an unsigned integer.
- *
- * ※ Unlike BigInt.asUintN, this function accepts both big·int and
- * number values.
- *
- * ☡ The first argument, the number of bits, must be a number.
- */
- toUintN,
-} = (() => {
- const { asIntN, asUintN } = BigInt;
- return {
- toIntN: (n, $) => {
- const prim = toPrimitive($);
- if (typeof prim === "bigint") {
- // The primitive value is a big·int.
- return asIntN(n, prim);
- } else {
- // The primitive value is not a big·int.
- const int = trunc(prim);
- if (!isFiniteNumber(int) || int == 0) {
- // The truncated value is zero or not finite.
- return 0;
- } else {
- // The truncated value is finite.
- return toNumber(asIntN(n, toBigInt(int)));
- }
- }
- },
- toUintN: (n, $) => {
- const prim = toPrimitive($);
- if (typeof prim === "bigint") {
- // The primitive value is a big·int.
- return asUintN(n, prim);
- } else {
- // The primitive value is not a big·int.
- const int = trunc(prim);
- if (!isFiniteNumber(int) || int == 0) {
- // The truncated value is zero or not finite.
- return 0;
- } else {
- // The truncated value is finite.
- return toNumber(asUintN(n, toBigInt(int)));
- }
- }
- },
- };
-})();
-
/**
* Returns the result of converting the provided number to an integral
* number.
*
* ※ This function is safe to use with big·ints.
*
- * ※ This is effectively a nonconstructible version of the Number
+ * ※ This is effectively a nonconstructible version of the `Number`
* constructor.
*/
export const { toNumber } = (() => {
const primValue = toPrimitive($, "number");
return typeof primValue === "bigint" ? primValue : +primValue;
};
+
+export const {
+ /**
+ * Returns the result of converting the provided value to fit within
+ * the provided number of bits as a signed integer.
+ *
+ * ※ Unlike `BigInt.asIntN`, this function accepts both big·int and
+ * number values.
+ *
+ * ☡ The first argument, the number of bits, must be a number.
+ */
+ toSignedIntegralNumeric,
+
+ /**
+ * Returns the result of converting the provided value to fit within
+ * the provided number of bits as an unsigned integer.
+ *
+ * ※ Unlike `BigInt.asUintN`, this function accepts both big·int and
+ * number values.
+ *
+ * ☡ The first argument, the number of bits, must be a number.
+ */
+ toUnsignedIntegralNumeric,
+} = (() => {
+ const { asIntN, asUintN } = BigInt;
+ return {
+ toSignedIntegralNumeric: (n, $) => {
+ const prim = toPrimitive($);
+ if (typeof prim === "bigint") {
+ // The primitive value is a big·int.
+ return asIntN(n, prim);
+ } else {
+ // The primitive value is not a big·int.
+ const int = trunc(prim);
+ if (!isFiniteNumber(int) || int == 0) {
+ // The truncated value is zero or not finite.
+ return 0;
+ } else {
+ // The truncated value is finite.
+ return toNumber(asIntN(n, toBigInt(int)));
+ }
+ }
+ },
+ toUnsignedIntegralNumeric: (n, $) => {
+ const prim = toPrimitive($);
+ if (typeof prim === "bigint") {
+ // The primitive value is a big·int.
+ return asUintN(n, prim);
+ } else {
+ // The primitive value is not a big·int.
+ const int = trunc(prim);
+ if (!isFiniteNumber(int) || int == 0) {
+ // The truncated value is zero or not finite.
+ return 0;
+ } else {
+ // The truncated value is finite.
+ return toNumber(asUintN(n, toBigInt(int)));
+ }
+ }
+ },
+ };
+})();
// ♓🌟 Piscēs ∷ numeric.test.js
// ====================================================================
//
-// Copyright © 2022 Lady [@ Lady’s Computer].
+// Copyright © 2022–2023 Lady [@ Lady’s Computer].
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
toFloat32,
toIntegralNumber,
toIntegralNumberOrInfinity,
- toIntN,
toNumber,
toNumeric,
- toUintN,
+ toSignedIntegralNumeric,
+ toUnsignedIntegralNumeric,
} from "./numeric.js";
describe("NEGATIVE_ZERO", () => {
});
});
-describe("toIntN", () => {
+describe("toSignedIntegralNumeric", () => {
it("[[Call]] converts to an int·n", () => {
- assertStrictEquals(toIntN(2, 7n), -1n);
+ assertStrictEquals(toSignedIntegralNumeric(2, 7n), -1n);
});
it("[[Call]] works with numbers", () => {
- assertStrictEquals(toIntN(2, 7), -1);
+ assertStrictEquals(toSignedIntegralNumeric(2, 7), -1);
});
it("[[Call]] works with non‐integers", () => {
- assertStrictEquals(toIntN(2, 7.21), -1);
- assertStrictEquals(toIntN(2, Infinity), 0);
+ assertStrictEquals(toSignedIntegralNumeric(2, 7.21), -1);
+ assertStrictEquals(toSignedIntegralNumeric(2, Infinity), 0);
});
});
});
});
-describe("toUintN", () => {
+describe("toUnsignedIntegralNumeric", () => {
it("[[Call]] converts to an int·n", () => {
- assertStrictEquals(toUintN(2, 7n), 3n);
+ assertStrictEquals(toUnsignedIntegralNumeric(2, 7n), 3n);
});
it("[[Call]] works with numbers", () => {
- assertStrictEquals(toUintN(2, 7), 3);
+ assertStrictEquals(toUnsignedIntegralNumeric(2, 7), 3);
});
it("[[Call]] works with non‐integers", () => {
- assertStrictEquals(toUintN(2, 7.21), 3);
- assertStrictEquals(toUintN(2, Infinity), 0);
+ assertStrictEquals(toUnsignedIntegralNumeric(2, 7.21), 3);
+ assertStrictEquals(toUnsignedIntegralNumeric(2, Infinity), 0);
});
});
// ♓🌟 Piscēs ∷ object.js
// ====================================================================
//
-// Copyright © 2022 Lady [@ Lady’s Computer].
+// Copyright © 2022–2023 Lady [@ Lady’s Computer].
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
import { bind, call } from "./function.js";
-import { toPrimitive, type } from "./value.js";
+import { ITERATOR, SPECIES, toPrimitive, type } from "./value.js";
/**
* An object whose properties are lazy‐loaded from the methods on the
* Methods will be called with the resulting object as their this
* value.
*
- * LazyLoader objects have the same prototype as the passed methods
+ * `LazyLoader` objects have the same prototype as the passed methods
* object.
*/
export class LazyLoader extends null {
/**
- * Constructs a new LazyLoader object.
+ * Constructs a new `LazyLoader` object.
*
* ☡ This function throws if the provided value is not an object.
*/
* object.
*
* The resulting object is proxied to enforce types (for example,
- * its `enumerable` property, if defined, will always be a
+ * its `.enumerable` property, if defined, will always be a
* boolean).
*/
constructor(O) {
* descriptors on the enumerable own properties of the provided
* additional objects.
*
- * ※ This differs from Object.defineProperties in that it can take
+ * ※ This differs from `Object.defineProperties` in that it can take
* multiple source objects.
*/
defineOwnProperties,
* Defines an own property on the provided object on the provided
* property key using the provided property descriptor.
*
- * ※ This is an alias for Object.defineProperty.
+ * ※ This is an alias for `Object.defineProperty`.
*/
defineProperty: defineOwnProperty,
* properties as nonconfigurable and (if data properties)
* nonwritable, and returns the object.
*
- * ※ This is an alias for Object.freeze.
+ * ※ This is an alias for `Object.freeze`.
*/
freeze,
* provided property key on the provided object, or null if none
* exists.
*
- * ※ This is an alias for Object.getOwnPropertyDescriptor.
+ * ※ This is an alias for `Object.getOwnPropertyDescriptor`.
*/
getOwnPropertyDescriptor,
* Returns the property descriptors for the own properties on the
* provided object.
*
- * ※ This is an alias for Object.getOwnPropertyDescriptors.
+ * ※ This is an alias for `Object.getOwnPropertyDescriptors`.
*/
getOwnPropertyDescriptors,
*
* ☡ This includes both enumerable and non·enumerable properties.
*
- * ※ This is an alias for Object.getOwnPropertyNames.
+ * ※ This is an alias for `Object.getOwnPropertyNames`.
*/
getOwnPropertyNames: getOwnPropertyStrings,
*
* ☡ This includes both enumerable and non·enumerable properties.
*
- * ※ This is an alias for Object.getOwnPropertySymbols.
+ * ※ This is an alias for `Object.getOwnPropertySymbols`.
*/
getOwnPropertySymbols,
/**
* Returns the prototype of the provided object.
*
- * ※ This is an alias for Object.getPrototypeOf.
+ * ※ This is an alias for `Object.getPrototypeOf`.
*/
getPrototypeOf: getPrototype,
* Returns whether the provided object has an own property with the
* provided property key.
*
- * ※ This is an alias for Object.hasOwn.
+ * ※ This is an alias for `Object.hasOwn`.
*/
hasOwn: hasOwnProperty,
/**
* Returns whether the provided object is extensible.
*
- * ※ This is an alias for Object.isExtensible.
+ * ※ This is an alias for `Object.isExtensible`.
*/
- isExtensible,
+ isExtensible: isExtensibleObject,
/**
* Returns whether the provided object is frozen.
*
- * ※ This is an alias for Object.isFrozen.
+ * ※ This is an alias for `Object.isFrozen`.
*/
- isFrozen,
+ isFrozen: isFrozenObject,
/**
* Returns whether the provided object is sealed.
*
- * ※ This is an alias for Object.isSealed.
+ * ※ This is an alias for `Object.isSealed`.
*/
- isSealed,
+ isSealed: isSealedObject,
/**
* Returns an array of key~value pairs for the enumerable,
* string‐valued property keys on the provided object.
*
- * ※ This is an alias for Object.entries.
+ * ※ This is an alias for `Object.entries`.
*/
entries: namedEntries,
* Returns an array of the enumerable, string‐valued property keys on
* the provided object.
*
- * ※ This is an alias for Object.keys.
+ * ※ This is an alias for `Object.keys`.
*/
keys: namedKeys,
* Returns an array of property values for the enumerable,
* string‐valued property keys on the provided object.
*
- * ※ This is an alias for Object.values.
+ * ※ This is an alias for `Object.values`.
*/
values: namedValues,
* Returns a new object with the provided prototype and property
* descriptors.
*
- * ※ This is an alias for Object.create.
+ * ※ This is an alias for `Object.create`.
*/
create: objectCreate,
/**
* Returns a new object with the provided property keys and values.
*
- * ※ This is an alias for Object.fromEntries.
+ * ※ This is an alias for `Object.fromEntries`.
*/
fromEntries: objectFromEntries,
* Marks the provided object as non·extensible, and returns the
* object.
*
- * ※ This is an alias for Object.preventExtensions.
+ * ※ This is an alias for `Object.preventExtensions`.
*/
preventExtensions,
* Marks the provided object as non·extensible and marks all its
* properties as nonconfigurable, and returns the object.
*
- * ※ This is an alias for Object.seal.
+ * ※ This is an alias for `Object.seal`.
*/
seal,
* Sets the values of the enumerable own properties of the provided
* additional objects on the provided object.
*
- * ※ This is an alias for Object.assign.
+ * ※ This is an alias for `Object.assign`.
*/
assign: setPropertyValues,
* Sets the prototype of the provided object to the provided value
* and returns the object.
*
- * ※ This is an alias for Object.setPrototypeOf.
+ * ※ This is an alias for `Object.setPrototypeOf`.
*/
setPrototypeOf: setPrototype,
} = Object;
* Removes the provided property key from the provided object and
* returns the object.
*
- * ※ This function differs from Reflect.deleteProperty and the
+ * ※ This function differs from `Reflect.deleteProperty` and the
* `delete` operator in that it throws if the deletion is
* unsuccessful.
*
/**
* Returns an array of property keys on the provided object.
*
- * ※ This is effectively an alias for Reflect.ownKeys, except that
+ * ※ This is effectively an alias for `Reflect.ownKeys`, except that
* it does not require that the argument be an object.
*/
getOwnPropertyKeys,
* Returns the value of the provided property key on the provided
* object.
*
- * ※ This is effectively an alias for Reflect.get, except that it
+ * ※ This is effectively an alias for `Reflect.get`, except that it
* does not require that the argument be an object.
*/
getPropertyValue,
* Returns whether the provided property key exists on the provided
* object.
*
- * ※ This is effectively an alias for Reflect.has, except that it
+ * ※ This is effectively an alias for `Reflect.has`, except that it
* does not require that the argument be an object.
*
* ※ This includes properties present on the prototype chain.
* Sets the provided property key to the provided value on the
* provided object and returns the object.
*
- * ※ This function differs from Reflect.set in that it throws if the
- * setting is unsuccessful.
+ * ※ This function differs from `Reflect.set` in that it throws if
+ * the setting is unsuccessful.
*
* ☡ This function throws if the first argument is not an object.
*/
* property with the same getter *and* setter.
*
* The prototype for the resulting object will be taken from the
- * `prototype` property of the provided constructor, or the
- * `prototype` of the `constructor` of the provided object if the
+ * `.prototype` property of the provided constructor, or the
+ * `.prototype` of the `.constructor` of the provided object if the
* provided constructor is undefined. If the used constructor has a
- * nonnullish `Symbol.species`, that will be used instead. If the
+ * nonnullish `.[Symbol.species]`, that will be used instead. If the
* used constructor or species is nullish or does not have a
- * `prototype` property, the prototype is set to null.
+ * `.prototype` property, the prototype is set to null.
*
* ※ The prototype of the provided object itself is ignored.
*/
frozenCopy,
} = (() => {
- const {
- iterator: iteratorSymbol,
- species: speciesSymbol,
- } = Symbol;
const {
next: generatorIteratorNext,
} = getPrototype(function* () {}.prototype);
const propertyDescriptorEntryIterablePrototype = {
- [iteratorSymbol]() {
+ [ITERATOR]() {
return {
next: bind(generatorIteratorNext, this.generator(), []),
};
// O is not null or undefined.
//
// (If not provided, the constructor will be the value of
- // getting the `constructor` property of O.)
- const species = constructor?.[speciesSymbol] ?? constructor;
+ // getting the `.constructor` property of O.)
+ const species = constructor?.[SPECIES] ?? constructor;
return preventExtensions(
objectCreate(
species == null || !("prototype" in species)
objectCreate,
setPrototype,
} from "./object.js";
-import { type } from "./value.js";
+import { ITERATOR, TO_STRING_TAG } from "./value.js";
+
+const RE = RegExp;
+const { prototype: rePrototype } = RE;
+const { prototype: arrayPrototype } = Array;
+const { prototype: stringPrototype } = String;
+
+const { exec: reExec } = rePrototype;
export const {
/**
- * A RegExp·like object which only matches entire strings, and may
+ * A `RegExp`like object which only matches entire strings, and may
* have additional constraints specified.
*
* Matchers are callable objects and will return true if they are
* called with a string that they match, and false otherwise.
* Matchers will always return false if called with nonstrings,
- * although other methods like `exec` coerce their arguments and may
- * still return true.
+ * although other methods like `::exec` coerce their arguments and
+ * may still return true.
*/
Matcher,
} = (() => {
- const RE = RegExp;
- const { prototype: rePrototype } = RE;
- const { exec: reExec, toString: reToString } = rePrototype;
+ const { toString: reToString } = rePrototype;
const getDotAll =
Object.getOwnPropertyDescriptor(rePrototype, "dotAll").get;
const getFlags =
#regExp;
/**
- * Constructs a new Matcher from the provided source.
+ * Constructs a new `Matcher` from the provided source.
*
* If the provided source is a regular expression, then it must
* have the unicode flag set. Otherwise, it is interpreted as the
* A callable constraint on acceptable inputs may be provided as a
* third argument. If provided, it will be called with three
* arguments whenever a match appears successful: first, the string
- * being matched, second, the match result, and third, the Matcher
- * object itself. If the return value of this call is falsey, then
- * the match will be considered a failure.
+ * being matched, second, the match result, and third, the
+ * `Matcher` object itself. If the return value of this call is
+ * falsey, then the match will be considered a failure.
*
* ☡ If the provided source regular expression uses nongreedy
* quantifiers, it may not match the whole string even if a match
// The provided value is not a string.
return false;
} else {
- // The provided value is a string. Set the `lastIndex` of
+ // The provided value is a string. Set the `.lastIndex` of
// the regular expression to 0 and see if the first attempt
// at a match matches the whole string and passes the
// provided constraint (if present).
}
}
- /** Gets whether the dotAll flag is present on this Matcher. */
+ /** Gets whether the dot‐all flag is present on this `Matcher`. */
get dotAll() {
return call(getDotAll, this.#regExp, []);
}
/**
- * Executes this Matcher on the provided value and returns the
+ * Executes this `Matcher` on the provided value and returns the
* result if there is a match, or null otherwise.
*
* Matchers only match if they can match the entire value on the
}
/**
- * Gets the flags present on this Matcher.
+ * Gets the flags present on this `Matcher`.
*
- * ※ This needs to be defined because the internal RegExp object
+ * ※ This needs to be defined because the internal `RegExp` object
* may have flags which are not yet recognized by ♓🌟 Piscēs.
*/
get flags() {
return call(getFlags, this.#regExp, []);
}
- /** Gets whether the global flag is present on this Matcher. */
+ /** Gets whether the global flag is present on this `Matcher`. */
get global() {
return call(getGlobal, this.#regExp, []);
}
- /** Gets whether the hasIndices flag is present on this Matcher. */
+ /**
+ * Gets whether the has‐indices flag is present on this `Matcher`.
+ */
get hasIndices() {
return call(getHasIndices, this.#regExp, []);
}
- /** Gets whether the ignoreCase flag is present on this Matcher. */
+ /**
+ * Gets whether the ignore‐case flag is present on this `Matcher`.
+ */
get ignoreCase() {
return call(getIgnoreCase, this.#regExp, []);
}
- /** Gets whether the multiline flag is present on this Matcher. */
+ /**
+ * Gets whether the multiline flag is present on this `Matcher`.
+ */
get multiline() {
return call(getMultiline, this.#regExp, []);
}
- /** Gets the regular expression source for this Matcher. */
+ /** Gets the regular expression source for this `Matcher`. */
get source() {
return call(getSource, this.#regExp, []);
}
- /** Gets whether the sticky flag is present on this Matcher. */
+ /** Gets whether the sticky flag is present on this `Matcher`. */
get sticky() {
return call(getSticky, this.#regExp, []);
}
/**
- * Gets whether the unicode flag is present on this Matcher.
+ * Gets whether the unicode flag is present on this `Matcher`.
*
* ※ This will always be true.
*/
const {
toLowerCase: stringToLowercase,
toUpperCase: stringToUppercase,
- } = String.prototype;
+ } = stringPrototype;
return {
asciiLowercase: ($) =>
stringReplaceAll(
*/
scalarValueString,
} = (() => {
- const {
- iterator: iteratorSymbol,
- toStringTag: toStringTagSymbol,
- } = Symbol;
- const { [iteratorSymbol]: arrayIterator } = Array.prototype;
+ const { [ITERATOR]: arrayIterator } = arrayPrototype;
const arrayIteratorPrototype = Object.getPrototypeOf(
- [][iteratorSymbol](),
+ [][ITERATOR](),
);
const { next: arrayIteratorNext } = arrayIteratorPrototype;
const iteratorPrototype = Object.getPrototypeOf(
arrayIteratorPrototype,
);
- const { [iteratorSymbol]: stringIterator } = String.prototype;
+ const { [ITERATOR]: stringIterator } = stringPrototype;
const stringIteratorPrototype = Object.getPrototypeOf(
- ""[iteratorSymbol](),
+ ""[ITERATOR](),
);
const { next: stringIteratorNext } = stringIteratorPrototype;
value: stringCodeValueIteratorNext,
writable: true,
},
- [toStringTagSymbol]: {
+ [TO_STRING_TAG]: {
configurable: true,
enumerable: false,
value: "String Code Value Iterator",
},
);
const scalarValueIterablePrototype = {
- [iteratorSymbol]() {
+ [ITERATOR]() {
return {
next: bind(
stringCodeValueIteratorNext,
/**
* Returns an iterator over the codepoints in the string representation
* of the provided value according to the algorithm of
- * String::[Symbol.iterator].
+ * `String::[Symbol.iterator]`.
*/
export const characters = makeCallable(
- String.prototype[Symbol.iterator],
+ stringPrototype[ITERATOR],
);
/**
* Returns the character at the provided position in the string
* representation of the provided value according to the algorithm of
- * String::codePointAt.
+ * `String::codePointAt`.
*/
export const getCharacter = ($, pos) => {
const codepoint = getCodepoint($, pos);
/**
* Returns the code unit at the provided position in the string
* representation of the provided value according to the algorithm of
- * String::charAt.
+ * `String::charAt`.
*/
-export const getCodeUnit = makeCallable(String.prototype.charCodeAt);
+export const getCodeUnit = makeCallable(stringPrototype.charCodeAt);
/**
* Returns the codepoint at the provided position in the string
* representation of the provided value according to the algorithm of
- * String::codePointAt.
+ * `String::codePointAt`.
*/
-export const getCodepoint = makeCallable(String.prototype.codePointAt);
+export const getCodepoint = makeCallable(stringPrototype.codePointAt);
/**
* Returns the index of the first occurrence of the search string in
* the string representation of the provided value according to the
- * algorithm of String::indexOf.
+ * algorithm of `String::indexOf`.
*/
export const getFirstSubstringIndex = makeCallable(
- String.prototype.indexOf,
+ stringPrototype.indexOf,
);
/**
* Returns the index of the last occurrence of the search string in the
* string representation of the provided value according to the
- * algorithm of String::lastIndexOf.
+ * algorithm of `String::lastIndexOf`.
*/
export const getLastSubstringIndex = makeCallable(
- String.prototype.lastIndexOf,
+ stringPrototype.lastIndexOf,
);
/**
* If a value is nullish, it will be stringified as the empty string.
*/
export const join = (() => {
- const { join: arrayJoin } = Array.prototype;
+ const { join: arrayJoin } = arrayPrototype;
const join = ($, separator = ",") =>
call(arrayJoin, [...$], [`${separator}`]);
return join;
* Returns a string created from the raw value of the tagged template
* literal.
*
- * ※ This is an alias for String.raw.
+ * ※ This is an alias for `String.raw`.
*/
raw: rawString,
/**
* Returns a string created from the provided code units.
*
- * ※ This is an alias for String.fromCharCode.
+ * ※ This is an alias for `String.fromCharCode`.
*/
fromCharCode: stringFromCodeUnits,
/**
* Returns a string created from the provided codepoints.
*
- * ※ This is an alias for String.fromCodePoint.
+ * ※ This is an alias for `String.fromCodePoint`.
*/
fromCodePoint: stringFromCodepoints,
} = String;
/**
* Returns the result of catenating the string representations of the
* provided values, returning a new string according to the algorithm
- * of String::concat.
+ * of `String::concat`.
*/
-export const stringCatenate = makeCallable(String.prototype.concat);
+export const stringCatenate = makeCallable(stringPrototype.concat);
/**
* Returns whether the string representation of the provided value ends
* with the provided search string according to the algorithm of
- * String::endsWith.
+ * `String::endsWith`.
*/
-export const stringEndsWith = makeCallable(String.prototype.endsWith);
+export const stringEndsWith = makeCallable(stringPrototype.endsWith);
/**
* Returns whether the string representation of the provided value
* contains the provided search string according to the algorithm of
- * String::includes.
+ * `String::includes`.
*/
-export const stringIncludes = makeCallable(String.prototype.includes);
+export const stringIncludes = makeCallable(stringPrototype.includes);
/**
* Returns the result of matching the string representation of the
* provided value with the provided matcher according to the algorithm
- * of String::match.
+ * of `String::match`.
*/
-export const stringMatch = makeCallable(String.prototype.match);
+export const stringMatch = makeCallable(stringPrototype.match);
/**
* Returns the result of matching the string representation of the
* provided value with the provided matcher according to the algorithm
- * of String::matchAll.
+ * of `String::matchAll`.
*/
-export const stringMatchAll = makeCallable(String.prototype.matchAll);
+export const stringMatchAll = makeCallable(stringPrototype.matchAll);
/**
* Returns the normalized form of the string representation of the
- * provided value according to the algorithm of String::matchAll.
+ * provided value according to the algorithm of `String::matchAll`.
*/
export const stringNormalize = makeCallable(
- String.prototype.normalize,
+ stringPrototype.normalize,
);
/**
* Returns the result of padding the end of the string representation
* of the provided value padded until it is the desired length
- * according to the algorithm of String::padEnd.
+ * according to the algorithm of `String::padEnd`.
*/
-export const stringPadEnd = makeCallable(String.prototype.padEnd);
+export const stringPadEnd = makeCallable(stringPrototype.padEnd);
/**
* Returns the result of padding the start of the string representation
* of the provided value padded until it is the desired length
- * according to the algorithm of String::padStart.
+ * according to the algorithm of `String::padStart`.
*/
-export const stringPadStart = makeCallable(String.prototype.padStart);
+export const stringPadStart = makeCallable(stringPrototype.padStart);
/**
* Returns the result of repeating the string representation of the
* provided value the provided number of times according to the
- * algorithm of String::repeat.
+ * algorithm of `String::repeat`.
*/
-export const stringRepeat = makeCallable(String.prototype.repeat);
+export const stringRepeat = makeCallable(stringPrototype.repeat);
/**
* Returns the result of replacing the string representation of the
* provided value with the provided replacement, using the provided
- * matcher and according to the algorithm of String::replace.
+ * matcher and according to the algorithm of `String::replace`.
*/
-export const stringReplace = makeCallable(String.prototype.replace);
+export const stringReplace = makeCallable(stringPrototype.replace);
/**
* Returns the result of replacing the string representation of the
* provided value with the provided replacement, using the provided
- * matcher and according to the algorithm of String::replaceAll.
+ * matcher and according to the algorithm of `String::replaceAll`.
*/
export const stringReplaceAll = makeCallable(
- String.prototype.replaceAll,
+ stringPrototype.replaceAll,
);
/**
* Returns the result of searching the string representation of the
* provided value using the provided matcher and according to the
- * algorithm of String::search.
+ * algorithm of `String::search`.
*/
-export const stringSearch = makeCallable(String.prototype.search);
+export const stringSearch = makeCallable(stringPrototype.search);
/**
* Returns a slice of the string representation of the provided value
- * according to the algorithm of String::slice.
+ * according to the algorithm of `String::slice`.
*/
-export const stringSlice = makeCallable(String.prototype.slice);
+export const stringSlice = makeCallable(stringPrototype.slice);
/**
* Returns the result of splitting of the string representation of the
* provided value on the provided separator according to the algorithm
- * of String::split.
+ * of `String::split`.
*/
-export const stringSplit = makeCallable(String.prototype.split);
+export const stringSplit = makeCallable(stringPrototype.split);
/**
* Returns whether the string representation of the provided value
* starts with the provided search string according to the algorithm of
- * String::startsWith.
+ * `String::startsWith`.
*/
export const stringStartsWith = makeCallable(
- String.prototype.startsWith,
+ stringPrototype.startsWith,
);
/**
* ☡ This function will throw if the provided object does not have a
* `[[StringData]]` internal slot.
*/
-export const stringValue = makeCallable(String.prototype.valueOf);
+export const stringValue = makeCallable(stringPrototype.valueOf);
/**
* Returns the result of stripping leading and trailing A·S·C·I·I
* Returns the result of stripping leading and trailing A·S·C·I·I
* whitespace from the string representation of the provided value.
*/
-export const stripLeadingAndTrailingASCIIWhitespace = (() => {
- const { exec: reExec } = RegExp.prototype;
- return ($) =>
- call(reExec, /^[\n\r\t\f ]*([^]*?)[\n\r\t\f ]*$/u, [$])[1];
-})();
+export const stripLeadingAndTrailingASCIIWhitespace = ($) =>
+ call(reExec, /^[\n\r\t\f ]*([^]*?)[\n\r\t\f ]*$/u, [$])[1];
/**
* Returns a substring of the string representation of the provided
- * value according to the algorithm of String::substring.
+ * value according to the algorithm of `String::substring`.
*/
-export const substring = makeCallable(String.prototype.substring);
+export const substring = makeCallable(stringPrototype.substring);
/**
* Returns the result of converting the provided value to a string.
import {
assert,
assertEquals,
- assertSpyCall,
assertSpyCalls,
assertStrictEquals,
assertThrows,
return "etaoin";
},
});
+ assertEquals([...result], ["etaoin", "e"]);
assertSpyCalls(constraint, 1);
assertStrictEquals(constraint.calls[0].args[0], "etaoin");
assertEquals([...constraint.calls[0].args[1]], ["etaoin", "e"]);
// ♓🌟 Piscēs ∷ value.js
// ====================================================================
//
-// Copyright © 2022 Lady [@ Lady’s Computer].
+// Copyright © 2022‐2023 Lady [@ Lady’s Computer].
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
-import { call } from "./function.js";
+export const {
+ /** The welknown `@@asyncIterator` symbol. */
+ asyncIterator: ASYNC_ITERATOR,
+
+ /** The welknown `@@hasInstance` symbol. */
+ hasInstance: HAS_INSTANCE,
+
+ /** The welknown `@@isConcatSpreadable` symbol. */
+ isConcatSpreadable: IS_CONCAT_SPREADABLE,
+
+ /** The welknown `@@iterator` symbol. */
+ iterator: ITERATOR,
+
+ /** The welknown `@@match` symbol. */
+ match: MATCH,
+
+ /** The welknown `@@matchAll` symbol. */
+ matchAll: MATCH_ALL,
+
+ /** The welknown `@@replace` symbol. */
+ replace: REPLACE,
+
+ /** The welknown `@@species` symbol. */
+ species: SPECIES,
+
+ /** The welknown `@@split` symbol. */
+ split: SPLIT,
+
+ /** The welknown `@@toPrimitive` symbol. */
+ toPrimitive: TO_PRIMITIVE,
+
+ /** The welknown `@@toStringTag` symbol. */
+ toStringTag: TO_STRING_TAG,
+
+ /** The welknown `@@unscopables` symbol. */
+ unscopables: UNSCOPABLES,
+} = Symbol;
/** The null primitive. */
export const NULL = null;
export const {
/**
* Returns the primitive value of the provided object per its
- * `toString` and `valueOf` methods.
+ * `.toString` and `.valueOf` methods.
*
- * If the provided hint is "string", then `toString` takes
- * precedence; otherwise, `valueOf` does.
+ * If the provided hint is "string", then `.toString` takes
+ * precedence; otherwise, `.valueOf` does.
*
* Throws an error if both of these methods are not callable or do
* not return a primitive.
*
* The provided preferred type, if specified, should be "string",
* "number", or "default". If the provided input has a
- * `[Symbol.toPrimitive]` method, this function will throw rather
+ * `.[Symbol.toPrimitive]` method, this function will throw rather
* than calling that method with a preferred type other than one of
* the above.
*/
toPrimitive,
} = (() => {
- const { toPrimitive: toPrimitiveSymbol } = Symbol;
+ const { apply: call } = Reflect;
return {
ordinaryToPrimitive: (O, hint) => {
);
} else if (type($) === "object") {
// The provided value is an object.
- const exoticToPrim = $[toPrimitiveSymbol] ?? undefined;
+ const exoticToPrim = $[TO_PRIMITIVE] ?? undefined;
if (exoticToPrim !== undefined) {
// The provided value has an exotic primitive conversion
// method.
if (typeof exoticToPrim !== "function") {
// The method is not callable.
throw new TypeError(
- "Piscēs: `[Symbol.toPrimitive]` was neither nullish nor callable.",
+ "Piscēs: `.[Symbol.toPrimitive]` was neither nullish nor callable.",
);
} else {
// The method is callable.
// ♓🌟 Piscēs ∷ value.test.js
// ====================================================================
//
-// Copyright © 2022 Lady [@ Lady’s Computer].
+// Copyright © 2022–2023 Lady [@ Lady’s Computer].
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
it,
} from "./dev-deps.js";
import {
+ ASYNC_ITERATOR,
+ HAS_INSTANCE,
+ IS_CONCAT_SPREADABLE,
+ ITERATOR,
+ MATCH,
+ MATCH_ALL,
NULL,
ordinaryToPrimitive,
+ REPLACE,
sameValue,
sameValueZero,
+ SPECIES,
+ SPLIT,
+ TO_PRIMITIVE,
+ TO_STRING_TAG,
toPrimitive,
type,
UNDEFINED,
+ UNSCOPABLES,
} from "./value.js";
+describe("ASYNC_ITERATOR", () => {
+ it("[[Get]] is @@asyncIterator", () => {
+ assertStrictEquals(ASYNC_ITERATOR, Symbol.asyncIterator);
+ });
+});
+
+describe("HAS_INSTANCE", () => {
+ it("[[Get]] is @@hasInstance", () => {
+ assertStrictEquals(HAS_INSTANCE, Symbol.hasInstance);
+ });
+});
+
+describe("IS_CONCAT_SPREADABLE", () => {
+ it("[[Get]] is @@isConcatSpreadable", () => {
+ assertStrictEquals(
+ IS_CONCAT_SPREADABLE,
+ Symbol.isConcatSpreadable,
+ );
+ });
+});
+
+describe("ITERATOR", () => {
+ it("[[Get]] is @@iterator", () => {
+ assertStrictEquals(ITERATOR, Symbol.iterator);
+ });
+});
+
+describe("MATCH", () => {
+ it("[[Get]] is @@match", () => {
+ assertStrictEquals(MATCH, Symbol.match);
+ });
+});
+
+describe("MATCH_ALL", () => {
+ it("[[Get]] is @@matchAll", () => {
+ assertStrictEquals(MATCH_ALL, Symbol.matchAll);
+ });
+});
+
describe("NULL", () => {
it("[[Get]] is null", () => {
assertStrictEquals(NULL, null);
});
});
+describe("REPLACE", () => {
+ it("[[Get]] is @@replace", () => {
+ assertStrictEquals(REPLACE, Symbol.replace);
+ });
+});
+
+describe("SPECIES", () => {
+ it("[[Get]] is @@species", () => {
+ assertStrictEquals(SPECIES, Symbol.species);
+ });
+});
+
+describe("SPLIT", () => {
+ it("[[Get]] is @@split", () => {
+ assertStrictEquals(SPLIT, Symbol.split);
+ });
+});
+
+describe("TO_PRIMITIVE", () => {
+ it("[[Get]] is @@toPrimitive", () => {
+ assertStrictEquals(TO_PRIMITIVE, Symbol.toPrimitive);
+ });
+});
+
+describe("TO_STRING_TAG", () => {
+ it("[[Get]] is @@toStringTag", () => {
+ assertStrictEquals(TO_STRING_TAG, Symbol.toStringTag);
+ });
+});
+
describe("UNDEFINED", () => {
it("[[Get]] is undefined", () => {
assertStrictEquals(UNDEFINED, void {});
});
});
+describe("UNSCOPABLES", () => {
+ it("[[Get]] is @@unscopables", () => {
+ assertStrictEquals(UNSCOPABLES, Symbol.unscopables);
+ });
+});
+
describe("ordinaryToPrimitive", () => {
it("[[Call]] prefers `valueOf` by default", () => {
const obj = {