pxt-core 11.3.6 → 11.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/built/cli.d.ts CHANGED
@@ -44,6 +44,11 @@ export declare function staticpkgAsync(parsed: commandParser.ParsedCommand): Pro
44
44
  export declare function cleanAsync(parsed?: commandParser.ParsedCommand): Promise<void>;
45
45
  export declare function cleanGenAsync(parsed: commandParser.ParsedCommand): Promise<void>;
46
46
  export declare function npmInstallNativeAsync(): Promise<void>;
47
+ /**
48
+ * Checks for syntax errors in a translated block strings file by comparing against a baseline.
49
+ * Optionally prints the results to console or sends to a file, if an output file is specified.
50
+ */
51
+ export declare function validateTranslatedBlocks(parsed?: commandParser.ParsedCommand): Promise<void>;
47
52
  export declare function buildJResSpritesAsync(parsed: commandParser.ParsedCommand): Promise<void>;
48
53
  export declare function buildJResAsync(parsed: commandParser.ParsedCommand): Promise<void>;
49
54
  export declare function buildAsync(parsed: commandParser.ParsedCommand): Promise<void>;
package/built/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  /* eslint-disable @typescript-eslint/no-for-in-array */
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.mainCli = exports.getCodeSnippets = exports.getSnippets = exports.hex2uf2Async = exports.hexdumpAsync = exports.extractAsync = exports.testAsync = exports.runAsync = exports.deployAsync = exports.consoleAsync = exports.gendocsAsync = exports.buildShareSimJsAsync = exports.buildAsync = exports.buildJResAsync = exports.buildJResSpritesAsync = exports.npmInstallNativeAsync = exports.cleanGenAsync = exports.cleanAsync = exports.staticpkgAsync = exports.formatAsync = exports.downloadDiscourseTagAsync = exports.validateAndFixPkgConfig = exports.downloadPlaylistsAsync = exports.exportCppAsync = exports.timeAsync = exports.augmnetDocsAsync = exports.serviceAsync = exports.initAsync = exports.addAsync = exports.installAsync = exports.serveAsync = exports.internalBuildTargetAsync = exports.buildTargetAsync = exports.ghpPushAsync = exports.uploadTargetRefsAsync = exports.uploadTargetReleaseAsync = exports.yesNoAsync = exports.queryAsync = exports.apiAsync = exports.pokeRepoAsync = exports.globalConfig = void 0;
4
+ exports.mainCli = exports.getCodeSnippets = exports.getSnippets = exports.hex2uf2Async = exports.hexdumpAsync = exports.extractAsync = exports.testAsync = exports.runAsync = exports.deployAsync = exports.consoleAsync = exports.gendocsAsync = exports.buildShareSimJsAsync = exports.buildAsync = exports.buildJResAsync = exports.buildJResSpritesAsync = exports.validateTranslatedBlocks = exports.npmInstallNativeAsync = exports.cleanGenAsync = exports.cleanAsync = exports.staticpkgAsync = exports.formatAsync = exports.downloadDiscourseTagAsync = exports.validateAndFixPkgConfig = exports.downloadPlaylistsAsync = exports.exportCppAsync = exports.timeAsync = exports.augmnetDocsAsync = exports.serviceAsync = exports.initAsync = exports.addAsync = exports.installAsync = exports.serveAsync = exports.internalBuildTargetAsync = exports.buildTargetAsync = exports.ghpPushAsync = exports.uploadTargetRefsAsync = exports.uploadTargetReleaseAsync = exports.yesNoAsync = exports.queryAsync = exports.apiAsync = exports.pokeRepoAsync = exports.globalConfig = void 0;
5
5
  /// <reference path="../built/pxtlib.d.ts"/>
6
6
  /// <reference path="../built/pxtcompiler.d.ts"/>
7
7
  /// <reference path="../built/pxtpy.d.ts"/>
@@ -4509,6 +4509,143 @@ function npmInstallNativeAsync() {
4509
4509
  return nextAsync();
4510
4510
  }
4511
4511
  exports.npmInstallNativeAsync = npmInstallNativeAsync;
