Full Code of rtfeldman/node-elm-compiler for AI

master 5801685cf669 cached
32 files
29.0 KB
8.4k tokens
21 symbols
1 requests
Download .txt
Repository: rtfeldman/node-elm-compiler
Branch: master
Commit: 5801685cf669
Files: 32
Total size: 29.0 KB

Directory structure:
gitextract_lihzjcl8/

├── .gitignore
├── .npmignore
├── .travis.yml
├── LICENSE
├── README.md
├── appveyor.yml
├── examples/
│   ├── .gitignore
│   ├── HelloWorld.elm
│   ├── compileHelloWorld.js
│   └── elm.json
├── package.json
├── src/
│   ├── index.ts
│   └── worker.ts
├── test/
│   ├── compile.ts
│   ├── compileSync.ts
│   ├── compileToStringSync.ts
│   └── fixtures/
│       ├── Bad.elm
│       ├── BasicWorker.elm
│       ├── Nested/
│       │   ├── Child.elm
│       │   ├── Parent/
│       │   │   └── Test.elm
│       │   └── Test/
│       │       └── Child.elm
│       ├── Parent.elm
│       ├── ParentWithNestedDeps.elm
│       ├── ParentWithPort.elm
│       ├── ParentWithUnindentedMultilineComment.elm
│       ├── SimplestMain.elm
│       ├── Test/
│       │   ├── ChildA.elm
│       │   ├── ChildB.elm
│       │   └── Sample/
│       │       └── NestedChild.elm
│       ├── TypeError.elm
│       └── elm.json
└── tsconfig.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Logs
logs
*.log

# Runtime data
pids
*.pid
*.seed

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directory
# Commenting this out is preferred by some people, see
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
node_modules

# Users Environment Variables
.lock-wscript

# Elm stuff
elm-stuff

test/fixtures/index.html

# Compiled files
dist

================================================
FILE: .npmignore
================================================
# Logs
logs
*.log

# Runtime data
pids
*.pid
*.seed

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# node-waf configuration
.lock-wscript

build

# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules
elm-stuff
tmp

# Specific to .npmignore
.travis.yml
README.md

tests
test

# Do not distribute TypeScript and source files
src
tsconfig.json

================================================
FILE: .travis.yml
================================================
sudo: false

language: node_js
node_js:
  - "8"
  - "10"
  - "12"

os:
  - linux
  - osx

env:
  matrix:
    - ELM_VERSION=0.19.0-no-deps

before_install:
  - rm -rf ~/.elm

install:
  - node --version
  - npm --version
  - npm install -g elm@$ELM_VERSION
  - npm install

script:
  - npm test


================================================
FILE: LICENSE
================================================
Copyright (c) 2015, Richard Feldman
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

* Neither the name of elm-stylesheets nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.



================================================
FILE: README.md
================================================
# node-elm-compiler [![Version](https://img.shields.io/npm/v/node-elm-compiler.svg)](https://www.npmjs.com/package/node-elm-compiler) [![Travis build Status](https://travis-ci.org/rtfeldman/node-elm-compiler.svg?branch=master)](http://travis-ci.org/rtfeldman/node-elm-compiler) [![AppVeyor build status](https://ci.appveyor.com/api/projects/status/xv83jcomgb81i1iu/branch/master?svg=true)](https://ci.appveyor.com/project/rtfeldman/node-elm-compiler/branch/master)

