derw
Version:
An Elm-inspired language that transpiles to TypeScript
320 lines (319 loc) • 9.71 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.addMissingNamesSuggestions = exports.namesPerBlock = exports.definedNamesPerBlock = exports.topLevelNamesPerBlock = void 0;
const distance_1 = require("./distance");
function isNumberLiteral(value) {
return !isNaN(parseInt(value.body, 10));
}
function isBoolean(value) {
return value.body === "true" || value.body === "false";
}
function namesPerExpression(expression) {
switch (expression.kind) {
case "Value":
if (isNumberLiteral(expression) || isBoolean(expression)) {
return [];
}
return [expression.body];
case "StringValue":
return [];
case "FormatStringValue":
return [];
case "ListValue": {
let results = [];
for (const innerExpression of expression.items) {
results = results.concat(namesPerExpression(innerExpression));
}
return results;
}
case "ListRange": {
return [
...namesPerExpression(expression.start),
...namesPerExpression(expression.end),
];
}
case "ObjectLiteral":
return [];
case "IfStatement":
return [
...namesPerExpression(expression.ifBody),
...namesPerExpression(expression.elseBody),
...namesPerExpression(expression.predicate),
];
case "CaseStatement": {
return [...namesPerExpression(expression.predicate)];
}
case "Addition":
return [
...namesPerExpression(expression.left),
...namesPerExpression(expression.right),
];
case "Subtraction":
return [
...namesPerExpression(expression.left),
...namesPerExpression(expression.right),
];
case "Multiplication":
return [
...namesPerExpression(expression.left),
...namesPerExpression(expression.right),
];
case "Division":
return [
...namesPerExpression(expression.left),
...namesPerExpression(expression.right),
];
case "Mod":
return [
...namesPerExpression(expression.left),
...namesPerExpression(expression.right),
];
case "And":
return [
...namesPerExpression(expression.left),
...namesPerExpression(expression.right),
];
case "Or":
return [
...namesPerExpression(expression.left),
...namesPerExpression(expression.right),
];
case "ListPrepend":
return [
...namesPerExpression(expression.left),
...namesPerExpression(expression.right),
];
case "LeftPipe":
return [
...namesPerExpression(expression.left),
...namesPerExpression(expression.right),
];
case "RightPipe":
return [
...namesPerExpression(expression.left),
...namesPerExpression(expression.right),
];
case "ModuleReference":
return [
expression.path.join(".") +
"." +
namesPerExpression(expression.value),
];
case "FunctionCall": {
let results = [expression.name];
for (const innerExpression of expression.args) {
results = results.concat(namesPerExpression(innerExpression));
}
return results;
}
case "Lambda": {
return [];
// return [
// ...expression.args,
// ...namesPerExpression(expression.body),
// ];
}
case "LambdaCall":
return [];
case "Constructor":
return [];
case "Equality":
return [
...namesPerExpression(expression.left),
...namesPerExpression(expression.right),
];
case "InEquality":
return [
...namesPerExpression(expression.left),
...namesPerExpression(expression.right),
];
case "LessThan":
return [
...namesPerExpression(expression.left),
...namesPerExpression(expression.right),
];
case "LessThanOrEqual":
return [
...namesPerExpression(expression.left),
...namesPerExpression(expression.right),
];
case "GreaterThan":
return [
...namesPerExpression(expression.left),
...namesPerExpression(expression.right),
];
case "GreaterThanOrEqual":
return [
...namesPerExpression(expression.left),
...namesPerExpression(expression.right),
];
}
}
function topLevelNamesPerBlock(block) {
switch (block.kind) {
case "Comment": {
return [];
}
case "Const": {
return [block.name];
}
case "Export": {
return [];
}
case "Function": {
return [block.name];
}
case "Import": {
let results = [];
for (const module of block.modules) {
results = results.concat(module.exposing);
}
return results;
}
case "MultilineComment": {
return [];
}
case "TypeAlias": {
return [];
}
case "Typeclass": {
return [];
}
case "Impl": {
return [];
}
case "UnionType": {
return [];
}
case "UnionUntaggedType": {
return [];
}
}
}
exports.topLevelNamesPerBlock = topLevelNamesPerBlock;
function definedNamesPerBlock(block) {
switch (block.kind) {
case "Comment": {
return [];
}
case "Const": {
return [block.name];
}
case "Export": {
return [];
}
case "Function": {
let results = [block.name];
for (const arg of block.args) {
if (arg.kind === "FunctionArg") {
results.push(arg.name);
}
else {
results.push(`${arg.index}`);
}
}
for (const letBlock of block.letBody) {
results = results.concat(definedNamesPerBlock(letBlock));
}
return results;
}
case "Import": {
return [];
}
case "MultilineComment": {
return [];
}
case "TypeAlias": {
return [];
}
case "Typeclass": {
return [];
}
case "Impl": {
return [];
}
case "UnionType": {
return [];
}
case "UnionUntaggedType": {
return [];
}
}
}
exports.definedNamesPerBlock = definedNamesPerBlock;
function namesPerBlock(block) {
switch (block.kind) {
case "Comment": {
return [];
}
case "Const": {
return [block.name, ...namesPerExpression(block.value)];
}
case "Export": {
return [];
}
case "Function": {
return [block.name, ...namesPerExpression(block.body)];
}
case "Import": {
return [];
}
case "MultilineComment": {
return [];
}
case "TypeAlias": {
return [];
}
case "Typeclass": {
return [];
}
case "Impl": {
return [];
}
case "UnionType": {
return [];
}
case "UnionUntaggedType": {
return [];
}
}
}
exports.namesPerBlock = namesPerBlock;
function isGlobal(str) {
if (str.split(".")[0] === "globalThis") {
return true;
}
return false;
}
function addMissingNamesSuggestions(module) {
let topLevelNames = [];
for (const names of module.body.map(topLevelNamesPerBlock)) {
topLevelNames = topLevelNames.concat(names);
}
const nameSuggestions = [];
module.body.forEach((block) => {
const blockName = (block.kind === "Function" && block.name) ||
(block.kind === "Const" && block.name);
namesPerBlock(block).forEach((name) => {
if (isGlobal(name)) {
return;
}
const knownNames = [
...topLevelNames,
...definedNamesPerBlock(block),
];
if (knownNames.indexOf(name) === -1) {
const suggestions = (0, distance_1.suggestName)(name, knownNames);
if (suggestions.length > 0) {
nameSuggestions.push(`Couldn't find \`${name}\` in the scope of \`${blockName}\`. Perhaps you meant: ${suggestions.join(", ")}?`);
}
else {
nameSuggestions.push(`Failed to find \`${name}\` in the scope of \`${blockName}\`.`);
}
}
});
});
module.errors = module.errors.concat(nameSuggestions);
return module;
}
exports.addMissingNamesSuggestions = addMissingNamesSuggestions;