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