This allows us to be a little safer about our property descriptors.
// 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/>.
// 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, toFunctionName, toLength, type } from "./value.js";
+import {
+ ITERATOR,
+ toFunctionName,
+ toLength,
+ type,
+ UNDEFINED,
+} from "./value.js";
+import {
+ defineOwnDataProperty,
+ defineOwnProperties,
+ defineOwnProperty,
+ getOwnPropertyDescriptor,
+ getPrototype,
+ objectCreate,
+ setPropertyValues,
+ setPrototype,
+} from "./object.js";
} = functionPrototype;
const objectConstructor = Object;
const proxyConstructor = Proxy;
} = functionPrototype;
const objectConstructor = Object;
const proxyConstructor = Proxy;
- const {
- create: objectCreate,
- defineProperty: defineOwnProperty,
- defineProperties: defineOwnProperties,
- getOwnPropertyDescriptor,
- getPrototypeOf: getPrototype,
- setPrototypeOf: setPrototype,
- } = Object;
const {
apply: reflectApply,
construct: reflectConstruct,
const {
apply: reflectApply,
construct: reflectConstruct,
},
};
const applyBaseFunction = ($, base, lengthDelta = 0) => {
},
};
const applyBaseFunction = ($, base, lengthDelta = 0) => {
- if (base === undefined) {
+ if (base === UNDEFINED) {
// No base function was provided to apply.
return $;
} else {
// No base function was provided to apply.
return $;
} else {
}
};
const applyProperties = ($, override) => {
}
};
const applyProperties = ($, override) => {
- if (override === undefined) {
+ if (override === UNDEFINED) {
// No properties were provided to apply.
return $;
} else {
// Properties were provided; apply them.
const { length, name, prototype } = override;
if (
// No properties were provided to apply.
return $;
} else {
// Properties were provided; apply them.
const { length, name, prototype } = override;
if (
- !getOwnPropertyDescriptor($, "prototype")?.writable ||
- prototype === undefined
+ prototype === UNDEFINED ||
+ !getOwnPropertyDescriptor($, "prototype")?.writable
) {
// The provided function has no `.prototype`, its prototype is
// not writable, or no prototype value was provided.
) {
// The provided function has no `.prototype`, its prototype is
// not writable, or no prototype value was provided.
//
// Change the prototype property of the provided function to
// match.
//
// Change the prototype property of the provided function to
// match.
- defineOwnProperty($, "prototype", { value: prototype });
+ defineOwnProperty(
+ $,
+ "prototype",
+ defineOwnDataProperty(
+ objectCreate(null),
+ "value",
+ prototype,
+ ),
+ );
}
return defineOwnProperties($, {
}
return defineOwnProperties($, {
- length: {
- value: toLength(length === undefined ? $.length : length),
- },
- name: {
- value: toFunctionName(
- name === undefined ? $.name ?? "" : name,
- ),
- },
+ length: defineOwnDataProperty(
+ objectCreate(null),
+ "value",
+ toLength(length === UNDEFINED ? $.length : length),
+ ),
+ name: defineOwnDataProperty(
+ objectCreate(null),
+ "value",
+ toFunctionName(name === UNDEFINED ? $.name ?? "" : name),
+ ),
- ...objectCreate(
- argumentIterablePrototype,
- { args: { value: boundArgs } },
+ ...defineOwnDataProperty(
+ objectCreate(argumentIterablePrototype),
+ "args",
+ boundArgs,
- createArrowFunction: ($, propertyOverride = undefined) =>
+ createArrowFunction: ($, propertyOverride = UNDEFINED) =>
applyProperties(
applyBaseFunction(
applyProperties(
applyBaseFunction(
- (...$s) => reflectApply($, undefined, $s),
+ (...$s) => reflectApply($, UNDEFINED, $s),
$,
),
propertyOverride,
),
$,
),
propertyOverride,
),
- createCallableFunction: ($, propertyOverride = undefined) =>
+ createCallableFunction: ($, propertyOverride = UNDEFINED) =>
applyProperties(
applyBaseFunction(
(...$s) => {
applyProperties(
applyBaseFunction(
(...$s) => {
- const iterator = objectCreate(
- argumentIterablePrototype,
- { args: { value: $s } },
+ const iterator = defineOwnDataProperty(
+ objectCreate(argumentIterablePrototype),
+ "args",
+ $s,
)[ITERATOR]();
const { value: thisValue } = iterator.next();
return reflectApply($, thisValue, [...iterator]);
)[ITERATOR]();
const { value: thisValue } = iterator.next();
return reflectApply($, thisValue, [...iterator]);
- createIllegalConstructor: ($, propertyOverride = undefined) =>
+ createIllegalConstructor: ($, propertyOverride = UNDEFINED) =>
defineOwnProperty(
applyProperties(
applyBaseFunction(
defineOwnProperty(
applyProperties(
applyBaseFunction(
createProxyConstructor: (
handler,
$,
createProxyConstructor: (
handler,
$,
- newTarget = undefined,
- propertyOverride = undefined,
+ newTarget = UNDEFINED,
+ propertyOverride = UNDEFINED,
- const constructor = $ === undefined ? objectConstructor : $;
- const target = newTarget === undefined ? constructor : newTarget;
+ const constructor = $ === UNDEFINED ? objectConstructor : $;
+ const target = newTarget === UNDEFINED ? constructor : newTarget;
const len = toLength(constructor.length);
if (!(type(handler) === "object")) {
const len = toLength(constructor.length);
if (!(type(handler) === "object")) {
+ // The provided handler is not an object; this is an error.
throw new TypeError(
`Piscēs: Proxy handler must be an object, but got: ${handler}.`,
);
} else if (!isConstructor(constructor)) {
throw new TypeError(
`Piscēs: Proxy handler must be an object, but got: ${handler}.`,
);
} else if (!isConstructor(constructor)) {
+ // The provided constructor is not a constructor; this is an
+ // error.
throw new TypeError(
"Piscēs: Cannot create proxy constructor from nonconstructible value.",
);
} else if (!isConstructor(target)) {
throw new TypeError(
"Piscēs: Cannot create proxy constructor from nonconstructible value.",
);
} else if (!isConstructor(target)) {
+ // The provided new target is not a constructor; this is an
+ // error.
throw new TypeError(
"Piscēs: New target must be a constructor.",
);
} else {
throw new TypeError(
"Piscēs: New target must be a constructor.",
);
} else {
+ // The arguments are acceptable.
return applyProperties(
defineOwnProperties(
setPrototype(
function C(...$s) {
return applyProperties(
defineOwnProperties(
setPrototype(
function C(...$s) {
- if (new.target === undefined) {
+ if (new.target === UNDEFINED) {
+ // The constructor was not called with new; this is
+ // an error.
throw new TypeError(
`Piscēs: ${
C.name ?? "Proxy"
} must be called with new.`,
);
} else {
throw new TypeError(
`Piscēs: ${
C.name ?? "Proxy"
} must be called with new.`,
);
} else {
+ // The constructor was called with new; return the
+ // appropriate proxy.
const O = reflectConstruct(
constructor,
$s,
const O = reflectConstruct(
constructor,
$s,
- length: { value: len },
- name: {
- value: `${
- toFunctionName(constructor.name ?? "")
- }Proxy`,
- },
- prototype: {
+ length: defineOwnDataProperty(
+ objectCreate(null),
+ "value",
+ len,
+ ),
+ name: defineOwnDataProperty(
+ objectCreate(null),
+ "value",
+ `${toFunctionName(constructor.name ?? "")}Proxy`,
+ ),
+ prototype: setPropertyValues(objectCreate(null), {
configurable: false,
enumerable: false,
configurable: false,
enumerable: false,
+ }),
+ revocable: setPropertyValues(objectCreate(null), {
configurable: true,
enumerable: false,
value: defineOwnProperties(
configurable: true,
enumerable: false,
value: defineOwnProperties(
return revocable(O, handler);
},
{
return revocable(O, handler);
},
{
- length: { value: len },
- name: { value: "revocable" },
+ length: defineOwnDataProperty(
+ objectCreate(null),
+ "value",
+ len,
+ ),
+ name: defineOwnDataProperty(
+ objectCreate(null),
+ "value",
+ "revocable",
+ ),