Skip to content

Commit 8d89fc9

Browse files
ExE-Bossdomenic
authored andcommitted
Make it possible to have depency cycles involving the generated files
This commit switches the generated files from using module.exports to using exports. This means that, as long as imports are referenced in certain careful ways, such as const Foo = require("./generated/Foo"); // later Foo.isImpl() instead of const isFooImpl = require("./generated/Foo").isImpl; // later isFooImpl() that the generated files can now be used as part of dependency cycles. Although this is fragile and not a pattern that should be used often, it can be important for implementing certain parts of the web platform which involve circular dependencies at the spec level.
1 parent a99c82f commit 8d89fc9

File tree

7 files changed

+5469
-5531
lines changed

7 files changed

+5469
-5531
lines changed

lib/constructs/attribute.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class Attribute {
2828
objName = `obj`;
2929
}
3030
let brandCheck = `
31-
if (!this || !module.exports.is(this)) {
31+
if (!this || !exports.is(this)) {
3232
throw new TypeError("Illegal invocation");
3333
}
3434
`;
@@ -111,7 +111,7 @@ class Attribute {
111111

112112
if (!this.static && this.idl.special === "stringifier") {
113113
addMethod("toString", [], `
114-
if (!this || !module.exports.is(this)) {
114+
if (!this || !exports.is(this)) {
115115
throw new TypeError("Illegal invocation");
116116
}
117117
${getterBody};

lib/constructs/dictionary.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,7 @@ class Dictionary {
7070

7171
generate() {
7272
this.str += `
73-
module.exports = {
74-
convertInherit(obj, ret, { context = "The provided value" } = {}) {
73+
exports.convertInherit = function convertInherit(obj, ret, { context = "The provided value" } = {}) {
7574
`;
7675

7776
if (this.idl.inheritance) {
@@ -82,18 +81,17 @@ class Dictionary {
8281

8382
this.str += `
8483
${this._generateConversions()}
85-
},
84+
};
8685
87-
convert(obj, { context = "The provided value" } = {}) {
86+
exports.convert = function convert(obj, { context = "The provided value" } = {}) {
8887
if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
8988
throw new TypeError(\`\${context} is not an object.\`);
9089
}
9190
9291
const ret = Object.create(null);
9392
module.exports.convertInherit(obj, ret, { context });
9493
return ret;
95-
}
96-
};
94+
};
9795
`;
9896

9997
if (this.idl.inheritance) {

lib/constructs/enumeration.js

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,14 @@ class Enumeration {
1616

1717
this.str += `
1818
const enumerationValues = new Set(${JSON.stringify([...values])});
19-
module.exports = {
20-
enumerationValues,
21-
convert(value, { context = "The provided value" } = {}) {
22-
const string = \`\${value}\`;
23-
if (!enumerationValues.has(value)) {
24-
throw new TypeError(\`\${context} '\${value}' is not a valid enumeration value for ${this.name}\`);
25-
}
26-
return string;
19+
exports.enumerationValues = enumerationValues;
20+
21+
exports.convert = function convert(value, { context = "The provided value" } = {}) {
22+
const string = \`\${value}\`;
23+
if (!enumerationValues.has(value)) {
24+
throw new TypeError(\`\${context} '\${value}' is not a valid enumeration value for ${this.name}\`);
2725
}
26+
return string;
2827
};
2928
`;
3029
}

lib/constructs/interface.js

Lines changed: 32 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -519,63 +519,65 @@ class Interface {
519519
generateMixins() {
520520
for (const iface of this.consequentialInterfaces()) {
521521
this.str += `
522-
${iface}._mixedIntoPredicates.push(module.exports.is);
522+
${iface}._mixedIntoPredicates.push(exports.is);
523523
`;
524524
}
525525
}
526526

527527
generateExport() {
528528
this.str += `
529-
// When an interface-module that implements this interface as a mixin is loaded, it will append its own \`.is()\`
530-
// method into this array. It allows objects that directly implements *those* interfaces to be recognized as
531-
// implementing this mixin interface.
532-
_mixedIntoPredicates: [],
533-
is(obj) {
529+
/**
530+
* When an interface-module that implements this interface as a mixin is loaded, it will append its own \`.is()\`
531+
* method into this array. It allows objects that directly implements *those* interfaces to be recognized as
532+
* implementing this mixin interface.
533+
*/
534+
exports._mixedIntoPredicates = [];
535+
exports.is = function is(obj) {
534536
if (obj) {
535537
if (utils.hasOwn(obj, impl) && obj[impl] instanceof Impl.implementation) {
536538
return true;
537539
}
538-
for (const isMixedInto of module.exports._mixedIntoPredicates) {
540+
for (const isMixedInto of exports._mixedIntoPredicates) {
539541
if (isMixedInto(obj)) {
540542
return true;
541543
}
542544
}
543545
}
544546
return false;
545-
},
546-
isImpl(obj) {
547+
};
548+
exports.isImpl = function isImpl(obj) {
547549
if (obj) {
548550
if (obj instanceof Impl.implementation) {
549551
return true;
550552
}
551553
552554
const wrapper = utils.wrapperForImpl(obj);
553-
for (const isMixedInto of module.exports._mixedIntoPredicates) {
555+
for (const isMixedInto of exports._mixedIntoPredicates) {
554556
if (isMixedInto(wrapper)) {
555557
return true;
556558
}
557559
}
558560
}
559561
return false;
560-
},
561-
convert(obj, { context = "The provided value" } = {}) {
562-
if (module.exports.is(obj)) {
562+
};
563+
exports.convert = function convert(obj, { context = "The provided value" } = {}) {
564+
if (exports.is(obj)) {
563565
return utils.implForWrapper(obj);
564566
}
565567
throw new TypeError(\`\${context} is not of type '${this.name}'.\`);
566-
},
568+
};
567569
`;
568570

569571
if (this.iterable && this.iterable.isPair) {
570572
this.str += `
571-
createDefaultIterator(target, kind) {
573+
exports.createDefaultIterator = function createDefaultIterator(target, kind) {
572574
const iterator = Object.create(IteratorPrototype);
573575
Object.defineProperty(iterator, utils.iterInternalSymbol, {
574576
value: { target, kind, index: 0 },
575577
configurable: true
576578
});
577579
return iterator;
578-
},
580+
};
579581
`;
580582
}
581583
}
@@ -1098,7 +1100,7 @@ class Interface {
10981100

10991101
generateIface() {
11001102
this.str += `
1101-
create(globalObject, constructorArgs, privateData) {
1103+
exports.create = function create(globalObject, constructorArgs, privateData) {
11021104
if (globalObject[ctorRegistry] === undefined) {
11031105
throw new Error('Internal error: invalid global object');
11041106
}
@@ -1109,14 +1111,14 @@ class Interface {
11091111
}
11101112
11111113
let obj = Object.create(ctor.prototype);
1112-
obj = iface.setup(obj, globalObject, constructorArgs, privateData);
1114+
obj = exports.setup(obj, globalObject, constructorArgs, privateData);
11131115
return obj;
1114-
},
1115-
createImpl(globalObject, constructorArgs, privateData) {
1116-
const obj = iface.create(globalObject, constructorArgs, privateData);
1116+
};
1117+
exports.createImpl = function createImpl(globalObject, constructorArgs, privateData) {
1118+
const obj = exports.create(globalObject, constructorArgs, privateData);
11171119
return utils.implForWrapper(obj);
1118-
},
1119-
_internalSetup(obj) {
1120+
};
1121+
exports._internalSetup = function _internalSetup(obj) {
11201122
`;
11211123

11221124
if (this.idl.inheritance) {
@@ -1128,11 +1130,11 @@ class Interface {
11281130
this.generateOnInstance();
11291131

11301132
this.str += `
1131-
},
1132-
setup(obj, globalObject, constructorArgs = [], privateData = {}) {
1133+
};
1134+
exports.setup = function setup(obj, globalObject, constructorArgs = [], privateData = {}) {
11331135
privateData.wrapper = obj;
11341136
1135-
iface._internalSetup(obj);
1137+
exports._internalSetup(obj);
11361138
Object.defineProperty(obj, impl, {
11371139
value: new Impl.implementation(globalObject, constructorArgs, privateData),
11381140
configurable: true
@@ -1149,7 +1151,7 @@ class Interface {
11491151
Impl.init(obj[impl], privateData);
11501152
}
11511153
return obj;
1152-
},
1154+
};
11531155
`;
11541156
}
11551157

@@ -1180,7 +1182,7 @@ class Interface {
11801182

11811183
body = `
11821184
${conversions.body}
1183-
return iface.setup(${formatArgs(setupArgs)});
1185+
return exports.setup(${formatArgs(setupArgs)});
11841186
`;
11851187
} else {
11861188
body = `
@@ -1414,7 +1416,7 @@ class Interface {
14141416
const { idl, name } = this;
14151417

14161418
this.str += `
1417-
install(globalObject) {
1419+
exports.install = function install(globalObject) {
14181420
`;
14191421

14201422
if (idl.inheritance) {
@@ -1444,26 +1446,17 @@ class Interface {
14441446
writable: true,
14451447
value: ${name}
14461448
});
1447-
},
1449+
};
14481450
`;
14491451
}
14501452

14511453
generate() {
14521454
this.generateIterator();
14531455

1454-
this.str += `
1455-
const iface = {
1456-
`;
1457-
14581456
this.generateExport();
14591457
this.generateIface();
14601458
this.generateInstall();
14611459

1462-
this.str += `
1463-
}; // iface
1464-
module.exports = iface;
1465-
`;
1466-
14671460
this.generateMixins();
14681461
this.generateRequires();
14691462
}

lib/constructs/iterable.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ class Iterable {
2020

2121
generateFunction(key, kind) {
2222
this.interface.addMethod(this.interface.defaultWhence, key, [], `
23-
if (!this || !module.exports.is(this)) {
23+
if (!this || !exports.is(this)) {
2424
throw new TypeError("Illegal invocation");
2525
}
26-
return module.exports.createDefaultIterator(this, "${kind}");
26+
return exports.createDefaultIterator(this, "${kind}");
2727
`);
2828
}
2929

@@ -35,7 +35,7 @@ class Iterable {
3535
this.generateFunction("entries", "key+value");
3636
this.interface.addProperty(whence, Symbol.iterator, `${this.interface.name}.prototype.entries`);
3737
this.interface.addMethod(whence, "forEach", ["callback"], `
38-
if (!this || !module.exports.is(this)) {
38+
if (!this || !exports.is(this)) {
3939
throw new TypeError("Illegal invocation");
4040
}
4141
if (arguments.length < 1) {

lib/constructs/operation.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class Operation {
6161

6262
if (!this.static) {
6363
str += `
64-
if (!this || !module.exports.is(this)) {
64+
if (!this || !exports.is(this)) {
6565
throw new TypeError("Illegal invocation");
6666
}
6767
`;

0 commit comments

Comments
 (0)