Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: separately export __proto__ for compatibility with CJS Transpiler Re-exports #5380

Merged
merged 12 commits into from
Feb 15, 2024
16 changes: 11 additions & 5 deletions src/finalisers/shared/getExportBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,16 @@ export function getExportBlock(
for (const specifier of reexports) {
if (specifier.reexported === '*') {
if (exportBlock) exportBlock += n;
if (!specifier.needsLiveBinding) {
const protoString = "'__proto__'";
exportBlock +=
`Object.prototype.hasOwnProperty.call(${name},${_}${protoString})${_}&&${n}` +
`${t}!Object.prototype.hasOwnProperty.call(exports,${_}${protoString})${_}&&${n}` +
`${t}Object.defineProperty(exports,${_}${protoString},${_}{${n}` +
`${t}${t}enumerable:${_}true,${n}` +
`${t}${t}value:${_}${name}[${protoString}]${n}` +
`${t}});${n}${n}`;
}
const copyPropertyIfNecessary = `{${n}${t}if${_}(k${_}!==${_}'default'${_}&&${_}!Object.prototype.hasOwnProperty.call(exports,${_}k))${_}${getDefineProperty(
name,
specifier.needsLiveBinding,
Expand Down Expand Up @@ -251,9 +261,5 @@ const getDefineProperty = (
`${t}${t}get:${_}${left}${name}[k]${right}${n}${t}})`
);
}
return (
`k${_}===${_}'__proto__'${_}?${_}Object.defineProperty(exports,${_}k,${_}{${n}` +
`${t}${t}enumerable:${_}true,${n}` +
`${t}${t}value:${_}${name}[k]${n}${t}})${_}:${_}exports[k]${_}=${_}${name}[k]`
);
return `exports[k]${_}=${_}${name}[k]`;
};
49 changes: 49 additions & 0 deletions test/form/samples/cjs-transpiler-re-exports/_config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const { execSync } = require('node:child_process');
TrickyPi marked this conversation as resolved.
Show resolved Hide resolved

module.exports = defineTest({
description:
'Compatibility with CJS Transpiler Re-exports if output.externalLiveBindings is false',
formats: ['cjs'],
options: {
output: {
externalLiveBindings: false
},
plugins: [
{
resolveId(id) {
if (id.endsWith('main.js')) {
return { id };
}
return {
id,
external: true
};
},
buildEnd() {
this.emitFile({
type: 'prebuilt-chunk',
fileName: 'foo.js',
code:
'exports.foo = 1;\n' +
'Object.defineProperty(exports, "__proto__", {\n' +
' enumerable: true,\n' +
' value: 2\n' +
'});'
});
this.emitFile({
type: 'prebuilt-chunk',
fileName: 'execute.mjs',
code:
'import assert from "node:assert";\n' +
'import { foo, __proto__ } from "./cjs.js";\n' +
'assert.strictEqual(foo, 1);\n' +
'assert.strictEqual(__proto__, 2);'
});
}
}
]
},
after() {
execSync('node _actual/execute.mjs', { cwd: __dirname });
}
});
16 changes: 16 additions & 0 deletions test/form/samples/cjs-transpiler-re-exports/_expected/cjs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
'use strict';

var foo_js = require('./foo.js');



Object.prototype.hasOwnProperty.call(foo_js, '__proto__') &&
!Object.prototype.hasOwnProperty.call(exports, '__proto__') &&
Object.defineProperty(exports, '__proto__', {
enumerable: true,
value: foo_js['__proto__']
});

Object.keys(foo_js).forEach(function (k) {
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) exports[k] = foo_js[k];
});
1 change: 1 addition & 0 deletions test/form/samples/cjs-transpiler-re-exports/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './foo.js';
12 changes: 8 additions & 4 deletions test/form/samples/export-__proto__/_expected/amd.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@ define(['exports', 'x'], (function (exports, x$1) { 'use strict';
value: __proto__
});
exports.x = x;
Object.keys(x$1).forEach(function (k) {
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) k === '__proto__' ? Object.defineProperty(exports, k, {
Object.prototype.hasOwnProperty.call(x$1, '__proto__') &&
!Object.prototype.hasOwnProperty.call(exports, '__proto__') &&
Object.defineProperty(exports, '__proto__', {
enumerable: true,
value: x$1[k]
}) : exports[k] = x$1[k];
value: x$1['__proto__']
});

Object.keys(x$1).forEach(function (k) {
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) exports[k] = x$1[k];
});

}));
12 changes: 8 additions & 4 deletions test/form/samples/export-__proto__/_expected/cjs.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@ Object.defineProperty(exports, "__proto__", {
value: __proto__
});
exports.x = x;
Object.keys(x$1).forEach(function (k) {
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) k === '__proto__' ? Object.defineProperty(exports, k, {
Object.prototype.hasOwnProperty.call(x$1, '__proto__') &&
!Object.prototype.hasOwnProperty.call(exports, '__proto__') &&
Object.defineProperty(exports, '__proto__', {
enumerable: true,
value: x$1[k]
}) : exports[k] = x$1[k];
value: x$1['__proto__']
});

Object.keys(x$1).forEach(function (k) {
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) exports[k] = x$1[k];
});
12 changes: 8 additions & 4 deletions test/form/samples/export-__proto__/_expected/iife.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ var bundle = (function (exports, x$1) {
value: __proto__
});
exports.x = x;
Object.keys(x$1).forEach(function (k) {
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) k === '__proto__' ? Object.defineProperty(exports, k, {
Object.prototype.hasOwnProperty.call(x$1, '__proto__') &&
!Object.prototype.hasOwnProperty.call(exports, '__proto__') &&
Object.defineProperty(exports, '__proto__', {
enumerable: true,
value: x$1[k]
}) : exports[k] = x$1[k];
value: x$1['__proto__']
});

Object.keys(x$1).forEach(function (k) {
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) exports[k] = x$1[k];
});

return exports;
Expand Down
12 changes: 8 additions & 4 deletions test/form/samples/export-__proto__/_expected/umd.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@
value: __proto__
});
exports.x = x;
Object.keys(x$1).forEach(function (k) {
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) k === '__proto__' ? Object.defineProperty(exports, k, {
Object.prototype.hasOwnProperty.call(x$1, '__proto__') &&
!Object.prototype.hasOwnProperty.call(exports, '__proto__') &&
Object.defineProperty(exports, '__proto__', {
enumerable: true,
value: x$1[k]
}) : exports[k] = x$1[k];
value: x$1['__proto__']
});

Object.keys(x$1).forEach(function (k) {
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) exports[k] = x$1[k];
});

}));

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 8 additions & 4 deletions test/form/samples/no-external-live-bindings/_expected/amd.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,15 @@ define(['require', 'exports', 'external1', 'external2'], (function (require, exp

exports.external1 = external1.external1;
exports.dynamic = dynamic;
Object.keys(external2).forEach(function (k) {
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) k === '__proto__' ? Object.defineProperty(exports, k, {
Object.prototype.hasOwnProperty.call(external2, '__proto__') &&
!Object.prototype.hasOwnProperty.call(exports, '__proto__') &&
Object.defineProperty(exports, '__proto__', {
enumerable: true,
value: external2[k]
}) : exports[k] = external2[k];
value: external2['__proto__']
});

Object.keys(external2).forEach(function (k) {
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) exports[k] = external2[k];
});

}));
12 changes: 8 additions & 4 deletions test/form/samples/no-external-live-bindings/_expected/cjs.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@ const dynamic = Promise.resolve().then(function () { return /*#__PURE__*/_intero

exports.external1 = external1.external1;
exports.dynamic = dynamic;
Object.keys(external2).forEach(function (k) {
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) k === '__proto__' ? Object.defineProperty(exports, k, {
Object.prototype.hasOwnProperty.call(external2, '__proto__') &&
!Object.prototype.hasOwnProperty.call(exports, '__proto__') &&
Object.defineProperty(exports, '__proto__', {
enumerable: true,
value: external2[k]
}) : exports[k] = external2[k];
value: external2['__proto__']
});

Object.keys(external2).forEach(function (k) {
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) exports[k] = external2[k];
});
12 changes: 8 additions & 4 deletions test/form/samples/no-external-live-bindings/_expected/iife.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ var bundle = (function (exports, external1, external2) {

exports.external1 = external1.external1;
exports.dynamic = dynamic;
Object.keys(external2).forEach(function (k) {
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) k === '__proto__' ? Object.defineProperty(exports, k, {
Object.prototype.hasOwnProperty.call(external2, '__proto__') &&
!Object.prototype.hasOwnProperty.call(exports, '__proto__') &&
Object.defineProperty(exports, '__proto__', {
enumerable: true,
value: external2[k]
}) : exports[k] = external2[k];
value: external2['__proto__']
});

Object.keys(external2).forEach(function (k) {
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) exports[k] = external2[k];
});

return exports;
Expand Down
12 changes: 8 additions & 4 deletions test/form/samples/no-external-live-bindings/_expected/umd.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@

exports.external1 = external1.external1;
exports.dynamic = dynamic;
Object.keys(external2).forEach(function (k) {
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) k === '__proto__' ? Object.defineProperty(exports, k, {
Object.prototype.hasOwnProperty.call(external2, '__proto__') &&
!Object.prototype.hasOwnProperty.call(exports, '__proto__') &&
Object.defineProperty(exports, '__proto__', {
enumerable: true,
value: external2[k]
}) : exports[k] = external2[k];
value: external2['__proto__']
});

Object.keys(external2).forEach(function (k) {
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) exports[k] = external2[k];
});

}));