Wraps [Elm](https://elm-lang.org) and exposes a [Node](https://nodejs.org) API to compile Elm 0.19 sources.

# Example

```bash
$ npm install
$ cd examples
$ node compileHelloWorld.js
```

# Releases

## 5.0.5

Upgrade find-elm-dependencies and lodash dependencies to fix CVE-2020-8203 vulnerability.

## 5.0.2

Upgrade lodash dependency to fix security audit warning. ([#93](https://github.com/rtfeldman/node-elm-compiler/pull/93))

## 5.0.1

Add helpful errors if you use the obsolete `warn` and `pathToMake` flags. ([#75](https://github.com/rtfeldman/node-elm-compiler/pull/75))

## 5.0.0

Add 0.19 support. Remove `yes` option. Add `optimize` option. Throw exceptions instead of emitting warnings or using process.exit.

## 4.5.0

Add `runtimeOptions`

## 4.4.0

Add `compileToStringSync`

## 4.3.1

Upgrade `findAllDependencies` dependency to correctly report all dependencies within a multi-source-directory project.

## 4.3.0

Add `compileSync` via @yormi

## 4.2.1

Epic perf improvements from @eeue56

## 4.2.0

Add support for `--debug` flag.

## 4.1.5

Clean up temporary directories more safely.

## 4.1.4

`findAllDependencies` now supports `port module` files.

## 4.1.3

Use utf-8 encoding for `compileToString`

## 4.1.2

Support checking dependencies for modules with no module declaration.

## 4.1.1

Fix bug in dependency searches beginning with a non-root `Main` module.

## 4.1.0

Log elm-make output in verbose mode.

## 4.0.1

Fix missing `temp` dependency.

## 4.0.0

Use an `Error` object for result errors instead of a string.

## 3.0.0

Passing the `warn` option now passes `--warn` to `elm-make`, and `emitWarning` now controls warning logging.

## 2.3.3

Fix bug where nonzero exit codes were not rejecting promises.

## 2.3.2

Fix bug related to converting module dots to directories in nested dependency
resolution.

## 2.3.1

Move `temp` dependency out of `devDependencies`

## 2.3.0

Added #compileToString

## 2.2.0

Added `cwd` to `options` and fixed a bug where Windows couldn't find `elm-make`.

## 2.1.0

Added #findAllDependencies

## 2.0.0

No longer searches `node_modules/.bin` for `elm-make` - now if you don't specify
a `pathToMake` option, only the one on PATH will be used as a fallback.

## 1.0.0

Initial release.


================================================
FILE: appveyor.yml
================================================
environment:
  ELM_VERSION: "0.19.0-bugfix6"
  matrix:
  - nodejs_version: "12.0"
  - nodejs_version: "10.0"
  - nodejs_version: "8.0"

platform:
  - x64

matrix:
  fast_finish: true

install:
  - ps: Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version) $env:Platform
  - node --version
  - npm --version
  - npm install
  - npm install -g elm@%ELM_VERSION%

test_script:
  - npm test

build: off


================================================
FILE: examples/.gitignore
================================================
compiled-hello-world.js



================================================
FILE: examples/HelloWorld.elm
================================================
module Main exposing (..)

import Html exposing (Html, text)


main : Html msg
main =
    Html.text "Hello, World!"


================================================
FILE: examples/compileHelloWorld.js
================================================
var compile = require("../index.js").compile;
var compileToString = require("../index.js").compileToString;

compile(["./HelloWorld.elm"], {
  output: "compiled-hello-world.js"
}).on('close', function(exitCode) {
  console.log("Finished with exit code", exitCode);
});


compileToString(["./HelloWorld.elm"], {}).then(function(data){
    console.log("compileToString produced a string with this length:", data.toString().length);
});

compileToString(["./HelloWorld.elm"], { output: "index.html" }).then(function(data){
    console.log("compileToString --output index.html produced a string with this length:", data.toString().length);
});


================================================
FILE: examples/elm.json
================================================
{
    "type": "application",
    "source-directories": [
        "."
    ],
    "elm-version": "0.19.0",
    "dependencies": {
        "direct": {
            "elm/browser": "1.0.0",
            "elm/core": "1.0.0",
            "elm/html": "1.0.0"
        },
        "indirect": {
            "elm/json": "1.0.0",
            "elm/time": "1.0.0",
            "elm/url": "1.0.0",
            "elm/virtual-dom": "1.0.0"
        }
    },
    "test-dependencies": {
        "direct": {},
        "indirect": {}
    }
}

================================================
FILE: package.json
================================================
{
  "name": "node-elm-compiler",
  "version": "5.0.6",
  "description": "A Node.js interface to the Elm compiler binaries.",
  "main": "dist/index.js",
  "scripts": {
    "prepack": "npm run build",
    "build": "rm -rf dist/ && tsc",
    "test": "rm -rf test/fixtures/elm-stuff && mocha test/**/*.ts --require ts-node/register --watch-extensions ts"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/rtfeldman/node-elm-compiler.git"
  },
  "engines": {
    "node": ">=4.0.0"
  },
  "keywords": [
    "elm",
    "compiler",
    "node"
  ],
  "author": "Richard Feldman",
  "license": "BSD-3-Clause",
  "bugs": {
    "url": "https://github.com/rtfeldman/node-elm-compiler/issues"
  },
  "homepage": "https://github.com/rtfeldman/node-elm-compiler",
  "dependencies": {
    "cross-spawn": "6.0.5",
    "find-elm-dependencies": "^2.0.4",
    "lodash": "^4.17.19",
    "temp": "^0.9.0"
  },
  "devDependencies": {
    "@types/mocha": "^5.2.7",
    "@types/node": "^12.6.8",
    "chai": "4.2.0",
    "glob": "7.1.4",
    "mocha": "6.2.0",
    "ts-node": "^8.3.0",
    "typescript": "^3.5.3"
  }
}


================================================
FILE: src/index.ts
================================================
'use strict';

var spawn = require("cross-spawn");
var _ = require("lodash");
var elmBinaryName = "elm";
var fs = require("fs");
var path = require("path");
var temp = require("temp").track();
var findAllDependencies = require("find-elm-dependencies").findAllDependencies;

var defaultOptions = {
  spawn: spawn,
  cwd: undefined,
  pathToElm: undefined,
  help: undefined,
  output: undefined,
  report: undefined,
  debug: undefined,
  verbose: false,
  processOpts: undefined,
  docs: undefined,
  optimize: undefined,
};

var supportedOptions = _.keys(defaultOptions);

function prepareSources(sources) {
  if (!(sources instanceof Array || typeof sources === "string")) {
    throw "compile() received neither an Array nor a String for its sources argument.";
  }

  return typeof sources === "string" ? [sources] : sources;
}

function prepareOptions(options, spawnFn) {
  return _.defaults({ spawn: spawnFn }, options, defaultOptions);
}

function prepareProcessArgs(sources, options) {
  var preparedSources = prepareSources(sources);
  var compilerArgs = compilerArgsFromOptions(options);

  return ["make"].concat(preparedSources ? preparedSources.concat(compilerArgs) : compilerArgs);
}

function prepareProcessOpts(options) {
  var env = _.merge({ LANG: 'en_US.UTF-8' }, process.env);
  return _.merge({ env: env, stdio: "inherit", cwd: options.cwd }, options.processOpts);

}

function runCompiler(sources, options, pathToElm) {
  if (typeof options.spawn !== "function") {
    throw "options.spawn was a(n) " + (typeof options.spawn) + " instead of a function.";
  }

  var processArgs = prepareProcessArgs(sources, options);
  var processOpts = prepareProcessOpts(options);

  if (options.verbose) {
    console.log(["Running", pathToElm].concat(processArgs).join(" "));
  }

  return options.spawn(pathToElm, processArgs, processOpts);
}

function compilerErrorToString(err, pathToElm) {
  if ((typeof err === "object") && (typeof err.code === "string")) {
    switch (err.code) {
      case "ENOENT":
        return "Could not find Elm compiler \"" + pathToElm + "\". Is it installed?";

      case "EACCES":
        return "Elm compiler \"" + pathToElm + "\" did not have permission to run. Do you need to give it executable permissions?";

      default:
        return "Error attempting to run Elm compiler \"" + pathToElm + "\":\n" + err;
    }
  } else if ((typeof err === "object") && (typeof err.message === "string")) {
    return JSON.stringify(err.message);
  } else {
    return "Exception thrown when attempting to run Elm compiler " + JSON.stringify(pathToElm);
  }
}

function compileSync(sources, options) {
  var optionsWithDefaults = prepareOptions(options, options.spawn || spawn.sync);
  var pathToElm = options.pathToElm || elmBinaryName;

  try {
    return runCompiler(sources, optionsWithDefaults, pathToElm);
  } catch (err) {
    throw compilerErrorToString(err, pathToElm);
  }
}

function compile(sources, options) {
  var optionsWithDefaults = prepareOptions(options, options.spawn || spawn);
  var pathToElm = options.pathToElm || elmBinaryName;


  try {
    return runCompiler(sources, optionsWithDefaults, pathToElm)
      .on('error', function (err) { throw (err); });
  } catch (err) {
    throw compilerErrorToString(err, pathToElm);
  }
}

function getSuffix(outputPath, defaultSuffix) {
  if (outputPath) {
    return path.extname(outputPath) || defaultSuffix;
  } else {
    return defaultSuffix;
  }
}

// write compiled Elm to a string output
// returns a Promise which will contain a Buffer of the text
// If you want html instead of js, use options object to set
// output to a html file instead
// creates a temp file and deletes it after reading
function compileToString(sources, options) {
  const suffix = getSuffix(options.output, '.js');

  return new Promise(function (resolve, reject) {
    temp.open({ suffix }, function (err, info) {
      if (err) {
        return reject(err);
      }

      options.output = info.path;
      options.processOpts = { stdio: 'pipe' }

      var compiler;

      try {
        compiler = compile(sources, options);
      } catch (compileError) {
        return reject(compileError);
      }

      compiler.stdout.setEncoding("utf8");
      compiler.stderr.setEncoding("utf8");

      var output = '';
      compiler.stdout.on('data', function (chunk) {
        output += chunk;
      });
      compiler.stderr.on('data', function (chunk) {
        output += chunk;
      });

      compiler.on("close", function (exitCode) {
        if (exitCode !== 0) {
          return reject(new Error('Compilation failed\n' + output));
        } else if (options.verbose) {
          console.log(output);
        }

        fs.readFile(info.path, { encoding: "utf8" }, function (err, data) {
          return err ? reject(err) : resolve(data);
        });
      });
    });
  });
}

function compileToStringSync(sources, options) {
  const suffix = getSuffix(options.output, '.js');

  const file = temp.openSync({ suffix });
  options.output = file.path;
  let compileProcess = compileSync(sources, options);

  if (compileProcess.status == 0) {
    return fs.readFileSync(file.path, { encoding: "utf8" });
  }
  else {
    // Throw a simple error. We already let elm output to stdout/stderr
    throw 'Compilation failed.';
  }
}

// Converts an object of key/value pairs to an array of arguments suitable
// to be passed to child_process.spawn for elm-make.
function compilerArgsFromOptions(options) {
  return _.flatten(_.map(options, function (value, opt) {
    if (value) {
      switch (opt) {
        case "help": return ["--help"];
        case "output": return ["--output", value];
        case "report": return ["--report", value];
        case "debug": return ["--debug"];
        case "docs": return ["--docs", value];
        case "optimize": return ["--optimize"];
        case "runtimeOptions": return [].concat(["+RTS"], value, ["-RTS"]);
        default:
          if (supportedOptions.indexOf(opt) === -1) {
            if (opt === "yes") {
              throw new Error('node-elm-compiler received the `yes` option, but that was removed in Elm 0.19. Try re-running without passing the `yes` option.');
            } else if (opt === "warn") {
              throw new Error('node-elm-compiler received the `warn` option, but that was removed in Elm 0.19. Try re-running without passing the `warn` option.');
            } else if (opt === "pathToMake") {
              throw new Error('node-elm-compiler received the `pathToMake` option, but that was renamed to `pathToElm` in Elm 0.19. Try re-running after renaming the parameter to `pathToElm`.');
            } else {
              throw new Error('node-elm-compiler was given an unrecognized Elm compiler option: ' + opt);
            }
          }

          return [];
      }
    } else {
      return [];
    }
  }));
}

module.exports = {
  compile: compile,
  compileSync: compileSync,
  compileWorker: require("./worker")(compile),
  compileToString: compileToString,
  compileToStringSync: compileToStringSync,
  findAllDependencies: findAllDependencies,
  _prepareProcessArgs: prepareProcessArgs
};


================================================
FILE: src/worker.ts
================================================
var temp = require("temp").track();
var path = require("path");
var jsEmitterFilename = "emitter.js";

var KNOWN_MODULES =
  [
    "fullscreen",
    "embed",
    "worker",
    "Basics",
    "Maybe",
    "List",
    "Array",
    "Char",
    "Color",
    "Transform2D",
    "Text",
    "Graphics",
    "Debug",
    "Result",
    "Task",
    "Signal",
    "String",
    "Dict",
    "Json",
    "Regex",
    "VirtualDom",
    "Html",
    "Css"
  ];


// elmModuleName is optional, and is by default inferred based on the filename.
module.exports = function (compile) {
  return function (projectRootDir, modulePath, moduleName, workerArgs) {
    var originalWorkingDir = process.cwd();
    process.chdir(projectRootDir);

    return createTmpDir()
      .then(function (tmpDirPath) {
        var dest = path.join(tmpDirPath, jsEmitterFilename);

        return compileEmitter(compile, modulePath, { output: dest })
          .then(function () { return runWorker(dest, moduleName, workerArgs) });
      })
      .then(function (worker) {
        process.chdir(originalWorkingDir);
        return worker;
      })
      .catch(function (err) {
        process.chdir(originalWorkingDir);
        throw Error(err);
      });
  };
};

function createTmpDir() {
  return new Promise(function (resolve, reject) {
    temp.mkdir("node-elm-compiler", function (err, tmpDirPath) {
      if (err) {
        reject(err);
      } else {
        resolve(tmpDirPath);
      }
    });
  });
}

function suggestModulesNames(Elm) {
  return Object.keys(Elm).filter(function (key) {
    return KNOWN_MODULES.indexOf(key) === -1;
  })
}

function missingEntryModuleMessage(moduleName, Elm) {
  var errorMessage = "I couldn't find the entry module " + moduleName + ".\n";
  var suggestions = suggestModulesNames(Elm);

  if (suggestions.length > 1) {
    errorMessage += "\nMaybe you meant one of these: " + suggestions.join(",");
  } else if (suggestions.length === 1) {
    errorMessage += "\nMaybe you meant: " + suggestions;
  }

  errorMessage += "\nYou can pass me a different module to use with --module=<moduleName>";

  return errorMessage;
}

function noPortsMessage(moduleName) {
  var errorMessage = "The module " + moduleName + " doesn't expose any ports!\n";

  errorMessage += "\n\nTry adding something like";
  errorMessage += "port foo : Value\nport foo =\n    someValue\n\nto " + moduleName + "!";

  return errorMessage.trim();
}

function runWorker(jsFilename, moduleName, workerArgs) {
  return new Promise(function (resolve, reject) {
    var Elm = require(jsFilename).Elm;

    if (!(moduleName in Elm)) {
      return reject(missingEntryModuleMessage(moduleName, Elm));
    }

    var worker = Elm[moduleName].init(workerArgs);

    if (Object.keys(worker.ports).length === 0) {
      return reject(noPortsMessage(moduleName));
    }

    return resolve(worker);
  });
}

function compileEmitter(compile, src, options) {
  return new Promise(function (resolve, reject) {
    compile(src, options)
      .on("close", function (exitCode) {
        if (exitCode === 0) {
          resolve(exitCode);
        } else {
          reject("Errored with exit code " + exitCode);
        }
      })
  });
}


================================================
FILE: test/compile.ts
================================================
var chai = require("chai")
var path = require("path");
var compiler = require(path.join(__dirname, "../src"));
var childProcess = require("child_process");
var _ = require("lodash");
var temp = require("temp");

var expect = chai.expect;

var fixturesDir = path.join(__dirname, "fixtures");

function prependFixturesDir(filename) {
  return path.join(fixturesDir, filename);
}

describe("#compile", function () {
  // Use a timeout of 5 minutes because Travis on Linux can be SUPER slow.
  this.timeout(300000);

  it("reports errors on bad source", function (done) {
    var opts = {
      verbose: true,
      cwd: fixturesDir
    };
    var compileProcess = compiler.compile(prependFixturesDir("Bad.elm"), opts);

    compileProcess.on("exit", function (exitCode) {
      var desc = "Expected elm make to have exit code 1";
      expect(exitCode, desc).to.equal(1);
      done();
    });
  });

  it("throws when given an unrecognized argument", function () {
    var opts = {
      foo: "bar",
      output: "/dev/null",
      verbose: true,
      cwd: fixturesDir
    };

    expect(function () {
      var compileProcess = compiler.compile(prependFixturesDir("Parent.elm"), opts);

    }).to.throw();
  });
});

describe("#compileToString", function () {
  // Use an epic timeout because Travis on Linux can be SUPER slow.
  this.timeout(600000);

  it("adds runtime options as arguments", function () {
    var opts = {
      verbose: true,
      cwd: fixturesDir,
      runtimeOptions: ["-A128M", "-H128M", "-n8m"]
    };

    return expect(compiler
      ._prepareProcessArgs("a.elm", opts)
      .join(" ")).to.equal("make a.elm +RTS -A128M -H128M -n8m -RTS");
  });

  it("reports errors on bad syntax", function () {
    var opts = {
      verbose: true,
      cwd: fixturesDir
    };
    var compilePromise = compiler.compileToString(prependFixturesDir("Bad.elm"), opts);

    return compilePromise.catch(function (err) {
      expect(err).to.be.an('error');
      expect(String(err))
        .to.contain("Compilation failed")
        .and.contain("PARSE ERROR");
    });
  });

  it("reports type errors", function () {
    var opts = {
      verbose: true,
      cwd: fixturesDir
    };
    var compilePromise = compiler.compileToString(prependFixturesDir("TypeError.elm"), opts);

    return compilePromise.catch(function (err) {
      expect(err).to.be.an('error');
      expect(String(err))
        .to.contain("Compilation failed")
        .and.contain("TYPE MISMATCH");
    });
  });

  it("Rejects the Promise when given an unrecognized argument like `yes`", function () {
    var opts = {
      foo: "bar",
      verbose: true,
      cwd: fixturesDir
    };

    var compilePromise = compiler.compileToString(prependFixturesDir("Parent.elm"), opts);

    return new Promise(function (resolve, reject) {
      return compilePromise.then(function () {
        reject("Expected the compilation promise to be rejected due to the unrecognized compiler argument.");
      }).catch(function () {
        resolve();
      });
    });
  });


  it("works when run multiple times", function () {
    var opts = {
      verbose: true,
      cwd: fixturesDir
    };

    var runCompile = function () {
      var compilePromise = compiler.compileToString(prependFixturesDir("Parent.elm"), opts)

      return compilePromise.then(function (result) {
        var desc = "Expected elm make to return the result of the compilation";
        expect(result.toString(), desc).to.be.a('string');
      });
    };

    // Compiling in parallel leads to issues with the cache. Therefore we chain
    // the compilations instead. For details, see https://github.com/elm/compiler/issues/1853.
    // This issue is tracked as https://github.com/rtfeldman/node-elm-compiler/issues/86.
    let promiseChain = Promise.resolve();
    for (var i = 0; i < 10; i++) {
      promiseChain = promiseChain.then(() => runCompile());
    }
    return promiseChain;
  });

  it("handles output suffix correctly", function () {
    var opts = {
      verbose: true,
      cwd: fixturesDir,
      output: prependFixturesDir("compiled.html"),
    };

    return compiler.compileToString(prependFixturesDir("Parent.elm"), opts)
      .then(function (result) {
        var desc = "Expected elm make to return the result of the compilation";
        expect(result.toString(), desc).to.be.a('string');
      });
  });
});

describe("#compileWorker", function () {
  // Use a timeout of 5 minutes because Travis on Linux can be SUPER slow.
  this.timeout(300000);

  it("works with BasicWorker.elm", function () {
    var opts = {
      verbose: true,
      cwd: fixturesDir
    };
    var compilePromise = compiler.compileWorker(
      prependFixturesDir(""),
      prependFixturesDir("BasicWorker.elm"),
      "BasicWorker"
    );

    return compilePromise.then(function (app) {
      app.ports.reportFromWorker.subscribe(function (str) {
        expect(str).to.equal("it's alive!");
      });
    })
  });
});


================================================
FILE: test/compileSync.ts
================================================
var chai = require("chai")
var path = require("path");
var compiler = require(path.join(__dirname, "../src"));

var expect = chai.expect;

var fixturesDir = path.join(__dirname, "fixtures");

function prependFixturesDir(filename) {
  return path.join(fixturesDir, filename);
}

describe("#compileSync", function () {
  // Use a timeout of 5 minutes because Travis on Linux can be SUPER slow.
  this.timeout(300000);

  it("succeeds on SimplestMain", function () {
    var opts = {
      verbose: true,
      cwd: fixturesDir
    };
    var compileProcess = compiler.compileSync(prependFixturesDir("SimplestMain.elm"), opts);

    var exitCode = compileProcess.status;
    var desc = "Expected elm make to have exit code 0";
    expect(exitCode, desc).to.equal(0);
  });

  it("reports errors on bad source", function () {
    var opts = {
      verbose: true,
      cwd: fixturesDir
    };
    var compileProcess = compiler.compileSync(prependFixturesDir("Bad.elm"), opts);

    var exitCode = compileProcess.status;
    var desc = "Expected elm make to have exit code 1";
    expect(exitCode, desc).to.equal(1);
  });

  it("throws when given an unrecognized argument like `yes`", function () {
    var opts = {
      yes: true,
      output: "/dev/null",
      verbose: true,
      cwd: fixturesDir
    };

    expect(function () {
      var compileProcess = compiler.compileSync(prependFixturesDir("Parent.elm"), opts);
    }).to.throw();
  });
});


================================================
FILE: test/compileToStringSync.ts
================================================
var chai = require("chai");
var path = require("path");
var compiler = require(path.join(__dirname, "../src"));

var expect = chai.expect;

var fixturesDir = path.join(__dirname, "fixtures");

function prependFixturesDir(filename) {
  return path.join(fixturesDir, filename);
}

describe("#compileToStringSync", function () {
  it('returns string JS output of the given elm file', function () {
    var opts = { verbose: true, cwd: fixturesDir };
    var result = compiler.compileToStringSync(prependFixturesDir("Parent.elm"), opts);

    expect(result).to.include("_Platform_export");
  });

  it('returns html output given "html" output option', function () {
    var opts = {
      verbose: true,
      cwd: fixturesDir,
      output: prependFixturesDir('compiled.html'),
    };
    var result = compiler.compileToStringSync(prependFixturesDir("Parent.elm"), opts);

    expect(result).to.include('<!DOCTYPE HTML>');
    expect(result).to.include('<title>Parent</title>');
    expect(result).to.include("_Platform_export");
  });
  it('throws on compilation errors', function () {
    var opts = { verbose: false, cwd: fixturesDir };

    expect(function () {
      compiler.compileToStringSync(prependFixturesDir("Bad.elm"), opts);
    }).to.throw();
  });
});


================================================
FILE: test/fixtures/Bad.elm
================================================
module Bad


main =
   hello! I am a syntax error! :D


================================================
FILE: test/fixtures/BasicWorker.elm
================================================
port module BasicWorker exposing (..)

import Platform


main : Program () String msg
main =
    Platform.worker
        { init = \_ -> ( "", reportFromWorker "it's alive!" )
        , update = \_ _ -> ( "", Cmd.none )
        , subscriptions = \_ -> Sub.none
        }


port reportFromWorker : String -> Cmd a


================================================
FILE: test/fixtures/Nested/Child.elm
================================================
module Nested.Child exposing (..)

import Test.ChildB
import Html


main =
    Html.text "I am child A"


================================================
FILE: test/fixtures/Nested/Parent/Test.elm
================================================
module Nested.Parent.Test exposing (..)

import Test.ChildA
import Nested.Child
import Nested.Test.Child


-- This is a comment in between two import statements.

import Test.Sample.NestedChild exposing (..)


main =
    "Hello, World!"


================================================
FILE: test/fixtures/Nested/Test/Child.elm
================================================
module Nested.Test.Child exposing (..)

import Test.ChildA
import Nested.Child


-- This is a comment in between two import statements.

import Test.Sample.NestedChild exposing (..)


main =
    "Hello, World!"


================================================
FILE: test/fixtures/Parent.elm
================================================
module Parent exposing (..)

import Test.ChildA


-- This is a comment in between two import statements.

import Test.ChildB exposing (..)
import Html


main =
    Html.text "Hello, World!"


================================================
FILE: test/fixtures/ParentWithNestedDeps.elm
================================================
module Parent exposing (..)

import Test.ChildA


-- This is a comment in between two import statements.

import Test.Sample.NestedChild exposing (..)


main =
    "Hello, World!"


================================================
FILE: test/fixtures/ParentWithPort.elm
================================================
port module ParentWithPort exposing (..)

import Test.ChildA


-- This is a comment in between two import statements.

import Test.ChildB exposing (..)
import Html


main =
    Html.text "Hello, World!"


================================================
FILE: test/fixtures/ParentWithUnindentedMultilineComment.elm
================================================
module ParentWithUnindentedMultilineComment exposing (..)

{-| This is a comment in between two import statements.
sometimes I write things here because I like to watch the world burn
-}
import Test.ChildA


import Test.ChildB exposing (..)
{- this comment will end before an import
-}
import Html


main =
    Html.text "Hello, World!"


================================================
FILE: test/fixtures/SimplestMain.elm
================================================
import Html

main =
    Html.text "Hello, World!"


================================================
FILE: test/fixtures/Test/ChildA.elm
================================================
module Test.ChildA exposing (..)

import Html


main =
    Html.text "I am child A"


================================================
FILE: test/fixtures/Test/ChildB.elm
================================================
module Test.ChildB exposing (..)

import Html


main =
    Html.text "I am child B"


================================================
FILE: test/fixtures/Test/Sample/NestedChild.elm
================================================
module Test.Sample.NestedChild exposing (..)

import Test.ChildB


main =
    "Hello, World!"


================================================
FILE: test/fixtures/TypeError.elm
================================================
module TypeError exposing (..)

import Html


main =
    Html.text (1 ++ "2")


================================================
FILE: test/fixtures/elm.json
================================================
{
    "type": "application",
    "source-directories": [
        "."
    ],
    "elm-version": "0.19.0",
    "dependencies": {
        "direct": {
            "elm/browser": "1.0.0",
            "elm/core": "1.0.0",
            "elm/html": "1.0.0"
        },
        "indirect": {
            "elm/json": "1.0.0",
            "elm/time": "1.0.0",
            "elm/url": "1.0.0",
            "elm/virtual-dom": "1.0.0"
        }
    },
    "test-dependencies": {
        "direct": {},
        "indirect": {}
    },
    "do-not-edit-this-by-hand": {
        "transitive-dependencies": {
            "elm-lang/json": "1.0.0",
            "elm-lang/virtual-dom": "3.0.0"
        }
    }
}

================================================
FILE: tsconfig.json
================================================
{
    "compilerOptions": {
        "outDir": "./dist",
        "allowJs": true,
        "target": "es5",
        "lib": [
            "es2015"
        ]
    },
    "include": [
        "./src/**/*"
    ]
}
Download .txt
gitextract_lihzjcl8/

├── .gitignore
├── .npmignore
├── .travis.yml
├── LICENSE
├── README.md
├── appveyor.yml
├── examples/
│   ├── .gitignore
│   ├── HelloWorld.elm
│   ├── compileHelloWorld.js
│   └── elm.json
├── package.json
├── src/
│   ├── index.ts
│   └── worker.ts
├── test/
│   ├── compile.ts
│   ├── compileSync.ts
│   ├── compileToStringSync.ts
│   └── fixtures/
│       ├── Bad.elm
│       ├── BasicWorker.elm
│       ├── Nested/
│       │   ├── Child.elm
│       │   ├── Parent/
│       │   │   └── Test.elm
│       │   └── Test/
│       │       └── Child.elm
│       ├── Parent.elm
│       ├── ParentWithNestedDeps.elm
│       ├── ParentWithPort.elm
│       ├── ParentWithUnindentedMultilineComment.elm
│       ├── SimplestMain.elm
│       ├── Test/
│       │   ├── ChildA.elm
│       │   ├── ChildB.elm
│       │   └── Sample/
│       │       └── NestedChild.elm
│       ├── TypeError.elm
│       └── elm.json
└── tsconfig.json
Download .txt
SYMBOL INDEX (21 symbols across 5 files)

FILE: src/index.ts
  function prepareSources (line 27) | function prepareSources(sources) {
  function prepareOptions (line 35) | function prepareOptions(options, spawnFn) {
  function prepareProcessArgs (line 39) | function prepareProcessArgs(sources, options) {
  function prepareProcessOpts (line 46) | function prepareProcessOpts(options) {
  function runCompiler (line 52) | function runCompiler(sources, options, pathToElm) {
  function compilerErrorToString (line 67) | function compilerErrorToString(err, pathToElm) {
  function compileSync (line 86) | function compileSync(sources, options) {
  function compile (line 97) | function compile(sources, options) {
  function getSuffix (line 110) | function getSuffix(outputPath, defaultSuffix) {
  function compileToString (line 123) | function compileToString(sources, options) {
  function compileToStringSync (line 169) | function compileToStringSync(sources, options) {
  function compilerArgsFromOptions (line 187) | function compilerArgsFromOptions(options) {

FILE: src/worker.ts
  function createTmpDir (line 57) | function createTmpDir() {
  function suggestModulesNames (line 69) | function suggestModulesNames(Elm) {
  function missingEntryModuleMessage (line 75) | function missingEntryModuleMessage(moduleName, Elm) {
  function noPortsMessage (line 90) | function noPortsMessage(moduleName) {
  function runWorker (line 99) | function runWorker(jsFilename, moduleName, workerArgs) {
  function compileEmitter (line 117) | function compileEmitter(compile, src, options) {

FILE: test/compile.ts
  function prependFixturesDir (line 12) | function prependFixturesDir(filename) {

FILE: test/compileSync.ts
  function prependFixturesDir (line 9) | function prependFixturesDir(filename) {

FILE: test/compileToStringSync.ts
  function prependFixturesDir (line 9) | function prependFixturesDir(filename) {
Condensed preview — 32 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (33K chars).
[
  {
    "path": ".gitignore",
    "chars": 658,
    "preview": "# Logs\nlogs\n*.log\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nl"
  },
  {
    "path": ".npmignore",
    "chars": 503,
    "preview": "# Logs\nlogs\n*.log\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nl"
  },
  {
    "path": ".travis.yml",
    "chars": 294,
    "preview": "sudo: false\n\nlanguage: node_js\nnode_js:\n  - \"8\"\n  - \"10\"\n  - \"12\"\n\nos:\n  - linux\n  - osx\n\nenv:\n  matrix:\n    - ELM_VERSI"
  },
  {
    "path": "LICENSE",
    "chars": 1489,
    "preview": "Copyright (c) 2015, Richard Feldman\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or wit"
  },
  {
    "path": "README.md",
    "chars": 2728,
    "preview": "# node-elm-compiler [![Version](https://img.shields.io/npm/v/node-elm-compiler.svg)](https://www.npmjs.com/package/node-"
  },
  {
    "path": "appveyor.yml",
    "chars": 414,
    "preview": "environment:\n  ELM_VERSION: \"0.19.0-bugfix6\"\n  matrix:\n  - nodejs_version: \"12.0\"\n  - nodejs_version: \"10.0\"\n  - nodejs_"
  },
  {
    "path": "examples/.gitignore",
    "chars": 25,
    "preview": "compiled-hello-world.js\n\n"
  },
  {
    "path": "examples/HelloWorld.elm",
    "chars": 116,
    "preview": "module Main exposing (..)\n\nimport Html exposing (Html, text)\n\n\nmain : Html msg\nmain =\n    Html.text \"Hello, World!\"\n"
  },
  {
    "path": "examples/compileHelloWorld.js",
    "chars": 640,
    "preview": "var compile = require(\"../index.js\").compile;\nvar compileToString = require(\"../index.js\").compileToString;\n\ncompile([\"."
  },
  {
    "path": "examples/elm.json",
    "chars": 514,
    "preview": "{\n    \"type\": \"application\",\n    \"source-directories\": [\n        \".\"\n    ],\n    \"elm-version\": \"0.19.0\",\n    \"dependenci"
  },
  {
    "path": "package.json",
    "chars": 1115,
    "preview": "{\n  \"name\": \"node-elm-compiler\",\n  \"version\": \"5.0.6\",\n  \"description\": \"A Node.js interface to the Elm compiler binarie"
  },
  {
    "path": "src/index.ts",
    "chars": 7172,
    "preview": "'use strict';\n\nvar spawn = require(\"cross-spawn\");\nvar _ = require(\"lodash\");\nvar elmBinaryName = \"elm\";\nvar fs = requir"
  },
  {
    "path": "src/worker.ts",
    "chars": 3196,
    "preview": "var temp = require(\"temp\").track();\nvar path = require(\"path\");\nvar jsEmitterFilename = \"emitter.js\";\n\nvar KNOWN_MODULES"
  },
  {
    "path": "test/compile.ts",
    "chars": 4988,
    "preview": "var chai = require(\"chai\")\nvar path = require(\"path\");\nvar compiler = require(path.join(__dirname, \"../src\"));\nvar child"
  },
  {
    "path": "test/compileSync.ts",
    "chars": 1452,
    "preview": "var chai = require(\"chai\")\nvar path = require(\"path\");\nvar compiler = require(path.join(__dirname, \"../src\"));\n\nvar expe"
  },
  {
    "path": "test/compileToStringSync.ts",
    "chars": 1265,
    "preview": "var chai = require(\"chai\");\nvar path = require(\"path\");\nvar compiler = require(path.join(__dirname, \"../src\"));\n\nvar exp"
  },
  {
    "path": "test/fixtures/Bad.elm",
    "chars": 54,
    "preview": "module Bad\n\n\nmain =\n   hello! I am a syntax error! :D\n"
  },
  {
    "path": "test/fixtures/BasicWorker.elm",
    "chars": 312,
    "preview": "port module BasicWorker exposing (..)\n\nimport Platform\n\n\nmain : Program () String msg\nmain =\n    Platform.worker\n       "
  },
  {
    "path": "test/fixtures/Nested/Child.elm",
    "chars": 104,
    "preview": "module Nested.Child exposing (..)\n\nimport Test.ChildB\nimport Html\n\n\nmain =\n    Html.text \"I am child A\"\n"
  },
  {
    "path": "test/fixtures/Nested/Parent/Test.elm",
    "chars": 237,
    "preview": "module Nested.Parent.Test exposing (..)\n\nimport Test.ChildA\nimport Nested.Child\nimport Nested.Test.Child\n\n\n-- This is a "
  },
  {
    "path": "test/fixtures/Nested/Test/Child.elm",
    "chars": 211,
    "preview": "module Nested.Test.Child exposing (..)\n\nimport Test.ChildA\nimport Nested.Child\n\n\n-- This is a comment in between two imp"
  },
  {
    "path": "test/fixtures/Parent.elm",
    "chars": 190,
    "preview": "module Parent exposing (..)\n\nimport Test.ChildA\n\n\n-- This is a comment in between two import statements.\n\nimport Test.Ch"
  },
  {
    "path": "test/fixtures/ParentWithNestedDeps.elm",
    "chars": 180,
    "preview": "module Parent exposing (..)\n\nimport Test.ChildA\n\n\n-- This is a comment in between two import statements.\n\nimport Test.Sa"
  },
  {
    "path": "test/fixtures/ParentWithPort.elm",
    "chars": 203,
    "preview": "port module ParentWithPort exposing (..)\n\nimport Test.ChildA\n\n\n-- This is a comment in between two import statements.\n\ni"
  },
  {
    "path": "test/fixtures/ParentWithUnindentedMultilineComment.elm",
    "chars": 337,
    "preview": "module ParentWithUnindentedMultilineComment exposing (..)\n\n{-| This is a comment in between two import statements.\nsomet"
  },
  {
    "path": "test/fixtures/SimplestMain.elm",
    "chars": 50,
    "preview": "import Html\n\nmain =\n    Html.text \"Hello, World!\"\n"
  },
  {
    "path": "test/fixtures/Test/ChildA.elm",
    "chars": 84,
    "preview": "module Test.ChildA exposing (..)\n\nimport Html\n\n\nmain =\n    Html.text \"I am child A\"\n"
  },
  {
    "path": "test/fixtures/Test/ChildB.elm",
    "chars": 84,
    "preview": "module Test.ChildB exposing (..)\n\nimport Html\n\n\nmain =\n    Html.text \"I am child B\"\n"
  },
  {
    "path": "test/fixtures/Test/Sample/NestedChild.elm",
    "chars": 94,
    "preview": "module Test.Sample.NestedChild exposing (..)\n\nimport Test.ChildB\n\n\nmain =\n    \"Hello, World!\"\n"
  },
  {
    "path": "test/fixtures/TypeError.elm",
    "chars": 78,
    "preview": "module TypeError exposing (..)\n\nimport Html\n\n\nmain =\n    Html.text (1 ++ \"2\")\n"
  },
  {
    "path": "test/fixtures/elm.json",
    "chars": 684,
    "preview": "{\n    \"type\": \"application\",\n    \"source-directories\": [\n        \".\"\n    ],\n    \"elm-version\": \"0.19.0\",\n    \"dependenci"
  },
  {
    "path": "tsconfig.json",
    "chars": 205,
    "preview": "{\n    \"compilerOptions\": {\n        \"outDir\": \"./dist\",\n        \"allowJs\": true,\n        \"target\": \"es5\",\n        \"lib\": "
  }
]

About this extraction

This page contains the full source code of the rtfeldman/node-elm-compiler GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 32 files (29.0 KB), approximately 8.4k tokens, and a symbol index with 21 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!