Comparing version 0.0.6-0 to 0.0.6
#!/usr/bin/env ts-node | ||
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
}) : function(o, v) { | ||
o["default"] = v; | ||
}); | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); | ||
__setModuleDefault(result, mod); | ||
return result; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.main = void 0; | ||
const result_1 = require("@eeue56/ts-core/build/main/lib/result"); | ||
const bundle_1 = require("./cli/bundle"); | ||
const compile_1 = require("./cli/compile"); | ||
const format_1 = require("./cli/format"); | ||
const info_1 = require("./cli/info"); | ||
const init_1 = require("./cli/init"); | ||
const install_1 = require("./cli/install"); | ||
const repl_1 = require("./cli/repl"); | ||
const template_1 = require("./cli/template"); | ||
const testing_1 = require("./cli/testing"); | ||
const utils_1 = require("./cli/utils"); | ||
function parseCliCommand() { | ||
@@ -71,38 +80,48 @@ if (typeof process.argv[2] === "undefined") { | ||
const argv = process.argv; | ||
const isInPackageDirectory = await utils_1.fileExists("derw-package.json"); | ||
const { fileExists } = await Promise.resolve().then(() => __importStar(require("./cli/utils"))); | ||
const isInPackageDirectory = await fileExists("derw-package.json"); | ||
switch (command.value) { | ||
case "compile": { | ||
await compile_1.compileFiles(isInPackageDirectory, argv); | ||
const { compileFiles } = await Promise.resolve().then(() => __importStar(require("./cli/compile"))); | ||
await compileFiles(isInPackageDirectory, argv); | ||
return 0; | ||
} | ||
case "init": { | ||
await init_1.init(isInPackageDirectory, argv); | ||
const { init } = await Promise.resolve().then(() => __importStar(require("./cli/init"))); | ||
await init(isInPackageDirectory, argv); | ||
return 0; | ||
} | ||
case "install": { | ||
await install_1.install(isInPackageDirectory, argv); | ||
const { install } = await Promise.resolve().then(() => __importStar(require("./cli/install"))); | ||
await install(isInPackageDirectory, argv); | ||
return 0; | ||
} | ||
case "test": { | ||
await testing_1.runTests(isInPackageDirectory, argv); | ||
const { runTests } = await Promise.resolve().then(() => __importStar(require("./cli/testing"))); | ||
await runTests(isInPackageDirectory, argv); | ||
return 0; | ||
} | ||
case "info": { | ||
await info_1.info(isInPackageDirectory, argv); | ||
const { info } = await Promise.resolve().then(() => __importStar(require("./cli/info"))); | ||
await info(isInPackageDirectory, argv); | ||
return 0; | ||
} | ||
case "repl": { | ||
await repl_1.repl(isInPackageDirectory, argv); | ||
const { repl } = await Promise.resolve().then(() => __importStar(require("./cli/repl"))); | ||
await repl(isInPackageDirectory, argv); | ||
return 0; | ||
} | ||
case "bundle": { | ||
await bundle_1.bundle(isInPackageDirectory, argv); | ||
const { bundle } = await Promise.resolve().then(() => __importStar(require("./cli/bundle"))); | ||
await bundle(isInPackageDirectory, argv); | ||
return 0; | ||
} | ||
case "format": { | ||
await format_1.format(isInPackageDirectory, argv); | ||
const { format } = await Promise.resolve().then(() => __importStar(require("./cli/format"))); | ||
await format(isInPackageDirectory, argv); | ||
return 0; | ||
} | ||
case "template": { | ||
await template_1.template(isInPackageDirectory, argv); | ||
const { template } = await Promise.resolve().then(() => __importStar(require("./cli/template"))); | ||
await template(isInPackageDirectory, argv); | ||
return 0; | ||
@@ -109,0 +128,0 @@ } |
@@ -34,3 +34,3 @@ "use strict"; | ||
baner_1.longFlag("output", "Output file to generate", baner_1.string()), | ||
baner_1.longFlag("quiet", "Dont print any output", baner_1.empty()), | ||
baner_1.longFlag("quiet", "Don't print any output", baner_1.empty()), | ||
baner_1.longFlag("watch", "Watch Derw files for changes", baner_1.empty()), | ||
@@ -105,6 +105,9 @@ baner_1.longFlag("optimize", "Run generated Javascript through minification", baner_1.empty()), | ||
if (program.flags.watch.isPresent) { | ||
console.log("Watching src..."); | ||
console.log("Watching src and derw-packages..."); | ||
let timer; | ||
chokidar | ||
.watch(path_1.default.join(process.cwd(), "src")) | ||
.watch([ | ||
path_1.default.join(process.cwd(), "src"), | ||
path_1.default.join(process.cwd(), "derw-packages"), | ||
]) | ||
.on("all", async (event, path) => { | ||
@@ -111,0 +114,0 @@ if (path.endsWith(".derw")) { |
@@ -33,10 +33,7 @@ "use strict"; | ||
const util = __importStar(require("util")); | ||
const compile_1 = require("../compile"); | ||
const names_1 = require("../errors/names"); | ||
const generator_1 = require("../generator"); | ||
const package_1 = require("../package"); | ||
const derwParser = __importStar(require("../parser")); | ||
const types_1 = require("../types"); | ||
const utils_1 = require("../utils"); | ||
const utils_2 = require("./utils"); | ||
const utils_1 = require("./utils"); | ||
const compileParser = baner_1.parser([ | ||
@@ -136,18 +133,4 @@ baner_1.longFlag("files", "File names to be compiled", baner_1.variableList(baner_1.string())), | ||
const files = isPackageDirectoryAndNoFilesPassed | ||
? await utils_2.getDerwFiles("./src") | ||
? await utils_1.getDerwFiles("./src") | ||
: program.flags.files.arguments.value; | ||
if (isPackageDirectoryAndNoFilesPassed) { | ||
const packageFile = await package_1.loadPackageFile("derw-package.json"); | ||
if (packageFile.kind === "err") { | ||
console.log("Failed to parse package file due to:"); | ||
console.log(packageFile.error); | ||
process.exit(1); | ||
} | ||
const validPackage = packageFile.value; | ||
for (const dep of validPackage.dependencies) { | ||
for (const file of await utils_2.getDerwFiles(`derw-packages/${dep.name}/src`)) { | ||
files.push(file); | ||
} | ||
} | ||
} | ||
const outputDir = program.flags.output.isPresent | ||
@@ -158,3 +141,3 @@ ? program.flags.output.arguments.value | ||
if (!isStdout) { | ||
await utils_2.ensureDirectoryExists(outputDir); | ||
await utils_1.ensureDirectoryExists(outputDir); | ||
} | ||
@@ -195,4 +178,3 @@ const target = program.flags.target.isPresent | ||
const derwContents = (await fs_1.promises.readFile(fileName)).toString(); | ||
const isMain = files.indexOf(fileName) > -1 && !utils_1.isTestFile(fileName); | ||
let parsed = derwParser.parseWithContext(derwContents, isMain ? "Main" : fileName); | ||
let parsed = derwParser.parseWithContext(derwContents, fileName); | ||
if (program.flags.names.isPresent) { | ||
@@ -212,2 +194,4 @@ parsed = names_1.addMissingNamesSuggestions(parsed); | ||
import_.modules.forEach((module) => { | ||
if (module.namespace === "Global") | ||
return; | ||
if (isPackageFile) { | ||
@@ -218,4 +202,2 @@ if (module.name.startsWith('"../derw-packages')) { | ||
} | ||
if (module.namespace === "Global") | ||
return; | ||
const moduleName = module.name.slice(1, -1); | ||
@@ -230,3 +212,3 @@ imports.push(path_1.default.normalize(path_1.default.join(dir, moduleName))); | ||
: import_ + `.derw`; | ||
const isDerw = await utils_2.fileExists(fileWithDerwExtension); | ||
const isDerw = await utils_1.fileExists(fileWithDerwExtension); | ||
if (isDerw) { | ||
@@ -241,6 +223,6 @@ parsedImports[fileName].push(fileWithDerwExtension); | ||
let doesFileExist = false; | ||
if (await utils_2.fileExists(fileWithTsExtension)) { | ||
if (await utils_1.fileExists(fileWithTsExtension)) { | ||
doesFileExist = true; | ||
} | ||
else if (await utils_2.fileExists(fileWithJsExtension)) { | ||
else if (await utils_1.fileExists(fileWithJsExtension)) { | ||
doesFileExist = true; | ||
@@ -280,3 +262,4 @@ } | ||
if (program.flags.verify.isPresent && target === "ts") { | ||
const output = compile_1.compileTypescript(generated); | ||
const { compileTypescript } = await Promise.resolve().then(() => __importStar(require("../compile"))); | ||
const output = compileTypescript(generated); | ||
if (output.kind === "err") { | ||
@@ -295,3 +278,3 @@ console.log(`Failed to compile ${fileName} due to`, output.error.map((e) => e.messageText).join("\n")); | ||
const dirName = fileName.split("/").slice(0, -1).join("/"); | ||
await utils_2.ensureDirectoryExists(path_1.default.join(outputDir, dirName)); | ||
await utils_1.ensureDirectoryExists(path_1.default.join(outputDir, dirName)); | ||
} | ||
@@ -320,6 +303,9 @@ const outputName = dotParts.slice(0, -1).join(".") + "." + target; | ||
if (!isQuiet) | ||
console.log("Watching..."); | ||
console.log("Watching src and derw-packages..."); | ||
let timer; | ||
chokidar | ||
.watch(path_1.default.join(process.cwd(), "src")) | ||
.watch([ | ||
path_1.default.join(process.cwd(), "src"), | ||
path_1.default.join(process.cwd(), "derw-packages"), | ||
]) | ||
.on("all", async (event, path) => { | ||
@@ -326,0 +312,0 @@ if (path.endsWith(".derw")) { |
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
}) : function(o, v) { | ||
o["default"] = v; | ||
}); | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); | ||
__setModuleDefault(result, mod); | ||
return result; | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.format = void 0; | ||
const baner_1 = require("@eeue56/baner"); | ||
const chokidar = __importStar(require("chokidar")); | ||
const promises_1 = require("fs/promises"); | ||
const path_1 = __importDefault(require("path")); | ||
const generator_1 = require("../generator"); | ||
@@ -9,2 +34,24 @@ const parser_1 = require("../parser"); | ||
const utils_1 = require("./utils"); | ||
const formatParser = baner_1.parser([ | ||
baner_1.longFlag("watch", "Watch Derw files for changes", baner_1.empty()), | ||
baner_1.bothFlag("h", "help", "This help text", baner_1.empty()), | ||
]); | ||
function showFormatHelp() { | ||
console.log("To format, run `derw format`"); | ||
console.log("To watch use the --watch flag"); | ||
console.log(baner_1.help(formatParser)); | ||
} | ||
async function formatFile(file) { | ||
const derwContents = (await promises_1.readFile(file)).toString(); | ||
let parsed = parser_1.parseWithContext(derwContents, "Main"); | ||
if (parsed.errors.length > 0) { | ||
console.log(`Failed to parse ${file}`); | ||
return; | ||
} | ||
const outputDerw = generator_1.generate("derw", types_1.contextModuleToModule(parsed)); | ||
// only write if files are formatted differently | ||
if (derwContents === outputDerw) | ||
return; | ||
await promises_1.writeFile(file, outputDerw); | ||
} | ||
async function format(isInPackageDirectory, argv) { | ||
@@ -15,14 +62,42 @@ if (!isInPackageDirectory) { | ||
} | ||
const files = await utils_1.getDerwFiles("./src"); | ||
for (const file of files) { | ||
const derwContents = (await promises_1.readFile(file)).toString(); | ||
let parsed = parser_1.parseWithContext(derwContents, "Main"); | ||
if (parsed.errors.length > 0) { | ||
console.log(`Failed to parse ${file}`); | ||
continue; | ||
const program = baner_1.parse(formatParser, argv); | ||
if (program.flags["h/help"].isPresent) { | ||
showFormatHelp(); | ||
return; | ||
} | ||
if (program.flags.watch.isPresent) { | ||
console.log("Watching src..."); | ||
const files = await utils_1.getDerwFiles("./src"); | ||
for (const file of files) { | ||
await formatFile(file); | ||
} | ||
const outputDerw = generator_1.generate("derw", types_1.contextModuleToModule(parsed)); | ||
await promises_1.writeFile(file, outputDerw); | ||
let timer; | ||
chokidar | ||
.watch(path_1.default.join(process.cwd(), "src")) | ||
.on("all", async (event, path) => { | ||
if (event === "add" || event === "change") { | ||
if (path.endsWith(".derw")) { | ||
if (timer !== null) { | ||
clearTimeout(timer); | ||
} | ||
timer = setTimeout(async () => { | ||
await formatFile(path); | ||
}, 50); | ||
} | ||
} | ||
else if (event === "addDir") { | ||
const files = await utils_1.getDerwFiles(path); | ||
for (const file of files) { | ||
await formatFile(file); | ||
} | ||
} | ||
}); | ||
} | ||
else { | ||
const files = await utils_1.getDerwFiles("./src"); | ||
for (const file of files) { | ||
await formatFile(file); | ||
} | ||
} | ||
} | ||
exports.format = format; |
@@ -13,6 +13,7 @@ "use strict"; | ||
const initParser = baner_1.parser([ | ||
baner_1.longFlag("dir", "name of a directory to use as package name e.g stdlib", baner_1.string()), | ||
baner_1.longFlag("dir", "name of a directory to use as package name e.g stdlib. Defaults to current directory's name", baner_1.string()), | ||
baner_1.bothFlag("h", "help", "This help text", baner_1.empty()), | ||
]); | ||
function showInfoHelp() { | ||
console.log("Initialize a directory as a Derw project."); | ||
console.log(baner_1.help(initParser)); | ||
@@ -19,0 +20,0 @@ } |
@@ -81,2 +81,12 @@ "use strict"; | ||
await utils_1.ensureDirectoryExists("derw-packages/.cli/"); | ||
async function run(currentBuffer) { | ||
module = parser_1.parseWithContext([...currentBuffer].join("\n"), "Main"); | ||
module = exportEverything(module); | ||
const generated = ts_1.generateTypescript(types_1.contextModuleToModule(module)); | ||
const fileTimestamp = new Date().getTime(); | ||
const filename = `${process.cwd()}/derw-packages/.cli/${fileTimestamp}.ts`; | ||
await promises_1.writeFile(filename, generated); | ||
currentlyImportedModule = await Promise.resolve().then(() => __importStar(require(filename))); | ||
} | ||
let linesAddedToCurrentBufferSinceLastParsing = []; | ||
try { | ||
@@ -86,9 +96,18 @@ for (var rl_1 = __asyncValues(rl), rl_1_1; rl_1_1 = await rl_1.next(), !rl_1_1.done;) { | ||
if (line.trim() === "") { | ||
currentBuffer.push(""); | ||
module = parser_1.parseWithContext(currentBuffer.join("\n"), "Main"); | ||
module = parser_1.parseWithContext([ | ||
...currentBuffer, | ||
"", | ||
...linesAddedToCurrentBufferSinceLastParsing, | ||
].join("\n"), "Main"); | ||
module = parser_1.addTypeErrors(module, []); | ||
if (module.errors.length > 0) { | ||
console.log(`Errors while parsing: ${module.errors.join("\n")}`); | ||
linesAddedToCurrentBufferSinceLastParsing = []; | ||
} | ||
else { | ||
for (const newLine of linesAddedToCurrentBufferSinceLastParsing) { | ||
currentBuffer.push(newLine); | ||
} | ||
linesAddedToCurrentBufferSinceLastParsing = []; | ||
currentBuffer.push(""); | ||
console.log("Parsed successfully"); | ||
@@ -98,13 +117,14 @@ } | ||
else if (line.trim() === ":run") { | ||
module = parser_1.parseWithContext([...currentBuffer].join("\n"), "Main"); | ||
module = exportEverything(module); | ||
const generated = ts_1.generateTypescript(types_1.contextModuleToModule(module)); | ||
const fileTimestamp = new Date().getTime(); | ||
const filename = `${process.cwd()}/derw-packages/.cli/${fileTimestamp}.ts`; | ||
await promises_1.writeFile(filename, generated); | ||
currentlyImportedModule = await Promise.resolve().then(() => __importStar(require(filename))); | ||
await run(currentBuffer); | ||
} | ||
else if (line.startsWith(":show")) { | ||
const name = line.split(" ")[1].trim(); | ||
console.log(currentlyImportedModule[name]); | ||
await run(currentBuffer); | ||
1; | ||
if (currentlyImportedModule[name] === undefined) { | ||
console.log(`Couldn't find ${name} in current scope.`); | ||
} | ||
else { | ||
console.log(currentlyImportedModule[name]); | ||
} | ||
} | ||
@@ -114,3 +134,3 @@ else if (line.trim() === ":help") { | ||
console.log("Run the current namespace via :run"); | ||
console.log("And check the values of code via :show <name> after using :run"); | ||
console.log("And check the values of code via :show <name>"); | ||
console.log("Or evaluate a constant or function with :eval <function> <args>"); | ||
@@ -140,3 +160,3 @@ } | ||
else { | ||
currentBuffer.push(line.split("\t").join(" ")); | ||
linesAddedToCurrentBufferSinceLastParsing.push(line.split("\t").join(" ")); | ||
} | ||
@@ -143,0 +163,0 @@ rl.prompt(); |
@@ -19,2 +19,4 @@ "use strict"; | ||
function showInfoHelp() { | ||
console.log("Generate a Derw file from a template."); | ||
console.log("Also installs required packages."); | ||
console.log(baner_1.help(templateParser)); | ||
@@ -21,0 +23,0 @@ } |
@@ -39,3 +39,3 @@ "use strict"; | ||
function showTestingHelp() { | ||
console.log("To run tests, run `derw test` from the package directory"); | ||
console.log("To run tests, run `derw test` from the package directory"); | ||
console.log("To watch use the --watch flag"); | ||
@@ -61,6 +61,10 @@ console.log(baner_1.help(testingParser)); | ||
if (program.flags.watch.isPresent) { | ||
process.argv.push("--clean-exit"); | ||
console.log("Watching src and derw-packages..."); | ||
argv.push("--clean-exit"); | ||
let timer; | ||
chokidar | ||
.watch(path_1.default.join(process.cwd(), "src")) | ||
.watch([ | ||
path_1.default.join(process.cwd(), "src"), | ||
path_1.default.join(process.cwd(), "derw-packages"), | ||
]) | ||
.on("error", () => { | ||
@@ -75,3 +79,3 @@ console.log("Got an error"); | ||
timer = setTimeout(async () => { | ||
await compile_1.compileFiles(isInPackageDirectory, []); | ||
await compile_1.compileFiles(isInPackageDirectory, argv); | ||
await bach_1.runner(); | ||
@@ -78,0 +82,0 @@ }, 300); |
@@ -116,3 +116,7 @@ "use strict"; | ||
: utils_1.getNameFromPath(withoutQuotes); | ||
const exposing = `import { ${module.exposing.join(", ")} } from ${module.name};`; | ||
const filteredExposing = module.alias.kind === "nothing" | ||
? module.exposing | ||
: module.exposing.filter((expose) => expose !== | ||
module.alias.value); | ||
const exposing = `import { ${filteredExposing.join(", ")} } from ${module.name};`; | ||
if (module.exposing.length === 0) { | ||
@@ -119,0 +123,0 @@ return `import * as ${name} from ${module.name};`; |
@@ -540,2 +540,10 @@ "use strict"; | ||
} | ||
function generateComment(comment) { | ||
return `-- ${comment.body}`; | ||
} | ||
function generateMultilineComment(comment) { | ||
return `{- | ||
${comment.body} | ||
-}`; | ||
} | ||
function generateBlock(syntax) { | ||
@@ -556,6 +564,22 @@ switch (syntax.kind) { | ||
case "Comment": | ||
return generateComment(syntax); | ||
case "MultilineComment": | ||
return ""; | ||
return generateMultilineComment(syntax); | ||
} | ||
} | ||
function joinBlocks(blocks) { | ||
let output = ""; | ||
for (const block of blocks) { | ||
const generated = generateBlock(block); | ||
if (generated.trim().length === 0) | ||
continue; | ||
if (block.kind === "Comment" || block.kind === "MultilineComment") { | ||
output += generated + "\n"; | ||
} | ||
else { | ||
output += generated + "\n\n"; | ||
} | ||
} | ||
return output.trim(); | ||
} | ||
function generateDerw(module) { | ||
@@ -571,8 +595,5 @@ const importBlocks = module.body.filter((block) => block.kind === "Import"); | ||
importBlocks.length > 0 ? "\n\n" : "", | ||
...nonImportBlocks | ||
.map(generateBlock) | ||
.filter((line) => line.length > 0) | ||
.join("\n\n"), | ||
...joinBlocks(nonImportBlocks), | ||
].join(""); | ||
} | ||
exports.generateDerw = generateDerw; |
@@ -515,2 +515,3 @@ "use strict"; | ||
moduleName = moduleName.toUpperCase()[0] + moduleName.slice(1); | ||
moduleName = moduleName.split("/").join(".").replace(".derw", ""); | ||
if (names.length === 0) | ||
@@ -517,0 +518,0 @@ return `module ${moduleName} exposing (..)`; |
@@ -70,3 +70,5 @@ "use strict"; | ||
? "\n" + | ||
common_1.prefixLines(ifStatement.ifLetBody.map(generateBlock).join("\n"), 4) | ||
common_1.prefixLines(ifStatement.ifLetBody | ||
.map((block) => generateBlock(block)) | ||
.join("\n"), 4) | ||
: ""; | ||
@@ -82,3 +84,5 @@ const ifBody = generateExpression(ifStatement.ifBody); | ||
? "\n" + | ||
common_1.prefixLines(ifStatement.elseLetBody.map(generateBlock).join("\n"), 4) | ||
common_1.prefixLines(ifStatement.elseLetBody | ||
.map((block) => generateBlock(block)) | ||
.join("\n"), 4) | ||
: ""; | ||
@@ -189,3 +193,5 @@ const elseBody = generateExpression(ifStatement.elseBody); | ||
? "\n" + | ||
common_1.prefixLines(branch.letBody.map(generateBlock).join("\n"), 4) | ||
common_1.prefixLines(branch.letBody | ||
.map((block) => generateBlock(block)) | ||
.join("\n"), 4) | ||
: ""; | ||
@@ -545,3 +551,5 @@ switch (branch.pattern.kind) { | ||
? "\n" + | ||
common_1.prefixLines(function_.letBody.map(generateBlock).join("\n"), 4) | ||
common_1.prefixLines(function_.letBody | ||
.map((block) => generateBlock(block)) | ||
.join("\n"), 4) | ||
: ""; | ||
@@ -629,3 +637,3 @@ const maybeDoBody = function_.doBody === null | ||
} | ||
function generateBlock(syntax) { | ||
function generateBlock(syntax, unionTypeNames) { | ||
switch (syntax.kind) { | ||
@@ -635,3 +643,3 @@ case "Import": | ||
case "Export": | ||
return common_to_ecma_1.generateExportBlock(syntax); | ||
return common_to_ecma_1.generateExportBlock(Object.assign(Object.assign({}, syntax), { names: syntax.names.filter((name) => !(unionTypeNames || []).includes(name)) })); | ||
case "UnionType": | ||
@@ -651,4 +659,7 @@ return generateUnionType(syntax); | ||
function generateJavascript(module) { | ||
const unionTypeNames = module.body | ||
.filter((block) => block.kind === "UnionType") | ||
.map((block) => block.type.name); | ||
return [blocks_1.exportTests(module), ...module.body] | ||
.map(generateBlock) | ||
.map((b) => generateBlock(b, unionTypeNames)) | ||
.filter((line) => line.length > 0) | ||
@@ -655,0 +666,0 @@ .join("\n\n"); |
@@ -10,10 +10,10 @@ "use strict"; | ||
const common_to_ecma_1 = require("./common_to_ecma"); | ||
function generateUnionType(syntax) { | ||
function generateUnionType(syntax, imports) { | ||
const tagCreators = syntax.tags | ||
.map((tag) => { | ||
const typeDefArgs = tag.args | ||
.map((arg) => arg.name + ": " + generateType(arg.type) + ";") | ||
.map((arg) => arg.name + ": " + generateType(arg.type, imports) + ";") | ||
.join("\n "); | ||
const funcDefArgs = tag.args | ||
.map((arg) => arg.name + ": " + generateType(arg.type)) | ||
.map((arg) => arg.name + ": " + generateType(arg.type, imports)) | ||
.join(", "); | ||
@@ -32,3 +32,3 @@ const generatedType = generateType(types_1.FixedType(tag.name, tag.args | ||
return true; | ||
}))); | ||
})), imports); | ||
const funcDefArgsStr = tag.args.length > 0 ? `{ ${funcDefArgs} }` : "{}"; | ||
@@ -62,3 +62,3 @@ return ` | ||
return true; | ||
}))); | ||
})), imports); | ||
}) | ||
@@ -69,14 +69,14 @@ .join(" | "); | ||
type ${generateType(syntax.type)} = ${tags}; | ||
type ${generateType(syntax.type, imports)} = ${tags}; | ||
`.trim(); | ||
} | ||
function generateProperty(syntax) { | ||
return `${syntax.name}: ${generateTopLevelType(syntax.type)}`; | ||
function generateProperty(syntax, imports) { | ||
return `${syntax.name}: ${generateTopLevelType(syntax.type, imports)}`; | ||
} | ||
function generateTypeAlias(syntax) { | ||
const generatedProperties = syntax.properties.map(generateProperty); | ||
function generateTypeAlias(syntax, imports) { | ||
const generatedProperties = syntax.properties.map((prop) => generateProperty(prop, imports)); | ||
const properties = generatedProperties.length === 0 | ||
? "" | ||
: " " + generatedProperties.join(";\n ") + ";"; | ||
const type = generateType(syntax.type); | ||
const type = generateType(syntax.type, imports); | ||
const args = generatedProperties.length === 0 | ||
@@ -413,6 +413,17 @@ ? " " | ||
} | ||
function generateTopLevelType(type_) { | ||
function typeHasOverlapWithImportedModule(type_, imports) { | ||
for (const import_ of imports) { | ||
for (const module_ of import_.modules) { | ||
if (module_.alias.kind === "just" && | ||
module_.alias.value === type_.name) { | ||
return true; | ||
} | ||
} | ||
} | ||
return false; | ||
} | ||
function generateTopLevelType(type_, imports) { | ||
switch (type_.kind) { | ||
case "GenericType": { | ||
return generateType(type_); | ||
return generateType(type_, imports); | ||
} | ||
@@ -422,3 +433,3 @@ case "FixedType": { | ||
if (type_.args[0] && type_.args[0].kind === "GenericType") { | ||
return generateTopLevelType(type_.args[0]) + "[]"; | ||
return generateTopLevelType(type_.args[0], imports) + "[]"; | ||
} | ||
@@ -430,5 +441,7 @@ const fixedArgs = type_.args.filter((type_) => type_.kind === "FixedType"); | ||
else if (fixedArgs.length === 1) { | ||
return `${generateTopLevelType(fixedArgs[0])}[]`; | ||
return `${generateTopLevelType(fixedArgs[0], imports)}[]`; | ||
} | ||
return `(${fixedArgs.map(generateTopLevelType).join(" | ")})[]`; | ||
return `(${fixedArgs | ||
.map((arg) => generateTopLevelType(arg, imports)) | ||
.join(" | ")})[]`; | ||
} | ||
@@ -439,3 +452,3 @@ if (type_.args.length > 0 && | ||
return `${type_.name}<${type_.args | ||
.map(generateTopLevelType) | ||
.map((arg) => generateTopLevelType(arg, imports)) | ||
.join(", ")}>`; | ||
@@ -454,6 +467,11 @@ } | ||
} | ||
const qualifiedName = typeHasOverlapWithImportedModule(type_, imports) | ||
? `${type_.name}.${type_.name}` | ||
: type_.name; | ||
if (args.length === 0) { | ||
return type_.name; | ||
return qualifiedName; | ||
} | ||
return `${type_.name}<${args.map(generateType).join(", ")}>`; | ||
return `${qualifiedName}<${args | ||
.map((arg) => generateType(arg, imports)) | ||
.join(", ")}>`; | ||
} | ||
@@ -464,3 +482,3 @@ case "FunctionType": { | ||
for (const typePart of type_.args.slice(0, -1)) { | ||
parts.push(`arg${index}: ${generateTopLevelType(typePart)}`); | ||
parts.push(`arg${index}: ${generateTopLevelType(typePart, imports)}`); | ||
index++; | ||
@@ -471,7 +489,7 @@ } | ||
") => " + | ||
generateType(type_.args[type_.args.length - 1])); | ||
generateType(type_.args[type_.args.length - 1], imports)); | ||
} | ||
} | ||
} | ||
function generateType(type_) { | ||
function generateType(type_, imports) { | ||
switch (type_.kind) { | ||
@@ -484,3 +502,3 @@ case "GenericType": { | ||
if (type_.args[0] && type_.args[0].kind === "GenericType") { | ||
return generateType(type_.args[0]) + "[]"; | ||
return generateType(type_.args[0], imports) + "[]"; | ||
} | ||
@@ -492,5 +510,7 @@ const fixedArgs = type_.args.filter((type_) => type_.kind === "FixedType"); | ||
else if (fixedArgs.length === 1) { | ||
return `${generateType(fixedArgs[0])}[]`; | ||
return `${generateType(fixedArgs[0], imports)}[]`; | ||
} | ||
return `(${fixedArgs.map(generateType).join(" | ")})[]`; | ||
return `(${fixedArgs | ||
.map((arg) => generateType(arg, imports)) | ||
.join(" | ")})[]`; | ||
} | ||
@@ -508,6 +528,11 @@ const args = []; | ||
} | ||
const qualifiedName = typeHasOverlapWithImportedModule(type_, imports) | ||
? `${type_.name}.${type_.name}` | ||
: type_.name; | ||
if (args.length === 0) { | ||
return type_.name; | ||
return qualifiedName; | ||
} | ||
return `${type_.name}<${args.map(generateType).join(", ")}>`; | ||
return `${qualifiedName}<${args | ||
.map((arg) => generateType(arg, imports)) | ||
.join(", ")}>`; | ||
} | ||
@@ -518,3 +543,3 @@ case "FunctionType": { | ||
for (const typePart of type_.args.slice(0, -1)) { | ||
parts.push(`arg${index}: ${generateType(typePart)}`); | ||
parts.push(`arg${index}: ${generateType(typePart, imports)}`); | ||
index++; | ||
@@ -525,3 +550,3 @@ } | ||
") => " + | ||
generateType(type_.args[type_.args.length - 1])); | ||
generateType(type_.args[type_.args.length - 1], imports)); | ||
} | ||
@@ -727,3 +752,3 @@ } | ||
} | ||
function generateDoBlock(doBody, parentTypeArguments, parentTypes) { | ||
function generateDoBlock(doBody, parentTypeArguments, parentTypes, imports) { | ||
const lines = []; | ||
@@ -733,7 +758,7 @@ for (const expression of doBody.expressions) { | ||
case "Const": { | ||
lines.push(generateConst(expression)); | ||
lines.push(generateConst(expression, imports)); | ||
break; | ||
} | ||
case "Function": { | ||
lines.push(generateFunction(expression, parentTypeArguments, parentTypes)); | ||
lines.push(generateFunction(expression, parentTypeArguments, parentTypes, imports)); | ||
break; | ||
@@ -753,3 +778,3 @@ } | ||
} | ||
function generateFunction(function_, parentTypeArguments, parentTypes) { | ||
function generateFunction(function_, parentTypeArguments, parentTypes, imports) { | ||
const functionArguments = function_.args | ||
@@ -759,5 +784,10 @@ .map((arg) => { | ||
case "FunctionArg": | ||
return arg.name + ": " + generateTopLevelType(arg.type); | ||
return (arg.name + | ||
": " + | ||
generateTopLevelType(arg.type, imports)); | ||
case "AnonFunctionArg": | ||
return ("_" + arg.index + ": " + generateTopLevelType(arg.type)); | ||
return ("_" + | ||
arg.index + | ||
": " + | ||
generateTopLevelType(arg.type, imports)); | ||
} | ||
@@ -773,6 +803,3 @@ }) | ||
common_1.prefixLines(function_.letBody | ||
.map((block) => generateBlock(block, [ | ||
...typeArguments, | ||
...parentTypeArguments, | ||
])) | ||
.map((block) => generateBlock(block, [...typeArguments, ...parentTypeArguments], [], imports)) | ||
.join("\n"), 4) | ||
@@ -783,4 +810,4 @@ : ""; | ||
: "\n" + | ||
common_1.prefixLines(generateDoBlock(function_.doBody, parentTypeArguments, parentTypes), 4); | ||
const returnType = generateTopLevelType(function_.returnType); | ||
common_1.prefixLines(generateDoBlock(function_.doBody, parentTypeArguments, parentTypes, imports), 4); | ||
const returnType = generateTopLevelType(function_.returnType, imports); | ||
const isSimpleBody = types_1.isSimpleValue(function_.body.kind); | ||
@@ -813,4 +840,4 @@ const bodyPrefix = isSimpleBody ? "return " : ""; | ||
} | ||
function generateNestedConst(constDef, body) { | ||
const typeDef = generateTopLevelType(constDef.type); | ||
function generateNestedConst(constDef, body, imports) { | ||
const typeDef = generateTopLevelType(constDef.type, imports); | ||
const generatedBlocks = constDef.letBody | ||
@@ -825,3 +852,3 @@ .map((block) => generateBlock(block, [], [])) | ||
} | ||
function generateConst(constDef) { | ||
function generateConst(constDef, imports) { | ||
let body = ""; | ||
@@ -834,3 +861,3 @@ switch (constDef.value.kind) { | ||
else { | ||
body = generateNestedConst(constDef, generateInlineIf(constDef.value)); | ||
body = generateNestedConst(constDef, generateInlineIf(constDef.value), imports); | ||
} | ||
@@ -844,3 +871,3 @@ break; | ||
else { | ||
body = generateNestedConst(constDef, generateInlineCase(constDef.value)); | ||
body = generateNestedConst(constDef, generateInlineCase(constDef.value), imports); | ||
} | ||
@@ -854,3 +881,3 @@ break; | ||
else { | ||
body = generateNestedConst(constDef, generateExpression(constDef.value)); | ||
body = generateNestedConst(constDef, generateExpression(constDef.value), imports); | ||
} | ||
@@ -860,3 +887,3 @@ break; | ||
} | ||
const typeDef = generateTopLevelType(constDef.type); | ||
const typeDef = generateTopLevelType(constDef.type, imports); | ||
return ` | ||
@@ -866,3 +893,3 @@ const ${constDef.name}: ${typeDef} = ${body}; | ||
} | ||
function generateBlock(syntax, parentTypeArguments, parentTypes) { | ||
function generateBlock(syntax, parentTypeArguments, parentTypes, imports) { | ||
switch (syntax.kind) { | ||
@@ -874,9 +901,9 @@ case "Import": | ||
case "UnionType": | ||
return generateUnionType(syntax); | ||
return generateUnionType(syntax, imports || []); | ||
case "TypeAlias": | ||
return generateTypeAlias(syntax); | ||
return generateTypeAlias(syntax, imports || []); | ||
case "Function": | ||
return generateFunction(syntax, parentTypeArguments || [], parentTypes || []); | ||
return generateFunction(syntax, parentTypeArguments || [], parentTypes || [], imports || []); | ||
case "Const": | ||
return generateConst(syntax); | ||
return generateConst(syntax, imports || []); | ||
case "Comment": | ||
@@ -888,4 +915,5 @@ case "MultilineComment": | ||
function generateTypescript(module) { | ||
const imports = module.body.filter((block) => block.kind === "Import"); | ||
return [blocks_1.exportTests(module), ...module.body] | ||
.map((block) => generateBlock(block)) | ||
.map((block) => generateBlock(block, [], [], imports)) | ||
.filter((line) => line.length > 0) | ||
@@ -892,0 +920,0 @@ .join("\n\n"); |
@@ -798,13 +798,1 @@ "use strict"; | ||
exports.nextNonWhitespace = nextNonWhitespace; | ||
function log(x) { | ||
console.log(x); | ||
tokenize(x) | ||
.map((token) => { | ||
if (token.body) | ||
return `${token.kind}("${token.body}"),`; | ||
return `${token.kind}(),`; | ||
}) | ||
.forEach((token) => { | ||
console.log(token); | ||
}); | ||
} |
@@ -308,8 +308,10 @@ import { Maybe } from "@eeue56/ts-core/build/main/lib/maybe"; | ||
kind: "Comment"; | ||
body: string; | ||
}; | ||
export declare function Comment(): Comment; | ||
export declare function Comment(body: string): Comment; | ||
export declare type MultilineComment = { | ||
kind: "MultilineComment"; | ||
body: string; | ||
}; | ||
export declare function MultilineComment(): MultilineComment; | ||
export declare function MultilineComment(body: string): MultilineComment; | ||
export declare type UnparsedBlockTypes = "ImportBlock" | "ExportBlock" | "UnionTypeBlock" | "TypeAliasBlock" | "FunctionBlock" | "ConstBlock" | "CommentBlock" | "MultilineCommentBlock" | "UnknownBlock"; | ||
@@ -316,0 +318,0 @@ export declare type UnparsedBlock = { |
@@ -435,11 +435,13 @@ "use strict"; | ||
exports.Export = Export; | ||
function Comment() { | ||
function Comment(body) { | ||
return { | ||
kind: "Comment", | ||
body, | ||
}; | ||
} | ||
exports.Comment = Comment; | ||
function MultilineComment() { | ||
function MultilineComment(body) { | ||
return { | ||
kind: "MultilineComment", | ||
body, | ||
}; | ||
@@ -446,0 +448,0 @@ } |
{ | ||
"name": "derw", | ||
"version": "0.0.6-0", | ||
"version": "0.0.6", | ||
"description": "An Elm-inspired language that transpiles to TypeScript", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -11,2 +11,6 @@ # derw | ||
The compiler runs through ts-node currently, so you'll need to install that via `npm install -g ts-node`. | ||
You can also just use node, through running `node <path-to-derw>/build/cli.js`. | ||
```bash | ||
@@ -22,2 +26,3 @@ npm install --save-dev derw | ||
# Usage | ||
@@ -363,2 +368,3 @@ | ||
import "./another" exposing ( isTrue, isFalse ) | ||
import "./Maybe" as Maybe exposing (Maybe) | ||
``` | ||
@@ -575,2 +581,11 @@ | ||
# VScode auto-formatting | ||
``` | ||
git clone https://github.com/derw-lang/derw-formatter-vscode | ||
cp -r derw-formatter-vscode ~/.vscode/extensions/derw-formatter-vscode-0.0.1 | ||
``` | ||
# Name | ||
@@ -577,0 +592,0 @@ |
#!/usr/bin/env ts-node | ||
import { Err, Ok, Result } from "@eeue56/ts-core/build/main/lib/result"; | ||
import { bundle } from "./cli/bundle"; | ||
import { compileFiles } from "./cli/compile"; | ||
import { format } from "./cli/format"; | ||
import { info } from "./cli/info"; | ||
import { init } from "./cli/init"; | ||
import { install } from "./cli/install"; | ||
import { repl } from "./cli/repl"; | ||
import { template } from "./cli/template"; | ||
import { runTests } from "./cli/testing"; | ||
import { fileExists } from "./cli/utils"; | ||
@@ -87,2 +77,3 @@ type CliCommand = | ||
const argv = process.argv; | ||
const { fileExists } = await import("./cli/utils"); | ||
const isInPackageDirectory = await fileExists("derw-package.json"); | ||
@@ -92,2 +83,4 @@ | ||
case "compile": { | ||
const { compileFiles } = await import("./cli/compile"); | ||
await compileFiles(isInPackageDirectory, argv); | ||
@@ -97,2 +90,3 @@ return 0; | ||
case "init": { | ||
const { init } = await import("./cli/init"); | ||
await init(isInPackageDirectory, argv); | ||
@@ -102,2 +96,3 @@ return 0; | ||
case "install": { | ||
const { install } = await import("./cli/install"); | ||
await install(isInPackageDirectory, argv); | ||
@@ -107,2 +102,3 @@ return 0; | ||
case "test": { | ||
const { runTests } = await import("./cli/testing"); | ||
await runTests(isInPackageDirectory, argv); | ||
@@ -112,2 +108,3 @@ return 0; | ||
case "info": { | ||
const { info } = await import("./cli/info"); | ||
await info(isInPackageDirectory, argv); | ||
@@ -117,2 +114,3 @@ return 0; | ||
case "repl": { | ||
const { repl } = await import("./cli/repl"); | ||
await repl(isInPackageDirectory, argv); | ||
@@ -122,2 +120,3 @@ return 0; | ||
case "bundle": { | ||
const { bundle } = await import("./cli/bundle"); | ||
await bundle(isInPackageDirectory, argv); | ||
@@ -127,2 +126,3 @@ return 0; | ||
case "format": { | ||
const { format } = await import("./cli/format"); | ||
await format(isInPackageDirectory, argv); | ||
@@ -132,2 +132,3 @@ return 0; | ||
case "template": { | ||
const { template } = await import("./cli/template"); | ||
await template(isInPackageDirectory, argv); | ||
@@ -134,0 +135,0 @@ return 0; |
@@ -19,3 +19,3 @@ import { | ||
longFlag("output", "Output file to generate", string()), | ||
longFlag("quiet", "Dont print any output", empty()), | ||
longFlag("quiet", "Don't print any output", empty()), | ||
longFlag("watch", "Watch Derw files for changes", empty()), | ||
@@ -117,6 +117,9 @@ longFlag( | ||
if (program.flags.watch.isPresent) { | ||
console.log("Watching src..."); | ||
console.log("Watching src and derw-packages..."); | ||
let timer: any; | ||
chokidar | ||
.watch(path.join(process.cwd(), "src")) | ||
.watch([ | ||
path.join(process.cwd(), "src"), | ||
path.join(process.cwd(), "derw-packages"), | ||
]) | ||
.on("all", async (event: Event, path: string): Promise<any> => { | ||
@@ -123,0 +126,0 @@ if (path.endsWith(".derw")) { |
@@ -20,9 +20,6 @@ import { | ||
import * as util from "util"; | ||
import { compileTypescript } from "../compile"; | ||
import { addMissingNamesSuggestions } from "../errors/names"; | ||
import { generate, Target } from "../generator"; | ||
import { loadPackageFile } from "../package"; | ||
import * as derwParser from "../parser"; | ||
import { Block, ContextModule, contextModuleToModule, Import } from "../types"; | ||
import { isTestFile } from "../utils"; | ||
import { ensureDirectoryExists, fileExists, getDerwFiles } from "./utils"; | ||
@@ -153,21 +150,2 @@ | ||
if (isPackageDirectoryAndNoFilesPassed) { | ||
const packageFile = await loadPackageFile("derw-package.json"); | ||
if (packageFile.kind === "err") { | ||
console.log("Failed to parse package file due to:"); | ||
console.log(packageFile.error); | ||
process.exit(1); | ||
} | ||
const validPackage = packageFile.value; | ||
for (const dep of validPackage.dependencies) { | ||
for (const file of await getDerwFiles( | ||
`derw-packages/${dep.name}/src` | ||
)) { | ||
files.push(file); | ||
} | ||
} | ||
} | ||
const outputDir = program.flags.output.isPresent | ||
@@ -231,7 +209,5 @@ ? (program.flags.output.arguments as Ok<string>).value | ||
const isMain = | ||
files.indexOf(fileName) > -1 && !isTestFile(fileName); | ||
let parsed = derwParser.parseWithContext( | ||
derwContents, | ||
isMain ? "Main" : fileName | ||
fileName | ||
); | ||
@@ -258,2 +234,3 @@ | ||
import_.modules.forEach((module) => { | ||
if (module.namespace === "Global") return; | ||
if (isPackageFile) { | ||
@@ -267,3 +244,2 @@ if (module.name.startsWith('"../derw-packages')) { | ||
} | ||
if (module.namespace === "Global") return; | ||
const moduleName = module.name.slice(1, -1); | ||
@@ -347,2 +323,3 @@ imports.push( | ||
if (program.flags.verify.isPresent && target === "ts") { | ||
const { compileTypescript } = await import("../compile"); | ||
const output = compileTypescript(generated); | ||
@@ -399,6 +376,9 @@ | ||
if (program.flags.watch.isPresent) { | ||
if (!isQuiet) console.log("Watching..."); | ||
if (!isQuiet) console.log("Watching src and derw-packages..."); | ||
let timer: any; | ||
chokidar | ||
.watch(path.join(process.cwd(), "src")) | ||
.watch([ | ||
path.join(process.cwd(), "src"), | ||
path.join(process.cwd(), "derw-packages"), | ||
]) | ||
.on("all", async (event: Event, path: string): Promise<any> => { | ||
@@ -405,0 +385,0 @@ if (path.endsWith(".derw")) { |
@@ -0,2 +1,5 @@ | ||
import { bothFlag, empty, help, longFlag, parse, parser } from "@eeue56/baner"; | ||
import * as chokidar from "chokidar"; | ||
import { readFile, writeFile } from "fs/promises"; | ||
import path from "path"; | ||
import { generate } from "../generator"; | ||
@@ -7,2 +10,31 @@ import { parseWithContext } from "../parser"; | ||
const formatParser = parser([ | ||
longFlag("watch", "Watch Derw files for changes", empty()), | ||
bothFlag("h", "help", "This help text", empty()), | ||
]); | ||
function showFormatHelp(): void { | ||
console.log("To format, run `derw format`"); | ||
console.log("To watch use the --watch flag"); | ||
console.log(help(formatParser)); | ||
} | ||
async function formatFile(file: string): Promise<void> { | ||
const derwContents = (await readFile(file)).toString(); | ||
let parsed = parseWithContext(derwContents, "Main"); | ||
if (parsed.errors.length > 0) { | ||
console.log(`Failed to parse ${file}`); | ||
return; | ||
} | ||
const outputDerw = generate("derw", contextModuleToModule(parsed)); | ||
// only write if files are formatted differently | ||
if (derwContents === outputDerw) return; | ||
await writeFile(file, outputDerw); | ||
} | ||
export async function format( | ||
@@ -17,18 +49,50 @@ isInPackageDirectory: boolean, | ||
const files = await getDerwFiles("./src"); | ||
const program = parse(formatParser, argv); | ||
if (program.flags["h/help"].isPresent) { | ||
showFormatHelp(); | ||
return; | ||
} | ||
for (const file of files) { | ||
const derwContents = (await readFile(file)).toString(); | ||
if (program.flags.watch.isPresent) { | ||
console.log("Watching src..."); | ||
let parsed = parseWithContext(derwContents, "Main"); | ||
const files = await getDerwFiles("./src"); | ||
if (parsed.errors.length > 0) { | ||
console.log(`Failed to parse ${file}`); | ||
continue; | ||
for (const file of files) { | ||
await formatFile(file); | ||
} | ||
const outputDerw = generate("derw", contextModuleToModule(parsed)); | ||
let timer: any; | ||
chokidar | ||
.watch(path.join(process.cwd(), "src")) | ||
.on( | ||
"all", | ||
async ( | ||
event: "add" | "addDir" | "change" | "unlink" | "unlinkDir", | ||
path: string | ||
): Promise<any> => { | ||
if (event === "add" || event === "change") { | ||
if (path.endsWith(".derw")) { | ||
if (timer !== null) { | ||
clearTimeout(timer); | ||
} | ||
timer = setTimeout(async () => { | ||
await formatFile(path); | ||
}, 50); | ||
} | ||
} else if (event === "addDir") { | ||
const files = await getDerwFiles(path); | ||
for (const file of files) { | ||
await formatFile(file); | ||
} | ||
} | ||
} | ||
); | ||
} else { | ||
const files = await getDerwFiles("./src"); | ||
await writeFile(file, outputDerw); | ||
for (const file of files) { | ||
await formatFile(file); | ||
} | ||
} | ||
} |
@@ -19,3 +19,3 @@ import { | ||
"dir", | ||
"name of a directory to use as package name e.g stdlib", | ||
"name of a directory to use as package name e.g stdlib. Defaults to current directory's name", | ||
string() | ||
@@ -27,2 +27,3 @@ ), | ||
function showInfoHelp() { | ||
console.log("Initialize a directory as a Derw project."); | ||
console.log(help(initParser)); | ||
@@ -29,0 +30,0 @@ } |
@@ -67,6 +67,26 @@ import { writeFile } from "fs/promises"; | ||
async function run(currentBuffer: string[]): Promise<void> { | ||
module = parseWithContext([ ...currentBuffer ].join("\n"), "Main"); | ||
module = exportEverything(module); | ||
const generated = generateTypescript(contextModuleToModule(module)); | ||
const fileTimestamp = new Date().getTime(); | ||
const filename = `${process.cwd()}/derw-packages/.cli/${fileTimestamp}.ts`; | ||
await writeFile(filename, generated); | ||
currentlyImportedModule = await import(filename); | ||
} | ||
let linesAddedToCurrentBufferSinceLastParsing: string[] = [ ]; | ||
for await (const line of rl) { | ||
if (line.trim() === "") { | ||
currentBuffer.push(""); | ||
module = parseWithContext(currentBuffer.join("\n"), "Main"); | ||
module = parseWithContext( | ||
[ | ||
...currentBuffer, | ||
"", | ||
...linesAddedToCurrentBufferSinceLastParsing, | ||
].join("\n"), | ||
"Main" | ||
); | ||
module = addTypeErrors(module, [ ]); | ||
@@ -78,25 +98,27 @@ | ||
); | ||
linesAddedToCurrentBufferSinceLastParsing = [ ]; | ||
} else { | ||
for (const newLine of linesAddedToCurrentBufferSinceLastParsing) { | ||
currentBuffer.push(newLine); | ||
} | ||
linesAddedToCurrentBufferSinceLastParsing = [ ]; | ||
currentBuffer.push(""); | ||
console.log("Parsed successfully"); | ||
} | ||
} else if (line.trim() === ":run") { | ||
module = parseWithContext([ ...currentBuffer ].join("\n"), "Main"); | ||
module = exportEverything(module); | ||
const generated = generateTypescript(contextModuleToModule(module)); | ||
const fileTimestamp = new Date().getTime(); | ||
const filename = `${process.cwd()}/derw-packages/.cli/${fileTimestamp}.ts`; | ||
await writeFile(filename, generated); | ||
currentlyImportedModule = await import(filename); | ||
await run(currentBuffer); | ||
} else if (line.startsWith(":show")) { | ||
const name = line.split(" ")[1].trim(); | ||
console.log(currentlyImportedModule[name]); | ||
await run(currentBuffer); | ||
1; | ||
if (currentlyImportedModule[name] === undefined) { | ||
console.log(`Couldn't find ${name} in current scope.`); | ||
} else { | ||
console.log(currentlyImportedModule[name]); | ||
} | ||
} else if (line.trim() === ":help") { | ||
console.log("Enter some code, followed by a blank newline."); | ||
console.log("Run the current namespace via :run"); | ||
console.log("And check the values of code via :show <name>"); | ||
console.log( | ||
"And check the values of code via :show <name> after using :run" | ||
); | ||
console.log( | ||
"Or evaluate a constant or function with :eval <function> <args>" | ||
@@ -133,3 +155,5 @@ ); | ||
} else { | ||
currentBuffer.push(line.split("\t").join(" ")); | ||
linesAddedToCurrentBufferSinceLastParsing.push( | ||
line.split("\t").join(" ") | ||
); | ||
} | ||
@@ -136,0 +160,0 @@ rl.prompt(); |
@@ -26,2 +26,4 @@ import { | ||
function showInfoHelp() { | ||
console.log("Generate a Derw file from a template."); | ||
console.log("Also installs required packages."); | ||
console.log(help(templateParser)); | ||
@@ -28,0 +30,0 @@ } |
@@ -25,3 +25,3 @@ import { runner } from "@eeue56/bach/build/bach"; | ||
function showTestingHelp(): void { | ||
console.log("To run tests, run `derw test` from the package directory"); | ||
console.log("To run tests, run `derw test` from the package directory"); | ||
console.log("To watch use the --watch flag"); | ||
@@ -54,6 +54,10 @@ console.log(help(testingParser)); | ||
if (program.flags.watch.isPresent) { | ||
process.argv.push("--clean-exit"); | ||
console.log("Watching src and derw-packages..."); | ||
argv.push("--clean-exit"); | ||
let timer: any; | ||
chokidar | ||
.watch(path.join(process.cwd(), "src")) | ||
.watch([ | ||
path.join(process.cwd(), "src"), | ||
path.join(process.cwd(), "derw-packages"), | ||
]) | ||
.on("error", () => { | ||
@@ -68,3 +72,3 @@ console.log("Got an error"); | ||
timer = setTimeout(async () => { | ||
await compileFiles(isInPackageDirectory, [ ]); | ||
await compileFiles(isInPackageDirectory, argv); | ||
await runner(); | ||
@@ -71,0 +75,0 @@ }, 300); |
@@ -0,1 +1,2 @@ | ||
import { Just } from "@eeue56/ts-core/build/main/lib/maybe"; | ||
import { | ||
@@ -151,3 +152,12 @@ Export, | ||
: getNameFromPath(withoutQuotes); | ||
const exposing = `import { ${module.exposing.join( | ||
const filteredExposing = | ||
module.alias.kind === "nothing" | ||
? module.exposing | ||
: module.exposing.filter( | ||
(expose) => | ||
expose !== | ||
(module.alias as Just<string>).value | ||
); | ||
const exposing = `import { ${filteredExposing.join( | ||
", " | ||
@@ -154,0 +164,0 @@ )} } from ${module.name};`; |
@@ -8,2 +8,3 @@ import { | ||
CaseStatement, | ||
Comment, | ||
Const, | ||
@@ -37,2 +38,3 @@ Constructor, | ||
ModuleReference, | ||
MultilineComment, | ||
Multiplication, | ||
@@ -716,2 +718,12 @@ ObjectLiteral, | ||
function generateComment(comment: Comment): string { | ||
return `-- ${comment.body}`; | ||
} | ||
function generateMultilineComment(comment: MultilineComment): string { | ||
return `{- | ||
${comment.body} | ||
-}`; | ||
} | ||
function generateBlock(syntax: Block): string { | ||
@@ -732,7 +744,24 @@ switch (syntax.kind) { | ||
case "Comment": | ||
return generateComment(syntax); | ||
case "MultilineComment": | ||
return ""; | ||
return generateMultilineComment(syntax); | ||
} | ||
} | ||
function joinBlocks(blocks: Block[]): string { | ||
let output = ""; | ||
for (const block of blocks) { | ||
const generated = generateBlock(block); | ||
if (generated.trim().length === 0) continue; | ||
if (block.kind === "Comment" || block.kind === "MultilineComment") { | ||
output += generated + "\n"; | ||
} else { | ||
output += generated + "\n\n"; | ||
} | ||
} | ||
return output.trim(); | ||
} | ||
export function generateDerw(module: Module): string { | ||
@@ -751,7 +780,4 @@ const importBlocks = module.body.filter((block) => block.kind === "Import"); | ||
importBlocks.length > 0 ? "\n\n" : "", | ||
...nonImportBlocks | ||
.map(generateBlock) | ||
.filter((line) => line.length > 0) | ||
.join("\n\n"), | ||
...joinBlocks(nonImportBlocks), | ||
].join(""); | ||
} |
@@ -672,2 +672,3 @@ import { | ||
moduleName = moduleName.toUpperCase()[0] + moduleName.slice(1); | ||
moduleName = moduleName.split("/").join(".").replace(".derw", ""); | ||
@@ -674,0 +675,0 @@ if (names.length === 0) return `module ${moduleName} exposing (..)`; |
@@ -136,3 +136,5 @@ import { exportTests } from "../blocks"; | ||
prefixLines( | ||
ifStatement.ifLetBody.map(generateBlock).join("\n"), | ||
ifStatement.ifLetBody | ||
.map((block) => generateBlock(block)) | ||
.join("\n"), | ||
4 | ||
@@ -155,3 +157,5 @@ ) | ||
prefixLines( | ||
ifStatement.elseLetBody.map(generateBlock).join("\n"), | ||
ifStatement.elseLetBody | ||
.map((block) => generateBlock(block)) | ||
.join("\n"), | ||
4 | ||
@@ -300,3 +304,8 @@ ) | ||
? "\n" + | ||
prefixLines(branch.letBody.map(generateBlock).join("\n"), 4) | ||
prefixLines( | ||
branch.letBody | ||
.map((block) => generateBlock(block)) | ||
.join("\n"), | ||
4 | ||
) | ||
: ""; | ||
@@ -750,3 +759,8 @@ | ||
? "\n" + | ||
prefixLines(function_.letBody.map(generateBlock).join("\n"), 4) | ||
prefixLines( | ||
function_.letBody | ||
.map((block) => generateBlock(block)) | ||
.join("\n"), | ||
4 | ||
) | ||
: ""; | ||
@@ -859,3 +873,3 @@ | ||
function generateBlock(syntax: Block): string { | ||
function generateBlock(syntax: Block, unionTypeNames?: string[]): string { | ||
switch (syntax.kind) { | ||
@@ -865,3 +879,8 @@ case "Import": | ||
case "Export": | ||
return generateExportBlock(syntax); | ||
return generateExportBlock({ | ||
...syntax, | ||
names: syntax.names.filter( | ||
(name) => !(unionTypeNames || [ ]).includes(name) | ||
), | ||
}); | ||
case "UnionType": | ||
@@ -882,6 +901,10 @@ return generateUnionType(syntax); | ||
export function generateJavascript(module: Module): string { | ||
const unionTypeNames = module.body | ||
.filter((block) => block.kind === "UnionType") | ||
.map((block) => (block as UnionType).type.name); | ||
return [ exportTests(module), ...module.body ] | ||
.map(generateBlock) | ||
.map((b) => generateBlock(b, unionTypeNames)) | ||
.filter((line) => line.length > 0) | ||
.join("\n\n"); | ||
} |
@@ -26,2 +26,3 @@ import { exportTests } from "../blocks"; | ||
IfStatement, | ||
Import, | ||
InEquality, | ||
@@ -69,11 +70,14 @@ isSimpleValue, | ||
function generateUnionType(syntax: UnionType): string { | ||
function generateUnionType(syntax: UnionType, imports: Import[]): string { | ||
const tagCreators = syntax.tags | ||
.map((tag) => { | ||
const typeDefArgs = tag.args | ||
.map((arg) => arg.name + ": " + generateType(arg.type) + ";") | ||
.map( | ||
(arg) => | ||
arg.name + ": " + generateType(arg.type, imports) + ";" | ||
) | ||
.join("\n "); | ||
const funcDefArgs = tag.args | ||
.map((arg) => arg.name + ": " + generateType(arg.type)) | ||
.map((arg) => arg.name + ": " + generateType(arg.type, imports)) | ||
.join(", "); | ||
@@ -97,3 +101,4 @@ | ||
}) | ||
) | ||
), | ||
imports | ||
); | ||
@@ -138,3 +143,4 @@ | ||
}) | ||
) | ||
), | ||
imports | ||
); | ||
@@ -147,12 +153,14 @@ }) | ||
type ${generateType(syntax.type)} = ${tags}; | ||
type ${generateType(syntax.type, imports)} = ${tags}; | ||
`.trim(); | ||
} | ||
function generateProperty(syntax: Property): string { | ||
return `${syntax.name}: ${generateTopLevelType(syntax.type)}`; | ||
function generateProperty(syntax: Property, imports: Import[]): string { | ||
return `${syntax.name}: ${generateTopLevelType(syntax.type, imports)}`; | ||
} | ||
function generateTypeAlias(syntax: TypeAlias): string { | ||
const generatedProperties = syntax.properties.map(generateProperty); | ||
function generateTypeAlias(syntax: TypeAlias, imports: Import[]): string { | ||
const generatedProperties = syntax.properties.map((prop) => | ||
generateProperty(prop, imports) | ||
); | ||
const properties = | ||
@@ -162,3 +170,3 @@ generatedProperties.length === 0 | ||
: " " + generatedProperties.join(";\n ") + ";"; | ||
const type = generateType(syntax.type); | ||
const type = generateType(syntax.type, imports); | ||
const args = | ||
@@ -630,6 +638,23 @@ generatedProperties.length === 0 | ||
function generateTopLevelType(type_: Type): string { | ||
function typeHasOverlapWithImportedModule( | ||
type_: FixedType, | ||
imports: Import[] | ||
): boolean { | ||
for (const import_ of imports) { | ||
for (const module_ of import_.modules) { | ||
if ( | ||
module_.alias.kind === "just" && | ||
module_.alias.value === type_.name | ||
) { | ||
return true; | ||
} | ||
} | ||
} | ||
return false; | ||
} | ||
function generateTopLevelType(type_: Type, imports: Import[]): string { | ||
switch (type_.kind) { | ||
case "GenericType": { | ||
return generateType(type_); | ||
return generateType(type_, imports); | ||
} | ||
@@ -639,4 +664,5 @@ case "FixedType": { | ||
if (type_.args[0] && type_.args[0].kind === "GenericType") { | ||
return generateTopLevelType(type_.args[0]) + "[]"; | ||
return generateTopLevelType(type_.args[0], imports) + "[]"; | ||
} | ||
const fixedArgs = type_.args.filter( | ||
@@ -649,6 +675,8 @@ (type_) => type_.kind === "FixedType" | ||
} else if (fixedArgs.length === 1) { | ||
return `${generateTopLevelType(fixedArgs[0])}[]`; | ||
return `${generateTopLevelType(fixedArgs[0], imports)}[]`; | ||
} | ||
return `(${fixedArgs.map(generateTopLevelType).join(" | ")})[]`; | ||
return `(${fixedArgs | ||
.map((arg) => generateTopLevelType(arg, imports)) | ||
.join(" | ")})[]`; | ||
} | ||
@@ -662,3 +690,3 @@ | ||
return `${type_.name}<${type_.args | ||
.map(generateTopLevelType) | ||
.map((arg) => generateTopLevelType(arg, imports)) | ||
.join(", ")}>`; | ||
@@ -681,7 +709,16 @@ } | ||
const qualifiedName = typeHasOverlapWithImportedModule( | ||
type_, | ||
imports | ||
) | ||
? `${type_.name}.${type_.name}` | ||
: type_.name; | ||
if (args.length === 0) { | ||
return type_.name; | ||
return qualifiedName; | ||
} | ||
return `${type_.name}<${args.map(generateType).join(", ")}>`; | ||
return `${qualifiedName}<${args | ||
.map((arg) => generateType(arg, imports)) | ||
.join(", ")}>`; | ||
} | ||
@@ -692,3 +729,5 @@ case "FunctionType": { | ||
for (const typePart of type_.args.slice(0, -1)) { | ||
parts.push(`arg${index}: ${generateTopLevelType(typePart)}`); | ||
parts.push( | ||
`arg${index}: ${generateTopLevelType(typePart, imports)}` | ||
); | ||
index++; | ||
@@ -701,3 +740,3 @@ } | ||
") => " + | ||
generateType(type_.args[type_.args.length - 1]) | ||
generateType(type_.args[type_.args.length - 1], imports) | ||
); | ||
@@ -708,3 +747,3 @@ } | ||
function generateType(type_: Type): string { | ||
function generateType(type_: Type, imports: Import[]): string { | ||
switch (type_.kind) { | ||
@@ -717,3 +756,3 @@ case "GenericType": { | ||
if (type_.args[0] && type_.args[0].kind === "GenericType") { | ||
return generateType(type_.args[0]) + "[]"; | ||
return generateType(type_.args[0], imports) + "[]"; | ||
} | ||
@@ -727,6 +766,8 @@ const fixedArgs = type_.args.filter( | ||
} else if (fixedArgs.length === 1) { | ||
return `${generateType(fixedArgs[0])}[]`; | ||
return `${generateType(fixedArgs[0], imports)}[]`; | ||
} | ||
return `(${fixedArgs.map(generateType).join(" | ")})[]`; | ||
return `(${fixedArgs | ||
.map((arg) => generateType(arg, imports)) | ||
.join(" | ")})[]`; | ||
} | ||
@@ -748,7 +789,16 @@ | ||
const qualifiedName = typeHasOverlapWithImportedModule( | ||
type_, | ||
imports | ||
) | ||
? `${type_.name}.${type_.name}` | ||
: type_.name; | ||
if (args.length === 0) { | ||
return type_.name; | ||
return qualifiedName; | ||
} | ||
return `${type_.name}<${args.map(generateType).join(", ")}>`; | ||
return `${qualifiedName}<${args | ||
.map((arg) => generateType(arg, imports)) | ||
.join(", ")}>`; | ||
} | ||
@@ -759,3 +809,3 @@ case "FunctionType": { | ||
for (const typePart of type_.args.slice(0, -1)) { | ||
parts.push(`arg${index}: ${generateType(typePart)}`); | ||
parts.push(`arg${index}: ${generateType(typePart, imports)}`); | ||
index++; | ||
@@ -768,3 +818,3 @@ } | ||
") => " + | ||
generateType(type_.args[type_.args.length - 1]) | ||
generateType(type_.args[type_.args.length - 1], imports) | ||
); | ||
@@ -1022,3 +1072,4 @@ } | ||
parentTypeArguments: string[], | ||
parentTypes: Type[] | ||
parentTypes: Type[], | ||
imports: Import[] | ||
): string { | ||
@@ -1030,3 +1081,3 @@ const lines = [ ]; | ||
case "Const": { | ||
lines.push(generateConst(expression)); | ||
lines.push(generateConst(expression, imports)); | ||
break; | ||
@@ -1039,3 +1090,4 @@ } | ||
parentTypeArguments, | ||
parentTypes | ||
parentTypes, | ||
imports | ||
) | ||
@@ -1067,3 +1119,4 @@ ); | ||
parentTypeArguments: string[], | ||
parentTypes: Type[] | ||
parentTypes: Type[], | ||
imports: Import[] | ||
): string { | ||
@@ -1074,6 +1127,13 @@ const functionArguments = function_.args | ||
case "FunctionArg": | ||
return arg.name + ": " + generateTopLevelType(arg.type); | ||
return ( | ||
arg.name + | ||
": " + | ||
generateTopLevelType(arg.type, imports) | ||
); | ||
case "AnonFunctionArg": | ||
return ( | ||
"_" + arg.index + ": " + generateTopLevelType(arg.type) | ||
"_" + | ||
arg.index + | ||
": " + | ||
generateTopLevelType(arg.type, imports) | ||
); | ||
@@ -1101,6 +1161,8 @@ } | ||
.map((block) => | ||
generateBlock(block, [ | ||
...typeArguments, | ||
...parentTypeArguments, | ||
]) | ||
generateBlock( | ||
block, | ||
[ ...typeArguments, ...parentTypeArguments ], | ||
[ ], | ||
imports | ||
) | ||
) | ||
@@ -1120,3 +1182,4 @@ .join("\n"), | ||
parentTypeArguments, | ||
parentTypes | ||
parentTypes, | ||
imports | ||
), | ||
@@ -1126,3 +1189,3 @@ 4 | ||
const returnType = generateTopLevelType(function_.returnType); | ||
const returnType = generateTopLevelType(function_.returnType, imports); | ||
const isSimpleBody = isSimpleValue(function_.body.kind); | ||
@@ -1174,4 +1237,8 @@ | ||
function generateNestedConst(constDef: Const, body: string): string { | ||
const typeDef = generateTopLevelType(constDef.type); | ||
function generateNestedConst( | ||
constDef: Const, | ||
body: string, | ||
imports: Import[] | ||
): string { | ||
const typeDef = generateTopLevelType(constDef.type, imports); | ||
const generatedBlocks = constDef.letBody | ||
@@ -1187,3 +1254,3 @@ .map((block) => generateBlock(block, [ ], [ ])) | ||
function generateConst(constDef: Const): string { | ||
function generateConst(constDef: Const, imports: Import[]): string { | ||
let body = ""; | ||
@@ -1198,3 +1265,4 @@ | ||
constDef, | ||
generateInlineIf(constDef.value) | ||
generateInlineIf(constDef.value), | ||
imports | ||
); | ||
@@ -1210,3 +1278,4 @@ } | ||
constDef, | ||
generateInlineCase(constDef.value) | ||
generateInlineCase(constDef.value), | ||
imports | ||
); | ||
@@ -1222,3 +1291,4 @@ } | ||
constDef, | ||
generateExpression(constDef.value) | ||
generateExpression(constDef.value), | ||
imports | ||
); | ||
@@ -1229,3 +1299,3 @@ } | ||
} | ||
const typeDef = generateTopLevelType(constDef.type); | ||
const typeDef = generateTopLevelType(constDef.type, imports); | ||
@@ -1240,3 +1310,4 @@ return ` | ||
parentTypeArguments?: string[], | ||
parentTypes?: Type[] | ||
parentTypes?: Type[], | ||
imports?: Import[] | ||
): string { | ||
@@ -1249,5 +1320,5 @@ switch (syntax.kind) { | ||
case "UnionType": | ||
return generateUnionType(syntax); | ||
return generateUnionType(syntax, imports || [ ]); | ||
case "TypeAlias": | ||
return generateTypeAlias(syntax); | ||
return generateTypeAlias(syntax, imports || [ ]); | ||
case "Function": | ||
@@ -1257,6 +1328,7 @@ return generateFunction( | ||
parentTypeArguments || [ ], | ||
parentTypes || [ ] | ||
parentTypes || [ ], | ||
imports || [ ] | ||
); | ||
case "Const": | ||
return generateConst(syntax); | ||
return generateConst(syntax, imports || [ ]); | ||
case "Comment": | ||
@@ -1269,6 +1341,9 @@ case "MultilineComment": | ||
export function generateTypescript(module: Module): string { | ||
const imports: Import[] = module.body.filter( | ||
(block) => block.kind === "Import" | ||
) as Import[]; | ||
return [ exportTests(module), ...module.body ] | ||
.map((block) => generateBlock(block)) | ||
.map((block) => generateBlock(block, [ ], [ ], imports)) | ||
.filter((line) => line.length > 0) | ||
.join("\n\n"); | ||
} |
@@ -987,14 +987,1 @@ import { Ok, Result } from "@eeue56/ts-core/build/main/lib/result"; | ||
} | ||
function log(x: string): void { | ||
console.log(x); | ||
tokenize(x) | ||
.map((token) => { | ||
if ((token as any).body) | ||
return `${token.kind}("${(token as any).body}"),`; | ||
return `${token.kind}(),`; | ||
}) | ||
.forEach((token) => { | ||
console.log(token); | ||
}); | ||
} |
@@ -871,7 +871,9 @@ import { Maybe } from "@eeue56/ts-core/build/main/lib/maybe"; | ||
kind: "Comment"; | ||
body: string; | ||
}; | ||
export function Comment(): Comment { | ||
export function Comment(body: string): Comment { | ||
return { | ||
kind: "Comment", | ||
body, | ||
}; | ||
@@ -882,7 +884,9 @@ } | ||
kind: "MultilineComment"; | ||
body: string; | ||
}; | ||
export function MultilineComment(): MultilineComment { | ||
export function MultilineComment(body: string): MultilineComment { | ||
return { | ||
kind: "MultilineComment", | ||
body, | ||
}; | ||
@@ -889,0 +893,0 @@ } |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
14894060
24914
612
12
115