pxt-core 13.1.5 → 13.1.6

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.
@@ -131,6 +131,7 @@ declare namespace pxt.docs {
131
131
  parse?: (src: string, options?: any) => string;
132
132
  }
133
133
  export function htmlQuote(s: string): string;
134
+ export function normalizeStaticMarkdown(markdown: string): string;
134
135
  export function html2Quote(s: string): string;
135
136
  export interface BreadcrumbEntry {
136
137
  name: string;
@@ -509,6 +509,35 @@ var pxt;
509
509
  return s;
510
510
  }
511
511
  docs.htmlQuote = htmlQuote;
512
+ function normalizeStaticMarkdown(markdown) {
513
+ const lines = markdown.split(/\r?\n/);
514
+ let codeFenceMarker = "";
515
+ for (let i = 0; i < lines.length; i++) {
516
+ const fenceMatch = /^ {0,3}(`{3,}|~{3,})(.*)$/.exec(lines[i]);
517
+ if (fenceMatch) {
518
+ const marker = fenceMatch[1];
519
+ const trailingText = fenceMatch[2];
520
+ const closesCodeFence = !!codeFenceMarker
521
+ && marker[0] === codeFenceMarker[0]
522
+ && marker.length >= codeFenceMarker.length
523
+ && !trailingText.trim();
524
+ if (closesCodeFence) {
525
+ codeFenceMarker = "";
526
+ }
527
+ else if (!codeFenceMarker) {
528
+ codeFenceMarker = marker;
529
+ }
530
+ continue;
531
+ }
532
+ if (!codeFenceMarker && /^ {0,3}<br\s*\/?>\s*$/i.test(lines[i])) {
533
+ // Marked treats a standalone break as inline content, which can extend a
534
+ // preceding table or keep the following Markdown in the same paragraph.
535
+ lines[i] = "\n<p><br/></p>\n";
536
+ }
537
+ }
538
+ return lines.join("\n");
539
+ }
540
+ docs.normalizeStaticMarkdown = normalizeStaticMarkdown;
512
541
  // the input already should be HTML-quoted but we want to make sure, and also quote quotes
513
542
  function html2Quote(s) {
514
543
  if (!s)
@@ -1023,7 +1052,7 @@ ${opts.repo.name.replace(/^pxt-/, '')}=github:${opts.repo.fullName}#${opts.repo.
1023
1052
  \`\`\`
1024
1053
  `;
1025
1054
  //Uses the CmdLink definitions to replace links to YouTube and Vimeo (limited at the moment)
1026
- markdown = markdown.replace(/^\s*https?:\/\/(\S+)\s*$/mg, (f, lnk) => {
1055
+ markdown = markdown.replace(/^[ \t]*https?:\/\/(\S+)[ \t]*\r?$/mg, (f, lnk) => {
1027
1056
  for (let ent of links) {
1028
1057
  let m = ent.rx.exec(lnk);
1029
1058
  if (m) {
package/built/cli.js CHANGED
@@ -41,7 +41,7 @@ pxt.docs.requireDOMSanitizer = () => {
41
41
  const existing = baseAllowedAttrs[tag] || [];
42
42
  return Array.from(new Set([...existing, "class", ...otherAttributes]));
43
43
  };
44
- const options = Object.assign(Object.assign({}, defaults), { allowedTags: [...allowedTags, "img"], allowedAttributes: Object.assign(Object.assign({}, baseAllowedAttrs), { code: mergeClassAttribute("code"), pre: mergeClassAttribute("pre"), div: mergeClassAttribute("div", "data-youtube", "title") }) });
44
+ const options = Object.assign(Object.assign({}, defaults), { allowedTags: [...allowedTags, "img"], allowedAttributes: Object.assign(Object.assign({}, baseAllowedAttrs), { code: mergeClassAttribute("code"), pre: mergeClassAttribute("pre"), div: mergeClassAttribute("div", "data-youtube", "title"), img: mergeClassAttribute("img") }) });
45
45
  return (html) => sanitizeHtml(html, options);
46
46
  };
47
47
  let forceCloudBuild = process.env["KS_FORCE_CLOUD"] !== "no";
@@ -2690,7 +2690,7 @@ function renderDocs(builtPackaged, localDir) {
2690
2690
  nodeutil.writeFileSync(outputFile, patchedMd, { encoding: "utf8" });
2691
2691
  html = pxt.docs.renderMarkdown({
2692
2692
  template: docsTemplate,
2693
- markdown: patchedMd,
2693
+ markdown: pxt.docs.normalizeStaticMarkdown(patchedMd),
2694
2694
  theme: pxt.appTarget.appTheme,
2695
2695
  filepath: path.join("docs", pathUnderDocs),
2696
2696
  });
package/built/pxt.js CHANGED
@@ -106143,6 +106143,9 @@ var pxt;
106143
106143
  diff_1.compute = compute;
106144
106144
  function computeFormattedDiff(fileA, fileB, options = {}) {
106145
106145
  const diff = compute(fileA, fileB, options);
106146
+ if (!diff) {
106147
+ return null;
106148
+ }
106146
106149
  if (options.context == Infinity || options.full) {
106147
106150
  return diff.map(formatEdit);
106148
106151
  }
@@ -106820,6 +106823,35 @@ var pxt;
106820
106823
  return s;
106821
106824
  }
106822
106825
  docs.htmlQuote = htmlQuote;
106826
+ function normalizeStaticMarkdown(markdown) {
106827
+ const lines = markdown.split(/\r?\n/);
106828
+ let codeFenceMarker = "";
106829
+ for (let i = 0; i < lines.length; i++) {
106830
+ const fenceMatch = /^ {0,3}(`{3,}|~{3,})(.*)$/.exec(lines[i]);
106831
+ if (fenceMatch) {
106832
+ const marker = fenceMatch[1];
106833
+ const trailingText = fenceMatch[2];
106834
+ const closesCodeFence = !!codeFenceMarker
106835
+ && marker[0] === codeFenceMarker[0]
106836
+ && marker.length >= codeFenceMarker.length
106837
+ && !trailingText.trim();
106838
+ if (closesCodeFence) {
106839
+ codeFenceMarker = "";
106840
+ }
106841
+ else if (!codeFenceMarker) {
106842
+ codeFenceMarker = marker;
106843
+ }
106844
+ continue;
106845
+ }
106846
+ if (!codeFenceMarker && /^ {0,3}<br\s*\/?>\s*$/i.test(lines[i])) {
106847
+ // Marked treats a standalone break as inline content, which can extend a
106848
+ // preceding table or keep the following Markdown in the same paragraph.
106849
+ lines[i] = "\n<p><br/></p>\n";
106850
+ }
106851
+ }
106852
+ return lines.join("\n");
106853
+ }
106854
+ docs.normalizeStaticMarkdown = normalizeStaticMarkdown;
106823
106855
  // the input already should be HTML-quoted but we want to make sure, and also quote quotes
106824
106856
  function html2Quote(s) {
106825
106857
  if (!s)
@@ -107334,7 +107366,7 @@ ${opts.repo.name.replace(/^pxt-/, '')}=github:${opts.repo.fullName}#${opts.repo.
107334
107366
  \`\`\`
107335
107367
  `;
107336
107368
  //Uses the CmdLink definitions to replace links to YouTube and Vimeo (limited at the moment)
107337
- markdown = markdown.replace(/^\s*https?:\/\/(\S+)\s*$/mg, (f, lnk) => {
107369
+ markdown = markdown.replace(/^[ \t]*https?:\/\/(\S+)[ \t]*\r?$/mg, (f, lnk) => {
107338
107370
  for (let ent of links) {
107339
107371
  let m = ent.rx.exec(lnk);
107340
107372
  if (m) {
@@ -118852,7 +118884,7 @@ var pxt;
118852
118884
  this.needsRebuild = true;
118853
118885
  }
118854
118886
  }
118855
- pushUndo() {
118887
+ pushUndo(protectedAssetId) {
118856
118888
  if (this.undoStack.length && this.committedState.revision === this.state.revision)
118857
118889
  return;
118858
118890
  this.redoStack = [];
@@ -118866,7 +118898,7 @@ var pxt;
118866
118898
  entry.assetDiffs[type] = this.state.assets[type].diff(this.committedState.assets[type]);
118867
118899
  }
118868
118900
  this.committedState = this.cloneState();
118869
- this.cleanupTemporaryAssets();
118901
+ this.cleanupTemporaryAssets(protectedAssetId);
118870
118902
  }
118871
118903
  revision() {
118872
118904
  return this.state.revision;
@@ -119448,9 +119480,9 @@ var pxt;
119448
119480
  }
119449
119481
  return assets;
119450
119482
  }
119451
- cleanupTemporaryAssets() {
119483
+ cleanupTemporaryAssets(protectedAssetId) {
119452
119484
  const images = this.getAssetCollection("image" /* AssetType.Image */);
119453
- const orphaned = images.getSnapshot(image => { var _a; return !image.meta.displayName && !((_a = image.meta.blockIDs) === null || _a === void 0 ? void 0 : _a.length); });
119485
+ const orphaned = images.getSnapshot(image => { var _a; return image.id !== protectedAssetId && !image.meta.displayName && !((_a = image.meta.blockIDs) === null || _a === void 0 ? void 0 : _a.length); });
119454
119486
  for (const image of orphaned) {
119455
119487
  images.removeByID(image.id);
119456
119488
  }
@@ -119735,22 +119767,22 @@ var pxt;
119735
119767
  return new pxt.sprite.TilemapData(tilemap, tileset, layers);
119736
119768
  }
119737
119769
  function cloneAsset(asset, includeEditorData = false) {
119738
- asset.meta = Object.assign({}, asset.meta);
119739
- if (asset.meta.temporaryInfo) {
119740
- asset.meta.temporaryInfo = Object.assign({}, asset.meta.temporaryInfo);
119770
+ const meta = Object.assign({}, asset.meta);
119771
+ if (meta.temporaryInfo) {
119772
+ meta.temporaryInfo = Object.assign({}, meta.temporaryInfo);
119741
119773
  }
119742
119774
  switch (asset.type) {
119743
119775
  case "tile" /* AssetType.Tile */:
119744
119776
  case "image" /* AssetType.Image */:
119745
- return Object.assign(Object.assign({}, asset), { bitmap: cloneBitmap(asset.bitmap) });
119777
+ return Object.assign(Object.assign({}, asset), { meta, bitmap: cloneBitmap(asset.bitmap) });
119746
119778
  case "animation" /* AssetType.Animation */:
119747
- return Object.assign(Object.assign({}, asset), { frames: asset.frames.map(frame => cloneBitmap(frame)) });
119779
+ return Object.assign(Object.assign({}, asset), { meta, frames: asset.frames.map(frame => cloneBitmap(frame)) });
119748
119780
  case "tilemap" /* AssetType.Tilemap */:
119749
- return Object.assign(Object.assign({}, asset), { data: asset.data.cloneData(includeEditorData) });
119781
+ return Object.assign(Object.assign({}, asset), { meta, data: asset.data.cloneData(includeEditorData) });
119750
119782
  case "song" /* AssetType.Song */:
119751
- return Object.assign(Object.assign({}, asset), { song: pxt.assets.music.cloneSong(asset.song) });
119783
+ return Object.assign(Object.assign({}, asset), { meta, song: pxt.assets.music.cloneSong(asset.song) });
119752
119784
  case "json" /* AssetType.Json */:
119753
- return Object.assign(Object.assign({}, asset), { data: pxt.U.clone(asset.data) });
119785
+ return Object.assign(Object.assign({}, asset), { meta, data: pxt.U.clone(asset.data) });
119754
119786
  }
119755
119787
  }
119756
119788
  pxt.cloneAsset = cloneAsset;
@@ -150526,7 +150558,11 @@ var pxt;
150526
150558
  else {
150527
150559
  let [exp, sup] = emitExp(s.body);
150528
150560
  stmts = stmts.concat(sup);
150529
- stmts.concat(exp);
150561
+ stmts = stmts.concat(exp);
150562
+ const retType = tc.getTypeAtLocation(s.body);
150563
+ if (retType && !hasTypeFlag(retType, ts.TypeFlags.Void)) {
150564
+ stmts = expWrap("return ", stmts);
150565
+ }
150530
150566
  }
150531
150567
  if (stmts.length) {
150532
150568
  // global or nonlocal declerations
@@ -157907,8 +157943,6 @@ var pxsim;
157907
157943
  this._runOptions = {};
157908
157944
  this.state = SimulatorState.Unloaded;
157909
157945
  this._allowedOrigins = [];
157910
- // BEGIN TEMPORARY: jacdac simulator
157911
- this.newJacdacSimulator = false;
157912
157946
  this.frameCleanupTimeout = undefined;
157913
157947
  this.debuggerSeq = 1;
157914
157948
  this.debuggerResolvers = {};
@@ -158118,7 +158152,6 @@ var pxsim;
158118
158152
  setSingleSimulator() {
158119
158153
  this.singleSimulator = true;
158120
158154
  }
158121
- // END TEMPORARY: jacdac simulator
158122
158155
  postMessage(msg, source, frameID) {
158123
158156
  var _a;
158124
158157
  if (this.hwdbg) {
@@ -158132,8 +158165,14 @@ var pxsim;
158132
158165
  let isDeferrableBroadcastMessage = false;
158133
158166
  const broadcastmsg = msg;
158134
158167
  if (source && (broadcastmsg === null || broadcastmsg === void 0 ? void 0 : broadcastmsg.broadcast)) {
158168
+ const mkcdFrames = frames.filter(frame => !frame.dataset[FRAME_DATA_MESSAGE_CHANNEL]);
158169
+ const messageChannel = msg.type === "messagepacket" && msg.channel;
158135
158170
  // include index of the source iframe
158136
158171
  broadcastmsg.srcFrameIndex = this.simFrames().findIndex((item) => item.contentWindow === source);
158172
+ const sourceFrame = broadcastmsg.srcFrameIndex >= 0 ? this.simFrames()[broadcastmsg.srcFrameIndex] : undefined;
158173
+ // jacdac messages from a board sim other than first should be dropped
158174
+ if (broadcastmsg.srcFrameIndex > 0 && mkcdFrames.find(f => f === sourceFrame) && messageChannel === "jacdac")
158175
+ return;
158137
158176
  // if the editor is hosted in a multi-editor setting
158138
158177
  // don't start extra frames
158139
158178
  const single = !!((_a = this._currentRuntime) === null || _a === void 0 ? void 0 : _a.single);
@@ -158157,7 +158196,6 @@ var pxsim;
158157
158196
  // start second simulator
158158
158197
  }
158159
158198
  else if (!single) {
158160
- const messageChannel = msg.type === "messagepacket" && msg.channel;
158161
158199
  const messageSimulator = messageChannel &&
158162
158200
  this.options.messageSimulators &&
158163
158201
  this.options.messageSimulators[messageChannel];
@@ -158183,10 +158221,6 @@ var pxsim;
158183
158221
  if (simulatorExtension) {
158184
158222
  // find a frame already running that simulator
158185
158223
  let messageFrame = frames.find(frame => frame.dataset[FRAME_DATA_MESSAGE_CHANNEL] === messageChannel);
158186
- // BEGIN TEMPORARY: jacdac simulator
158187
- if (messageChannel === "jacdac/pxt-jacdac")
158188
- this.newJacdacSimulator = true;
158189
- // END TEMPORARY: jacdac simulator
158190
158224
  // not found, spin a new one
158191
158225
  if (!messageFrame) {
158192
158226
  const url = new URL(simulatorExtension.url);
@@ -158207,13 +158241,11 @@ var pxsim;
158207
158241
  let messageFrame = frames.find(frame => frame.dataset[FRAME_DATA_MESSAGE_CHANNEL] === messageChannel);
158208
158242
  // not found, spin a new one
158209
158243
  if (!messageFrame) {
158210
- if (messageChannel !== "jacdac" || !this.newJacdacSimulator) { // TEMPORARY: jacdac simulator
158211
- const useLocalHost = pxsim.U.isLocalHost() && /localhostmessagesims=1/i.test(window.location.href);
158212
- const url = ((useLocalHost && messageSimulator.localHostUrl) || messageSimulator.url)
158213
- .replace("$PARENT_ORIGIN$", encodeURIComponent(this.options.parentOrigin || ""))
158214
- .replace("$LANGUAGE$", encodeURIComponent(this.options.userLanguage));
158215
- startSimulatorExtension(url, messageSimulator.permanent, messageSimulator.aspectRatio);
158216
- }
158244
+ const useLocalHost = pxsim.U.isLocalHost() && /localhostmessagesims=1/i.test(window.location.href);
158245
+ const url = ((useLocalHost && messageSimulator.localHostUrl) || messageSimulator.url)
158246
+ .replace("$PARENT_ORIGIN$", encodeURIComponent(this.options.parentOrigin || ""))
158247
+ .replace("$LANGUAGE$", encodeURIComponent(this.options.userLanguage));
158248
+ startSimulatorExtension(url, messageSimulator.permanent, messageSimulator.aspectRatio);
158217
158249
  }
158218
158250
  // not running the curren run, restart
158219
158251
  else if (messageFrame.dataset['runid'] != this.runId) {
@@ -158223,7 +158255,6 @@ var pxsim;
158223
158255
  else {
158224
158256
  isDeferrableBroadcastMessage = true;
158225
158257
  // start secondary frame if needed
158226
- const mkcdFrames = frames.filter(frame => !frame.dataset[FRAME_DATA_MESSAGE_CHANNEL]);
158227
158258
  if (!messageChannel &&
158228
158259
  (mkcdFrames.length == 0 || mkcdFrames.length == 1 && !this.singleSimulator)) {
158229
158260
  // messageChannel is set to false whenever msg.type !== "messagepacket"
@@ -158248,6 +158279,10 @@ var pxsim;
158248
158279
  // same frame as source
158249
158280
  if (source && frame.contentWindow == source)
158250
158281
  continue;
158282
+ // if jacdac message, don't send to other (board) simulator frames
158283
+ if (i > 0 && !frame.dataset[FRAME_DATA_MESSAGE_CHANNEL] &&
158284
+ msg.type === "messagepacket" && msg.channel === "jacdac")
158285
+ continue;
158251
158286
  // frame not in DOM
158252
158287
  if (!frame.contentWindow)
158253
158288
  continue;
@@ -164204,7 +164239,7 @@ pxt.docs.requireDOMSanitizer = () => {
164204
164239
  const existing = baseAllowedAttrs[tag] || [];
164205
164240
  return Array.from(new Set([...existing, "class", ...otherAttributes]));
164206
164241
  };
164207
- const options = Object.assign(Object.assign({}, defaults), { allowedTags: [...allowedTags, "img"], allowedAttributes: Object.assign(Object.assign({}, baseAllowedAttrs), { code: mergeClassAttribute("code"), pre: mergeClassAttribute("pre"), div: mergeClassAttribute("div", "data-youtube", "title") }) });
164242
+ const options = Object.assign(Object.assign({}, defaults), { allowedTags: [...allowedTags, "img"], allowedAttributes: Object.assign(Object.assign({}, baseAllowedAttrs), { code: mergeClassAttribute("code"), pre: mergeClassAttribute("pre"), div: mergeClassAttribute("div", "data-youtube", "title"), img: mergeClassAttribute("img") }) });
164208
164243
  return (html) => sanitizeHtml(html, options);
164209
164244
  };
164210
164245
  let forceCloudBuild = process.env["KS_FORCE_CLOUD"] !== "no";
@@ -166853,7 +166888,7 @@ function renderDocs(builtPackaged, localDir) {
166853
166888
  nodeutil.writeFileSync(outputFile, patchedMd, { encoding: "utf8" });
166854
166889
  html = pxt.docs.renderMarkdown({
166855
166890
  template: docsTemplate,
166856
- markdown: patchedMd,
166891
+ markdown: pxt.docs.normalizeStaticMarkdown(patchedMd),
166857
166892
  theme: pxt.appTarget.appTheme,
166858
166893
  filepath: path.join("docs", pathUnderDocs),
166859
166894
  });
@@ -80,6 +80,7 @@ export declare class FieldColorNumber extends FieldGridDropdown implements Field
80
80
  * @returns Height and width.
81
81
  */
82
82
  getSize(): Blockly.utils.Size;
83
+ getScaledBBox(): Blockly.utils.Rect;
83
84
  /**
84
85
  * Updates the colour of the block to reflect whether this is a full
85
86
  * block field or not.
@@ -12,5 +12,6 @@ export declare class FieldMusicEditor extends FieldAssetEditor<FieldMusicEditorO
12
12
  protected parseFieldOptions(opts: FieldMusicEditorOptions): ParsedFieldMusicEditorOptions;
13
13
  protected redrawPreview(): void;
14
14
  protected previewWidth(): number;
15
+ protected shouldInflateAsset(): boolean;
15
16
  }
16
17
  export {};
@@ -20,5 +20,6 @@ export declare class FieldPianoRoll extends FieldMusicEditor {
20
20
  protected onEditorClose(newValue: pxt.Asset): void;
21
21
  protected syncTempoField(bpm: number): void;
22
22
  protected getTempoField(): Blockly.Field;
23
+ protected shouldInflateAsset(): boolean;
23
24
  }
24
25
  export {};
package/built/pxtlib.d.ts CHANGED
@@ -1267,6 +1267,7 @@ declare namespace pxt.docs {
1267
1267
  parse?: (src: string, options?: any) => string;
1268
1268
  }
1269
1269
  export function htmlQuote(s: string): string;
1270
+ export function normalizeStaticMarkdown(markdown: string): string;
1270
1271
  export function html2Quote(s: string): string;
1271
1272
  export interface BreadcrumbEntry {
1272
1273
  name: string;
@@ -3140,7 +3141,7 @@ declare namespace pxt {
3140
3141
  protected cloneState(): AssetSnapshot;
3141
3142
  undo(): void;
3142
3143
  redo(): void;
3143
- pushUndo(): void;
3144
+ pushUndo(protectedAssetId?: string): void;
3144
3145
  revision(): number;
3145
3146
  encodeTilemap(tilemap: sprite.TilemapData, id: string): JRes;
3146
3147
  forceUpdate(): void;
@@ -3254,7 +3255,7 @@ declare namespace pxt {
3254
3255
  protected generateNewIDInternal(type: AssetType, varPrefix: string, namespaceString?: string): string;
3255
3256
  protected onChange(): void;
3256
3257
  protected readImages(allJRes: Map<JRes>, isProjectFile?: boolean): (Tile | ProjectImage | Animation | Song | JsonAsset)[];
3257
- protected cleanupTemporaryAssets(): void;
3258
+ protected cleanupTemporaryAssets(protectedAssetId?: string): void;
3258
3259
  protected getAssetCollection(type: AssetType.Animation, gallery?: boolean): AssetCollection<Animation>;
3259
3260
  protected getAssetCollection(type: AssetType.Image, gallery?: boolean): AssetCollection<ProjectImage>;
3260
3261
  protected getAssetCollection(type: AssetType.Song, gallery?: boolean): AssetCollection<Song>;
package/built/pxtlib.js CHANGED
@@ -8422,6 +8422,9 @@ var pxt;
8422
8422
  diff_1.compute = compute;
8423
8423
  function computeFormattedDiff(fileA, fileB, options = {}) {
8424
8424
  const diff = compute(fileA, fileB, options);
8425
+ if (!diff) {
8426
+ return null;
8427
+ }
8425
8428
  if (options.context == Infinity || options.full) {
8426
8429
  return diff.map(formatEdit);
8427
8430
  }
@@ -9099,6 +9102,35 @@ var pxt;
9099
9102
  return s;
9100
9103
  }
9101
9104
  docs.htmlQuote = htmlQuote;
9105
+ function normalizeStaticMarkdown(markdown) {
9106
+ const lines = markdown.split(/\r?\n/);
9107
+ let codeFenceMarker = "";
9108
+ for (let i = 0; i < lines.length; i++) {
9109
+ const fenceMatch = /^ {0,3}(`{3,}|~{3,})(.*)$/.exec(lines[i]);
9110
+ if (fenceMatch) {
9111
+ const marker = fenceMatch[1];
9112
+ const trailingText = fenceMatch[2];
9113
+ const closesCodeFence = !!codeFenceMarker
9114
+ && marker[0] === codeFenceMarker[0]
9115
+ && marker.length >= codeFenceMarker.length
9116
+ && !trailingText.trim();
9117
+ if (closesCodeFence) {
9118
+ codeFenceMarker = "";
9119
+ }
9120
+ else if (!codeFenceMarker) {
9121
+ codeFenceMarker = marker;
9122
+ }
9123
+ continue;
9124
+ }
9125
+ if (!codeFenceMarker && /^ {0,3}<br\s*\/?>\s*$/i.test(lines[i])) {
9126
+ // Marked treats a standalone break as inline content, which can extend a
9127
+ // preceding table or keep the following Markdown in the same paragraph.
9128
+ lines[i] = "\n<p><br/></p>\n";
9129
+ }
9130
+ }
9131
+ return lines.join("\n");
9132
+ }
9133
+ docs.normalizeStaticMarkdown = normalizeStaticMarkdown;
9102
9134
  // the input already should be HTML-quoted but we want to make sure, and also quote quotes
9103
9135
  function html2Quote(s) {
9104
9136
  if (!s)
@@ -9613,7 +9645,7 @@ ${opts.repo.name.replace(/^pxt-/, '')}=github:${opts.repo.fullName}#${opts.repo.
9613
9645
  \`\`\`
9614
9646
  `;
9615
9647
  //Uses the CmdLink definitions to replace links to YouTube and Vimeo (limited at the moment)
9616
- markdown = markdown.replace(/^\s*https?:\/\/(\S+)\s*$/mg, (f, lnk) => {
9648
+ markdown = markdown.replace(/^[ \t]*https?:\/\/(\S+)[ \t]*\r?$/mg, (f, lnk) => {
9617
9649
  for (let ent of links) {
9618
9650
  let m = ent.rx.exec(lnk);
9619
9651
  if (m) {
@@ -21131,7 +21163,7 @@ var pxt;
21131
21163
  this.needsRebuild = true;
21132
21164
  }
21133
21165
  }
21134
- pushUndo() {
21166
+ pushUndo(protectedAssetId) {
21135
21167
  if (this.undoStack.length && this.committedState.revision === this.state.revision)
21136
21168
  return;
21137
21169
  this.redoStack = [];
@@ -21145,7 +21177,7 @@ var pxt;
21145
21177
  entry.assetDiffs[type] = this.state.assets[type].diff(this.committedState.assets[type]);
21146
21178
  }
21147
21179
  this.committedState = this.cloneState();
21148
- this.cleanupTemporaryAssets();
21180
+ this.cleanupTemporaryAssets(protectedAssetId);
21149
21181
  }
21150
21182
  revision() {
21151
21183
  return this.state.revision;
@@ -21727,9 +21759,9 @@ var pxt;
21727
21759
  }
21728
21760
  return assets;
21729
21761
  }
21730
- cleanupTemporaryAssets() {
21762
+ cleanupTemporaryAssets(protectedAssetId) {
21731
21763
  const images = this.getAssetCollection("image" /* AssetType.Image */);
21732
- const orphaned = images.getSnapshot(image => { var _a; return !image.meta.displayName && !((_a = image.meta.blockIDs) === null || _a === void 0 ? void 0 : _a.length); });
21764
+ const orphaned = images.getSnapshot(image => { var _a; return image.id !== protectedAssetId && !image.meta.displayName && !((_a = image.meta.blockIDs) === null || _a === void 0 ? void 0 : _a.length); });
21733
21765
  for (const image of orphaned) {
21734
21766
  images.removeByID(image.id);
21735
21767
  }
@@ -22014,22 +22046,22 @@ var pxt;
22014
22046
  return new pxt.sprite.TilemapData(tilemap, tileset, layers);
22015
22047
  }
22016
22048
  function cloneAsset(asset, includeEditorData = false) {
22017
- asset.meta = Object.assign({}, asset.meta);
22018
- if (asset.meta.temporaryInfo) {
22019
- asset.meta.temporaryInfo = Object.assign({}, asset.meta.temporaryInfo);
22049
+ const meta = Object.assign({}, asset.meta);
22050
+ if (meta.temporaryInfo) {
22051
+ meta.temporaryInfo = Object.assign({}, meta.temporaryInfo);
22020
22052
  }
22021
22053
  switch (asset.type) {
22022
22054
  case "tile" /* AssetType.Tile */:
22023
22055
  case "image" /* AssetType.Image */:
22024
- return Object.assign(Object.assign({}, asset), { bitmap: cloneBitmap(asset.bitmap) });
22056
+ return Object.assign(Object.assign({}, asset), { meta, bitmap: cloneBitmap(asset.bitmap) });
22025
22057
  case "animation" /* AssetType.Animation */:
22026
- return Object.assign(Object.assign({}, asset), { frames: asset.frames.map(frame => cloneBitmap(frame)) });
22058
+ return Object.assign(Object.assign({}, asset), { meta, frames: asset.frames.map(frame => cloneBitmap(frame)) });
22027
22059
  case "tilemap" /* AssetType.Tilemap */:
22028
- return Object.assign(Object.assign({}, asset), { data: asset.data.cloneData(includeEditorData) });
22060
+ return Object.assign(Object.assign({}, asset), { meta, data: asset.data.cloneData(includeEditorData) });
22029
22061
  case "song" /* AssetType.Song */:
22030
- return Object.assign(Object.assign({}, asset), { song: pxt.assets.music.cloneSong(asset.song) });
22062
+ return Object.assign(Object.assign({}, asset), { meta, song: pxt.assets.music.cloneSong(asset.song) });
22031
22063
  case "json" /* AssetType.Json */:
22032
- return Object.assign(Object.assign({}, asset), { data: pxt.U.clone(asset.data) });
22064
+ return Object.assign(Object.assign({}, asset), { meta, data: pxt.U.clone(asset.data) });
22033
22065
  }
22034
22066
  }
22035
22067
  pxt.cloneAsset = cloneAsset;
package/built/pxtpy.js CHANGED
@@ -5747,7 +5747,11 @@ var pxt;
5747
5747
  else {
5748
5748
  let [exp, sup] = emitExp(s.body);
5749
5749
  stmts = stmts.concat(sup);
5750
- stmts.concat(exp);
5750
+ stmts = stmts.concat(exp);
5751
+ const retType = tc.getTypeAtLocation(s.body);
5752
+ if (retType && !hasTypeFlag(retType, ts.TypeFlags.Void)) {
5753
+ stmts = expWrap("return ", stmts);
5754
+ }
5751
5755
  }
5752
5756
  if (stmts.length) {
5753
5757
  // global or nonlocal declerations
package/built/pxtsim.d.ts CHANGED
@@ -1474,7 +1474,6 @@ declare namespace pxsim {
1474
1474
  private simFrames;
1475
1475
  private getSimUrl;
1476
1476
  setSingleSimulator(): void;
1477
- newJacdacSimulator: boolean;
1478
1477
  postMessage(msg: pxsim.SimulatorMessage, source?: Window, frameID?: string): void;
1479
1478
  protected deferredMessages: [HTMLIFrameElement, SimulatorMessage][];
1480
1479
  protected postDeferrableMessage(frame: HTMLIFrameElement, msg: SimulatorMessage): void;
package/built/pxtsim.js CHANGED
@@ -6440,8 +6440,6 @@ var pxsim;
6440
6440
  this._runOptions = {};
6441
6441
  this.state = SimulatorState.Unloaded;
6442
6442
  this._allowedOrigins = [];
6443
- // BEGIN TEMPORARY: jacdac simulator
6444
- this.newJacdacSimulator = false;
6445
6443
  this.frameCleanupTimeout = undefined;
6446
6444
  this.debuggerSeq = 1;
6447
6445
  this.debuggerResolvers = {};
@@ -6651,7 +6649,6 @@ var pxsim;
6651
6649
  setSingleSimulator() {
6652
6650
  this.singleSimulator = true;
6653
6651
  }
6654
- // END TEMPORARY: jacdac simulator
6655
6652
  postMessage(msg, source, frameID) {
6656
6653
  var _a;
6657
6654
  if (this.hwdbg) {
@@ -6665,8 +6662,14 @@ var pxsim;
6665
6662
  let isDeferrableBroadcastMessage = false;
6666
6663
  const broadcastmsg = msg;
6667
6664
  if (source && (broadcastmsg === null || broadcastmsg === void 0 ? void 0 : broadcastmsg.broadcast)) {
6665
+ const mkcdFrames = frames.filter(frame => !frame.dataset[FRAME_DATA_MESSAGE_CHANNEL]);
6666
+ const messageChannel = msg.type === "messagepacket" && msg.channel;
6668
6667
  // include index of the source iframe
6669
6668
  broadcastmsg.srcFrameIndex = this.simFrames().findIndex((item) => item.contentWindow === source);
6669
+ const sourceFrame = broadcastmsg.srcFrameIndex >= 0 ? this.simFrames()[broadcastmsg.srcFrameIndex] : undefined;
6670
+ // jacdac messages from a board sim other than first should be dropped
6671
+ if (broadcastmsg.srcFrameIndex > 0 && mkcdFrames.find(f => f === sourceFrame) && messageChannel === "jacdac")
6672
+ return;
6670
6673
  // if the editor is hosted in a multi-editor setting
6671
6674
  // don't start extra frames
6672
6675
  const single = !!((_a = this._currentRuntime) === null || _a === void 0 ? void 0 : _a.single);
@@ -6690,7 +6693,6 @@ var pxsim;
6690
6693
  // start second simulator
6691
6694
  }
6692
6695
  else if (!single) {
6693
- const messageChannel = msg.type === "messagepacket" && msg.channel;
6694
6696
  const messageSimulator = messageChannel &&
6695
6697
  this.options.messageSimulators &&
6696
6698
  this.options.messageSimulators[messageChannel];
@@ -6716,10 +6718,6 @@ var pxsim;
6716
6718
  if (simulatorExtension) {
6717
6719
  // find a frame already running that simulator
6718
6720
  let messageFrame = frames.find(frame => frame.dataset[FRAME_DATA_MESSAGE_CHANNEL] === messageChannel);
6719
- // BEGIN TEMPORARY: jacdac simulator
6720
- if (messageChannel === "jacdac/pxt-jacdac")
6721
- this.newJacdacSimulator = true;
6722
- // END TEMPORARY: jacdac simulator
6723
6721
  // not found, spin a new one
6724
6722
  if (!messageFrame) {
6725
6723
  const url = new URL(simulatorExtension.url);
@@ -6740,13 +6738,11 @@ var pxsim;
6740
6738
  let messageFrame = frames.find(frame => frame.dataset[FRAME_DATA_MESSAGE_CHANNEL] === messageChannel);
6741
6739
  // not found, spin a new one
6742
6740
  if (!messageFrame) {
6743
- if (messageChannel !== "jacdac" || !this.newJacdacSimulator) { // TEMPORARY: jacdac simulator
6744
- const useLocalHost = pxsim.U.isLocalHost() && /localhostmessagesims=1/i.test(window.location.href);
6745
- const url = ((useLocalHost && messageSimulator.localHostUrl) || messageSimulator.url)
6746
- .replace("$PARENT_ORIGIN$", encodeURIComponent(this.options.parentOrigin || ""))
6747
- .replace("$LANGUAGE$", encodeURIComponent(this.options.userLanguage));
6748
- startSimulatorExtension(url, messageSimulator.permanent, messageSimulator.aspectRatio);
6749
- }
6741
+ const useLocalHost = pxsim.U.isLocalHost() && /localhostmessagesims=1/i.test(window.location.href);
6742
+ const url = ((useLocalHost && messageSimulator.localHostUrl) || messageSimulator.url)
6743
+ .replace("$PARENT_ORIGIN$", encodeURIComponent(this.options.parentOrigin || ""))
6744
+ .replace("$LANGUAGE$", encodeURIComponent(this.options.userLanguage));
6745
+ startSimulatorExtension(url, messageSimulator.permanent, messageSimulator.aspectRatio);
6750
6746
  }
6751
6747
  // not running the curren run, restart
6752
6748
  else if (messageFrame.dataset['runid'] != this.runId) {
@@ -6756,7 +6752,6 @@ var pxsim;
6756
6752
  else {
6757
6753
  isDeferrableBroadcastMessage = true;
6758
6754
  // start secondary frame if needed
6759
- const mkcdFrames = frames.filter(frame => !frame.dataset[FRAME_DATA_MESSAGE_CHANNEL]);
6760
6755
  if (!messageChannel &&
6761
6756
  (mkcdFrames.length == 0 || mkcdFrames.length == 1 && !this.singleSimulator)) {
6762
6757
  // messageChannel is set to false whenever msg.type !== "messagepacket"
@@ -6781,6 +6776,10 @@ var pxsim;
6781
6776
  // same frame as source
6782
6777
  if (source && frame.contentWindow == source)
6783
6778
  continue;
6779
+ // if jacdac message, don't send to other (board) simulator frames
6780
+ if (i > 0 && !frame.dataset[FRAME_DATA_MESSAGE_CHANNEL] &&
6781
+ msg.type === "messagepacket" && msg.channel === "jacdac")
6782
+ continue;
6784
6783
  // frame not in DOM
6785
6784
  if (!frame.contentWindow)
6786
6785
  continue;