pxt-core 9.2.9 → 9.2.11

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.
@@ -8597,7 +8597,7 @@ var pxtblockly;
8597
8597
  const existing = pxt.lookupProjectAssetByTSReference(text, project);
8598
8598
  if (existing)
8599
8599
  return existing;
8600
- const frames = parseImageArrayString(text);
8600
+ const frames = parseImageArrayString(text, this.params.taggedTemplate);
8601
8601
  if (frames && frames.length) {
8602
8602
  const id = this.sourceBlock_.id;
8603
8603
  const newAnimation = {
@@ -8633,7 +8633,7 @@ var pxtblockly;
8633
8633
  if (!this.asset)
8634
8634
  return "[]";
8635
8635
  if (this.isTemporaryAsset()) {
8636
- return "[" + this.asset.frames.map(frame => pxt.sprite.bitmapToImageLiteral(pxt.sprite.Bitmap.fromData(frame), "typescript" /* pxt.editor.FileType.TypeScript */)).join(",") + "]";
8636
+ return "[" + this.asset.frames.map(frame => pxt.sprite.bitmapToImageLiteral(pxt.sprite.Bitmap.fromData(frame), "typescript" /* pxt.editor.FileType.TypeScript */, this.params.taggedTemplate)).join(",") + "]";
8637
8637
  }
8638
8638
  return pxt.getTSReferenceForAsset(this.asset);
8639
8639
  }
@@ -8712,6 +8712,7 @@ var pxtblockly;
8712
8712
  }
8713
8713
  parsed.initWidth = withDefault(opts.initWidth, parsed.initWidth);
8714
8714
  parsed.initHeight = withDefault(opts.initHeight, parsed.initHeight);
8715
+ parsed.taggedTemplate = opts.taggedTemplate;
8715
8716
  return parsed;
8716
8717
  function withDefault(raw, def) {
8717
8718
  const res = parseInt(raw);
@@ -8721,11 +8722,11 @@ var pxtblockly;
8721
8722
  return res;
8722
8723
  }
8723
8724
  }
