diff --git a/package.json b/package.json index 76c65f4..f4440c5 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ }, "dependencies": { "@alex.garcia/unofficial-observablehq-compiler": "0.6.0-alpha.9", + "@observablehq/prettier": "^2.2.1-alpha.1", "@observablehq/runtime": "4.9", "chalk": "^4.1.1", "chokidar": "^3.5.1", diff --git a/src/dataflow b/src/dataflow index 2a5fb8b..f316285 100755 --- a/src/dataflow +++ b/src/dataflow @@ -2,6 +2,7 @@ const { program } = require("commander"); const { compileNotebook } = require("./compile"); const { runServer } = require("./run"); +const {format} = require("./format"); function parseSecrets(values) { const secrets = new Map(); @@ -52,7 +53,7 @@ program }); }); -program + program .command("run ") .description( "Start a server that runs the given Observable notebook (from a .ojs file)." @@ -87,4 +88,18 @@ program }); }); + program + .command("format ") + .description( + "Format a notebook's source with the custom Prettier plugin." + ) + .option( + "--write", + "Over-write the given file with the formatted source.", + false + ) + .action((notebook, options) => { + format(notebook, options); + }); + program.parse(process.argv); diff --git a/src/format.js b/src/format.js new file mode 100644 index 0000000..f31d51b --- /dev/null +++ b/src/format.js @@ -0,0 +1,73 @@ +const prettier = require("@observablehq/prettier"); +const {ModuleParser} = require("@observablehq/parser"); +const {readFileSync, writeFileSync} = require("rw").dash; + +// this was not fun to figure out :( +function prettify(source) { + return prettier.format(source, + { + parser: "dataflow", + semi: true, + singleQuote: true, + embeddedLanguageFormatting: "off", + plugins: [ + { + parsers: { + dataflow: { + astFormat: "estree", + locStart: (e) => e.start, + locEnd: (e) => e.end, + parse: (src) => { + const comments = []; + const tokens = []; + const program = ModuleParser.parse(src, { + onComment: comments, + onToken: tokens, + ranges: true, + allowAwaitOutsideFunction: true, + allowReturnOutsideFunction: true, + allowImportExportEverywhere: true + }); + return { + ...program, + type: "Program", + body: program.cells + }; + } + } + } + } + ] + }) +} + +// let body = [shouldAddParens ? "(" : "", path.call(print, "body"), shouldAddParens ? ")" : "", n.body.type === "Identifier" ? ";" : ""]; +function prettifyX(source) { + return prettier.format(source, { + semi: true, + singleQuote: true, + embeddedLanguageFormatting: "off", + parser(text) { + const ast = ModuleParser.parse(text); + return { + ...ast, + body: ast.cells + }; + }, + }); +} +function format(inFile, options) { + const {write=false} = options; + const src = readFileSync(inFile, "utf8"); + const formatted = prettifyX(src); + if(write) { + writeFileSync(inFile, formatted, "utf8"); + } + else { + console.log(formatted); + } +} + +module.exports = { + format +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index f64e8a1..41598e7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23,6 +23,11 @@ acorn "^7.1.1" acorn-walk "^7.0.0" +"@observablehq/prettier@^2.2.1-alpha.1": + version "2.2.1-alpha.1" + resolved "https://registry.yarnpkg.com/@observablehq/prettier/-/prettier-2.2.1-alpha.1.tgz#f84ba0372c0ccb5ec7e9bb1c3955f5de1fe92fca" + integrity sha512-1DZEC2xCtL1NRehFxfgj3nETzTCkioX2O8am5a7YrsA2AtvSZ6lvy4+YR/QS9Hbw6YJe6PnAETm6biSuVDyVgg== + "@observablehq/runtime@4.9": version "4.9.0" resolved "https://registry.yarnpkg.com/@observablehq/runtime/-/runtime-4.9.0.tgz#eb359942df2b3fc76dadf74943cc6c60ad0cd259"