4512
+ /**
4513
+ * Checks for syntax errors in a single block string by comparing against a baseline string for the same block.
4514
+ */
4515
+ function validateBlockString(original, toValidate) {
4516
+ var _a, _b, _c;
4517
+ function getResponse(result, message) {
4518
+ return {
4519
+ result,
4520
+ message,
4521
+ original,
4522
+ validate: toValidate
4523
+ };
4524
+ }
4525
+ // Check for empty strings. Both empty is fine. One empty and not the other, fail.
4526
+ if (!original && !toValidate) {
4527
+ return getResponse(true, "Empty strings");
4528
+ }
4529
+ else if (!original || !toValidate) {
4530
+ return getResponse(false, "Mis-match empty and non-empty strings.");
4531
+ }
4532
+ // Split block strings by the optional parameter separator "||" and parse each section separately.
4533
+ const originalParts = original.split("||");
4534
+ const toValidateParts = toValidate.split("||");
4535
+ if (originalParts.length !== toValidateParts.length) {
4536
+ return getResponse(false, "Block string has non-matching number of segments.");
4537
+ }
4538
+ for (let i = 0; i < originalParts.length; i++) {
4539
+ const originalParsed = pxtc.parseBlockDefinition(originalParts[i]);
4540
+ const toValidateParsed = pxtc.parseBlockDefinition(toValidateParts[i]);
4541
+ // Check if parameter count changed
4542
+ if (((_a = originalParsed.parameters) === null || _a === void 0 ? void 0 : _a.length) != ((_b = toValidateParsed.parameters) === null || _b === void 0 ? void 0 : _b.length)) {
4543
+ return getResponse(false, "Block string has non-matching number of parameters.");
4544
+ }
4545
+ // Check if anything has been translated when it should not have been.
4546
+ for (let p = 0; p < ((_c = toValidateParsed.parameters) === null || _c === void 0 ? void 0 : _c.length); p++) {
4547
+ // For ref ($) params, order does not matter. For non-ref (%) params, it does.
4548
+ const toValidateParam = toValidateParsed.parameters[p];
4549
+ let matchParam;
4550
+ if (toValidateParam.ref) {
4551
+ matchParam = originalParsed.parameters.find(op => op.ref && op.name === toValidateParam.name);
4552
+ if (!matchParam) {
4553
+ return getResponse(false, "Block string has non-matching parameters.");
4554
+ }
4555
+ }
4556
+ else {
4557
+ matchParam = originalParsed.parameters[p];
4558
+ if (matchParam.ref || toValidateParam.name !== matchParam.name) {
4559
+ return getResponse(false, "Block string has non-matching ordered parameters.");
4560
+ }
4561
+ }
4562
+ if (toValidateParam.shadowBlockId !== matchParam.shadowBlockId) {
4563
+ return getResponse(false, "Block string has non-matching shadow block IDs.");
4564
+ }
4565
+ }
4566
+ }
4567
+ // Passed all checks
4568
+ return getResponse(true);
4569
+ }
4570
+ /**
4571
+ * Checks for syntax errors in a translated block strings file by comparing against a baseline.
4572
+ * Optionally prints the results to console or sends to a file, if an output file is specified.
4573
+ */
4574
+ function validateTranslatedBlocks(parsed) {
4575
+ const originalFilePath = parsed.args[0];
4576
+ const translatedFilePath = parsed.args[1];
4577
+ const outputFilePath = parsed.args[2]; // Optional
4578
+ if (!originalFilePath || !translatedFilePath) {
4579
+ U.userError("Missing required arguments: originalFilePath, translatedFilePath");
4580
+ }
4581
+ if (!fs.existsSync(originalFilePath)) {
4582
+ U.userError(`File ${originalFilePath} not found`);
4583
+ }
4584
+ if (!fs.existsSync(translatedFilePath)) {
4585
+ U.userError(`File ${translatedFilePath} not found`);
4586
+ }
4587
+ /**
4588
+ * Takes a key string from a translations file and returns the type of content it refers to (a block, a category, etc...)
4589
+ * Matches pxtc.gendocs key construction
4590
+ */
4591
+ function getKeyType(key) {
4592
+ if (key.startsWith("{id:category}"))
4593
+ return "category";
4594
+ if (key.startsWith("{id:subcategory}"))
4595
+ return "subcategory";
4596
+ if (key.startsWith("{id:group}"))
4597
+ return "group";
4598
+ if (key.endsWith("|block"))
4599
+ return "block";
4600
+ return "unknown";
4601
+ }
4602
+ const originalMap = JSON.parse(fs.readFileSync(originalFilePath, 'utf8'));
4603
+ const translationMap = JSON.parse(fs.readFileSync(translatedFilePath, 'utf8'));
4604
+ const translationKeys = Object.keys(translationMap);
4605
+ const results = {};
4606
+ for (const translationKey of translationKeys) {
4607
+ if (!(translationKey in originalMap)) {
4608
+ results[translationKey] = { result: false, message: `Original string not found for key: ${translationKey}` };
4609
+ continue;
4610
+ }
4611
+ const keyType = getKeyType(translationKey);
4612
+ const translationString = translationMap[translationKey];
4613
+ const originalString = originalMap[translationKey];
4614
+ switch (keyType) {
4615
+ case "block": {
4616
+ const validation = validateBlockString(originalString, translationString);
4617
+ results[translationKey] = validation;
4618
+ break;
4619
+ }
4620
+ case "category":
4621
+ case "subcategory":
4622
+ case "group":
4623
+ case "unknown":
4624
+ default: {
4625
+ results[translationKey] = {
4626
+ result: true,
4627
+ message: `No validation performed for key type: ${keyType}`,
4628
+ original: originalString,
4629
+ validate: translationString
4630
+ };
4631
+ }
4632
+ }
4633
+ }
4634
+ if (outputFilePath) {
4635
+ // Create directories for output file, if needed.
4636
+ const outputDir = path.dirname(outputFilePath);
4637
+ if (!fs.existsSync(outputDir)) {
4638
+ fs.mkdirSync(outputDir, { recursive: true });
4639
+ }
4640
+ fs.writeFileSync(outputFilePath, JSON.stringify(results, null, 2));
4641
+ pxt.log(`Results written to ${outputFilePath}`);
4642
+ }
4643
+ else {
4644
+ pxt.log(JSON.stringify(results, null, 2));
4645
+ }
4646
+ return Promise.resolve();
4647
+ }
4648
+ exports.validateTranslatedBlocks = validateTranslatedBlocks;
4512
4649
  function buildJResSpritesAsync(parsed) {
4513
4650
  ensurePkgDir();
4514
4651
  return loadPkgAsync()
@@ -6632,6 +6769,13 @@ ${pxt.crowdin.KEY_VARIABLE} - crowdin key
6632
6769
  help: "Validate and attempt to fix common pxt.json issues",
6633
6770
  }, validateAndFixPkgConfig);
