derw
Version:
An Elm-inspired language that transpiles to TypeScript
197 lines (165 loc) • 5.54 kB
text/typescript
import {
allErrors,
bothFlag,
empty,
help,
longFlag,
parse,
parser,
string,
} from "@eeue56/baner";
import { withDefault } from "@eeue56/ts-core/build/main/lib/maybe";
import {
Const,
ContextModule,
Export,
Function,
Import,
ImportModule,
TypeAlias,
UnionType,
} from "../types";
import { compileFiles } from "./compile";
const infoParser = parser([
longFlag(
"file",
"name of a particular file to get info about e.g src/Html.derw",
string()
),
bothFlag("h", "help", "This help text", empty()),
]);
function showInfoHelp() {
console.log(help(infoParser));
}
function importModuleInfo(module: ImportModule): void {
const aliasExtra = withDefault(module.name, module.alias);
console.log(`Importing ${module.name} as ${aliasExtra}`);
if (module.exposing.length > 0) {
console.log(`Exposing ${module.exposing.join(", ")}`);
}
}
function moduleInfo(fileName: string, module: ContextModule): void {
console.log(`Analyizing ${fileName}...`);
const imports = module.body.filter((b) => b.kind === "Import") as Import[];
console.log(`Imports ${imports.length} modules...`);
for (const import_ of imports) {
for (const module_ of import_.modules) {
importModuleInfo(module_);
console.log("------------------------");
}
}
const exportBlocks = module.body.filter(
(b) => b.kind === "Export"
) as Export[];
let exportNames: string[] = [ ];
for (const export_ of exportBlocks) {
exportNames = exportNames.concat(export_.names);
}
console.log(`Exports ${exportNames.length} values and functions...`);
if (exportNames.length > 0) {
console.log(`${exportNames.join(", ")}`);
}
console.log("------------------------");
const functionNames = (
module.body.filter((b) => b.kind === "Function") as Function[]
).map((f) => f.name);
const nonExportedFunctionNames = functionNames.filter(
(f) => exportNames.indexOf(f) === -1
);
console.log("Unexported functions");
console.log(nonExportedFunctionNames.join(", "));
console.log("------------------------");
const constNames = (
module.body.filter((b) => b.kind === "Const") as Const[]
).map((f) => f.name);
const nonExportedConstNames = constNames.filter(
(f) => exportNames.indexOf(f) === -1
);
console.log("Unexported consts");
console.log(nonExportedConstNames.join(", "));
console.log("------------------------");
const missingUnionTypes = [ ];
const unionTypes = module.body.filter(
(b) => b.kind === "UnionType"
) as UnionType[];
for (const unionType of unionTypes) {
const isRootTypeExported =
exportNames.indexOf(unionType.type.name) > -1;
const missingTagNames = [ ];
for (const tag of unionType.tags) {
if (exportNames.indexOf(tag.name) === -1) {
missingTagNames.push(tag.name);
}
}
if (!isRootTypeExported || missingTagNames.length > 0) {
if (isRootTypeExported) {
missingUnionTypes.push(
`Type ${
unionType.type.name
} is exported but the constructors ${missingTagNames.join(
", "
)} are not`
);
} else {
missingUnionTypes.push(
`${unionType.type.name}(${missingTagNames.join(", ")})`
);
}
}
}
console.log("Unexported union types");
console.log(missingUnionTypes.join("\n "));
console.log("------------------------");
const typeAliasNames = (
module.body.filter((b) => b.kind === "TypeAlias") as TypeAlias[]
).map((f) => f.type.name);
const nonExportedTypeAliasNames = typeAliasNames.filter(
(f) => exportNames.indexOf(f) === -1
);
console.log("Unexported type aliases");
console.log(nonExportedTypeAliasNames.join(", "));
console.log("------------------------");
}
export async function info(
isInPackageDirectory: boolean,
argv: string[]
): Promise<void> {
const program = parse(infoParser, argv);
if (program.flags["h/help"].isPresent) {
showInfoHelp();
return;
}
const errors = allErrors(program);
if (errors.length > 0) {
console.log("Errors:");
console.log(errors.join("\n"));
process.exit(1);
}
const fileNameToParse =
program.flags.file.isPresent &&
program.flags.file.arguments.kind === "Ok" &&
(program.flags.file.arguments.value as string);
if (!isInPackageDirectory && !fileNameToParse) {
console.log(
"No derw-package.json found. Maybe you need to run `derw init` first?"
);
console.log("Or provide a file to analyize via --file.");
process.exit(1);
}
let parsedFiles;
if (fileNameToParse) {
parsedFiles = await compileFiles(isInPackageDirectory, [
"--files",
fileNameToParse,
"--quiet",
]);
} else {
parsedFiles = await compileFiles(isInPackageDirectory, [ "--quiet" ]);
}
for (const fileName of Object.keys(parsedFiles)) {
if (fileNameToParse && fileNameToParse !== fileName) {
continue;
}
moduleInfo(fileName, parsedFiles[fileName]);
}
}