pxt-core 7.3.4 → 7.3.8

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")
@@ -1751,7 +1768,9 @@ function buildSemanticUIAsync(parsed) {
1751
1768
  // Append icons.css to semantic.css (custom pxt icons)
1752
1769
  const iconsFile = (pkg["name"] == "pxt-core") ? 'built/web/icons.css' : 'node_modules/pxt-core/built/web/icons.css';
1753
1770
  const iconsCss = fs.readFileSync(iconsFile, "utf-8");
1754
- semCss = semCss + "\n" + iconsCss;
1771
+ const reactCommonFile = (pkg["name"] == "pxt-core") ? 'built/web/react-common.css' : 'node_modules/pxt-core/built/web/react-common.css';
1772
+ const reactCommonCss = fs.readFileSync(reactCommonFile, "utf-8");
1773
+ semCss = semCss + "\n" + iconsCss + "\n" + reactCommonCss;
1755
1774
  nodeutil.writeFileSync('built/web/semantic.css', semCss);
1756
1775
  }).then(() => {
1757
1776
  // generate blockly css
@@ -1819,6 +1838,7 @@ function buildSkillMapAsync(parsed) {
1819
1838
  nodeutil.cp("node_modules/pxt-core/built/pxtlib.js", `${skillmapRoot}/public/blb`);
1820
1839
  nodeutil.cp("built/web/semantic.css", `${skillmapRoot}/public/blb`);
1821
1840
  nodeutil.cp("node_modules/pxt-core/built/web/icons.css", `${skillmapRoot}/public/blb`);
1841
+ nodeutil.cp("node_modules/pxt-core/built/web/react-common.css", `${skillmapRoot}/public/blb`);
1822
1842
  // copy 'assets' over from docs/static
1823
1843
  nodeutil.cpR("docs/static/skillmap/assets", `${skillmapRoot}/public/assets`);
1824
1844
  if (docsPath) {
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() {
@@ -98339,6 +98356,17 @@ var pxt;
98339
98356
  }
98340
98357
  }
98341
98358
  auth.generateUserProfilePicDataUrl = generateUserProfilePicDataUrl;
98359
+ /**
98360
+ * Checks only the ID and sourceURL
98361
+ */
98362
+ function badgeEquals(badgeA, badgeB) {
98363
+ return badgeA.id === badgeB.id && badgeA.sourceURL === badgeB.sourceURL;
98364
+ }
98365
+ auth.badgeEquals = badgeEquals;
98366
+ function hasBadge(preferences, badge) {
98367
+ return preferences.badges.some(toCheck => badgeEquals(toCheck, badge));
98368
+ }
98369
+ auth.hasBadge = hasBadge;
98342
98370
  })(auth = pxt.auth || (pxt.auth = {}));
98343
98371
  })(pxt || (pxt = {}));
98344
98372
  // Needs to be in its own file to avoid a circular dependency: util.ts -> main.ts -> util.ts
@@ -101052,6 +101080,8 @@ var pxt;
101052
101080
  }
101053
101081
  if (!comp.switches)
101054
101082
  comp.switches = {};
101083
+ if (comp.nativeType == pxtc.NATIVE_TYPE_VM)
101084
+ comp.sourceMap = true;
101055
101085
  pxt.U.jsonCopyFrom(comp.switches, savedSwitches);
101056
101086
  // JS ref counting currently not supported
101057
101087
  comp.jsRefCounting = false;