6634
6771
  advancedCommand("buildshims", "Regenerate shims.d.ts, enums.d.ts", buildShimsAsync);
6772
+ p.defineCommand({
6773
+ name: "validatetranslatedblocks",
6774
+ aliases: ["vtb"],
6775
+ help: "Validate a file of translated block strings against a baseline",
6776
+ advanced: true,
6777
+ argString: "<original-file> <translated-file> <output-file>"
6778
+ }, validateTranslatedBlocks);
6635
6779
  function simpleCmd(name, help, callback, argString, onlineHelp) {
6636
6780
  p.defineCommand({ name, help, onlineHelp, argString }, callback);
6637
6781
  }
package/built/pxt.d.ts CHANGED
@@ -44,6 +44,11 @@ export declare function staticpkgAsync(parsed: commandParser.ParsedCommand): Pro
44
44
  export declare function cleanAsync(parsed?: commandParser.ParsedCommand): Promise<void>;
45
45
  export declare function cleanGenAsync(parsed: commandParser.ParsedCommand): Promise<void>;
46
46
  export declare function npmInstallNativeAsync(): Promise<void>;
47
+ /**
48
+ * Checks for syntax errors in a translated block strings file by comparing against a baseline.
49
+ * Optionally prints the results to console or sends to a file, if an output file is specified.
50
+ */
51
+ export declare function validateTranslatedBlocks(parsed?: commandParser.ParsedCommand): Promise<void>;
47
52
  export declare function buildJResSpritesAsync(parsed: commandParser.ParsedCommand): Promise<void>;
