pxt-core 7.3.3 → 7.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/built/cli.js CHANGED
@@ -403,6 +403,8 @@ function ciAsync() {
403
403
  pxt.log(`pull request: ${pullRequest}`);
404
404
  pxt.log(`upload api strings: ${uploadApiStrings}`);
405
405
  pxt.log(`upload docs: ${uploadDocs}`);
406
+ lintJSONInDirectory(path.resolve("."));
407
+ lintJSONInDirectory(path.resolve("docs"));
406
408
  function npmPublishAsync() {
407
409
  if (!npmPublish)
408
410
  return Promise.resolve();
@@ -459,6 +461,21 @@ function ciAsync() {
459
461
  });
460
462
  }
461
463
  }
464
+ function lintJSONInDirectory(dir) {
465
+ for (const file of fs.readdirSync(dir)) {
466
+ const fullPath = path.join(dir, file);
467
+ if (file.endsWith(".json")) {
468
+ const contents = fs.readFileSync(fullPath, "utf8");
469
+ try {
470
+ JSON.parse(contents);
471
+ }
472
+ catch (e) {
473
+ console.log("Could not parse " + fullPath);
474
+ process.exit(1);
475
+ }
476
+ }
477
+ }
478
+ }
462
479
  function bumpPxtCoreDepAsync() {
463
480
  let pkg = readJson("package.json");
464
481
  if (pkg["name"] == "pxt-core")
package/built/pxt.js CHANGED
@@ -97876,6 +97876,10 @@ var pxt;
97876
97876
  let _client;
97877
97877
  function client() { return _client; }
97878
97878
  auth.client = client;
97879
+ const PREFERENCES_DEBOUNCE_MS = 5 * 1000;
97880
+ const PREFERENCES_DEBOUNCE_MAX_MS = 30 * 1000;
97881
+ let debouncePreferencesChangedTimeout = 0;
97882
+ let debouncePreferencesChangedStarted = 0;
97879
97883
  class AuthClient {
97880
97884
  constructor() {
97881
97885
  this.initialUserPreferences_ = undefined;
@@ -98081,15 +98085,28 @@ var pxt;
98081
98085
  if (!await this.loggedInAsync()) {
98082
98086
  return;
98083
98087
  }
98084
- // If the user is logged in, save to cloud
98085
- const result = await this.apiAsync('/api/user/preferences', ops, 'PATCH');
98086
- if (result.success) {
98087
- pxt.debug("Updating local user preferences w/ cloud data after result of POST");
98088
- // Set user profile from returned value so we stay in-sync
98089
- this.setUserPreferencesAsync(result.resp);
98088
+ // If the user is logged in, save to cloud, but debounce the api call as this can be called frequently from skillmaps
98089
+ clearTimeout(debouncePreferencesChangedTimeout);
98090
+ const savePrefs = async () => {
98091
+ debouncePreferencesChangedStarted = 0;
98092
+ const result = await this.apiAsync('/api/user/preferences', ops, 'PATCH');
98093
+ if (result.success) {
98094
+ pxt.debug("Updating local user preferences w/ cloud data after result of POST");
98095
+ // Set user profile from returned value so we stay in-sync
98096
+ this.setUserPreferencesAsync(result.resp);
98097
+ }
98098
+ else {
98099
+ pxt.reportError("identity", "update preferences failed", result);
98100
+ }
98101
+ };
98102
+ if (!debouncePreferencesChangedStarted) {
98103
+ debouncePreferencesChangedStarted = pxt.U.now();
98104
+ }
98105
+ if (PREFERENCES_DEBOUNCE_MAX_MS < pxt.U.now() - debouncePreferencesChangedStarted) {
98106
+ await savePrefs();
98090
98107
  }
98091
98108
  else {
98092
- pxt.reportError("identity", "update preferences failed", result);
98109
+ debouncePreferencesChangedTimeout = setTimeout(savePrefs, PREFERENCES_DEBOUNCE_MS);
98093
98110
  }
98094
98111
  }
98095
98112
  /*protected*/ hasUserId() {
@@ -101052,6 +101069,8 @@ var pxt;
101052
101069
  }
101053
101070
  if (!comp.switches)
101054
101071
  comp.switches = {};
101072
+ if (comp.nativeType == pxtc.NATIVE_TYPE_VM)
101073
+ comp.sourceMap = true;
101055
101074
  pxt.U.jsonCopyFrom(comp.switches, savedSwitches);
101056
101075
  // JS ref counting currently not supported
101057
101076
  comp.jsRefCounting = false;
@@ -103399,6 +103418,7 @@ var pxt;
103399
103418
  commands.electronDeployAsync = undefined; // A pointer to the Electron deploy function, so that targets can access it in their extension.ts
103400
103419
  commands.webUsbPairDialogAsync = undefined;
103401
103420
  commands.onTutorialCompleted = undefined;
103421
+ commands.workspaceLoadedAsync = undefined;
103402
103422
  })(commands = pxt.commands || (pxt.commands = {}));
103403
103423
  })(pxt || (pxt = {}));
