-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The nodeJs tool is used to run new ES JavaScript code in Node.js
- Loading branch information
Matthew Giannini
authored and
Matthew Giannini
committed
Aug 14, 2023
1 parent
a2051d8
commit 9a151aa
Showing
10 changed files
with
791 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
#! /usr/bin/env fan | ||
// | ||
// Copyright (c) 2006, Brian Frank and Andy Frank | ||
// Licensed under the Academic Free License version 3.0 | ||
// | ||
// History: | ||
// 17 Jul 2023 Matthew Giannini creation | ||
// | ||
|
||
using build | ||
|
||
** | ||
** Build: nodeJs | ||
** | ||
class Build : BuildPod | ||
{ | ||
new make() | ||
{ | ||
podName = "nodeJs" | ||
summary = "Utilities for running Fantom in Node JS" | ||
meta = ["org.name": "Fantom", | ||
"org.uri": "https://fantom.org/", | ||
"proj.name": "Fantom Core", | ||
"proj.uri": "https://fantom.org/", | ||
"license.name": "Academic Free License 3.0", | ||
"vcs.name": "Git", | ||
"vcs.uri": "https://github.com/fantom-lang/fantom", | ||
] | ||
depends = ["sys 1.0", | ||
"compiler 1.0", | ||
"compilerEs 1.0", | ||
"fandoc 1.0", | ||
"util 1.0", | ||
] | ||
srcDirs = [ | ||
`fan/`, | ||
`fan/cmd/`, | ||
// `fan/ts/`, | ||
] | ||
resDirs = [ | ||
`res/`, | ||
] | ||
docApi = false | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,202 @@ | ||
// | ||
// Copyright (c) 2023, SkyFoundry LLC | ||
// All Rights Reserved | ||
// | ||
// History: | ||
// 27 Jul 2023 Matthew Giannini Creation | ||
// | ||
|
||
using compilerEs | ||
using util | ||
|
||
** | ||
** Utility for emitting various JS code | ||
** | ||
internal class EmitUtil | ||
{ | ||
|
||
////////////////////////////////////////////////////////////////////////// | ||
// Constructor | ||
////////////////////////////////////////////////////////////////////////// | ||
|
||
new make(NodeJsCmd cmd) | ||
{ | ||
this.cmd = cmd | ||
} | ||
|
||
private NodeJsCmd cmd | ||
private Pod[] depends := [Pod.find("sys")] | ||
private File? scriptJs := null | ||
private ModuleSystem ms() { cmd.ms } | ||
private Bool isCjs() { ms.moduleType == "cjs" } | ||
|
||
////////////////////////////////////////////////////////////////////////// | ||
// Configure Dependencies | ||
////////////////////////////////////////////////////////////////////////// | ||
|
||
** Configure the pod dependencies before emitting any code | ||
This withDepends(Pod[] pods) | ||
{ | ||
this.depends = Pod.orderByDepends(Pod.flattenDepends(pods)) | ||
return this | ||
} | ||
|
||
** Configure the script js for a Fantom script | ||
This withScript(File scriptJs) | ||
{ | ||
this.scriptJs = scriptJs | ||
return this | ||
} | ||
|
||
////////////////////////////////////////////////////////////////////////// | ||
// Util | ||
////////////////////////////////////////////////////////////////////////// | ||
|
||
private File? podJsFile(Pod pod, Str name := pod.name) | ||
{ | ||
ext := isCjs ? "js" : "mjs" | ||
script := "${name}.${ext}" | ||
return pod.file(`/js/$script`, false) | ||
} | ||
|
||
////////////////////////////////////////////////////////////////////////// | ||
// Emit | ||
////////////////////////////////////////////////////////////////////////// | ||
|
||
Void writePackageJson([Str:Obj?] json := [:]) | ||
{ | ||
if (json["name"] == null) json["name"] = "@fantom/fan" | ||
if (json["version"] == null) json["version"] = Pod.find("sys").version.toStr | ||
ms.writePackageJson(json) | ||
} | ||
|
||
** Copy all pod js files into '<dir>/node_modules/'. | ||
// ** Also copies in mime.js, units.js, and indexed-props.js | ||
Void writeNodeModules() | ||
{ | ||
writeFanJs | ||
writeNode | ||
writeDepends | ||
writeScriptJs | ||
writeMimeJs | ||
writeUnitsJs | ||
// TODO: indexed-props? | ||
} | ||
|
||
** Write 'es6.js' (grab it from sys.js) | ||
Void writeFanJs() | ||
{ | ||
out := ms.file("fan").out | ||
podJsFile(Pod.find("sys"), "fan").in.pipe(out) | ||
out.flush.close | ||
} | ||
|
||
|
||
** Write 'es6.js' (grab it from sys.js) | ||
Void writeEs6() | ||
{ | ||
out := ms.file("es6").out | ||
podJsFile(Pod.find("sys"), "es6").in.pipe(out) | ||
out.flush.close | ||
} | ||
|
||
** Write 'node.js' | ||
Void writeNode() | ||
{ | ||
modules := ["os", "path", "fs", "crypto", "url", "zlib"] | ||
out := ms.file("node").out | ||
ms.writeBeginModule(out) | ||
modules.each |m, i| { ms.writeInclude(out, m) } | ||
ms.writeExports(out, modules) | ||
ms.writeEndModule(out).flush.close | ||
} | ||
|
||
** Write js from configured pod dependencies | ||
Void writeDepends() | ||
{ | ||
copyOpts := ["overwrite": true] | ||
|
||
this.depends.each |pod| | ||
{ | ||
file := podJsFile(pod) | ||
target := ms.file(pod.name) | ||
if (file != null) | ||
{ | ||
file.copyTo(target, copyOpts) | ||
// if (pod.name == "sys") | ||
// { | ||
// out := target.out | ||
// file.in.pipe(out) | ||
// out.flush.close | ||
// } | ||
// else file.copyTo(target, copyOpts) | ||
} | ||
} | ||
} | ||
|
||
** Write the fantom script if one was configured | ||
Void writeScriptJs() | ||
{ | ||
if (scriptJs == null) return | ||
out := ms.file(scriptJs.basename).out | ||
try | ||
{ | ||
scriptJs.in.pipe(out) | ||
} | ||
finally out.flush.close | ||
} | ||
|
||
** Write the code for configuring MIME types to 'fan_mime.js' | ||
Void writeMimeJs() | ||
{ | ||
out := ms.file("fan_mime").out | ||
JsExtToMime(ms).write(out) | ||
out.flush.close | ||
} | ||
|
||
** Write the unit database to 'fan_units.js' | ||
Void writeUnitsJs() | ||
{ | ||
out := ms.file("fan_units").out | ||
JsUnitDatabase(ms).write(out) | ||
out.flush.close | ||
} | ||
|
||
////////////////////////////////////////////////////////////////////////// | ||
// Str | ||
////////////////////////////////////////////////////////////////////////// | ||
|
||
** Get a Str with all the include statements for the configured | ||
** dependencies that is targetted for the current module system | ||
** This method assumes the script importing the modules is in | ||
** the parent directory. | ||
Str includeStatements() | ||
{ | ||
baseDir := "./${ms.moduleDir.name}/" | ||
buf := Buf() | ||
this.depends.each |pod| | ||
{ | ||
if ("sys" == pod.name) | ||
{ | ||
// need explicit js ext because node has built-in lib named sys | ||
ms.writeInclude(buf.out, "sys.ext", baseDir) | ||
ms.writeInclude(buf.out, "fan_mime.ext", baseDir) | ||
} | ||
else ms.writeInclude(buf.out, "${pod.name}.ext", baseDir) | ||
} | ||
if (scriptJs != null) throw Err("TODO: script js") | ||
// if (scriptJs != null) | ||
// buf.add("import * as ${scriptJs.basename} from './${ms.moduleType}/${scriptJs.name}';\n") | ||
return buf.flip.readAllStr | ||
} | ||
|
||
** Get the JS code to configure the Env home, work and temp directories. | ||
Str envDirs() | ||
{ | ||
buf := StrBuf() | ||
buf.add(" sys.Env.cur().__homeDir = sys.File.os(${Env.cur.homeDir.pathStr.toCode});\n") | ||
buf.add(" sys.Env.cur().__workDir = sys.File.os(${Env.cur.workDir.pathStr.toCode});\n") | ||
buf.add(" sys.Env.cur().__tempDir = sys.File.os(${Env.cur.tempDir.pathStr.toCode});\n") | ||
return buf.toStr | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// | ||
// Copyright (c) 2023, SkyFoundry LLC | ||
// All Rights Reserved | ||
// | ||
// History: | ||
// 27 Jul 2023 Matthew Giannini Creation | ||
// | ||
|
||
using util | ||
|
||
** | ||
** Command line main | ||
** | ||
class Main | ||
{ | ||
static Int main(Str[] args) | ||
{ | ||
// lookup command | ||
if (args.isEmpty) args = ["help"] | ||
name := args.first | ||
cmd := NodeJsCmd.find(name) | ||
if (cmd == null) | ||
{ | ||
echo("ERROR: unknown nodeJs command '$name'") | ||
return 1 | ||
} | ||
|
||
// strip commandname from args and process as util::AbstractMain | ||
return cmd.main(args.dup[1..-1]) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
// | ||
// Copyright (c) 2023, SkyFoundry LLC | ||
// All Rights Reserved | ||
// | ||
// History: | ||
// 27 Jul 2023 Matthew Giannini Creation | ||
// | ||
|
||
using compilerEs | ||
using util | ||
|
||
** | ||
** NodeJs command target | ||
** | ||
abstract class NodeJsCmd : AbstractMain | ||
{ | ||
** Find a specific target or return null | ||
static NodeJsCmd? find(Str name) | ||
{ | ||
list.find |t| { t.name == name || t.aliases.contains(name) } | ||
} | ||
|
||
** List installed commands | ||
static NodeJsCmd[] list() | ||
{ | ||
NodeJsCmd[] acc := NodeJsCmd#.pod.types.mapNotNull |t->NodeJsCmd?| | ||
{ | ||
if (t.isAbstract || !t.fits(NodeJsCmd#)) return null | ||
return t.make | ||
} | ||
acc.sort |a, b| { a.name <=> b.name } | ||
return acc | ||
} | ||
|
||
** App name is "nodeJs {name}" | ||
override final Str appName() { "nodeJs ${name}" } | ||
|
||
** Log name is "nodeJs" | ||
override Log log() { Log.get("nodeJs") } | ||
|
||
** Command name | ||
abstract Str name() | ||
|
||
** Command aliases/shortcuts | ||
virtual Str[] aliases() { Str[,] } | ||
|
||
** Run the command. Return zero on success | ||
abstract override Int run() | ||
|
||
** Single line summary of the command for help | ||
abstract Str summary() | ||
|
||
@Opt { help="Verbose debug output"; aliases=["v"] } | ||
Bool verbose | ||
|
||
@Opt { help = "Root directory for staging Node.js environment"; aliases = ["d"] } | ||
virtual File dir := Env.cur.tempDir.plus(`nodeJs/`) | ||
|
||
@Opt { help = "Emit CommonJs" } | ||
Bool cjs := false | ||
|
||
////////////////////////////////////////////////////////////////////////// | ||
// NodeJs | ||
////////////////////////////////////////////////////////////////////////// | ||
|
||
protected Bool checkForNode() | ||
{ | ||
cmd := ["which", "-s", "node"] | ||
if ("win32" == Env.cur.os) cmd = ["where", "node"] | ||
if (Process(cmd) { it.out = null }.run.join != 0) | ||
{ | ||
err("Node not found") | ||
printLine("Please ensure Node.js is installed and available in your PATH") | ||
return false | ||
} | ||
return true | ||
} | ||
|
||
** Get the module system environment | ||
once ModuleSystem ms() | ||
{ | ||
return this.cjs ? CommonJs(this.dir) : Esm(this.dir) | ||
} | ||
|
||
** Get the JS emit utility | ||
internal once EmitUtil emit() { EmitUtil(this) } | ||
|
||
////////////////////////////////////////////////////////////////////////// | ||
// Console | ||
////////////////////////////////////////////////////////////////////////// | ||
|
||
** Print a line to stdout | ||
Void printLine(Str line := "") { Env.cur.out.printLine(line) } | ||
|
||
** Print error message and return 1 | ||
Int err(Str msg) { printLine("ERROR: ${msg}"); return 1 } | ||
|
||
|
||
} |
Oops, something went wrong.