MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1let pass = true;
2const { EventEmitter } = require('events');
3
4if ('a' + [].at !== 'afunction at() { [native code] }') {
5 console.log('FAIL: built-in methods should stringify with their exposed property name');
6 pass = false;
7}
8
9if (fetch.name !== 'fetch') {
10 console.log('FAIL: global native functions should expose their property name');
11 pass = false;
12}
13
14if (Number.parseInt !== globalThis.parseInt || Number.parseFloat !== globalThis.parseFloat) {
15 console.log('FAIL: Number parse aliases should reuse the global native functions');
16 pass = false;
17}
18
19if (Function.prototype.toString.call(fetch) !== 'function fetch() { [native code] }') {
20 console.log('FAIL: Function.prototype.toString should use the exposed global name for native functions');
21 pass = false;
22}
23
24const nameDesc = Object.getOwnPropertyDescriptor(Function.prototype.toString, 'name');
25if (!nameDesc || nameDesc.value !== 'toString') {
26 console.log('FAIL: Function.prototype.toString should expose a name descriptor');
27 pass = false;
28}
29
30if (!nameDesc || nameDesc.writable !== false || nameDesc.enumerable !== false || nameDesc.configurable !== true) {
31 console.log('FAIL: Function.prototype.toString.name descriptor flags should match builtin functions');
32 pass = false;
33}
34
35const lengthDesc = Object.getOwnPropertyDescriptor(Function.prototype.toString, 'length');
36if (!lengthDesc) {
37 console.log('FAIL: Function.prototype.toString should expose a length descriptor');
38 pass = false;
39}
40
41if (!lengthDesc || lengthDesc.writable !== false || lengthDesc.enumerable !== false || lengthDesc.configurable !== true) {
42 console.log('FAIL: Function.prototype.toString.length descriptor flags should match builtin functions');
43 pass = false;
44}
45
46const names = Object.getOwnPropertyNames(Function.prototype.toString);
47if (!names.includes('name') || !names.includes('length')) {
48 console.log('FAIL: Object.getOwnPropertyNames should include builtin function metadata');
49 pass = false;
50}
51
52if (String.prototype.toLowerCase.name !== 'toLowerCase') {
53 console.log('FAIL: shared native entrypoints should preserve the primary exposed name');
54 pass = false;
55}
56
57if (String.prototype.toLocaleLowerCase.name !== 'toLocaleLowerCase') {
58 console.log('FAIL: shared native entrypoints should preserve alternate exposed names');
59 pass = false;
60}
61
62if (URLSearchParams.prototype[Symbol.iterator] !== URLSearchParams.prototype.entries) {
63 console.log('FAIL: URLSearchParams @@iterator should alias entries');
64 pass = false;
65}
66
67if (URLSearchParams.prototype[Symbol.iterator].name !== 'entries') {
68 console.log('FAIL: URLSearchParams @@iterator should keep the entries name');
69 pass = false;
70}
71
72if (Headers.prototype[Symbol.iterator] !== Headers.prototype.entries) {
73 console.log('FAIL: Headers @@iterator should alias entries');
74 pass = false;
75}
76
77if (Headers.prototype[Symbol.iterator].name !== 'entries') {
78 console.log('FAIL: Headers @@iterator should keep the entries name');
79 pass = false;
80}
81
82if (Map.prototype[Symbol.iterator] !== Map.prototype.entries) {
83 console.log('FAIL: Map @@iterator should alias entries');
84 pass = false;
85}
86
87if (Map.prototype[Symbol.iterator].name !== 'entries') {
88 console.log('FAIL: Map @@iterator should keep the entries name');
89 pass = false;
90}
91
92if (Set.prototype.keys !== Set.prototype.values || Set.prototype[Symbol.iterator] !== Set.prototype.values) {
93 console.log('FAIL: Set iterator aliases should reuse values');
94 pass = false;
95}
96
97if (Set.prototype[Symbol.iterator].name !== 'values') {
98 console.log('FAIL: Set @@iterator should keep the values name');
99 pass = false;
100}
101
102if (FormData.prototype[Symbol.iterator] !== FormData.prototype.entries) {
103 console.log('FAIL: FormData @@iterator should alias entries');
104 pass = false;
105}
106
107if (EventEmitter.prototype.on !== EventEmitter.prototype.addListener) {
108 console.log('FAIL: EventEmitter.addListener should alias on');
109 pass = false;
110}
111
112if (EventEmitter.prototype.off !== EventEmitter.prototype.removeListener) {
113 console.log('FAIL: EventEmitter.removeListener should alias off');
114 pass = false;
115}
116
117if (process.on !== process.addListener || process.off !== process.removeListener) {
118 console.log('FAIL: process event aliases should reuse the canonical methods');
119 pass = false;
120}
121
122if (
123 process.stdin.off !== process.stdin.removeListener ||
124 process.stdout.off !== process.stdout.removeListener ||
125 process.stderr.off !== process.stderr.removeListener
126) {
127 console.log('FAIL: stdio removeListener aliases should reuse the canonical methods');
128 pass = false;
129}
130
131if (Uint8Array.prototype[Symbol.iterator] !== Uint8Array.prototype.values) {
132 console.log('FAIL: TypedArray @@iterator should alias values');
133 pass = false;
134}
135
136if (Uint8Array.prototype[Symbol.iterator].name !== 'values') {
137 console.log('FAIL: TypedArray @@iterator should keep the values name');
138 pass = false;
139}
140
141const wrapped = (() => {}).bind(null);
142Object.defineProperty(wrapped, 'name', nameDesc);
143
144if (wrapped.name !== 'toString') {
145 console.log('FAIL: builtin function name descriptors should round-trip through defineProperty');
146 pass = false;
147}
148
149const aliasedFetch = fetch;
150const aliasTarget = {};
151aliasTarget.a = aliasedFetch;
152aliasTarget.b = aliasedFetch;
153
154if (
155 aliasTarget.a !== aliasedFetch ||
156 aliasTarget.b !== aliasedFetch ||
157 aliasTarget.a !== aliasTarget.b
158) {
159 console.log('FAIL: ordinary assignment should preserve native function identity');
160 pass = false;
161}
162
163if (aliasTarget.a.name !== 'fetch' || aliasTarget.b.name !== 'fetch') {
164 console.log('FAIL: ordinary assignment should not rename native functions');
165 pass = false;
166}
167
168const nativeReproSym = Symbol('native-method-descriptors');
169const originalFetchProto = Object.getPrototypeOf(fetch);
170const customFetchProto = { fromCustomProto: 42 };
171
172fetch.extra = 'value-from-set';
173Object.defineProperty(fetch, 'defined', {
174 value: 'value-from-defineProperty',
175 enumerable: true,
176 configurable: true,
177 writable: true,
178});
179Object.defineProperty(fetch, nativeReproSym, {
180 value: 'symbol-value',
181 enumerable: true,
182 configurable: true,
183 writable: true,
184});
185Object.setPrototypeOf(fetch, customFetchProto);
186
187if (fetch.extra !== 'value-from-set' || fetch.defined !== 'value-from-defineProperty') {
188 console.log('FAIL: promoted native functions should preserve own string properties on later reads');
189 pass = false;
190}
191
192if (fetch[nativeReproSym] !== 'symbol-value') {
193 console.log('FAIL: promoted native functions should preserve own symbol properties on later reads');
194 pass = false;
195}
196
197if (Object.getPrototypeOf(fetch) !== customFetchProto || fetch.fromCustomProto !== 42) {
198 console.log('FAIL: promoted native functions should preserve prototype updates');
199 pass = false;
200}
201
202const fetchOwnNames = Object.getOwnPropertyNames(fetch);
203const fetchOwnSymbols = Object.getOwnPropertySymbols(fetch);
204
205if (!fetchOwnNames.includes('prototype')) {
206 console.log('FAIL: native functions with prototype metadata should expose prototype in own property names');
207 pass = false;
208}
209
210if (!fetchOwnNames.includes('extra') || !fetchOwnNames.includes('defined')) {
211 console.log('FAIL: native function own property names should include promoted writes');
212 pass = false;
213}
214
215if (!fetchOwnSymbols.includes(nativeReproSym)) {
216 console.log('FAIL: native function own property symbols should include promoted writes');
217 pass = false;
218}
219
220const extraDesc = Object.getOwnPropertyDescriptor(fetch, 'extra');
221const definedDesc = Object.getOwnPropertyDescriptor(fetch, 'defined');
222const symDesc = Object.getOwnPropertyDescriptor(fetch, nativeReproSym);
223const prototypeDesc = Object.getOwnPropertyDescriptor(fetch, 'prototype');
224
225if (!extraDesc || extraDesc.value !== 'value-from-set' || !extraDesc.enumerable || !extraDesc.configurable || !extraDesc.writable) {
226 console.log('FAIL: promoted native string properties should keep their descriptors');
227 pass = false;
228}
229
230if (!definedDesc || definedDesc.value !== 'value-from-defineProperty' || !definedDesc.enumerable || !definedDesc.configurable || !definedDesc.writable) {
231 console.log('FAIL: defineProperty on native functions should be reflected later');
232 pass = false;
233}
234
235if (!symDesc || symDesc.value !== 'symbol-value' || !symDesc.enumerable || !symDesc.configurable || !symDesc.writable) {
236 console.log('FAIL: promoted native symbol properties should keep their descriptors');
237 pass = false;
238}
239
240if (!prototypeDesc || prototypeDesc.enumerable || prototypeDesc.configurable || !prototypeDesc.writable) {
241 console.log('FAIL: native function prototype descriptors should match built-in function defaults');
242 pass = false;
243}
244
245delete fetch.extra;
246delete fetch.defined;
247delete fetch[nativeReproSym];
248Object.setPrototypeOf(fetch, originalFetchProto);
249
250if (pass) console.log('PASS');