makecode-core
Version:
MakeCode (PXT) - web-cached build tool
186 lines • 8.7 kB
JavaScript
;
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