48
53
  export declare function buildJResAsync(parsed: commandParser.ParsedCommand): Promise<void>;
49
54
  export declare function buildAsync(parsed: commandParser.ParsedCommand): Promise<void>;
package/built/pxt.js CHANGED
@@ -113979,7 +113979,7 @@ var pxt;
113979
113979
  files[this.id + "/" + pxt.CONFIG_NAME] = this.readFile(pxt.CONFIG_NAME);
113980
113980
  }
113981
113981
  /**
113982
- * Returns localized strings qName -> translation
113982
+ * Returns localized strings qName (+ some additional identification data) -> translation
113983
113983
  */
113984
113984
  packageLocalizationStringsAsync(lang) {
113985
113985
  const targetId = pxt.appTarget.id;
@@ -161051,7 +161051,7 @@ var pxsim;
161051
161051
  "use strict";
161052
161052
  /* eslint-disable @typescript-eslint/no-for-in-array */
161053
161053
  Object.defineProperty(exports, "__esModule", { value: true });
161054
- exports.mainCli = exports.getCodeSnippets = exports.getSnippets = exports.hex2uf2Async = exports.hexdumpAsync = exports.extractAsync = exports.testAsync = exports.runAsync = exports.deployAsync = exports.consoleAsync = exports.gendocsAsync = exports.buildShareSimJsAsync = exports.buildAsync = exports.buildJResAsync = exports.buildJResSpritesAsync = exports.npmInstallNativeAsync = exports.cleanGenAsync = exports.cleanAsync = exports.staticpkgAsync = exports.formatAsync = exports.downloadDiscourseTagAsync = exports.validateAndFixPkgConfig = exports.downloadPlaylistsAsync = exports.exportCppAsync = exports.timeAsync = exports.augmnetDocsAsync = exports.serviceAsync = exports.initAsync = exports.addAsync = exports.installAsync = exports.serveAsync = exports.internalBuildTargetAsync = exports.buildTargetAsync = exports.ghpPushAsync = exports.uploadTargetRefsAsync = exports.uploadTargetReleaseAsync = exports.yesNoAsync = exports.queryAsync = exports.apiAsync = exports.pokeRepoAsync = exports.globalConfig = void 0;
161054
+ exports.mainCli = exports.getCodeSnippets = exports.getSnippets = exports.hex2uf2Async = exports.hexdumpAsync = exports.extractAsync = exports.testAsync = exports.runAsync = exports.deployAsync = exports.consoleAsync = exports.gendocsAsync = exports.buildShareSimJsAsync = exports.buildAsync = exports.buildJResAsync = exports.buildJResSpritesAsync = exports.validateTranslatedBlocks = exports.npmInstallNativeAsync = exports.cleanGenAsync = exports.cleanAsync = exports.staticpkgAsync = exports.formatAsync = exports.downloadDiscourseTagAsync = exports.validateAndFixPkgConfig = exports.downloadPlaylistsAsync = exports.exportCppAsync = exports.timeAsync = exports.augmnetDocsAsync = exports.serviceAsync = exports.initAsync = exports.addAsync = exports.installAsync = exports.serveAsync = exports.internalBuildTargetAsync = exports.buildTargetAsync = exports.ghpPushAsync = exports.uploadTargetRefsAsync = exports.uploadTargetReleaseAsync = exports.yesNoAsync = exports.queryAsync = exports.apiAsync = exports.pokeRepoAsync = exports.globalConfig = void 0;
161055
161055
  /// <reference path="../built/pxtlib.d.ts"/>
161056
161056
  /// <reference path="../built/pxtcompiler.d.ts"/>
161057
161057
  /// <reference path="../built/pxtpy.d.ts"/>
@@ -165559,6 +165559,143 @@ function npmInstallNativeAsync() {
165559
165559
  return nextAsync();
165560
165560
  }
165561
165561
  exports.npmInstallNativeAsync = npmInstallNativeAsync;
165562
+ /**
165563
+ * Checks for syntax errors in a single block string by comparing against a baseline string for the same block.
165564
+ */
165565
+ function validateBlockString(original, toValidate) {
165566
+ var _a, _b, _c;
165567
+ function getResponse(result, message) {
165568
+ return {
165569
+ result,
165570
+ message,
165571
+ original,
165572
+ validate: toValidate
165573
+ };
165574
+ }
165575
+ // Check for empty strings. Both empty is fine. One empty and not the other, fail.
165576
+ if (!original && !toValidate) {
165577
+ return getResponse(true, "Empty strings");
165578
+ }
165579
+ else if (!original || !toValidate) {
165580
+ return getResponse(false, "Mis-match empty and non-empty strings.");
165581
+ }
165582
+ // Split block strings by the optional parameter separator "||" and parse each section separately.
165583
+ const originalParts = original.split("||");
165584
+ const toValidateParts = toValidate.split("||");
165585
+ if (originalParts.length !== toValidateParts.length) {
165586
+ return getResponse(false, "Block string has non-matching number of segments.");
165587
+ }
165588
+ for (let i = 0; i < originalParts.length; i++) {
165589
+ const originalParsed = pxtc.parseBlockDefinition(originalParts[i]);
165590
+ const toValidateParsed = pxtc.parseBlockDefinition(toValidateParts[i]);
165591
+ // Check if parameter count changed
165592
+ if (((_a = originalParsed.parameters) === null || _a === void 0 ? void 0 : _a.length) != ((_b = toValidateParsed.parameters) === null || _b === void 0 ? void 0 : _b.length)) {
165593
+ return getResponse(false, "Block string has non-matching number of parameters.");
165594
+ }
165595
+ // Check if anything has been translated when it should not have been.
165596
+ for (let p = 0; p < ((_c = toValidateParsed.parameters) === null || _c === void 0 ? void 0 : _c.length); p++) {
165597
+ // For ref ($) params, order does not matter. For non-ref (%) params, it does.
165598
+ const toValidateParam = toValidateParsed.parameters[p];
165599
+ let matchParam;
165600
+ if (toValidateParam.ref) {
165601
+ matchParam = originalParsed.parameters.find(op => op.ref && op.name === toValidateParam.name);
165602
+ if (!matchParam) {
165603
+ return getResponse(false, "Block string has non-matching parameters.");
165604
+ }
165605
+ }
165606
+ else {
165607
+ matchParam = originalParsed.parameters[p];
165608
+ if (matchParam.ref || toValidateParam.name !== matchParam.name) {
165609
+ return getResponse(false, "Block string has non-matching ordered parameters.");
165610
+ }
165611
+ }
165612
+ if (toValidateParam.shadowBlockId !== matchParam.shadowBlockId) {
165613
+ return getResponse(false, "Block string has non-matching shadow block IDs.");
165614
+ }
165615
+ }
165616
+ }
165617
+ // Passed all checks
165618
+ return getResponse(true);
165619
+ }
165620
+ /**
165621
+ * Checks for syntax errors in a translated block strings file by comparing against a baseline.
165622
+ * Optionally prints the results to console or sends to a file, if an output file is specified.
165623
+ */
165624
+ function validateTranslatedBlocks(parsed) {
165625
+ const originalFilePath = parsed.args[0];
165626
+ const translatedFilePath = parsed.args[1];
165627
+ const outputFilePath = parsed.args[2]; // Optional
165628
+ if (!originalFilePath || !translatedFilePath) {
165629
+ U.userError("Missing required arguments: originalFilePath, translatedFilePath");
165630
+ }
165631
+ if (!fs.existsSync(originalFilePath)) {
165632
+ U.userError(`File ${originalFilePath} not found`);
165633
+ }
165634
+ if (!fs.existsSync(translatedFilePath)) {
165635
+ U.userError(`File ${translatedFilePath} not found`);
165636
+ }
165637
+ /**
165638
+ * Takes a key string from a translations file and returns the type of content it refers to (a block, a category, etc...)
165639
+ * Matches pxtc.gendocs key construction
165640
+ */
165641
+ function getKeyType(key) {
165642
+ if (key.startsWith("{id:category}"))
165643
+ return "category";
165644
+ if (key.startsWith("{id:subcategory}"))
165645
+ return "subcategory";
165646
+ if (key.startsWith("{id:group}"))
165647
+ return "group";
165648
+ if (key.endsWith("|block"))
165649
+ return "block";
165650
+ return "unknown";
165651
+ }
165652
+ const originalMap = JSON.parse(fs.readFileSync(originalFilePath, 'utf8'));
165653
+ const translationMap = JSON.parse(fs.readFileSync(translatedFilePath, 'utf8'));
165654
+ const translationKeys = Object.keys(translationMap);
165655
+ const results = {};
165656
+ for (const translationKey of translationKeys) {
165657
+ if (!(translationKey in originalMap)) {
165658
+ results[translationKey] = { result: false, message: `Original string not found for key: ${translationKey}` };
165659
+ continue;
165660
+ }
165661
+ const keyType = getKeyType(translationKey);
165662
+ const translationString = translationMap[translationKey];
165663
+ const originalString = originalMap[translationKey];
165664
+ switch (keyType) {
165665
+ case "block": {
165666
+ const validation = validateBlockString(originalString, translationString);
165667
+ results[translationKey] = validation;
165668
+ break;
165669
+ }
165670
+ case "category":
165671
+ case "subcategory":
165672
+ case "group":
165673
+ case "unknown":
165674
+ default: {
165675
+ results[translationKey] = {
165676
+ result: true,
165677
+ message: `No validation performed for key type: ${keyType}`,
165678
+ original: originalString,
165679
+ validate: translationString
165680
+ };
165681
+ }
165682
+ }
165683
+ }
165684
+ if (outputFilePath) {
165685
+ // Create directories for output file, if needed.
165686
+ const outputDir = path.dirname(outputFilePath);
165687
+ if (!fs.existsSync(outputDir)) {
165688
+ fs.mkdirSync(outputDir, { recursive: true });
165689
+ }
165690
+ fs.writeFileSync(outputFilePath, JSON.stringify(results, null, 2));
165691
+ pxt.log(`Results written to ${outputFilePath}`);
165692
+ }
165693
+ else {
165694
+ pxt.log(JSON.stringify(results, null, 2));
165695
+ }
165696
+ return Promise.resolve();
165697
+ }
165698
+ exports.validateTranslatedBlocks = validateTranslatedBlocks;
165562
165699
  function buildJResSpritesAsync(parsed) {
165563
165700
  ensurePkgDir();
165564
165701
  return loadPkgAsync()
@@ -167682,6 +167819,13 @@ ${pxt.crowdin.KEY_VARIABLE} - crowdin key
167682
167819
  help: "Validate and attempt to fix common pxt.json issues",
167683
167820
  }, validateAndFixPkgConfig);
