@@ -22,7 +22,7 @@ class Interface {
2222 this . ctx = ctx ;
2323 this . idl = idl ;
2424 this . name = idl . name ;
25- this . factory = Boolean ( utils . getExtAttr ( this . idl . extAttrs , "WebIDL2JSFactory" ) ) ;
25+ this . factory = utils . isGlobal ( this . idl ) || Boolean ( utils . getExtAttr ( this . idl . extAttrs , "WebIDL2JSFactory" ) ) ;
2626 for ( const member of this . idl . members ) {
2727 member . definingInterface = this . name ;
2828 }
@@ -347,15 +347,19 @@ class Interface {
347347 ` ;
348348 }
349349
350+ if ( utils . isGlobal ( this . idl ) && this . supportsNamedProperties ) {
351+ this . generateNamedPropertiesObject ( ) ;
352+ this . str += `Object.setPrototypeOf(${ this . name } .prototype, namedPropertiesObject);` ;
353+ } else if ( this . idl . inheritance ) {
354+ this . str += `Object.setPrototypeOf(${ this . name } .prototype, ${ this . idl . inheritance } .interface.prototype);` ;
355+ } else if ( utils . getExtAttr ( this . idl . extAttrs , "LegacyArrayClass" ) ) {
356+ this . str += `Object.setPrototypeOf(${ this . name } .prototype, Array.prototype);` ;
357+ }
358+
350359 if ( this . idl . inheritance ) {
351360 this . str += `
352- Object.setPrototypeOf(${ this . name } .prototype, ${ this . idl . inheritance } .interface.prototype);
353361 Object.setPrototypeOf(${ this . name } , ${ this . idl . inheritance } .interface);
354362 ` ;
355- } else if ( utils . getExtAttr ( this . idl . extAttrs , "LegacyArrayClass" ) ) {
356- this . str += `
357- Object.setPrototypeOf(${ this . name } .prototype, Array.prototype);
358- ` ;
359363 }
360364
361365 this . str += `
@@ -544,6 +548,180 @@ class Interface {
544548 return conditions . join ( " && " ) ;
545549 }
546550
551+ generateNamedPropertiesObject ( ) {
552+ const proto = ( ( ) => {
553+ if ( this . idl . inheritance ) {
554+ return `${ this . idl . inheritance } .interface.prototype` ;
555+ } else if ( utils . getExtAttr ( this . idl . extAttrs , "LegacyArrayClass" ) ) {
556+ return "Array.prototype" ;
557+ }
558+ return "Object.prototype" ;
559+ } ) ( ) ;
560+
561+ this . str += `
562+ const namedPropertiesObject = new Proxy(Object.create(${ proto } , {
563+ [Symbol.toStringTag]: {
564+ value: "${ this . name } Properties",
565+ writable: false,
566+ enumerable: false,
567+ configurable: true
568+ }
569+ }), {
570+ ` ;
571+
572+ // [[SetPrototypeOf]]
573+ this . str += `
574+ setPrototypeOf() {
575+ throw new TypeError("Immutable prototype object '#<${ this . name } Properties>' cannot have their prototype set");
576+ },
577+ ` ;
578+
579+ // [[PreventExtensions]]
580+ this . str += `
581+ preventExtensions() {
582+ return false;
583+ },
584+ ` ;
585+
586+ // [[GetOwnProperty]]
587+ this . str += `
588+ getOwnPropertyDescriptor(target, P) {
589+ if (typeof P === "symbol") {
590+ return Reflect.getOwnPropertyDescriptor(target, P);
591+ }
592+ const object = defaultPrivateData.globalObject;
593+ ` ;
594+
595+ const func = this . namedGetter . name !== null ? `.${ this . namedGetter . name } ` : "[utils.namedGet]" ;
596+ const enumerable = ! utils . getExtAttr ( this . idl . extAttrs , "LegacyUnenumerableNamedProperties" ) ;
597+ let preamble = "" ;
598+ const conditions = [ ] ;
599+ if ( utils . getExtAttr ( this . namedGetter . extAttrs , "WebIDL2JSValueAsUnsupported" ) ) {
600+ this . str += `
601+ const namedValue = object[impl]${ func } (P);
602+ ` ;
603+ conditions . push ( this . _supportsPropertyName ( "object" , "index" , "namedValue" ) ) ;
604+ conditions . push ( this . _namedPropertyVisible ( "P" , "object" , true ) ) ;
605+ } else {
606+ preamble = `
607+ const namedValue = object[impl]${ func } (P);
608+ ` ;
609+ conditions . push ( this . _namedPropertyVisible ( "P" , "object" , false ) ) ;
610+ }
611+
612+ this . str += `
613+ if (${ conditions . join ( " && " ) } ) {
614+ ${ preamble }
615+ return {
616+ writable: true,
617+ enumerable: ${ enumerable } ,
618+ configurable: true,
619+ value: utils.tryWrapperForImpl(namedValue)
620+ };
621+ }
622+ return Reflect.getOwnPropertyDescriptor(target, P);
623+ },
624+ ` ;
625+
626+ // [[DefineOwnProperty]]
627+ this . str += `
628+ defineProperty() {
629+ return false;
630+ },
631+ ` ;
632+
633+ // [[HasProperty]]
634+ this . str += `
635+ has(target, P) {
636+ if (typeof P === "symbol") {
637+ return Reflect.has(target, P);
638+ }
639+ const desc = this.getOwnPropertyDescriptor(target, P);
640+ if (desc !== undefined) {
641+ return true;
642+ }
643+ const parent = Object.getPrototypeOf(target);
644+ if (parent !== null) {
645+ return Reflect.has(parent, P);
646+ }
647+ return false;
648+ },
649+ ` ;
650+
651+ // [[Get]]
652+ this . str += `
653+ get(target, P, receiver) {
654+ if (typeof P === "symbol") {
655+ return Reflect.get(target, P, receiver);
656+ }
657+ const desc = this.getOwnPropertyDescriptor(target, P);
658+ if (desc === undefined) {
659+ const parent = Object.getPrototypeOf(target);
660+ if (parent === null) {
661+ return undefined;
662+ }
663+ return Reflect.get(target, P, receiver);
664+ }
665+ if (!desc.get && !desc.set) {
666+ return desc.value;
667+ }
668+ const getter = desc.get;
669+ if (getter === undefined) {
670+ return undefined;
671+ }
672+ return Reflect.apply(getter, receiver, []);
673+ },
674+ ` ;
675+
676+ // [[Set]]
677+ this . str += `
678+ set(target, P, V, receiver) {
679+ if (typeof P === "symbol") {
680+ return Reflect.set(target, P, V, receiver);
681+ }
682+ const ownDesc = this.getOwnPropertyDescriptor(P);
683+ if (ownDesc === undefined) {
684+ const parent = Reflect.getPrototypeOf(target);
685+ // parent is never null.
686+ return Reflect.set(parent, P, V, receiver);
687+ }
688+ // ownDesc.writable is always true.
689+ if (!utils.isObject(receiver)) {
690+ return false;
691+ }
692+ // If receiver is this Proxy object, the following will always return false. Problem is, receiver may not be
693+ // this Proxy object.
694+ const existingDesc = Reflect.getOwnPropertyDescriptor(receiver, P);
695+ let valueDesc;
696+ if (existingDesc !== undefined) {
697+ if (existingDesc.get || existingDesc.set) {
698+ return false;
699+ }
700+ if (!existingDesc.writable) {
701+ return false;
702+ }
703+ valueDesc = { value: V };
704+ } else {
705+ valueDesc = { writable: true, enumerable: true, configurable: true, value: V };
706+ }
707+ return Reflect.defineProperty(receiver, P, valueDesc);
708+ },
709+ ` ;
710+
711+ // [[Delete]]
712+ this . str += `
713+ deleteProperty() {
714+ return false;
715+ },
716+ ` ;
717+
718+ // [[OwnPropertyKeys]] not overriden
719+
720+ this . str += `
721+ });
722+ ` ;
723+ }
724+
547725 generateLegacyProxy ( ) {
548726 const hasIndexedSetter = this . indexedSetter !== null ;
549727 const hasNamedSetter = this . namedSetter !== null ;
0 commit comments