mirror of
https://github.com/bendtherules/completion-viz.git
synced 2026-08-18 21:52:36 +00:00
Clone engine262 in /engine262
This commit is contained in:
@@ -0,0 +1,330 @@
|
||||
'use strict';
|
||||
|
||||
const engine262 = require('..');
|
||||
|
||||
const contexts = [];
|
||||
|
||||
class InspectorContext {
|
||||
constructor(realm) {
|
||||
this.realm = realm;
|
||||
this.idToObject = new Map();
|
||||
this.objectToId = new Map();
|
||||
this.objectCounter = 0;
|
||||
this.previewStack = [];
|
||||
}
|
||||
|
||||
internObject(object, group = 'default') {
|
||||
if (this.objectToId.has(object)) {
|
||||
return this.objectToId.get(object);
|
||||
}
|
||||
const id = `${group}:${this.objectCounter}`;
|
||||
this.objectCounter += 1;
|
||||
this.idToObject.set(id, object);
|
||||
this.objectToId.set(object, id);
|
||||
return id;
|
||||
}
|
||||
|
||||
releaseObjectGroup(group) {
|
||||
for (const [id, object] of this.idToObject.entries()) {
|
||||
if (id.startsWith(group)) {
|
||||
this.idToObject.delete(id);
|
||||
this.objectToId.delete(object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getObject(objectId) {
|
||||
return this.idToObject.get(objectId);
|
||||
}
|
||||
|
||||
toRemoteObject(object, options) {
|
||||
const result = {};
|
||||
switch (engine262.Type(object)) {
|
||||
case 'Object':
|
||||
result.objectId = this.internObject(object, options.objectGroup);
|
||||
if ('Call' in object) {
|
||||
result.type = 'function';
|
||||
} else {
|
||||
result.type = 'object';
|
||||
if ('PromiseState' in object) {
|
||||
result.subtype = 'promise';
|
||||
} else if ('MapData' in object) {
|
||||
result.subtype = 'map';
|
||||
} else if ('SetData' in object) {
|
||||
result.subtype = 'set';
|
||||
} else if ('ErrorData' in object) {
|
||||
result.subtype = 'error';
|
||||
} else if ('TypedArrayName' in object) {
|
||||
result.subtype = 'typedarray';
|
||||
} else if ('DataView' in object) {
|
||||
result.subtype = 'dataview';
|
||||
} else if ('ProxyTarget' in object) {
|
||||
result.subtype = 'proxy';
|
||||
} else if ('DateValue' in object) {
|
||||
result.subtype = 'date';
|
||||
} else if ('GeneratorState' in object) {
|
||||
result.subtype = 'generator';
|
||||
} else if (engine262.IsArray(object) === engine262.Value.true) {
|
||||
result.subtype = 'array';
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'Null':
|
||||
result.type = 'object';
|
||||
result.subtype = 'null';
|
||||
result.value = null;
|
||||
break;
|
||||
case 'Undefined':
|
||||
result.type = 'undefined';
|
||||
break;
|
||||
case 'String':
|
||||
result.type = 'string';
|
||||
result.value = object.stringValue();
|
||||
break;
|
||||
case 'Number': {
|
||||
result.type = 'number';
|
||||
const v = object.numberValue();
|
||||
if (!Number.isFinite(v)) {
|
||||
result.unserializableValue = v.toString();
|
||||
} else {
|
||||
result.value = v;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'Boolean':
|
||||
result.type = 'boolean';
|
||||
result.value = object.booleanValue();
|
||||
break;
|
||||
case 'BigInt':
|
||||
result.type = 'bigint';
|
||||
result.unserializableValue = `${object.bigintValue().toString()}n`;
|
||||
break;
|
||||
case 'Symbol':
|
||||
result.type = 'symbol';
|
||||
result.description = object.Description === engine262.Value.undefined
|
||||
? undefined
|
||||
: object.Description.stringValue();
|
||||
break;
|
||||
default:
|
||||
throw new RangeError();
|
||||
}
|
||||
if (options.generatePreview
|
||||
&& result.type === 'object'
|
||||
&& result.subtype !== 'null'
|
||||
&& !this.previewStack.includes(object)) {
|
||||
this.previewStack.push(object);
|
||||
const properties = this.getPropertyPreview(object, options);
|
||||
let entries;
|
||||
if ('MapData' in object) {
|
||||
entries = object.MapData.map((d) => ({
|
||||
key: this.toRemoteObject(d.Key, options).preview,
|
||||
value: this.toRemoteObject(d.Value, options).preview,
|
||||
}));
|
||||
}
|
||||
this.previewStack.pop();
|
||||
result.preview = {
|
||||
type: result.type,
|
||||
subtype: result.subtype,
|
||||
overflow: properties.length > 5,
|
||||
properties: properties.slice(0, 5),
|
||||
entries,
|
||||
};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
getProperties(object, options) {
|
||||
const wrap = (v) => this.toRemoteObject(v, options);
|
||||
|
||||
const properties = [];
|
||||
const internalProperties = [];
|
||||
|
||||
let p = object;
|
||||
while (p !== engine262.Value.null) {
|
||||
const keys = p.OwnPropertyKeys();
|
||||
if (keys instanceof engine262.AbruptCompletion) {
|
||||
return keys;
|
||||
}
|
||||
|
||||
for (const key of keys) {
|
||||
const desc = p.GetOwnProperty(key);
|
||||
if (desc instanceof engine262.AbruptCompletion) {
|
||||
return desc;
|
||||
}
|
||||
if (options.accessorPropertiesOnly && desc.Value) {
|
||||
continue;
|
||||
}
|
||||
const descriptor = {
|
||||
name: key.stringValue
|
||||
? key.stringValue()
|
||||
: undefined,
|
||||
value: desc.Value ? wrap(desc.Value) : undefined,
|
||||
writable: desc.Writable === engine262.Value.true,
|
||||
get: desc.Get ? wrap(desc.Get) : undefined,
|
||||
set: desc.Set ? wrap(desc.Set) : undefined,
|
||||
configurable: desc.Configurable === engine262.Value.true,
|
||||
enumerable: desc.Enumerable === engine262.Value.true,
|
||||
wasThrown: false,
|
||||
isOwn: p === object,
|
||||
symbol: key.stringValue ? undefined : wrap(key),
|
||||
};
|
||||
properties.push(descriptor);
|
||||
}
|
||||
|
||||
if (options.ownProperties) {
|
||||
break;
|
||||
}
|
||||
p = p.GetPrototypeOf();
|
||||
if (p instanceof engine262.AbruptCompletion) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
if ('PromiseState' in object) {
|
||||
internalProperties.push({
|
||||
name: '[[PromiseState]]',
|
||||
value: {
|
||||
type: 'string',
|
||||
value: object.PromiseState,
|
||||
},
|
||||
});
|
||||
internalProperties.push({
|
||||
name: '[[PromiseResult]]',
|
||||
value: wrap(object.PromiseResult),
|
||||
});
|
||||
}
|
||||
|
||||
return { properties, internalProperties };
|
||||
}
|
||||
|
||||
getPropertyPreview(object, options) {
|
||||
const wrap = (v) => this.toRemoteObject(v, options);
|
||||
|
||||
const keys = object.OwnPropertyKeys();
|
||||
if (keys instanceof engine262.AbruptCompletion) {
|
||||
return keys;
|
||||
}
|
||||
|
||||
const properties = [];
|
||||
for (const key of keys) {
|
||||
const desc = object.GetOwnProperty(key);
|
||||
if (desc instanceof engine262.AbruptCompletion) {
|
||||
return desc;
|
||||
}
|
||||
const descriptor = {
|
||||
name: key.stringValue
|
||||
? key.stringValue()
|
||||
: `Symbol(${key.Description.stringValue ? key.Description.stringValue() : ''})`,
|
||||
};
|
||||
if (desc.Value) {
|
||||
desc.valuePreview = wrap(desc.Value).preview;
|
||||
switch (engine262.Type(desc.Value)) {
|
||||
case 'Object':
|
||||
if ('Call' in desc.Value) {
|
||||
descriptor.type = 'function';
|
||||
} else {
|
||||
descriptor.type = 'object';
|
||||
if ('PromiseState' in desc.Value) {
|
||||
descriptor.subtype = 'promise';
|
||||
} else if ('MapData' in desc.Value) {
|
||||
descriptor.subtype = 'map';
|
||||
} else if ('SetData' in desc.Value) {
|
||||
descriptor.subtype = 'set';
|
||||
} else if ('ErrorData' in desc.Value) {
|
||||
descriptor.subtype = 'error';
|
||||
} else if ('TypedArrayName' in desc.Value) {
|
||||
descriptor.subtype = 'typedarray';
|
||||
} else if ('DataView' in desc.Value) {
|
||||
descriptor.subtype = 'dataview';
|
||||
} else if ('ProxyTarget' in desc.Value) {
|
||||
descriptor.subtype = 'proxy';
|
||||
} else if ('DateValue' in desc.Value) {
|
||||
descriptor.subtype = 'date';
|
||||
} else if ('GeneratorState' in desc.Value) {
|
||||
descriptor.subtype = 'generator';
|
||||
} else if (engine262.IsArray(desc.Value) === engine262.Value.true) {
|
||||
descriptor.subtype = 'array';
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'Null':
|
||||
descriptor.type = 'object';
|
||||
descriptor.subtype = 'null';
|
||||
descriptor.value = 'null';
|
||||
break;
|
||||
case 'Undefined':
|
||||
descriptor.type = 'undefined';
|
||||
descriptor.value = 'undefined';
|
||||
break;
|
||||
case 'String':
|
||||
descriptor.type = 'string';
|
||||
descriptor.value = desc.Value.stringValue();
|
||||
break;
|
||||
case 'Number': {
|
||||
descriptor.type = 'number';
|
||||
descriptor.value = desc.Value.numberValue().toString();
|
||||
break;
|
||||
}
|
||||
case 'Boolean':
|
||||
descriptor.type = 'boolean';
|
||||
descriptor.value = desc.Value.booleanValue().toString();
|
||||
break;
|
||||
case 'BigInt':
|
||||
descriptor.type = 'bigint';
|
||||
descriptor.value = `${desc.Value.bigintValue().toString()}n`;
|
||||
break;
|
||||
case 'Symbol': {
|
||||
descriptor.type = 'symbol';
|
||||
const description = desc.Value.Description === engine262.Value.undefined
|
||||
? ''
|
||||
: desc.Value.Description.stringValue();
|
||||
descriptor.value = `Symbol(${description})`;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new RangeError();
|
||||
}
|
||||
} else {
|
||||
desc.type = 'accessor';
|
||||
}
|
||||
properties.push(descriptor);
|
||||
}
|
||||
|
||||
if ('PromiseState' in object) {
|
||||
properties.push({
|
||||
name: '[[PromiseState]]',
|
||||
type: 'string',
|
||||
value: object.PromiseState,
|
||||
});
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
createEvaluationResult(completion, options) {
|
||||
if (completion instanceof engine262.AbruptCompletion) {
|
||||
return {
|
||||
exceptionDetails: {
|
||||
text: 'uh oh',
|
||||
lineNumber: 0,
|
||||
columnNumber: 0,
|
||||
exception: this.toRemoteObject(completion.Value, options),
|
||||
},
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
result: this.toRemoteObject(completion.Value, options),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function attachRealm(realm) {
|
||||
contexts.push(new InspectorContext(realm));
|
||||
}
|
||||
|
||||
function getContext(id) {
|
||||
return contexts[id] || contexts[0];
|
||||
}
|
||||
|
||||
module.exports = { attachRealm, getContext };
|
||||
Reference in New Issue
Block a user