103404
103424
  /// <reference path="../localtypings/pxtarget.d.ts"/>
@@ -104645,7 +104665,7 @@ int main() {
104645
104665
  .then(ret => new Promise((resolve, reject) => {
104646
104666
  let retry = 0;
104647
104667
  const delay = 8000; // ms
104648
- const maxWait = 180000; // ms
104668
+ const maxWait = 300000; // ms
104649
104669
  const startTry = pxt.U.now();
104650
104670
  const tryGet = () => {
104651
104671
  retry++;
@@ -112845,6 +112865,7 @@ var ts;
112845
112865
  pxtc.BINARY_ELF = "binary.elf";
112846
112866
  pxtc.BINARY_PXT64 = "binary.pxt64";
112847
112867
  pxtc.BINARY_ESP = "binary.bin";
112868
+ pxtc.BINARY_SRCMAP = "binary.srcmap";
112848
112869
  pxtc.NATIVE_TYPE_THUMB = "thumb";
112849
112870
  pxtc.NATIVE_TYPE_VM = "vm";
112850
112871
  function BuildSourceMapHelpers(sourceMap, tsFile, pyFile) {
@@ -118709,7 +118730,6 @@ var pxt;
118709
118730
  youtube.watchUrl = watchUrl;
118710
118731
  })(youtube = pxt.youtube || (pxt.youtube = {}));
118711
118732
  })(pxt || (pxt = {}));
118712
- /* eslint-disable no-cond-assign */
118713
118733
  // TODO: add a macro facility to make 8-bit assembly easier?
118714
118734
  var ts;
118715
118735
  (function (ts) {
@@ -118967,7 +118987,7 @@ var ts;
118967
118987
  // recursive-descent parsing of multiplication
118968
118988
  if (s.indexOf("*") >= 0) {
118969
118989
  let m = null;
118970
- while (m = /^([^\*]*)\*(.*)$/.exec(s)) {
118990
+ while (null != (m = /^([^\*]*)\*(.*)$/.exec(s))) {
118971
118991
  let tmp = this.parseOneInt(m[1]);
118972
118992
  if (tmp == null)
118973
118993
  return null;
@@ -119582,6 +119602,37 @@ var ts;
119582
119602
  }
119583
119603
  });
119584
119604
  }
119605
+ getSourceMap() {
119606
+ const sourceMap = {};
119607
+ let locFile = "";
119608
+ let locLn = 0;
119609
+ let locPos = 0;
119610
+ let locEnd = 0;
119611
+ this.lines.forEach((ln, i) => {
119612
+ const m = /^; ([\w\/\.-]+)\(([\d]+),\d+\):/.exec(ln.text);
119613
+ if (m) {
119614
+ flush();
119615
+ locFile = m[1];
119616
+ locLn = parseInt(m[2]);
119617
+ }
119618
+ if (ln.type == "instruction") {
119619
+ if (!locPos)
119620
+ locPos = ln.location;
119621
+ locEnd = ln.location;
119622
+ }
119623
+ });
119624
+ flush();
119625
+ function flush() {
119626
+ if (locFile && locPos) {
119627
+ if (!sourceMap[locFile])
119628
+ sourceMap[locFile] = [];
119629
+ sourceMap[locFile].push(locLn, locPos, locEnd - locPos);
119630
+ }
119631
+ locPos = 0;
119632
+ locEnd = 0;
119633
+ }
119634
+ return sourceMap;
119635
+ }
119585
119636
  getSource(clean, numStmts = 1, flashSize = 0) {
119586
119637
  let lenPrev = 0;
119587
119638
  let size = (lbl) => {
@@ -124092,6 +124143,53 @@ ${info.id}_IfaceVT:
124092
124143
  else
124093
124144
  return `0xffffffff, 0xffffffff ; -> ${vt}`;
124094
124145
  }
124146
+ function encodeSourceMap(srcmap) {
124147
+ // magic: 0x4d435253 0x2d4e1588 0x719986aa ('SRCM' ... )
124148
+ const res = [0x53, 0x52, 0x43, 0x4d, 0x88, 0x15, 0x4e, 0x2d, 0xaa, 0x86, 0x99, 0x71, 0x00, 0x00, 0x00, 0x00];
124149
+ for (const fn of Object.keys(srcmap)) {
124150
+ for (const c of pxtc.U.stringToUint8Array(fn))
124151
+ res.push(c);
124152
+ res.push(0);
124153
+ const arr = srcmap[fn];
124154
+ let prevLn = 0;
124155
+ let prevOff = 0;
124156
+ for (let i = 0; i < arr.length; i += 3) {
124157
+ encodeNumber(arr[i] - prevLn);
124158
+ encodeNumber((arr[i + 1] - prevOff) >> 1);
124159
+ encodeNumber(arr[i + 2] >> 1);
124160
+ prevLn = arr[i];
124161
+ prevOff = arr[i + 1];
124162
+ }
124163
+ res.push(0xff); // end-marker
124164
+ }
124165
+ res.push(0);
124166
+ if (res.length & 1)
124167
+ res.push(0);
124168
+ const res2 = [];
124169
+ for (let i = 0; i < res.length; i += 2)
124170
+ res2.push(res[i] | (res[i + 1] << 8));
124171
+ return res2;
124172
+ function encodeNumber(k) {
124173
+ if (0 <= k && k < 0xf0)
124174
+ res.push(k);
124175
+ else {
124176
+ let mark = 0xf0;
124177
+ if (k < 0) {
124178
+ k = -k;
124179
+ mark |= 0x08;
124180
+ }
124181
+ const idx = res.length;
124182
+ res.push(null); // placeholder
124183
+ let len = 0;
124184
+ while (k != 0) {
124185
+ res.push(k & 0xff);
124186
+ k >>>= 8;
124187
+ len++;
124188
+ }
124189
+ res[idx] = mark | len;
124190
+ }
124191
+ }
124192
+ }
124095
124193
  /* eslint-disable no-trailing-spaces */
124096
124194
  function vmEmit(bin, opts) {
124097
124195
  let vmsource = `; VM start
@@ -124129,7 +124227,7 @@ _start_${name}:
124129
124227
  vmsource += `\n.balign 8\n_end_${name}:\n`;
124130
124228
  address++;
124131
124229
  }
124132
- const now = new Date();
124230
+ const now = new Date(0); // new Date()
124133
124231
  let encodedName = pxtc.U.toUTF8(opts.name, true);
124134
124232
  if (encodedName.length > 100)
124135
124233
  encodedName = encodedName.slice(0, 100);
@@ -124215,8 +124313,25 @@ _start_${name}:
124215
124313
  vmsource += "\n; The end.\n";
124216
124314
  bin.writeFile(pxtc.BINARY_ASM, vmsource);
124217
124315
  let res = pxtc.assemble(opts.target, bin, vmsource);
124316
+ const srcmap = res.thumbFile.getSourceMap();
124317
+ const encodedSrcMap = encodeSourceMap(srcmap);
124218
124318
  if (res.src)
124219
- bin.writeFile(pxtc.BINARY_ASM, res.src);
124319
+ bin.writeFile(pxtc.BINARY_ASM, `; srcmap size: ${encodedSrcMap.length << 1} bytes\n` + res.src);
124320
+ {
124321
+ let binstring = "";
124322
+ for (let v of res.buf)
124323
+ binstring += String.fromCharCode(v & 0xff, v >> 8);
124324
+ const hash = pxtc.U.sha256(binstring);
124325
+ for (let i = 0; i < 4; ++i) {
124326
+ res.buf[16 + i] = parseInt(hash.slice(i * 4, i * 4 + 4), 16);
124327
+ }
124328
+ srcmap["__meta"] = {
124329
+ name: opts.name,
124330
+ programHash: res.buf[16] | (res.buf[16 + 1] << 16),
124331
+ // TODO would be nice to include version number of editor...
124332
+ };
124333
+ }
124334
+ bin.writeFile(pxtc.BINARY_SRCMAP, JSON.stringify(srcmap));
124220
124335
  if (pxt.options.debug) {
124221
124336
  let pc = res.thumbFile.peepCounts;
124222
124337
  let keys = Object.keys(pc);
@@ -124227,12 +124342,16 @@ _start_${name}:
124227
124342
  }
124228
124343
  if (res.buf) {
124229
124344
  let binstring = "";
124230
- for (let v of res.buf)
124345
+ const buf = res.buf;
124346
+ while (buf.length & 0xf)
124347
+ buf.push(0);
124348
+ pxtc.U.pushRange(buf, encodedSrcMap);
124349
+ for (let v of buf)
124231
124350
  binstring += String.fromCharCode(v & 0xff, v >> 8);
124232
124351
  binstring = ts.pxtc.encodeBase64(binstring);
124233
124352
  if (embedVTs()) {
124234
124353
  bin.writeFile(pxtc.BINARY_PXT64, binstring);
124235
- const patched = pxtc.hexfile.patchHex(bin, res.buf, false, !!pxtc.target.useUF2)[0];
124354
+ const patched = pxtc.hexfile.patchHex(bin, buf, false, !!pxtc.target.useUF2)[0];
124236
124355
  bin.writeFile(pxt.outputName(pxtc.target), ts.pxtc.encodeBase64(patched));
124237
124356
  }
124238
124357
  else {
@@ -124263,7 +124382,7 @@ _start_${name}:
124263
124382
  emitAll();
124264
124383
  return resText;
124265
124384
  function emitAll() {
124266
- writeRaw(`;\n; Proc: ${proc.getFullName()}\n;`);
124385
+ writeRaw(`;\n; ${proc.getFullName()}\n;`);
124267
124386
  write(".section code");
124268
124387
  if (bin.procs[0] == proc) {
124269
124388
  writeRaw(`; main`);
@@ -129005,7 +129124,7 @@ var ts;
129005
129124
  let name = pxtc.getDeclName(this.action);
129006
129125
  if (this.action) {
129007
129126
  let info = ts.pxtc.nodeLocationInfo(this.action);
129008
- name += " " + info.fileName.replace("pxt_modules/", "") + ":" + (info.line + 1);
129127
+ name = info.fileName.replace("pxt_modules/", "") + "(" + (info.line + 1) + "," + (info.column + 1) + "): " + name;
129009
129128
  }
129010
129129
  return name;
129011
129130
  }
@@ -132948,7 +133067,7 @@ ${lbl}: .short 0xffff
132948
133067
  }
132949
133068
  function emitBrk(node) {
132950
133069
  bin.numStmts++;
132951
- const needsComment = pxtc.assembler.debug || pxtc.target.switches.size;
133070
+ const needsComment = pxtc.assembler.debug || pxtc.target.switches.size || pxtc.target.sourceMap;
132952
133071
  let needsBreak = !!opts.breakpoints;
132953
133072
  if (!needsComment && !needsBreak)
132954
133073
  return;
@@ -156153,6 +156272,8 @@ function ciAsync() {
156153
156272
  pxt.log(`pull request: ${pullRequest}`);
156154
156273
  pxt.log(`upload api strings: ${uploadApiStrings}`);
156155
156274
  pxt.log(`upload docs: ${uploadDocs}`);
156275
+ lintJSONInDirectory(path.resolve("."));
156276
+ lintJSONInDirectory(path.resolve("docs"));
156156
156277
  function npmPublishAsync() {
156157
156278
  if (!npmPublish)
156158
156279
  return Promise.resolve();
@@ -156209,6 +156330,21 @@ function ciAsync() {
156209
156330
  });
156210
156331
  }
156211
156332
  }
156333
+ function lintJSONInDirectory(dir) {
156334
+ for (const file of fs.readdirSync(dir)) {
156335
+ const fullPath = path.join(dir, file);
156336
+ if (file.endsWith(".json")) {
156337
+ const contents = fs.readFileSync(fullPath, "utf8");
156338
+ try {
156339
+ JSON.parse(contents);
156340
+ }
156341
+ catch (e) {
156342
+ console.log("Could not parse " + fullPath);
156343
+ process.exit(1);
156344
+ }
156345
+ }
156346
+ }
156347
+ }
156212
156348
  function bumpPxtCoreDepAsync() {
156213
156349
  let pkg = readJson("package.json");
156214
156350
  if (pkg["name"] == "pxt-core")
@@ -3350,6 +3350,53 @@ ${info.id}_IfaceVT:
3350
3350
  else
3351
3351
  return `0xffffffff, 0xffffffff ; -> ${vt}`;
3352
3352
  }
3353
+ function encodeSourceMap(srcmap) {
3354
+ // magic: 0x4d435253 0x2d4e1588 0x719986aa ('SRCM' ... )
3355
+ const res = [0x53, 0x52, 0x43, 0x4d, 0x88, 0x15, 0x4e, 0x2d, 0xaa, 0x86, 0x99, 0x71, 0x00, 0x00, 0x00, 0x00];
3356
+ for (const fn of Object.keys(srcmap)) {
3357
+ for (const c of pxtc.U.stringToUint8Array(fn))
3358
+ res.push(c);
3359
+ res.push(0);
3360
+ const arr = srcmap[fn];
3361
+ let prevLn = 0;
3362
+ let prevOff = 0;
3363
+ for (let i = 0; i < arr.length; i += 3) {
3364
+ encodeNumber(arr[i] - prevLn);
3365
+ encodeNumber((arr[i + 1] - prevOff) >> 1);
3366
+ encodeNumber(arr[i + 2] >> 1);
3367
+ prevLn = arr[i];
3368
+ prevOff = arr[i + 1];
3369
+ }
3370
+ res.push(0xff); // end-marker
3371
+ }
3372
+ res.push(0);
3373
+ if (res.length & 1)
3374
+ res.push(0);
3375
+ const res2 = [];
3376
+ for (let i = 0; i < res.length; i += 2)
3377
+ res2.push(res[i] | (res[i + 1] << 8));
3378
+ return res2;
3379
+ function encodeNumber(k) {
3380
+ if (0 <= k && k < 0xf0)
3381
+ res.push(k);
3382
+ else {
3383
+ let mark = 0xf0;
3384
+ if (k < 0) {
3385
+ k = -k;
3386
+ mark |= 0x08;
3387
+ }
3388
+ const idx = res.length;
3389
+ res.push(null); // placeholder
3390
+ let len = 0;
3391
+ while (k != 0) {
3392
+ res.push(k & 0xff);
3393
+ k >>>= 8;
3394
+ len++;
3395
+ }
3396
+ res[idx] = mark | len;
3397
+ }
3398
+ }
3399
+ }
3353
3400
  /* eslint-disable no-trailing-spaces */
3354
3401
  function vmEmit(bin, opts) {
3355
3402
  let vmsource = `; VM start
@@ -3387,7 +3434,7 @@ _start_${name}:
3387
3434
  vmsource += `\n.balign 8\n_end_${name}:\n`;
3388
3435
  address++;
3389
3436
  }
3390
- const now = new Date();
3437
+ const now = new Date(0); // new Date()
3391
3438
  let encodedName = pxtc.U.toUTF8(opts.name, true);
3392
3439
  if (encodedName.length > 100)
3393
3440
  encodedName = encodedName.slice(0, 100);
@@ -3473,8 +3520,25 @@ _start_${name}:
3473
3520
  vmsource += "\n; The end.\n";
3474
3521
  bin.writeFile(pxtc.BINARY_ASM, vmsource);
3475
3522
  let res = pxtc.assemble(opts.target, bin, vmsource);
3523
+ const srcmap = res.thumbFile.getSourceMap();
3524
+ const encodedSrcMap = encodeSourceMap(srcmap);
3476
3525
  if (res.src)
3477
- bin.writeFile(pxtc.BINARY_ASM, res.src);
3526
+ bin.writeFile(pxtc.BINARY_ASM, `; srcmap size: ${encodedSrcMap.length << 1} bytes\n` + res.src);
3527
+ {
3528
+ let binstring = "";
3529
+ for (let v of res.buf)
3530
+ binstring += String.fromCharCode(v & 0xff, v >> 8);
3531
+ const hash = pxtc.U.sha256(binstring);
3532
+ for (let i = 0; i < 4; ++i) {
3533
+ res.buf[16 + i] = parseInt(hash.slice(i * 4, i * 4 + 4), 16);
3534
+ }
3535
+ srcmap["__meta"] = {
3536
+ name: opts.name,
3537
+ programHash: res.buf[16] | (res.buf[16 + 1] << 16),
3538
+ // TODO would be nice to include version number of editor...
3539
+ };
3540
+ }
3541
+ bin.writeFile(pxtc.BINARY_SRCMAP, JSON.stringify(srcmap));
3478
3542
  if (pxt.options.debug) {
3479
3543
  let pc = res.thumbFile.peepCounts;
3480
3544
  let keys = Object.keys(pc);
@@ -3485,12 +3549,16 @@ _start_${name}:
3485
3549
  }
3486
3550
  if (res.buf) {
3487
3551
  let binstring = "";
3488
- for (let v of res.buf)
3552
+ const buf = res.buf;
3553
+ while (buf.length & 0xf)
3554
+ buf.push(0);
3555
+ pxtc.U.pushRange(buf, encodedSrcMap);
3556
+ for (let v of buf)
3489
3557
  binstring += String.fromCharCode(v & 0xff, v >> 8);
3490
3558
  binstring = ts.pxtc.encodeBase64(binstring);
3491
3559
  if (embedVTs()) {
3492
3560
  bin.writeFile(pxtc.BINARY_PXT64, binstring);
3493
- const patched = pxtc.hexfile.patchHex(bin, res.buf, false, !!pxtc.target.useUF2)[0];
3561
+ const patched = pxtc.hexfile.patchHex(bin, buf, false, !!pxtc.target.useUF2)[0];
3494
3562
  bin.writeFile(pxt.outputName(pxtc.target), ts.pxtc.encodeBase64(patched));
3495
3563
  }
3496
3564
  else {
@@ -3521,7 +3589,7 @@ _start_${name}:
3521
3589
  emitAll();
3522
3590
  return resText;
3523
3591
  function emitAll() {
3524
- writeRaw(`;\n; Proc: ${proc.getFullName()}\n;`);
3592
+ writeRaw(`;\n; ${proc.getFullName()}\n;`);
3525
3593
  write(".section code");
3526
3594
  if (bin.procs[0] == proc) {
3527
3595
  writeRaw(`; main`);
@@ -8263,7 +8331,7 @@ var ts;
8263
8331
  let name = pxtc.getDeclName(this.action);
8264
8332
  if (this.action) {
8265
8333
  let info = ts.pxtc.nodeLocationInfo(this.action);
8266
- name += " " + info.fileName.replace("pxt_modules/", "") + ":" + (info.line + 1);
8334
+ name = info.fileName.replace("pxt_modules/", "") + "(" + (info.line + 1) + "," + (info.column + 1) + "): " + name;
8267
8335
  }
8268
8336
  return name;
8269
8337
  }
@@ -12206,7 +12274,7 @@ ${lbl}: .short 0xffff
12206
12274
  }
12207
12275
  function emitBrk(node) {
12208
12276
  bin.numStmts++;
12209
- const needsComment = pxtc.assembler.debug || pxtc.target.switches.size;
12277
+ const needsComment = pxtc.assembler.debug || pxtc.target.switches.size || pxtc.target.sourceMap;
12210
12278
  let needsBreak = !!opts.breakpoints;
12211
12279
  if (!needsComment && !needsBreak)
12212
12280
  return;
package/built/pxtlib.d.ts CHANGED
@@ -47,6 +47,7 @@ declare namespace pxt.auth {
47
47
  encoded?: string;
48
48
  dataUrl?: string;
49
49
  };
50
+ pictureUrl?: string;
50
51
  };
51
52
  };
52
53
  type UserSkillmapState = {
@@ -876,6 +877,7 @@ declare namespace pxt.commands {
876
877
  let electronDeployAsync: (r: ts.pxtc.CompileResult) => Promise<void>;
877
878
  let webUsbPairDialogAsync: (pairAsync: () => Promise<boolean>, confirmAsync: (options: any) => Promise<number>) => Promise<number>;
878
879
  let onTutorialCompleted: () => void;
880
+ let workspaceLoadedAsync: () => Promise<void>;
879
881
  }
880
882
  declare namespace pxt {
881
883
  function lzmaDecompressAsync(buf: Uint8Array): Promise<string>;
@@ -1925,6 +1927,7 @@ declare namespace ts.pxtc {
1925
1927
  const BINARY_ELF = "binary.elf";
1926
1928
  const BINARY_PXT64 = "binary.pxt64";
1927
1929
  const BINARY_ESP = "binary.bin";
1930
+ const BINARY_SRCMAP = "binary.srcmap";
1928
1931
  const NATIVE_TYPE_THUMB = "thumb";
1929
1932
  const NATIVE_TYPE_VM = "vm";
1930
1933
  interface BlocksInfo {
@@ -3377,6 +3380,7 @@ declare namespace ts.pxtc.assembler {
3377
3380
  buildLine(tx: string, lst: Line[]): void;
3378
3381
  private prepLines;
3379
3382
  private iterLines;
3383
+ getSourceMap(): pxt.Map<number[]>;
3380
3384
  getSource(clean: boolean, numStmts?: number, flashSize?: number): string;
3381
3385
  private peepHole;
3382
3386
  private clearLabels;
package/built/pxtlib.js CHANGED
@@ -190,6 +190,10 @@ var pxt;
190
190
  let _client;
191
191
  function client() { return _client; }
192
192
  auth.client = client;
193
+ const PREFERENCES_DEBOUNCE_MS = 5 * 1000;
194
+ const PREFERENCES_DEBOUNCE_MAX_MS = 30 * 1000;
195
+ let debouncePreferencesChangedTimeout = 0;
196
+ let debouncePreferencesChangedStarted = 0;
193
197
  class AuthClient {
194
198
  constructor() {
195
199
  this.initialUserPreferences_ = undefined;
@@ -395,15 +399,28 @@ var pxt;
395
399
  if (!await this.loggedInAsync()) {
396
400
  return;
397
401
  }
398
- // If the user is logged in, save to cloud
399
- const result = await this.apiAsync('/api/user/preferences', ops, 'PATCH');
400
- if (result.success) {
401
- pxt.debug("Updating local user preferences w/ cloud data after result of POST");
402
- // Set user profile from returned value so we stay in-sync
403
- this.setUserPreferencesAsync(result.resp);
402
+ // If the user is logged in, save to cloud, but debounce the api call as this can be called frequently from skillmaps
403
+ clearTimeout(debouncePreferencesChangedTimeout);
404
+ const savePrefs = async () => {
405
+ debouncePreferencesChangedStarted = 0;
406
+ const result = await this.apiAsync('/api/user/preferences', ops, 'PATCH');
407
+ if (result.success) {
408
+ pxt.debug("Updating local user preferences w/ cloud data after result of POST");
409
+ // Set user profile from returned value so we stay in-sync
410
+ this.setUserPreferencesAsync(result.resp);
411
+ }
412
+ else {
413
+ pxt.reportError("identity", "update preferences failed", result);
414
+ }
415
+ };
416
+ if (!debouncePreferencesChangedStarted) {
417
+ debouncePreferencesChangedStarted = pxt.U.now();
418
+ }
419
+ if (PREFERENCES_DEBOUNCE_MAX_MS < pxt.U.now() - debouncePreferencesChangedStarted) {
420
+ await savePrefs();
404
421
  }
405
422
  else {
406
- pxt.reportError("identity", "update preferences failed", result);
423
+ debouncePreferencesChangedTimeout = setTimeout(savePrefs, PREFERENCES_DEBOUNCE_MS);
407
424
  }
408
425
  }
409
426
  /*protected*/ hasUserId() {
@@ -3366,6 +3383,8 @@ var pxt;
3366
3383
  }
3367
3384
  if (!comp.switches)
3368
3385
  comp.switches = {};
3386
+ if (comp.nativeType == pxtc.NATIVE_TYPE_VM)
3387
+ comp.sourceMap = true;
3369
3388
  pxt.U.jsonCopyFrom(comp.switches, savedSwitches);
3370
3389
  // JS ref counting currently not supported
3371
3390
  comp.jsRefCounting = false;
@@ -5713,6 +5732,7 @@ var pxt;
5713
5732
  commands.electronDeployAsync = undefined; // A pointer to the Electron deploy function, so that targets can access it in their extension.ts
5714
5733
  commands.webUsbPairDialogAsync = undefined;
5715
5734
  commands.onTutorialCompleted = undefined;
5735
+ commands.workspaceLoadedAsync = undefined;
5716
5736
  })(commands = pxt.commands || (pxt.commands = {}));
5717
5737
  })(pxt || (pxt = {}));
5718
5738
  /// <reference path="../localtypings/pxtarget.d.ts"/>
@@ -6959,7 +6979,7 @@ int main() {
6959
6979
  .then(ret => new Promise((resolve, reject) => {
6960
6980
  let retry = 0;
6961
6981
  const delay = 8000; // ms
6962
- const maxWait = 180000; // ms
6982
+ const maxWait = 300000; // ms
6963
6983
  const startTry = pxt.U.now();
6964
6984
  const tryGet = () => {
6965
6985
  retry++;
@@ -15159,6 +15179,7 @@ var ts;
15159
15179
  pxtc.BINARY_ELF = "binary.elf";
15160
15180
  pxtc.BINARY_PXT64 = "binary.pxt64";
15161
15181
  pxtc.BINARY_ESP = "binary.bin";
15182
+ pxtc.BINARY_SRCMAP = "binary.srcmap";
15162
15183
  pxtc.NATIVE_TYPE_THUMB = "thumb";
15163
15184
  pxtc.NATIVE_TYPE_VM = "vm";
15164
15185
  function BuildSourceMapHelpers(sourceMap, tsFile, pyFile) {
@@ -21023,7 +21044,6 @@ var pxt;
21023
21044
  youtube.watchUrl = watchUrl;
21024
21045
  })(youtube = pxt.youtube || (pxt.youtube = {}));
21025
21046
  })(pxt || (pxt = {}));
21026
- /* eslint-disable no-cond-assign */
21027
21047
  // TODO: add a macro facility to make 8-bit assembly easier?
21028
21048
  var ts;
21029
21049
  (function (ts) {
@@ -21281,7 +21301,7 @@ var ts;
21281
21301
  // recursive-descent parsing of multiplication
21282
21302
  if (s.indexOf("*") >= 0) {
21283
21303
  let m = null;
21284
- while (m = /^([^\*]*)\*(.*)$/.exec(s)) {
21304
+ while (null != (m = /^([^\*]*)\*(.*)$/.exec(s))) {
21285
21305
  let tmp = this.parseOneInt(m[1]);
21286
21306
  if (tmp == null)
21287
21307
  return null;
@@ -21896,6 +21916,37 @@ var ts;
21896
21916
  }
21897
21917
  });
21898
21918
  }
21919
+ getSourceMap() {
21920
+ const sourceMap = {};
21921
+ let locFile = "";
21922
+ let locLn = 0;
21923
+ let locPos = 0;
21924
+ let locEnd = 0;
21925
+ this.lines.forEach((ln, i) => {
21926
+ const m = /^; ([\w\/\.-]+)\(([\d]+),\d+\):/.exec(ln.text);
21927
+ if (m) {
21928
+ flush();
21929
+ locFile = m[1];
21930
+ locLn = parseInt(m[2]);
21931
+ }
21932
+ if (ln.type == "instruction") {
21933
+ if (!locPos)
21934
+ locPos = ln.location;
21935
+ locEnd = ln.location;
21936
+ }
21937
+ });
21938
+ flush();
21939
+ function flush() {
21940
+ if (locFile && locPos) {
21941
+ if (!sourceMap[locFile])
21942
+ sourceMap[locFile] = [];
21943
+ sourceMap[locFile].push(locLn, locPos, locEnd - locPos);
21944
+ }
21945
+ locPos = 0;
21946
+ locEnd = 0;
21947
+ }
21948
+ return sourceMap;
21949
+ }
21899
21950
  getSource(clean, numStmts = 1, flashSize = 0) {
21900
21951
  let lenPrev = 0;
21901
21952
  let size = (lbl) => {