pxt-core 9.2.8 → 9.2.10

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/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() {