Skip to content

Commit

Permalink
Mark class prototype as read-only
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolo-ribaudo committed Dec 10, 2021
1 parent 0f0e41c commit acda160
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 13 deletions.
Expand Up @@ -14,6 +14,9 @@
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
Object.defineProperty(Constructor, "prototype", {
writable: false
});
return Constructor;
}

Expand Down
16 changes: 10 additions & 6 deletions packages/babel-helpers/src/helpers.ts
Expand Up @@ -223,6 +223,7 @@ helpers.createClass = helper("7.0.0-beta.0")`
export default function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
Object.defineProperty(Constructor, "prototype", { writable: false });
return Constructor;
}
`;
Expand Down Expand Up @@ -334,12 +335,15 @@ helpers.inherits = helper("7.0.0-beta.0")`
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function");
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
writable: true,
configurable: true
}
Object.defineProperty(subClass, "prototype", {
value: Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
writable: true,
configurable: true
}
}),
writable: false,
});
if (superClass) setPrototypeOf(subClass, superClass);
}
Expand Down
21 changes: 14 additions & 7 deletions packages/babel-plugin-transform-classes/src/transformClass.ts
Expand Up @@ -60,6 +60,7 @@ export default function transformClass(
pushedInherits: false,
protoAlias: null,
isLoose: false,
createClassInjected: false,

dynamicKeys: new Map(),

Expand Down Expand Up @@ -93,6 +94,10 @@ export default function transformClass(
},
]);

function createClassHelper(args) {
return t.callExpression(classState.file.addHelper("createClass"), args);
}

/**
* Creates a class constructor or bail out if there is none
*/
Expand Down Expand Up @@ -240,11 +245,8 @@ export default function transformClass(
}
args = args.slice(0, lastNonNullIndex + 1);

body.push(
t.expressionStatement(
t.callExpression(classState.file.addHelper("createClass"), args),
),
);
body.push(t.expressionStatement(createClassHelper(args)));
classState.createClassInjected = true;
}
}

Expand Down Expand Up @@ -737,10 +739,15 @@ export default function transformClass(

if (constructorOnly) {
// named class with only a constructor
return t.toExpression(body[0]);
return createClassHelper([t.toExpression(body[0])]);
}

let returnArg = t.cloneNode(classState.classRef);
if (!classState.createClassInjected) {
returnArg = createClassHelper([returnArg]);
}

body.push(t.returnStatement(t.cloneNode(classState.classRef)));
body.push(t.returnStatement(returnArg));
const container = t.arrowFunctionExpression(
closureParams,
t.blockStatement(body, directives),
Expand Down
@@ -0,0 +1,16 @@
class A {}
class B extends A {}

expect(Object.getOwnPropertyDescriptor(A, "prototype")).toEqual({
value: A.prototype,
configurable: false,
enumerable: false,
writable: false,
});

expect(Object.getOwnPropertyDescriptor(B, "prototype")).toEqual({
value: B.prototype,
configurable: false,
enumerable: false,
writable: false,
});

0 comments on commit acda160

Please sign in to comment.