@@ -385,6 +385,10 @@ class Interface {
385
385
return ! this . isGlobal && ( this . supportsIndexedProperties || this . supportsNamedProperties ) ;
386
386
}
387
387
388
+ get needsNamedPropertiesObject ( ) {
389
+ return this . isGlobal && this . supportsNamedProperties ;
390
+ }
391
+
388
392
includes ( source ) {
389
393
const mixin = this . ctx . interfaceMixins . get ( source ) ;
390
394
if ( ! mixin ) {
@@ -1124,6 +1128,170 @@ class Interface {
1124
1128
` ;
1125
1129
}
1126
1130
1131
+ // https://heycam.github.io/webidl/#named-properties-object
1132
+ generateNamedPropertiesObject ( ) {
1133
+ const { idl, name, namedGetter } = this ;
1134
+ const overrideBuiltins = Boolean ( utils . getExtAttr ( idl . extAttrs , "OverrideBuiltins" ) ) ;
1135
+
1136
+ function supportsPropertyName ( O , P , namedValue ) {
1137
+ let unsupportedValue = utils . getExtAttr ( namedGetter . extAttrs , "WebIDL2JSValueAsUnsupported" ) ;
1138
+ if ( unsupportedValue ) {
1139
+ unsupportedValue = unsupportedValue . rhs . value ;
1140
+ }
1141
+ if ( unsupportedValue ) {
1142
+ const func = namedGetter . name ? `.${ namedGetter . name } ` : "[utils.namedGet]" ;
1143
+ const value = namedValue || `${ O } [impl]${ func } (${ P } )` ;
1144
+ return `${ value } !== ${ unsupportedValue } ` ;
1145
+ }
1146
+ return `${ O } [impl][utils.supportsPropertyName](${ P } )` ;
1147
+ }
1148
+
1149
+ // "named property visibility algorithm"
1150
+ // If `supports` is true then skip the supportsPropertyName check.
1151
+ function namedPropertyVisible ( P , O , supports = false ) {
1152
+ const conditions = [ ] ;
1153
+ if ( ! supports ) {
1154
+ conditions . push ( supportsPropertyName ( O , P ) ) ;
1155
+ }
1156
+ if ( overrideBuiltins ) {
1157
+ conditions . push ( `!utils.hasOwn(${ O } , ${ P } )` ) ;
1158
+ } else {
1159
+ // TODO: create a named properties object.
1160
+ conditions . push ( `!(${ P } in ${ O } )` ) ;
1161
+ }
1162
+ return conditions . join ( " && " ) ;
1163
+ }
1164
+
1165
+ this . str += `
1166
+ const NamedPropertiesObject = new Proxy(
1167
+ Object.create(
1168
+ globalObject.${ idl . inheritance ? idl . inheritance : "Object" } .prototype,
1169
+ { [Symbol.toStringTag]: { value: "${ name } Properties", configurable: true } }
1170
+ ),
1171
+ {
1172
+ ` ;
1173
+
1174
+ // [[Get]] (necessary because of proxy semantics)
1175
+ this . str += `
1176
+ get(target, P, receiver) {
1177
+ if (typeof P === "symbol") {
1178
+ return Reflect.get(target, P, receiver);
1179
+ }
1180
+ const desc = this.getOwnPropertyDescriptor(target, P);
1181
+ if (desc === undefined) {
1182
+ const parent = Object.getPrototypeOf(target);
1183
+ if (parent === null) {
1184
+ return undefined;
1185
+ }
1186
+ return Reflect.get(parent, P, receiver);
1187
+ }
1188
+ if (!desc.get && !desc.set) {
1189
+ return desc.value;
1190
+ }
1191
+ const getter = desc.get;
1192
+ if (getter === undefined) {
1193
+ return undefined;
1194
+ }
1195
+ return Reflect.apply(getter, receiver, []);
1196
+ },
1197
+ ` ;
1198
+
1199
+ // [[HasProperty]] (necessary because of proxy semantics)
1200
+ this . str += `
1201
+ has(target, P) {
1202
+ if (typeof P === "symbol") {
1203
+ return Reflect.has(target, P);
1204
+ }
1205
+ const desc = this.getOwnPropertyDescriptor(target, P);
1206
+ if (desc !== undefined) {
1207
+ return true;
1208
+ }
1209
+ const parent = Object.getPrototypeOf(target);
1210
+ if (parent !== null) {
1211
+ return Reflect.has(parent, P);
1212
+ }
1213
+ return false;
1214
+ },
1215
+ ` ;
1216
+
1217
+ // [[GetOwnProperty]]
1218
+ this . str += `
1219
+ getOwnPropertyDescriptor(target, P) {
1220
+ const object = globalObject;
1221
+ if (typeof P === "symbol") {
1222
+ return Reflect.getOwnPropertyDescriptor(target, P);
1223
+ }
1224
+ ` ;
1225
+
1226
+ const func = namedGetter . name ? `.${ namedGetter . name } ` : "[utils.namedGet]" ;
1227
+ const enumerable = ! utils . getExtAttr ( idl . extAttrs , "LegacyUnenumerableNamedProperties" ) ;
1228
+ let preamble = "" ;
1229
+ const conditions = [ ] ;
1230
+ if ( utils . getExtAttr ( namedGetter . extAttrs , "WebIDL2JSValueAsUnsupported" ) ) {
1231
+ this . str += `
1232
+ const namedValue = object[impl]${ func } (P);
1233
+ ` ;
1234
+ conditions . push ( supportsPropertyName ( "object" , "index" , "namedValue" ) ) ;
1235
+ conditions . push ( namedPropertyVisible ( "P" , "object" , true ) ) ;
1236
+ } else {
1237
+ preamble = `
1238
+ const namedValue = object[impl]${ func } (P);
1239
+ ` ;
1240
+ conditions . push ( namedPropertyVisible ( "P" , "object" ) ) ;
1241
+ }
1242
+ this . str += `
1243
+ if (${ conditions . join ( " && " ) } ) {
1244
+ ${ preamble }
1245
+ return {
1246
+ writable: true,
1247
+ enumerable: ${ enumerable } ,
1248
+ configurable: true,
1249
+ value: utils.tryWrapperForImpl(namedValue)
1250
+ };
1251
+ }
1252
+ return Reflect.getOwnPropertyDescriptor(target, P);
1253
+ },
1254
+ ` ;
1255
+
1256
+ // [[DefineOwnProperty]]
1257
+ this . str += `
1258
+ defineProperty() {
1259
+ return false;
1260
+ },
1261
+ ` ;
1262
+
1263
+ // [[Delete]]
1264
+ this . str += `
1265
+ deleteProperty() {
1266
+ return false;
1267
+ },
1268
+ ` ;
1269
+
1270
+ // [[SetPrototypeOf]]
1271
+ this . str += `
1272
+ setPrototypeOf(O, V) {
1273
+ // 1. Return ? SetImmutablePrototype(O, V).
1274
+ return Reflect.getPrototypeOf(O) === V;
1275
+ },
1276
+ ` ;
1277
+
1278
+ // [[PreventExtensions]]
1279
+ this . str += `
1280
+ preventExtensions() {
1281
+ return false;
1282
+ }
1283
+ ` ;
1284
+
1285
+ this . str += `
1286
+ }
1287
+ );
1288
+ ` ;
1289
+
1290
+ this . str += `
1291
+ Object.setPrototypeOf(${ name } .prototype, NamedPropertiesObject);
1292
+ ` ;
1293
+ }
1294
+
1127
1295
generateIface ( ) {
1128
1296
this . str += `
1129
1297
exports.create = function create(globalObject, constructorArgs, privateData) {
@@ -1470,6 +1638,10 @@ class Interface {
1470
1638
1471
1639
this . generateOffInstanceAfterClass ( ) ;
1472
1640
1641
+ if ( this . needsNamedPropertiesObject ) {
1642
+ this . generateNamedPropertiesObject ( ) ;
1643
+ }
1644
+
1473
1645
this . str += `
1474
1646
if (globalObject[ctorRegistry] === undefined) {
1475
1647
globalObject[ctorRegistry] = Object.create(null);
0 commit comments