@@ -104646,7 +104676,7 @@ int main() {
104646
104676
  .then(ret => new Promise((resolve, reject) => {
104647
104677
  let retry = 0;
104648
104678
  const delay = 8000; // ms
104649
- const maxWait = 180000; // ms
104679
+ const maxWait = 300000; // ms
104650
104680
  const startTry = pxt.U.now();
104651
104681
  const tryGet = () => {
104652
104682
  retry++;
@@ -112846,6 +112876,7 @@ var ts;
112846
112876
  pxtc.BINARY_ELF = "binary.elf";
112847
112877
  pxtc.BINARY_PXT64 = "binary.pxt64";
112848
112878
  pxtc.BINARY_ESP = "binary.bin";
112879
+ pxtc.BINARY_SRCMAP = "binary.srcmap";
112849
112880
  pxtc.NATIVE_TYPE_THUMB = "thumb";
112850
112881
  pxtc.NATIVE_TYPE_VM = "vm";
112851
112882
  function BuildSourceMapHelpers(sourceMap, tsFile, pyFile) {
@@ -118710,7 +118741,6 @@ var pxt;
118710
118741
  youtube.watchUrl = watchUrl;
118711
118742
  })(youtube = pxt.youtube || (pxt.youtube = {}));
118712
118743
  })(pxt || (pxt = {}));
118713
- /* eslint-disable no-cond-assign */
118714
118744
  // TODO: add a macro facility to make 8-bit assembly easier?
118715
118745
  var ts;
118716
118746
  (function (ts) {
@@ -118968,7 +118998,7 @@ var ts;
118968
118998
  // recursive-descent parsing of multiplication
118969
118999
  if (s.indexOf("*") >= 0) {
118970
119000
  let m = null;
118971
- while (m = /^([^\*]*)\*(.*)$/.exec(s)) {
119001
+ while (null != (m = /^([^\*]*)\*(.*)$/.exec(s))) {
118972
119002
  let tmp = this.parseOneInt(m[1]);
118973
119003
  if (tmp == null)
118974
119004
  return null;
@@ -119583,6 +119613,37 @@ var ts;
119583
119613
  }
119584
119614
  });
119585
119615
  }
119616
+ getSourceMap() {
119617
+ const sourceMap = {};
119618
+ let locFile = "";
119619
+ let locLn = 0;
119620
+ let locPos = 0;
119621
+ let locEnd = 0;
119622
+ this.lines.forEach((ln, i) => {
119623
+ const m = /^; ([\w\/\.-]+)\(([\d]+),\d+\):/.exec(ln.text);
119624
+ if (m) {
119625
+ flush();
119626
+ locFile = m[1];
119627
+ locLn = parseInt(m[2]);
119628
+ }
119629
+ if (ln.type == "instruction") {
119630
+ if (!locPos)
119631
+ locPos = ln.location;
119632
+ locEnd = ln.location;
119633
+ }
119634
+ });
119635
+ flush();
119636
+ function flush() {
119637
+ if (locFile && locPos) {
119638
+ if (!sourceMap[locFile])
119639
+ sourceMap[locFile] = [];
119640
+ sourceMap[locFile].push(locLn, locPos, locEnd - locPos);
119641
+ }
119642
+ locPos = 0;
119643
+ locEnd = 0;
119644
+ }
119645
+ return sourceMap;
119646
+ }
119586
119647
  getSource(clean, numStmts = 1, flashSize = 0) {
119587
119648
  let lenPrev = 0;
119588
119649
  let size = (lbl) => {
@@ -124093,6 +124154,53 @@ ${info.id}_IfaceVT:
124093
124154
  else
124094
124155
  return `0xffffffff, 0xffffffff ; -> ${vt}`;
124095
124156
  }
124157
+ function encodeSourceMap(srcmap) {
124158
+ // magic: 0x4d435253 0x2d4e1588 0x719986aa ('SRCM' ... )
124159
+ const res = [0x53, 0x52, 0x43, 0x4d, 0x88, 0x15, 0x4e, 0x2d, 0xaa, 0x86, 0x99, 0x71, 0x00, 0x00, 0x00, 0x00];
124160
+ for (const fn of Object.keys(srcmap)) {
124161
+ for (const c of pxtc.U.stringToUint8Array(fn))
124162
+ res.push(c);
124163
+ res.push(0);
124164
+ const arr = srcmap[fn];
124165
+ let prevLn = 0;
124166
+ let prevOff = 0;
124167
+ for (let i = 0; i < arr.length; i += 3) {
124168
+ encodeNumber(arr[i] - prevLn);
124169
+ encodeNumber((arr[i + 1] - prevOff) >> 1);
124170
+ encodeNumber(arr[i + 2] >> 1);
124171
+ prevLn = arr[i];
124172
+ prevOff = arr[i + 1];
124173
+ }
124174
+ res.push(0xff); // end-marker
124175
+ }
124176
+ res.push(0);
124177
+ if (res.length & 1)
124178
+ res.push(0);
124179
+ const res2 = [];
124180
+ for (let i = 0; i < res.length; i += 2)
124181
+ res2.push(res[i] | (res[i + 1] << 8));
124182
+ return res2;
124183
+ function encodeNumber(k) {
124184
+ if (0 <= k && k < 0xf0)
124185
+ res.push(k);
124186
+ else {
124187
+ let mark = 0xf0;
124188
+ if (k < 0) {
124189
+ k = -k;
124190
+ mark |= 0x08;
124191
+ }
124192
+ const idx = res.length;
124193
+ res.push(null); // placeholder
124194
+ let len = 0;
124195
+ while (k != 0) {
124196
+ res.push(k & 0xff);
124197
+ k >>>= 8;
124198
+ len++;
124199
+ }
124200
+ res[idx] = mark | len;
124201
+ }
124202
+ }
124203
+ }
124096
124204
  /* eslint-disable no-trailing-spaces */
124097
124205
  function vmEmit(bin, opts) {
124098
124206
  let vmsource = `; VM start
@@ -124130,7 +124238,7 @@ _start_${name}:
124130
124238
  vmsource += `\n.balign 8\n_end_${name}:\n`;
124131
124239
  address++;
124132
124240
  }
124133
- const now = new Date();
124241
+ const now = new Date(0); // new Date()
124134
124242
  let encodedName = pxtc.U.toUTF8(opts.name, true);
124135
124243
  if (encodedName.length > 100)
124136
124244
  encodedName = encodedName.slice(0, 100);
@@ -124216,8 +124324,25 @@ _start_${name}:
124216
124324
  vmsource += "\n; The end.\n";
124217
124325
  bin.writeFile(pxtc.BINARY_ASM, vmsource);
124218
124326
  let res = pxtc.assemble(opts.target, bin, vmsource);
124327
+ const srcmap = res.thumbFile.getSourceMap();
124328
+ const encodedSrcMap = encodeSourceMap(srcmap);
124219
124329
  if (res.src)
124220
- bin.writeFile(pxtc.BINARY_ASM, res.src);
124330
+ bin.writeFile(pxtc.BINARY_ASM, `; srcmap size: ${encodedSrcMap.length << 1} bytes\n` + res.src);
124331
+ {
124332
+ let binstring = "";
124333
+ for (let v of res.buf)
124334
+ binstring += String.fromCharCode(v & 0xff, v >> 8);
124335
+ const hash = pxtc.U.sha256(binstring);
124336
+ for (let i = 0; i < 4; ++i) {
124337
+ res.buf[16 + i] = parseInt(hash.slice(i * 4, i * 4 + 4), 16);
124338
+ }
124339
+ srcmap["__meta"] = {
124340
+ name: opts.name,
124341
+ programHash: res.buf[16] | (res.buf[16 + 1] << 16),
124342
+ // TODO would be nice to include version number of editor...
124343
+ };
124344
+ }
124345
+ bin.writeFile(pxtc.BINARY_SRCMAP, JSON.stringify(srcmap));
124221
124346
  if (pxt.options.debug) {
124222
124347
  let pc = res.thumbFile.peepCounts;
124223
124348
  let keys = Object.keys(pc);
@@ -124228,12 +124353,16 @@ _start_${name}:
124228
124353
  }
124229
124354
  if (res.buf) {
124230
124355
  let binstring = "";
124231
- for (let v of res.buf)
124356
+ const buf = res.buf;
124357
+ while (buf.length & 0xf)
124358
+ buf.push(0);
124359
+ pxtc.U.pushRange(buf, encodedSrcMap);
124360
+ for (let v of buf)
124232
124361
  binstring += String.fromCharCode(v & 0xff, v >> 8);
124233
124362
  binstring = ts.pxtc.encodeBase64(binstring);
124234
124363
  if (embedVTs()) {
124235
124364
  bin.writeFile(pxtc.BINARY_PXT64, binstring);
124236
- const patched = pxtc.hexfile.patchHex(bin, res.buf, false, !!pxtc.target.useUF2)[0];
124365
+ const patched = pxtc.hexfile.patchHex(bin, buf, false, !!pxtc.target.useUF2)[0];
124237
124366
  bin.writeFile(pxt.outputName(pxtc.target), ts.pxtc.encodeBase64(patched));
124238
124367
  }
124239
124368
  else {
@@ -124264,7 +124393,7 @@ _start_${name}:
124264
124393
  emitAll();
124265
124394
  return resText;
124266
124395
  function emitAll() {
124267
- writeRaw(`;\n; Proc: ${proc.getFullName()}\n;`);
124396
+ writeRaw(`;\n; ${proc.getFullName()}\n;`);
124268
124397
  write(".section code");
124269
124398
  if (bin.procs[0] == proc) {
124270
124399
  writeRaw(`; main`);
@@ -129006,7 +129135,7 @@ var ts;
129006
129135
  let name = pxtc.getDeclName(this.action);
129007
129136
  if (this.action) {
129008
129137
  let info = ts.pxtc.nodeLocationInfo(this.action);
129009
- name += " " + info.fileName.replace("pxt_modules/", "") + ":" + (info.line + 1);
129138
+ name = info.fileName.replace("pxt_modules/", "") + "(" + (info.line + 1) + "," + (info.column + 1) + "): " + name;
129010
129139
  }
129011
129140
  return name;
129012
129141
  }
@@ -132949,7 +133078,7 @@ ${lbl}: .short 0xffff
132949
133078
  }
132950
133079
  function emitBrk(node) {
132951
133080
  bin.numStmts++;
132952
- const needsComment = pxtc.assembler.debug || pxtc.target.switches.size;
133081
+ const needsComment = pxtc.assembler.debug || pxtc.target.switches.size || pxtc.target.sourceMap;
132953
133082
  let needsBreak = !!opts.breakpoints;
132954
133083
  if (!needsComment && !needsBreak)
132955
133084
  return;
@@ -156154,6 +156283,8 @@ function ciAsync() {
156154
156283
  pxt.log(`pull request: ${pullRequest}`);
156155
156284
  pxt.log(`upload api strings: ${uploadApiStrings}`);
156156
156285
  pxt.log(`upload docs: ${uploadDocs}`);
156286
+ lintJSONInDirectory(path.resolve("."));
156287
+ lintJSONInDirectory(path.resolve("docs"));
156157
156288
  function npmPublishAsync() {
156158
156289
  if (!npmPublish)
156159
156290
  return Promise.resolve();
@@ -156210,6 +156341,21 @@ function ciAsync() {
156210
156341
  });
156211
156342
  }
156212
156343
  }
156344
+ function lintJSONInDirectory(dir) {
156345
+ for (const file of fs.readdirSync(dir)) {
156346
+ const fullPath = path.join(dir, file);
156347
+ if (file.endsWith(".json")) {
156348
+ const contents = fs.readFileSync(fullPath, "utf8");
156349
+ try {
156350
+ JSON.parse(contents);
156351
+ }
156352
+ catch (e) {
156353
+ console.log("Could not parse " + fullPath);
156354
+ process.exit(1);
156355
+ }
156356
+ }
156357
+ }
156358
+ }
156213
156359
  function bumpPxtCoreDepAsync() {
156214
156360
  let pkg = readJson("package.json");
156215
156361
  if (pkg["name"] == "pxt-core")
@@ -157502,7 +157648,9 @@ function buildSemanticUIAsync(parsed) {
157502
157648
  // Append icons.css to semantic.css (custom pxt icons)
157503
157649
  const iconsFile = (pkg["name"] == "pxt-core") ? 'built/web/icons.css' : 'node_modules/pxt-core/built/web/icons.css';
157504
157650
  const iconsCss = fs.readFileSync(iconsFile, "utf-8");
157505
- semCss = semCss + "\n" + iconsCss;
157651
+ const reactCommonFile = (pkg["name"] == "pxt-core") ? 'built/web/react-common.css' : 'node_modules/pxt-core/built/web/react-common.css';
157652
+ const reactCommonCss = fs.readFileSync(reactCommonFile, "utf-8");
157653
+ semCss = semCss + "\n" + iconsCss + "\n" + reactCommonCss;
157506
157654
  nodeutil.writeFileSync('built/web/semantic.css', semCss);
157507
157655
  }).then(() => {
157508
157656
  // generate blockly css
@@ -157570,6 +157718,7 @@ function buildSkillMapAsync(parsed) {
157570
157718
  nodeutil.cp("node_modules/pxt-core/built/pxtlib.js", `${skillmapRoot}/public/blb`);
157571
157719
  nodeutil.cp("built/web/semantic.css", `${skillmapRoot}/public/blb`);
157572
157720
  nodeutil.cp("node_modules/pxt-core/built/web/icons.css", `${skillmapRoot}/public/blb`);
157721
+ nodeutil.cp("node_modules/pxt-core/built/web/react-common.css", `${skillmapRoot}/public/blb`);
157573
157722
  // copy 'assets' over from docs/static
157574
157723
  nodeutil.cpR("docs/static/skillmap/assets", `${skillmapRoot}/public/assets`);
157575
157724
  if (docsPath) {
@@ -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,12 +47,16 @@ 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 = {
53
54
  mapProgress: any;
54
55
  completedTags: any;
55
56
  };
57
+ type UserBadgeState = {
58
+ badges: Badge[];
59
+ };
56
60
  /**
57
61
  * User preference state that should be synced with the cloud.
58
62
  */
@@ -61,6 +65,7 @@ declare namespace pxt.auth {
61
65
  highContrast?: boolean;
62
66
  reader?: string;
63
67
  skillmap?: UserSkillmapState;
68
+ badges?: UserBadgeState;
64
69
  };
65
70
  const DEFAULT_USER_PREFERENCES: () => UserPreferences;
66
71
  /**
@@ -164,6 +169,11 @@ declare namespace pxt.auth {
164
169
  function userName(user: pxt.auth.UserProfile): string;
165
170
  function userInitials(user: pxt.auth.UserProfile): string;
166
171
  function generateUserProfilePicDataUrl(profile: pxt.auth.UserProfile): void;
172
+ /**
173
+ * Checks only the ID and sourceURL
174
+ */
175
+ function badgeEquals(badgeA: pxt.auth.Badge, badgeB: pxt.auth.Badge): boolean;
176
+ function hasBadge(preferences: pxt.auth.UserBadgeState, badge: pxt.auth.Badge): boolean;
167
177
  }
168
178
  declare namespace pxt {
169
179
  interface TelemetryEventOptions {
@@ -1926,6 +1936,7 @@ declare namespace ts.pxtc {
1926
1936
  const BINARY_ELF = "binary.elf";
1927
1937
  const BINARY_PXT64 = "binary.pxt64";
1928
1938
  const BINARY_ESP = "binary.bin";
1939
+ const BINARY_SRCMAP = "binary.srcmap";
1929
1940
  const NATIVE_TYPE_THUMB = "thumb";
1930
1941
  const NATIVE_TYPE_VM = "vm";
1931
1942
  interface BlocksInfo {
@@ -3378,6 +3389,7 @@ declare namespace ts.pxtc.assembler {
3378
3389
  buildLine(tx: string, lst: Line[]): void;
3379
3390
  private prepLines;
3380
3391
  private iterLines;
3392
+ getSourceMap(): pxt.Map<number[]>;
3381
3393
  getSource(clean: boolean, numStmts?: number, flashSize?: number): string;
3382
3394
  private peepHole;
3383
3395
  private clearLabels;