@@ -22,7 +22,7 @@ class Interface {
22
22
this . ctx = ctx ;
23
23
this . idl = idl ;
24
24
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" ) ) ;
26
26
for ( const member of this . idl . members ) {
27
27
member . definingInterface = this . name ;
28
28
}
@@ -347,15 +347,19 @@ class Interface {
347
347
` ;
348
348
}
349
349
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
+
350
359
if ( this . idl . inheritance ) {
351
360
this . str += `
352
- Object.setPrototypeOf(${ this . name } .prototype, ${ this . idl . inheritance } .interface.prototype);
353
361
Object.setPrototypeOf(${ this . name } , ${ this . idl . inheritance } .interface);
354
362
` ;
355
- } else if ( utils . getExtAttr ( this . idl . extAttrs , "LegacyArrayClass" ) ) {
356
- this . str += `
357
- Object.setPrototypeOf(${ this . name } .prototype, Array.prototype);
358
- ` ;
359
363
}
360
364
361
365
this . str += `
@@ -544,6 +548,180 @@ class Interface {
544
548
return conditions . join ( " && " ) ;
545
549
}
546
550
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
+
547
725
generateLegacyProxy ( ) {
548
726
const hasIndexedSetter = this . indexedSetter !== null ;
549
727
const hasNamedSetter = this . namedSetter !== null ;
0 commit comments