UNPKG

@yuebai008/cli

Version:

Command line interface for rapid qg-minigame development

1 lines 12.7 kB
import*as Common from"../../core/common/common.js";import*as Platform from"../../core/platform/platform.js";import*as SDK from"../../core/sdk/sdk.js";import*as TextUtils from"../../models/text_utils/text_utils.js";export var Events;!function(e){e.CoverageUpdated="CoverageUpdated",e.CoverageReset="CoverageReset"}(Events||(Events={}));const COVERAGE_POLLING_PERIOD_MS=200;export class CoverageModel extends SDK.SDKModel.SDKModel{cpuProfilerModel;cssModel;debuggerModel;coverageByURL;coverageByContentProvider;coverageUpdateTimes;suspensionState;pollTimer;currentPollPromise;shouldResumePollingOnResume;jsBacklog;cssBacklog;performanceTraceRecording;constructor(e){super(e),this.cpuProfilerModel=e.model(SDK.CPUProfilerModel.CPUProfilerModel),this.cssModel=e.model(SDK.CSSModel.CSSModel),this.debuggerModel=e.model(SDK.DebuggerModel.DebuggerModel),this.coverageByURL=new Map,this.coverageByContentProvider=new Map,this.coverageUpdateTimes=new Set,this.suspensionState="Active",this.pollTimer=null,this.currentPollPromise=null,this.shouldResumePollingOnResume=!1,this.jsBacklog=[],this.cssBacklog=[],this.performanceTraceRecording=!1}async start(e){if("Active"!==this.suspensionState)throw Error("Cannot start CoverageModel while it is not active.");const t=[];return this.cssModel&&(this.clearCSS(),this.cssModel.addEventListener(SDK.CSSModel.Events.StyleSheetAdded,this.handleStyleSheetAdded,this),t.push(this.cssModel.startCoverage())),this.cpuProfilerModel&&t.push(this.cpuProfilerModel.startPreciseCoverage(e,this.preciseCoverageDeltaUpdate.bind(this))),await Promise.all(t),Boolean(this.cssModel||this.cpuProfilerModel)}preciseCoverageDeltaUpdate(e,t,s){this.coverageUpdateTimes.add(e),this.backlogOrProcessJSCoverage(s,e)}async stop(){await this.stopPolling();const e=[];this.cpuProfilerModel&&e.push(this.cpuProfilerModel.stopPreciseCoverage()),this.cssModel&&(e.push(this.cssModel.stopCoverage()),this.cssModel.removeEventListener(SDK.CSSModel.Events.StyleSheetAdded,this.handleStyleSheetAdded,this)),await Promise.all(e)}reset(){this.coverageByURL=new Map,this.coverageByContentProvider=new Map,this.coverageUpdateTimes=new Set,this.dispatchEventToListeners(Events.CoverageReset)}async startPolling(){this.currentPollPromise||"Active"!==this.suspensionState||await this.pollLoop()}async pollLoop(){this.clearTimer(),this.currentPollPromise=this.pollAndCallback(),await this.currentPollPromise,("Active"===this.suspensionState||this.performanceTraceRecording)&&(this.pollTimer=window.setTimeout((()=>this.pollLoop()),200))}async stopPolling(){this.clearTimer(),await this.currentPollPromise,this.currentPollPromise=null,await this.pollAndCallback()}async pollAndCallback(){if("Suspended"===this.suspensionState&&!this.performanceTraceRecording)return;const e=await this.takeAllCoverage();console.assert("Suspended"!==this.suspensionState||Boolean(this.performanceTraceRecording),"CoverageModel was suspended while polling."),e.length&&this.dispatchEventToListeners(Events.CoverageUpdated,e)}clearTimer(){this.pollTimer&&(clearTimeout(this.pollTimer),this.pollTimer=null)}async preSuspendModel(e){"Active"===this.suspensionState&&(this.suspensionState="Suspending","performance-timeline"!==e?this.currentPollPromise&&(await this.stopPolling(),this.shouldResumePollingOnResume=!0):this.performanceTraceRecording=!0)}async suspendModel(e){this.suspensionState="Suspended"}async resumeModel(){}async postResumeModel(){this.suspensionState="Active",this.performanceTraceRecording=!1,this.shouldResumePollingOnResume&&(this.shouldResumePollingOnResume=!1,await this.startPolling())}entries(){return Array.from(this.coverageByURL.values())}getCoverageForUrl(e){return this.coverageByURL.get(e)||null}usageForRange(e,t,s){const o=this.coverageByContentProvider.get(e);return o&&o.usageForRange(t,s)}clearCSS(){for(const e of this.coverageByContentProvider.values()){if(1!==e.type())continue;const t=e.getContentProvider();this.coverageByContentProvider.delete(t);const s=this.coverageByURL.get(e.url());if(!s)continue;const o=`${t.startLine}:${t.startColumn}`;s.removeCoverageEntry(o,e),0===s.numberOfEntries()&&this.coverageByURL.delete(e.url())}if(this.cssModel)for(const e of this.cssModel.getAllStyleSheetHeaders())this.addStyleSheetToCSSCoverage(e)}async takeAllCoverage(){const[e,t]=await Promise.all([this.takeCSSCoverage(),this.takeJSCoverage()]);return[...e,...t]}async takeJSCoverage(){if(!this.cpuProfilerModel)return[];const{coverage:e,timestamp:t}=await this.cpuProfilerModel.takePreciseCoverage();return this.coverageUpdateTimes.add(t),this.backlogOrProcessJSCoverage(e,t)}getCoverageUpdateTimes(){return this.coverageUpdateTimes}async backlogOrProcessJSCoverage(e,t){if(e.length>0&&this.jsBacklog.push({rawCoverageData:e,stamp:t}),"Active"!==this.suspensionState)return[];const s=(e,t)=>e.stamp-t.stamp,o=[];for(const{rawCoverageData:e,stamp:t}of this.jsBacklog.sort(s))o.push(this.processJSCoverage(e,t));return this.jsBacklog=[],o.flat()}async processJSBacklog(){this.backlogOrProcessJSCoverage([],0)}processJSCoverage(e,t){if(!this.debuggerModel)return[];const s=[];for(const o of e){const e=this.debuggerModel.scriptForId(o.scriptId);if(!e)continue;const r=[];let n=2;for(const e of o.functions){!1!==e.isBlockCoverage||1===e.ranges.length&&!e.ranges[0].count||(n|=4);for(const t of e.ranges)r.push(t)}const i=this.addCoverage(e,e.contentLength,e.lineOffset,e.columnOffset,r,n,t);i&&s.push(i)}return s}handleStyleSheetAdded(e){this.addStyleSheetToCSSCoverage(e.data)}async takeCSSCoverage(){if(!this.cssModel||"Active"!==this.suspensionState)return[];const{coverage:e,timestamp:t}=await this.cssModel.takeCoverageDelta();return this.coverageUpdateTimes.add(t),this.backlogOrProcessCSSCoverage(e,t)}async backlogOrProcessCSSCoverage(e,t){if(e.length>0&&this.cssBacklog.push({rawCoverageData:e,stamp:t}),"Active"!==this.suspensionState)return[];const s=(e,t)=>e.stamp-t.stamp,o=[];for(const{rawCoverageData:e,stamp:t}of this.cssBacklog.sort(s))o.push(this.processCSSCoverage(e,t));return this.cssBacklog=[],o.flat()}processCSSCoverage(e,t){if(!this.cssModel)return[];const s=[],o=new Map;for(const t of e){const e=this.cssModel.styleSheetHeaderForId(t.styleSheetId);if(!e)continue;let s=o.get(e);s||(s=[],o.set(e,s)),s.push({startOffset:t.startOffset,endOffset:t.endOffset,count:Number(t.used)})}for(const e of o){const o=e[0],r=e[1],n=this.addCoverage(o,o.contentLength,o.startLine,o.startColumn,r,1,t);n&&s.push(n)}return s}static convertToDisjointSegments(e,t){e.sort(((e,t)=>e.startOffset-t.startOffset));const s=[],o=[];for(const t of e){let e=o[o.length-1];for(;e&&e.endOffset<=t.startOffset;)r(e.endOffset,e.count),o.pop(),e=o[o.length-1];r(t.startOffset,e?e.count:0),o.push(t)}for(let e=o.pop();e;e=o.pop())r(e.endOffset,e.count);function r(e,o){const r=s[s.length-1];if(r){if(r.end===e)return;if(r.count===o)return void(r.end=e)}s.push({end:e,count:o,stamp:t})}return s}addStyleSheetToCSSCoverage(e){this.addCoverage(e,e.contentLength,e.startLine,e.startColumn,[],1,Date.now())}addCoverage(e,t,s,o,r,n,i){const a=e.contentURL();if(!a)return null;let c=this.coverageByURL.get(a),l=!1;c||(l=!0,c=new URLCoverageInfo(a),this.coverageByURL.set(a,c));const h=c.ensureEntry(e,t,s,o,n);this.coverageByContentProvider.set(e,h);const u=CoverageModel.convertToDisjointSegments(r,i),d=u[u.length-1];d&&d.end<t&&u.push({end:t,stamp:i,count:0});const g=h.mergeCoverage(u);return l||0!==g?(c.addToSizes(g,0),h):null}async exportReport(e){const t=[],s=Array.from(this.coverageByURL.keys()).sort();for(const e of s){const s=this.coverageByURL.get(e);if(!s)continue;const o=s.url();o.startsWith("extensions::")||o.startsWith("chrome-extension://")||t.push(...await s.entriesForExport())}await e.write(JSON.stringify(t,void 0,2)),e.close()}}function locationCompare(e,t){const[s,o]=e.split(":"),[r,n]=t.split(":");return Number.parseInt(s,10)-Number.parseInt(r,10)||Number.parseInt(o,10)-Number.parseInt(n,10)}SDK.SDKModel.SDKModel.register(CoverageModel,{capabilities:SDK.Target.Capability.None,autostart:!1});export class URLCoverageInfo extends Common.ObjectWrapper.ObjectWrapper{urlInternal;coverageInfoByLocation;sizeInternal;usedSizeInternal;typeInternal;isContentScriptInternal;constructor(e){super(),this.urlInternal=e,this.coverageInfoByLocation=new Map,this.sizeInternal=0,this.usedSizeInternal=0,this.isContentScriptInternal=!1}url(){return this.urlInternal}type(){return this.typeInternal}size(){return this.sizeInternal}usedSize(){return this.usedSizeInternal}unusedSize(){return this.sizeInternal-this.usedSizeInternal}usedPercentage(){return 0===this.sizeInternal?0:this.usedSize()/this.size()}unusedPercentage(){return 0===this.sizeInternal?100:this.unusedSize()/this.size()}isContentScript(){return this.isContentScriptInternal}entries(){return this.coverageInfoByLocation.values()}numberOfEntries(){return this.coverageInfoByLocation.size}removeCoverageEntry(e,t){this.coverageInfoByLocation.delete(e)&&this.addToSizes(-t.getUsedSize(),-t.getSize())}addToSizes(e,t){this.usedSizeInternal+=e,this.sizeInternal+=t,0===e&&0===t||this.dispatchEventToListeners(URLCoverageInfo.Events.SizesChanged)}ensureEntry(e,t,s,o,r){const n=`${s}:${o}`;let i=this.coverageInfoByLocation.get(n);return 2&r&&!this.coverageInfoByLocation.size&&(this.isContentScriptInternal=e.isContentScript()),this.typeInternal|=r,i?(i.addCoverageType(r),i):(2&r&&!this.coverageInfoByLocation.size&&(this.isContentScriptInternal=e.isContentScript()),i=new CoverageInfo(e,t,s,o,r),this.coverageInfoByLocation.set(n,i),this.addToSizes(0,t),i)}async getFullText(){let e=!1;const t=this.url();for(const s of this.coverageInfoByLocation.values()){const{lineOffset:o,columnOffset:r}=s.getOffsets();if(o||r){e=Boolean(t);break}}if(!e)return null;const s=SDK.ResourceTreeModel.ResourceTreeModel.resourceForURL(t);if(!s)return null;const o=(await s.requestContent()).content;return new TextUtils.Text.Text(o||"")}entriesForExportBasedOnFullText(e){const t=Array.from(this.coverageInfoByLocation.keys()).sort(locationCompare),s={url:this.url(),ranges:[],text:e.value()};for(const o of t){const t=this.coverageInfoByLocation.get(o);if(!t)continue;const{lineOffset:r,columnOffset:n}=t.getOffsets(),i=e?e.offsetFromPosition(r,n):0;s.ranges.push(...t.rangesForExport(i))}return s}async entriesForExportBasedOnContent(){const e=Array.from(this.coverageInfoByLocation.keys()).sort(locationCompare),t=[];for(const s of e){const e=this.coverageInfoByLocation.get(s);if(!e)continue;const o={url:this.url(),ranges:e.rangesForExport(),text:(await e.getContentProvider().requestContent()).content};t.push(o)}return t}async entriesForExport(){const e=await this.getFullText();return e?[await this.entriesForExportBasedOnFullText(e)]:this.entriesForExportBasedOnContent()}}!function(e){let t;!function(e){e.SizesChanged="SizesChanged"}(t=e.Events||(e.Events={}))}(URLCoverageInfo||(URLCoverageInfo={}));export const mergeSegments=(e,t)=>{const s=[];let o=0,r=0;for(;o<e.length&&r<t.length;){const n=e[o],i=t[r],a=(n.count||0)+(i.count||0),c=Math.min(n.end,i.end),l=s[s.length-1],h=Math.min(n.stamp,i.stamp);l&&l.count===a&&l.stamp===h?l.end=c:s.push({end:c,count:a,stamp:h}),n.end<=i.end&&o++,n.end>=i.end&&r++}for(;o<e.length;o++)s.push(e[o]);for(;r<t.length;r++)s.push(t[r]);return s};export class CoverageInfo{contentProvider;size;usedSize;statsByTimestamp;lineOffset;columnOffset;coverageType;segments;constructor(e,t,s,o,r){this.contentProvider=e,this.size=t,this.usedSize=0,this.statsByTimestamp=new Map,this.lineOffset=s,this.columnOffset=o,this.coverageType=r,this.segments=[]}getContentProvider(){return this.contentProvider}url(){return this.contentProvider.contentURL()}type(){return this.coverageType}addCoverageType(e){this.coverageType|=e}getOffsets(){return{lineOffset:this.lineOffset,columnOffset:this.columnOffset}}mergeCoverage(e){const t=this.usedSize;return this.segments=mergeSegments(this.segments,e),this.updateStats(),this.usedSize-t}usedByTimestamp(){return this.statsByTimestamp}getSize(){return this.size}getUsedSize(){return this.usedSize}usageForRange(e,t){let s=Platform.ArrayUtilities.upperBound(this.segments,e,((e,t)=>e-t.end));for(;s<this.segments.length&&this.segments[s].end<t;++s)if(this.segments[s].count)return!0;return s<this.segments.length&&Boolean(this.segments[s].count)}updateStats(){this.statsByTimestamp=new Map,this.usedSize=0;let e=0;for(const t of this.segments){let s=this.statsByTimestamp.get(t.stamp);if(void 0===s&&(s=0),t.count){const o=t.end-e;this.usedSize+=o,this.statsByTimestamp.set(t.stamp,s+o)}e=t.end}}rangesForExport(e=0){const t=[];let s=0;for(const o of this.segments){if(o.count){const r=t.length>0?t[t.length-1]:null;r&&r.end===s+e?r.end=o.end+e:t.push({start:s+e,end:o.end+e})}s=o.end}return t}}