From 930c6ef474eb93c7bce6fcef1627625ec1f66d43 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Fri, 17 Jun 2022 21:45:58 -0700 Subject: [PATCH] First attempt at new CLI --- packages/cli/.gitignore | 4 ++ packages/cli/README.md | 20 ++++++++ packages/cli/index.js | 97 +++++++++++++++++++++++++++++++++++++++ packages/cli/package.json | 22 +++++++++ yarn.lock | 10 ++++ 5 files changed, 153 insertions(+) create mode 100644 packages/cli/.gitignore create mode 100644 packages/cli/README.md create mode 100644 packages/cli/index.js create mode 100644 packages/cli/package.json diff --git a/packages/cli/.gitignore b/packages/cli/.gitignore new file mode 100644 index 00000000..03087060 --- /dev/null +++ b/packages/cli/.gitignore @@ -0,0 +1,4 @@ +## Artifacts +*.swp +/node_modules/ +yarn-error.log \ No newline at end of file diff --git a/packages/cli/README.md b/packages/cli/README.md new file mode 100644 index 00000000..d1ec4b8b --- /dev/null +++ b/packages/cli/README.md @@ -0,0 +1,20 @@ +## Squiggle CLI + +This package can be used to incorporate a very simple `import` system into Squiggle. + +To use, write special files with a ``.squiggleU`` file type. In these files, you can write lines like, + +``` +@import(models/gdp_over_time.squiggle, gdpOverTime) +gdpOverTime(2.5) +``` + +The imports will be replaced with the contents of the file in `models/gdp_over_time.squiggle` upon compilation. The ``.squiggleU`` file will be converted into a ``.squiggle`` file with the ``import`` statement having this replacement. + +## Running + +### `npx squiggle-cli-experimental compile` +Runs compilation in the current directory and all of its subdirectories. + +### `npx squiggle-cli-experimental watch` +Watches ``.squiggleU`` files in the current directory (and subdirectories) and rebuilds them when they are saved. Note that this will *not* rebuild files when their dependencies are changed, just when they are changed directly. \ No newline at end of file diff --git a/packages/cli/index.js b/packages/cli/index.js new file mode 100644 index 00000000..8d040c60 --- /dev/null +++ b/packages/cli/index.js @@ -0,0 +1,97 @@ +#!/usr/bin/env node + +import fs from "fs"; +import path from "path"; +import indentString from "indent-string"; +import chokidar from "chokidar"; +import chalk from "chalk"; +import { Command } from "commander"; +import glob from "glob"; + +function run(fileName) { + const fileContents = fs.readFileSync(fileName, "utf-8"); + + const regex = /\@import\(\s*([^)]+?)\s*\)/g; + const matches = Array.from(fileContents.matchAll(regex)).map((r) => + r[1].split(/\s*,\s*/) + ); + const newContent = fileContents.replaceAll(regex, ""); + const appendings = []; + + matches.forEach((r) => { + const importFileName = r[0]; + const rename = r[1]; + const item = fs.statSync(importFileName); + if (item.isFile()) { + const data = fs.readFileSync( + importFileName, + { encoding: "utf8" }, + function (err, _data) { + if (err) { + console.log(`Error importing ${importFileName}: `, err); + return false; + } + return _data; + } + ); + if (data) { + let importString = `${rename} = {\n${indentString(data, 2)}\n}`; + appendings.push(importString); + } + } else { + console.log( + chalk.red(`Import Error`) + + `: ` + + chalk.cyan(importFileName) + + ` not found in file ` + + chalk.cyan(fileName) + + `. Make sure the @import file names all exist in this repo.` + ); + } + }); + const imports = appendings.join("\n"); + + const newerContent = imports.concat(newContent); + const parsedPath = path.parse(fileName) + const newFilename = parsedPath.dir + "/" + parsedPath.name + ".squiggle"; + fs.writeFileSync(newFilename, newerContent); + console.log(chalk.cyan(`Updated ${fileName} -> ${newFilename}`)); +} + +function compile() { + glob("**/*.squiggleU", (_err, files) => { + files.forEach(run); + }); +} + +function watch() { + chokidar + .watch("**.squiggleU") + .on("ready", () => console.log(chalk.green("Ready!"))) + .on("change", (event, _) => { + run(event); + }); +} + +const program = new Command(); + +program + .name("squiggle-utils") + .description("CLI to transform squiggle files with @imports") + .version("0.0.1"); + +program + .command("watch") + .description("watch files and compile on the fly") + .action(() => { + watch(); + }); + +program + .command("compile") + .description("compile all .squiggleU files into .squiggle files") + .action(() => { + compile(); + }); + +program.parse(); diff --git a/packages/cli/package.json b/packages/cli/package.json new file mode 100644 index 00000000..9ee84bca --- /dev/null +++ b/packages/cli/package.json @@ -0,0 +1,22 @@ +{ + "name": "squiggle-cli-experimental", + "version": "0.0.1", + "main": "index.js", + "homepage": "https://squiggle-language.com", + "author": "Quantified Uncertainty Research Institute", + "bin": "index.js", + "type": "module", + "scripts": { + "start": "node ." + }, + "license": "MIT", + "dependencies": { + "chalk": "^5.0.1", + "chokidar": "^3.5.3", + "commander": "^9.3.0", + "fs": "^0.0.1-security", + "glob": "^8.0.3", + "indent-string": "^5.0.0" + } + } + \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 157d637f..8ccdcc12 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9292,6 +9292,11 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== +fs@^0.0.1-security: + version "0.0.1-security" + resolved "https://registry.yarnpkg.com/fs/-/fs-0.0.1-security.tgz#8a7bd37186b6dddf3813f23858b57ecaaf5e41d4" + integrity sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w== + fsevents@^1.2.7: version "1.2.13" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" @@ -10268,6 +10273,11 @@ indent-string@^4.0.0: resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== +indent-string@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-5.0.0.tgz#4fd2980fccaf8622d14c64d694f4cf33c81951a5" + integrity sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg== + infer-owner@^1.0.3, infer-owner@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467"