pxt-core 9.3.13 → 9.3.14
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/README.md +11 -0
- package/built/cli.js +7 -2
- package/built/pxt.js +43 -2
- package/built/pxtblockly.js +97 -57
- package/built/pxtblocks.d.ts +59 -21
- package/built/pxtblocks.js +97 -57
- package/built/pxteditor.d.ts +6 -1
- package/built/pxteditor.js +12 -0
- package/built/pxtlib.d.ts +9 -0
- package/built/pxtlib.js +36 -0
- package/built/target.js +1 -1
- package/built/web/main.js +1 -1
- package/built/web/pxtapp.js +1 -1
- package/built/web/pxtblockly.js +2 -2
- package/built/web/pxtblocks.js +1 -1
- package/built/web/pxteditor.js +1 -1
- package/built/web/pxtembed.js +2 -2
- package/built/web/pxtlib.js +1 -1
- package/built/web/pxtworker.js +1 -1
- package/built/web/rtlsemantic.css +1 -1
- package/built/web/runnerembed.js +1 -0
- package/built/web/semantic.css +1 -1
- package/built/web/teachertool/css/main.807e0772.css +1 -0
- package/built/web/teachertool/js/{main.3a94a341.js → main.37b40d1d.js} +2 -2
- package/package.json +1 -1
- package/react-common/components/util.tsx +1 -1
- package/theme/pxt.less +1 -0
- package/theme/themepacks.less +41 -0
- package/webapp/public/embed.js +1 -1
- package/webapp/public/teachertool.html +1 -3
- package/built/pxtrunner.d.ts +0 -151
- package/built/pxtrunner.js +0 -2626
- package/built/web/pxtrunner.js +0 -1
- package/built/web/teachertool/css/main.59776cd1.css +0 -1
package/README.md
CHANGED
|
@@ -114,6 +114,17 @@ npm install -g svgo
|
|
|
114
114
|
svgo svgicons/myicon.svg
|
|
115
115
|
```
|
|
116
116
|
|
|
117
|
+
### Shared Styling
|
|
118
|
+
|
|
119
|
+
When adding a CSS color or other style element that will be shared across editor targets (e.g. micro:bit, Arcade) and sub-applications (a.k.a. "CRAs", like skillmap, teachertool, etc.). Declare a CSS variable for it in `theme/themepacks.less`:
|
|
120
|
+
|
|
121
|
+
1. Add the new variable to the `:root` pseudo-class. Choose a reasonable default value according to the guidlines in the file.
|
|
122
|
+
2. Add the new variable to all theme classes defined in that file. At the time of this writing, only `theme-highcontrast` is defined. Choose a value that works well for the given theme.
|
|
123
|
+
3. Add the new variable to the theme overrides for each target. This will be done in the target repo's `theme/themepacks.less` file (e.g. pxt-microbit, pxt-arcade).
|
|
124
|
+
|
|
125
|
+
Variables declared this way will be available to CRAs at runtime, and they will be initialized with the override values defined by the target in which they're running.
|
|
126
|
+
|
|
127
|
+
|
|
117
128
|
### Documentation Highlighting
|
|
118
129
|
|
|
119
130
|
In the documentation, highlighting of code snippets uses highlight.js (hljs).
|
package/built/cli.js
CHANGED
|
@@ -2403,8 +2403,13 @@ async function buildAndWatchTargetAsync(includeSourceMaps, rebundle) {
|
|
|
2403
2403
|
}
|
|
2404
2404
|
else {
|
|
2405
2405
|
console.log("rebuilding css");
|
|
2406
|
-
|
|
2407
|
-
|
|
2406
|
+
try {
|
|
2407
|
+
await buildSemanticUIAsync();
|
|
2408
|
+
console.log("css build complete");
|
|
2409
|
+
}
|
|
2410
|
+
catch (e) {
|
|
2411
|
+
console.error("css build failed", e);
|
|
2412
|
+
}
|
|
2408
2413
|
}
|
|
2409
2414
|
return lessFiles;
|
|
2410
2415
|
};
|
package/built/pxt.js
CHANGED
|
@@ -101617,6 +101617,7 @@ var pxt;
|
|
|
101617
101617
|
var blocks;
|
|
101618
101618
|
(function (blocks) {
|
|
101619
101619
|
const THIS_NAME = "this";
|
|
101620
|
+
blocks.showBlockIdInTooltip = false;
|
|
101620
101621
|
// The JS Math functions supported in the blocks. The order of this array
|
|
101621
101622
|
// determines the order of the dropdown in the math_js_op block
|
|
101622
101623
|
blocks.MATH_FUNCTIONS = {
|
|
@@ -102318,6 +102319,21 @@ var pxt;
|
|
|
102318
102319
|
}));
|
|
102319
102320
|
});
|
|
102320
102321
|
}
|
|
102322
|
+
if (pxt.blocks.showBlockIdInTooltip) {
|
|
102323
|
+
for (const id of Object.keys(_blockDefinitions)) {
|
|
102324
|
+
const tooltip = _blockDefinitions[id].tooltip;
|
|
102325
|
+
if (typeof tooltip === "object" && tooltip !== null) {
|
|
102326
|
+
for (const innerKey in tooltip) {
|
|
102327
|
+
if (tooltip.hasOwnProperty(innerKey)) {
|
|
102328
|
+
_blockDefinitions[id].tooltip[innerKey] = `${tooltip[innerKey]} (id: ${id})`;
|
|
102329
|
+
}
|
|
102330
|
+
}
|
|
102331
|
+
}
|
|
102332
|
+
else {
|
|
102333
|
+
_blockDefinitions[id].tooltip = `${_blockDefinitions[id].tooltip} (id: ${id})`;
|
|
102334
|
+
}
|
|
102335
|
+
}
|
|
102336
|
+
}
|
|
102321
102337
|
}
|
|
102322
102338
|
})(blocks = pxt.blocks || (pxt.blocks = {}));
|
|
102323
102339
|
})(pxt || (pxt = {}));
|
|
@@ -103680,6 +103696,26 @@ var pxt;
|
|
|
103680
103696
|
}
|
|
103681
103697
|
}
|
|
103682
103698
|
BrowserUtils.legacyCopyText = legacyCopyText;
|
|
103699
|
+
/**
|
|
103700
|
+
* Sets the theme of the application by adding a class to the body. Themes
|
|
103701
|
+
* are defined in CSS variable packs. The default theme is defined in
|
|
103702
|
+
* `themes/themepacks.less`, in the `:root` pseudoclass. `highcontrast` is
|
|
103703
|
+
* also defined there. Target-specific themes are defined in the target
|
|
103704
|
+
* repo's `theme/themepack.less`.
|
|
103705
|
+
*/
|
|
103706
|
+
function setApplicationTheme(theme) {
|
|
103707
|
+
const body = document.body;
|
|
103708
|
+
const classes = body.classList;
|
|
103709
|
+
for (let i = 0; i < classes.length; i++) {
|
|
103710
|
+
if (/^theme-/.test(classes[i])) {
|
|
103711
|
+
body.classList.remove(classes[i]);
|
|
103712
|
+
}
|
|
103713
|
+
}
|
|
103714
|
+
if (theme) {
|
|
103715
|
+
body.classList.add(`theme-${theme}`);
|
|
103716
|
+
}
|
|
103717
|
+
}
|
|
103718
|
+
BrowserUtils.setApplicationTheme = setApplicationTheme;
|
|
103683
103719
|
})(BrowserUtils = pxt.BrowserUtils || (pxt.BrowserUtils = {}));
|
|
103684
103720
|
})(pxt || (pxt = {}));
|
|
103685
103721
|
var pxt;
|
|
@@ -162971,8 +163007,13 @@ async function buildAndWatchTargetAsync(includeSourceMaps, rebundle) {
|
|
|
162971
163007
|
}
|
|
162972
163008
|
else {
|
|
162973
163009
|
console.log("rebuilding css");
|
|
162974
|
-
|
|
162975
|
-
|
|
163010
|
+
try {
|
|
163011
|
+
await buildSemanticUIAsync();
|
|
163012
|
+
console.log("css build complete");
|
|
163013
|
+
}
|
|
163014
|
+
catch (e) {
|
|
163015
|
+
console.error("css build failed", e);
|
|
163016
|
+
}
|
|
162976
163017
|
}
|
|
162977
163018
|
return lessFiles;
|
|
162978
163019
|
};
|
package/built/pxtblockly.js
CHANGED
|
@@ -7919,7 +7919,7 @@ var pxt;
|
|
|
7919
7919
|
const hasHandlers = hasArrowFunction(fn);
|
|
7920
7920
|
block.setPreviousStatement(!(hasHandlers && !fn.attributes.handlerStatement) && fn.retType == "void");
|
|
7921
7921
|
block.setNextStatement(!(hasHandlers && !fn.attributes.handlerStatement) && fn.retType == "void");
|
|
7922
|
-
block.setTooltip(/^__/.test(fn.namespace) ? "" : fn.attributes.jsDoc);
|
|
7922
|
+
block.setTooltip((/^__/.test(fn.namespace) ? "" : fn.attributes.jsDoc) + (pxt.blocks.showBlockIdInTooltip ? " (id: '" + fn.attributes.blockId + "')" : ""));
|
|
7923
7923
|
function buildBlockFromDef(def, expanded = false) {
|
|
7924
7924
|
let anonIndex = 0;
|
|
7925
7925
|
let firstParam = !expanded && !!comp.thisParameter;
|
|
@@ -11525,66 +11525,56 @@ var pxt;
|
|
|
11525
11525
|
(function (pxt) {
|
|
11526
11526
|
var blocks;
|
|
11527
11527
|
(function (blocks) {
|
|
11528
|
-
|
|
11529
|
-
|
|
11530
|
-
|
|
11531
|
-
|
|
11532
|
-
|
|
11533
|
-
|
|
11534
|
-
|
|
11535
|
-
|
|
11536
|
-
|
|
11537
|
-
|
|
11538
|
-
|
|
11539
|
-
|
|
11540
|
-
|
|
11541
|
-
|
|
11542
|
-
|
|
11543
|
-
|
|
11544
|
-
|
|
11545
|
-
|
|
11546
|
-
|
|
11547
|
-
|
|
11548
|
-
|
|
11549
|
-
|
|
11550
|
-
|
|
11528
|
+
const maxConcurrentChecks = 4;
|
|
11529
|
+
async function runValidatorPlanAsync(usedBlocks, plan) {
|
|
11530
|
+
// Each plan can have multiple checks it needs to run.
|
|
11531
|
+
// Run all of them in parallel, and then check if the number of successes is greater than the specified threshold.
|
|
11532
|
+
// TBD if it's faster to run in parallel without short-circuiting once the threshold is reached, or if it's faster to run sequentially and short-circuit.
|
|
11533
|
+
const startTime = Date.now();
|
|
11534
|
+
const checkRuns = pxt.Util.promisePoolAsync(maxConcurrentChecks, plan.checks, async (check) => {
|
|
11535
|
+
switch (check.validator) {
|
|
11536
|
+
case "blocksExist":
|
|
11537
|
+
return runBlocksExistValidation(usedBlocks, check);
|
|
11538
|
+
case "blockCommentsExist":
|
|
11539
|
+
return runValidateBlockCommentsExist(usedBlocks, check);
|
|
11540
|
+
case "specificBlockCommentsExist":
|
|
11541
|
+
return runValidateSpecificBlockCommentsExist(usedBlocks, check);
|
|
11542
|
+
case "blocksInSetExist":
|
|
11543
|
+
return runBlocksInSetExistValidation(usedBlocks, check);
|
|
11544
|
+
default:
|
|
11545
|
+
pxt.debug(`Unrecognized validator: ${check.validator}`);
|
|
11546
|
+
return false;
|
|
11547
|
+
}
|
|
11548
|
+
});
|
|
11549
|
+
const results = await checkRuns;
|
|
11550
|
+
const successCount = results.filter((r) => r).length;
|
|
11551
|
+
const passed = successCount >= plan.threshold;
|
|
11552
|
+
pxt.tickEvent("validation.evaluation_complete", {
|
|
11553
|
+
plan: plan.name,
|
|
11554
|
+
durationMs: Date.now() - startTime,
|
|
11555
|
+
passed: `${passed}`,
|
|
11556
|
+
});
|
|
11557
|
+
return passed;
|
|
11551
11558
|
}
|
|
11552
|
-
blocks.
|
|
11553
|
-
|
|
11554
|
-
|
|
11555
|
-
|
|
11556
|
-
|
|
11557
|
-
|
|
11558
|
-
|
|
11559
|
-
function getCriteria(data) {
|
|
11560
|
-
switch (data.criteriaId) {
|
|
11561
|
-
case "blockCheck":
|
|
11562
|
-
return new BlockCheckCriteria(data.displayText, data.blockRequirements);
|
|
11563
|
-
case "comment":
|
|
11564
|
-
return new CommentCriteria(data.displayText, data.count);
|
|
11565
|
-
default:
|
|
11566
|
-
console.error(`Unrecognized criteriaId: ${data.criteriaId}`);
|
|
11567
|
-
return null;
|
|
11568
|
-
}
|
|
11559
|
+
blocks.runValidatorPlanAsync = runValidatorPlanAsync;
|
|
11560
|
+
function runBlocksExistValidation(usedBlocks, inputs) {
|
|
11561
|
+
const blockResults = blocks.validateBlocksExist({ usedBlocks, requiredBlockCounts: inputs.blockCounts });
|
|
11562
|
+
const success = blockResults.disabledBlocks.length === 0 &&
|
|
11563
|
+
blockResults.missingBlocks.length === 0 &&
|
|
11564
|
+
blockResults.insufficientBlocks.length === 0;
|
|
11565
|
+
return success;
|
|
11569
11566
|
}
|
|
11570
|
-
|
|
11571
|
-
|
|
11572
|
-
|
|
11573
|
-
this.displayText = displayText;
|
|
11574
|
-
}
|
|
11567
|
+
function runValidateBlockCommentsExist(usedBlocks, inputs) {
|
|
11568
|
+
const blockResults = blocks.validateBlockCommentsExist({ usedBlocks, numRequired: inputs.count });
|
|
11569
|
+
return blockResults.passed;
|
|
11575
11570
|
}
|
|
11576
|
-
|
|
11577
|
-
|
|
11578
|
-
|
|
11579
|
-
super(displayText);
|
|
11580
|
-
this.blockRequirements = blockRequirements;
|
|
11581
|
-
}
|
|
11571
|
+
function runValidateSpecificBlockCommentsExist(usedBlocks, inputs) {
|
|
11572
|
+
const blockResults = blocks.validateSpecificBlockCommentsExist({ usedBlocks, blockType: inputs.blockType });
|
|
11573
|
+
return blockResults.passed;
|
|
11582
11574
|
}
|
|
11583
|
-
|
|
11584
|
-
|
|
11585
|
-
|
|
11586
|
-
this.count = count;
|
|
11587
|
-
}
|
|
11575
|
+
function runBlocksInSetExistValidation(usedBlocks, inputs) {
|
|
11576
|
+
const blockResults = blocks.validateBlocksInSetExist({ usedBlocks, blockIdsToCheck: inputs.blocks, count: inputs.count });
|
|
11577
|
+
return blockResults.passed;
|
|
11588
11578
|
}
|
|
11589
11579
|
})(blocks = pxt.blocks || (pxt.blocks = {}));
|
|
11590
11580
|
})(pxt || (pxt = {}));
|
|
@@ -11624,6 +11614,56 @@ var pxt;
|
|
|
11624
11614
|
blocks.validateBlocksExist = validateBlocksExist;
|
|
11625
11615
|
})(blocks = pxt.blocks || (pxt.blocks = {}));
|
|
11626
11616
|
})(pxt || (pxt = {}));
|
|
11617
|
+
var pxt;
|
|
11618
|
+
(function (pxt) {
|
|
11619
|
+
var blocks;
|
|
11620
|
+
(function (blocks) {
|
|
11621
|
+
// validates that a combination of blocks in the set satisfies the required count
|
|
11622
|
+
// returns the blocks that make the validator pass
|
|
11623
|
+
function validateBlocksInSetExist({ usedBlocks, blockIdsToCheck, count, requireUnique }) {
|
|
11624
|
+
const successfulBlocks = [];
|
|
11625
|
+
const enabledBlocks = usedBlocks.filter((block) => block.isEnabled());
|
|
11626
|
+
for (const block of blockIdsToCheck) {
|
|
11627
|
+
const blockInstances = enabledBlocks.filter((b) => b.type === block);
|
|
11628
|
+
if (requireUnique && blockInstances.length >= 1) {
|
|
11629
|
+
successfulBlocks.push(blockInstances[0]);
|
|
11630
|
+
}
|
|
11631
|
+
else {
|
|
11632
|
+
successfulBlocks.push(...blockInstances);
|
|
11633
|
+
}
|
|
11634
|
+
}
|
|
11635
|
+
return { successfulBlocks, passed: successfulBlocks.length >= count };
|
|
11636
|
+
}
|
|
11637
|
+
blocks.validateBlocksInSetExist = validateBlocksInSetExist;
|
|
11638
|
+
})(blocks = pxt.blocks || (pxt.blocks = {}));
|
|
11639
|
+
})(pxt || (pxt = {}));
|
|
11640
|
+
var pxt;
|
|
11641
|
+
(function (pxt) {
|
|
11642
|
+
var blocks;
|
|
11643
|
+
(function (blocks) {
|
|
11644
|
+
// validates that one or more blocks comments are in the project
|
|
11645
|
+
// returns the blocks that have comments for teacher tool scenario
|
|
11646
|
+
function validateBlockCommentsExist({ usedBlocks, numRequired }) {
|
|
11647
|
+
const commentedBlocks = usedBlocks.filter((block) => !!block.getCommentText());
|
|
11648
|
+
return { commentedBlocks, passed: commentedBlocks.length >= numRequired };
|
|
11649
|
+
}
|
|
11650
|
+
blocks.validateBlockCommentsExist = validateBlockCommentsExist;
|
|
11651
|
+
})(blocks = pxt.blocks || (pxt.blocks = {}));
|
|
11652
|
+
})(pxt || (pxt = {}));
|
|
11653
|
+
var pxt;
|
|
11654
|
+
(function (pxt) {
|
|
11655
|
+
var blocks;
|
|
11656
|
+
(function (blocks) {
|
|
11657
|
+
// validates that all of a specific block type have comments
|
|
11658
|
+
// returns the blocks that do not have comments for a tutorial validation scenario
|
|
11659
|
+
function validateSpecificBlockCommentsExist({ usedBlocks, blockType }) {
|
|
11660
|
+
const allSpecifcBlocks = usedBlocks.filter((block) => block.type === blockType);
|
|
11661
|
+
const uncommentedBlocks = allSpecifcBlocks.filter((block) => !block.getCommentText());
|
|
11662
|
+
return { uncommentedBlocks, passed: uncommentedBlocks.length === 0 };
|
|
11663
|
+
}
|
|
11664
|
+
blocks.validateSpecificBlockCommentsExist = validateSpecificBlockCommentsExist;
|
|
11665
|
+
})(blocks = pxt.blocks || (pxt.blocks = {}));
|
|
11666
|
+
})(pxt || (pxt = {}));
|
|
11627
11667
|
var pxtblockly;
|
|
11628
11668
|
(function (pxtblockly) {
|
|
11629
11669
|
class FieldBase extends Blockly.Field {
|
package/built/pxtblocks.d.ts
CHANGED
|
@@ -393,30 +393,12 @@ declare namespace pxt.blocks {
|
|
|
393
393
|
function initMathRoundBlock(): void;
|
|
394
394
|
}
|
|
395
395
|
declare namespace pxt.blocks {
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
constructor(criteria: RubricCriteria[]);
|
|
396
|
+
interface EvaluationResult {
|
|
397
|
+
result: boolean;
|
|
399
398
|
}
|
|
400
|
-
function parseRubric(rubric: string): Rubric;
|
|
401
399
|
}
|
|
402
400
|
declare namespace pxt.blocks {
|
|
403
|
-
|
|
404
|
-
blocks: string[];
|
|
405
|
-
count: number;
|
|
406
|
-
}
|
|
407
|
-
export interface CriteriaData {
|
|
408
|
-
criteriaId: string;
|
|
409
|
-
displayText: string;
|
|
410
|
-
blockRequirements?: BlockSet[];
|
|
411
|
-
count?: number;
|
|
412
|
-
}
|
|
413
|
-
export function getCriteria(data: CriteriaData): RubricCriteria;
|
|
414
|
-
export abstract class RubricCriteria {
|
|
415
|
-
displayText: string;
|
|
416
|
-
abstract criteriaId: string;
|
|
417
|
-
constructor(displayText: string);
|
|
418
|
-
}
|
|
419
|
-
export {};
|
|
401
|
+
function runValidatorPlanAsync(usedBlocks: Blockly.Block[], plan: ValidatorPlan): Promise<boolean>;
|
|
420
402
|
}
|
|
421
403
|
declare namespace pxt.blocks {
|
|
422
404
|
function validateBlocksExist({ usedBlocks, requiredBlockCounts }: {
|
|
@@ -428,6 +410,62 @@ declare namespace pxt.blocks {
|
|
|
428
410
|
insufficientBlocks: string[];
|
|
429
411
|
};
|
|
430
412
|
}
|
|
413
|
+
declare namespace pxt.blocks {
|
|
414
|
+
function validateBlocksInSetExist({ usedBlocks, blockIdsToCheck, count, requireUnique }: {
|
|
415
|
+
usedBlocks: Blockly.Block[];
|
|
416
|
+
blockIdsToCheck: string[];
|
|
417
|
+
count: number;
|
|
418
|
+
requireUnique?: boolean;
|
|
419
|
+
}): {
|
|
420
|
+
successfulBlocks: Blockly.Block[];
|
|
421
|
+
passed: boolean;
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
declare namespace pxt.blocks {
|
|
425
|
+
function validateBlockCommentsExist({ usedBlocks, numRequired }: {
|
|
426
|
+
usedBlocks: Blockly.Block[];
|
|
427
|
+
numRequired: number;
|
|
428
|
+
}): {
|
|
429
|
+
commentedBlocks: Blockly.Block[];
|
|
430
|
+
passed: boolean;
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
declare namespace pxt.blocks {
|
|
434
|
+
function validateSpecificBlockCommentsExist({ usedBlocks, blockType }: {
|
|
435
|
+
usedBlocks: Blockly.Block[];
|
|
436
|
+
blockType: string;
|
|
437
|
+
}): {
|
|
438
|
+
uncommentedBlocks: Blockly.Block[];
|
|
439
|
+
passed: boolean;
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
declare namespace pxt.blocks {
|
|
443
|
+
interface ValidatorPlan {
|
|
444
|
+
name: string;
|
|
445
|
+
threshold: number;
|
|
446
|
+
checks: ValidatorCheckBase[];
|
|
447
|
+
}
|
|
448
|
+
interface ValidatorCheckBase {
|
|
449
|
+
validator: string;
|
|
450
|
+
}
|
|
451
|
+
interface BlocksExistValidatorCheck extends ValidatorCheckBase {
|
|
452
|
+
validator: "blocksExist";
|
|
453
|
+
blockCounts: pxt.Map<number>;
|
|
454
|
+
}
|
|
455
|
+
interface BlockCommentsExistValidatorCheck extends ValidatorCheckBase {
|
|
456
|
+
validator: "blockCommentsExist";
|
|
457
|
+
count: number;
|
|
458
|
+
}
|
|
459
|
+
interface SpecificBlockCommentsExistValidatorCheck extends ValidatorCheckBase {
|
|
460
|
+
validator: "specificBlockCommentsExist";
|
|
461
|
+
blockType: string;
|
|
462
|
+
}
|
|
463
|
+
interface BlocksInSetExistValidatorCheck extends ValidatorCheckBase {
|
|
464
|
+
validator: "blocksInSetExist";
|
|
465
|
+
blocks: string[];
|
|
466
|
+
count: number;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
431
469
|
declare namespace pxtblockly {
|
|
432
470
|
abstract class FieldBase<U> extends Blockly.Field implements Blockly.FieldCustom {
|
|
433
471
|
isFieldCustom_: true;
|
package/built/pxtblocks.js
CHANGED
|
@@ -4357,7 +4357,7 @@ var pxt;
|
|
|
4357
4357
|
const hasHandlers = hasArrowFunction(fn);
|
|
4358
4358
|
block.setPreviousStatement(!(hasHandlers && !fn.attributes.handlerStatement) && fn.retType == "void");
|
|
4359
4359
|
block.setNextStatement(!(hasHandlers && !fn.attributes.handlerStatement) && fn.retType == "void");
|
|
4360
|
-
block.setTooltip(/^__/.test(fn.namespace) ? "" : fn.attributes.jsDoc);
|
|
4360
|
+
block.setTooltip((/^__/.test(fn.namespace) ? "" : fn.attributes.jsDoc) + (pxt.blocks.showBlockIdInTooltip ? " (id: '" + fn.attributes.blockId + "')" : ""));
|
|
4361
4361
|
function buildBlockFromDef(def, expanded = false) {
|
|
4362
4362
|
let anonIndex = 0;
|
|
4363
4363
|
let firstParam = !expanded && !!comp.thisParameter;
|
|
@@ -7963,66 +7963,56 @@ var pxt;
|
|
|
7963
7963
|
(function (pxt) {
|
|
7964
7964
|
var blocks;
|
|
7965
7965
|
(function (blocks) {
|
|
7966
|
-
|
|
7967
|
-
|
|
7968
|
-
|
|
7969
|
-
|
|
7970
|
-
|
|
7971
|
-
|
|
7972
|
-
|
|
7973
|
-
|
|
7974
|
-
|
|
7975
|
-
|
|
7976
|
-
|
|
7977
|
-
|
|
7978
|
-
|
|
7979
|
-
|
|
7980
|
-
|
|
7981
|
-
|
|
7982
|
-
|
|
7983
|
-
|
|
7984
|
-
|
|
7985
|
-
|
|
7986
|
-
|
|
7987
|
-
|
|
7988
|
-
|
|
7966
|
+
const maxConcurrentChecks = 4;
|
|
7967
|
+
async function runValidatorPlanAsync(usedBlocks, plan) {
|
|
7968
|
+
// Each plan can have multiple checks it needs to run.
|
|
7969
|
+
// Run all of them in parallel, and then check if the number of successes is greater than the specified threshold.
|
|
7970
|
+
// TBD if it's faster to run in parallel without short-circuiting once the threshold is reached, or if it's faster to run sequentially and short-circuit.
|
|
7971
|
+
const startTime = Date.now();
|
|
7972
|
+
const checkRuns = pxt.Util.promisePoolAsync(maxConcurrentChecks, plan.checks, async (check) => {
|
|
7973
|
+
switch (check.validator) {
|
|
7974
|
+
case "blocksExist":
|
|
7975
|
+
return runBlocksExistValidation(usedBlocks, check);
|
|
7976
|
+
case "blockCommentsExist":
|
|
7977
|
+
return runValidateBlockCommentsExist(usedBlocks, check);
|
|
7978
|
+
case "specificBlockCommentsExist":
|
|
7979
|
+
return runValidateSpecificBlockCommentsExist(usedBlocks, check);
|
|
7980
|
+
case "blocksInSetExist":
|
|
7981
|
+
return runBlocksInSetExistValidation(usedBlocks, check);
|
|
7982
|
+
default:
|
|
7983
|
+
pxt.debug(`Unrecognized validator: ${check.validator}`);
|
|
7984
|
+
return false;
|
|
7985
|
+
}
|
|
7986
|
+
});
|
|
7987
|
+
const results = await checkRuns;
|
|
7988
|
+
const successCount = results.filter((r) => r).length;
|
|
7989
|
+
const passed = successCount >= plan.threshold;
|
|
7990
|
+
pxt.tickEvent("validation.evaluation_complete", {
|
|
7991
|
+
plan: plan.name,
|
|
7992
|
+
durationMs: Date.now() - startTime,
|
|
7993
|
+
passed: `${passed}`,
|
|
7994
|
+
});
|
|
7995
|
+
return passed;
|
|
7989
7996
|
}
|
|
7990
|
-
blocks.
|
|
7991
|
-
|
|
7992
|
-
|
|
7993
|
-
|
|
7994
|
-
|
|
7995
|
-
|
|
7996
|
-
|
|
7997
|
-
function getCriteria(data) {
|
|
7998
|
-
switch (data.criteriaId) {
|
|
7999
|
-
case "blockCheck":
|
|
8000
|
-
return new BlockCheckCriteria(data.displayText, data.blockRequirements);
|
|
8001
|
-
case "comment":
|
|
8002
|
-
return new CommentCriteria(data.displayText, data.count);
|
|
8003
|
-
default:
|
|
8004
|
-
console.error(`Unrecognized criteriaId: ${data.criteriaId}`);
|
|
8005
|
-
return null;
|
|
8006
|
-
}
|
|
7997
|
+
blocks.runValidatorPlanAsync = runValidatorPlanAsync;
|
|
7998
|
+
function runBlocksExistValidation(usedBlocks, inputs) {
|
|
7999
|
+
const blockResults = blocks.validateBlocksExist({ usedBlocks, requiredBlockCounts: inputs.blockCounts });
|
|
8000
|
+
const success = blockResults.disabledBlocks.length === 0 &&
|
|
8001
|
+
blockResults.missingBlocks.length === 0 &&
|
|
8002
|
+
blockResults.insufficientBlocks.length === 0;
|
|
8003
|
+
return success;
|
|
8007
8004
|
}
|
|
8008
|
-
|
|
8009
|
-
|
|
8010
|
-
|
|
8011
|
-
this.displayText = displayText;
|
|
8012
|
-
}
|
|
8005
|
+
function runValidateBlockCommentsExist(usedBlocks, inputs) {
|
|
8006
|
+
const blockResults = blocks.validateBlockCommentsExist({ usedBlocks, numRequired: inputs.count });
|
|
8007
|
+
return blockResults.passed;
|
|
8013
8008
|
}
|
|
8014
|
-
|
|
8015
|
-
|
|
8016
|
-
|
|
8017
|
-
super(displayText);
|
|
8018
|
-
this.blockRequirements = blockRequirements;
|
|
8019
|
-
}
|
|
8009
|
+
function runValidateSpecificBlockCommentsExist(usedBlocks, inputs) {
|
|
8010
|
+
const blockResults = blocks.validateSpecificBlockCommentsExist({ usedBlocks, blockType: inputs.blockType });
|
|
8011
|
+
return blockResults.passed;
|
|
8020
8012
|
}
|
|
8021
|
-
|
|
8022
|
-
|
|
8023
|
-
|
|
8024
|
-
this.count = count;
|
|
8025
|
-
}
|
|
8013
|
+
function runBlocksInSetExistValidation(usedBlocks, inputs) {
|
|
8014
|
+
const blockResults = blocks.validateBlocksInSetExist({ usedBlocks, blockIdsToCheck: inputs.blocks, count: inputs.count });
|
|
8015
|
+
return blockResults.passed;
|
|
8026
8016
|
}
|
|
8027
8017
|
})(blocks = pxt.blocks || (pxt.blocks = {}));
|
|
8028
8018
|
})(pxt || (pxt = {}));
|
|
@@ -8062,6 +8052,56 @@ var pxt;
|
|
|
8062
8052
|
blocks.validateBlocksExist = validateBlocksExist;
|
|
8063
8053
|
})(blocks = pxt.blocks || (pxt.blocks = {}));
|
|
8064
8054
|
})(pxt || (pxt = {}));
|
|
8055
|
+
var pxt;
|
|
8056
|
+
(function (pxt) {
|
|
8057
|
+
var blocks;
|
|
8058
|
+
(function (blocks) {
|
|
8059
|
+
// validates that a combination of blocks in the set satisfies the required count
|
|
8060
|
+
// returns the blocks that make the validator pass
|
|
8061
|
+
function validateBlocksInSetExist({ usedBlocks, blockIdsToCheck, count, requireUnique }) {
|
|
8062
|
+
const successfulBlocks = [];
|
|
8063
|
+
const enabledBlocks = usedBlocks.filter((block) => block.isEnabled());
|
|
8064
|
+
for (const block of blockIdsToCheck) {
|
|
8065
|
+
const blockInstances = enabledBlocks.filter((b) => b.type === block);
|
|
8066
|
+
if (requireUnique && blockInstances.length >= 1) {
|
|
8067
|
+
successfulBlocks.push(blockInstances[0]);
|
|
8068
|
+
}
|
|
8069
|
+
else {
|
|
8070
|
+
successfulBlocks.push(...blockInstances);
|
|
8071
|
+
}
|
|
8072
|
+
}
|
|
8073
|
+
return { successfulBlocks, passed: successfulBlocks.length >= count };
|
|
8074
|
+
}
|
|
8075
|
+
blocks.validateBlocksInSetExist = validateBlocksInSetExist;
|
|
8076
|
+
})(blocks = pxt.blocks || (pxt.blocks = {}));
|
|
8077
|
+
})(pxt || (pxt = {}));
|
|
8078
|
+
var pxt;
|
|
8079
|
+
(function (pxt) {
|
|
8080
|
+
var blocks;
|
|
8081
|
+
(function (blocks) {
|
|
8082
|
+
// validates that one or more blocks comments are in the project
|
|
8083
|
+
// returns the blocks that have comments for teacher tool scenario
|
|
8084
|
+
function validateBlockCommentsExist({ usedBlocks, numRequired }) {
|
|
8085
|
+
const commentedBlocks = usedBlocks.filter((block) => !!block.getCommentText());
|
|
8086
|
+
return { commentedBlocks, passed: commentedBlocks.length >= numRequired };
|
|
8087
|
+
}
|
|
8088
|
+
blocks.validateBlockCommentsExist = validateBlockCommentsExist;
|
|
8089
|
+
})(blocks = pxt.blocks || (pxt.blocks = {}));
|
|
8090
|
+
})(pxt || (pxt = {}));
|
|
8091
|
+
var pxt;
|
|
8092
|
+
(function (pxt) {
|
|
8093
|
+
var blocks;
|
|
8094
|
+
(function (blocks) {
|
|
8095
|
+
// validates that all of a specific block type have comments
|
|
8096
|
+
// returns the blocks that do not have comments for a tutorial validation scenario
|
|
8097
|
+
function validateSpecificBlockCommentsExist({ usedBlocks, blockType }) {
|
|
8098
|
+
const allSpecifcBlocks = usedBlocks.filter((block) => block.type === blockType);
|
|
8099
|
+
const uncommentedBlocks = allSpecifcBlocks.filter((block) => !block.getCommentText());
|
|
8100
|
+
return { uncommentedBlocks, passed: uncommentedBlocks.length === 0 };
|
|
8101
|
+
}
|
|
8102
|
+
blocks.validateSpecificBlockCommentsExist = validateSpecificBlockCommentsExist;
|
|
8103
|
+
})(blocks = pxt.blocks || (pxt.blocks = {}));
|
|
8104
|
+
})(pxt || (pxt = {}));
|
|
8065
8105
|
var pxtblockly;
|
|
8066
8106
|
(function (pxtblockly) {
|
|
8067
8107
|
class FieldBase extends Blockly.Field {
|
package/built/pxteditor.d.ts
CHANGED
|
@@ -304,6 +304,7 @@ declare namespace pxt.editor {
|
|
|
304
304
|
blocksScreenshotAsync(pixelDensity?: number, encodeBlocks?: boolean): Promise<string>;
|
|
305
305
|
renderBlocksAsync(req: EditorMessageRenderBlocksRequest): Promise<EditorMessageRenderBlocksResponse>;
|
|
306
306
|
renderPythonAsync(req: EditorMessageRenderPythonRequest): Promise<EditorMessageRenderPythonResponse>;
|
|
307
|
+
getBlocks(): Blockly.Block[];
|
|
307
308
|
toggleHighContrast(): void;
|
|
308
309
|
setHighContrast(on: boolean): void;
|
|
309
310
|
toggleGreenScreen(): void;
|
|
@@ -562,7 +563,7 @@ declare namespace pxt.editor {
|
|
|
562
563
|
/**
|
|
563
564
|
* Request action
|
|
564
565
|
*/
|
|
565
|
-
action: "switchblocks" | "switchjavascript" | "startsimulator" | "restartsimulator" | "stopsimulator" | "hidesimulator" | "showsimulator" | "closeflyout" | "newproject" | "importproject" | "importtutorial" | "openheader" | "proxytosim" | "undo" | "redo" | "renderblocks" | "renderpython" | "setscale" | "startactivity" | "saveproject" | "unloadproject" | "shareproject" | "savelocalprojectstocloud" | "projectcloudstatus" | "requestprojectcloudstatus" | "convertcloudprojectstolocal" | "setlanguagerestriction" | "toggletrace" | "togglehighcontrast" | "sethighcontrast" | "togglegreenscreen" | "settracestate" | "setsimulatorfullscreen" | "print" | "pair" | "workspacesync" | "workspacereset" | "workspacesave" | "workspaceloaded" | "workspaceevent" | "workspacediagnostics" | "event" | "simevent" | "info" | "tutorialevent" | "editorcontentloaded" | ExtInitializeType | ExtDataStreamType | ExtUserCodeType | ExtReadCodeType | ExtWriteCodeType;
|
|
566
|
+
action: "switchblocks" | "switchjavascript" | "startsimulator" | "restartsimulator" | "stopsimulator" | "hidesimulator" | "showsimulator" | "closeflyout" | "newproject" | "importproject" | "importtutorial" | "openheader" | "proxytosim" | "undo" | "redo" | "renderblocks" | "renderpython" | "setscale" | "startactivity" | "saveproject" | "unloadproject" | "shareproject" | "savelocalprojectstocloud" | "projectcloudstatus" | "requestprojectcloudstatus" | "convertcloudprojectstolocal" | "setlanguagerestriction" | "toggletrace" | "togglehighcontrast" | "sethighcontrast" | "togglegreenscreen" | "settracestate" | "setsimulatorfullscreen" | "print" | "pair" | "workspacesync" | "workspacereset" | "workspacesave" | "workspaceloaded" | "workspaceevent" | "workspacediagnostics" | "event" | "simevent" | "info" | "tutorialevent" | "editorcontentloaded" | "runeval" | ExtInitializeType | ExtDataStreamType | ExtUserCodeType | ExtReadCodeType | ExtWriteCodeType;
|
|
566
567
|
}
|
|
567
568
|
/**
|
|
568
569
|
* Request sent by the editor when a tick/error/expection is registered
|
|
@@ -710,6 +711,10 @@ declare namespace pxt.editor {
|
|
|
710
711
|
snippetMode?: boolean;
|
|
711
712
|
layout?: pxt.blocks.BlockLayout;
|
|
712
713
|
}
|
|
714
|
+
interface EditorMessageRunEvalRequest extends EditorMessageRequest {
|
|
715
|
+
action: "runeval";
|
|
716
|
+
validatorPlan: pxt.blocks.ValidatorPlan;
|
|
717
|
+
}
|
|
713
718
|
interface EditorMessageRenderBlocksResponse {
|
|
714
719
|
svg: SVGSVGElement;
|
|
715
720
|
xml: Promise<any>;
|
package/built/pxteditor.js
CHANGED
|
@@ -210,6 +210,18 @@ var pxt;
|
|
|
210
210
|
});
|
|
211
211
|
});
|
|
212
212
|
}
|
|
213
|
+
case "runeval": {
|
|
214
|
+
const evalmsg = data;
|
|
215
|
+
const plan = evalmsg.validatorPlan;
|
|
216
|
+
return Promise.resolve()
|
|
217
|
+
.then(() => {
|
|
218
|
+
const blocks = projectView.getBlocks();
|
|
219
|
+
return pxt.blocks.runValidatorPlanAsync(blocks, plan);
|
|
220
|
+
})
|
|
221
|
+
.then(results => {
|
|
222
|
+
resp = { result: results };
|
|
223
|
+
});
|
|
224
|
+
}
|
|
213
225
|
case "renderpython": {
|
|
214
226
|
const rendermsg = data;
|
|
215
227
|
return Promise.resolve()
|
package/built/pxtlib.d.ts
CHANGED
|
@@ -632,6 +632,7 @@ declare namespace pxt {
|
|
|
632
632
|
function isOutputText(trg?: pxtc.CompileTarget): boolean;
|
|
633
633
|
}
|
|
634
634
|
declare namespace pxt.blocks {
|
|
635
|
+
let showBlockIdInTooltip: boolean;
|
|
635
636
|
const MATH_FUNCTIONS: {
|
|
636
637
|
unary: string[];
|
|
637
638
|
binary: string[];
|
|
@@ -888,6 +889,14 @@ declare namespace pxt.BrowserUtils {
|
|
|
888
889
|
export function setCookieLang(langId: string, docs?: boolean): void;
|
|
889
890
|
export function cacheBustingUrl(url: string): string;
|
|
890
891
|
export function legacyCopyText(element: HTMLInputElement | HTMLTextAreaElement): boolean;
|
|
892
|
+
/**
|
|
893
|
+
* Sets the theme of the application by adding a class to the body. Themes
|
|
894
|
+
* are defined in CSS variable packs. The default theme is defined in
|
|
895
|
+
* `themes/themepacks.less`, in the `:root` pseudoclass. `highcontrast` is
|
|
896
|
+
* also defined there. Target-specific themes are defined in the target
|
|
897
|
+
* repo's `theme/themepack.less`.
|
|
898
|
+
*/
|
|
899
|
+
export function setApplicationTheme(theme: string | undefined): void;
|
|
891
900
|
export {};
|
|
892
901
|
}
|
|
893
902
|
declare namespace pxt.cloud {
|