mozilla/sweet.js — pull request #179 by natefaubion (2014-01-07 02:44:37+00:00)
Title: Module primitives

This PR tweaks the way modules are handled. Previously we were just reading the `-m` modules and concating the sources with the built in macros. I've added a new function `expandModule` and tweaked the signature of `expandTopLevel`. Both take a read tree as the first argument and an array of module contexts as the second. You can obtain module contexts by calling `expandModule`. I've also added two exports to the main `sweet` module: `loadModule` and `loadNodeModule`. `loadModule` just takes a source string and returns a module context. `loadNodeModule` will take a `root` path and a node module name, read in the file, and call `loadModule`. The node module will be looked up based on the root. So the `sjs` binary uses `process.cwd()` as the root, to look up modules from wherever it is invoked.

These serve as decent primitives for module loading. You could actually set up a tree of dependencies manually using this api. This also means that we can cache modules between calls to compile, which makes compiling multiple files really fast. The modules are only read in once instead of for every file. The test files all compile quicker, and the test suite (for me at least) has gone from nearly 4 seconds to 400 ms.

One thing I had to change was our usage of `Map` from `es6-collections`. Its implementation of `Map` doesn't have any way to traverse keys, so it wasn't of much use to me for this. I have to be able to copy the `env` of one module to another. I created a `StringMap` constructor, which follows the same api, but uses a normal object as the store, and has an `extend` method.

As an aside, is our usage of `Map` necessary? I tried using `StringMap` for everything, and all tests passed. I think template ids are just numbers, which works fine when coercing to a string for a key.