167684
167821
  advancedCommand("buildshims", "Regenerate shims.d.ts, enums.d.ts", buildShimsAsync);
167822
+ p.defineCommand({
167823
+ name: "validatetranslatedblocks",
167824
+ aliases: ["vtb"],
167825
+ help: "Validate a file of translated block strings against a baseline",
167826
+ advanced: true,
167827
+ argString: "<original-file> <translated-file> <output-file>"
167828
+ }, validateTranslatedBlocks);
167685
167829
  function simpleCmd(name, help, callback, argString, onlineHelp) {
167686
167830
  p.defineCommand({ name, help, onlineHelp, argString }, callback);
167687
167831
  }
package/built/pxtlib.d.ts CHANGED
@@ -1973,7 +1973,7 @@ declare namespace pxt {
1973
1973
  getFiles(): string[];
1974
1974
  addSnapshot(files: Map<string>, exts?: string[]): void;
1975
1975
  /**
1976
- * Returns localized strings qName -> translation
1976
+ * Returns localized strings qName (+ some additional identification data) -> translation
1977
1977
  */
1978
1978
  packageLocalizationStringsAsync(lang: string): Promise<Map<string>>;
1979
1979
  bundledStringsForFile(lang: string, filename: string): Map<string>;
package/built/pxtlib.js CHANGED
@@ -16293,7 +16293,7 @@ var pxt;
16293
16293
  files[this.id + "/" + pxt.CONFIG_NAME] = this.readFile(pxt.CONFIG_NAME);
16294
16294
  }
16295
16295
  /**
16296
- * Returns localized strings qName -> translation
16296
+ * Returns localized strings qName (+ some additional identification data) -> translation
16297
16297
  */
16298
16298
  packageLocalizationStringsAsync(lang) {
16299
16299
  const targetId = pxt.appTarget.id;