@@ -14,12 +14,13 @@ const keywords = require("../keywords");
1414function Interface ( idl , opts ) {
1515 this . idl = idl ;
1616 this . name = idl . name ;
17+ this . factory = ! ! utils . getExtAttr ( this . idl . extAttrs , "WebIDL2JSFactory" ) ;
1718
1819 this . mixins = [ ] ;
1920 this . requires = { } ;
2021 this . str = null ;
2122 this . opts = opts ;
22- this . iterable = false ;
23+ this . iterable = this . idl . members . some ( member => member . type === "iterable" ) ;
2324}
2425
2526Interface . prototype . type = "interface" ;
@@ -28,6 +29,55 @@ Interface.prototype.implements = function (source) {
2829 this . mixins . push ( source ) ;
2930} ;
3031
32+ Interface . prototype . generateIterator = function ( ) {
33+ if ( this . iterable ) {
34+ this . str += `
35+ const IteratorPrototype = Object.create(utils.IteratorPrototype, {
36+ next: {
37+ value: function next() {
38+ const internal = this[utils.iterInternalSymbol];
39+ const target = internal.target;
40+ const kind = internal.kind;
41+ const index = internal.index;
42+ const values = Array.from(target[impl]);
43+ const len = values.length;
44+ if (index >= len) {
45+ return { value: undefined, done: true };
46+ }
47+
48+ const pair = values[index];
49+ internal.index = index + 1;
50+
51+ let result;
52+ switch (kind) {
53+ case "key":
54+ result = pair[0];
55+ break;
56+ case "value":
57+ result = pair[1];
58+ break;
59+ case "key+value":
60+ result = [pair[0], pair[1]];
61+ break;
62+ }
63+ return { value: result, done: false };
64+ },
65+ writable: true,
66+ enumerable: true,
67+ configurable: true
68+ },
69+ toString: {
70+ value: function toString() {
71+ return "[object ${ this . name } Iterator]";
72+ },
73+ writable: true,
74+ enumerable: false,
75+ configurable: true
76+ }
77+ });` ;
78+ }
79+ } ;
80+
3181Interface . prototype . generateConstructor = function ( ) {
3282 const overloads = Overloads . getEffectiveOverloads ( "constructor" , 0 , this . idl , null ) ;
3383
@@ -58,7 +108,7 @@ Interface.prototype.generateConstructor = function () {
58108 this . str += conversions . body + "\n" ;
59109
60110 this . str += `
61- module.exports .setup(this, args);
111+ iface .setup(this, args);
62112}\n` ;
63113 } else {
64114 this . str += `function ${ this . name } () {
@@ -105,6 +155,52 @@ ${this.mixins[i]}.mixedInto.push(${this.name});\n`;
105155} ;
106156
107157Interface . prototype . generateExport = function ( ) {
158+ this . str += `
159+ mixedInto: [],
160+ is(obj) {
161+ if (obj) {
162+ if (obj[impl] instanceof Impl.implementation) {
163+ return true;
164+ }
165+ for (let i = 0; i < module.exports.mixedInto.length; ++i) {
166+ if (obj instanceof module.exports.mixedInto[i]) {
167+ return true;
168+ }
169+ }
170+ }
171+ return false;
172+ },
173+ isImpl(obj) {
174+ if (obj) {
175+ if (obj instanceof Impl.implementation) {
176+ return true;
177+ }
178+
179+ const wrapper = utils.wrapperForImpl(obj);
180+ for (let i = 0; i < module.exports.mixedInto.length; ++i) {
181+ if (wrapper instanceof module.exports.mixedInto[i]) {
182+ return true;
183+ }
184+ }
185+ }
186+ return false;
187+ },` ;
188+
189+ if ( this . iterable ) {
190+ this . str += `
191+ createDefaultIterator(target, kind) {
192+ const iterator = Object.create(IteratorPrototype);
193+ iterator[utils.iterInternalSymbol] = {
194+ target,
195+ kind,
196+ index: 0
197+ };
198+ return iterator;
199+ },` ;
200+ }
201+ } ;
202+
203+ Interface . prototype . generateIface = function ( ) {
108204 const shouldExposeRoot = ! utils . getExtAttr ( this . idl . extAttrs , "NoInterfaceObject" ) ;
109205
110206 const exposedMap = { } ;
@@ -132,84 +228,9 @@ Interface.prototype.generateExport = function () {
132228 exposers . push ( keys [ i ] + ": { " + exposedOnObj . join ( ", " ) + " }" ) ;
133229 }
134230
135- if ( this . iterable ) {
136- this . str += `\nconst IteratorPrototype = Object.create(utils.IteratorPrototype, {
137- next: {
138- value: function next() {
139- const internal = this[utils.iterInternalSymbol];
140- const target = internal.target;
141- const kind = internal.kind;
142- const index = internal.index;
143- const values = Array.from(target[impl]);
144- const len = values.length;
145- if (index >= len) {
146- return { value: undefined, done: true };
147- }
148-
149- const pair = values[index];
150- internal.index = index + 1;
151-
152- let result;
153- switch (kind) {
154- case "key":
155- result = pair[0];
156- break;
157- case "value":
158- result = pair[1];
159- break;
160- case "key+value":
161- result = [pair[0], pair[1]];
162- break;
163- }
164- return { value: result, done: false };
165- },
166- writable: true,
167- enumerable: true,
168- configurable: true
169- },
170- toString: {
171- value: function toString() {
172- return "[object ${ this . name } Iterator]";
173- },
174- writable: true,
175- enumerable: false,
176- configurable: true
177- }
178- });` ;
179- }
180-
181231 // since we don't have spread arg calls, we can't do new Interface(...arguments) yet
182232 // add initialized symbol as to not destroy the object shape and cause deopts
183- this . str += `\nmodule.exports = {
184- mixedInto: [],
185- is(obj) {
186- if (obj) {
187- if (obj[impl] instanceof Impl.implementation) {
188- return true;
189- }
190- for (let i = 0; i < module.exports.mixedInto.length; ++i) {
191- if (obj instanceof module.exports.mixedInto[i]) {
192- return true;
193- }
194- }
195- }
196- return false;
197- },
198- isImpl(obj) {
199- if (obj) {
200- if (obj instanceof Impl.implementation) {
201- return true;
202- }
203-
204- const wrapper = utils.wrapperForImpl(obj);
205- for (let i = 0; i < module.exports.mixedInto.length; ++i) {
206- if (wrapper instanceof module.exports.mixedInto[i]) {
207- return true;
208- }
209- }
210- }
211- return false;
212- },
233+ this . str += `
213234 create(constructorArgs, privateData) {
214235 let obj = Object.create(${ this . name } .prototype);
215236 this.setup(obj, constructorArgs, privateData);
@@ -220,15 +241,6 @@ Interface.prototype.generateExport = function () {
220241 this.setup(obj, constructorArgs, privateData);
221242 return utils.implForWrapper(obj);
222243 },
223- createDefaultIterator(target, kind) {
224- const iterator = Object.create(IteratorPrototype);
225- iterator[utils.iterInternalSymbol] = {
226- target,
227- kind,
228- index: 0
229- };
230- return iterator;
231- },
232244 _internalSetup(obj) {` ;
233245
234246 if ( this . idl . inheritance ) {
@@ -255,7 +267,18 @@ Interface.prototype.generateExport = function () {
255267 this . str += `
256268 },
257269 setup(obj, constructorArgs, privateData) {
258- if (!privateData) privateData = {};
270+ if (!privateData) privateData = {};` ;
271+
272+ if ( this . factory ) {
273+ this . str += `
274+ for (var prop in defaultPrivateData) {
275+ if (!(prop in privateData)) {
276+ privateData[prop] = defaultPrivateData[prop];
277+ }
278+ }` ;
279+ }
280+
281+ this . str += `
259282 privateData.wrapper = obj;
260283
261284 this._internalSetup(obj);\n` ;
@@ -273,8 +296,7 @@ Interface.prototype.generateExport = function () {
273296 interface: ${ this . name } ,
274297 expose: {
275298 ${ exposers . join ( ",\n " ) }
276- }
277- };\n\n` ;
299+ }` ;
278300} ;
279301
280302Interface . prototype . generateOperations = function ( ) {
@@ -292,7 +314,6 @@ Interface.prototype.generateOperations = function () {
292314 done [ member . name ] = true ;
293315 break ;
294316 case "iterable" :
295- this . iterable = true ;
296317 member = new Iterable ( this , this . idl , memberIdl , { customTypes : this . opts . customTypes } ) ;
297318 break ;
298319 default :
@@ -375,6 +396,16 @@ ${this.name}.prototype[Symbol.unscopables] = ${JSON.stringify(unscopables, null,
375396} ;
376397
377398Interface . prototype . generate = function ( ) {
399+ this . generateIterator ( ) ;
400+
401+ if ( this . factory ) {
402+ // TODO: use default function parameters when jsdom requires Node >=6
403+ this . str += `
404+ module.exports = {
405+ createInterface: function (defaultPrivateData) {
406+ defaultPrivateData = defaultPrivateData === undefined ? {} : defaultPrivateData;\n\n` ;
407+ }
408+
378409 this . generateConstructor ( ) ;
379410 this . generateMixins ( ) ;
380411
@@ -386,7 +417,25 @@ Interface.prototype.generate = function () {
386417
387418 this . generateSymbols ( ) ;
388419
389- this . generateExport ( ) ;
420+ this . str += `
421+ const iface = {` ;
422+
423+ if ( this . factory ) {
424+ this . generateIface ( ) ;
425+ this . str += `
426+ };
427+ return iface;
428+ },` ;
429+ this . generateExport ( ) ;
430+ this . str += `
431+ };\n` ;
432+ } else {
433+ this . generateExport ( ) ;
434+ this . generateIface ( ) ;
435+ this . str += `
436+ };
437+ module.exports = iface;\n` ;
438+ }
390439} ;
391440
392441Interface . prototype . toString = function ( ) {
0 commit comments