8724
- function parseImageArrayString(str) {
8725
+ function parseImageArrayString(str, templateLiteral) {
8725
8726
  if (str.indexOf("[") === -1)
8726
8727
  return null;
8727
8728
  str = str.replace(/[\[\]]/mg, "");
8728
- return str.split(",").map(s => pxt.sprite.imageLiteralToBitmap(s).data()).filter(b => b.height && b.width);
8729
+ return str.split(",").map(s => pxt.sprite.imageLiteralToBitmap(s, templateLiteral).data()).filter(b => b.height && b.width);
8729
8730
  }
8730
8731
  function isNumberType(type) {
8731
8732
  return type === "math_number" || type === "math_integer" || type === "math_whole_number";
@@ -12764,7 +12765,7 @@ var pxtblockly;
12764
12765
  if (this.getBlockData()) {
12765
12766
  return project.lookupAsset("image" /* pxt.AssetType.Image */, this.getBlockData());
12766
12767
  }
12767
- const bmp = text ? pxt.sprite.imageLiteralToBitmap(text) : new pxt.sprite.Bitmap(this.params.initWidth, this.params.initHeight);
12768
+ const bmp = text ? pxt.sprite.imageLiteralToBitmap(text, this.params.taggedTemplate) : new pxt.sprite.Bitmap(this.params.initWidth, this.params.initHeight);
12768
12769
  if (!bmp) {
12769
12770
  this.isGreyBlock = true;
12770
12771
  this.valueText = text;
@@ -12785,7 +12786,7 @@ var pxtblockly;
12785
12786
  if (this.asset && !this.isTemporaryAsset()) {
12786
12787
  return pxt.getTSReferenceForAsset(this.asset);
12787
12788
  }
12788
- return pxt.sprite.bitmapToImageLiteral(this.asset && pxt.sprite.Bitmap.fromData(this.asset.bitmap), "typescript" /* pxt.editor.FileType.TypeScript */);
12789
+ return pxt.sprite.bitmapToImageLiteral(this.asset && pxt.sprite.Bitmap.fromData(this.asset.bitmap), "typescript" /* pxt.editor.FileType.TypeScript */, this.params.taggedTemplate);
12789
12790
  }
12790
12791
  parseFieldOptions(opts) {
12791
12792
  return parseFieldOptions(opts);
@@ -12840,6 +12841,7 @@ var pxtblockly;
12840
12841
  parsed.initColor = withDefault(opts.initColor, parsed.initColor);
12841
12842
  parsed.initWidth = withDefault(opts.initWidth, parsed.initWidth);
12842
12843
  parsed.initHeight = withDefault(opts.initHeight, parsed.initHeight);
12844
+ parsed.taggedTemplate = opts.taggedTemplate;
12843
12845
  return parsed;
12844
12846
  function withDefault(raw, def) {
12845
12847
  const res = parseInt(raw);
package/built/pxtlib.d.ts CHANGED
@@ -996,42 +996,7 @@ declare namespace pxt.hexloader {
996
996
  declare namespace pxt.crowdin {
997
997
  const KEY_VARIABLE = "CROWDIN_KEY";
998
998
  let testMode: boolean;
999
- const TEST_KEY = "!!!testmode!!!";
1000
999
  function setTestMode(): void;
1001
- interface CrowdinFileInfo {
1002
- name: string;
1003
- fullName?: string;
1004
- id: number;
1005
- node_type: "file" | "directory" | "branch";
1006
- phrases?: number;
1007
- translated?: number;
1008
- approved?: number;
1009
- branch?: string;
1010
- files?: CrowdinFileInfo[];
1011
- }
1012
- interface CrowdinProjectInfo {
1013
- languages: {
1014
- name: string;
1015
- code: string;
1016
- }[];
1017
- files: CrowdinFileInfo[];
1018
- }
1019
- interface DownloadOptions {
1020
- translatedOnly?: boolean;
1021
- validatedOnly?: boolean;
1022
- }
1023
- function downloadTranslationsAsync(branch: string, prj: string, key: string, filename: string, options?: DownloadOptions): Promise<Map<Map<string>>>;
1024
- function createDirectoryAsync(branch: string, prj: string, key: string, name: string, incr?: () => void): Promise<void>;
1025
- function uploadTranslationAsync(branch: string, prj: string, key: string, filename: string, data: string): Promise<void>;
1026
- function projectInfoAsync(prj: string, key: string): Promise<CrowdinProjectInfo>;
1027
- /**
1028
- * Scans files in crowdin and report files that are not on disk anymore
1029
- */
1030
- function listFilesAsync(prj: string, key: string, crowdinPath: string): Promise<{
1031
- fullName: string;
1032
- branch: string;
1033
- }[]>;
1034
- function languageStatsAsync(prj: string, key: string, lang: string): Promise<CrowdinFileInfo[]>;
1035
1000
  function inContextLoadAsync(text: string): Promise<string>;
1036
1001
  }
1037
1002
  declare namespace pxt.diff {
@@ -1759,12 +1724,12 @@ declare namespace pxt.sprite {
1759
1724
  function formatByte(value: number, bytes: number): string;
1760
1725
  function resizeBitmap(img: Bitmap, width: number, height: number): Bitmap;
1761
1726
  function resizeTilemap(img: Tilemap, width: number, height: number): Tilemap;
1762
- function imageLiteralToBitmap(text: string): Bitmap;
1727
+ function imageLiteralToBitmap(text: string, templateLiteral?: string): Bitmap;
1763
1728
  function encodeAnimationString(frames: BitmapData[], interval: number): string;
1764
1729
  function addMissingTilemapTilesAndReferences(project: TilemapProject, asset: ProjectTilemap): void;
1765
1730
  function updateTilemapReferencesFromResult(project: TilemapProject, assetResult: ProjectTilemap): void;
1766
1731
  function imageLiteralFromDimensions(width: number, height: number, color: number, fileType: "typescript" | "python"): string;
1767
- function bitmapToImageLiteral(bitmap: Bitmap, fileType: "typescript" | "python"): string;
1732
+ function bitmapToImageLiteral(bitmap: Bitmap, fileType: "typescript" | "python", templateLiteral?: string): string;
1768
1733
  function bitmapEquals(a: pxt.sprite.BitmapData, b: pxt.sprite.BitmapData): boolean;
1769
1734
  function tileWidthToTileScale(tileWidth: number): string;
1770
1735
  function tileScaleToTileWidth(tileScale: string): number;
@@ -1919,6 +1884,7 @@ declare namespace pxt {
1919
1884
  */
1920
1885
  packageLocalizationStringsAsync(lang: string): Promise<Map<string>>;
1921
1886
  bundledStringsForFile(lang: string, filename: string): Map<string>;
1887
+ patchAppTargetPalette(): void;
1922
1888
  }
1923
1889
  class MainPackage extends Package {
1924
1890
  _host: Host;
package/built/pxtlib.js CHANGED
@@ -7618,251 +7618,11 @@ var pxt;
7618
7618
  (function (crowdin) {
7619
7619
  crowdin.KEY_VARIABLE = "CROWDIN_KEY";
7620
7620
  crowdin.testMode = false;
7621
- crowdin.TEST_KEY = "!!!testmode!!!";
7622
7621
  function setTestMode() {
7623
7622
  pxt.crowdin.testMode = true;
7624
7623
  pxt.log(`CROWDIN TEST MODE - files will NOT be uploaded`);
7625
7624
  }
7626
7625
  crowdin.setTestMode = setTestMode;
7627
- function multipartPostAsync(key, uri, data = {}, filename = null, filecontents = null) {
7628
- if (crowdin.testMode || key == crowdin.TEST_KEY) {
7629
- const resp = {
7630
- success: true
7631
- };
7632
- return Promise.resolve({ statusCode: 200, headers: {}, text: JSON.stringify(resp), json: resp });
7633
- }
7634
- return pxt.Util.multipartPostAsync(uri, data, filename, filecontents);
7635
- }
7636
- function apiUri(branch, prj, key, cmd, args) {
7637
- pxt.Util.assert(!!prj && !!key && !!cmd);
7638
- const apiRoot = "https://api.crowdin.com/api/project/" + prj + "/";
7639
- args = args || {};
7640
- if (crowdin.testMode)
7641
- delete args["key"]; // ensure no key is passed in test mode
7642
- else
7643
- args["key"] = key;
7644
- if (branch)
7645
- args["branch"] = branch;
7646
- return apiRoot + cmd + "?" + Object.keys(args).map(k => `${k}=${encodeURIComponent(args[k])}`).join("&");
7647
- }
7648
- function downloadTranslationsAsync(branch, prj, key, filename, options = {}) {
7649
- const q = { json: "true" };
7650
- const infoUri = apiUri(branch, prj, key, "info", q);
7651
- const r = {};
7652
- filename = normalizeFileName(filename);
7653
- return pxt.Util.httpGetTextAsync(infoUri).then(respText => {
7654
- const info = JSON.parse(respText);
7655
- if (!info)
7656
- throw new Error("info failed");
7657
- let todo = info.languages.filter(l => l.code != "en");
7658
- if (pxt.appTarget && pxt.appTarget.appTheme && pxt.appTarget.appTheme.availableLocales)
7659
- todo = todo.filter(l => pxt.appTarget.appTheme.availableLocales.indexOf(l.code) > -1);
7660
- pxt.log('languages: ' + todo.map(l => l.code).join(', '));
7661
- const nextFile = () => {
7662
- const item = todo.pop();
7663
- if (!item)
7664
- return Promise.resolve();
7665
- const exportFileUri = apiUri(branch, prj, key, "export-file", {
7666
- file: filename,
7667
- language: item.code,
7668
- export_translated_only: options.translatedOnly ? "1" : "0",
7669
- export_approved_only: options.validatedOnly ? "1" : "0"
7670
- });
7671
- pxt.log(`downloading ${item.name} - ${item.code} (${todo.length} more)`);
7672
- return pxt.Util.httpGetTextAsync(exportFileUri).then((transationsText) => {
7673
- try {
7674
- const translations = JSON.parse(transationsText);
7675
- if (translations)
7676
- r[item.code] = translations;
7677
- }
7678
- catch (e) {
7679
- pxt.log(exportFileUri + ' ' + e);
7680
- }
7681
- return nextFile();
7682
- }).then(() => pxt.Util.delay(1000)); // throttling otherwise crowdin fails
7683
- };
7684
- return nextFile();
7685
- }).then(() => r);
7686
- }
7687
- crowdin.downloadTranslationsAsync = downloadTranslationsAsync;
7688
- function mkIncr(filename) {
7689
- let cnt = 0;
7690
- return function incr() {
7691
- if (cnt++ > 10) {
7692
- throw new Error("Too many API calls for " + filename);
7693
- }
7694
- };
7695
- }
7696
- function createDirectoryAsync(branch, prj, key, name, incr) {
7697
- name = normalizeFileName(name);
7698
- pxt.debug(`create directory ${branch || ""}/${name}`);
7699
- if (!incr)
7700
- incr = mkIncr(name);
7701
- return multipartPostAsync(key, apiUri(branch, prj, key, "add-directory"), { json: "true", name: name })
7702
- .then(resp => {
7703
- pxt.debug(`crowdin resp: ${resp.statusCode}`);
7704
- // 400 returned by folder already exists
7705
- if (resp.statusCode == 200 || resp.statusCode == 400)
7706
- return Promise.resolve();
7707
- if (resp.statusCode == 500 && resp.text) {
7708
- const json = JSON.parse(resp.text);
7709
- if (json.error.code === 50) {
7710
- pxt.log('directory already exists');
7711
- return Promise.resolve();
7712
- }
7713
- }
7714
- const data = resp.json || JSON.parse(resp.text) || { error: {} };
7715
- if (resp.statusCode == 404 && data.error.code == 17) {
7716
- pxt.log(`parent directory missing for ${name}`);
7717
- const par = name.replace(/\/[^\/]+$/, "");
7718
- if (par != name) {
7719
- return createDirectoryAsync(branch, prj, key, par, incr)
7720
- .then(() => createDirectoryAsync(branch, prj, key, name, incr)); // retry
7721
- }
7722
- }
7723
- throw new Error(`cannot create directory ${branch || ""}/${name}: ${resp.statusCode} ${JSON.stringify(data)}`);
7724
- });
7725
- }
7726
- crowdin.createDirectoryAsync = createDirectoryAsync;
7727
- function normalizeFileName(filename) {
7728
- return filename.replace(/\\/g, '/');
7729
- }
7730
- function uploadTranslationAsync(branch, prj, key, filename, data) {
7731
- pxt.Util.assert(!!prj);
7732
- pxt.Util.assert(!!key);
7733
- filename = normalizeFileName(filename);
7734
- const incr = mkIncr(filename);
7735
- function startAsync() {
7736
- return uploadAsync("update-file", { update_option: "update_as_unapproved" });
7737
- }
7738
- function uploadAsync(op, opts) {
7739
- opts["type"] = "auto";
7740
- opts["json"] = "";
7741
- opts["escape_quotes"] = "0";
7742
- incr();
7743
- return multipartPostAsync(key, apiUri(branch, prj, key, op), opts, filename, data)
7744
- .then(resp => handleResponseAsync(resp));
7745
- }
7746
- function handleResponseAsync(resp) {
7747
- var _a, _b, _c;
7748
- const code = resp.statusCode;
7749
- const errorData = pxt.Util.jsonTryParse(resp.text) || {};
7750
- pxt.debug(`upload result: ${code}`);
7751
- if (code == 404 && errorData.error && errorData.error.code == 8) {
7752
- pxt.log(`create new translation file: ${filename}`);
7753
- return uploadAsync("add-file", {});
7754
- }
7755
- else if (code == 404 && ((_a = errorData.error) === null || _a === void 0 ? void 0 : _a.code) == 17) {
7756
- return createDirectoryAsync(branch, prj, key, filename.replace(/\/[^\/]+$/, ""), incr)
7757
- .then(() => startAsync());
7758
- }
7759
- else if (!errorData.success && ((_b = errorData.error) === null || _b === void 0 ? void 0 : _b.code) == 53) {
7760
- // file is being updated
7761
- pxt.log(`${filename} being updated, waiting 5s and retry...`);
7762
- return pxt.U.delay(5000) // wait 5s and try again
7763
- .then(() => uploadTranslationAsync(branch, prj, key, filename, data));
7764
- }
7765
- else if (code == 429 && ((_c = errorData.error) === null || _c === void 0 ? void 0 : _c.code) == 55) {
7766
- // Too many concurrent requests
7767
- pxt.log(`Maximum concurrent requests reached, waiting 10s and retry...`);
7768
- return pxt.U.delay(10 * 1000) // wait 10s and try again
7769
- .then(() => uploadTranslationAsync(branch, prj, key, filename, data));
7770
- }
7771
- else if (code == 200 || errorData.success) {
7772
- // something crowdin reports 500 with success=true
7773
- return Promise.resolve();
7774
- }
7775
- else {
7776
- throw new Error(`Error, upload translation: ${filename}, ${code}, ${resp.text}`);
7777
- }
7778
- }
7779
- return startAsync();
7780
- }
7781
- crowdin.uploadTranslationAsync = uploadTranslationAsync;
7782
- function flatten(allFiles, node, parentDir, branch) {
7783
- const n = node.name;
7784
- const d = parentDir ? parentDir + "/" + n : n;
7785
- node.fullName = d;
7786
- node.branch = branch || "";
7787
- switch (node.node_type) {
7788
- case "file":
7789
- allFiles.push(node);
7790
- break;
7791
- case "directory":
7792
- (node.files || []).forEach(f => flatten(allFiles, f, d, branch));
7793
- break;
7794
- case "branch":
7795
- (node.files || []).forEach(f => flatten(allFiles, f, parentDir, node.name));
7796
- break;
7797
- }
7798
- }
7799
- function filterAndFlattenFiles(files, crowdinPath) {
7800
- const pxtCrowdinBranch = pxt.appTarget.versions.pxtCrowdinBranch || "";
7801
- const targetCrowdinBranch = pxt.appTarget.versions.targetCrowdinBranch || "";
7802
- let allFiles = [];
7803
- // flatten the files
7804
- files.forEach(f => flatten(allFiles, f, ""));
7805
- // top level files are for PXT, subolder are targets
7806
- allFiles = allFiles.filter(f => {
7807
- if (f.fullName.indexOf('/') < 0)
7808
- return f.branch == pxtCrowdinBranch; // pxt file
7809
- else
7810
- return f.branch == targetCrowdinBranch;
7811
- });
7812
- // folder filter
7813
- if (crowdinPath) {
7814
- // filter out crowdin folder
7815
- allFiles = allFiles.filter(f => f.fullName.indexOf(crowdinPath) == 0);
7816
- }
7817
- // filter out non-target files
7818
- if (pxt.appTarget.id != "core") {
7819
- const id = pxt.appTarget.id + '/';
7820
- allFiles = allFiles.filter(f => {
7821
- return f.fullName.indexOf('/') < 0 // top level file
7822
- || f.fullName.substr(0, id.length) == id // from the target folder
7823
- || f.fullName.indexOf('common-docs') >= 0; // common docs
7824
- });
7825
- }
7826
- return allFiles;
7827
- }
7828
- function projectInfoAsync(prj, key) {
7829
- const q = { json: "true" };
7830
- const infoUri = apiUri("", prj, key, "info", q);
7831
- return pxt.Util.httpGetTextAsync(infoUri).then(respText => {
7832
- const info = JSON.parse(respText);
7833
- return info;
7834
- });
7835
- }
7836
- crowdin.projectInfoAsync = projectInfoAsync;
7837
- /**
7838
- * Scans files in crowdin and report files that are not on disk anymore
7839
- */
7840
- function listFilesAsync(prj, key, crowdinPath) {
7841
- pxt.log(`crowdin: listing files under ${crowdinPath}`);
7842
- return projectInfoAsync(prj, key)
7843
- .then(info => {
7844
- if (!info)
7845
- throw new Error("info failed");
7846
- let allFiles = filterAndFlattenFiles(info.files, crowdinPath);
7847
- pxt.debug(`crowdin: found ${allFiles.length} under ${crowdinPath}`);
7848
- return allFiles.map(f => {
7849
- return {
7850
- fullName: f.fullName,
7851
- branch: f.branch || ""
7852
- };
7853
- });
7854
- });
7855
- }
7856
- crowdin.listFilesAsync = listFilesAsync;
7857
- function languageStatsAsync(prj, key, lang) {
7858
- const uri = apiUri("", prj, key, "language-status", { language: lang, json: "true" });
7859
- return pxt.Util.httpGetJsonAsync(uri)
7860
- .then(info => {
7861
- const allFiles = filterAndFlattenFiles(info.files);
7862
- return allFiles;
7863
- });
7864
- }
7865
- crowdin.languageStatsAsync = languageStatsAsync;
7866
7626
  function inContextLoadAsync(text) {
7867
7627
  const node = document.createElement("input");
7868
7628
  node.type = "text";
@@ -13353,11 +13113,12 @@ var pxt;
13353
13113
  return result;
13354
13114
  }
13355
13115
  sprite_1.resizeTilemap = resizeTilemap;
13356
- function imageLiteralToBitmap(text) {
13116
+ function imageLiteralToBitmap(text, templateLiteral = "img") {
13357
13117
  // Strip the tagged template string business and the whitespace. We don't have to exhaustively
13358
13118
  // replace encoded characters because the compiler will catch any disallowed characters and throw
13359
13119
  // an error before the decompilation happens. 96 is backtick and 9 is tab
13360
13120
  text = text.replace(/[ `]|(?:&#96;)|(?:&#9;)|(?:img)/g, "").trim();
13121
+ text = text.replaceAll(templateLiteral, "");
13361
13122
  text = text.replace(/^["`\(\)]*/, '').replace(/["`\(\)]*$/, '');
13362
13123
  text = text.replace(/&#10;/g, "\n");
13363
13124
  const rows = text.split("\n");
@@ -13519,14 +13280,14 @@ var pxt;
13519
13280
  pxt.sprite.trimTilemapTileset(result);
13520
13281
  }
13521
13282
  sprite_1.updateTilemapReferencesFromResult = updateTilemapReferencesFromResult;
13522
- function imageLiteralPrologue(fileType) {
13283
+ function imageLiteralPrologue(fileType, templateLiteral = "img") {
13523
13284
  let res = '';
13524
13285
  switch (fileType) {
13525
13286
  case "python":
13526
- res = "img(\"\"\"";
13287
+ res = `${templateLiteral}("""`;
13527
13288
  break;
13528
13289
  default:
13529
- res = "img`";
13290
+ res = `${templateLiteral}\``;
13530
13291
  break;
13531
13292
  }
13532
13293
  return res;
@@ -13557,10 +13318,10 @@ var pxt;
13557
13318
  return res;
13558
13319
  }
13559
13320
  sprite_1.imageLiteralFromDimensions = imageLiteralFromDimensions;
13560
- function bitmapToImageLiteral(bitmap, fileType) {
13321
+ function bitmapToImageLiteral(bitmap, fileType, templateLiteral = "img") {
13561
13322
  if (!bitmap || bitmap.height === 0 || bitmap.width === 0)
13562
13323
  return "";
13563
- let res = imageLiteralPrologue(fileType);
13324
+ let res = imageLiteralPrologue(fileType, templateLiteral);
13564
13325
  if (bitmap) {
13565
13326
  const paddingBetweenPixels = (bitmap.width * bitmap.height > 300) ? "" : " ";
13566
13327
  for (let r = 0; r < bitmap.height; r++) {
@@ -16061,11 +15822,7 @@ var pxt;
16061
15822
  };
16062
15823
  await loadDepsRecursive(null, this);
16063
15824
  // get paletter config loading deps, so the more higher level packages take precedence
16064
- if (this.config.palette && pxt.appTarget.runtime) {
16065
- pxt.appTarget.runtime.palette = pxt.U.clone(this.config.palette);
16066
- if (this.config.paletteNames)
16067
- pxt.appTarget.runtime.paletteNames = this.config.paletteNames;
16068
- }
15825
+ this.patchAppTargetPalette();
16069
15826
  // get screen size loading deps, so the more higher level packages take precedence
16070
15827
  if (this.config.screenSize && pxt.appTarget.runtime)
16071
15828
  pxt.appTarget.runtime.screenSize = pxt.U.clone(this.config.screenSize);
@@ -16211,6 +15968,13 @@ var pxt;
16211
15968
  }
16212
15969
  return r;
16213
15970
  }
15971
+ patchAppTargetPalette() {
15972
+ if (this.config.palette && pxt.appTarget.runtime) {
15973
+ pxt.appTarget.runtime.palette = pxt.U.clone(this.config.palette);
15974
+ if (this.config.paletteNames)
15975
+ pxt.appTarget.runtime.paletteNames = this.config.paletteNames;
15976
+ }
15977
+ }
16214
15978
  }
16215
15979
  Package.depWarnings = {};
16216
15980
  pxt.Package = Package;
@@ -16472,6 +16236,10 @@ var pxt;
16472
16236
  opts.jres = this.getJRes();
16473
16237
  const functionOpts = pxt.appTarget.runtime && pxt.appTarget.runtime.functionsOptions;
16474
16238
  opts.allowedArgumentTypes = functionOpts && functionOpts.extraFunctionEditorTypes && functionOpts.extraFunctionEditorTypes.map(info => info.typeName).concat("number", "boolean", "string");
16239
+ for (const dep of this.sortedDeps()) {
16240
+ dep.patchAppTargetPalette();
16241
+ }
16242
+ this.patchAppTargetPalette();
16475
16243
  return opts;
16476
16244
  }
16477
16245
  prepareConfigToBePublished() {
@@ -21246,7 +21014,7 @@ var pxt;
21246
21014
  if (!steps)
21247
21015
  return undefined; // error parsing steps
21248
21016
  // collect code and infer editor
21249
- const { code, templateCode, editor, language, jres, assetJson, customTs, simThemeJson } = computeBodyMetadata(body);
21017
+ const { code, templateCode, templateLanguage, editor, language, jres, assetJson, customTs, simThemeJson } = computeBodyMetadata(body);
21250
21018
  // noDiffs legacy
21251
21019
  if (metadata.diffs === true // enabled in tutorial
21252
21020
  || (metadata.diffs !== false && metadata.noDiffs !== true // not disabled
@@ -21272,6 +21040,7 @@ var pxt;
21272
21040
  activities,
21273
21041
  code,
21274
21042
  templateCode,
21043
+ templateLanguage,
21275
21044
  metadata,
21276
21045
  language,
21277
21046
  jres,
@@ -21284,7 +21053,7 @@ var pxt;
21284
21053
  }
21285
21054
  tutorial_1.parseTutorial = parseTutorial;
21286
21055
  function getMetadataRegex() {
21287
- return /``` *(sim|block|blocks|filterblocks|spy|ghost|typescript|ts|js|javascript|template|python|jres|assetjson|customts|simtheme)\s*\n([\s\S]*?)\n```/gmi;
21056
+ return /``` *(sim|block|blocks|filterblocks|spy|ghost|typescript|ts|js|javascript|template|python|jres|assetjson|customts|simtheme|python-template|ts-template|typescript-template|js-template|javascript-template)\s*\n([\s\S]*?)\n```/gmi;
21288
21057
  }
21289
21058
  tutorial_1.getMetadataRegex = getMetadataRegex;
21290
21059
  function computeBodyMetadata(body) {
@@ -21294,6 +21063,7 @@ var pxt;
21294
21063
  let jres;
21295
21064
  let code = [];
21296
21065
  let templateCode;
21066
+ let templateLanguage;
21297
21067
  let language;
21298
21068
  let idx = 0;
21299
21069
  let assetJson;
@@ -21329,6 +21099,22 @@ var pxt;
21329
21099
  case "template":
21330
21100
  templateCode = m2;
21331
21101
  break;
21102
+ case "python-template":
21103
+ if (!checkTutorialEditor(pxt.PYTHON_PROJECT_NAME))
21104
+ return undefined;
21105
+ templateCode = m2;
21106
+ templateLanguage = "python";
21107
+ language = "python";
21108
+ break;
21109
+ case "ts-template":
21110
+ case "typescript-template":
21111
+ case "js-template":
21112
+ case "javascript-template":
21113
+ if (!checkTutorialEditor(pxt.JAVASCRIPT_PROJECT_NAME))
21114
+ return undefined;
21115
+ templateCode = m2;
21116
+ templateLanguage = "typescript";
21117
+ break;
21332
21118
  case "jres":
21333
21119
  jres = m2;
21334
21120
  break;
@@ -21352,6 +21138,7 @@ var pxt;
21352
21138
  return {
21353
21139
  code,
21354
21140
  templateCode,
21141
+ templateLanguage,
21355
21142
  editor,
21356
21143
  language,
21357
21144
  jres,
@@ -21634,6 +21421,7 @@ ${code}
21634
21421
  tutorialCode: tutorialInfo.code,
21635
21422
  tutorialRecipe: !!recipe,
21636
21423
  templateCode: tutorialInfo.templateCode,
21424
+ templateLanguage: tutorialInfo.templateLanguage,
21637
21425
  autoexpandStep: ((_a = tutorialInfo.metadata) === null || _a === void 0 ? void 0 : _a.autoexpandOff) ? false : true,
21638
21426
  metadata: tutorialInfo.metadata,
21639
21427
  language: tutorialInfo.language,