UNPKG

makecode-core

Version:

MakeCode (PXT) - web-cached build tool

186 lines 8.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Ctx = exports.DiagnosticCategory = void 0; const mkc = require("./mkc"); const downloader = require("./downloader"); const host_1 = require("./host"); const cdnUrl = "https://cdn.makecode.com"; var DiagnosticCategory; (function (DiagnosticCategory) { DiagnosticCategory[DiagnosticCategory["Warning"] = 0] = "Warning"; DiagnosticCategory[DiagnosticCategory["Error"] = 1] = "Error"; DiagnosticCategory[DiagnosticCategory["Message"] = 2] = "Message"; })(DiagnosticCategory = exports.DiagnosticCategory || (exports.DiagnosticCategory = {})); class Ctx { constructor(editor) { this.editor = editor; this.makerHw = false; this.supportsGhPkgs = false; this.initAsync(); } async initAsync() { this.languageService = await (0, host_1.host)().createLanguageServiceAsync(this.editor); const cachePref = "c-"; // TODO should this be editor-dependent? const callbacks = { cacheGet: (key) => this.editor.cache .getAsync(cachePref + key) .then(buf => (buf ? (0, host_1.host)().bufferToString(buf) : null)), cacheSet: (key, val) => this.editor.cache.setAsync(cachePref + key, (0, host_1.host)().stringToBuffer(val)), httpRequestAsync: (options) => (0, host_1.host)().requestAsync(options, (protocol, method) => { if (protocol != "https:") throw new Error("only https: supported"); if (method != "GET") throw new Error("only GET supported"); if (!options.url.startsWith(cdnUrl + "/") && !options.url.startsWith("https://www.makecode.com/api/")) throw new Error("only CDN URLs and makecode.com/api support: " + cdnUrl + ", got " + options.url); mkc.log("GET " + options.url); }), pkgOverrideAsync: id => { if (this.lastUser && this.lastUser.linkedPackage) return this.lastUser.linkedPackage(id); else return Promise.resolve(null); }, }; await this.languageService.registerDriverCallbacksAsync(callbacks); await this.languageService.setWebConfigAsync({ cdnUrl: "https://cdn.makecode.com", }); this.supportsGhPkgs = await this.languageService.supportsGhPackagesAsync(); } async setUserAsync(user) { if (this.lastUser !== user) { this.lastUser = user; if (user) await this.languageService.performOperationAsync("reset", {}); } } async compileExtInfo(extinfo) { let existing = await this.editor.cache.getAsync("cpp-" + extinfo.sha); if (!existing) { const url = this.editor.cdnUrl + "/compile/" + extinfo.sha + ".hex"; const resp = await downloader.requestAsync({ url }).then(r => r, err => null); if (resp == null) { mkc.log(`compiling C++; this can take a while`); const cdata = extinfo.compileData; const cdataObj = JSON.parse((0, host_1.host)().bufferToString((0, host_1.host)().stringToBuffer(cdata, "base64"))); if (!cdataObj.config) throw new Error(`Compile config missing in C++; compile variant likely misconfigured`); // writeFileSync("compilereq.json", JSON.stringify(JSON.parse(Buffer.from(cdata, "base64").toString()), null, 4)) const cresp = await downloader.requestAsync({ url: "https://www.makecode.com/api/compile/extension", data: { data: cdata }, allowGzipPost: true, }); const hexurl = cresp.json.hex; const jsonUrl = hexurl.replace(/\.hex/, ".json"); let ok = false; for (let i = 0; i < 30; ++i) { const jresp = await downloader .requestAsync({ url: jsonUrl }) .then(r => r, e => null); if (jresp) { const json = jresp.json; mkc.log(`build log ${jsonUrl.replace(/\.json$/, ".log")}`); if (!json.success) { mkc.error(`C++ build failed`); if (json.mbedresponse && json.mbedresponse.result && json.mbedresponse.result.exception) mkc.error(json.mbedresponse.result.exception); throw new Error("C++ build failed"); } else { const hexresp = await downloader.requestAsync({ url: hexurl, }); ok = true; existing = hexresp.buffer; break; } } // as in pxt CLI, wait for 8 seconds, then check again const delay = 8000; mkc.log(`waiting ${(delay / 1000) | 0}s for C++ build... [${i}]`); await new Promise(resolve => setTimeout(resolve, delay)); } if (!ok) { mkc.error(`C++ build timed out`); throw new Error("C++ build timed out"); } } else { existing = resp.buffer; } await this.editor.cache.setAsync("cpp-" + extinfo.sha, existing); } extinfo.hexinfo = { hex: (0, host_1.host)().bufferToString(existing).split(/\r?\n/) }; } async simpleCompileAsync(prj, simpleOpts = {}) { var _a; let opts = await this.getOptionsAsync(prj, simpleOpts); if (simpleOpts.emitBreakpoints) { opts.breakpoints = true; } if (simpleOpts.native && ((_a = opts === null || opts === void 0 ? void 0 : opts.extinfo) === null || _a === void 0 ? void 0 : _a.sha)) { const infos = [opts.extinfo].concat((opts.otherMultiVariants || []).map(x => x.extinfo)); for (const info of infos) await this.compileExtInfo(info); } // Manually set this option for now if (simpleOpts.computeUsedParts) opts.computeUsedParts = true; // opts.breakpoints = true return this.languageService.performOperationAsync("compile", { options: opts }); } async buildSimJsInfoAsync(result) { return await this.languageService.buildSimJsInfoAsync(result); } async setHwVariantAsync(prj) { if (this.makerHw) { const tmp = Object.assign({}, prj.files); const cfg = JSON.parse(tmp["pxt.json"]); if (prj.mkcConfig.hwVariant) cfg.dependencies[prj.mkcConfig.hwVariant] = "*"; tmp["pxt.json"] = mkc.stringifyConfig(cfg); await this.languageService.setProjectTextAsync(tmp); } else { await this.languageService.setProjectTextAsync(prj.files); await this.languageService.setHwVariantAsync(prj.mkcConfig.hwVariant || ""); } } async getOptionsAsync(prj, simpleOpts = {}) { await this.setHwVariantAsync(prj); return this.languageService.getCompileOptionsAsync(prj, simpleOpts); } async installGhPackagesAsync(prj) { await this.setHwVariantAsync(prj); const pkg = await this.languageService.installGhPackagesAsync(prj.files); prj.files = pkg; } async getHardwareVariantsAsync() { let hwVariants = await this.languageService.getHardwareVariantsAsync(); if (hwVariants.length == 0) { hwVariants = await this.languageService.getBundledPackageConfigsAsync(); hwVariants = hwVariants.filter(pkg => !/prj/.test(pkg.name) && !!pkg.core); for (const pkg of hwVariants) { pkg.card = { name: "", description: pkg.description, }; } if (hwVariants.length > 1) this.makerHw = true; else hwVariants = []; } return hwVariants; } dispose() { var _a, _b; (_b = (_a = this.languageService) === null || _a === void 0 ? void 0 : _a.dispose) === null || _b === void 0 ? void 0 : _b.call(_a); } } exports.Ctx = Ctx; //# sourceMappingURL=service.js.map