From 1083c9439b4e475ed0f613354200d6a94c474e49 Mon Sep 17 00:00:00 2001 From: Daniel Moore Date: Sun, 10 Dec 2023 16:25:33 -0800 Subject: [PATCH 1/2] Support mjs loading --- source/compiler.civet | 48 +++++++++++++++++++++++-------------------- source/main.civet | 26 +++++++++++++++++++++++ test/main.coffee | 11 +++++++++- 3 files changed, 62 insertions(+), 23 deletions(-) diff --git a/source/compiler.civet b/source/compiler.civet index 531b357..bd2fd47 100644 --- a/source/compiler.civet +++ b/source/compiler.civet @@ -3,11 +3,12 @@ import type { HeraAST, HeraRules, StructuralHandling } from ./hera-types.ts export type CompilerOptions = { - filename: string - inlineMap: boolean - source: string - types: boolean + filename?: string + inlineMap?: boolean + source?: string + types?: boolean libPath?: string | undefined + module?: boolean } strDefs: string[] := [] @@ -266,15 +267,15 @@ compileRulesObject := (ruleNames: string[]) -> ${meat} }` -compileExports := (options: CompilerOptions, ruleNames: string[]) -> - if options.types +compileExports := (ruleNames: string[], module: boolean) -> + if module meat := ruleNames.map (name) -> ` ${name}` .join(",\n") return `export {\n${meat}\n}` - else - ruleNames.map (name) -> + + return ruleNames.map (name) -> `exports.${name} = ${name};` .join("\n") @@ -309,7 +310,10 @@ defaultOptions: CompilerOptions := export function compile(rules: HeraRules, maybeOptions?: CompilerOptions) options := { ...defaultOptions, ...maybeOptions } - { types } := options + strDefs.length = 0 + reDefs.length = 0 + + { types, module } := options /* c8 ignore next */ libPath := options.libPath or defaultOptions.libPath ruleNames := Object.keys(rules) @@ -330,8 +334,9 @@ export function compile(rules: HeraRules, maybeOptions?: CompilerOptions) sm = SourceMap(options.source) genOpts.updateSourceMap = sm.updateSourceMap - head := (types ? tsHead : jsHead).replace("\"./machine.js\"", JSON.stringify(libPath)) - tail := (types ? tsTail : jsTail).replace("\"./machine.js\"", JSON.stringify(libPath)) + head := (module ? mjsHead : cjsHead).replace("\"./machine.js\"", JSON.stringify(libPath)) + tail := types ? tsTail : jsTail + exp := (module ? mjsExport : cjsExport) code := generate [ head @@ -344,7 +349,9 @@ export function compile(rules: HeraRules, maybeOptions?: CompilerOptions) "\n\n" tail "\n\n" - compileExports(options, ruleNames) + exp + "\n\n" + compileExports(ruleNames, !!module) "\n\n" //@ts-ignore rules[Symbol.for("code")] @@ -409,7 +416,7 @@ generate := (node: ASTNode, options: GenerateOptions): string -> /* c8 ignore next */ throw new Error "unknown node type" -jsHead := """ +cjsHead := """ const { $C, $E, @@ -429,9 +436,7 @@ jsHead := """ $TS, $TV, $Y, - HeraGrammar, Parser, - ParseState, ParserContext, ParserOptions, Validator @@ -468,12 +473,14 @@ jsTail := """ } } }()) +""" +cjsExport := """ exports.default = parser exports.parse = parser.parse """ -tsHead := """ +mjsHead := """ import { $C, $E, @@ -493,13 +500,8 @@ tsHead := """ $TS, $TV, $Y, - HeraGrammar, - Parser, - ParseState, - ParserContext, - ParserOptions, Validator - } from "./machine.ts" + } from "./machine.js" """ @@ -532,7 +534,9 @@ tsTail := """ } } }()) +""" +mjsExport := """ export default parser export const { parse } = parser """ diff --git a/source/main.civet b/source/main.civet index b3507b1..ef3f330 100644 --- a/source/main.civet +++ b/source/main.civet @@ -38,9 +38,35 @@ generate := (src: string) => { } } +modImport := async (src: string) => { + fs := await import('node:fs/promises') + { fileURLToPath } := await import "url" + { dirname } := await import "path" + + __dirname := dirname fileURLToPath(import.meta.url) + + js := compile(parse(src), { + module: true, + libPath: `${ __dirname }/machine.js`, + }) + + // random temp file + tmpPath := `${ __dirname }/hera-tmp-${ Math.random().toString(36).slice(2) }.mjs` + await fs.writeFile(tmpPath, js) + + try + (await import tmpPath) as { + parse: (input: string, options?: ParserOptions) => unknown + } + finally + await fs.unlink(tmpPath) +} + export { parse compile + execMod + modImport generate grammarToEBNF } diff --git a/test/main.coffee b/test/main.coffee index 5a29160..da689b0 100644 --- a/test/main.coffee +++ b/test/main.coffee @@ -1,5 +1,5 @@ import assert from "assert" -import hera, { compile, generate } from "../source/main.civet" +import hera, { compile, generate, modImport } from "../source/main.civet" test = it @@ -787,3 +787,12 @@ describe "Hera", -> value: "a" }, "the data"] ] + + describe "modImport", -> + it "should generate module", -> + {parse} = await modImport """ + Rule + "a" + """ + + assert parse("a") From 51f1949de56472b2f5c207d27f6a6ceb85c43a85 Mon Sep 17 00:00:00 2001 From: Daniel Moore Date: Sun, 4 Feb 2024 19:12:39 -0800 Subject: [PATCH 2/2] ESM loader for node 18.19 --- build/compile | 2 ++ package.json | 5 +++-- build/hera-esm.mjs => source/esm.mjs | 21 +++++++++++++++++---- 3 files changed, 22 insertions(+), 6 deletions(-) rename build/hera-esm.mjs => source/esm.mjs (56%) diff --git a/build/compile b/build/compile index 001c88e..bcb8983 100644 --- a/build/compile +++ b/build/compile @@ -27,3 +27,5 @@ fi # build hera esbuild-plugin civet < source/esbuild-plugin.civet > esbuild-plugin.js + +cp source/esm.mjs dist/ diff --git a/package.json b/package.json index 4fc4bf2..193935a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@danielx/hera", - "version": "0.8.10", + "version": "0.8.11", "description": "Small and fast parsing expression grammars", "devDependencies": { "@babel/core": "^7.17.8", @@ -38,7 +38,7 @@ "loader": [ "ts-node/esm", "./build/coffee-esm.mjs", - "./build/hera-esm.mjs", + "./source/esm.mjs", "@danielx/civet/esm" ], "reporter": "spec", @@ -90,6 +90,7 @@ "./lib": "./dist/machine.js", "./esbuild-plugin": "./esbuild-plugin.js", "./register": "./register.js", + "./esm": "./dist/esm.mjs", "./*": "./*", "./dist/*": "./dist/*" }, diff --git a/build/hera-esm.mjs b/source/esm.mjs similarity index 56% rename from build/hera-esm.mjs rename to source/esm.mjs index dda2b61..034ae83 100644 --- a/build/hera-esm.mjs +++ b/source/esm.mjs @@ -1,5 +1,7 @@ -import { pathToFileURL } from 'url'; -import "../register.js"; +import { fileURLToPath, pathToFileURL } from 'url'; + +import fs from "fs"; +import { compile } from "@danielx/hera"; const baseURL = pathToFileURL(process.cwd() + '/').href; const extensionsRegex = /\.hera$/; @@ -20,9 +22,20 @@ export async function resolve(specifier, context, defaultResolve) { export async function load(url, context, next) { if (extensionsRegex.test(url)) { - return next(url.replace(extensionsRegex, ".cjs"), { - format: "commonjs" + const filename = fileURLToPath(url); + const source = compile(fs.readFileSync(filename, 'utf8'), { + filename, + inlineMap: true, + module: true, }); + + // TODO: how to avoid shortCircuit? + // We may want to pass the module to babel or whatever in the future + return { + format: "module", + source, + shortCircuit: true, + }; } // Let Node.js handle all other URLs.