UNPKG

@yuebai008/cli

Version:

Command line interface for rapid qg-minigame development

1 lines 14.2 kB
import*as Root from"../../../core/root/root.js";import*as SDK from"../../../core/sdk/sdk.js";import*as Bindings from"../../../models/bindings/bindings.js";import*as JavaScriptMetaData from"../../../models/javascript_metadata/javascript_metadata.js";import*as SourceMapScopes from"../../../models/source_map_scopes/source_map_scopes.js";import*as CodeMirror from"../../../third_party/codemirror.next/codemirror.next.js";import*as UI from"../../legacy/legacy.js";import{closeTooltip,cursorTooltip}from"./cursor_tooltip.js";export function completion(){return CodeMirror.javascript.javascriptLanguage.data.of({autocomplete:javascriptCompletionSource})}export async function completeInContext(e,t,n=!1){const o=CodeMirror.EditorState.create({doc:e+t,selection:{anchor:e.length},extensions:CodeMirror.javascript.javascriptLanguage}),r=await javascriptCompletionSource(new CodeMirror.CompletionContext(o,o.doc.length,n));return r?r.options.filter((e=>e.label.startsWith(t))).map((e=>({text:e.label,priority:100+(e.boost||0),isSecondary:"secondary"===e.type}))):[]}class CompletionSet{completions;seen;constructor(e=[],t=new Set){this.completions=e,this.seen=t}add(e){this.seen.has(e.label)||(this.seen.add(e.label),this.completions.push(e))}copy(){return new CompletionSet(this.completions.slice(),new Set(this.seen))}}const javascriptKeywords=["async","await","break","case","catch","class","const","continue","debugger","default","delete","do","else","export","extends","false","finally","for","function","if","import","in","instanceof","let","new","null","of","return","static","super","switch","this","throw","true","try","typeof","var","void","while","with","yield"],consoleBuiltinFunctions=["clear","copy","debug","dir","dirxml","getEventListeners","inspect","keys","monitor","monitorEvents","profile","profileEnd","queryObjects","table","undebug","unmonitor","unmonitorEvents","values"],consoleBuiltinVariables=["$","$$","$x","$0","$_"],baseCompletions=new CompletionSet;for(const e of javascriptKeywords)baseCompletions.add({label:e,type:"keyword"});for(const t of consoleBuiltinFunctions)baseCompletions.add({label:t,type:"function"});for(const n of consoleBuiltinVariables)baseCompletions.add({label:n,type:"variable"});const dontCompleteIn=new Set(["TemplateString","LineComment","BlockComment","TypeDefinition","VariableDefinition","PropertyDefinition","TypeName"]);export function getQueryType(e,t,n){let o=e.resolveInner(t,-1);const r=o.parent;if(dontCompleteIn.has(o.name))return null;if("PropertyName"===o.name||"PrivatePropertyName"===o.name)return"MemberExpression"!==r?.name?null:{type:1,from:o.from,relatedNode:r};if("VariableName"===o.name||!o.firstChild&&o.to-o.from<20&&!/[^a-z]/.test(n.sliceString(o.from,o.to)))return{type:0,from:o.from};if("String"===o.name){const e=o.parent;return"MemberExpression"===e?.name&&"["===e.childBefore(o.from)?.name?{type:2,from:o.from,relatedNode:e}:null}if(o=o.enterUnfinishedNodesBefore(t),o.to===t&&"MemberExpression"===o.parent?.name&&(o=o.parent),"MemberExpression"===o.name){const e=o.childBefore(Math.min(t,o.to));if("["===e?.name)return{type:2,relatedNode:o};if("."===e?.name||"?."===e?.name)return{type:1,relatedNode:o}}if("("===o.name&&"ArgList"===r?.name&&"CallExpression"===r?.parent?.name){const e=r?.parent?.firstChild;if("MemberExpression"===e?.name){const t=e?.lastChild;if(t&&"get"===n.sliceString(t.from,t.to)){const t=e?.firstChild;return{type:3,relatedNode:t||void 0}}}}return{type:0}}export async function javascriptCompletionSource(e){const t=getQueryType(CodeMirror.syntaxTree(e.state),e.pos,e.state.doc);if(!t||void 0===t.from&&!e.explicit&&0===t.type)return null;const n=getExecutionContext()?.debuggerModel.selectedCallFrame()?.script;if(n&&Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().pluginManager?.hasPluginForScript(n))return null;let o,r;if(0===t.type){const[e,t]=await Promise.all([completeExpressionInScope(),completeExpressionGlobal()]);if(e.completions.length){o=e;for(const e of t.completions)o.add(e)}else o=t}else if(1===t.type||2===t.type){const n=t.relatedNode.getChild("Expression");if(2===t.type&&(r=void 0===t.from?"'":e.state.sliceDoc(t.from,t.from+1)),!n)return null;o=await completeProperties(e.state.sliceDoc(n.from,n.to),r,"]"===e.state.sliceDoc(e.pos,e.pos+1))}else{if(3!==t.type)return null;{const n=t.relatedNode;if(!n)return null;o=await maybeCompleteKeysFromMap(e.state.sliceDoc(n.from,n.to))}}return{from:t.from??e.pos,options:o.completions,validFor:r?"'"===r?SPAN_SINGLE_QUOTE:SPAN_DOUBLE_QUOTE:SPAN_IDENT}}const SPAN_IDENT=/^#?(?:[$_\p{ID_Start}])(?:[$_\u200C\u200D\p{ID_Continue}])*$/u,SPAN_SINGLE_QUOTE=/^\'(\\.|[^\\'\n])*'?$/,SPAN_DOUBLE_QUOTE=/^"(\\.|[^\\"\n])*"?$/;function getExecutionContext(){return UI.Context.Context.instance().flavor(SDK.RuntimeModel.ExecutionContext)}async function evaluateExpression(e,t,n){const o=await e.evaluate({expression:t,objectGroup:n,includeCommandLineAPI:!0,silent:!0,returnByValue:!1,generatePreview:!1,throwOnSideEffect:!0,timeout:500},!1,!1);return"error"in o||o.exceptionDetails||!o.object?null:o.object}const primitivePrototypes=new Map([["string","String"],["symbol","Symbol"],["number","Number"],["boolean","Boolean"],["bigint","BigInt"]]),maxCacheAge=3e4;let cacheInstance=null;class PropertyCache{#e=new Map;constructor(){const e=()=>this.#e.clear();SDK.TargetManager.TargetManager.instance().addModelListener(SDK.ConsoleModel.ConsoleModel,SDK.ConsoleModel.Events.CommandEvaluated,e),UI.Context.Context.instance().addFlavorChangeListener(SDK.RuntimeModel.ExecutionContext,e),SDK.TargetManager.TargetManager.instance().addModelListener(SDK.DebuggerModel.DebuggerModel,SDK.DebuggerModel.Events.DebuggerResumed,e),SDK.TargetManager.TargetManager.instance().addModelListener(SDK.DebuggerModel.DebuggerModel,SDK.DebuggerModel.Events.DebuggerPaused,e)}get(e){return this.#e.get(e)}set(e,t){this.#e.set(e,t),window.setTimeout((()=>{this.#e.get(e)===t&&this.#e.delete(e)}),3e4)}static instance(){return cacheInstance||(cacheInstance=new PropertyCache),cacheInstance}}async function maybeCompleteKeysFromMap(e){const t=new CompletionSet,n=getExecutionContext();if(!n)return t;const o=await evaluateExpression(n,`[...Map.prototype.keys.call(${e})]`,"completion");if(!o)return t;const r=SDK.RemoteObject.RemoteArray.objectAsArray(o),i=r.length();for(let e=0;e<i;e++)t.add({label:`"${(await r.at(e)).value}")`,type:"constant",boost:-1*e});return t}async function completeProperties(e,t,n=!1){const o=PropertyCache.instance();if(!t){const t=o.get(e);if(t)return t}const r=getExecutionContext();if(!r)return new CompletionSet;const i=completePropertiesInner(e,r,t,n);return t||o.set(e,i),i}async function completePropertiesInner(e,t,n,o=!1){const r=new CompletionSet;if(!t)return r;let i=await evaluateExpression(t,e,"completion");if(!i)return r;for(;"object"===i.type&&"proxy"===i.subtype;){const e=await i.getOwnProperties(!1),t=e.internalProperties?.find((e=>"[[Target]]"===e.name))?.value;if(!t)break;i=t}const s=primitivePrototypes.get(i.type);s&&(i=await evaluateExpression(t,s+".prototype","completion"));const a="globalThis"===e?"function":"method",c="globalThis"===e?"variable":"property";if(i&&("object"===i.type||"function"===i.type)){const t=await i.getAllProperties(!1,!1,!0),s="function"===i.type;for(const i of t.properties||[])if(!i.symbol&&(!s||"arguments"!==i.name&&"caller"!==i.name)&&(!i.private||"this"===e)&&(n||SPAN_IDENT.test(i.name))){const e=n?n+i.name.replaceAll("\\","\\\\").replaceAll(n,"\\"+n)+n:i.name,t=n&&!o?`${e}]`:void 0,s=2*Number(i.isOwn)+1*Number(i.enumerable),l="function"===i.value?.type?a:c;r.add({apply:t,label:e,type:l,boost:s})}}return t.runtimeModel.releaseObjectGroup("completion"),r}async function completeExpressionInScope(){const e=new CompletionSet,t=getExecutionContext()?.debuggerModel.selectedCallFrame();if(!t)return e;const n=await Promise.all(t.scopeChain().map((e=>(e=>Root.Runtime.experiments.isEnabled("evaluateExpressionsWithSourceMaps")?SourceMapScopes.NamesResolver.resolveScopeInObject(e):e.object())(e).getAllProperties(!1,!1))));for(const t of n)for(const n of t.properties||[])e.add({label:n.name,type:"function"===n.value?.type?"function":"variable"});return e}async function completeExpressionGlobal(){const e=PropertyCache.instance(),t=e.get("");if(t)return t;const n=getExecutionContext();if(!n)return baseCompletions;const o=baseCompletions.copy(),r=completePropertiesInner("globalThis",n).then((e=>n.globalLexicalScopeNames().then((t=>{for(const t of e.completions)o.add(t);for(const e of t||[])o.add({label:e,type:"variable"});return o}))));return e.set("",r),r}export async function isExpressionComplete(e){const t=UI.Context.Context.instance().flavor(SDK.RuntimeModel.ExecutionContext);if(!t)return!0;const n=await t.runtimeModel.compileScript(e,"",!1,t.id);if(!n||!n.exceptionDetails||!n.exceptionDetails.exception)return!0;const o=n.exceptionDetails.exception.description;return!!o&&(!o.startsWith("SyntaxError: Unexpected end of input")&&!o.startsWith("SyntaxError: Unterminated template literal"))}export function argumentHints(){return cursorTooltip(getArgumentHints)}export function closeArgumentsHintsTooltip(e,t){return null!==e.state.field(t)&&(e.dispatch({effects:closeTooltip.of(null)}),!0)}async function getArgumentHints(e,t){const n=CodeMirror.syntaxTree(e).resolveInner(t).enterUnfinishedNodesBefore(t);if("ArgList"!==n.name)return null;const o=n.parent?.getChild("Expression");if(!o)return null;const r=await getArgumentsForExpression(o,e.doc);if(!r)return null;let i=0;for(let e=t;;){const t=n.childBefore(e);if(!t)break;t.type.is("Expression")&&i++,e=t.from}return()=>tooltipBuilder(r,i)}async function getArgumentsForExpression(e,t){const n=getExecutionContext();if(!n)return null;const o=t.sliceString(e.from,e.to),r=await evaluateExpression(n,o,"argumentsHint");if(!r||"function"!==r.type)return null;return getArgumentsForFunctionValue(r,(async()=>{const o=e.firstChild;return o&&"MemberExpression"===e.name?evaluateExpression(n,t.sliceString(o.from,o.to),"argumentsHint"):null}),o).finally((()=>n.runtimeModel.releaseObjectGroup("argumentsHint")))}export function argumentsList(e){function t(t){for(;"ParamList"!==t.name&&t.nextSibling(););const n=[];if("ParamList"===t.name&&t.firstChild()){let o="";do{switch(t.name){case"ArrayPattern":n.push(o+"arr"),o="";break;case"ObjectPattern":n.push(o+"obj"),o="";break;case"VariableDefinition":n.push(o+e.slice(t.from,t.to)),o="";break;case"Spread":o="..."}}while(t.nextSibling())}return n}try{try{const{parser:n}=CodeMirror.javascript.javascriptLanguage.configure({strict:!0,top:"SingleClassItem"}),o=n.parse(e).cursor();if(o.firstChild()&&"MethodDeclaration"===o.name&&o.firstChild())return t(o);throw new Error("SingleClassItem rule is expected to have exactly one MethodDeclaration child")}catch{const{parser:n}=CodeMirror.javascript.javascriptLanguage.configure({strict:!0,top:"SingleExpression"}),o=n.parse(e).cursor();if(!o.firstChild())throw new Error("SingleExpression rule is expected to have children");switch(o.name){case"ArrowFunction":case"FunctionExpression":if(!o.firstChild())throw new Error(`${o.name} rule is expected to have children`);return t(o);case"ClassExpression":if(!o.firstChild())throw new Error(`${o.name} rule is expected to have children`);for(;o.nextSibling()&&"ClassBody"!==o.name;);if("ClassBody"===o.name&&o.firstChild())do{if("MethodDeclaration"===o.name&&o.firstChild()){if("PropertyDefinition"===o.name&&"constructor"===e.slice(o.from,o.to))return t(o);o.parent()}}while(o.nextSibling());return[]}throw new Error("Unexpected expression")}}catch(t){throw new Error(`Failed to parse for arguments list: ${e}`,{cause:t})}}async function getArgumentsForFunctionValue(e,t,n){const o=e.description;if(!o)return null;if(!o.endsWith("{ [native code] }"))return[argumentsList(o)];if("function () { [native code] }"===o){const t=await getArgumentsForBoundFunction(e);if(t)return t}const r=JavaScriptMetaData.JavaScriptMetadata.JavaScriptMetadataImpl.instance(),i=/^function ([^(]*)\(/.exec(o),s=i&&i[1]||n;if(!s)return null;const a=r.signaturesForNativeFunction(s);if(a)return a;const c=await t();if(!c)return null;const l=c.className;if(l){const e=r.signaturesForInstanceMethod(s,l);if(e)return e}if(c.description&&"function"===c.type&&c.description.endsWith("{ [native code] }")){const e=/^function ([^(]*)\(/.exec(c.description);if(e){const t=e[1],n=r.signaturesForStaticMethod(s,t);if(n)return n}}for(const e of await prototypesFromObject(c)){const t=r.signaturesForInstanceMethod(s,e);if(t)return t}return null}async function prototypesFromObject(e){return"number"===e.type?["Number","Object"]:"string"===e.type?["String","Object"]:"symbol"===e.type?["Symbol","Object"]:"bigint"===e.type?["BigInt","Object"]:"boolean"===e.type?["Boolean","Object"]:"undefined"===e.type||"null"===e.subtype?[]:await e.callFunctionJSON((function(){const e=[];for(let t=this;t;t=Object.getPrototypeOf(t))"object"==typeof t&&t.constructor&&t.constructor.name&&(e[e.length]=t.constructor.name);return e}),[])}async function getArgumentsForBoundFunction(e){const{internalProperties:t}=await e.getOwnProperties(!1);if(!t)return null;const n=t.find((e=>"[[TargetFunction]]"===e.name))?.value,o=t.find((e=>"[[BoundArgs]]"===e.name))?.value,r=t.find((e=>"[[BoundThis]]"===e.name))?.value;if(!r||!n||!o)return null;const i=await getArgumentsForFunctionValue(n,(()=>Promise.resolve(r))),s=SDK.RemoteObject.RemoteObject.arrayLength(o);return i?i.map((e=>{const t=e.findIndex((e=>e.startsWith("...")));return t>-1&&t<s?e.slice(t):e.slice(s)})):null}function tooltipBuilder(e,t){const n=document.createElement("div");n.className="cm-argumentHints";for(const o of e){const e=document.createElement("span");for(let n=0;n<o.length;n++){if(n===t||n<t&&o[n].startsWith("...")){e.appendChild(document.createElement("b")).appendChild(document.createTextNode(o[n]))}else e.appendChild(document.createTextNode(o[n]));n<o.length-1&&e.appendChild(document.createTextNode(", "))}const r=n.appendChild(document.createElement("div"));r.className="source-code",r.appendChild(document.createTextNode("ƒ(")),r.appendChild(e),r.appendChild(document.createTextNode(")"))}return{dom:n}}