-
Notifications
You must be signed in to change notification settings - Fork 596
/
Copy pathvalidateVariableUsage.ts
55 lines (50 loc) · 1.91 KB
/
validateVariableUsage.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/// <reference path="../../localtypings/pxtpackage.d.ts" />
import * as Blockly from "blockly";
// Validates that variables are created and used within the workspace.
// Name is optional. If undefined or empty, all variable names are permitted.
// Returns the definition blocks for variables that passed the check.
export function validateVariableUsage({
usedBlocks,
count,
name,
}: {
usedBlocks: Blockly.Block[];
count: number;
name?: String;
}): {
passingVarDefinitions: Map<string, Blockly.Block[]>;
passed: boolean;
} {
const varDefinitionBlocks: Map<string, Blockly.Block[]> = new Map();
const usedVars: Set<string> = new Set();
for (const block of usedBlocks) {
if (!block.isEnabled()) {
continue;
}
const varsUsed = block.getVarModels();
for (const varModel of varsUsed ?? []) {
const varName = varModel.name;
if (!name || varName === name) {
if (block.type === "variables_set" || block.type === "variables_change") {
// Variable created
if (!varDefinitionBlocks.has(varName)) {
varDefinitionBlocks.set(varName, []);
}
varDefinitionBlocks.get(varName).push(block);
} else {
// Variable used
usedVars.add(varName);
}
}
}
}
// Var passes check if it is both used and defined.
// We return the definition blocks to allow for recursively checking how the var was set.
const passingVarDefinitions = new Map<string, Blockly.Block[]>();
for (const [varName, definitionBlocks] of varDefinitionBlocks) {
if (usedVars.has(varName)) {
passingVarDefinitions.set(varName, definitionBlocks);
}
}
return { passingVarDefinitions, passed: passingVarDefinitions.size >= count };
}