diff --git a/.babelrc b/.babelrc index 9a615718..0c2b576e 100644 --- a/.babelrc +++ b/.babelrc @@ -1,3 +1,12 @@ { - "plugins": ["transform-es2015-modules-commonjs"] -} \ No newline at end of file + "presets": [ + [ + "env", + { + "targets": { + "node": "current" + } + } + ] + ] +} diff --git a/.credo.exs b/.credo.exs index 18abcc24..f7a2bbb3 100644 --- a/.credo.exs +++ b/.credo.exs @@ -52,38 +52,27 @@ {Credo.Check.Consistency.MultiAliasImportRequireUse}, {Credo.Check.Consistency.ParameterPatternMatching}, {Credo.Check.Consistency.SpaceAroundOperators}, - {Credo.Check.Consistency.SpaceInParentheses}, + {Credo.Check.Consistency.SpaceInParentheses, false}, {Credo.Check.Consistency.TabsOrSpaces}, - - # For some checks, like AliasUsage, you can only customize the priority - # Priority values are: `low, normal, high, higher` - {Credo.Check.Design.AliasUsage, priority: :low}, - - # For others you can set parameters - - # If you don't want the `setup` and `test` macro calls in ExUnit tests - # or the `schema` macro in Ecto schemas to trigger DuplicatedCode, just - # set the `excluded_macros` parameter to `[:schema, :setup, :test]`. {Credo.Check.Design.DuplicatedCode, excluded_macros: []}, - - # You can also customize the exit_status of each check. - # If you don't want TODO comments to cause `mix credo` to fail, just - # set this value to 0 (zero). {Credo.Check.Design.TagTODO, exit_status: 2}, {Credo.Check.Design.TagFIXME}, + {Credo.Check.Design.AliasUsage, false}, {Credo.Check.Readability.FunctionNames}, {Credo.Check.Readability.LargeNumbers}, - {Credo.Check.Readability.MaxLineLength, priority: :low, max_length: 80}, + {Credo.Check.Readability.MaxLineLength, + priority: :low, max_length: 80, ignore_specs: true + }, {Credo.Check.Readability.ModuleAttributeNames}, {Credo.Check.Readability.ModuleDoc}, {Credo.Check.Readability.ModuleNames}, - {Credo.Check.Readability.NoParenthesesWhenZeroArity}, + {Credo.Check.Readability.ParenthesesOnZeroArityDefs}, {Credo.Check.Readability.ParenthesesInCondition}, {Credo.Check.Readability.PredicateFunctionNames}, {Credo.Check.Readability.PreferImplicitTry}, {Credo.Check.Readability.RedundantBlankLines}, - {Credo.Check.Readability.Specs}, + {Credo.Check.Readability.Specs, false}, {Credo.Check.Readability.StringSigils}, {Credo.Check.Readability.TrailingBlankLine}, {Credo.Check.Readability.TrailingWhiteSpace}, @@ -98,9 +87,9 @@ {Credo.Check.Refactor.NegatedConditionsInUnless}, {Credo.Check.Refactor.NegatedConditionsWithElse}, {Credo.Check.Refactor.Nesting}, - {Credo.Check.Refactor.PipeChainStart}, + {Credo.Check.Refactor.PipeChainStart, false}, {Credo.Check.Refactor.UnlessWithElse}, - {Credo.Check.Refactor.VariableRebinding}, + {Credo.Check.Refactor.VariableRebinding, false}, {Credo.Check.Warning.BoolOperationOnSameValues}, {Credo.Check.Warning.IExPry}, @@ -119,9 +108,6 @@ {Credo.Check.Warning.UnusedRegexOperation}, {Credo.Check.Warning.UnusedStringOperation}, {Credo.Check.Warning.UnusedTupleOperation}, - - # Custom checks can be created using `mix credo.gen.check`. - # ] } ] diff --git a/.ebert.yml b/.ebert.yml new file mode 100644 index 00000000..148907f7 --- /dev/null +++ b/.ebert.yml @@ -0,0 +1,15 @@ +styleguide: elixirscript/elixirscript +engines: + credo: + enabled: true + fixme: + enabled: true + eslint: + enabled: true + remark-lint: + enabled: true +exclude_paths: +- config +- test +- priv/testrunner/vendor.build.js +- priv/testrunner/esm diff --git a/.eslintrc.js b/.eslintrc.js index cc2122f0..df660be2 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,16 +1,26 @@ module.exports = { rules: { - camelcase: "off", - "no-bitwise": "off", - "no-plusplus": "off", - "no-restricted-syntax": "off", - "no-underscore-dangle": "off" + camelcase: 'off', + 'no-bitwise': 'off', + 'no-plusplus': 'off', + 'no-restricted-syntax': 'off', + 'no-underscore-dangle': 'off', + 'import/extensions': 'off', + 'import/no-extraneous-dependencies': ['error', {devDependencies: true}], }, - extends: "airbnb-base", - plugins: ["import"], + 'overrides': [ + { + 'files': ['*spec.js', 'priv/testrunner/**/*'], + 'rules': { + 'no-console': 'off' + } + } + ], + extends: 'airbnb-base', + plugins: ['import'], env: { browser: true, node: true, - mocha: true - } -}; + mocha: true, + }, +} diff --git a/.flowconfig b/.flowconfig deleted file mode 100644 index 7f76ba60..00000000 --- a/.flowconfig +++ /dev/null @@ -1,12 +0,0 @@ -[ignore] -.*/dist/.* -.*/build/.* -.*/dist_build/.* -.*/node_modules/.* - -[include] -./priv/javascript - -[libs] - -[options] diff --git a/.formatter.exs b/.formatter.exs new file mode 100644 index 00000000..562e8863 --- /dev/null +++ b/.formatter.exs @@ -0,0 +1,4 @@ +[ + import_deps: [:phoenix], + inputs: ["*.{ex,exs}", "{config,lib,priv,test}/**/*.{ex,exs}"] +] diff --git a/.gitignore b/.gitignore index e0db4469..1a813296 100644 --- a/.gitignore +++ b/.gitignore @@ -10,12 +10,18 @@ deploy.sh .DS_Store sample/dest fprof.trace -index.js /doc /bench/snapshots .tern-port test/std_lib_compile_test.exs src/elixirscript -priv/**/*.js stdlib_state.bin *.log +.nyc_output +test/app/build +.vscode +cover +/priv/build +/tmp +.esm-cache +.elixir_ls diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 00000000..000eeb3e --- /dev/null +++ b/.tool-versions @@ -0,0 +1,3 @@ +erlang 22.0 +elixir 1.9.1-otp-22 +nodejs 12.8.1 diff --git a/.travis.yml b/.travis.yml index 94a48916..43916696 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,25 +1,27 @@ sudo: false language: elixir elixir: - - 1.4.2 + - 1.9 otp_release: - - 19.0 -env: - - TRAVIS_NODE_VERSION="6" + - 22.0 +cache: + directories: + - _build + - deps + - node_modules install: - - rm -rf ~/.nvm && git clone https://github.com/creationix/nvm.git ~/.nvm && (cd ~/.nvm && git checkout `git describe --abbrev=0 --tags`) && source ~/.nvm/nvm.sh && nvm install $TRAVIS_NODE_VERSION + - nvm install 12.8.1 && nvm use 12.8.1 - npm install -script: - mix local.hex --force - mix local.rebar --force - mix deps.get - - mix compile - - mix test - - npm test +script: + - make + - make test notifications: webhooks: urls: - https://webhooks.gitter.im/e/fbd8944d285c0696dc41 - on_success: always # options: [always|never|change] default: always - on_failure: always # options: [always|never|change] default: always - on_start: never # options: [always|never|change] default: always \ No newline at end of file + on_success: always # options: [always|never|change] default: always + on_failure: always # options: [always|never|change] default: always + on_start: never # options: [always|never|change] default: always diff --git a/CHANGELOG.md b/CHANGELOG.md index b575e273..89d3cd1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,155 @@ # Change Log + All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [0.32.1] - 2018-03-17 + +### Fixed + +* Global JavaScript modules not compiling correctly + +## [0.32.0] - 2018-02-10 + +### Added + +* `ElixirScript.Test` for testing ElixirScript modules in JavaScript. ElixirScript.Test is for unit testing modules that interact with JavaScript in some way. For modules that are can be used in both Elixir and ElixirScript, ExUnit is still preferred. Tests that use ElixirScript.Test must be placed in a `test_elixir_script` folder in the root of your project. These tests are run using node.js. The API for ElixirScript.Test is meant to be as close to ExUnit as possible. + +### Changed + +* ElixirScript now requires Elixir 1.6. This is so that ElixirScript can use the new `Mix.Task.Compiler` behaviour. +* `mix clean` will now correctly clean up ElixirScript output. +* Compiler will now output a JavaScript file per Elixir module. +* Modules with a start function **must** be started directly. + + ```elixir + # Before ElixirScript 0.32.0: + import Elixir from './elixirscript.build.js' + Elixir.start(Elixir.Main, [1, 2, 3]) + + # ElixirScript 0.32.0 and later: + import Main from './Elixir.Main.js' + Main.start(Symbol.for('normal'), [1, 2, 3]) + ``` + +## [0.31.1] - 2017-09-27 + +### Fixed + +* Compiler error when `receive` is used as variable name + +## [0.31.0] - 2017-09-24 + +### Added + +* [Compiler will now accept a path to Elixir Files to compile](https://github.com/elixirscript/elixirscript/issues/420) +* [Added `ElixirScript.JS.map_to_object/2` with options [keys: :string, symbols: false]](https://github.com/elixirscript/elixirscript/issues/362) +* [Added `ElixirScript.JS.object_to_map/1|2` with options [keys: :atom, recurse_array: true]](https://github.com/elixirscript/elixirscript/issues/381) +* [Fully implement `__info__` on modules](https://github.com/elixirscript/elixirscript/pull/378) +* [Concurrent Compilation](https://github.com/elixirscript/elixirscript/issues/376) +* [The following erlang functions have been implemented](https://github.com/elixirscript/elixirscript/issues/306): +* :erlang.nodes/0 +* :erlang.nodes/1 +* :math.log2/1 +* :binary.copy/1 +* :binary.copy/2 +* :binary.part/2 +* :binary.part/3 +* :binary.replace/3 +* :binary.replace/4 (some options still missing) + +### Fixed + +* Make sure not to add underscores to erlang functions +* [Make sure any variable names that are javascript keywords are handled properly](https://github.com/elixirscript/elixirscript/issues/355) +* [Make sure variables that begin with `_` are available](https://github.com/elixirscript/elixirscript/issues/356) +* [Finding the use of functions within anonymous functions](https://github.com/elixirscript/elixirscript/issues/358) +* [Reimplement `String.split_at/2` to make sure Unicode library isn't compiled](https://github.com/elixirscript/elixirscript/issues/353) +* [byte_size does not work on binaries that started via "" elixir string syntax](https://github.com/elixirscript/elixirscript/issues/384) +* [using . (dot) reference syntax on a map fails when value is a function](https://github.com/elixirscript/elixirscript/issues/380) +* [Make sure that remote ast works correctly with variables](https://github.com/elixirscript/elixirscript/issues/390) +* [Make sure == works as expected](https://github.com/elixirscript/elixirscript/issues/382) +* [Make sure that erlang function names that are also JavaScript keywords are not filters](https://github.com/elixirscript/elixirscript/issues/359) +* [erlang.error now throws errors resembling those in Elixir](https://github.com/elixirscript/elixirscript/pull/397) +* [Map.get fails if key is tuple or list](https://github.com/elixirscript/elixirscript/issues/406) + +## [0.30.0] - 2017-08-15 + +### Added + +* ElixirScript now has a Foreign Function Interface (FFI) for interoperability with JavaScript. For more details, see documentation at `ElixirScript.FFI` +* `ElixirScript.JS.mutate/3` +* `ElixirScript.JS.map_to_object/1` +* `root` option for specifying the root import path for FFI JavaScript modules. Defaults to `"."` + +### Changed + +* Compiler has been completely rewritten. ElixirScript now requires Erlang 20+ and Elixir 1.5+ +* `JS` module renamed to `ElixirScript.JS` +* Default output path is now `priv/elixir_script/build` + +### Removed + +* Support for CommonJS and UMD output formats has been removed. Output will be in ES module format +* The `js_modules` option has been removed in favor of the new FFI +* ElixirScript.Watcher has been removed + +## [0.28.0] - 2017-06-11 + +### Added + +* `remove-unused` option that will remove all unused modules from output +* reimplemented structs to avoid creating JavaScript classes + +## [0.27.0] - 2017-03-17 + +### Added + +* `super` +* `defoverridable` +* `IO.inspect\1`, `IO.puts\1`, `IO.puts\2`, `IO.warn\1` +* `Elixir.load` for loading generated JavaScript modules in bundled output. + Unlike `Elixir.start`, this will only call `__load` on the module and return the functions on it + +```javascript +const exports = Elixir.load(Elixir.MyApp); +exports.hello(); +``` + +### Changed + +* `-ex` alias is now `-e` +* A filename can be specified for output +* To access global JavaScript functions, modules, and properties, use the `JS` module + +```elixir +JS.length # translates to 'length' +JS.alert() # translates to 'alert()' +JS.String.raw("hi") # translate to String.raw('hi') +JS.console.log("hi") # translates to console.log('hi') +``` + +### Fixed + +* Make sure mix compiler works in umbrella apps + +## [0.26.1] - 2017-02-27 + +### Fixed + +* Fixed `for` translation +* Updated documentation + ## [0.26.0] - 2017-02-27 ### Added -- Multiple `when` clauses in guards -- Kernel.defdelegate/2 -- `js_modules` configuration option has been added. This is a keyword list of JavaScript modules that will be used. + +* Multiple `when` clauses in guards +* Kernel.defdelegate/2 +* `js_modules` configuration option has been added. This is a list of JavaScript modules that will be used. + ``` js_modules: [ {React, "react"}, @@ -17,96 +157,103 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ] ``` -- `js-module` flag has been added to the CLI in order to pass js modules. +* `js-module` flag has been added to the CLI in order to pass js modules. + ``` elixirscript "app/elixirscript" -o dist --js-module React:react --js-module ReactDOM:react-dom ``` ### Removed -- `@on_js_load` has been removed in favor of having a `start/2` function defined. More info below -- `JS.import` has been removed in favor of defining JavaScript modules used in configuration + +* `@on_js_load` has been removed in favor of having a `start/2` function defined. More info below +* `JS.import` has been removed in favor of defining JavaScript modules used in configuration ### Changed -- Now bundles all output, including the boostrap code. + +* Now bundles all output, including the boostrap code. The exported object has Elixir modules in JavaScript namespaces that are lazily loaded when called. - To start your application import the bundle according to whichever module format was selected and + To start your application import the bundle according to whichever module format was selected and then call start giving it the module and the initial args ```javascript //ES module example - import Elixir from './Elixir.App' - Elixir.start(Elixir.App, []) + import Elixir from './Elixir.App'; + Elixir.start(Elixir.App, []); ``` The `start` function will look for a `start/2` function there. This is analogous to a [Application module callback](https://hexdocs.pm/elixir/Application.html#module-application-module-callback) - - - ## [0.25.0] - 2017-02-19 ### Added -- Updated elixir_script mix compiler to support compiling elixir_script paths in dependencies if dependency has mix compiler defined as well -- Add `Collectable` protocol implementations -- Updated `for` implementation to use `Collectable` -- `format` option. Can now specify the module format of output. - Choices are: - * `:es` (default) for ES Modules - * `:umd` for UMD - * `:common` for CommonJS -- Default input, output and format for elixirscript mix compiler. In a mix project by default the elixirscript compiler will look in `lib/elixirscript` and input and place output in `priv/elixirscript`. The default format is `:es` +* Updated elixir_script mix compiler to support compiling elixir_script paths in dependencies if dependency has mix compiler defined as well +* Add `Collectable` protocol implementations +* Updated `for` implementation to use `Collectable` +* `format` option. Can now specify the module format of output. + Choices are: + _ `:es` (default) for ES Modules + _ `:umd` for UMD \* `:common` for CommonJS + +* Default input, output and format for elixirscript mix compiler. In a mix project by default the elixirscript compiler will look in `lib/elixirscript` and input and place output in `priv/elixirscript`. The default format is `:es` ### Removed -- `receive` -- `Process` module + +* `receive` +* `Process` module ### Fixed -- JS module functions not translated properly when imported -- Update fs dependency to 2.12 -- Incorrect handling of function heads with guards + +* JS module functions not translated properly when imported +* Update fs dependency to 2.12 +* Incorrect handling of function heads with guards ## [0.24.0] - 2017-01-15 ### Added -- Support for `sigil_r` -- `Regex` module -- Better JavaScript formatting + +* Support for `sigil_r` +* `Regex` module +* Better JavaScript formatting ### Fixed -- CLI now allows a comma-separated or space-separated list of paths -- Struct not properly referenced -- Tail call optimization + +* CLI now allows a comma-separated or space-separated list of paths +* Struct not properly referenced +* Tail call optimization ## [0.23.3] - 2016-11-18 ### Added -- `@load_only`: lets the compiler know to load in the module, but not to compile it +* `@load_only`: lets the compiler know to load in the module, but not to compile it ## [0.23.2] - 2016-11-17 ### Fixed -- Agent not functioning properly. Now uses internal store instead of making a process and using that to put data in store -- Protocol incorrectly handling strings -- `defgen` and `defgenp` functions not being recognized by Elixir compiler. +* Agent not functioning properly. Now uses internal store instead of making a process and using that to put data in store +* Protocol incorrectly handling strings +* `defgen` and `defgenp` functions not being recognized by Elixir compiler. ## [0.23.1] - 2016-11-16 ### Fixed -- Incorrectly sending standard lib when using compile or compile_path by default + +* Incorrectly sending standard lib when using compile or compile_path by default ## [0.23.0] - 2016-11-15 ### Added -- [`with` now supports `else`](https://github.com/bryanjos/elixirscript/pull/207) -- [Implement `context` option on `quote`](https://github.com/bryanjos/elixirscript/pull/208) -- New compiler pipeline -- `@on_js_load`. Expects a 0 arity function. This function will be called when the compiled module is loaded in JavaScript -- `JS.import\3`. Just like `JS.import\2` but expects options to decide if the import should be a default one or a namespace on. Only option allowed is `default`. Set to `true` by default + +* [`with` now supports `else`](https://github.com/bryanjos/elixirscript/pull/207) +* [Implement `context` option on `quote`](https://github.com/bryanjos/elixirscript/pull/208) +* New compiler pipeline +* `@on_js_load`. Expects a 0 arity function. This function will be called when the compiled module is loaded in JavaScript +* `JS.import\3`. Just like `JS.import\2` but expects options to decide if the import should be a default one or a namespace on. Only option allowed is `default`. Set to `true` by default + ```elixir # translates to "import A from 'a'" JS.import A, "a" @@ -116,351 +263,438 @@ elixirscript "app/elixirscript" -o dist --js-module React:react --js-module Reac ``` ### Removed -- The form of `JS.import` that accepted a list of atoms as the first arg. Used `JS.import\3` with `default: false` instead to create a namespace import -- `env` and `root` are no longer options for `ElixirScript`'s compile functions and cli -- Syntax once supported by Elixirscript `JQuery.("#element")`, is no longer supported + +* The form of `JS.import` that accepted a list of atoms as the first arg. Used `JS.import\3` with `default: false` instead to create a namespace import +* `env` and `root` are no longer options for `ElixirScript`'s compile functions and cli +* Syntax once supported by Elixirscript `JQuery.("#element")`, is no longer supported ### Changed -- [Changed CHANGELOG.md to adhere the format from Keep a Changelog](https://github.com/bryanjos/elixirscript/pull/205) -- `defmacro` now supported. No longer have to separate macros from functions in separate files. `defmacrop` still unsupported -- To use anything in the `JS` module, you must `require` the `JS` module first -- Elixirscript files must now contain valid Elixir syntax. -- Now compiles `exjs` and `ex` files within the path can be compiled all the same. Dependencies from hex are still unsupported so these files must not rely on any code outside of the path. What this does mean is that it is now possible to share code between Elixir and Elixirscript as long as the Elixir files functionality fall within what Elixirscript currently supports. -- `defgen`, `defgenp`, `yield`, `yield_to`, and `object` are now in the `JS` module -- To access functions in the global JavaScript scope, either use `JS.global\0` or use the erlang module call syntax - ```elixir - #calling alert - JS.global().alert("hi") - - #calling alert - :window.alert("hi") - ``` - Calling JavaScript modules in the global scope works without using the above methods - ```elixir - #calls window.Date.now() - Date.now() - ``` + +* [Changed CHANGELOG.md to adhere the format from Keep a Changelog](https://github.com/bryanjos/elixirscript/pull/205) +* `defmacro` now supported. No longer have to separate macros from functions in separate files. `defmacrop` still unsupported +* To use anything in the `JS` module, you must `require` the `JS` module first +* Elixirscript files must now contain valid Elixir syntax. +* Now compiles `exjs` and `ex` files within the path can be compiled all the same. Dependencies from hex are still unsupported so these files must not rely on any code outside of the path. What this does mean is that it is now possible to share code between Elixir and Elixirscript as long as the Elixir files functionality fall within what Elixirscript currently supports. +* `defgen`, `defgenp`, `yield`, `yield_to`, and `object` are now in the `JS` module +* To access functions in the global JavaScript scope, either use `JS.global\0` or use the erlang module call syntax + + ```elixir + #calling alert + JS.global().alert("hi") + + #calling alert + :window.alert("hi") + ``` + + Calling JavaScript modules in the global scope works without using the above methods + + ```elixir + #calls window.Date.now() + Date.now() + ``` ## [0.22.0] - 2016-10-16 + ### Added -- `defgen` and `defgenp` for defining public and private generators -- `yield/0`, `yield/1`, and `yield_to\1` to `Kernel` + +* `defgen` and `defgenp` for defining public and private generators +* `yield/0`, `yield/1`, and `yield_to\1` to `Kernel` ### Changed -- Updated output folder structure. stdlib code will now go in an `elxiir` folder under the output paths while generated app code will go into an `app` folder under the output path -- All process macros and functions now expect to receive and/or work using generators as entry points. Using functions defined with `def` or `defp` will not work correctly with them + +* Updated output folder structure. stdlib code will now go in an `elxiir` folder under the output paths while generated app code will go into an `app` folder under the output path +* All process macros and functions now expect to receive and/or work using generators as entry points. Using functions defined with `def` or `defp` will not work correctly with them ### Fixed -- Correctly returning list if list is only item in body + +* Correctly returning list if list is only item in body ## [0.21.0] - 2016-06-28 + ### Added -- This is the first release with early support for processes in elixirscript. Creating a process only works currently using `spawn/1`, `spawn_link/1`, and `spawn_monitor/1`. Inside of a process, you can use functions such as `send` and `receive`, along with some defined in the `Process` module. From outside of a process, you can send messages to a process, but you cannot receive a message from a process. Eventually all code will run inside processes and this restriction will naturally lift. -- The `Process` module has been implemented with the following functions: - * `alive?/1` - * `delete/1` - * `demonitor/1` - * `exit/2` - * `flag/2` - * `flag/3` - * `get/0` - * `get_keys/0` - * `get_keys/1` - * `link/1` - * `list/0` - * `monitor/1` - * `put/2` - * `register/2` - * `registered/0` - * `send/3` - * `sleep/1` - * `unlink/1` - * `unregister/1` - * `whereis/1` -- The `receive` special form has been implemented with the above caveat -- The following have been implemented on `Kernel`: - * `spawn/1` - * `spawn_link/1` - * `spawn_monitor/1` - * `send/2` - * `make_ref/0` + +* This is the first release with early support for processes in elixirscript. Creating a process only works currently using `spawn/1`, `spawn_link/1`, and `spawn_monitor/1`. Inside of a process, you can use functions such as `send` and `receive`, along with some defined in the `Process` module. From outside of a process, you can send messages to a process, but you cannot receive a message from a process. Eventually all code will run inside processes and this restriction will naturally lift. +* The `Process` module has been implemented with the following functions: + * `alive?/1` + * `delete/1` + * `demonitor/1` + * `exit/2` + * `flag/2` + * `flag/3` + * `get/0` + * `get_keys/0` + * `get_keys/1` + * `link/1` + * `list/0` + * `monitor/1` + * `put/2` + * `register/2` + * `registered/0` + * `send/3` + * `sleep/1` + * `unlink/1` + * `unregister/1` + * `whereis/1` +* The `receive` special form has been implemented with the above caveat +* The following have been implemented on `Kernel`: + * `spawn/1` + * `spawn_link/1` + * `spawn_monitor/1` + * `send/2` + * `make_ref/0` ## Fixed -- Scoping on `fn` and `def` + +* Scoping on `fn` and `def` ## [0.20.0] - 2016-05-14 + ### Added -- `ElixirScript.Watcher` module and `elixirscript.watch` mix task -- logging MatchError exceptions to better show terms that don't match + +* `ElixirScript.Watcher` module and `elixirscript.watch` mix task +* logging MatchError exceptions to better show terms that don't match ## [0.19.0] - 2016-04-30 + ### Added -- elixir_script mix compiler + +* elixir_script mix compiler ### Removed -- `Html`, `View`, and `VDom` modules have been removed + +* `Html`, `View`, and `VDom` modules have been removed ## [0.18.0] - 2016-04-08 + ### Changed -- Better support for macros. Macros should be defined in .ex or .exs files. ElixirScript code should be in .exjs files + +* Better support for macros. Macros should be defined in .ex or .exs files. ElixirScript code should be in .exjs files **NOTE**: The above functionality will cause either compiler errors or no output. Please change extensions of ElixirScript code to .exjs ### Deprecated -- `Html`, `View`, and `VDom` modules will be removed in the next version as they can now be replicated using macros + +* `Html`, `View`, and `VDom` modules will be removed in the next version as they can now be replicated using macros ## [0.17.0] - 2016-03-31 + ### Added -- `output` as an option for compiler functions. This controls whether output is returned as a list of tuples, send to stdout, or saved to a file path -- `:full_build` as an option for compiler functions and `--full-build` option to CLI. These force the compiler to perform a full build -- `--version` option to CLI. Outputs current version of elixirscript -- `--std-lib` option to CLI. Takes a path and adds the stdlib to that path + +* `output` as an option for compiler functions. This controls whether output is returned as a list of tuples, send to stdout, or saved to a file path +* `:full_build` as an option for compiler functions and `--full-build` option to CLI. These force the compiler to perform a full build +* `--version` option to CLI. Outputs current version of elixirscript +* `--std-lib` option to CLI. Takes a path and adds the stdlib to that path ### Changed -- Renamed `copy_core_to_destination` to `copy_stdlib_to_destination` -- Incremental Compilation: ElixirScript will now only build files and modules that have changed since the last build + +* Renamed `copy_core_to_destination` to `copy_stdlib_to_destination` +* Incremental Compilation: ElixirScript will now only build files and modules that have changed since the last build ### Removed -- `--core` option from CLI and `:core` compiler option. + +* `--core` option from CLI and `:core` compiler option. ## [0.16.0] 2016-02-27 + ### Added -- Bitstring pattern matching -- Bitstrings in for comprehensions -- Functions with catch, after, else clauses -- `with` special form -- Pin operator in map keys and function clauses -- Added `Kernel.object/1` function to make it more natural to create a JavaScript object with string keys. Elixirscript, by default turns the following, `%{a:"b"}` into `{[Symbol.for("a")]: "b"}` in JavaScript. In order to get string keys, one would have to do `%{"a" => "b"}` which turns into `{a: "b"}` in JavaScript. With `Kernel.object`, you can create string keyed maps conveniently, `object(a: "b")` which turns into `{a: "b"}`. - **NOTE**: when updating the created by, you still have to use the string form `%{ my_map | "a" => "c" }` +* Bitstring pattern matching +* Bitstrings in for comprehensions +* Functions with catch, after, else clauses +* `with` special form +* Pin operator in map keys and function clauses +* Added `Kernel.object/1` function to make it more natural to create a JavaScript object with string keys. Elixirscript, by default turns the following, `%{a:"b"}` into `{[Symbol.for("a")]: "b"}` in JavaScript. In order to get string keys, one would have to do `%{"a" => "b"}` which turns into `{a: "b"}` in JavaScript. With `Kernel.object`, you can create string keyed maps conveniently, `object(a: "b")` which turns into `{a: "b"}`. + + **NOTE**: when updating the created by, you still have to use the string form `%{ my_map | "a" => "c" }` ### Removed -- `JS.update(object, property, value)` has been removed and replaced with `JS.update(object, map)`. This allows you to update multiple values on a javascript object at once. + +* `JS.update(object, property, value)` has been removed and replaced with `JS.update(object, map)`. This allows you to update multiple values on a javascript object at once. ### Fixed -- Optional parameters should now work as expected + +* Optional parameters should now work as expected ## [0.15.2] - 2016-02-21 + ### Addded -- Support for variables as map keys + +* Support for variables as map keys ### Fixed -- Protocol implementations for Integer and Float which where not recognized -- Calling properties on non-objects + +* Protocol implementations for Integer and Float which where not recognized +* Calling properties on non-objects ## [0.15.1] - 2016-02-19 + ### Removed -- Removed `catch` as a javascript keyword to filter + +* Removed `catch` as a javascript keyword to filter ### Fixed -- Fixed View module so that an element can have multiple elements within -- struct implementation so that lists of atoms for fields are compiled correctly -- head-tail pattern match to allow for more complicated scenarios -- ModuleCollector to properly alias inner modules -- Raise translation to properly translate when string messages are given + +* Fixed View module so that an element can have multiple elements within +* struct implementation so that lists of atoms for fields are compiled correctly +* head-tail pattern match to allow for more complicated scenarios +* ModuleCollector to properly alias inner modules +* Raise translation to properly translate when string messages are given ## [0.15.0] - 2016-01-26 + ### Added -- `__ENV__` and `__CALLER__` are now supported -- `JS.import/1`, `JS.typeof/1`,`JS.instanceof/1`, and `JS.global/1` -- Support for multi alias/require/imports statements + +* `__ENV__` and `__CALLER__` are now supported +* `JS.import/1`, `JS.typeof/1`,`JS.instanceof/1`, and `JS.global/1` +* Support for multi alias/require/imports statements ### Changed -- `alias`, `require`, and `import` now work inside lexical scopes -- Some of the standard library originally written in JavaScript has been rewritten in Elixir. -- Generated JavaScript export statements are now default exports -- When output is sent to standard out, there are now markers to specify where each module begins as well as what the file name would be. For the end of a file, `//:ENDFILE` is used. For the file name, `//:ENDFILENAME` is used where `` is the name of the file -- `compile`, `compile_path`, and `compile_quoted` opts parameter now expects a map -- The `stdlib` compiler option is now `core`. The `stdlib_path` compiler options is now `core_path` + +* `alias`, `require`, and `import` now work inside lexical scopes +* Some of the standard library originally written in JavaScript has been rewritten in Elixir. +* Generated JavaScript export statements are now default exports +* When output is sent to standard out, there are now markers to specify where each module begins as well as what the file name would be. For the end of a file, `//:ENDFILE` is used. For the file name, `//:ENDFILENAME` is used where `` is the name of the file +* `compile`, `compile_path`, and `compile_quoted` opts parameter now expects a map +* The `stdlib` compiler option is now `core`. The `stdlib_path` compiler options is now `core_path` ## [0.14.1] - 2015-12-07 + ### Removed -- .DS_Store and LICENSE from output + +* .DS_Store and LICENSE from output ## [0.14.0] - 2015-12-06 + ### Added -- Can now implement protocols using JavaScript types + +* Can now implement protocols using JavaScript types ```elixir defimpl MyProtocol, for: HTMLElement ``` -- virtual-dom JavaScript library -- ElixirScript.Html module for defining a virtual-dom tree -- ElixirScript.VDom module for manipulating the virtual-dom tree created using the ElixirScript.Html module -- Added ElixirScript.View module for handling view state and rendering virtual-dom -- Added `stdlib_path` compiler option to specify the es6 path to the standard library. If used, elixir.js will not be exported with the compiled modules +* virtual-dom JavaScript library +* ElixirScript.Html module for defining a virtual-dom tree +* ElixirScript.VDom module for manipulating the virtual-dom tree created using the ElixirScript.Html module +* Added ElixirScript.View module for handling view state and rendering virtual-dom +* Added `stdlib_path` compiler option to specify the es6 path to the standard library. If used, elixir.js will not be exported with the compiled modules ### Changed -- Renamed `ex2js` to `elixirscript`. This effects the escript as well as the + +* Renamed `ex2js` to `elixirscript`. This effects the escript as well as the mix task -- Structs are now translated into classes -- Structs and Tuples now match on their types -- Can now match on JavaScript classes. Works just like matching on structs: +* Structs are now translated into classes +* Structs and Tuples now match on their types +* Can now match on JavaScript classes. Works just like matching on structs: ```elixir def my_func(%HTMLElement{id: "myId"}) ``` -- Moved non-elixir JavaScript code into `core` es6 module. This will hopefully +* Moved non-elixir JavaScript code into `core` es6 module. This will hopefully make it so ElixirScript Standard Library modules can be defined in Elixir soon. ## [0.13.0] - 2015-10-26 + ### Added -- `Base` module with function: encode64, decode64, and decode64! -- `String` module -- `Bitwise` module -- `Map` module -- `MapSet` module -- `Set` module -- Protocol support -- Added `Collectable`, `Enumerable`, `Inspect`, `List.Chars`, and `String.Chars` protocols. The only one currently being used in the Standard Library, however, is String.Chars + +* `Base` module with function: encode64, decode64, and decode64! +* `String` module +* `Bitwise` module +* `Map` module +* `MapSet` module +* `Set` module +* Protocol support +* Added `Collectable`, `Enumerable`, `Inspect`, `List.Chars`, and `String.Chars` protocols. The only one currently being used in the Standard Library, however, is String.Chars ## [0.12.0] - 2015-09-23 + ### Added -- Added PostOffice. Only thing that current uses it is Agent + +* Added PostOffice. Only thing that current uses it is Agent ### Changed -- Updated tuple implementation. It's now a class. -- Replaced pattern matching library with custom one -- Moved data types to Kernel.SpecialForms -- `else` now works for try expressions -- for now works with `into` for lists + +* Updated tuple implementation. It's now a class. +* Replaced pattern matching library with custom one +* Moved data types to Kernel.SpecialForms +* `else` now works for try expressions +* for now works with `into` for lists ### Removed -- Removed erlang.js. + +* Removed erlang.js. ## [0.11.0] - 2015-09-17 + ### Added -- Added `JS` module with `new`, `mutate`, `import` macros -- Added `Keyword` module with functions, `has_key?` and `get` -- Added `Agent` module with functions, `start`, `get`, `update`, and `get_and_update` + +* Added `JS` module with `new`, `mutate`, `import` macros +* Added `Keyword` module with functions, `has_key?` and `get` +* Added `Agent` module with functions, `start`, `get`, `update`, and `get_and_update` ### Changed -- Map keys are now correctly turned into their atom counterparts if atom keys are used -- `import` works with all options -- `Mutable.update` has been replaced by `JS.update` -- `transpile`, `transpile_quoted`, and `transpile_path` are now `compile`, `compile_quoted`, and `compile_path` -- All Standard libraries are rolled up into one elixir.js file and imported from that -- Modules no longer export a default object -- `alias` now translates to a namespace import unless `default` option is given + +* Map keys are now correctly turned into their atom counterparts if atom keys are used +* `import` works with all options +* `Mutable.update` has been replaced by `JS.update` +* `transpile`, `transpile_quoted`, and `transpile_path` are now `compile`, `compile_quoted`, and `compile_path` +* All Standard libraries are rolled up into one elixir.js file and imported from that +* Modules no longer export a default object +* `alias` now translates to a namespace import unless `default` option is given ## [0.10.0] - 2015-09-02 + ### Added -- Added `env` option for `ElixirScript.transpile` adding macros for compilation -- Added `Logger` that translates Logger functions to console + +* Added `env` option for `ElixirScript.transpile` adding macros for compilation +* Added `Logger` that translates Logger functions to console ### Changed -- Updated `Kernel` module to translate some functions to it's JavaScript equivalent + +* Updated `Kernel` module to translate some functions to it's JavaScript equivalent ### Fixed -- Fixed `case` implementation to add `this` to call + +* Fixed `case` implementation to add `this` to call ## [0.9.0] - 2015-08-30 + ### Added -- an implementation for quote. Currently ignores `:location` and `:context` options -- an implementation for unquote and unquote_splicing + +* an implementation for quote. Currently ignores `:location` and `:context` options +* an implementation for unquote and unquote_splicing ## [0.8.0] - 2015-08-15 + ### Added -- Can now support catch blocks in try expressions -- Added receive + +* Can now support catch blocks in try expressions +* Added receive ### Changed -- Updated pattern matching implementation -- Wrapped try's in function closure to make sure they return a value; + +* Updated pattern matching implementation +* Wrapped try's in function closure to make sure they return a value; ## [0.7.0] - 2015-08-01 + ### Added -- Can now support rescue and after blocks in try expressions + +* Can now support rescue and after blocks in try expressions ## [0.6.5] - 2015-07-13 + ### Changed -- Now using the JS code generator from elixir-estree for code generation, improving speed of transpilation -- the parse functions in the ElixirScript module have been renamed to transpile + +* Now using the JS code generator from elixir-estree for code generation, improving speed of transpilation +* the parse functions in the ElixirScript module have been renamed to transpile ## [0.6.0] - 2015-07-02 + ### Added -- Added iterators for Range and BitString -- Now replacing characters that can't be used in variable and function names in JavaScript with something that it (i.e. `match?` -> `match__qmark__`) -- Implemented Integer module + +* Added iterators for Range and BitString +* Now replacing characters that can't be used in variable and function names in JavaScript with something that it (i.e. `match?` -> `match__qmark__`) +* Implemented Integer module ### Changed -- Made the Tuple, Range and BitString data structures more immutable -- Atom now translates to an ES6 Symbol -- List now translates to a frozen JS Array -- Updated the pattern match binding to use ES6 destructuring for lists and tuples -- Inner modules are now split out into their own files - * Standard lib is now exported with file output from cli - * Standard lib modules are now automatically imported - * No longer have to define modules via aliases ahead of time. They will be automatically be resolved - and made into JavaScript import statements + +* Made the Tuple, Range and BitString data structures more immutable +* Atom now translates to an ES6 Symbol +* List now translates to a frozen JS Array +* Updated the pattern match binding to use ES6 destructuring for lists and tuples +* Inner modules are now split out into their own files + * Standard lib is now exported with file output from cli + * Standard lib modules are now automatically imported + * No longer have to define modules via aliases ahead of time. They will be automatically be resolved + and made into JavaScript import statements ## [0.5.0] - 2015-05-31 + ### Added -- added `from` clause to `import`, `alias`, and `require` so that the import path can be overridden + +* added `from` clause to `import`, `alias`, and `require` so that the import path can be overridden ### Changed -- For statements now work with pattern matching tuples -- Improved function chaining -- `alias` now acts like `require` in that it is translated into an import default statement -- modules now export a default object with def functions added as properties on it. -- for function closures, now calling by using `.call(this)` so that `this` is available inside of it + +* For statements now work with pattern matching tuples +* Improved function chaining +* `alias` now acts like `require` in that it is translated into an import default statement +* modules now export a default object with def functions added as properties on it. +* for function closures, now calling by using `.call(this)` so that `this` is available inside of it ## [0.4.0] - 2015-05-05 + ### Added -- bitstrings -- Better Pattern Matching (Does not support bitstrings yet) -- Capture Operator -- Added more functions from the list standard library + +* bitstrings +* Better Pattern Matching (Does not support bitstrings yet) +* Capture Operator +* Added more functions from the list standard library ### Changed -- Updated variable implementation to match Elixir's (i.e. Reusing the same variable name creates a new one in the background) + +* Updated variable implementation to match Elixir's (i.e. Reusing the same variable name creates a new one in the background) ### Fixed -- Fixed multi arity implementation + +* Fixed multi arity implementation ## [0.3.0] - 2015-04-23 + ### Added -- function and case guards -- function and case pattern matching + +* function and case guards +* function and case pattern matching ### Changed -- Can now use ^ on a variable during assignment + +* Can now use ^ on a variable during assignment ## [0.2.1] - 2015-04-14 + ### Changed -- Renamed project to ElixirScript -- Reduced escript file size + +* Renamed project to ElixirScript +* Reduced escript file size ## [0.2.0] - 2015-04-12 + ### Added -- Pipe operator -- String interpolation -- Adding more functions to the Kernel module -- Fully implemented Tuple module -- Fully implemented Atom module -- Fully implemented Range module + +* Pipe operator +* String interpolation +* Adding more functions to the Kernel module +* Fully implemented Tuple module +* Fully implemented Atom module +* Fully implemented Range module ### Changed -- Now checking to see if a function is a Kernel function and prepending Kernel to it -- Now turning Atoms into an Atom javascript object instead of a Symbol -- Now turning tuples into a Tuple javascript object -- Can now call properties and zero parameter functions correctly -- case, cond, and if are now turned into if statements wrapped in function closures -- Anonymous functions are now turned into anonymous functions in javascript insteed of arrow functions + +* Now checking to see if a function is a Kernel function and prepending Kernel to it +* Now turning Atoms into an Atom javascript object instead of a Symbol +* Now turning tuples into a Tuple javascript object +* Can now call properties and zero parameter functions correctly +* case, cond, and if are now turned into if statements wrapped in function closures +* Anonymous functions are now turned into anonymous functions in javascript insteed of arrow functions ## [0.1.0] - 2015-04-04 + ### Added -- From standard library implemented: - * Enum.map - * Kernel.tl - * Kernel.hd - * Logger -- Implemented language features: - * All primitives except bitstrings - * defmodule - * import, alias, and require - * case, cond, if - * def, defp - * defstruct, defexception - * raise - * multiple arity functions - * basic binary operations - * for without into + +* From standard library implemented: + +- Enum.map +- Kernel.tl +- Kernel.hd +- Logger + +* Implemented language features: + +- All primitives except bitstrings +- defmodule +- import, alias, and require +- case, cond, if +- def, defp +- defstruct, defexception +- raise +- multiple arity functions +- basic binary operations +- for without into diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 511aa424..56fcb028 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,9 +6,9 @@ This contributing guide is based on the contributing for Elixir with changes sui Use the issues tracker for: -* [bug reports](#bug-reports) -* [submitting pull requests](#pull-requests) -* [feature requests](#feature-requests) +- [bug reports](#bug-reports) +- [submitting pull requests](#pull-requests) +- [feature requests](#feature-requests) ## Bug reports @@ -18,7 +18,7 @@ Good bug reports are extremely helpful - thank you! Guidelines for bug reports: 1. **Use the GitHub issue search** — [check if the issue has already been - reported](https://github.com/bryanjos/elixirscript/search?type=Issues). + reported](https://github.com/elixirscript/elixirscript/search?type=Issues). 2. **Check if the issue has been fixed** — try to reproduce it using the `master` branch in the repository. @@ -51,7 +51,7 @@ Example: ## Feature requests Feature requests are welcome. But take a moment to find -out whether your idea fits with the scope and aims of the project. It's up to *you* +out whether your idea fits with the scope and aims of the project. It's up to _you_ to make a strong case to convince the community of the merits of this feature. Please provide as much detail and context as possible. @@ -63,29 +63,22 @@ found in Elixir in ElixirScript. ElixirScript is broken up into the following parts: -* The compiler, written in Elixir -* The standard library modules, mostly written in Elixir -* The javascript core +- The compiler, written in Elixir +- The JavaScript core -The ElixirScript compiler is in the `lib` folder of the project. +The ElixirScript compiler is in the `lib` folder of the project. Here is where Elixir code is converted into JavaScript. -The standard library modules are in the `lib/std_lib` folder. +The JavaScript code is in the `src/javascript`. +This is where the special forms and the Erlang Compatibility Layer are defined -The JavaScript code is in the `src/javascript`. -This is where features such as pattern matching and the standard library are implemented. +The ElixirScript tests are ran using `mix test` -The ElixirScript tests can be run using `mix test` - -The JavaScript tests can be run using `npm test` +The JavaScript tests are ran using `npm test` Please make sure all tests pass after making changes. Also make sure to include tests for the changes you made. -Contributing to the JavaScript code may be the easiest and most rewarding changes. -Don't see a feature, module or function from Elixir in ElixirScript yet? You can implement it -in the JavaScript code. - ## Pull requests Good pull requests - patches, improvements, new features - are a fantastic @@ -111,72 +104,72 @@ documentation. When working with Git, we recommend the following process in order to craft an excellent pull request: 1. [Fork](https://help.github.com/fork-a-repo/) the project, clone your fork, - and configure the remotes: + and configure the remotes: - ```sh - # Clone your fork of the repo into the current directory - git clone https://github.com//elixirscript - # Navigate to the newly cloned directory - cd elixirscript - # Assign the original repo to a remote called "upstream" - git remote add upstream https://github.com/bryanjos/elixirscript - ``` +```sh +# Clone your fork of the repo into the current directory +git clone https://github.com//elixirscript +# Navigate to the newly cloned directory +cd elixirscript +# Assign the original repo to a remote called "upstream" +git remote add upstream https://github.com/elixirscript/elixirscript +``` 2. If you cloned a while ago, get the latest changes from upstream: - ```sh - git checkout master - git pull upstream master - ``` +```sh +git checkout master +git pull upstream master +``` 3. Create a new topic branch (off of `master`) to contain your feature, change, - or fix. + or fix. - **IMPORTANT**: Making changes in `master` is discouraged. You should always - keep your local `master` in sync with upstream `master` and make your - changes in topic branches. + **IMPORTANT**: Making changes in `master` is discouraged. You should always + keep your local `master` in sync with upstream `master` and make your + changes in topic branches. - ```sh - git checkout -b - ``` +```sh +git checkout -b +``` 4. Commit your changes in logical chunks. Keep your commit messages organized, - with a short description in the first line and more detailed information on - the following lines. Feel free to use Git's - [interactive rebase](https://help.github.com/articles/interactive-rebase) - feature to tidy up your commits before making them public. + with a short description in the first line and more detailed information on + the following lines. Feel free to use Git's + [interactive rebase](https://help.github.com/articles/interactive-rebase) + feature to tidy up your commits before making them public. 5. Make sure all the tests are still passing. - ```sh - mix test - npm test - ``` +```sh +mix test +npm test +``` - This is needed to ensure your changes can - pass all the tests. +This is needed to ensure your changes can +pass all the tests. 6. Push your topic branch up to your fork: - ```sh - git push origin - ``` +```sh +git push origin +``` 7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) - with a clear title and description. + with a clear title and description. 8. If you haven't updated your pull request for a while, you should consider - rebasing on master and resolving any conflicts. - - **IMPORTANT**: _Never ever_ merge upstream `master` into your branches. You - should always `git rebase` on `master` to bring your changes up to date when - necessary. - - ```sh - git checkout master - git pull upstream master - git checkout - git rebase master - ``` + rebasing on master and resolving any conflicts. + + **IMPORTANT**: _Never ever_ merge upstream `master` into your branches. You + should always `git rebase` on `master` to bring your changes up to date when + necessary. + +```sh +git checkout master +git pull upstream master +git checkout +git rebase master +``` Thank you for your contributions! diff --git a/CompilerInternals.md b/CompilerInternals.md new file mode 100644 index 00000000..c729ee09 --- /dev/null +++ b/CompilerInternals.md @@ -0,0 +1,51 @@ +# Compiler Internals + +This is a document describing how ElixirScript works. This is intended for those who would like to contribute to ElixirScript or those who are curious how it works. + +## Input + +[ElixrScript.Compiler](https://github.com/elixirscript/elixirscript/blob/master/lib/elixir_script/compiler.ex) is the entry point of the compiler. It takes in either a module or a list of modules. These are what are called the `entry modules` or the entry points into your application. These are the places ElixirScript will start it's compilation process. It will traverse what is used and only compile those things. This is the first step in the compilation process. Finding used modules to compile. + +## Finding Used Modules + +[ElixirScript.FindUsedModules](https://github.com/elixirscript/elixirscript/blob/master/lib/elixir_script/passes/find_used_modules.ex) looks at our entry modules and recursively crawls them to find all the modules used. It firsts exacts the Abstract Syntax Tree (AST) from the Beam file and then looks for references to modules that haven't been crawled yet. This information is stored in [ElixirScript.State](https://github.com/elixirscript/elixirscript/blob/master/lib/elixir_script/state.ex) + +## AST Extraction from Beam Files + +ElixirScript requires at Erlang 20+ and Elixir 1.6+. The reason why is that in Erlang 20 there is a new feature that allows for debug information to be stored in beam files. Any of the beam languages can use this. Elixir uses it by storing the AST for the module in there. This is a special version of the AST where all of the macros are expanded. This means ElixirScript does not have to worry about macro expansion itself. This AST is what ElixirScript works with. + +The code for this is in the [ElixirScript.Beam](https://github.com/elixirscript/elixirscript/blob/master/lib/elixir_script/beam.ex) module. + +`ElixirScript.debug_info/1` takes in a module name and returns the AST for that module. For a normal module, `{:ok, map}` are returned. If a protocol is given, `{:ok, atom, map, list}` is returned. The `atom` is the name of the protocol, The `map` is the protocol's AST and the `list` is the list of all of the implementation modules. + +This module handles the `String` and `Agent` modules a little bit differenly. Because of how Elixir compiles the unicode library, ElixirScript has to be careful not to compile the entire unicode library in JavaScript. So here, `debug_info` will get the AST from `String`, but replace some functions with the AST from `ElixirScript.String`. This ensures ElixirScript uses versions of functions in the standard lib that won't bring in the unicode module. The ame thing happens for `Agent` for different reasons. `Agent` is the only OTP module ElixirScript supports. ElixirScript hacks together a version of `Agent` that stores state in a way that allows ElixirScript users to use `Agent` just like they would with Elixir. + +## Finding Used Functions + +[ElixirScript.FindUsedFunctions](https://github.com/elixirscript/elixirscript/blob/master/lib/elixir_script/passes/find_used_functions.ex) is our second process in shrinking our compilation suface. In this process, we crawl through the modules we have found for compilation and see which functions are actually being called. This information is also stored in [ElixirScript.State](https://github.com/elixirscript/elixirscript/blob/master/lib/elixir_script/state.ex) for each module. + +**Note**: Because of the way protocols work, it is impossible to know what is used and what isn't. So for protocols and their implementations, we have to take in everything. + +Now we have what we need to compile to the JavaScript AST. + +## JavaScript AST (ESTree) + +Before going further, here is a brief intro into the JavaScript AST we use. The [ESTree spec](https://github.com/estree/estree) is a specification based on SpiderMonkey's JavaScript AST. This is used by several tools in the JavaScript ecosystem. There are many other versions of JavaScript ASTs, but the reason ElixirScript uses this one is because there are popular tools in the JavaScript ecosystem that understand it. ElixirScript uses the [ESTree](https://github.com/elixirscript/elixir-estree) Hex package. This package has structs that represent ESTree Nodes. It can also turn those into JavaScript code. + +## Translation + +[ElixirScript.Translate](https://github.com/elixirscript/elixirscript/blob/master/lib/elixir_script/passes/translate.ex) starts off the translation process. All this module does though is call [ElixirScript.Translate.Module](https://github.com/elixirscript/elixirscript/blob/master/lib/elixir_script/passes/translate/module.ex) on each of our modules. Here is where we take in the module info for each module and start translating to JavaScript AST. We compile the function definitions into JavaScript. Here is where we process the information gained from `ElixirScript.FindUsedFunctions` to remove any unused functions. In Elixir, function names are made up of the name and the arity. In JavaScript, that is not the case. ElixirScript combines function arities here into one definition. From here, ElixirScript compiles each function and places the translated AST back into `ElixirScript.State`. + +Functions comprise of clauses. Clauses have guards and blocks. Blocks being the blocks of code that make up the implementation. + +[ElixirScript.Translate.Function](https://github.com/elixirscript/elixirscript/blob/master/lib/elixir_script/passes/translate/function.ex) handles function translation. `ElixirScript.Translate.Function.compile_block\2` handles compilation of blocks. for each item in the block, `ElixirScript.Translate.Form.compile\2` is called. This is what is responsible for a bulk of the translation. + +Another aside to talk about function translation. Elixir supports tail call recursion. JavaScript does not. To allow our ElixirScript-translated functions to do so, we use a technique called `trampolining`. ElixirScript implementation still has some bugs, but it works for the most part. + +## Pattern Matching Translation + +Patterns are processed using [ElixirScript.Translate.Forms.Pattern](https://github.com/elixirscript/elixirscript/blob/master/lib/elixir_script/passes/translate/forms/pattern.ex). It takes all the forms of patterns and compiles them into JavaScript AST. The AST represents calls to the [Tailored](https://github.com/elixirscript/tailored) JavaScript library. This library is responsible for pattern matching at run time. + +## Output + +[ElixirScript.Output](https://github.com/elixirscript/elixirscript/blob/master/lib/elixir_script/passes/output.ex) is the last step in compilation. This modules is responsible for creating JavaScript modules and writing them to the file system. Each Elixir module is translated into a JavaScript module. diff --git a/FAQ.md b/FAQ.md deleted file mode 100644 index 107cd895..00000000 --- a/FAQ.md +++ /dev/null @@ -1,98 +0,0 @@ -# FAQ - -# Q. How do I get started? - -### A. Check out the [Getting Started](GettingStarted.md) Guide for more info. - -# Q. How much is implemented? - -### A. Most of Kernel.SpecialForms as well as some modules in the Standard Library - -The compiler to this point has been focused on translating Kernel.SpecialForms and Kernel. Below is a list of what is complete, incomplete, as well as missing - -#### Kernel.SpecialForms - -* Complete - * `__DIR__` - * `__MODULE__` - * `^var` - * `&expr` - * `for` - * `%{}` - * `{args}` - * `<>` - * `fn [clauses] end` - * `cond(clauses)` - * `__block__` - * `__aliases__` - * `unquote` - * `unquote_splicing` - * `%` - * `left.right` - * `quote` - * `import` - * `case` - * `left = right` - * `require` - * `left :: right` - * `alias` - * `__CALLER__` - * `__ENV__` - -* Missing - * `super(args)` - * `receive` - -* Caveats - * `quote` - ignores `context` options - * `left = right` does not support full unification yet. - ```elixir - a = 1 # works as expected - - 1 = a # may not work currently, but in some cases it will - ``` - - -#### Completed Modules - - * Tuple - * List - * Atom - * Range - * Logger - * Map - * MapSet - -#### Incomplete Modules - - * Kernel - * Enum - * Agent - * Integer - * Keyword - * Base - * String - * Bitwise - * Set - -#### Missing Modules - * Everything else - - -## Q. Can I use it today? - -### A. Yes, but realize this is not at 1.0 yet. - -You **can** use ElixirScript on your front ends and have it work and interoperate with JavaScript modules. The problem is since most of the standard library is incomplete. - -## Q. Can I use pattern matching? - -### A. Yes - -## Q. Can I use processes? - -### A. ElixirScript does not support processes - -## Q. What about OTP? - -### A. ElixirScript does not support OTP diff --git a/GettingStarted.md b/GettingStarted.md deleted file mode 100644 index 3691d4ea..00000000 --- a/GettingStarted.md +++ /dev/null @@ -1,143 +0,0 @@ -# Getting Started with ElixirScript - -The intent of this guide is to get you started with ElixirScript. It will give you instructions on using ElixirScript. I will go over the two ways you can use Elixirscript: - -* As a CLI -* As a mix dependency - -### CLI - -**macOS**: Elixirscript is available via homebrew `brew install elixirscript`. For everyone else, please read below - -Step 1: Get CLI - -You can download the elixirscript CLI from the [releases page on github](https://github.com/bryanjos/elixirscript/releases). It is a tar file named elixirscript.tar.gz. - -Step 2: Untar - -Next, untar elixirscript.tar.gz - - tar -xvzf elixirscript.tar.gz - -You will want to put the bin folder from the uncompressed folder into your path. This should allow you to use the elixirscript CLI. - -Step 3: Use - -This is the help output of elixirscript - - usage: elixirscript [options] - path to elixir files or - the elixir code string if passed the -ex flag - options: - -f --format [format] module format of output. options: es (default), common, umd - -o --output [path] places output at the given path - -ex --elixir read input as elixir code string - --full-build informs the compiler to do a full build instead of an incremental one - --core-path import path to the elixirscript standard lib - only used with the [output] option. When used, Elixir.js is not exported - -v --version the current version number - -h --help this message - -the `` is the elixir code string or file path you want to convert from elixir to javascript. Below is an example of using a code string and turning it into JavaScript - - $ elixirscript ":atom" -ex - Symbol.for('atom') - -It changed the elixir code, `:atom` into the JavaScript code `Symbol.for('atom')`. The `-ex` parameter lets the script know that the input is an Elixir code string instead of a file. - -elixirscript also takes a path to your `.ex` files as well: - - $ elixirscript "src" -o "dist" - -If you look in the dist folder, you should see 2 folders. `app` contains your code and `elixir` contains the elixirscript standard library files. - -### Mix dependency - -Adding Elixirscript to your mix project gives you the ability to add it to your list of mix compilers. This means when you `mix compile`, Elixirscript will compile your code as well. - -Add dependency to your deps in mix.exs: - - ```elixir - {:elixir_script, "~> 0.25"} - ``` - - Elixirscript uses default input, output and module formats if options are not given. If you wish to change any or all options, add an `elixir_script` key to your project configuration. - - def project do - [ - app: :my_app, - version: "0.1.0", - elixir: "~> 1.0", - deps: deps, - elixir_script: [ input: "lib/elixirscript", output: "priv/elixirscript", format: :es], - compilers: [:elixir_script] ++ Mix.compilers - ] - end - -Available options are: - -* `input`: The folder to look for Elixirscript files in. (defaults to `lib/elixirscript`) - -* `output`: The folder to place generated JavaScript code in. (defaults to `priv/elixirscript`) - -* `format`: The module format of generated JavaScript code. (defaults to `:es`). Choices are:     - - * `:es` - ES Modules - - * `:common` - CommonJS - - * `:umd` - UMD - -### Macros - -Elixirscript supports public macros. Private macros are currently unsupported. - -### JavaScript Interop - -Elixirscript has a couple of ways of interacting with JavaScript. - -#### Globally scoped functions - -Use the erlang module syntax, to call JavaScript functions in the global scope. - - # Calling alert - :window.alert("hi") - - # console - :console.log("hello") - - # document - :document.getElementById("main") - -#### Globally scoped modules - -You can call globally scoped modules you would an Elixir module - - Date.now() - -Only works if module begins with a captial letter - -#### Importing Modules - -To import modules, first you must `require` the `JS` module. Then import the module using `JS.import` - - defmodule MyModule do - require JS - JS.import React, "react" - - def func() do - React.render(my_component) - end - end - -#### The JS module - -The JS module has many other functions and macros. For more information, check out the docs. - -#### Frontend Project Boilerplate - -There is an [elixirscript frontend boilerplate project](https://github.com/bryanjos/elixirscript-project-boilerplate). This setup uses gulp and webpack to build and bundle assets. - -#### ElixirScript-Brunch - -There is an Brunch plugin, [ElixirScript-Brunch](https://www.npmjs.com/package/elixirscript-brunch). There are instructions there on how to use it with Phoenix. \ No newline at end of file diff --git a/JavascriptInterop.md b/JavascriptInterop.md new file mode 100644 index 00000000..4426b0df --- /dev/null +++ b/JavascriptInterop.md @@ -0,0 +1,107 @@ +# JavaScript Interoperability + +## Data Type Conversions + +ElixirScript translates Elixir primitive types to the following: + +| Elixir | JavaScript | +|--------|------------| +| Integer | Number | +| Float | Number | +| Binary | String | +| Atom | Symbol | +| List | Array | +| Map | Map | +| Tuple | ErlangTypes.Tuple | +| Bitstring | ErlangTypes.Bitstring | +| PID | ErlangTypes.PID | +| Reference | ErlangTypes.Reference | + +The ErlangTypes library can be found [here](https://github.com/elixirscript/erlang-types) + +## ElixirScript Calling JavaScript + +### ElixirScript.JS module + +The `ElixirScript.JS` module has functions and macros that help with interacting with JavaScript. +Most of them correspond to JavaScript keywords that may be useful. + +```elixir +# Calling the JavaScript Debugger +ElixirScript.JS.debugger() + +# Getting the type of a value +ElixirScript.JS.typeof(my_value) +``` + +### Foreign Function Interface + +ElixirScript calls JavaScript modules through a Foreign Function Interface (FFI). A foreign module is defined by creating a new Elixir module and adding `use ElixirScript.FFI` to it. + +Here is an example of a foreign module for a JSON module + +```elixir +defmodule MyApp.JSON do + use ElixirScript.FFI + + defexternal stringify(map) + defexternal parse(string) +end +``` + +Foreign modules map to JavaScript files that export functions defined with the `defexternal` macro. +ElixirScript expects JavaScript modules to be in the `priv/elixir_script` directory. +These modules are copied to the output directory upon compilation. + +For our example, a JavaScript file must be placed at `priv/elixir_script/my_app/json.js`. + +It looks like this +```javascript +export default { + stringify: JSON.stringify, + parse: JSON.parse +} +``` + +For more information and options. Check the documentation for `ElixirScript.FFI` + +## JavaScript Calling ElixirScript + + In order to start an ElixirScript application, you must first import it using whichever JavaScript module system you are using and then call `Elixir.start` + + ```Elixir + # Our ElixirScript module + + defmodule Main do + def start(:normal, args) do + args + end + end + + ``` + + ```javascript + import Main from './Elixir.Main.js' + Main.start(Symbol.for('normal'), [1, 2, 3]) + ``` + + In the above example, we have an ElixirScript module, `Main` with a `start/2` function. + + + If you want to use an ElixirScript module inside of your JavaScript code, you can do so like below. + + ```Elixir + # Our ElixirScript module + + defmodule MyModule do + def hi() do + "hello" + end + end + ``` + + + ```javascript + import MyModule from './Elixir.MyModule.js' + MyModule.hi() + ``` diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..9ede1be1 --- /dev/null +++ b/Makefile @@ -0,0 +1,32 @@ +.PHONY: compile test clean js_compile elixir_compile elixir_test js_test deps elixir_deps js_deps + +default: deps compile + +compile: js_compile elixir_compile + +js_compile: + npm run build + +elixir_compile: + mix compile + +test: js_compile elixir_test js_test + +js_test: + npm test + +elixir_test: + mix test --cover + mix elixirscript.test + +clean: + rm -rf priv/build + mix clean + +deps: elixir_deps js_deps + +elixir_deps: + mix deps.get + +js_deps: + npm install diff --git a/README.md b/README.md index dce8097d..6d464386 100644 --- a/README.md +++ b/README.md @@ -1,77 +1,80 @@ -## ElixirScript [![Documentation](https://img.shields.io/badge/docs-hexpm-blue.svg)](http://hexdocs.pm/elixir_script/) [![Build](https://travis-ci.org/elixirscript/elixirscript.svg?branch=master)](https://travis-ci.org/elixirscript/elixirscript) [![Deps Status](https://beta.hexfaktor.org/badge/all/github/bryanjos/elixirscript.svg)](https://beta.hexfaktor.org/github/bryanjos/elixirscript) [![Join the chat at https://gitter.im/elixirscript/elixirscript](https://badges.gitter.im/elixirscript/elixirscript.svg)](https://gitter.im/elixirscript/elixirscript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +## ElixirScript [![Documentation](https://img.shields.io/badge/docs-hexpm-blue.svg)](http://hexdocs.pm/elixir_script/) [![Build](https://travis-ci.org/elixirscript/elixirscript.svg?branch=master)](https://travis-ci.org/elixirscript/elixirscript) -The goal is to convert a subset (or full set) of Elixir code to JavaScript, providing the ability to write JavaScript in Elixir. This is done by taking the Elixir AST and converting it into JavaScript AST and then to JavaScript code. This is done using the [Elixir-ESTree](https://github.com/bryanjos/elixir-estree) library. +The goal is to convert a subset (or full set) of Elixir code to JavaScript, providing the ability to write JavaScript in Elixir. This is done by taking the Elixir AST and converting it into JavaScript AST and then to JavaScript code. This is done using the [Elixir-ESTree](https://github.com/elixirscript/elixir-estree) library. -Requirements -=========== -* Elixir -* Node (only for development) +[Documentation for current release](http://hexdocs.pm/elixir_script/) -Usage -======== +# Requirements -Please check the [Getting Started Guide](GettingStarted.md) for usage +* Erlang 20 or greater +* Elixir 1.6 or greater (must be compiled with Erlang 20 or greater) +* Node 8.2.1 or greater (only for development) +# Usage -FAQ, Limitations -======== +Add dependency to your deps in mix.exs: -Please check the [FAQ](FAQ.md) +```elixir +{:elixir_script, "~> x.x"} +``` +Add `elixir_script` to list of mix compilers in mix.exs +Also add `elixir_script` configuration -Development -=========== +```elixir + def project do + [ + app: :my_app, + # ... + # Add elixir_script as a compiler + compilers: Mix.compilers ++ [:elixir_script], + # Our elixir_script configuration + elixir_script: [ + # Entry module. Can also be a list of modules + input: MyEntryModule, + # Output path. Either a path to a js file or a directory + output: "priv/elixir_script/build/elixirscript.build.js" + ] + ] + end +``` -Clone the repo +Run `mix compile` - git clone git@github.com:bryanjos/elixirscript.git +# Examples -Get dependencies +### Application - mix deps.get - npm install +[ElixirScript Todo Example](https://github.com/elixirscript/todo-elixirscript) -Compile +### Library - mix compile +[ElixirScript React](https://github.com/elixirscript/elixirscript_react) -Test +### Starter kit - mix test - npm test +[Elixirscript Starter Kit](https://github.com/harlantwood/elixirscript-starter-kit) +# Development -Build -============= - MIX_ENV=prod mix do clean, compile, dist +```bash +# Clone the repo +git clone git@github.com:bryanjos/elixirscript.git -This will build a tarball in the dist folder. -By default the escript built will look into the folder above it for the -core JavaScript files needed for ElixirScript. To change the location, -update the `lib_path` config variable in the `:elixir_script` config block -to the path to look in and then do a clean build. +#Get dependencies +make deps -Communication -======== +# Compile +make -[gitter room](https://gitter.im/elixirscript/elixirscript) -[#elixirscript](https://elixir-lang.slack.com/messages/elixirscript/) on the elixir-lang Slack - -Contributing -======== - -Please check the [CONTRIBUTING.md](CONTRIBUTING.md) +# Test +make test +``` +# Communication -### Example projects -* [hello](https://github.com/bryanjos/hello) Shows using Phoenix + Elixirscript with file watching -* [Elixirscript frontend boilerplate](https://github.com/bryanjos/elixirscript-project-boilerplate) A boilerplate project for elixirscript frontends -* [Elixirscript React example](https://github.com/bryanjos/elixirscript_react) An example of using with React -* [Elixirscript AWS Lambda example](https://github.com/bryanjos/elixirscript_lambda) +[#elixirscript](https://elixir-lang.slack.com/messages/elixirscript/) on the elixir-lang Slack -#### Using with Brunch -There is a plugin for using ElixirScript in your Brunch project -[here](https://www.npmjs.com/package/elixirscript-brunch) +# Contributing -#### 1.0 Roadmap -There is a [1.0.0 Milestone](https://github.com/bryanjos/elixirscript/milestones/1.0.0) defined which includes issues that are needed to be cleared before 1.0 can be reached. +Please check the [CONTRIBUTING.md](CONTRIBUTING.md) diff --git a/gulpfile.js b/gulpfile.js deleted file mode 100644 index 8b68b656..00000000 --- a/gulpfile.js +++ /dev/null @@ -1,13 +0,0 @@ -var gulp = require('gulp'); -var babel = require('gulp-babel'); -var sourcemaps = require('gulp-sourcemaps'); - -var path = './src/javascript'; - -gulp.task('build', function() { - return gulp.src([path + '/**/*.js', '!' + path + '/dist_build/**/*.js', '!' + path + '/tests/**/*.js']) - .pipe(sourcemaps.init()) - .pipe(babel({ presets: ["react", "stage-0"], babelrc: false })) - .pipe(sourcemaps.write()) - .pipe(gulp.dest('./src/elixirscript')); -}); diff --git a/lib/elixir_script.ex b/lib/elixir_script.ex index 659fa607..cfb1b9a6 100644 --- a/lib/elixir_script.ex +++ b/lib/elixir_script.ex @@ -1,238 +1,78 @@ defmodule ElixirScript do - require Logger - @moduledoc """ - Translates Elixir into JavaScript. - - All compile functions return a list of - transpiled javascript code or a tuple consisting of - the file name for the code and the transpiled javascript code. - All compile functions also take an optional opts parameter - that controls transpiler output. + ElixirScript acts as a mix compiler. This means that when you execute `mix compile`, + ElixirScript's compiler will run as well. Make sure to add ElixirScript to your + list of compilers in mix.exs. + + ElixirScript must be told which modules to use as the entry to your ElixirScript application. + This is done by adding an `elixir_script` key to your project configuration whose value is a keyword list of options. + Add an `input` key and make the value either the name of a module or a list of modules + that are the entry modules you wish to compile to JavaScript. ElixirScript will use + those modules to find what other modules and functions it needs to convert to JavaScript. + ElixirScript by default places output in `priv/elixir_script/build`. If you wish to change this, + add an `output` key to your ElixirScript configuration. + + An example configuration for a project is shown below + + ``` elixir + def project do + [ + app: :my_app, + version: "0.1.0", + elixir: "~> 1.0", + deps: deps, + # Add elixir_script as a compilter + compilers: Mix.compilers() ++ [:elixir_script], + # Our elixir_script configuration + elixir_script: [ + # Entry module. Can also be a list of modules + input: MyEntryModule, + # Output path. Either a path to a js file or a directory + output: "priv/elixir_script/build" + ] + ] + end + ``` Available options are: - * `:include_path` - a boolean controlling whether to return just the JavaScript code - or a tuple of the file name and the JavaScript code - * `:core_path` - The es6 import path used to import the elixirscript core. - When using this option, the Elixir.js file is not exported - * `:full_build` - For compile_path, tells the compiler to perform a full build instead of incremental one - * `:output` - option to tell compiler how to output data - * `nil`: Return as list - * `:stdout`: Write to standard out - * `path (string)`: Write to specified path - """ - defmacro __using__(_) do - quote do - import Kernel, except: [ - if: 2, unless: 2, abs: 1, apply: 2, apply: 3, binary_part: 3, hd: 1, - tl: 1, is_atom: 1, is_binary: 1, is_bitstring: 1, is_boolean: 1, is_float: 1, - is_function: 1, is_function: 2, is_integer: 1, is_list: 1, is_number: 1, - is_pid: 1, is_tuple: 1, is_map: 1, is_port: 1, is_reference: 1, length: 1, - map_size: 1, max: 2, min: 2, round: 1, trunc: 1, tuple_size: 1, elem: 2, is_nil: 1, - make_ref: 1, spawn: 1, spawn: 3, spawn_link: 1, spawn_link: 3, spawn_monitor: 1, - spawn_monitor: 3, send: 2, self: 0, match?: 2, to_string: 1, "|>": 2, in: 2, "..": 2, - sigil_r: 2 - ] - import ElixirScript.Kernel - require JS - end - end - - # This is the serialized state of the ElixirScript.State module containing references to the standard library - @lib_path Application.get_env(:elixir_script, :lib_path) - @version Mix.Project.config[:version] - - @doc """ - Compiles the given Elixir code string - """ - @spec compile(binary, Map.t) :: [binary | {binary, binary} | :ok] - def compile(elixir_code, opts \\ %{}) do - elixir_code - |> List.wrap - |> Enum.map(fn(x) -> - x - |> Code.string_to_quoted! - |> compile_quoted(opts) - end) - |> List.flatten - end - - @doc """ - Compiles the given Elixir code in quoted form - """ - @spec compile_quoted(Macro.t, Map.t) :: [binary | {binary, binary} | :ok] - def compile_quoted(quoted, opts \\ %{}) do - - opts = build_compiler_options(opts) - - data = quoted - |> get_modules_from_quoted - |> Enum.map(fn(x) -> %{ast: x, app: :app} end) - - std_lib_quoted = get_quoted_std_lib() - - %{data: std_lib_quoted ++ data} - |> ElixirScript.Passes.Init.execute(opts) - |> ElixirScript.Passes.FindModules.execute(opts) - |> ElixirScript.Passes.FindLoadOnly.execute(opts) - |> ElixirScript.Passes.FindFunctions.execute(opts) - |> ElixirScript.Passes.JavaScriptAST.execute(opts) - |> ElixirScript.Passes.ConsolidateProtocols.execute(opts) - |> ElixirScript.Passes.CreateJSModules.execute(opts) - |> ElixirScript.Passes.JavaScriptCode.execute(opts) - |> ElixirScript.Passes.HandleOutput.execute(opts) - end - - defp get_quoted_std_lib() do - files = [get_std_lib_path(), "**", "*.ex"] - |> Path.join - |> Path.wildcard - - files - |> Enum.map(fn path -> File.read!(path) end) - |> Enum.map(&Code.string_to_quoted!(&1)) - |> Enum.flat_map(&get_modules_from_quoted(&1)) - |> Enum.map(fn(x) -> %{ast: x, app: :elixir} end) - end - - defp get_modules_from_quoted(quoted) do - results = case quoted do - {:__block__, _, list} -> - {modules, not_modules} = Enum.partition(list, - fn - {type, _, _ } when type in [:defprotocol, :defimpl, :defmodule] -> - true - _ -> - false - end) - - temp_module = case not_modules do - [] -> - [] - _ -> - [{:defmodule, [], [{:__aliases__, [], [:ElixirScript, :Temp]}, [do: { :__block__, [], not_modules }]]}] - end - - modules ++ temp_module - - {type, _, _ } = x when type in [:defprotocol, :defimpl, :defmodule] -> - x - x -> - {:defmodule, [], [{:__aliases__, [], [:ElixirScript, :Temp]}, [do: { :__block__, [], [x] }]]} - end - - List.wrap(results) - end - - @doc """ - Compiles the elixir files found at the given path - """ - @spec compile_path(binary | [binary] | map, Map.t) :: [binary | {binary, binary} | :ok] - def compile_path(path, opts \\ %{}) - - def compile_path(path, opts) when is_binary(path) do - compile_path([path], opts) - end - - def compile_path(path, opts) when is_list(path) do - built_opts = build_compiler_options(opts) - - app_name = cond do - !is_nil(built_opts[:app]) -> - built_opts[:app] - Code.ensure_loaded?(Mix) -> - Mix.Project.config()[:app] - true -> - :app - end - - compile_path(Map.put(%{}, app_name, path), opts) - end - - def compile_path(path, opts) do - opts = build_compiler_options(opts) - - deps = path - |> Map.to_list - |> Enum.map(fn {app, path} -> {app, List.wrap(path)} end) - - deps = [{:elixir, List.wrap(get_std_lib_path())}] ++ deps - - result = %{data: deps} - |> ElixirScript.Passes.Init.execute(opts) - |> ElixirScript.Passes.ASTFromFile.execute(opts) - |> ElixirScript.Passes.LoadModules.execute(opts) - |> ElixirScript.Passes.FindModules.execute(opts) - |> ElixirScript.Passes.FindLoadOnly.execute(opts) - |> ElixirScript.Passes.FindFunctions.execute(opts) - |> ElixirScript.Passes.JavaScriptAST.execute(opts) - |> ElixirScript.Passes.ConsolidateProtocols.execute(opts) - |> ElixirScript.Passes.CreateJSModules.execute(opts) - |> ElixirScript.Passes.JavaScriptCode.execute(opts) - |> ElixirScript.Passes.HandleOutput.execute(opts) - - result - end - - defp build_compiler_options(opts) do - default_options = Map.new - |> Map.put(:include_path, false) - |> Map.put(:root, nil) - |> Map.put(:env, __ENV__) - |> Map.put(:import_standard_libs, true) - |> Map.put(:core_path, "Elixir.Bootstrap") - |> Map.put(:full_build, false) - |> Map.put(:output, nil) - |> Map.put(:app, :app) - |> Map.put(:format, :es) - |> Map.put(:js_modules, []) - - options = Map.merge(default_options, opts) - Map.put(options, :module_formatter, get_module_formatter(options[:format])) - end - - defp get_module_formatter(:umd) do - ElixirScript.ModuleSystems.UMD - end - - defp get_module_formatter(:common) do - ElixirScript.ModuleSystems.Common - end - - defp get_module_formatter(_) do - ElixirScript.ModuleSystems.ES - end - - @doc """ - Returns the contents of the bootrstrap js file - """ - def get_bootstrap_js(module_format) do - path = Path.join([operating_path, "build", to_string(module_format), "Elixir.Bootstrap.js"]) - File.read!(path) - end - - #Gets path to js files whether the mix project is available - #or when used as an escript - defp operating_path() do - case @lib_path do - nil -> - if Code.ensure_loaded?(Mix.Project) do - Path.join([Mix.Project.build_path, "lib", "elixir_script", "priv"]) - else - split_path = Path.split(Application.app_dir(:elixirscript)) - replaced_path = List.delete_at(split_path, length(split_path) - 1) - replaced_path = List.delete_at(replaced_path, length(replaced_path) - 1) - Path.join(replaced_path) - end - lib_path -> - lib_path - end - end - - defp get_std_lib_path() do - Path.join([operating_path(), "std_lib"]) - end + * `input` (required): The entry module(s) for your application or library + + * `output`: The path of the generated JavaScript files. (defaults to `priv/elixir_script/build`) + + This should be a directory. If given a file, it will dump JavaScript files into the same directory as the given file path + + * `root`: Optional root for imports of FFI JavaScript modules. Defaults to `.`. If using output directly in a browser, you may want to make it something like `/js` or some uri. + Now run `mix compile` and you should see a JavaScript file named `elixirscript.build.js` in the `priv/elixir_script/build/` directory. ElixirScript outputs JavaScript in the ES Module format. If your browser supports it, you can include the output in a script tag with the type "module" + + ```html + + ``` + + If your browser does not yet support ES modules directly, use a tool such as [webpack](https://webpack.js.org/) or [brunch](http://brunch.io/) to convert it into something that can be used in the browser + + ### JavaScript Interop + + Check out the [JavaScript Interoperability](javascriptinterop.html) documentation + + ### Dependencies + + ElixirScript can use many of the same Hex packages and dependencies that currently exist. + It is also possible to make packages that are specific to ElixirScript. If you decide to + make such a package, please prepend `elixir_script` to the app name. For instance is making + a package for ElixirScript with FFI modules for interacting with React, the name would be + `elixir_script_react`. This is to make sure that other developers know that a package in Hex + is specifically for use with ElixirScript. + + ### Limitations + + ElixirScript does not support `receive` or any of OTP at this time. + """ end diff --git a/lib/elixir_script/beam.ex b/lib/elixir_script/beam.ex new file mode 100644 index 00000000..0a727ef1 --- /dev/null +++ b/lib/elixir_script/beam.ex @@ -0,0 +1,146 @@ +defmodule ElixirScript.Beam do + @moduledoc false + + @doc """ + Takes a module and finds the expanded AST + from the debug info inside the beam file. + For protocols, this will return a list of + all the protocol implementations + """ + @spec debug_info(atom | bitstring) :: {:ok, map} | {:ok, atom, map, list} | {:error, binary} + def debug_info(module) + + # We get debug info from String and then replace + # functions in it with equivalents in ElixirScript.String. + # This is so that we don't include the unicode database + # in our output + def debug_info(String) do + {:ok, info} = do_debug_info(String) + {:ok, ex_string_info} = do_debug_info(ElixirScript.String) + + definitions = replace_definitions(info.definitions, ex_string_info.definitions) + + info = %{info | definitions: definitions} + + {:ok, info} + end + + # Replace some modules with ElixirScript versions + def debug_info(module) when module in [Agent] do + case do_debug_info(Module.concat(ElixirScript, module)) do + {:ok, info} -> + {:ok, Map.put(info, :module, module)} + + e -> + e + end + end + + def debug_info(module) when is_atom(module) do + do_debug_info(module) + end + + def debug_info(beam) when is_bitstring(beam) do + do_debug_info(beam) + end + + defp do_debug_info(module, path \\ nil) + + defp do_debug_info(module, _) when is_atom(module) do + case :code.get_object_code(module) do + {_, beam, beam_path} -> + do_debug_info(beam, beam_path) + + :error -> + {:error, "Unknown module"} + end + end + + defp do_debug_info(beam, beam_path) do + with {:ok, {module, [debug_info: {:debug_info_v1, backend, data}]}} <- + :beam_lib.chunks(beam, [:debug_info]), + {:ok, {^module, attribute_info}} = :beam_lib.chunks(beam, [:attributes]) do + if Keyword.get(attribute_info[:attributes], :protocol) do + get_protocol_implementations(module, beam_path) + else + backend.debug_info(:elixir_v1, module, data, []) + |> process_debug_info(beam_path) + end + else + :error -> + {:error, "Unknown module"} + + {:error, :beam_lib, {:unknown_chunk, "non_existing.beam", :debug_info}} -> + {:error, "Unsupported version of Erlang"} + + {:error, :beam_lib, {:missing_chunk, _, _}} -> + {:error, "Debug info not available"} + + {:error, :beam_lib, {:file_error, "non_existing.beam", :enoent}} -> + {:error, "Debug info not available"} + end + end + + defp process_debug_info({:ok, info}, nil) do + info = Map.put(info, :last_modified, nil) + {:ok, info} + end + + defp process_debug_info({:ok, info}, beam_path) do + info = + case File.stat(beam_path, time: :posix) do + {:ok, file_info} -> + Map.put(info, :last_modified, file_info.mtime) + + _ -> + Map.put(info, :last_modified, nil) + end + + info = Map.put(info, :beam_path, beam_path) + + {:ok, info} + end + + defp process_debug_info(error, _) do + error + end + + defp get_protocol_implementations(module, beam_path) do + {:ok, protocol_module_info} = process_debug_info({:ok, %{}}, beam_path) + + implementations = + module + |> Protocol.extract_impls(:code.get_path()) + |> Enum.map(fn x -> Module.concat([module, x]) end) + |> Enum.map(fn x -> + case debug_info(x) do + {:ok, info} -> + {x, info} + + _ -> + raise ElixirScript.CompileError, + message: "Unable to compile protocol implementation #{inspect(x)}", + severity: :error + end + end) + + {:ok, module, protocol_module_info, implementations} + end + + defp replace_definitions(original_definitions, replacement_definitions) do + Enum.map(original_definitions, fn {{function, arity}, type, _, _} = ast -> + ex_ast = + Enum.find(replacement_definitions, fn {{ex_function, ex_arity}, ex_type, _, _} -> + ex_function == function and ex_arity == arity and ex_type == type + end) + + case ex_ast do + nil -> + ast + + _ -> + ex_ast + end + end) + end +end diff --git a/lib/elixir_script/cli.ex b/lib/elixir_script/cli.ex index 44e03ed1..1eedfc37 100644 --- a/lib/elixir_script/cli.ex +++ b/lib/elixir_script/cli.ex @@ -4,104 +4,82 @@ defmodule ElixirScript.CLI do @app_version Mix.Project.config()[:version] @switches [ - output: :string, elixir: :boolean, - help: :boolean, full_build: :boolean, version: :boolean, - watch: :boolean, format: :string, js_module: [:string, :keep] + output: :string, + help: :boolean, + version: :boolean, + root: :string ] @aliases [ - o: :output, ex: :elixir, h: :help, v: :version, f: :format + o: :output, + h: :help, + v: :version ] - def main(argv) do - argv - |> parse_args - |> process - end - def parse_args(args) do - { options, input, errors } = OptionParser.parse(args, switches: @switches, aliases: @aliases) + {options, input, errors} = OptionParser.parse(args, switches: @switches, aliases: @aliases) cond do length(errors) > 0 -> :help + Keyword.get(options, :help, false) -> :help + Keyword.get(options, :version, false) -> :version + length(input) == 0 -> :help + true -> - { input, options } + {input, options} end - end - def help_message() do - """ - usage: elixirscript [options] - path to elixir files or - the elixir code string if passed the -ex flag - - options: - --js-module [:] A js module used in your code. ex: React:react - Multiple can be defined - -f --format [format] module format of output. options: es (default), common, umd - -o --output [path] places output at the given path - -ex --elixir read input as elixir code string - --full-build informs the compiler to do a full build instead of an incremental one - -v --version the current version number - -h --help this message - """ + defp help_message do + """ + usage: elixirscript [options] + the entry module of your application + the path to .ex(s) files to compile + + options: + -o --output [path] places output at the given path. + Can be a directory or filename. + -v --version the current version number + -h --help this message + --root The root import path for FFI imports + """ end def process(:help) do - IO.write help_message + IO.write(help_message()) end def process(:version) do - IO.write @app_version + IO.write(@app_version) end - def process({ input, options }) do + def process({input, options}) do if options_contains_unknown_values(options) do - process(:help) + process(:help) else - do_process(input, options) + do_process(input, options) end end - def do_process(input, options) do - {watch, options} = Keyword.pop(options, :watch, false) - - js_modules = Keyword.get_values(options, :js_module) - |> build_js_modules - - compile_opts = %{ - include_path: true, - core_path: Keyword.get(options, :core_path, "Elixir.Bootstrap"), - full_build: Keyword.get(options, :full_build, false), + defp do_process(input, options) do + compile_opts = [ output: Keyword.get(options, :output, :stdout), - format: String.to_atom(Keyword.get(options, :format, "es")), - js_modules: js_modules - } + root: Keyword.get(options, :root, ".") + ] - case options[:elixir] do - true -> - ElixirScript.compile(input, compile_opts) - _ -> - input = handle_input(input) - ElixirScript.compile_path(input, compile_opts) - - if watch do - ElixirScript.Watcher.start_link(input, compile_opts) - :timer.sleep :infinity - end - end + input = handle_input(input) + ElixirScript.Compiler.compile(input, compile_opts) end defp options_contains_unknown_values(options) do - Enum.any?(options, fn({key, _value}) -> + Enum.any?(options, fn {key, _value} -> if key in Keyword.keys(@switches) do false else @@ -111,30 +89,9 @@ defmodule ElixirScript.CLI do end defp handle_input(input) do - input = input - |> Enum.map(fn(x) -> String.split(x, [" ", ","], trim: true) end) - |> List.flatten - end - - defp build_js_modules(values) do - values - |> Enum.map(fn x -> - [identifier, path] = String.split(x,":", trim: true) - { format_identifier(identifier), format_path(path) } - end) - end - - defp format_identifier(id) do - id - |> String.split(".") - |> Module.concat - end - - - defp format_path(path) do - path - |> String.replace("\"", "") - |> String.replace("`", "") - |> String.replace("'", "") + input + |> Enum.map(fn x -> String.split(x, [" ", ","], trim: true) end) + |> List.flatten() + |> Enum.map(fn x -> Module.concat([x]) end) end end diff --git a/lib/elixir_script/compile_error.ex b/lib/elixir_script/compile_error.ex new file mode 100644 index 00000000..d670552b --- /dev/null +++ b/lib/elixir_script/compile_error.ex @@ -0,0 +1,3 @@ +defmodule ElixirScript.CompileError do + defexception [:message, :severity] +end diff --git a/lib/elixir_script/compiler.ex b/lib/elixir_script/compiler.ex new file mode 100644 index 00000000..9e36d5a8 --- /dev/null +++ b/lib/elixir_script/compiler.ex @@ -0,0 +1,186 @@ +defmodule ElixirScript.Compiler do + @moduledoc """ + The entry point for the ElixirScript compilation process. + Takes the given module(s) and compiles them and all modules + and functions they use into JavaScript. + + Will also take a path to Elixir files + """ + + @doc """ + Takes either a module name, list of module names, or a path as + the entry point(s) of an application/library. From there + it will determine which modules and functions are needed + to be compiled. + + Available options are: + * `output`: The path of the generated JavaScript file. + + If output is `nil`, then generated code is sent to standard out + + If output is a path, the generated code placed in that path. + If path ends in `.js` then that will be the name of the file. + If a directory is given, file will be named `elixirscript.build.js` + + * `root`: Optional root for imports of FFI JavaScript modules. Defaults to `.`. + """ + alias ElixirScript.{ + State, + Translate, + FindUsedModules, + FindUsedFunctions, + Output + } + + alias ElixirScript.ModuleSystems.ES + alias Kernel.ParallelCompiler + + @type compiler_input :: + atom + | [atom] + | binary + + @spec compile(compiler_input, []) :: map + def compile(path, opts \\ []) + + def compile(path, opts) when is_binary(path) do + opts = build_compiler_options(opts) + {:ok, pid} = State.start_link(opts) + + path = + if String.ends_with?(path, [".ex", ".exs"]) do + path + else + Path.join([path, "**", "*.{ex,exs}"]) + end + + files = Path.wildcard(path) + + ParallelCompiler.compile(files, each_module: &on_module_compile(pid, &1, &2, &3)) + + entry_modules = + pid + |> State.get_in_memory_modules() + |> Keyword.keys() + + do_compile(entry_modules, pid, opts) + end + + def compile(entry_modules, opts) do + opts = build_compiler_options(opts) + {:ok, pid} = State.start_link(opts) + + entry_modules = List.wrap(entry_modules) + + do_compile(entry_modules, pid, opts) + end + + defp do_compile(entry_modules, pid, opts) do + FindUsedModules.execute(entry_modules, pid) + + if opts.remove_unused_functions do + FindUsedFunctions.execute(entry_modules, pid) + end + + modules = State.list_modules(pid) + Translate.execute(modules, pid) + + modules = State.list_modules(pid) + result = Output.execute(modules, pid, opts) + + State.stop(pid) + + transform_output(modules, result, opts) + end + + defp build_compiler_options(opts) do + remove_used_functions? = Keyword.get(opts, :remove_unused_functions, true) + + default_options = + Map.new() + |> Map.put(:output, Keyword.get(opts, :output)) + |> Map.put(:format, :es) + |> Map.put(:root, Keyword.get(opts, :root, ".")) + |> Map.put(:remove_unused_functions, remove_used_functions?) + + options = default_options + Map.put(options, :module_formatter, ES) + end + + defp on_module_compile(pid, _file, module, beam) do + State.put_in_memory_module(pid, module, beam) + end + + defp transform_output(modules, compiled_js, opts) do + output_path = + cond do + opts.output == nil or opts.output == :stdout -> + "" + + File.dir?(opts.output) -> + opts.output + + true -> + Path.dirname(opts.output) + end + + data = %{ + ElixirScript.Core => %{ + references: [], + last_modified: nil, + beam_path: nil, + source: nil, + js_path: Path.join(output_path, "ElixirScript.Core.js"), + diagnostics: [], + js_code: nil, + type: :ffi + } + } + + Enum.reduce(modules, data, fn {module, info}, current_data -> + diagnostics = + Map.get(info, :diagnostics, []) + |> Enum.map(fn x -> + Map.put(x, :file, Map.get(info, :file)) + end) + + info = %{ + references: Map.get(info, :used_modules, []), + last_modified: Map.get(info, :last_modified, nil), + beam_path: Map.get(info, :beam_path), + source: Map.get(info, :file), + js_path: Path.join(output_path, "#{module}.js"), + diagnostics: diagnostics + } + + info = + case Keyword.get(compiled_js, module) do + [js_input_path, js_output_path] -> + last_modified = + case File.stat(js_input_path, time: :posix) do + {:ok, file_info} -> + file_info.mtime + + _ -> + nil + end + + info + |> Map.put(:last_modified, last_modified) + |> Map.put(:beam_path, nil) + |> Map.put(:source, js_input_path) + |> Map.put(:js_path, js_output_path) + |> Map.put(:js_code, nil) + |> Map.put(:type, :ffi) + + js_code -> + info + |> Map.put(:js_path, Path.join(output_path, "#{module}.js")) + |> Map.put(:js_code, js_code) + |> Map.put(:type, :module) + end + + Map.put(current_data, module, info) + end) + end +end diff --git a/lib/elixir_script/ffi.ex b/lib/elixir_script/ffi.ex new file mode 100644 index 00000000..71249fe0 --- /dev/null +++ b/lib/elixir_script/ffi.ex @@ -0,0 +1,107 @@ +defmodule ElixirScript.FFI do + @moduledoc """ + The Foreign Function Interface (FFI) for interacting with JavaScript + + To define a foreign module, make a new module and add `use ElixirScript.FFI` to it. + To define external functions, use the `defexternal` macro. + + Here is an example of a foreign module for a JSON module + + ```elixir + defmodule MyApp.JSON do + use ElixirScript.FFI + + defexternal stringify(map) + defexternal parse(string) + end + ``` + + Foreign modules map to JavaScript files that export functions defined with the `defexternal` macro. + ElixirScript expects JavaScript modules to be in the `priv/elixir_script` directory. + These modules are copied to the output directory upon compilation. + + For our example, a JavaScript file must be placed in the `priv/elixir_script` folder. + In our example, it could either be `priv/elixir_script/my_app/json.js` or + `priv/elixir_script/my_app.json.js`. ElixirScript will look for either path + + It looks like this + ```javascript + export default { + stringify: JSON.stringify, + parse: JSON.parse + } + ``` + + `ElixirScript.FFI` takes the following options + * `global`: If the module is defined in the global state or not. If this is set to `true`, + nothing is imported and instead ElixirScript will use the name of the module to call a module and + function in the global scope. + * `name`: Only applicable with `global` is set to `true`. This will use the name defined here + instead of the module name for calling modules and functions in the global scope + + An example using the global option to reference the JSON module in browsers + + ```elixir + defmodule JSON do + use ElixirScript.FFI, global: true + + defexternal stringify(map) + defexternal parse(string) + end + ``` + + The calls above are translated to calls to the `JSON` module in the global scope + + An example using global and name options + + ```elixir + defmodule Console do + use ElixirScript.FFI, global: true, name: :console + + defexternal log(term) + end + ``` + + With the above, calls in ElixirScript to `Console.log` will translate to `console.log` in JavaScript + """ + + defmacro __using__(opts) do + quote do + import ElixirScript.FFI + Module.register_attribute __MODULE__, :__foreign_info__, persist: true + @__foreign_info__ %{ + path: Macro.underscore(__MODULE__), + name: unquote(Keyword.get(opts, :name, nil)), + global: unquote(Keyword.get(opts, :global, false)) + } + end + end + + @doc """ + Defines a JavaScript function to be called from Elixir modules + + To define an external function, pass the name and arguments to `defexternal` + + ```elixir + defexternal my_js_function(arg1, arg2, arg3) + ``` + """ + defmacro defexternal({name, _, args}) do + args = Enum.map(args, fn + {:\\, meta0, [{name, meta, atom}, value]} -> + name = String.to_atom("_" <> Atom.to_string(name)) + {:\\, meta0, [{name, meta, atom}, value]} + + {name, meta, atom} -> + name = String.to_atom("_" <> Atom.to_string(name)) + {name, meta, atom} + + other -> + other + end) + + quote do + def unquote(name)(unquote_splicing(args)), do: nil + end + end +end diff --git a/lib/elixir_script/lib/agent.ex b/lib/elixir_script/lib/agent.ex new file mode 100644 index 00000000..4048350f --- /dev/null +++ b/lib/elixir_script/lib/agent.ex @@ -0,0 +1,49 @@ +defmodule ElixirScript.Agent do + @moduledoc false + + def start(fun, options \\ []) do + name = if Keyword.has_key?(options, :name) do + Keyword.get(options, :name) + else + nil + end + + pid = ElixirScript.Core.Store.create(fun.(), name) + { :ok, pid } + end + + def start_link(fun, options \\ []) do + name = if Keyword.has_key?(options, :name) do + Keyword.get(options, :name) + else + nil + end + + pid = ElixirScript.Core.Store.create(fun.(), name) + { :ok, pid } + end + + def stop(agent) do + ElixirScript.Core.Store.remove(agent) + :ok + end + + def update(agent, fun) do + current_state = ElixirScript.Core.Store.read(agent) + ElixirScript.Core.Store.update(agent, fun.(current_state)) + :ok + end + + def get(agent, fun) do + current_state = ElixirScript.Core.Store.read(agent) + fun.(current_state) + end + + def get_and_update(agent, fun) do + current_state = ElixirScript.Core.Store.read(agent) + {val, new_state} = fun.(current_state) + ElixirScript.Core.Store.update(agent, new_state) + val + end + +end diff --git a/lib/elixir_script/lib/functions.ex b/lib/elixir_script/lib/functions.ex new file mode 100644 index 00000000..acc12525 --- /dev/null +++ b/lib/elixir_script/lib/functions.ex @@ -0,0 +1,8 @@ +defmodule ElixirScript.Core.Functions do + @moduledoc false + use ElixirScript.FFI, global: true + + defexternal split_at(value, position) + + defexternal graphemes(str) +end diff --git a/lib/elixir_script/lib/js.ex b/lib/elixir_script/lib/js.ex new file mode 100644 index 00000000..a8713880 --- /dev/null +++ b/lib/elixir_script/lib/js.ex @@ -0,0 +1,94 @@ +defmodule ElixirScript.JS do + @moduledoc """ + This module defines macros and functions which implement + JavaScript functionality that may not translate easily to + Elixir. For instance, creating a new object + """ + + use ElixirScript.FFI, global: true + + @doc """ + Creates new JavaScript objects. + + ```elixir + ElixirScript.JS.new User, ["first_name", "last_name"] + ``` + """ + defexternal new(module, params) + + @doc """ + Returns the type of the given value + """ + defexternal typeof(value) + + @doc """ + Determines if value is an instance of type. + """ + defexternal instanceof(value, type) + + @doc """ + Throws the term given + """ + defexternal throw(term) + + @doc """ + Creates a breakpoint for JavaScript debuggers to stop at + """ + defexternal debugger() + + @doc """ + The current JavaScript context + """ + defexternal this() + + @doc """ + Mutates an existing JavaScript object. + + ```elixir + ElixirScript.JS.mutate elem, "width", 100 + ``` + """ + defexternal mutate(object, key, value) + + @doc """ + Takes the given map and returns an object + Throws an error if any key is not a + number, binary, or atom + + ```elixir + ElixirScript.JS.map_to_object(%{my: "map"}) + ``` + """ + defexternal map_to_object(map) + + @doc """ + Takes the given map and returns an object + Throws an error if any key is not a + number, binary, or atom + + ```elixir + ElixirScript.JS.map_to_object(%{my: "map"}, keys: :string) + ``` + """ + defexternal map_to_object(map, options) + + @doc """ + Takes the given object and returns a map + Options include [{:keys, :atom}, {:recurse_array, true}] + + ```elixir + ElixirScript.JS.object_to_object({my: "object"}) + ``` + """ + defexternal object_to_map(object) + + @doc """ + Takes the given object and returns a map + Options include [{:keys, :atom}, {:recurse_array, true}] + + ```elixir + ElixirScript.JS.object_to_object({my: "map"}, keys: :atom) + ``` + """ + defexternal object_to_map(object, options) +end diff --git a/lib/elixir_script/lib/store.ex b/lib/elixir_script/lib/store.ex new file mode 100644 index 00000000..9e98bce3 --- /dev/null +++ b/lib/elixir_script/lib/store.ex @@ -0,0 +1,12 @@ +defmodule ElixirScript.Core.Store do + @moduledoc false + use ElixirScript.FFI, global: true + + defexternal create(value, name \\ nil) + + defexternal update(key, value) + + defexternal read(key) + + defexternal remove(key) +end diff --git a/priv/std_lib/string.ex b/lib/elixir_script/lib/string.ex similarity index 88% rename from priv/std_lib/string.ex rename to lib/elixir_script/lib/string.ex index 2997ab63..f5227fc5 100644 --- a/priv/std_lib/string.ex +++ b/lib/elixir_script/lib/string.ex @@ -3,11 +3,11 @@ defmodule ElixirScript.String do import Kernel, except: [length: 1] def to_atom(str) do - Symbol.for(str) + :erlang.binary_to_atom(str, :utf8) end def to_existing_atom(str) do - Symbol.for(str) + :erlang.binary_to_existing_atom(str, :utf8) end def to_char_list(str) do @@ -15,15 +15,15 @@ defmodule ElixirScript.String do end def to_float(str) do - Bootstrap.Core.get_global().parseFloat(str) + :erlang.binary_to_float(str) end def to_integer(str) do - Bootstrap.Core.get_global().parseInt(str, 10) + :erlang.binary_to_integer(str) end def to_integer(str, base) do - Bootstrap.Core.get_global().parseInt(str, base) + :erlang.binary_to_integer(str, base) end def upcase(str) do @@ -68,7 +68,6 @@ defmodule ElixirScript.String do end) end - def next_grapheme(nil), do: nil def next_grapheme(""), do: nil @@ -87,11 +86,11 @@ defmodule ElixirScript.String do end def graphemes(str) do - str.split('') + ElixirScript.Core.Functions.graphemes(str) end def length(str) do - str.length() + graphemes(str).length() end def match?(str, regex) do @@ -137,7 +136,6 @@ defmodule ElixirScript.String do end end - def ends_with?(str, suffix) when is_binary(suffix) do str.endsWith(suffix) end @@ -163,7 +161,6 @@ defmodule ElixirScript.String do str.repeat(n) end - def contains?(str, s) when is_binary(s) do str.indexOf(s) > -1 end @@ -185,7 +182,6 @@ defmodule ElixirScript.String do end end - def codepoints(str) do do_codepoints(str, []) end @@ -198,7 +194,11 @@ defmodule ElixirScript.String do do_codepoints(str.substr(1), codepoint_list ++ [first(str).codePointAt(0)]) end - def valid_character?(codepoint) do - Bootstrap.Core.Functions.is_valid_character(codepoint) + def valid?(str) do + is_binary(str) + end + + def split_at(value, position) do + ElixirScript.Core.Functions.split_at(value, position) end end diff --git a/lib/elixir_script/manifest.ex b/lib/elixir_script/manifest.ex new file mode 100644 index 00000000..a7974cb1 --- /dev/null +++ b/lib/elixir_script/manifest.ex @@ -0,0 +1,28 @@ +defmodule ElixirScript.Manifest do + @moduledoc false + + @spec read_manifest(binary) :: nil + def read_manifest(manifest_path) do + if File.exists?(manifest_path) do + manifest_path + |> File.read!() + |> :erlang.binary_to_term() + else + %{} + end + end + + @spec write_manifest(binary, map) :: :ok + def write_manifest(manifest_path, modules) do + data = + Enum.reduce(modules, %{}, fn {module, info}, current_data -> + Map.put(current_data, module, Map.drop(info, [:js_code])) + end) + + data = :erlang.term_to_binary(data, [:compressed]) + File.mkdir_p!(Path.dirname(manifest_path)) + File.write!(manifest_path, data) + + :ok + end +end diff --git a/lib/elixir_script/module_systems/common.ex b/lib/elixir_script/module_systems/common.ex deleted file mode 100644 index c3caf08a..00000000 --- a/lib/elixir_script/module_systems/common.ex +++ /dev/null @@ -1,54 +0,0 @@ -defmodule ElixirScript.ModuleSystems.Common do - @moduledoc false - alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator - alias ElixirScript.Translator.State - alias ElixirScript.Translator.Utils - - def build(imports, js_imports, body, exports) do - module_imports = Enum.map(imports, fn {module, path} -> import_module(module, path) end) - - imports = js_imports - |> Enum.map(fn - {module, path} -> import_module(module, path) - {module, path, _} -> import_module(module, path) - end) - - imports = Enum.uniq(imports ++ module_imports) - - export = if is_nil(exports), do: [], else: [export_module(exports)] - imports ++ body ++ export - end - - defp import_module(module_name, from) do - js_module_name = ElixirScript.Translator.Identifier.make_namespace_members(module_name) - do_import_module(js_module_name, from) - end - - defp do_import_module(ref, file_path) do - - ref_declarator = JS.variable_declarator( - ref, - JS.call_expression( - JS.identifier("require"), - [JS.literal(file_path)] - ) - ) - - JS.variable_declaration([ref_declarator], :const) - - end - - defp export_module(exported_object) do - JS.assignment_expression( - :=, - JS.member_expression( - JS.identifier("module"), - JS.identifier("exports") - ), - exported_object - ) - end - - -end diff --git a/lib/elixir_script/module_systems/es.ex b/lib/elixir_script/module_systems/es.ex index 4423d064..c5c9ef9d 100644 --- a/lib/elixir_script/module_systems/es.ex +++ b/lib/elixir_script/module_systems/es.ex @@ -1,39 +1,34 @@ defmodule ElixirScript.ModuleSystems.ES do @moduledoc false alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator - alias ElixirScript.Translator.State - alias ElixirScript.Translator.Utils - - def build(imports, js_imports, body, exports) do - module_imports = Enum.map(imports, fn {module, path} -> import_module(module, path) end) + def build(js_imports, body, exports) do imports = js_imports + |> Enum.filter(fn + {_module, _name, nil, _import_path} -> false + _ -> true + end) |> Enum.map(fn - {module, path} -> import_module(module, path) - {module, path, default: true} -> import_module(module, path) - {module, path, default: false} -> import_namespace_module(module, path) + {_module, name, _path, import_path} -> import_module(name, import_path) end) - imports = Enum.uniq(imports ++ module_imports) - export = if is_nil(exports), do: [], else: [export_module(exports)] imports ++ body ++ export end - defp import_namespace_module(module_name, from) do - js_module_name = ElixirScript.Translator.Identifier.make_namespace_members(module_name) - - import_specifier = JS.import_namespace_specifier( - js_module_name, - js_module_name - ) + def build_imports(js_imports) do + js_imports + |> Enum.map(fn + {_module, name, _path, import_path} -> import_module(name, import_path) + end) + end - do_import_module([import_specifier], from) + def build_export(exports) do + if is_nil(exports), do: [], else: [export_module(exports)] end defp import_module(import_name, from) do - js_module_name = ElixirScript.Translator.Identifier.make_namespace_members(import_name) + js_module_name = JS.identifier(import_name) import_specifier = JS.import_default_specifier( js_module_name diff --git a/lib/elixir_script/module_systems/namespace.ex b/lib/elixir_script/module_systems/namespace.ex index ba2f0724..c98eee87 100644 --- a/lib/elixir_script/module_systems/namespace.ex +++ b/lib/elixir_script/module_systems/namespace.ex @@ -1,12 +1,10 @@ defmodule ElixirScript.ModuleSystems.Namespace do @moduledoc false alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator - alias ElixirScript.Translator.State - alias ElixirScript.Translator.Utils - alias ElixirScript.Translator.Identifier + alias ElixirScript.Translate.Helpers + alias ElixirScript.Translate.Identifier - def build(module_name, body, exports, env) do + def build(module_name, body, exports) do List.wrap(make_namespace_body(module_name, body, exports)) end @@ -15,23 +13,9 @@ defmodule ElixirScript.ModuleSystems.Namespace do Identifier.make_namespace_members(members) end - def import_module(module_name) do - name = ["Elixir" | Module.split(module_name) ] |> Enum.join("$") - - declarator = JS.variable_declarator( - JS.identifier(name), - JS.call_expression( - module_name_function_call(module_name, "__load"), - [JS.identifier("Elixir")] - ) - ) - - JS.variable_declaration([declarator], :const) - end - defp build_namespace() do JS.member_expression( - JS.identifier("Bootstrap"), + JS.identifier("ElixirScript"), JS.member_expression( JS.identifier(:Core), JS.member_expression( @@ -39,53 +23,43 @@ defmodule ElixirScript.ModuleSystems.Namespace do JS.identifier(:build_namespace) ) ) - ) + ) end defp make_namespace_body(module_name, body, exports) do values = module_name_function_call(module_name, "__exports") - _if = JS.if_statement( + js_if = JS.if_statement( values, JS.return_statement(values) ) exports = if is_nil(exports) do JS.object_expression([]) - else + else exports end - declarator = JS.variable_declarator( - JS.identifier("__exports"), - exports - ) - - declaration = JS.variable_declaration([declarator], :const) + declaration = Helpers.declare("__exports", exports) - assign = JS.assignment_expression( - :=, - values, - JS.identifier("__exports") - ) + assign = Helpers.assign(values, JS.identifier("__exports")) - exports = [JS.return_statement(JS.identifier("__exports"))] + exports = [JS.return_statement(JS.identifier("__exports"))] make = JS.member_expression( - JS.call_expression( + Helpers.call( build_namespace(), - [JS.identifier("Elixir"), JS.literal(Utils.name_to_js_file_name(module_name))] + [JS.identifier("Elixir"), JS.literal(Enum.join(["Elixir"] ++ Module.split(module_name), "."))] ), JS.identifier("__load") ) - func_body = JS.block_statement([_if] ++ body ++ [declaration, assign] ++ exports) + func_body = JS.block_statement([js_if] ++ body ++ [declaration, assign] ++ exports) - func = JS.function_expression([JS.identifier("Elixir")], [], func_body) - JS.assignment_expression( - :=, + func = Helpers.function([JS.identifier("Elixir")], func_body) + Helpers.assign( make, func ) end -end \ No newline at end of file +end diff --git a/lib/elixir_script/module_systems/umd.ex b/lib/elixir_script/module_systems/umd.ex deleted file mode 100644 index 5a94cb5c..00000000 --- a/lib/elixir_script/module_systems/umd.ex +++ /dev/null @@ -1,108 +0,0 @@ -defmodule ElixirScript.ModuleSystems.UMD do - @moduledoc false - alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator - alias ElixirScript.Translator.State - alias ElixirScript.Translator.Utils - - def build(imports, js_imports, body, exports) do - module_imports = Enum.map(imports, fn {module, path} -> import_module(module, path) end) - - imports = js_imports - |> Enum.map(fn - {module, path} -> import_module(module, path) - {module, path, _} -> import_module(module, path) - end) - - imports = Enum.uniq(imports ++ module_imports) - - export = export_module(exports) - List.wrap(make_umd(imports, body, export)) - end - - defp import_module(module_name, from) do - js_module_name = ElixirScript.Translator.Identifier.make_namespace_members(module_name) - {js_module_name, JS.literal(from)} - end - - defp export_module(exported_object) do - exported_object - end - - defp make_umd(imports, body, exports) do - import_paths = Enum.map(imports, fn({_, path}) -> path end) - import_identifiers = Enum.map(imports, fn({id, _}) -> id end) - exports = if is_nil(exports), do: [], else: [JS.return_statement(exports)] - - JS.expression_statement( - JS.call_expression( - JS.function_expression([JS.identifier("root"), JS.identifier("factory")], [], JS.block_statement([ - JS.if_statement( - JS.logical_expression( - :&&, - JS.binary_expression( - :===, - JS.unary_expression(:typeof, true, JS.identifier("define")), - JS.literal("function") - ), - JS.member_expression( - JS.identifier("define"), - JS.identifier("amd") - ) - ), - JS.block_statement([ - JS.call_expression( - JS.identifier("define"), - [JS.array_expression(import_paths), JS.identifier("factory")] - ) - ]), - JS.if_statement( - JS.binary_expression( - :===, - JS.unary_expression(:typeof, true, JS.identifier("exports")), - JS.literal("object") - ), - JS.block_statement([ - JS.assignment_expression( - :=, - JS.member_expression( - JS.identifier("module"), - JS.identifier("exports") - ), - JS.call_expression( - JS.identifier("factory"), - Enum.map(import_paths, fn x -> - JS.call_expression( - JS.identifier("require"), - [x] - ) - end) - ) - ) - ]), - JS.block_statement([ - JS.assignment_expression( - :=, - JS.member_expression( - JS.identifier("root"), - JS.identifier("Elixir") - ), - JS.call_expression( - JS.identifier("factory"), - Enum.map(import_identifiers, fn x -> - JS.member_expression( - JS.identifier("root"), - x - ) - end) - ) - ) - ]) - ) - ) - ])), - [JS.this_expression(), JS.function_expression(import_identifiers, [], JS.block_statement(body ++ exports))] - ) - ) - end -end \ No newline at end of file diff --git a/lib/elixir_script/passes/ast_from_file.ex b/lib/elixir_script/passes/ast_from_file.ex deleted file mode 100644 index 271ccdec..00000000 --- a/lib/elixir_script/passes/ast_from_file.ex +++ /dev/null @@ -1,26 +0,0 @@ -defmodule ElixirScript.Passes.ASTFromFile do - @moduledoc false - - def execute(compiler_data, opts) do - data = Enum.reduce(compiler_data.data, [], fn({dep, paths}, list) -> - - file_paths = paths - |> Enum.flat_map(fn(path) -> Path.join([path, "**", "*.{ex,exs,exjs}"]) |> Path.wildcard end) - |> Enum.reduce([], fn(path, list) -> - quoted = path - |> File.read! - |> Code.string_to_quoted! - - stat = File.stat!(path) - - list ++ [%{path: path, app: dep, stat: stat, ast: quoted}] - end) - - - list ++ file_paths - end) - - Map.put(compiler_data, :data, data) - end - -end diff --git a/lib/elixir_script/passes/consolidate_protocols.ex b/lib/elixir_script/passes/consolidate_protocols.ex deleted file mode 100644 index f0c40d2b..00000000 --- a/lib/elixir_script/passes/consolidate_protocols.ex +++ /dev/null @@ -1,103 +0,0 @@ -defmodule ElixirScript.Passes.ConsolidateProtocols do - @moduledoc false - alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator.Utils - alias ElixirScript.Translator.State - alias ElixirScript.Translator.Identifier - require Logger - - def execute(compiler_data, opts) do - State.set_module_data(compiler_data.state, compiler_data.data) - data = State.get_module_data(compiler_data.state) - - only_protocols_and_impls = Enum.filter(data, fn - ({_, %{type: :module}}) -> - false - ({_, %{type: :consolidated}}) -> - false - _ -> - true - end) - - grouped = group_protocol_data(only_protocols_and_impls) - consolidated_protocols = update_protocols(grouped, opts) - - data = Enum.reduce(consolidated_protocols, data, fn({ key, value }, d) -> Keyword.put(d, key, value) end) - - %{ compiler_data | data: data } - end - - - defp group_protocol_data(data) do - Enum.reduce(data, %{}, fn({module_name, module_data} = dat, state) -> - if module_data.type == :protocol do - existing = Map.get(state, module_name, %{}) - existing = Map.put(existing, :protocol, dat) - Map.put(state, module_name, existing) - else - existing = Map.get(state, module_data.implements, %{}) - existing_protocol_data = Map.get(existing, :impls, []) - existing_protocol_data = existing_protocol_data ++ [dat] - existing = Map.put(existing, :impls, existing_protocol_data) - Map.put(state, module_data.implements, existing) - end - end) - end - - defp update_protocols(grouped_protocol_data, opts) do - Enum.map(grouped_protocol_data, fn - ({ protocol_name, %{ protocol: protocol, impls: impls } }) -> - make_defimpl(protocol_name, protocol, Enum.uniq(impls), opts) - - ({ protocol_name, %{ protocol: protocol } }) -> - make_defimpl(protocol_name, protocol, [], opts) - end) - end - - defp make_defimpl(name, {_, protocol}, implementations, compiler_opts) do - declarator = JS.variable_declarator( - JS.identifier("impls"), - JS.array_expression([]) - ) - - declaration = JS.variable_declaration([declarator], :let) - - default = JS.export_default_declaration(JS.identifier("impls")) - - protocol_name = Atom.to_string(name) - - app_name = protocol.app - - body = Enum.map(implementations, fn({_, impl_data}) -> - x = Utils.quoted_to_name(impl_data.for) - members = ["Elixir"] ++ Module.split(name) ++ ["DefImpl", "Elixir"] ++ Module.split(x) ++ ["__load"] - ast = JS.call_expression( - Identifier.make_namespace_members(members), - [JS.identifier("Elixir")] - ) - - - JS.call_expression( - JS.member_expression( - JS.identifier("impls"), - JS.identifier("push") - ), - [ast] - ) - end) - - module_name = String.to_atom(protocol_name <> ".DefImpl") - module_data = %{ - name: name, - module: String.to_atom(protocol_name <> ".DefImpl"), - body: [declaration] ++ body, - exports: JS.identifier("impls"), - app: app_name, - type: :consolidated, - protocol: name - } - - {module_name, module_data} - end - -end diff --git a/lib/elixir_script/passes/create_js_modules.ex b/lib/elixir_script/passes/create_js_modules.ex deleted file mode 100644 index 0986ae7c..00000000 --- a/lib/elixir_script/passes/create_js_modules.ex +++ /dev/null @@ -1,105 +0,0 @@ -defmodule ElixirScript.Passes.CreateJSModules do - @moduledoc false - alias ElixirScript.Translator.Utils - alias ESTree.Tools.Builder, as: JS - - def execute(compiler_data, opts) do - namespace_modules = Enum.reduce(compiler_data.data, [], fn - ({_, %{load_only: true} = module_data}, acc) -> - acc - - ({module_name, module_data}, acc) -> - if module_data.app == :elixir && opts.import_standard_libs == false do - acc - else - body = generate_namespace_module( - module_data.type, - module_name, - Map.get(module_data, :javascript_module, module_data), - opts, - compiler_data.state - ) - - acc ++ List.wrap(body) - end - end) - - compiled = compile(namespace_modules, opts) - Map.put(compiler_data, :compiled, compiled) - end - - defp generate_namespace_module(:consolidated, module_name, js_module, opts, state) do - env = ElixirScript.Translator.LexicalScope.module_scope( - js_module.name, - Utils.name_to_js_file_name(js_module.name) <> ".js", - opts.env, - state, - opts) - - body = ElixirScript.ModuleSystems.Namespace.build( - module_name, - js_module.body, - js_module.exports, - env - ) - - body - end - - defp generate_namespace_module(_, module_name, js_module, _, _) do - body = ElixirScript.ModuleSystems.Namespace.build( - module_name, - js_module.body, - js_module.exports, - js_module.env - ) - - body - end - - defp compile(body, opts) do - declarator = JS.variable_declarator( - JS.identifier("Elixir"), - JS.object_expression([]) - ) - - elixir = JS.variable_declaration([declarator], :const) - - start = JS.assignment_expression( - :=, - JS.member_expression( - JS.identifier("Elixir"), - JS.identifier("start") - ), - JS.function_expression( - [JS.identifier(:app), JS.identifier(:args)], - [], - JS.block_statement([ - JS.call_expression( - JS.member_expression( - JS.call_expression( - JS.member_expression( - JS.identifier(:app), - JS.identifier("__load") - ), - [JS.identifier("Elixir")] - ), - JS.identifier("start") - ), - [ElixirScript.Translator.Primitive.make_atom(:normal), JS.identifier(:args)] - ) - ]) - ) - ) - - ast = opts.module_formatter.build( - [], - opts.js_modules, - [elixir, start] ++ body, - JS.identifier("Elixir") - ) - - ast - end - -end diff --git a/lib/elixir_script/passes/find_functions.ex b/lib/elixir_script/passes/find_functions.ex deleted file mode 100644 index f78e2d38..00000000 --- a/lib/elixir_script/passes/find_functions.ex +++ /dev/null @@ -1,92 +0,0 @@ -defmodule ElixirScript.Passes.FindFunctions do - @moduledoc false - @function_types [:def, :defp, :defgen, :defgenp, :defmacro, :defmacrop] - - def execute(data, _) do - new_data = Enum.map(data.data, fn { module_name, module_data } -> - - %{ - def: functions, - defp: private_functions, - defgen: generators, - defgenp: private_generators, - defmacro: macros, - defmacrop: private_macros, - defdelegate: delegates - } = get_functions_from_module(module_data.ast) - - module_data = Map.put(module_data, :functions, functions ++ generators ++ delegates) - |> Map.put(:private_functions, private_functions ++ private_generators) - |> Map.put(:macros, macros) - |> Map.put(:private_macros, private_macros) - - {module_name, module_data} - end) - - %{data | data: new_data} - end - - defp get_functions_from_module({:__block__, _, list}) do - Enum.reduce(list, new_function_map(), fn - ({type, _, [{:when, _, [{name, _, params} | _guards] }, _] }, state) when type in @function_types and is_atom(params) -> - arity = 0 - add_function_to_map(state, type, name, arity) - - ({type, _, [{:when, _, [{name, _, params} | _guards] }, _] }, state) when type in @function_types -> - arity = if is_nil(params), do: 0, else: length(params) - add_function_to_map(state, type, name, arity) - - ({type, _, [{name, _, params}, _]}, state) when type in @function_types and is_atom(params) -> - arity = 0 - add_function_to_map(state, type, name, arity) - - ({type, _, [{name, _, params}, _]}, state) when type in @function_types -> - arity = if is_nil(params), do: 0, else: length(params) - add_function_to_map(state, type, name, arity) - - ({type, _, [{name, _, params}]}, state) when is_atom(params) and type in @function_types -> - arity = 0 - add_function_to_map(state, type, name, arity) - - ({type, _, [{name, _, params}]}, state) when type in @function_types -> - arity = length(params) - add_function_to_map(state, type, name, arity) - - ({:defdelegate, _, [{name, _, params}], _}, state) -> - arity = length(params) - add_function_to_map(state, :defdelegate, name, arity) - - _, state -> - state - - end) - end - - defp new_function_map() do - %{ - def: Keyword.new, - defp: Keyword.new, - defgen: Keyword.new, - defgenp: Keyword.new, - defmacro: Keyword.new, - defmacrop: Keyword.new, - defdelegate: Keyword.new - } - end - - defp get_functions_from_module(_) do - new_function_map() - end - - defp add_function_to_map(map, type, name, arity) do - list = Map.get(map, type) - - if {name, arity} in list do - map - else - Map.put(map, type, list ++ [{ name, arity }]) - end - end - - -end \ No newline at end of file diff --git a/lib/elixir_script/passes/find_load_only.ex b/lib/elixir_script/passes/find_load_only.ex deleted file mode 100644 index 86fb0754..00000000 --- a/lib/elixir_script/passes/find_load_only.ex +++ /dev/null @@ -1,33 +0,0 @@ -defmodule ElixirScript.Passes.FindLoadOnly do - @moduledoc false - - def execute(compiler_data, opts) do - data = compiler_data.data - |> Enum.map(fn({module_name, module_data}) -> - - {_, load_only} = Macro.prewalk(module_data.ast, false, fn - ({:@, _, [{:load_only, _, [true]}]} = ast, state) -> - {ast, true} - - ({:@, _, [{:load_only, _, [false]}]} = ast, state) -> - {ast, false} - - ({:@, _, [{:load_only, _, []}]} = ast, state) -> - {ast, true} - - (ast, state) -> - {ast, state} - end) - - { module_name, Map.put(module_data, :load_only, load_only) } - - end) - - - - %{ compiler_data | data: data } - end - - - -end diff --git a/lib/elixir_script/passes/find_modules.ex b/lib/elixir_script/passes/find_modules.ex deleted file mode 100644 index 0079aadb..00000000 --- a/lib/elixir_script/passes/find_modules.ex +++ /dev/null @@ -1,177 +0,0 @@ -defmodule ElixirScript.Passes.FindModules do - @moduledoc false - alias ElixirScript.Translator.Utils - alias ElixirScript.Translator.State - - def execute(compiler_data, opts) do - data = Enum.reduce(compiler_data.data, [], fn(data, list) -> - quoted = update_quoted(data.ast) - { _, modules } = Macro.postwalk(quoted, [], &get_defmodules(&1, &2, opts, compiler_data)) - - modules = Enum.map(modules, fn(x) -> { x.name, Map.merge(data, x) } end) - list ++ modules - end) - - Map.put(compiler_data, :data, data) - end - - defp get_defmodules({:defprotocol, _, [{:__aliases__, _, _} = the_alias, [do: {:__block__, _, _} = block]]} = ast, state, _, _) do - s = %{ name: Utils.quoted_to_name(the_alias), type: :protocol, ast: block } - { ast, state ++ [s] } - end - - defp get_defmodules({:defprotocol, _, [{:__aliases__, _, _} = the_alias, [do: spec]]} = ast, state, _, _) do - s = %{ name: Utils.quoted_to_name(the_alias), type: :protocol, ast: {:__block__, [], [spec]} } - { ast, state ++ [s] } - end - - defp get_defmodules({:defimpl, _, [ the_alias, [for: {:__aliases__, _, type_name} = type], [do: {:__block__, context, spec}] ]} = ast, state, _, compiler_data) do - {:__aliases__, _, original_name} = Utils.name_to_quoted(State.get_module_name(compiler_data.state, the_alias)) - name = original_name ++ [DefImpl] ++ [Elixir] ++ type_name - s = %{name: Utils.quoted_to_name({:__aliases__, [], name}), type: :impl, for: type, ast: {:__block__, context, spec}, implements: Utils.quoted_to_name({:__aliases__, [], original_name}) } - { ast, state ++ [s] } - end - - defp get_defmodules({:defimpl, _, [ the_alias, [for: {:__aliases__, _, type_name} = type], [do: spec] ]} = ast, state, _, compiler_data) do - {:__aliases__, _, original_name} = Utils.name_to_quoted(State.get_module_name(compiler_data.state, the_alias)) - name = original_name ++ [DefImpl] ++ [Elixir] ++ type_name - s = %{name: Utils.quoted_to_name({:__aliases__, [], name}), type: :impl, for: type, ast: {:__block__, [], [spec]}, implements: Utils.quoted_to_name({:__aliases__, [], original_name}) } - { ast, state ++ [s] } - end - - defp get_defmodules({:defmodule, _, [{:__aliases__, _, [:ElixirScript, :Temp]}, [do: body]]} = ast, state, _, _) do - s = %{name: ElixirScript.Temp, type: :module, ast: body } - { ast, state ++ [s] } - end - - - defp get_defmodules({:defmodule, _, [{:__aliases__, _, _}, [do: _]]} = ast, state, opts, _) do - { ast, do_module_processing(ast, state, opts) } - end - - defp get_defmodules(ast, state, _, _) do - { ast, state } - end - - defp do_module_processing({:defmodule, context1, [{:__aliases__, _, name} = the_alias, [do: body]]}, state, opts) do - { body, inner_modules } = make_inner_module_aliases(name, body) - - aliases = Enum.map(inner_modules, fn - ({:defmodule, _, [{:__aliases__, _, inner_module_name}, [do: inner_module_body]]}) -> - { :alias, [], [{:__aliases__, [alias: false], name ++ inner_module_name}, [as: {:__aliases__, [alias: false], inner_module_name }] ] } - end) - - state = Enum.reduce(inner_modules, state, fn - ({:defmodule, context1, [{:__aliases__, context2, inner_module_name}, [do: inner_module_body]]}, state) -> - - module_name = Utils.quoted_to_name({:__aliases__, [], tl(name) ++ inner_module_name}) - state = Enum.reject(state, fn(x) -> x.name == module_name end) - - this_module_aliases = aliases -- [{ :alias, [], [{:__aliases__, [alias: false], name ++ inner_module_name}, [as: {:__aliases__, [alias: false], inner_module_name }] ] }] - - do_module_processing( - {:defmodule, context1, [{:__aliases__, context2, name ++ inner_module_name}, [do: add_aliases_to_body(inner_module_body, this_module_aliases)]]}, - state, opts) - end) - - body = case body do - {:__block__, context, list } -> - list = Enum.map(list, fn - {:use, _, [module, _] } = using -> - {:use, handle_use_expression(using, module, opts) } - {:use, _, [module] } = using -> - {:use, handle_use_expression(using, module, opts) } - ast -> - {:expanded, ast} - end) - |> Enum.reduce([], fn - {:use, ast}, state -> - case ast do - {:__block__, _, list} -> - state ++ list - _ -> - state ++ [ast] - end - - {:expanded, ast}, state -> - state ++ [ast] - end) - - {:__block__, context, list} - - _ -> - body - end - - body = add_aliases_to_body(body, aliases) - - [%{name: Utils.quoted_to_name(the_alias), type: :module, ast: body }] ++ state - end - - defp add_aliases_to_body(body, aliases) do - case body do - { :__block__, context, body } -> - { :__block__, context, aliases ++ List.wrap(body) } - _ -> - { :__block__, [], aliases ++ List.wrap(body) } - end - end - - defp make_inner_module_aliases(name, body) do - case body do - nil -> - { { :__block__, [], [] }, [] } - - {:__block__, context, list2 } -> - { list2, inner_modules } = Enum.partition(list2, fn(x) -> - case x do - {:defmodule, _, [{:__aliases__, _, inner_module_name}, [do: inner_module_body]]} -> - false - _ -> - true - end - end) - - { {:__block__, context, list2}, inner_modules } - {:defmodule, _, [{:__aliases__, context, inner_module_name}, [do: inner_module_body]]} = mod -> - { {:__block__, context, [] }, [mod] } - _ -> - { body, [] } - end - end - - defp handle_use_expression(using_ast, module, opts) do - module = Utils.quoted_to_name(module) - - eval = """ - require #{inspect module} - __ENV__ - """ - {env, _} = Code.eval_string(eval, [], opts.env) - - - case Macro.expand(using_ast, env) do - {:__block__, _, - [{:__block__, _, - [{:require, _, _}, - {{:., _, [_, :__using__]}, _, _} = ast]}]} -> - Macro.expand_once(ast, env) - end - end - - defp update_quoted(quoted) do - Macro.prewalk(quoted, fn - ({name, context, parms}) -> - context = if context[:import] == Kernel do - context = Keyword.update!(context, :import, fn(_) -> ElixirScript.Kernel end) - else - context - end - - {name, context, parms} - (x) -> - x - end) - end - -end diff --git a/lib/elixir_script/passes/find_used_functions.ex b/lib/elixir_script/passes/find_used_functions.ex new file mode 100644 index 00000000..861d7c44 --- /dev/null +++ b/lib/elixir_script/passes/find_used_functions.ex @@ -0,0 +1,316 @@ +defmodule ElixirScript.FindUsedFunctions do + @moduledoc false + alias ElixirScript.State, as: ModuleState + + @doc """ + Takes a list of entry modules and finds modules they use along with + documenting the functions used. The data collected about used functions + is used to filter only the used functions for compilation + """ + @spec execute([atom], pid) :: nil + def execute(entry_modules, pid) do + entry_modules + |> List.wrap() + |> Enum.each(fn module -> + walk_module(module, pid) + end) + + pid + |> ElixirScript.State.list_modules() + |> Enum.each(fn {module, info} -> + if get_in(info, [:attributes, :protocol_impl]) do + walk_module(module, pid) + end + end) + end + + defp walk_module(module, pid) do + %{ + attributes: _attrs, + compile_opts: _compile_opts, + definitions: defs, + file: _file, + line: _line, + module: ^module, + unreachable: unreachable + } = ModuleState.get_module(pid, module) + + reachable_defs = + Enum.filter(defs, fn + {_, type, _, _} when type in [:defmacro, :defmacrop] -> + false + + {name, _, _, _} -> + name not in unreachable + + _ -> + true + end) + + state = %{ + pid: pid, + module: module + } + + Enum.each(reachable_defs, fn {name, _type, _, _clauses} -> + ModuleState.put_used(state.pid, module, name) + end) + + Enum.each(reachable_defs, &walk(&1, state)) + end + + defp walk_module(module, function, arity, pid) do + function = {function, arity} + + unless ModuleState.has_used?(pid, module, function) do + info = ModuleState.get_module(pid, module) + + state = %{ + pid: pid, + module: module + } + + reachable_def = + Enum.find(Map.get(info, :definitions, []), fn {name, _, _, _} -> name == function end) + + case reachable_def do + nil -> + nil + + {name, _type, _, _clauses} = func -> + ModuleState.put_used(state.pid, module, name) + walk(func, state) + end + end + end + + defp walk({{_name, _arity}, _type, _, clauses}, state) do + Enum.each(clauses, &walk(&1, state)) + end + + defp walk({_, _args, _guards, body}, state) do + walk_block(body, state) + end + + defp walk({:->, _, [[{:when, _, params}], body]}, state) do + guards = List.last(params) + params = params |> Enum.reverse() |> tl |> Enum.reverse() + + walk({[], params, guards, body}, state) + end + + defp walk({:->, _, [params, body]}, state) do + walk({[], params, [], body}, state) + end + + defp walk({:|, _, [head, tail]}, state) do + walk(head, state) + walk(tail, state) + end + + defp walk({:::, _, [target, _type]}, state) do + walk(target, state) + end + + defp walk(form, state) when is_list(form) do + Enum.each(form, &walk(&1, state)) + end + + defp walk({a, b}, state) do + walk({:{}, [], [a, b]}, state) + end + + defp walk({:{}, _, elements}, state) do + walk(elements, state) + end + + defp walk({:%{}, _, properties}, state) do + Enum.each(properties, fn val -> walk(val, state) end) + end + + defp walk({:<<>>, _, elements}, state) do + Enum.each(elements, fn val -> walk(val, state) end) + end + + defp walk({:=, _, [left, right]}, state) do + walk(left, state) + walk(right, state) + end + + defp walk({:%, _, [module, params]}, state) do + walk_module(module, :__struct__, 0, state.pid) + walk_module(module, :__struct__, 1, state.pid) + walk(params, state) + end + + defp walk({:for, _, generators}, state) when is_list(generators) do + Enum.each(generators, fn + {:<<>>, _, body} -> + walk(body, state) + + {:<-, _, [identifier, enum]} -> + walk(identifier, state) + walk(enum, state) + + [into: expression] -> + walk(expression, state) + + [into: expression, do: expression2] -> + walk(expression, state) + walk_block(expression2, state) + + [do: expression] -> + walk_block(expression, state) + + filter -> + walk(filter, state) + end) + end + + defp walk({:case, _, [condition, [do: clauses]]}, state) do + Enum.each(clauses, &walk(&1, state)) + walk(condition, state) + end + + defp walk({:cond, _, [[do: clauses]]}, state) do + Enum.each(clauses, fn {:->, _, [clause, clause_body]} -> + Enum.each(List.wrap(clause_body), &walk(&1, state)) + walk(hd(clause), state) + end) + end + + defp walk({:receive, _context, blocks}, state) do + do_block = Keyword.get(blocks, :do) + after_block = Keyword.get(blocks, :after, nil) + + walk_block(do_block, state) + + if after_block do + Enum.each(List.wrap(after_block), &walk(&1, state)) + end + end + + defp walk({:try, _, [blocks]}, state) do + try_block = Keyword.get(blocks, :do) + rescue_block = Keyword.get(blocks, :rescue, nil) + catch_block = Keyword.get(blocks, :catch, nil) + after_block = Keyword.get(blocks, :after, nil) + else_block = Keyword.get(blocks, :else, nil) + + walk_block(try_block, state) + + if rescue_block do + Enum.each(rescue_block, fn + {:->, _, [[{:in, _, [param, names]}], body]} -> + walk({[], [param], [{{:., [], [Enum, :member?]}, [], [param, names]}], body}, state) + + {:->, _, [[param], body]} -> + walk({[], [param], [], body}, state) + end) + end + + if catch_block do + walk({:fn, [], catch_block}, state) + end + + if after_block do + Enum.each(List.wrap(after_block), &walk(&1, state)) + end + + if else_block do + walk({:fn, [], else_block}, state) + end + end + + defp walk({:fn, _, clauses}, state) do + Enum.each(clauses, &walk(&1, state)) + end + + defp walk({:with, _, args}, state) do + Enum.each(args, fn + {:<-, _, [left, right]} -> + walk(left, state) + walk(right, state) + + {:=, _, [left, right]} -> + walk(left, state) + walk(right, state) + + [do: expression] -> + walk_block(expression, state) + + [do: expression, else: elses] -> + walk_block(expression, state) + + Enum.each(elses, fn {:->, _, [left, right]} -> + walk(left, state) + walk(right, state) + end) + end) + end + + defp walk({{:., _, [:erlang, :apply]}, _, [module, function, params]}, state) do + walk({{:., [], [module, function]}, [], params}, state) + end + + defp walk({{:., _, [:erlang, :apply]}, _, [function, params]}, state) do + walk({function, [], params}, state) + end + + defp walk({{:., _, [ElixirScript.JS, _]}, _, params}, state) do + walk(params, state) + end + + defp walk({{:., _, [module, function]}, _, params}, state) do + cond do + ElixirScript.Translate.Module.is_js_module(module, state) -> + nil + + ElixirScript.Translate.Module.is_elixir_module(module) -> + walk_module(module, function, length(params), state.pid) + + is_tuple(module) -> + walk(module, state) + + true -> + nil + end + + walk(params, state) + end + + defp walk({:super, _, [{_, function} | params]}, state) do + walk_module(state.module, function, length(params), state.pid) + walk(params, state) + end + + defp walk({function, _, params}, state) when is_atom(function) and is_list(params) do + walk_module(state.module, function, length(params), state.pid) + walk(params, state) + end + + defp walk({value, _, params}, state) when is_list(params) do + walk(value, state) + walk(params, state) + end + + defp walk(_, _) do + nil + end + + defp walk_block(block, state) do + case block do + nil -> + nil + + {:__block__, _, block_body} -> + Enum.each(block_body, &walk(&1, state)) + + b when is_list(b) -> + Enum.each(b, &walk(&1, state)) + + _ -> + walk(block, state) + end + end +end diff --git a/lib/elixir_script/passes/find_used_modules.ex b/lib/elixir_script/passes/find_used_modules.ex new file mode 100644 index 00000000..e294c7c1 --- /dev/null +++ b/lib/elixir_script/passes/find_used_modules.ex @@ -0,0 +1,402 @@ +defmodule ElixirScript.FindUsedModules do + @moduledoc false + alias ElixirScript.State, as: ModuleState + require Logger + + @doc """ + Takes a list of entry modules and finds modules they use. + """ + @spec execute([atom], pid) :: :ok + def execute(modules, pid) do + modules + |> List.wrap() + |> Enum.each(fn module -> + do_execute(module, pid) + end) + end + + defp do_execute(module, result, pid) do + case result do + {:ok, info} -> + walk_module(module, info, pid) + + {:ok, module, module_info, implementations} -> + walk_protocol(module, module_info, implementations, pid) + + {:error, "Unknown module"} -> + Logger.warn(fn -> + "ElixirScript: #{inspect(module)} is missing or unavailable" + end) + + ModuleState.put_diagnostic(pid, module, %{ + severity: :warning, + message: "#{inspect(module)} is missing or unavailable" + }) + + {:error, error} -> + raise ElixirScript.CompileError, + message: "An error occurred while compiling #{inspect(module)}: #{error}", + severity: :error + end + end + + defp do_execute(module, pid) do + result = get_debug_info(module, pid) + do_execute(module, result, pid) + end + + defp get_debug_info(module, pid) do + case ModuleState.get_in_memory_module(pid, module) do + nil -> + ElixirScript.Beam.debug_info(module) + + beam -> + ElixirScript.Beam.debug_info(beam) + end + end + + defp walk_module( + module, + %{attributes: [__foreign_info__: %{path: path, name: name, global: global}]} = info, + pid + ) do + {name, path} = + if global do + name = if name, do: name, else: module + path = nil + {name, path} + else + name = Enum.join(Module.split(module), "_") + path = path <> ".js" + {name, path} + end + + ModuleState.put_javascript_module(pid, module, name, path) + ModuleState.put_module(pid, module, info) + + nil + end + + defp walk_module(module, info, pid) do + %{ + attributes: _attrs, + compile_opts: _compile_opts, + definitions: defs, + file: _file, + line: _line, + module: ^module, + unreachable: unreachable + } = info + + ModuleState.put_module(pid, module, info) + + reachable_defs = + Enum.filter(defs, fn + {_, type, _, _} when type in [:defmacro, :defmacrop] -> false + {name, _, _, _} -> name not in unreachable + _ -> true + end) + + state = %{ + pid: pid, + module: module + } + + Enum.each(reachable_defs, fn x -> + walk(x, state) + end) + end + + defp walk_protocol(module, module_info, implementations, pid) do + impls = + Enum.map(implementations, fn {impl, %{attributes: attrs}} -> + protocol_impl = Keyword.fetch!(attrs, :protocol_impl) + impl_for = Keyword.fetch!(protocol_impl, :for) + {impl, impl_for} + end) + + first_implementation_functions = implementations |> hd |> elem(1) |> Map.get(:definitions) + + functions = Enum.map(first_implementation_functions, fn {name, _, _, _} -> name end) + + module_info = Map.merge(module_info, %{protocol: true, impls: impls, functions: functions}) + + ModuleState.put_module(pid, module, module_info) + + Enum.each(implementations, fn {impl, info} -> + ModuleState.put_used_module(pid, module, impl) + walk_module(impl, info, pid) + end) + end + + defp walk({{_name, _arity}, _type, _, clauses}, state) do + Enum.each(clauses, &walk(&1, state)) + end + + defp walk({_, args, guards, body}, state) do + walk(args, state) + walk(guards, state) + walk_block(body, state) + end + + defp walk({:->, _, [[{:when, _, params}], body]}, state) do + guards = List.last(params) + params = params |> Enum.reverse() |> tl |> Enum.reverse() + + walk({[], params, guards, body}, state) + end + + defp walk({:->, _, [params, body]}, state) do + walk({[], params, [], body}, state) + end + + defp walk({:|, _, [head, tail]}, state) do + walk(head, state) + walk(tail, state) + end + + defp walk({:::, _, [target, _type]}, state) do + walk(target, state) + end + + defp walk(form, state) when is_list(form) do + Enum.each(form, &walk(&1, state)) + end + + defp walk(form, state) + when is_atom(form) and form not in [BitString, Function, PID, Port, Reference, Any, Elixir] do + if ElixirScript.Translate.Module.is_elixir_module(form) and + !ElixirScript.Translate.Module.is_js_module(form, state) do + if ModuleState.get_module(state.pid, form) == nil do + case get_debug_info(form, state.pid) do + {:ok, _} = result -> + ModuleState.put_used_module(state.pid, state.module, form) + do_execute(form, result, state.pid) + + result -> + do_execute(form, result, state.pid) + end + else + ModuleState.put_used_module(state.pid, state.module, form) + end + end + end + + defp walk({a, b}, state) do + walk({:{}, [], [a, b]}, state) + end + + defp walk({:{}, _, elements}, state) do + Enum.each(elements, &walk(&1, state)) + end + + defp walk({:%{}, _, properties}, state) do + Enum.each(properties, fn val -> walk(val, state) end) + end + + defp walk({:<<>>, _, elements}, state) do + Enum.each(elements, fn val -> walk(val, state) end) + end + + defp walk({:=, _, [left, right]}, state) do + walk(left, state) + walk(right, state) + end + + defp walk({:%, _, [module, params]}, state) do + if ElixirScript.Translate.Module.is_elixir_module(module) and + !ElixirScript.Translate.Module.is_js_module(module, state) do + if ModuleState.get_module(state.pid, module) == nil do + case get_debug_info(module, state.pid) do + {:ok, _} = result -> + ModuleState.put_used_module(state.pid, state.module, module) + do_execute(module, result, state.pid) + + result -> + do_execute(module, result, state.pid) + end + else + ModuleState.put_used_module(state.pid, state.module, module) + end + end + + walk(params, state) + end + + defp walk({:for, _, generators}, state) when is_list(generators) do + walk(Collectable, state) + + Enum.each(generators, fn + {:<<>>, _, body} -> + walk(body, state) + + {:<-, _, [identifier, enum]} -> + walk(identifier, state) + walk(enum, state) + + [into: expression] -> + walk(expression, state) + + [into: expression, do: expression2] -> + walk(expression, state) + walk_block(expression2, state) + + [do: expression] -> + walk_block(expression, state) + + filter -> + walk(filter, state) + end) + end + + defp walk({:case, _, [condition, [do: clauses]]}, state) do + Enum.each(clauses, &walk(&1, state)) + walk(condition, state) + end + + defp walk({:cond, _, [[do: clauses]]}, state) do + Enum.each(clauses, fn {:->, _, [clause, clause_body]} -> + Enum.each(List.wrap(clause_body), &walk(&1, state)) + walk(hd(clause), state) + end) + end + + defp walk({:receive, _context, blocks}, state) when is_list(blocks) do + do_block = Keyword.get(blocks, :do) + after_block = Keyword.get(blocks, :after, nil) + + walk_block(do_block, state) + + if after_block do + Enum.each(List.wrap(after_block), &walk(&1, state)) + end + end + + defp walk({:try, _, [blocks]}, state) do + walk(Enum, state) + + try_block = Keyword.get(blocks, :do) + rescue_block = Keyword.get(blocks, :rescue, nil) + catch_block = Keyword.get(blocks, :catch, nil) + after_block = Keyword.get(blocks, :after, nil) + else_block = Keyword.get(blocks, :else, nil) + + walk_block(try_block, state) + + if rescue_block do + Enum.each(rescue_block, fn + {:->, _, [[{:in, _, [param, names]}], body]} -> + Enum.each(names, &walk(&1, state)) + walk({[], [param], [{{:., [], [Enum, :member?]}, [], [names, param]}], body}, state) + + {:->, _, [[param], body]} -> + walk({[], [param], [], body}, state) + end) + end + + if catch_block do + walk({:fn, [], catch_block}, state) + end + + if after_block do + Enum.each(List.wrap(after_block), &walk(&1, state)) + end + + if else_block do + walk({:fn, [], else_block}, state) + end + end + + defp walk({:fn, _, clauses}, state) do + Enum.each(clauses, &walk(&1, state)) + end + + defp walk({:with, _, args}, state) do + Enum.each(args, fn + {:<-, _, [left, right]} -> + walk(left, state) + walk(right, state) + + {:=, _, [left, right]} -> + walk(left, state) + walk(right, state) + + [do: expression] -> + walk_block(expression, state) + + [do: expression, else: elses] -> + walk_block(expression, state) + + Enum.each(elses, fn {:->, _, [left, right]} -> + walk(left, state) + walk(right, state) + end) + end) + end + + defp walk({{:., _, [:erlang, :apply]}, _, [module, function, params]}, state) do + walk({{:., [], [module, function]}, [], params}, state) + end + + defp walk({{:., _, [:erlang, :apply]}, _, [function, params]}, state) do + walk({function, [], params}, state) + end + + defp walk({{:., _, [_module, _function]} = ast, _, params}, state) do + walk(ast, state) + walk(params, state) + end + + defp walk({:., _, [ElixirScript.JS, _]}, _) do + nil + end + + defp walk({:., _, [module, function]}, state) do + if ElixirScript.Translate.Module.is_elixir_module(module) do + if ModuleState.get_module(state.pid, module) == nil do + case get_debug_info(module, state.pid) do + {:ok, _} = result -> + ModuleState.put_used_module(state.pid, state.module, module) + do_execute(module, result, state.pid) + + result -> + do_execute(module, result, state.pid) + end + else + ModuleState.put_used_module(state.pid, state.module, module) + end + else + walk(module, state) + walk(function, state) + end + end + + defp walk({:super, _, [{_, _} | params]}, state) do + walk(params, state) + end + + defp walk({function, _, params}, state) when is_list(params) do + walk(function, state) + walk(params, state) + end + + defp walk(_, _) do + nil + end + + defp walk_block(block, state) do + case block do + nil -> + nil + + {:__block__, _, block_body} -> + Enum.each(block_body, &walk(&1, state)) + + b when is_list(b) -> + Enum.each(b, &walk(&1, state)) + + _ -> + walk(block, state) + end + end +end diff --git a/lib/elixir_script/passes/handle_output.ex b/lib/elixir_script/passes/handle_output.ex deleted file mode 100644 index 56512ac8..00000000 --- a/lib/elixir_script/passes/handle_output.ex +++ /dev/null @@ -1,50 +0,0 @@ -defmodule ElixirScript.Passes.HandleOutput do - @moduledoc false - alias ElixirScript.Translator.State - @generated_name "Elixir.App.js" - - def execute(compiler_data, opts) do - State.stop(compiler_data.state) - out(compiler_data, opts) - end - - defp out(compiler_output, %{output: nil} = compiler_opts) do - compiler_output - |> process_include_path(compiler_opts) - end - - defp out(compiler_output, %{output: :stdout} = compiler_opts) do - out = compiler_output - |> process_include_path(compiler_opts) - - code = case out do - {code, _} -> code - code -> code - end - - IO.write(concat(code)) - end - - defp out(compiler_output, %{output: output_path, core_path: _} = compiler_opts) do - file_name = Path.join([output_path, @generated_name]) - - if !File.exists?(Path.dirname(file_name)) do - File.mkdir_p!(Path.dirname(file_name)) - end - - File.write!(file_name, concat(compiler_output.generated)) - end - - defp concat(code) do - "'use strict';\n" <> ElixirScript.get_bootstrap_js("iife") <> "\n" <> code - end - - defp process_include_path(compiler_output, compiler_opts) do - case compiler_opts.include_path do - true -> - {compiler_output.generated, @generated_name} - false -> - compiler_output.generated - end - end -end diff --git a/lib/elixir_script/passes/init.ex b/lib/elixir_script/passes/init.ex deleted file mode 100644 index 3ac9d5d9..00000000 --- a/lib/elixir_script/passes/init.ex +++ /dev/null @@ -1,10 +0,0 @@ -defmodule ElixirScript.Passes.Init do - @moduledoc false - alias ElixirScript.Translator.State - - def execute(compiler_data, opts) do - {:ok, pid} = State.start_link(opts, []) - Map.put(compiler_data, :state, pid) - end - -end diff --git a/lib/elixir_script/passes/java_script_ast.ex b/lib/elixir_script/passes/java_script_ast.ex deleted file mode 100644 index 7a95f0eb..00000000 --- a/lib/elixir_script/passes/java_script_ast.ex +++ /dev/null @@ -1,43 +0,0 @@ -defmodule ElixirScript.Passes.JavaScriptAST do - @moduledoc false - alias ElixirScript.Translator.Utils - alias ElixirScript.Translator.State - - def execute(compiler_data, opts) do - - State.set_module_data(compiler_data.state, compiler_data.data) - State.set_loaded_modules(compiler_data.state, Map.get(compiler_data, :loaded_modules, [])) - - data = compiler_data.state - |> State.get_module_data - |> Enum.reject(fn {_,module_data} -> - module_data.app == :elixir && opts.import_standard_libs == false - end) - |> Enum.map(fn({module_name, module_data}) -> - module_data = compile(module_data, opts, compiler_data.state) - {module_name, module_data} - end) - - %{ compiler_data | data: data } - end - - defp compile(%{load_only: true} = module_data, opts, state) do - module_data - end - - defp compile(module_data, opts, state) do - - env = ElixirScript.Translator.LexicalScope.module_scope(module_data.name, Utils.name_to_js_file_name(module_data.name) <> ".js", opts.env, state, opts) - - module = case module_data.type do - :module -> - ElixirScript.Translator.Defmodule.make_module(module_data.name, module_data.ast, env) - :protocol -> - ElixirScript.Translator.Defprotocol.make(module_data.name, module_data.functions, env) - :impl -> - ElixirScript.Translator.Defimpl.make(module_data.name, module_data.for, module_data.ast, env) - end - - Map.put(module_data, :javascript_module, module) - end -end diff --git a/lib/elixir_script/passes/java_script_code.ex b/lib/elixir_script/passes/java_script_code.ex deleted file mode 100644 index 7eb2f7ef..00000000 --- a/lib/elixir_script/passes/java_script_code.ex +++ /dev/null @@ -1,31 +0,0 @@ -defmodule ElixirScript.Passes.JavaScriptCode do - @moduledoc false - alias ESTree.Tools.{Builder, Generator} - - def execute(compiler_data, _) do - parent = self - - js_code = compiler_data.compiled - |> List.wrap - |> Builder.program - |> prepare_js_ast - |> Generator.generate - - Map.put(compiler_data, :generated, js_code) - end - - defp prepare_js_ast(js_ast) do - case js_ast do - modules when is_list(modules) -> - modules - |> Enum.reduce([], &(&2 ++ &1.body)) - |> Builder.program - %ElixirScript.Translator.Group{body: body} -> - Builder.program(body) - %ElixirScript.Translator.Empty{} -> - Builder.program([]) - _ -> - js_ast - end - end -end diff --git a/lib/elixir_script/passes/load_modules.ex b/lib/elixir_script/passes/load_modules.ex deleted file mode 100644 index 5e57fe76..00000000 --- a/lib/elixir_script/passes/load_modules.ex +++ /dev/null @@ -1,27 +0,0 @@ -defmodule ElixirScript.Passes.LoadModules do - @moduledoc false - def execute(compiler_data, _) do - ex_files = compiler_data.data - |> Enum.filter(fn - {_, %{app: :elixir}} -> - false - %{app: :elixir} -> - false - _ -> true - end) - |> Enum.map(fn - { _, %{path: path} } -> path - %{path: path} -> path - end) - - loaded_modules = case Enum.reverse(ex_files) do - [] -> - [] - files -> - Kernel.ParallelCompiler.files(files) - end - - Map.put(compiler_data, :loaded_modules, loaded_modules) - end - -end diff --git a/lib/elixir_script/passes/load_modules_for_quoted.ex b/lib/elixir_script/passes/load_modules_for_quoted.ex deleted file mode 100644 index 7c737dd1..00000000 --- a/lib/elixir_script/passes/load_modules_for_quoted.ex +++ /dev/null @@ -1,28 +0,0 @@ -defmodule ElixirScript.Passes.LoadModulesForQuoted do - @moduledoc false - def execute(compiler_data, _) do - quoted = compiler_data.data - |> Enum.filter(fn - {_, %{app: :elixir}} -> - false - %{app: :elixir} -> - false - _ -> true - end) - |> Enum.map(fn - {_, %{ast: ast}} -> ast - %{ast: ast} -> ast - end) - - loaded_modules = Map.get(compiler_data, :loaded_modules, []) - - loaded_modules_from_quoted = quoted - |> Enum.map(&Code.compile_quoted(&1)) - |> List.flatten - |> Enum.map(fn {mod, _} -> mod end) - - - Map.put(compiler_data, :loaded_modules, loaded_modules ++ loaded_modules_from_quoted) - end - -end \ No newline at end of file diff --git a/lib/elixir_script/passes/output.ex b/lib/elixir_script/passes/output.ex new file mode 100644 index 00000000..2953ae0f --- /dev/null +++ b/lib/elixir_script/passes/output.ex @@ -0,0 +1,174 @@ +defmodule ElixirScript.Output do + @moduledoc false + + alias ElixirScript.State, as: ModuleState + alias ESTree.Tools.{Builder, Generator} + + @doc """ + Takes outputs the JavaScript code in the specified output + """ + @spec execute([atom], pid, map) :: [{atom, binary}] + def execute(modules, pid, opts) do + js_modules = + ModuleState.js_modules(pid) + |> Enum.filter(fn + {_module, _name, nil} -> false + _ -> true + end) + |> Enum.map(fn {module, name, path} -> + import_path = Path.join(opts.root, path) + {module, name, path, import_path} + end) + + prepared_modules = + modules + |> Enum.filter(fn {_, info} -> Map.has_key?(info, :js_ast) end) + |> Enum.map(fn {module, info} -> + {module, info.js_ast, filter_used_modules(info.used_modules, pid)} + end) + + create_modules(prepared_modules, opts, js_modules) + end + + defp filter_used_modules(used_modules, pid) do + used_modules + |> Enum.filter(fn module -> + module in ModuleState.list_javascript_modules(pid) == false + end) + end + + defp concat(code) do + """ + 'use strict'; + import ElixirScript from './ElixirScript.Core.js'; + #{code} + """ + end + + defp create_modules(modules, opts, js_modules) do + modules + |> Task.async_stream( + fn {module, [body, exports], used_modules} -> + modules = modules_to_import(used_modules) ++ js_modules + + imports = opts.module_formatter.build_imports(modules) + exports = opts.module_formatter.build_export(exports) + + js_parts = List.wrap(imports) ++ body ++ List.wrap(exports) + + js_parts + |> Builder.program() + |> Generator.generate() + |> concat + |> output(module, Map.get(opts, :output), js_modules) + end, + timeout: 10_000 + ) + |> Stream.map(fn {:ok, code} -> code end) + |> Enum.to_list() + |> List.flatten() + |> Enum.uniq() + end + + defp modules_to_import(modules) do + Enum.map(modules, &module_to_import(&1)) + end + + defp module_to_import(module) do + {module, module_to_name(module), "", "./Elixir.#{inspect(module)}.js"} + end + + def module_to_name(module) do + "$#{inspect(module)}$" + |> String.replace(".", "$") + end + + defp output(code, module, nil, _), do: [{module, code}] + + defp output(code, module, :stdout, _) do + IO.puts(code) + [{module, code}] + end + + defp output(code, module, path, js_modules) do + output_dir = + case Path.extname(path) do + "" -> + path + + _ -> + Path.dirname(path) + end + + file_name = Path.join(output_dir, "Elixir.#{inspect(module)}.js") + + if !File.exists?(output_dir) do + File.mkdir_p!(output_dir) + end + + apps = get_app_names() + + ffi_modules = + Enum.reduce(js_modules, [], fn {module, _, path, _}, acc -> + acc ++ copy_javascript_module(apps, output_dir, module, path) + end) + + copy_bootstrap_js(output_dir) + File.write!(file_name, code) + + [{module, code}] ++ ffi_modules + end + + defp copy_bootstrap_js(directory) do + operating_path = Path.join([Mix.Project.build_path(), "lib", "elixir_script", "priv"]) + path = Path.join([operating_path, "build", "es", "ElixirScript.Core.js"]) + File.cp!(path, Path.join([directory, "ElixirScript.Core.js"])) + end + + defp get_app_names() do + Mix.Project.config()[:app] + + deps = + Mix.Project.deps_paths() + |> Map.keys() + + [Mix.Project.config()[:app]] ++ deps + end + + defp copy_javascript_module(apps, output_dir, module, js_module_path) do + Enum.reduce(apps, [], fn app, acc -> + base_path = Path.join([:code.priv_dir(app), "elixir_script"]) + + js_input_path = + cond do + File.exists?(Path.join([base_path, js_module_path])) -> + Path.join([base_path, js_module_path]) + + File.exists?(Path.join([base_path, slashes_to_dots(js_module_path)])) -> + Path.join([base_path, slashes_to_dots(js_module_path)]) + + true -> + nil + end + + if js_input_path != nil do + js_output_path = Path.join(output_dir, js_module_path) + js_output_dir = Path.dirname(js_output_path) + + if !File.exists?(js_output_dir) do + File.mkdir_p!(js_output_dir) + end + + File.cp(js_input_path, js_output_path) + acc ++ [{module, [js_input_path, js_output_path]}] + else + acc + end + end) + end + + defp slashes_to_dots(js_module_path) do + js_module_path + |> String.replace("/", ".") + end +end diff --git a/lib/elixir_script/passes/output/js_module.ex b/lib/elixir_script/passes/output/js_module.ex new file mode 100644 index 00000000..9005dafc --- /dev/null +++ b/lib/elixir_script/passes/output/js_module.ex @@ -0,0 +1,13 @@ +defmodule ElixirScript.Output.JSModule do + @moduledoc false + + alias ESTree.Tools.Builder, as: J + + def compile(body, opts, js_modules) do + imports = opts.module_formatter.build_imports(js_modules) + exports = opts.module_formatter.build_export(J.identifier("Elixir")) + + [imports] ++ body ++ [exports] + end + +end diff --git a/lib/elixir_script/passes/translate.ex b/lib/elixir_script/passes/translate.ex new file mode 100644 index 00000000..0b6490fc --- /dev/null +++ b/lib/elixir_script/passes/translate.ex @@ -0,0 +1,19 @@ +defmodule ElixirScript.Translate do + @moduledoc false + + @doc """ + Takes a list of modules and translates their ast into + JavaScript AST. The modules are the ones collected from + the FindUsed pass. + """ + @spec execute([atom], pid) :: nil + def execute(modules, pid) do + modules + |> List.wrap() + |> Task.async_stream(fn + {module, info} -> + ElixirScript.Translate.Module.compile(module, info, pid) + end, timeout: 10_000) + |> Stream.run() + end +end diff --git a/lib/elixir_script/passes/translate/clause.ex b/lib/elixir_script/passes/translate/clause.ex new file mode 100644 index 00000000..38c42898 --- /dev/null +++ b/lib/elixir_script/passes/translate/clause.ex @@ -0,0 +1,125 @@ +defmodule ElixirScript.Translate.Clause do + @moduledoc false + + # Handles translation of all of the clause ASTs + + alias ESTree.Tools.Builder, as: J + alias ElixirScript.Translate.Helpers + alias ElixirScript.Translate.Form + alias ElixirScript.Translate.Forms.Pattern + alias ElixirScript.Translate.Function + + def compile({ _, args, guards, body}, state) do + {patterns, params, state} = Pattern.compile(args, state) + guard = compile_guard(params, guards, state) + + {body, _state} = Function.compile_block(body, state) + + body = body + |> return_last_statement + |> Function.update_last_call(state) + + ast = Helpers.call( + J.member_expression( + Helpers.patterns(), + J.identifier("clause") + ), + [ + J.array_expression(patterns), + Helpers.arrow_function( + params, + J.block_statement(body) + ), + guard + ] + ) + + { ast, state } + end + + def compile({:->, _, [[{:when, _, params}], body ]}, state) do + guards = List.last(params) + params = params |> Enum.reverse |> tl |> Enum.reverse + + compile({[], params, guards, body}, state) + end + + def compile({:->, _, [params, body]}, state) do + compile({[], params, [], body}, state) + end + + def return_last_statement(body) do + body + |> List.wrap + |> Enum.reverse + |> do_return_last_statement + |> Enum.reverse + end + + defp do_return_last_statement([%ESTree.ThrowStatement{} = ast]) do + [ast] + end + + defp do_return_last_statement([%ESTree.VariableDeclaration{} = head | tail]) do + declaration = hd(head.declarations).id + + return_statement = case declaration do + %ESTree.ArrayPattern{elements: elements} -> + if length(elements) == 1 do + J.return_statement(hd(declaration.elements)) + else + J.return_statement(J.array_expression(declaration.elements)) + end + _ -> + J.return_statement(declaration) + end + + [return_statement, head] ++ tail + end + + defp do_return_last_statement([head]) do + [J.return_statement(head)] + end + + defp do_return_last_statement([%ESTree.ThrowStatement{} = head | tail]) do + [head] ++ tail + end + + defp do_return_last_statement([head | tail]) do + [J.return_statement(head)] ++ tail + end + + defp do_return_last_statement([]) do + [J.return_statement(J.identifier("null"))] + end + + def compile_guard(params, guards, state) do + state = Map.put(state, :in_guard, true) + + guards = guards + |> List.wrap + |> Enum.reverse + |> process_guards + |> Form.compile!(state) + + Helpers.arrow_function( + params, + J.block_statement([ + J.return_statement(guards) + ]) + ) + + end + + defp process_guards([]) do + true + end + + defp process_guards([guard]) do + guard + end + + defp process_guards([head | tail]) do + {{:., [], [:erlang, :orelse]}, [], [process_guards(tail), head]} + end +end diff --git a/lib/elixir_script/passes/translate/form.ex b/lib/elixir_script/passes/translate/form.ex new file mode 100644 index 00000000..129d1723 --- /dev/null +++ b/lib/elixir_script/passes/translate/form.ex @@ -0,0 +1,467 @@ +defmodule ElixirScript.Translate.Form do + @moduledoc false + + # Handles translation of all forms that are not functions or clauses + + alias ESTree.Tools.Builder, as: J + alias ElixirScript.Translate.Helpers + alias ElixirScript.Translate.Forms.{Bitstring, Match, Try, For, Receive, Remote, Pattern, With} + alias ElixirScript.Translate.Clause + alias ElixirScript.State, as: ModuleState + require Logger + + @spec compile!(any, map) :: ESTree.Node.t() + def compile!(ast, state) do + {js_ast, _} = compile(ast, state) + + js_ast + end + + @spec compile(any, map) :: {ESTree.Node.t(), map} + def compile(ast, state) + + def compile(nil, state) do + {J.identifier("null"), state} + end + + def compile(map, state) when is_map(map) do + quoted = Code.string_to_quoted!("#{inspect(map)}") + compile(quoted, state) + end + + def compile(form, state) + when is_boolean(form) or is_integer(form) or is_float(form) or is_binary(form) do + {J.literal(form), state} + end + + def compile([{:|, _, [_head, _tail]} = ast], state) do + compile(ast, state) + end + + def compile({:|, _, [head, tail]}, state) do + ast = + Helpers.call( + J.member_expression( + Helpers.functions(), + J.identifier("concat") + ), + [compile!(head, state), compile!(tail, state)] + ) + + {ast, state} + end + + def compile(form, state) when is_list(form) do + ast = J.array_expression(Enum.map(form, &compile!(&1, state))) + + {ast, state} + end + + def compile(form, state) when is_atom(form) do + ast = + cond do + ElixirScript.Translate.Module.is_elixir_module(form) and + ModuleState.get_module(state.pid, form) != nil -> + Remote.process_module_name(form, state) + + ElixirScript.Translate.Module.is_elixir_module(form) -> + J.object_expression([]) + + true -> + Helpers.symbol(form) + end + + {ast, state} + end + + def compile({a, b}, state) do + compile({:{}, [], [a, b]}, state) + end + + def compile({:{}, _, elements}, state) do + ast = + Helpers.new( + Helpers.tuple(), + Enum.map(elements, &compile!(&1, state)) |> List.flatten() + ) + + {ast, state} + end + + def compile({:&, _, [{:/, _, [{{:., _, [_module, _function]} = ast, [], []}, _]}]}, state) do + Remote.compile(ast, state) + end + + def compile({:&, _, [{:/, _, [{var, _, _}, _]}]}, state) do + ast = ElixirScript.Translate.Identifier.make_function_name(var) + {ast, state} + end + + def compile({:%{}, _, _} = map, state) do + ElixirScript.Translate.Forms.Map.compile(map, state) + end + + def compile({:<<>>, _, []} = bitstring, state) do + Bitstring.compile(bitstring, state) + end + + def compile({:<<>>, _, elements} = bitstring, state) do + is_interpolated_string = + Enum.all?(elements, fn x -> + case x do + b when is_binary(b) -> + true + + {:::, _, [_target, {:binary, _, _}]} -> + true + + _ -> + false + end + end) + + if is_interpolated_string do + Bitstring.make_interpolated_string(elements, state) + else + Bitstring.compile(bitstring, state) + end + end + + def compile({:=, _, [_, _]} = match, state) do + Match.compile(match, state) + end + + def compile({:%, _, [module, params]}, state) do + ast = + Helpers.call( + J.member_expression( + Remote.process_module_name(module, state), + J.identifier("__struct__") + ), + [compile!(params, state)] + ) + + {ast, state} + end + + def compile({:for, _, generators} = ast, state) when is_list(generators) do + For.compile(ast, state) + end + + def compile({:case, _, [{:=, _, [left, _]} = match, [do: clauses]]}, state) do + {match_ast, state} = compile(match, state) + {case_ast, state} = compile({:case, [], [left, [do: clauses]]}, state) + + match_ast = List.wrap(match_ast) + + {match_ast ++ [case_ast], state} + end + + def compile({:case, _, [condition, [do: clauses]]}, state) do + func = + Helpers.call( + J.member_expression( + Helpers.patterns(), + J.identifier("defmatch") + ), + Enum.map(clauses, fn x -> Clause.compile(x, state) |> elem(0) end) |> List.flatten() + ) + + ast = + Helpers.call(J.member_expression(func, J.identifier("call")), [ + J.identifier(:this), + compile!(condition, state) + ]) + + {ast, state} + end + + def compile({:cond, _, [[do: clauses]]}, state) do + processed_clauses = + Enum.map(clauses, fn {:->, _, [clause, clause_body]} -> + {translated_body, state} = + ElixirScript.Translate.Function.compile_block(clause_body, state) + + translated_body = + translated_body + |> Clause.return_last_statement() + + translated_body = Helpers.arrow_function([], J.block_statement(translated_body)) + + {translated_clause, _} = compile(hd(clause), state) + + J.array_expression([translated_clause, translated_body]) + end) + + cond_function = + J.member_expression( + Helpers.special_forms(), + J.identifier("cond") + ) + + ast = + Helpers.call( + cond_function, + processed_clauses + ) + + {ast, state} + end + + def compile({:receive, context, [blocks]}, state) do + line = Keyword.get(context, :line, 1) + module = Map.get(state, :module) + pid = Map.get(state, :pid) + {function, _arity} = Map.get(state, :function) + + ModuleState.put_diagnostic(pid, module, %{ + severity: :warning, + message: "receive not supported, Module: #{inspect(state.module)}, Function: #{function}", + position: line + }) + + Logger.warn(fn -> + "ElixirScript: receive not supported, Module: #{inspect(state.module)}, Function: #{ + function + }, Line: #{line}" + end) + + Receive.compile(blocks, state) + end + + def compile({:try, _, [blocks]}, state) do + Try.compile(blocks, state) + end + + def compile({:with, _, args}, state) do + With.compile(args, state) + end + + def compile({:fn, _, _} = ast, state) do + ElixirScript.Translate.Function.compile(ast, state) + end + + def compile({{:., _, [:erlang, op]}, _, [item]}, state) when op in [:+, :-] do + ast = + J.unary_expression( + op, + true, + compile!(item, state) + ) + + {ast, state} + end + + def compile({{:., _, [:erlang, op]}, _, [left, right]}, state) when op in [:==, :===] do + ast = + Helpers.call( + J.member_expression( + Helpers.core_module("erlang"), + J.identifier("equals") + ), + [compile!(left, state), compile!(right, state)] + ) + + {ast, state} + end + + def compile({{:., _, [:erlang, op]}, _, [left, right]}, state) + when op in [:+, :-, :*, :/, :>, :<, :>=] do + ast = + J.binary_expression( + op, + compile!(left, state), + compile!(right, state) + ) + + {ast, state} + end + + def compile({{:., _, [:erlang, :"=<"]}, _, [left, right]}, state) do + ast = + J.binary_expression( + :<=, + compile!(left, state), + compile!(right, state) + ) + + {ast, state} + end + + def compile({{:., _, [:erlang, :"=:="]}, _, [left, right]}, state) do + ast = + J.binary_expression( + :===, + compile!(left, state), + compile!(right, state) + ) + + {ast, state} + end + + def compile({{:., _, [:erlang, :"=/="]}, _, [left, right]}, state) do + ast = + J.binary_expression( + :!==, + compile!(left, state), + compile!(right, state) + ) + + {ast, state} + end + + def compile({{:., _, [:erlang, :"/="]}, _, [left, right]}, state) do + ast = + J.binary_expression( + :!=, + compile!(left, state), + compile!(right, state) + ) + + {ast, state} + end + + def compile({{:., _, [:erlang, op]}, _, [left, right]}, state) when op in [:andalso, :and] do + ast = + J.binary_expression( + :&&, + compile!(left, state), + compile!(right, state) + ) + + {ast, state} + end + + def compile({{:., _, [:erlang, op]}, _, [left, right]}, state) when op in [:orelse, :or] do + ast = + J.binary_expression( + :||, + compile!(left, state), + compile!(right, state) + ) + + {ast, state} + end + + def compile({{:., _, [var, func_or_prop]}, _, []}, state) when not is_atom(var) do + ast = + Helpers.call(ElixirScript.Translate.Forms.JS.call_property(), [ + compile!(var, state), + J.literal(to_string(func_or_prop)) + ]) + + {ast, state} + end + + def compile({{:., _, [ElixirScript.JS, _]}, _, _} = ast, state) do + ElixirScript.Translate.Forms.JS.compile(ast, state) + end + + def compile({:., _, call} = ast, state) when is_list(call) do + Remote.compile(ast, state) + end + + def compile({:super, _, [_ | params]}, state) when is_list(params) do + {function_name, _} = Map.get(state, :function) + {var_decs, params} = compile_params(params, state) + + ast = + Helpers.call( + ElixirScript.Translate.Identifier.make_function_name(function_name), + params + ) + + case var_decs do + [] -> + {ast, state} + + _ -> + {var_decs ++ List.wrap(ast), state} + end + end + + def compile({:__block__, _, _} = ast, state) do + ElixirScript.Translate.Function.compile_block(ast, state) + end + + def compile({var, _, params}, state) when is_list(params) and is_atom(var) do + {var_decs, params} = compile_params(params, state) + + ast = + Helpers.call( + ElixirScript.Translate.Identifier.make_function_name(var), + params + ) + + case var_decs do + [] -> + {ast, state} + + _ -> + {var_decs ++ List.wrap(ast), state} + end + end + + def compile({function, _, []}, state) do + ast = + Helpers.call(ElixirScript.Translate.Forms.JS.call_property(), [compile!(function, state)]) + + {ast, state} + end + + def compile({function, _, params}, state) when is_list(params) do + {var_decs, params} = compile_params(params, state) + + ast = + Helpers.call( + compile!(function, state), + params + ) + + case var_decs do + [] -> + {ast, state} + + _ -> + {var_decs ++ List.wrap(ast), state} + end + end + + def compile({var, meta, _}, state) do + counter = Pattern.get_counter(meta) + + var = ElixirScript.Translate.Identifier.filter_name(var) + var = Pattern.get_variable_name(var <> counter, state) + {ElixirScript.Translate.Identifier.make_identifier(var), state} + end + + defp compile_params(params, state) do + {params, var_decs} = + Enum.map_reduce(params, [], fn + {:=, _, [{left_var, _, atom} = left, right]} = ast, acc when is_atom(atom) -> + case Atom.to_string(left_var) do + "_" <> _ -> + {compile!(right, state), acc} + + _ -> + {ast, state} = compile(ast, state) + left = compile!(left, state) + + {left, acc ++ List.wrap(ast)} + end + + {:=, _, [left, _]} = ast, acc -> + {ast, state} = compile(ast, state) + left = compile!(left, state) + + {left, acc ++ List.wrap(ast)} + + x, acc -> + compiled = compile!(x, state) + + {compiled, acc} + end) + + {var_decs, params} + end +end diff --git a/lib/elixir_script/passes/translate/forms/bitstring.ex b/lib/elixir_script/passes/translate/forms/bitstring.ex new file mode 100644 index 00000000..e4d2cc2a --- /dev/null +++ b/lib/elixir_script/passes/translate/forms/bitstring.ex @@ -0,0 +1,141 @@ +defmodule ElixirScript.Translate.Forms.Bitstring do + @moduledoc false + alias ESTree.Tools.Builder, as: JS + alias ElixirScript.Translate.Helpers + alias ElixirScript.Translate.Form + + + def compile({:<<>>, _, elements}, state) do + js_ast = Helpers.new( + Helpers.bitstring(), + Enum.map(elements, &compile_element(&1, state)) + ) + + { js_ast, state } + end + + def compile_element(element, state) when is_number(element) do + do_compile_element({:integer, Form.compile!(element, state)}) + end + + def compile_element(element, state) when is_binary(element) do + do_compile_element({:binary, Form.compile!(element, state)}) + end + + def compile_element({:<<>>, _, _} = ast, state) do + {ast, _} = compile(ast, state) + ast + end + + def compile_element({:::, _, [element, {type, _, _}]}, state) when type in [:integer, :float, :bitstring, :bits, :binary, :bytes, :utf8, :utf16, :utf32, :signed, :unsigned] do + do_compile_element({type, translate_element(element, state)}) + end + + def compile_element({:::, _, [element, {type, _, params}]}, state) when type in [:size, :unit] do + do_compile_element({type, translate_element(element, state), Enum.map(params, &translate_element(&1, state))}) + end + + def compile_element({:::, _, [element, {:*, _, [size, unit]}]}, state) do + size_ast = do_compile_element({:size, translate_element(element, state), [translate_element(size, state)]}) + do_compile_element({:unit, size_ast, [translate_element(unit, state)]}) + end + + def compile_element({:::, _, [element, {:-, _, types}]}, state) do + handle_type_adjectives({:-, [], types}, translate_element(element, state), state) + end + + def compile_element({:::, _, [element, size]}, state) do + do_compile_element({:size, translate_element(element, state), [translate_element(size, state)]}) + end + + def compile_element(element, state) do + do_compile_element({:binary, translate_element(element, state)}) + end + + def translate_element(ElixirScript.Translate.Forms.Pattern.Patterns, _) do + JS.object_expression([JS.property( + JS.literal("value"), + ElixirScript.Translate.Forms.Pattern.Patterns.parameter() + ) + ]) + end + + def translate_element(element, state) do + Form.compile!(element, state) + end + + defp handle_type_adjectives({:-, _, types}, ast, state) do + Enum.reduce(types, ast, fn(type, current_ast) -> + case type do + {:-, _, sub_types} -> + handle_type_adjectives({:-, [], sub_types}, current_ast, state) + {:*, _, [size, unit]} -> + size_ast = do_compile_element({:size, current_ast, [Form.compile!(size, state)]}) + do_compile_element({:unit, size_ast, [Form.compile!(unit, state)]}) + {the_type, _, params} when is_list(params) -> + do_compile_element({the_type, current_ast, Enum.map(params, &Form.compile!(&1, state))}) + {the_type, _, _} -> + do_compile_element({the_type, current_ast}) + end + end) + end + + defp do_compile_element({type, ast}) do + Helpers.call( + JS.member_expression( + Helpers.bitstring(), + JS.identifier(type) + ), + [ + ast + ] + ) + end + + defp do_compile_element({type, ast, params}) when is_list(params) do + Helpers.call( + JS.member_expression( + Helpers.bitstring(), + JS.identifier(type) + ), + [ + ast + ] ++ params + ) + end + + def make_interpolated_string(elements, state) do + translated_elements = Enum.map(elements, fn(x) -> + case x do + elem when is_binary(elem) -> + Form.compile!(elem, state) + {:::, _, data} -> + Form.compile!(hd(data), state) + end + end) + + result = case translated_elements do + [] -> + JS.literal('') + [_] -> + do_make_interpolated_string([], hd(translated_elements)) + elements -> + do_make_interpolated_string(tl(elements), hd(elements)) + end + + {result, state} + end + + defp do_make_interpolated_string([], ast) do + ast + end + + defp do_make_interpolated_string(elements, ast) do + JS.binary_expression( + :+, + ast, + do_make_interpolated_string(tl(elements), hd(elements)) + ) + end + +end diff --git a/lib/elixir_script/passes/translate/forms/for.ex b/lib/elixir_script/passes/translate/forms/for.ex new file mode 100644 index 00000000..a641d480 --- /dev/null +++ b/lib/elixir_script/passes/translate/forms/for.ex @@ -0,0 +1,114 @@ +defmodule ElixirScript.Translate.Forms.For do + @moduledoc false + + alias ESTree.Tools.Builder, as: JS + alias ElixirScript.Translate.{Form, Clause, Helpers} + alias ElixirScript.Translate.Forms.Pattern + + def compile({:for, _, generators}, state) do + args = handle_args(generators, state) + + generators = JS.array_expression(args.generators) + + into = args.into || JS.array_expression([]) + filter = args.filter || Helpers.arrow_function([], JS.block_statement([JS.return_statement(JS.identifier("true"))])) + fun = args.fun + + + expression = Helpers.call( + JS.member_expression( + Helpers.patterns(), + JS.identifier("clause") + ), + [JS.array_expression(args.patterns), fun, filter] + ) + + collectable = JS.identifier("Collectable") + + ast = Helpers.call( + JS.member_expression( + Helpers.special_forms(), + JS.identifier("_for") + ), + [expression, generators, collectable, into] + ) + + {ast, state} + end + + defp handle_args(nil, _) do + %{generators: [], args: [], filter: nil, fun: nil, into: nil, patterns: []} + end + + defp handle_args(generators, module_state) do + Enum.reduce(generators, %{generators: [], args: [], filter: nil, fun: nil, into: nil, patterns: []}, fn + + ({:<<>>, _, body}, state) -> + {bs_parts, collection} = Enum.map_reduce(body, nil, fn + {:::, _, _} = ast, state -> + {ast, state} + {:<-, _, [var, collection]}, _ -> + {var, collection} + end) + + {patterns, params, module_state} = Pattern.compile([{:<<>>, [], bs_parts}], module_state) + + gen = Helpers.call( + JS.member_expression( + Helpers.patterns(), + JS.identifier("bitstring_generator") + ), + [hd(patterns), Form.compile!(collection, module_state)] + ) + + %{state | generators: state.generators ++ [gen], args: state.args ++ params, patterns: state.patterns ++ patterns} + + ({:<-, _, [identifier, enum]}, state) -> + {patterns, params, module_state} = Pattern.compile([identifier], module_state) + + gen = Helpers.call( + JS.member_expression( + Helpers.patterns(), + JS.identifier("list_generator") + ), + [hd(patterns), Form.compile!(enum, module_state)] + ) + + %{state | generators: state.generators ++ [gen], args: state.args ++ params, patterns: state.patterns ++ patterns} + ([into: expression], state) -> + %{state | into: Form.compile!(expression, module_state)} + + ([do: expression2, into: expression], state) -> + fun = create_function_expression(expression2, state, module_state) + + %{state | into: Form.compile!(expression, module_state), fun: fun} + + ([into: expression, do: expression2], state) -> + fun = create_function_expression(expression2, state, module_state) + + %{state | into: Form.compile!(expression, module_state), fun: fun} + + ([do: expression], state) -> + fun = create_function_expression(expression, state, module_state) + + %{state | fun: fun} + (filter, state) -> + fun = create_function_expression(filter, state, module_state) + + %{state | filter: fun} + end) + end + + + defp create_function_expression(ast, state, module_state) do + ast = ast + |> ElixirScript.Translate.Function.compile_block(module_state) + |> elem(0) + |> Clause.return_last_statement + + Helpers.arrow_function( + state.args, + JS.block_statement(ast) + ) + end +end diff --git a/lib/elixir_script/passes/translate/forms/js.ex b/lib/elixir_script/passes/translate/forms/js.ex new file mode 100644 index 00000000..03fb0f0a --- /dev/null +++ b/lib/elixir_script/passes/translate/forms/js.ex @@ -0,0 +1,151 @@ +defmodule ElixirScript.Translate.Forms.JS do + @moduledoc false + alias ESTree.Tools.Builder, as: J + alias ElixirScript.Translate.Helpers + alias ElixirScript.Translate.Form + + def call_property() do + J.member_expression( + Helpers.functions(), + J.identifier("call_property") + ) + end + + def compile({{:., _, [ElixirScript.JS, :debugger]}, _, _}, state) do + ast = J.debugger_statement() + {ast, state} + end + + def compile({{:., _, [ElixirScript.JS, :this]}, _, _}, state) do + ast = J.this_expression() + {ast, state} + end + + def compile({{:., _, [ElixirScript.JS, :new]}, _, [module, params]}, state) do + members = Module.split(module) + + members = case members do + ["JS" | rest] -> + rest + x -> + x + end + + params = case params do + p when is_list(p) -> + Enum.map(params, &Form.compile!(&1, state)) + _ -> + [J.rest_element(Form.compile!(params, state))] + end + + ast = Helpers.new( + ElixirScript.Translate.Identifier.make_namespace_members(members), + params + ) + + {ast, state} + end + + def compile({{:., _, [ElixirScript.JS, :throw]}, _, [term]}, state) do + ast = J.throw_statement( + Form.compile!(term, state) + ) + + {ast, state} + end + + def compile({{:., _, [ElixirScript.JS, :import]}, _, [term]}, state) do + ast = Helpers.call( + J.identifier("import"), + [Form.compile!(term, state)] + ) + + {ast, state} + end + + def compile({{:., _, [ElixirScript.JS, :mutate]}, _, [object, map]}, state) do + ast = Helpers.call( + J.member_expression( + J.identifier("Object"), + J.identifier("assign") + ), + [ + Form.compile!(object, state), + Form.compile!(map, state) + ] + ) + + {ast, state} + end + + def compile({{:., _, [ElixirScript.JS, :mutate]}, _, [object, key, value]}, state) do + ast = Helpers.assign( + J.member_expression( + Form.compile!(object, state), + Form.compile!(key, state), + true + ), + Form.compile!(value, state) + ) + + {ast, state} + end + + def compile({{:., _, [ElixirScript.JS, :map_to_object]}, _, [map]}, state) do + ast = Helpers.call( + J.member_expression( + Helpers.functions(), + J.identifier("map_to_object") + ), + [ + Form.compile!(map, state) + ] + ) + + {ast, state} + end + + def compile({{:., _, [ElixirScript.JS, :map_to_object]}, _, [map, options]}, state) do + ast = Helpers.call( + J.member_expression( + Helpers.functions(), + J.identifier("map_to_object") + ), + [ + Form.compile!(map, state), + Form.compile!(options, state) + ] + ) + + {ast, state} + end + + def compile({{:., _, [ElixirScript.JS, :object_to_map]}, _, [object]}, state) do + ast = Helpers.call( + J.member_expression( + Helpers.functions(), + J.identifier("object_to_map") + ), + [ + Form.compile!(object, state) + ] + ) + + {ast, state} + end + + def compile({{:., _, [ElixirScript.JS, :object_to_map]}, _, [object, options]}, state) do + ast = Helpers.call( + J.member_expression( + Helpers.functions(), + J.identifier("object_to_map") + ), + [ + Form.compile!(object, state), + Form.compile!(options, state) + ] + ) + + {ast, state} + end +end diff --git a/lib/elixir_script/passes/translate/forms/map.ex b/lib/elixir_script/passes/translate/forms/map.ex new file mode 100644 index 00000000..19ae42e4 --- /dev/null +++ b/lib/elixir_script/passes/translate/forms/map.ex @@ -0,0 +1,71 @@ +defmodule ElixirScript.Translate.Forms.Map do + @moduledoc false + alias ESTree.Tools.Builder, as: J + alias ElixirScript.Translate.{Form, Helpers} + + def compile({:%{}, _, [{:|, _, [map, new_values]}]}, state) do + { map, state } = Form.compile(map, state) + data = Enum.map(new_values, fn {x, y} -> + J.array_expression([ + Form.compile!(x, state), + Form.compile!(y, state) + ]) + end) + + ast = Helpers.new( + J.identifier("Map"), + [ + J.array_expression( + [J.spread_element(map)] ++ data + ) + ] + ) + + { ast, state } + end + + def compile({:%{}, _, properties}, state) do + ast = Helpers.new( + J.identifier("Map"), + [ + J.array_expression( + Enum.map(properties, fn + {x, y} -> + J.array_expression( + [ + Form.compile!(x, state), + Form.compile!(y, state) + ] + ) + end) + ) + ] + ) + + {ast, state} + end + + def make_property(%ESTree.Identifier{} = key, value) do + J.property(key, value) + end + + def make_property(%ESTree.Literal{value: k}, value) when is_binary(k) do + key = case String.contains?(k, "-") do + true -> + J.literal(k) + false -> + ElixirScript.Translate.Identifier.make_identifier(k) + end + + J.property(key, value) + end + + def make_property(key, value) do + J.property(key, value, :init, false, false, true) + end + + def make_shorthand_property(%ESTree.Identifier{} = key) do + J.property(key, key, :init, true) + end + +end diff --git a/lib/elixir_script/passes/translate/forms/match.ex b/lib/elixir_script/passes/translate/forms/match.ex new file mode 100644 index 00000000..f09a3259 --- /dev/null +++ b/lib/elixir_script/passes/translate/forms/match.ex @@ -0,0 +1,146 @@ +defmodule ElixirScript.Translate.Forms.Match do + @moduledoc false + + alias ESTree.Tools.Builder, as: J + alias ElixirScript.Translate.Helpers + alias ElixirScript.Translate.Form + alias ElixirScript.Translate.Forms.Pattern + + def compile({:=, _, [left, right]}, state) do + build_matches(left, right, %{patterns: []}) + |> compile_match(state) + end + + defp make_list_ref(array_pattern, params) do + {ref, params} = make_params(params) + ref_declaration = Helpers.declare(ref, J.array_expression(params)) + + [array_pattern, ref_declaration] + end + + defp make_tuple_ref(array_pattern, params) do + {ref, params} = make_params(params) + + ref_declaration = Helpers.declare(ref, Helpers.new( + Helpers.tuple(), + params + )) + [array_pattern, ref_declaration] + end + + + defp make_params(params) do + ref = J.identifier("_ref#{:rand.uniform(10000000)}") + + params = Enum.map(params, fn + (nil) -> J.identifier(:undefined) + (x) -> x + end) + + { ref, params } + end + + defp build_matches(pattern, {:=, _, [left, right]}, parts) do + parts = parts + |> Map.update!(:patterns, fn(x) -> x ++ [pattern] end) + + build_matches(left, right, parts) + end + + defp build_matches(left, right, parts) do + parts + |> Map.update!(:patterns, fn(x) -> x ++ [left] end) + |> Map.put(:expression, right) + end + + defp compile_match(%{patterns: [left], expression: right}, state) do + { right_ast, state } = Form.compile(right, state) + + {var_decs, right_ast} = case right_ast do + x when is_list(x) -> + l = Enum.reverse(x) + [head | tail] = l + l = Enum.reverse(tail) + + {l, head} + x -> + {[], x} + end + + { patterns, params, state } = Pattern.compile([left], state) + + array_pattern = Helpers.declare(params, Helpers.call( + J.member_expression( + Helpers.patterns(), + J.identifier("match") + ), + [hd(patterns), right_ast] + )) + + js_ast = case left do + list when is_list(list) -> + make_list_ref(array_pattern, params) + { _, _ } -> + make_tuple_ref(array_pattern, params) + {:{}, _, _ } -> + make_tuple_ref(array_pattern, params) + _ -> + List.wrap(array_pattern) + end + + { var_decs ++ js_ast, state } + end + + defp compile_match(%{patterns: lefts, expression: right}, state) do + { right_ast, state } = Form.compile(right, state) + + {var_dec, right_ast} = case right_ast do + [variable_declaration, x] -> + {variable_declaration, x} + x -> + {nil, x} + end + + intermediate_assign = Helpers.assign( + J.identifier("__intermediate__"), + right_ast + ) + + {js_ast, state} = Enum.map_reduce(lefts, state, fn(left, state) -> + { patterns, params, state } = Pattern.compile([left], state) + + array_pattern = Helpers.declare(params, Helpers.call( + J.member_expression( + Helpers.patterns(), + J.identifier("match") + ), + [hd(patterns), J.identifier("__intermediate__")] + )) + + js_ast = case left do + list when is_list(list) -> + make_list_ref(array_pattern, params) + { _, _ } -> + make_tuple_ref(array_pattern, params) + {:{}, _, _ } -> + make_tuple_ref(array_pattern, params) + _ -> + List.wrap(array_pattern) + end + + js_ast = case var_dec do + nil -> + js_ast + x -> + [x] ++ js_ast + end + + { js_ast, state } + end) + + js_ast = [intermediate_assign] ++ List.flatten(js_ast) + + {js_ast, state} + end + +end diff --git a/lib/elixir_script/passes/translate/forms/pattern.ex b/lib/elixir_script/passes/translate/forms/pattern.ex new file mode 100644 index 00000000..a671178a --- /dev/null +++ b/lib/elixir_script/passes/translate/forms/pattern.ex @@ -0,0 +1,255 @@ +defmodule ElixirScript.Translate.Forms.Pattern do + alias ElixirScript.Translate.Forms.Pattern.Patterns, as: PM + alias ESTree.Tools.Builder, as: J + alias ElixirScript.Translate.Helpers + alias ElixirScript.Translate.Form + alias ElixirScript.Translate.Forms.Bitstring + + @moduledoc false + + @doc """ + Handles all pattern matching translations + """ + @spec compile(list(), map()) :: { list(), list(), map() } + def compile(patterns, state) do + patterns + |> do_compile(state) + |> update_env(state) + end + + defp do_compile(patterns, state) do + Enum.reduce(patterns, {[], []}, fn + x, { patterns, params } -> + {pattern, param} = process_pattern(x, state) + { patterns ++ List.wrap(pattern), params ++ List.wrap(param) } + end) + end + + defp update_env({ patterns, params }, state) do + { params, state } = Enum.map_reduce(params, state, fn + (%ESTree.Identifier{name: :undefined} = param, state) -> + { param, state } + + (%ESTree.Identifier{} = param, state) -> + state = update_variable(param.name, state) + new_name = get_variable_name(param.name, state) + + { %{ param | name: new_name }, state } + + (param, state) -> + { param, state } + end) + + { patterns, params, state } + end + + @spec get_variable_name(atom(), map()) :: atom() + def get_variable_name(function, state) do + number = Map.get(state.vars, function) + String.to_atom("#{function}#{number}") + end + + defp update_variable(name, state) do + vars = Map.update(state.vars, name, 0, fn val -> val + 1 end) + Map.put(state, :vars, vars) + end + + defp process_pattern(term, state) when is_number(term) or is_binary(term) or is_boolean(term) or is_atom(term) or is_nil(term) do + { [Form.compile!(term, state)], [] } + end + + defp process_pattern({:^, _, [value]}, state) do + { [PM.bound(Form.compile!(value, state))], [] } + end + + defp process_pattern({:_, _, _}, _) do + { [PM.parameter(J.literal("_"))], [] } + end + + defp process_pattern({a, b}, state) do + process_pattern({:{}, [], [a, b] }, state) + end + + defp process_pattern({:{}, _, elements }, state) do + { patterns, params } = elements + |> Enum.map(&do_compile([&1], state)) + |> reduce_patterns(state) + + pattern = J.object_expression([ + J.property( + J.identifier("values"), + J.array_expression(patterns) + ) + ]) + + tuple = Helpers.tuple() + + { [PM.type(tuple, pattern)], params } + end + + defp process_pattern([{:|, _, [head, tail]}], state) do + { head_patterns, head_params } = process_pattern(head, state) + { tail_patterns, tail_params } = process_pattern(tail, state) + params = head_params ++ tail_params + + { [PM.head_tail(hd(head_patterns), hd(tail_patterns))], params } + end + + defp process_pattern(list, state) when is_list(list) do + { patterns, params } = list + |> Enum.map(&do_compile([&1], state)) + |> reduce_patterns(state) + + {[J.array_expression(patterns)], params} + end + + defp process_pattern({:|, _, [head, tail]}, state) do + { head_patterns, head_params } = process_pattern(head, state) + { tail_patterns, tail_params } = process_pattern(tail, state) + params = head_params ++ tail_params + + { [PM.head_tail(hd(head_patterns), hd(tail_patterns))], params } + end + + defp process_pattern({{:., _, [:erlang, :++]}, context, [head, tail]}, state) do + process_pattern({:|, context, [head, tail]}, state) + end + + defp process_pattern({:%, _, [module, {:%{}, _, props}]}, state) do + process_pattern({:%{}, [], [__module__struct__: module] ++ props}, state) + end + + defp process_pattern({:%{}, _, props}, state) do + properties = Enum.map(props, fn + {:__module__struct__, {_, _, nil} = var } -> + {pattern, params} = process_pattern(var, state) + + a = J.object_expression([%ESTree.Property{ + key: J.identifier("__MODULE__"), + value: hd(List.wrap(pattern)) + }]) + + property = J.array_expression([ + Form.compile!(:__struct__, state), + a + ]) + + { property, params } + + {:__module__struct__, module} -> + a = J.object_expression([%ESTree.Property{ + key: J.identifier("__MODULE__"), + value: Helpers.symbol(to_string(module)) + }]) + + property = J.array_expression([ + Form.compile!(:__struct__, state), + a + ]) + + { property, [] } + + {key, value} -> + {pattern, params} = process_pattern(value, state) + property = case key do + {:^, _, [the_key]} -> + J.array_expression([ + Form.compile!(the_key, state), + hd(List.wrap(pattern)) + ]) + _ -> + J.array_expression([ + Form.compile!(key, state), + hd(List.wrap(pattern)) + ]) + end + + { property, params } + end) + + {props, params} = Enum.reduce(properties, {[], []}, fn({prop, param}, {props, params}) -> + { props ++ [prop], params ++ param } + end) + + ast = Helpers.new( + J.identifier("Map"), + [ + J.array_expression(List.wrap(props)) + ] + ) + + { [ast], params } + end + + defp process_pattern({:<<>>, _, elements}, state) do + params = Enum.reduce(elements, [], fn + ({:::, _, [{ _, _, params } = ast, _]}, state) when is_nil(params) + when is_list(params) and length(params) == 0 -> + + var_str = make_identifier(ast) + var_atom = String.to_atom(var_str) + state ++ [ElixirScript.Translate.Identifier.make_identifier(var_atom)] + _, state -> + state + end) + + elements = Enum.map(elements, fn + ({:::, context, [{ _, _, params }, options]}) when is_atom(params) -> + Bitstring.compile_element({:::, context, [ElixirScript.Translate.Forms.Pattern.Patterns, options]}, state) + x -> + Bitstring.compile_element(x, state) + end) + + { [PM.bitstring_match(elements)], params } + end + + defp process_pattern({:<>, _, [prefix, value]}, state) do + { [PM.starts_with(prefix)], [Form.compile!(value, state)] } + end + + defp process_pattern({:=, _, [{name, _, _} = target, right]}, state) when name not in [:%, :{}, :^, :%{}, :<<>>] do + unify(target, right, state) + end + + defp process_pattern({:=, _, [left, {name, _, _} = target]}, state) when name not in [:%, :{}, :^, :%{}, :<<>>] do + unify(target, left, state) + end + + defp process_pattern({_, _, a} = ast, _) when is_atom(a) do + var_str = make_identifier(ast) + var_atom = String.to_atom(var_str) + { [PM.parameter(J.literal(var_str))], [ElixirScript.Translate.Identifier.make_identifier(var_atom)] } + end + + defp process_pattern(ast, state) do + { [Form.compile!(ast, state)], [] } + end + + defp reduce_patterns(patterns, _) do + patterns + |> Enum.reduce({ [], [] }, fn({ pattern, new_param }, { patterns, new_params }) -> + { patterns ++ List.wrap(pattern), new_params ++ List.wrap(new_param) } + end) + end + + defp unify(target, source, state) do + { patterns, params } = do_compile([source], state) + { [_] , [param] } = process_pattern(target, state) + { [PM.capture(hd(patterns))], params ++ [param] } + end + + def get_counter(meta) do + case Keyword.get(meta, :counter, nil) do + nil -> "" + {module, value} -> + value + |> Kernel.abs() + |> to_string() + end + end + + defp make_identifier({var, meta, _}) do + counter = get_counter(meta) + to_string(var) <> counter + end +end diff --git a/lib/elixir_script/passes/translate/forms/pattern/patterns.ex b/lib/elixir_script/passes/translate/forms/pattern/patterns.ex new file mode 100644 index 00000000..eb873149 --- /dev/null +++ b/lib/elixir_script/passes/translate/forms/pattern/patterns.ex @@ -0,0 +1,97 @@ +defmodule ElixirScript.Translate.Forms.Pattern.Patterns do + @moduledoc false + + alias ESTree.Tools.Builder, as: J + alias ElixirScript.Translate.Helpers + + @parameter J.member_expression( + Helpers.patterns(), + J.identifier(:variable) + ) + + @head_tail J.member_expression( + Helpers.patterns(), + J.identifier(:headTail) + ) + + @starts_with J.member_expression( + Helpers.patterns(), + J.identifier(:startsWith) + ) + + @capture J.member_expression( + Helpers.patterns(), + J.identifier(:capture) + ) + + @bound J.member_expression( + Helpers.patterns(), + J.identifier(:bound) + ) + + @_type J.member_expression( + Helpers.patterns(), + J.identifier(:type) + ) + + @bitstring_match J.member_expression( + Helpers.patterns(), + J.identifier(:bitStringMatch) + ) + + def parameter() do + Helpers.call( + @parameter, + [] + ) + end + + def parameter(name) do + Helpers.call( + @parameter, + [name] + ) + end + + def head_tail(headParameter, tailParameter) do + Helpers.call( + @head_tail, + [headParameter, tailParameter] + ) + end + + def starts_with(prefix) do + Helpers.call( + @starts_with, + [J.literal(prefix)] + ) + end + + def capture(value) do + Helpers.call( + @capture, + [value] + ) + end + + def bound(value) do + Helpers.call( + @bound, + [value] + ) + end + + def type(prototype, value) do + Helpers.call( + @_type, + [prototype, value] + ) + end + + def bitstring_match(values) do + Helpers.call( + @bitstring_match, + values + ) + end +end diff --git a/lib/elixir_script/passes/translate/forms/receive.ex b/lib/elixir_script/passes/translate/forms/receive.ex new file mode 100644 index 00000000..1186c285 --- /dev/null +++ b/lib/elixir_script/passes/translate/forms/receive.ex @@ -0,0 +1,51 @@ +defmodule ElixirScript.Translate.Forms.Receive do + @moduledoc false + alias ESTree.Tools.Builder, as: J + alias ElixirScript.Translate.{Helpers, Form, Function, Clause} + + @doc """ + receive is not supported just yet, but we compile it + to a stub function for now + """ + def compile(blocks, state) do + receive_block = blocks + |> Keyword.get(:do, []) + |> Enum.map(fn x -> + Clause.compile(x, state) + |> elem(0) + end) + |> List.flatten + |> J.array_expression() + + receive_function = J.member_expression( + Helpers.special_forms(), + J.identifier("receive") + ) + + after_block = Keyword.get(blocks, :after, nil) + args = [receive_block] ++ process_after(after_block, state) + + ast = Helpers.call( + receive_function, + args + ) + + { ast, state } + end + + defp process_after(nil, _) do + [] + end + + defp process_after([{:->, _, [[timeout], body]}], state) do + timeout = Form.compile!(timeout, state) + {body, _state} = Function.compile_block(body, state) + + function = Helpers.arrow_function( + [], + J.block_statement(List.wrap(body)) + ) + + [timeout, function] + end +end diff --git a/lib/elixir_script/passes/translate/forms/remote.ex b/lib/elixir_script/passes/translate/forms/remote.ex new file mode 100644 index 00000000..fda121fe --- /dev/null +++ b/lib/elixir_script/passes/translate/forms/remote.ex @@ -0,0 +1,166 @@ +defmodule ElixirScript.Translate.Forms.Remote do + @moduledoc false + + alias ESTree.Tools.Builder, as: J + alias ElixirScript.Translate.{Form, Helpers} + alias ElixirScript.State, as: ModuleState + + @erlang_modules [ + :erlang, + :maps, + :lists, + :gen, + :elixir_errors, + :elixir_config, + :supervisor, + :application, + :code, + :elixir_utils, + :file, + :io, + :binary, + :unicode, + :math, + :calendar, + :filename, + :epp, + :re, + :ets, + :sys, + :global, + :os, + :rand, + :orddict, + :filelib, + :net_adm, + :net_kernel + ] + + @doc """ + Compiles functions into JavaScript AST. + These are not actual function calls, but + the function identifiers themselves. Also + includes function heads for converting some + erlang functions into JavaScript functions. + """ + + def compile({:., _, [:erlang, :++]}, state) do + ast = erlang_compat_function("erlang", "list_concatenation") + {ast, state} + end + + def compile({:., _, [:erlang, :--]}, state) do + ast = erlang_compat_function("erlang", "list_substraction") + {ast, state} + end + + def compile({:., _, [:erlang, :"=<"]}, state) do + ast = erlang_compat_function("erlang", "lessThanEqualTo") + {ast, state} + end + + def compile({:., _, [:erlang, :+]}, state) do + ast = erlang_compat_function("erlang", "add") + {ast, state} + end + + def compile({:., _, [module, function]}, state) when module in @erlang_modules do + ast = + J.member_expression( + Helpers.core_module(module), + J.identifier(function) + ) + + {ast, state} + end + + def compile({:., _, [function_name]}, state) do + Form.compile(function_name, state) + end + + def compile({:., _, [module, function]}, state) do + function_name = ElixirScript.Translate.Identifier.make_function_name(function) + + ast = + J.member_expression( + process_module_name(module, state), + function_name + ) + + {ast, state} + end + + def process_module_name(module, state) when is_atom(module) do + cond do + ElixirScript.Translate.Module.is_js_module(module, state) and + ModuleState.is_global_module(state.pid, module) -> + process_global_js_module_name(module, state) + + ElixirScript.Translate.Module.is_js_module(module, state) -> + process_js_module_name(module, state) + + module === Elixir -> + module + |> ElixirScript.Output.module_to_name() + |> J.identifier() + + module === :ElixirScript -> + module + |> ElixirScript.Output.module_to_name() + |> J.identifier() + + ElixirScript.Translate.Module.is_elixir_module(module) -> + module + |> ElixirScript.Output.module_to_name() + |> J.identifier() + + true -> + ElixirScript.Translate.Identifier.make_identifier(module) + end + end + + def process_module_name(module, state) do + Form.compile!(module, state) + end + + defp process_global_js_module_name(module, state) do + case ModuleState.get_js_module_name(state.pid, module) do + name when is_binary(name) -> + J.identifier(name) + + name when is_atom(name) -> + case to_string(name) do + "Elixir." <> _ -> + ElixirScript.Translate.Identifier.make_alias(Module.split(name) |> Enum.reverse()) + + x -> + J.identifier(x) + end + end + end + + defp process_js_module_name(module, state) do + case ModuleState.get_js_module_name(state.pid, module) do + name when is_binary(name) -> + J.identifier(name) + + name when is_atom(name) -> + case to_string(name) do + "Elixir." <> _ -> + module + |> ElixirScript.Output.module_to_name() + |> J.identifier() + + x -> + J.identifier(x) + end + end + end + + defp erlang_compat_function(module, function) do + J.member_expression( + Helpers.core_module(module), + ElixirScript.Translate.Identifier.make_function_name(function) + ) + end +end diff --git a/lib/elixir_script/passes/translate/forms/try.ex b/lib/elixir_script/passes/translate/forms/try.ex new file mode 100644 index 00000000..3d3c1283 --- /dev/null +++ b/lib/elixir_script/passes/translate/forms/try.ex @@ -0,0 +1,122 @@ +defmodule ElixirScript.Translate.Forms.Try do + @moduledoc false + alias ESTree.Tools.Builder, as: JS + alias ElixirScript.Translate.{Form, Function, Clause, Helpers} + + def compile(blocks, state) do + try_block = Keyword.get(blocks, :do) + rescue_block = Keyword.get(blocks, :rescue, nil) + catch_block = Keyword.get(blocks, :catch, nil) + after_block = Keyword.get(blocks, :after, nil) + else_block = Keyword.get(blocks, :else, nil) + + translated_body = prepare_function_body(try_block, state) + + translated_body = JS.block_statement(translated_body) + try_block = Helpers.arrow_function([], translated_body) + + rescue_block = if rescue_block do + process_rescue_block(rescue_block, state) + else + JS.identifier(:null) + end + + catch_block = if catch_block do + Form.compile!({:fn, [], catch_block}, state) + else + JS.identifier(:null) + end + + after_block = if after_block do + process_after_block(after_block, state) + else + JS.identifier(:null) + end + + else_block = if else_block do + Form.compile!({:fn, [], else_block}, state) + else + JS.identifier(:null) + end + + js_ast = Helpers.call( + JS.member_expression( + Helpers.special_forms(), + JS.identifier("_try") + ), + [ + try_block, + rescue_block, + catch_block, + else_block, + after_block + ] + ) + + { js_ast, state } + end + + defp process_rescue_block(rescue_block, state) do + processed_clauses = Enum.map(rescue_block, fn + {:->, _, [ [{:in, _, [{:_, context, atom}, names]}], body]} -> + names = Enum.map(names, &make_exception_ast(&1)) + + param = {:_e, context, atom} + reason_call = {{:., [], [param, :__reason]}, [], []} + reason_call = {{:., [], [reason_call, :__struct__]}, [], []} + reason_call = {{:., [], [reason_call, :__MODULE__]}, [], []} + + {ast, _} = Clause.compile({ + [], + [param], + [{{:., [], [Enum, :member?]}, [], [names, reason_call]}], + body}, + state) + ast + {:->, _, [ [{:in, _, [param, names]}], body]} -> + names = Enum.map(names, &make_exception_ast(&1)) + + reason_call = {{:., [], [param, :__reason]}, [], []} + reason_call = {{:., [], [reason_call, :__struct__]}, [], []} + reason_call = {{:., [], [reason_call, :__MODULE__]}, [], []} + + {ast, _} = Clause.compile({ + [], + [param], + [{{:., [], [Enum, :member?]}, [], [names, reason_call]}], + body}, + state) + ast + {:->, _, [ [param], body]} -> + {ast, _} = Clause.compile({[], [param], [], body}, state) + ast + end) + + + Helpers.call( + JS.member_expression( + Helpers.patterns(), + JS.identifier("defmatch") + ), + processed_clauses + ) + + end + + defp make_exception_ast(name) do + {{:., [], [name, :__MODULE__]}, [], []} + end + + defp process_after_block(after_block, state) do + translated_body = prepare_function_body(after_block, state) + translated_body = JS.block_statement(translated_body) + + Helpers.arrow_function([], translated_body) + end + + defp prepare_function_body(body, state) do + {ast, _} = Function.compile_block(body, state) + + Clause.return_last_statement(ast) + end +end diff --git a/lib/elixir_script/passes/translate/forms/with.ex b/lib/elixir_script/passes/translate/forms/with.ex new file mode 100644 index 00000000..2bc5ea08 --- /dev/null +++ b/lib/elixir_script/passes/translate/forms/with.ex @@ -0,0 +1,55 @@ +defmodule ElixirScript.Translate.Forms.With do + @moduledoc false + alias ESTree.Tools.Builder, as: JS + alias ElixirScript.Translate.{Function, Clause, Helpers} + alias ElixirScript.Translate.Forms.Pattern + + + def compile(args, module_state) do + result = Enum.reduce(args, %{ expressions: [], arguments: [], module_state: module_state }, fn + {symbol, _, [pattern, body] }, state when symbol in [:<-, :=] -> + {ast, module_state} = Function.compile_block(body, state.module_state) + body = Clause.return_last_statement(ast) + expr_function = Helpers.arrow_function(state.arguments, JS.block_statement(body)) + + { patterns, params, module_state } = Pattern.compile([pattern], module_state) + + %{state | arguments: state.arguments ++ params, + expressions: state.expressions ++ [ JS.array_expression([hd(patterns), expr_function]) ], + module_state: module_state + } + + [do: expr], state -> + expr_function = process_block(expr, state.arguments, state.module_state) + + %{state | expressions: state.expressions ++ [ expr_function ] } + [do: do_expr, else: else_expr], state -> + do_function = process_block(do_expr, state.arguments, state.module_state) + + { else_function, _ } = Function.compile({:fn, [], else_expr}, state.module_state) + + %{state | expressions: state.expressions ++ [ do_function, else_function ] } + end) + + expressions = result.expressions + + js_ast = Helpers.call( + JS.member_expression( + Helpers.special_forms(), + JS.identifier("_with") + ), + expressions + ) + + { js_ast, module_state } + + end + + + defp process_block(body, arguments, module_state) do + {ast, _} = Function.compile_block(body, module_state) + + body = Clause.return_last_statement(ast) + Helpers.arrow_function(arguments, JS.block_statement(body)) + end +end diff --git a/lib/elixir_script/passes/translate/function.ex b/lib/elixir_script/passes/translate/function.ex new file mode 100644 index 00000000..dc0ff282 --- /dev/null +++ b/lib/elixir_script/passes/translate/function.ex @@ -0,0 +1,234 @@ +defmodule ElixirScript.Translate.Function do + @moduledoc false + + # Translates the given Elixir function AST into the + # equivalent JavaScript AST. + + alias ESTree.Tools.Builder, as: J + alias ElixirScript.Translate.{Clause, Form, Helpers} + alias ElixirScript.Translate.Forms.Pattern + + @spec compile(any, map) :: {ESTree.Node.t, map} + def compile({:fn, _, clauses}, state) do + anonymous? = Map.get(state, :anonymous_fn, false) + + state = Map.put(state, :anonymous_fn, true) + |> Map.put(:in_guard, false) + + clauses = compile_clauses(clauses, state) + + arg_matches_declaration = Helpers.declare_let("__arg_matches__", J.identifier("null")) + + function_recur_dec = Helpers.function( + "recur", + [J.rest_element(J.identifier("__function_args__"))], + J.block_statement([ + arg_matches_declaration, + clauses, + J.throw_statement( + Helpers.new( + J.member_expression( + Helpers.patterns(), + J.identifier("MatchError") + ), + [J.identifier("__function_args__")] + ) + ) + ]) + ) + + function_dec = Helpers.arrow_function( + [J.rest_element(J.identifier("__function_args__"))], + J.block_statement([ + function_recur_dec, + J.return_statement( + trampoline() + ) + ]) + ) + + state = Map.put(state, :anonymous_fn, anonymous?) + { function_dec, state } + end + + def compile({{name, arity}, _type, _, clauses}, state) do + + state = Map.put(state, :function, {name, arity}) + |> Map.put(:anonymous_fn, false) + |> Map.put(:in_guard, false) + + clauses = compile_clauses(clauses, state) + + arg_matches_declaration = Helpers.declare_let("__arg_matches__", J.identifier("null")) + intermediate_declaration = Helpers.declare_let("__intermediate__", J.identifier("null")) + + function_recur_dec = Helpers.function( + "recur", + [J.rest_element(J.identifier("__function_args__"))], + J.block_statement([ + arg_matches_declaration, + intermediate_declaration, + clauses, + J.throw_statement( + Helpers.new( + J.member_expression( + Helpers.patterns(), + J.identifier("MatchError") + ), + [J.identifier("__function_args__")] + ) + ) + ]) + ) + + function_dec = Helpers.function( + ElixirScript.Translate.Identifier.make_function_name(name), + [J.rest_element(J.identifier("__function_args__"))], + J.block_statement([ + function_recur_dec, + J.return_statement( + trampoline() + ) + ]) + ) + + { function_dec, state } + end + + defp compile_clauses(clauses, state) do + clauses + |> Enum.map(&compile_clause(&1, state)) + |> Enum.map(fn {patterns, _params, guards, body} -> + match_or_default_call = Helpers.call( + J.member_expression( + Helpers.patterns(), + J.identifier("match_or_default") + ), + [J.array_expression(patterns), J.identifier("__function_args__"), guards] + ) + + J.if_statement( + J.binary_expression( + :!==, + Helpers.assign(J.identifier("__arg_matches__"), match_or_default_call), + J.identifier("null") + ), + J.block_statement(body) + ) + end) + |> Enum.reverse + |> Enum.reduce(nil, fn + if_ast, nil -> + if_ast + if_ast, ast -> + %{if_ast | alternate: ast} + end) + end + + defp compile_clause({ _, args, guards, body}, state) do + state = if Map.has_key?(state, :vars) do + state + else + Map.put(state, :vars, %{}) + end + + {patterns, params, state} = Pattern.compile(args, state) + guard = Clause.compile_guard(params, guards, state) + + {body, _state} = compile_block(body, state) + + body = body + |> Clause.return_last_statement + |> update_last_call(state) + + declaration = Helpers.declare_let(params, J.identifier("__arg_matches__")) + + body = [declaration] ++ body + {patterns, params, guard, body} + end + + defp compile_clause({:->, _, [[{:when, _, params}], body ]}, state) do + guards = List.last(params) + params = params |> Enum.reverse |> tl |> Enum.reverse + + compile_clause({[], params, guards, body}, state) + end + + defp compile_clause({:->, _, [params, body]}, state) do + compile_clause({[], params, [], body}, state) + end + + @spec compile_block(any, map) :: {ESTree.Node.t, map} + def compile_block(block, state) do + ast = case block do + nil -> + J.identifier("null") + {:__block__, _, block_body} -> + {list, _} = Enum.map_reduce(block_body, state, &Form.compile(&1, &2)) + List.flatten(list) + _ -> + Form.compile!(block, state) + end + + {ast, state} + end + + @spec update_last_call([ESTree.Node.t], map) :: list + def update_last_call(clause_body, %{function: {name, _}, anonymous_fn: anonymous?}) do + last_item = List.last(clause_body) + function_name = ElixirScript.Translate.Identifier.make_function_name(name) + + case last_item do + %ESTree.ReturnStatement{ argument: %ESTree.CallExpression{ callee: ^function_name, arguments: arguments } } -> + if anonymous? do + clause_body + else + new_last_item = J.return_statement( + recurse( + recur_bind(arguments) + ) + ) + + List.replace_at(clause_body, length(clause_body) - 1, new_last_item) + end + _ -> + clause_body + end + end + + defp recur_bind(args) do + Helpers.call( + J.member_expression( + J.identifier("recur"), + J.identifier("bind") + ), + [J.identifier("null")] ++ args + ) + end + + defp recurse(func) do + Helpers.new( + J.member_expression( + Helpers.functions(), + J.identifier("Recurse") + ), + [ + func + ] + ) + end + + defp trampoline() do + Helpers.call( + J.member_expression( + Helpers.functions(), + J.identifier("trampoline") + ), + [ + recurse( + recur_bind([J.rest_element(J.identifier("__function_args__"))]) + ) + ] + ) + end +end diff --git a/lib/elixir_script/passes/translate/helpers.ex b/lib/elixir_script/passes/translate/helpers.ex new file mode 100644 index 00000000..227eab39 --- /dev/null +++ b/lib/elixir_script/passes/translate/helpers.ex @@ -0,0 +1,140 @@ +defmodule ElixirScript.Translate.Helpers do + @moduledoc false + alias ESTree.Tools.Builder, as: J + + def symbol(value) do + J.call_expression( + J.member_expression( + J.identifier("Symbol"), + J.identifier("for") + ), + [J.literal(value)] + ) + end + + def new(callee, arguments) do + J.new_expression( + callee, + arguments + ) + end + + def call(callee, arguments) do + J.call_expression( + callee, + arguments + ) + end + + def arrow_function(params, body) do + J.arrow_function_expression( + params, + [], + body + ) + end + + def function(%ESTree.Identifier{} = name, params, body) do + J.function_declaration( + name, + params, + [], + body + ) + end + + def function(name, params, body) when is_binary(name) do + function(J.identifier(name), params, body) + end + + def function(params, body) do + J.function_expression( + params, + [], + body + ) + end + + def core do + J.member_expression( + J.identifier("ElixirScript"), + J.identifier("Core") + ) + end + + def core_module(module) do + J.member_expression( + core(), + J.identifier(module) + ) + end + + def tuple do + core_module("Tuple") + end + + def bitstring do + core_module("BitString") + end + + def patterns do + core_module("Patterns") + end + + def functions do + core_module("Functions") + end + + def special_forms do + core_module("SpecialForms") + end + + def declare(%ESTree.Identifier{} = name, value) do + declarator = J.variable_declarator( + name, + value + ) + + J.variable_declaration([declarator], :const) + end + + def declare(names, value) when is_list(names) do + declarator = J.variable_declarator( + J.array_pattern(names), + value + ) + + J.variable_declaration([declarator], :const) + end + + def declare(name, value) when is_binary(name) do + declare(J.identifier(name), value) + end + + def declare_let(names, value) when is_list(names) do + declarator = J.variable_declarator( + J.array_pattern(names), + value + ) + + J.variable_declaration([declarator], :let) + end + + def declare_let(name, value) do + declarator = J.variable_declarator( + J.identifier(name), + value + ) + + J.variable_declaration([declarator], :let) + end + + def assign(name, value) do + J.assignment_expression( + :=, + name, + value + ) + end + +end diff --git a/lib/elixir_script/translator/kernel/special_forms/identifier.ex b/lib/elixir_script/passes/translate/identifier.ex similarity index 53% rename from lib/elixir_script/translator/kernel/special_forms/identifier.ex rename to lib/elixir_script/passes/translate/identifier.ex index 3639432c..a04f35b8 100644 --- a/lib/elixir_script/translator/kernel/special_forms/identifier.ex +++ b/lib/elixir_script/passes/translate/identifier.ex @@ -1,6 +1,6 @@ -defmodule ElixirScript.Translator.Identifier do +defmodule ElixirScript.Translate.Identifier do @moduledoc false - alias ESTree.Tools.Builder, as: JS + alias ESTree.Tools.Builder, as: J @js_reserved_words [ :break, @@ -35,51 +35,54 @@ defmodule ElixirScript.Translator.Identifier do :yield ] - def make_identifier({:__aliases__, _, aliases}) do - aliases - |> Enum.reverse - |> make_alias - end - - def make_identifier([ast]) do - make_identifier(ast) - end - def make_identifier(ast) do ast |> filter_name - |> JS.identifier + |> J.identifier() end - defp filter_name(reserved_word) when reserved_word in @js_reserved_words do + def filter_name(reserved_word) when reserved_word in @js_reserved_words do "__#{Atom.to_string(reserved_word)}__" end - defp filter_name(name) do - to_string(name) - |> String.replace("?", "__qmark__") - |> String.replace("!", "__emark__") + def filter_name(name) do + name = to_string(name) + + if String.contains?(name, ["?", "!"]) do + name + |> String.replace("?", "__qmark__") + |> String.replace("!", "__emark__") + else + name + end end - defp make_alias([x]) do + def make_alias([x]) do make_identifier(x) end - defp make_alias([h|t]) do - JS.member_expression(make_alias(t), make_identifier(h)) + def make_alias([h | t]) do + J.member_expression(make_alias(t), make_identifier(h)) end def make_namespace_members(module_name) do case module_name do m when is_list(m) -> m - m when is_binary(m) -> - String.split(m, ".") + m when is_atom(m) -> Module.split(m) end - |> Enum.reverse + |> Enum.reverse() |> make_alias - end + end + def make_function_name(name) do + name = filter_name(name) + J.identifier(name) + end + + def js_reserved_words() do + @js_reserved_words + end end diff --git a/lib/elixir_script/passes/translate/module.ex b/lib/elixir_script/passes/translate/module.ex new file mode 100644 index 00000000..831c6848 --- /dev/null +++ b/lib/elixir_script/passes/translate/module.ex @@ -0,0 +1,308 @@ +defmodule ElixirScript.Translate.Module do + @moduledoc false + alias ESTree.Tools.Builder, as: J + alias ElixirScript.Translate.Helpers + alias ElixirScript.Translate.Function + alias ElixirScript.State, as: ModuleState + alias ElixirScript.Translate.Form + + @operators [ + :+, + :-, + :*, + :/, + :!=, + :==, + :===, + :<=, + :>=, + :=~, + :++, + :!==, + :--, + :<, + :>, + :=~ + ] + + @doc """ + Translate the given module's ast to + JavaScript AST + """ + def compile(module, %{protocol: true} = info, pid) do + ElixirScript.Translate.Protocol.compile(module, info, pid) + end + + def compile(_module, %{attributes: [__foreign_info__: %{path: _, name: _, global: _}]}, _) do + nil + end + + def compile(module, info, pid) do + %{ + attributes: attrs, + compile_opts: _compile_opts, + definitions: defs, + file: _file, + line: _line, + module: ^module, + unreachable: unreachable + } = info + + used = Map.get(info, :used) + remove_unused_functions = ModuleState.remove_unused_functions(pid) + + state = %{ + module: module, + pid: pid + } + + # Filter so that we only have the + # Used functions to compile + reachable_defs = + Enum.filter(defs, fn + {_, type, _, _} when type in [:defmacro, :defmacrop] -> false + {name, _, _, _} -> name not in unreachable + _ -> true + end) + + used_defs = + if Keyword.has_key?(attrs, :protocol_impl) or used == nil do + reachable_defs + else + Enum.filter(reachable_defs, fn + {{:start, 2}, _, _, _} -> + true + + {{:__struct__, _}, _, _, _} -> + true + + {{name, _}, _, _, _} when name in @operators -> + false + + {name, _, _, _} -> + if remove_unused_functions do + name in used + else + true + end + + _ -> + false + end) + end + + # we combine our function arities + combined_defs = combine_defs(used_defs) + exports = make_exports(module, combined_defs) + + {compiled_functions, _} = Enum.map_reduce(combined_defs, state, &Function.compile(&1, &2)) + + info_function = make_info_function(module, state) + compiled_functions = [info_function] ++ compiled_functions + + js_ast = [compiled_functions, exports] + + ModuleState.put_module(pid, module, Map.put(info, :js_ast, js_ast)) + end + + defp combine_defs(used_defs) do + used_defs + |> Enum.sort(fn {{name1, arity1}, _, _, _}, {{name2, arity2}, _, _, _} -> + "#{name1}#{arity1}" < "#{name2}#{arity2}" + end) + |> Enum.group_by(fn {{name, _}, _, _, _} -> name end) + |> Enum.map(fn {group, funs} -> + {_, type, _, _} = hd(funs) + + Enum.reduce(funs, {{group, nil}, type, [], []}, fn {_, _, _, clauses}, + {name, type, context, acc_clauses} -> + {name, type, context, acc_clauses ++ clauses} + end) + end) + end + + defp make_exports(module, reachable_defs) do + exports = + Enum.reduce(reachable_defs, [], fn + {{name, _arity}, :def, _, _}, list -> + function_name = ElixirScript.Translate.Identifier.make_identifier(name) + list ++ [J.property(function_name, function_name, :init, true)] + + _, list -> + list + end) + + # Add an attribute to use to determine if this is a module + # Will be used by the is_atom implementation + exports = + exports ++ + [ + %ESTree.Property{ + key: J.identifier("__MODULE__"), + value: Helpers.symbol(to_string(module)) + }, + J.property( + J.identifier("__info__"), + J.identifier("__info__"), + :init, + true + ) + ] + + J.object_expression(exports) + end + + @doc """ + Determins if the given atom + is an Elixir function + """ + def is_elixir_module(module) when is_atom(module) do + str_module = Atom.to_string(module) + + case str_module do + "Elixir" <> _ -> + true + + _ -> + false + end + end + + def is_elixir_module(_) do + false + end + + @doc """ + Determines is given function is a JS module. + A JS module is either one that begins with "JS" + or is a module defined from the js_modules compiler + opt + """ + def is_js_module(module, state) do + cond do + module in ModuleState.list_javascript_modules(state.pid) -> + true + + module === Elixir -> + false + + true -> + false + end + end + + defp make_info_map(module, state) do + functions = + module.__info__(:functions) + |> Form.compile!(state) + + macros = + module.__info__(:macros) + |> Form.compile!(state) + + attributes = + module.__info__(:attributes) + |> Form.compile!(state) + + compile = + module.__info__(:compile) + |> Keyword.update(:source, "", fn x -> :erlang.list_to_binary(x) end) + |> Form.compile!(state) + + md5 = + module.__info__(:md5) + |> :erlang.binary_to_list() + + md5 = Form.compile!({:<<>>, [], md5}, state) + + module = Helpers.symbol(to_string(module)) + + map_entries = + J.array_expression([ + J.array_expression([ + Helpers.symbol("functions"), + functions + ]), + J.array_expression([ + Helpers.symbol("macros"), + macros + ]), + J.array_expression([ + Helpers.symbol("attributes"), + attributes + ]), + J.array_expression([ + Helpers.symbol("compile"), + compile + ]), + J.array_expression([ + Helpers.symbol("md5"), + md5 + ]), + J.array_expression([ + Helpers.symbol("module"), + module + ]) + ]) + + map = + Helpers.new(J.identifier("Map"), [ + map_entries + ]) + + Helpers.declare("__info__map__", map) + end + + # Builds the __info__ function that Elixir modules + # have. + defp make_info_function(module, state) do + info_map = make_info_map(module, state) + + get_call = + Helpers.call( + J.member_expression( + J.identifier("__info__map__"), + J.identifier("get") + ), + [ + J.identifier("kind") + ] + ) + + value = Helpers.declare("value", get_call) + + body = + J.if_statement( + J.binary_expression( + :!==, + J.identifier("value"), + J.identifier("null") + ), + J.block_statement([ + J.return_statement(J.identifier("value")) + ]) + ) + + body = + J.block_statement([ + info_map, + value, + body, + J.throw_statement( + Helpers.new( + J.member_expression( + Helpers.patterns(), + J.identifier("MatchError") + ), + [J.identifier("kind")] + ) + ) + ]) + + Helpers.function( + "__info__", + [J.identifier("kind")], + body + ) + end +end diff --git a/lib/elixir_script/passes/translate/protocol.ex b/lib/elixir_script/passes/translate/protocol.ex new file mode 100644 index 00000000..ceaddcad --- /dev/null +++ b/lib/elixir_script/passes/translate/protocol.ex @@ -0,0 +1,115 @@ +defmodule ElixirScript.Translate.Protocol do + @moduledoc false + alias ESTree.Tools.Builder, as: J + alias ElixirScript.Translate.Helpers + alias ElixirScript.Translate.{Function, Identifier} + alias ElixirScript.State, as: ModuleState + + + @doc """ + This compiles and consolidates the given protocol + """ + def compile(module, %{protocol: true, impls: impls, functions: functions} = info, pid) do + object = Enum.map(functions, fn {function, _} -> + {Identifier.make_function_name(function), Helpers.function([], J.block_statement([]))} + end) + |> Enum.map(fn({key, value}) -> ElixirScript.Translate.Forms.Map.make_property(key, value) end) + |> J.object_expression + + declaration = Helpers.declare( + "protocol", + Helpers.call( + J.member_expression( + Helpers.functions(), + J.identifier(:defprotocol) + ), + [object] + ) + ) + + body = build_implementations(impls) + + body = [declaration] ++ body + + js_ast = [body, J.identifier("protocol")] + + ModuleState.put_module(pid, module, Map.put(info, :js_ast, js_ast)) + end + + defp build_implementations(impls) do + Enum.map(impls, fn({impl, impl_for}) -> + ast = impl + |> ElixirScript.Output.module_to_name() + |> J.identifier + + Helpers.call( + J.member_expression( + Helpers.functions(), + J.identifier(:defimpl) + ), + [ + J.identifier("protocol"), + map_to_js(impl_for), + ast + ] + ) + end) + end + + defp map_to_js(Integer) do + Helpers.core_module("Integer") + end + + defp map_to_js(Tuple) do + Helpers.tuple() + end + + defp map_to_js(Atom) do + J.identifier(:Symbol) + end + + defp map_to_js(List) do + J.identifier(:Array) + end + + defp map_to_js(BitString) do + Helpers.bitstring() + end + + defp map_to_js(Float) do + Helpers.core_module("Float") + end + + defp map_to_js(Function) do + J.identifier(:Function) + end + + defp map_to_js(PID) do + Helpers.core_module("PID") + end + + defp map_to_js(Port) do + Helpers.core_module("Port") + end + + defp map_to_js(Reference) do + Helpers.core_module("Reference") + end + + defp map_to_js(Map) do + J.identifier(:Map) + end + + defp map_to_js(Any) do + J.identifier(:null) + end + + defp map_to_js(module) when is_atom(module) do + case Module.split(module) do + ["JS" | rest] -> + Identifier.make_namespace_members(rest) + _ -> + Helpers.symbol(module) + end + end +end diff --git a/lib/elixir_script/state.ex b/lib/elixir_script/state.ex new file mode 100644 index 00000000..37d0473f --- /dev/null +++ b/lib/elixir_script/state.ex @@ -0,0 +1,175 @@ +defmodule ElixirScript.State do + @moduledoc false + + # Holds the state for the ElixirScript compiler + + def start_link(compiler_opts) do + Agent.start_link(fn -> + %{ + modules: Keyword.new(), + js_modules: [], + in_memory_modules: [], + compiler_opts: compiler_opts + } + end) + end + + def stop(pid) do + Agent.stop(pid) + end + + def get_module(pid, module) do + Agent.get(pid, fn state -> + Keyword.get(state.modules, module) + end) + end + + def put_module(pid, module, value) do + Agent.update(pid, fn state -> + value = + Map.put_new(value, :used, []) + |> Map.put_new(:used_modules, []) + + modules = Keyword.put(state.modules, module, value) + %{state | modules: modules} + end) + end + + def put_used_module(pid, module, used_module) do + Agent.update(pid, fn state -> + module_info = Keyword.get(state.modules, module) + + used_modules = Map.get(module_info, :used_modules, []) + used_modules = Enum.uniq([used_module | used_modules]) + + module_info = Map.put(module_info, :used_modules, used_modules) + modules = Keyword.put(state.modules, module, module_info) + + %{state | modules: modules} + end) + end + + def has_used?(pid, module, func) do + Agent.get(pid, fn state -> + module_info = Keyword.get(state.modules, module) + used = Map.get(module_info, :used, []) + + Enum.find(used, fn x -> x == func end) != nil + end) + end + + def put_used(pid, module, {_function, _arity} = func) do + Agent.update(pid, fn state -> + module_info = Keyword.get(state.modules, module) + + used = Map.get(module_info, :used, []) + used = [func | used] + + module_info = Map.put(module_info, :used, used) + modules = Keyword.put(state.modules, module, module_info) + + %{state | modules: modules} + end) + end + + def put_javascript_module(pid, module, name, path) do + Agent.update(pid, fn state -> + js_modules = Map.get(state, :js_modules, []) + js_modules = [{module, name, path} | js_modules] + %{state | js_modules: js_modules} + end) + end + + def put_diagnostic(pid, module, diagnostic) do + Agent.update(pid, fn state -> + module_info = Keyword.get(state.modules, module) + + if module_info do + diagnostics = Map.get(module_info, :diagnostics, []) + diagnostics = [diagnostic | diagnostics] + + module_info = Map.put(module_info, :diagnostics, diagnostics) + modules = Keyword.put(state.modules, module, module_info) + + %{state | modules: modules} + else + state + end + end) + end + + def list_javascript_modules(pid) do + Agent.get(pid, fn state -> + state.js_modules + |> Enum.map(fn {module, _name, _path} -> + module + end) + end) + end + + def js_modules(pid) do + Agent.get(pid, fn state -> + state.js_modules + end) + end + + def is_global_module(pid, module) do + Agent.get(pid, fn state -> + result = + Enum.find(state.js_modules, fn {mod, _name, path} -> mod == module and path == nil end) + + if result == nil, do: false, else: true + end) + end + + def get_global_module_name(pid, module) do + Agent.get(pid, fn state -> + result = + Enum.find(state.js_modules, fn {mod, _name, path} -> mod == module and path == nil end) + + if result == nil, do: nil, else: elem(result, 1) + end) + end + + def remove_unused_functions(pid) do + Agent.get(pid, fn state -> + state.compiler_opts.remove_unused_functions + end) + end + + def get_js_module_name(pid, module) do + Agent.get(pid, fn state -> + {_, name, _} = + state.js_modules + |> Enum.find(fn {m, _, _} -> module == m end) + + name + end) + end + + def list_modules(pid) do + Agent.get(pid, fn state -> + state.modules + end) + end + + def get_in_memory_module(pid, module) do + Agent.get(pid, fn state -> + Keyword.get(state.in_memory_modules, module) + end) + end + + def get_in_memory_modules(pid) do + Agent.get(pid, fn state -> + state.in_memory_modules + end) + end + + def put_in_memory_module(pid, module, beam) do + Agent.update(pid, fn state -> + in_memory_modules = Map.get(state, :in_memory_modules, []) + in_memory_modules = Keyword.put(in_memory_modules, module, beam) + %{state | in_memory_modules: in_memory_modules} + end) + end +end diff --git a/lib/elixir_script/translator.ex b/lib/elixir_script/translator.ex deleted file mode 100644 index 83d07ff6..00000000 --- a/lib/elixir_script/translator.ex +++ /dev/null @@ -1,703 +0,0 @@ -defmodule ElixirScript.Translator do - @moduledoc false - alias ElixirScript.Translator.Primitive - alias ElixirScript.Translator.Identifier - alias ElixirScript.Translator.Expression - alias ElixirScript.Translator.Match - alias ElixirScript.Translator.Map - alias ElixirScript.Translator.Function - alias ElixirScript.Translator.Call - alias ElixirScript.Translator.Def - alias ElixirScript.Translator.Capture - alias ElixirScript.Translator.Cond - alias ElixirScript.Translator.Case - alias ElixirScript.Translator.For - alias ElixirScript.Translator.Try - alias ElixirScript.Translator.With - alias ElixirScript.Translator.Block - alias ElixirScript.Translator.Struct - alias ElixirScript.Translator.Defmodule - alias ElixirScript.Translator.Utils - alias ElixirScript.Translator.Bitstring - alias ElixirScript.Translator.Quote - alias ElixirScript.Translator.Utils - alias ElixirScript.Translator.JS, as: JSLib - alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator.Rewriter - - # A list of erlang modules. These are rewritten into equivalent - # JavaScript functions using ElixirScript.Translator.Rewriter - @erlang_modules [ - :erlang, - :maps, - :lists, - :gen, - :elixir_errors, - :supervisor, - :application, - :code, - :elixir_utils, - :file - ] - - @module_attributes_to_ignore [ - :doc, :moduledoc, :type, :typep, :spec, - :opaque, :callback, :macrocallback, :after_compile, - :before_compile, :behaviour, :compile, :file, - :on_definition, :on_load, :dialyzer, :vsn, :external_resource - ] - - @function_types [:def, :defp, :defgen, :defgenp] - @generator_types [:defgen, :defgenp] - - - @doc """ - Translates the given Elixir AST to JavaScript AST. The given `env` is a `ElixirScript.Macro.Env` - used to track the variables, imports, aliases, and scopes like `Macro.Env`. The JavaScript AST and - the an updated `ElixirScript.Macro.Env` is returned - """ - @spec translate(term, ElixirScript.Macro.Env.t) :: { ESTree.Node.t, ElixirScript.Macro.Env.t } - def translate(ast, env) do - do_translate(ast, env) - end - - - @doc """ - Same as `translate/2`, but returns only the JavaScript AST - """ - @spec translate!(term, ElixirScript.Macro.Env.t) :: ESTree.Node.t - def translate!(ast, env) do - { js_ast, _ } = translate(ast, env) - js_ast - end - - defp do_translate(ast, env) when is_number(ast) or is_binary(ast) or is_boolean(ast) or is_nil(ast) do - { Primitive.make_literal(ast), env } - end - - defp do_translate(ast, env) when is_atom(ast) do - { Primitive.make_atom(ast), env } - end - - defp do_translate([ {:|, _, [left, right] } ], env) do - quoted = quote do - [unquote(left)].concat(unquote(right)) - end - - translate(quoted, env) - end - - defp do_translate(ast, env) when is_list(ast) do - Primitive.make_list(ast, env) - end - - defp do_translate({ one, two }, env) do - quoted = quote do - JS.new(Bootstrap.Core.Tuple, [unquote(one), unquote(two)]) - end - - translate(quoted, env) - end - - defp do_translate({operator, _, [value]}, env) when operator in [:-, :!, :+] do - Expression.make_unary_expression(operator, value, env) - end - - defp do_translate({:not, _, [value]}, env) do - Expression.make_unary_expression(:!, value, env) - end - - defp do_translate({:"~~~", _, [value]}, env) do - Expression.make_unary_expression(:"~~~", value, env) - end - - defp do_translate({operator, _, [left, right]}, env) when operator in [:+, :-, :/, :*, :==, :!=, :&&, :||, :>, :<, :>=, :<=, :===, :!==, :"**"] do - Expression.make_binary_expression(operator, left, right, env) - end - - defp do_translate({:&&&, _, [left, right]}, env) do - Expression.make_binary_expression(:&, left, right, env) - end - - defp do_translate({:<<<, _, [left, right]}, env) do - Expression.make_binary_expression(:<, left, right, env) - end - - defp do_translate({:>>>, _, [left, right]}, env) do - Expression.make_binary_expression(:^, left, right, env) - end - - defp do_translate({:^^^, _, [left, right]}, env) do - Expression.make_binary_expression(:^, left, right, env) - end - - defp do_translate({:|||, _, [left, right]}, env) do - Expression.make_binary_expression(:|, left, right, env) - end - - defp do_translate({:and, _, [left, right]}, env) do - Expression.make_binary_expression(:&&, left, right, env) - end - - defp do_translate({:or, _, [left, right]}, env) do - Expression.make_binary_expression(:||, left, right, env) - end - - defp do_translate({:div, _, [left, right]}, env) do - Expression.make_binary_expression(:/, left, right, env) - end - - defp do_translate({:rem, _, [left, right]}, env) do - Expression.make_binary_expression(:%, left, right, env) - end - - defp do_translate({:throw, _, [params]}, env) do - { result, env } = translate(params, env) - { JS.throw_statement(result), env } - end - - defp do_translate({:<>, context, [left, right]}, env) do - translate({:+, context, [left, right]}, env) - end - - defp do_translate({:++, _, [left, right]}, env) do - translate({{:., [], [left, :concat]}, [], [right]}, env) - end - - defp do_translate({:&, _, [number]}, env) when is_number(number) do - { Identifier.make_identifier(String.to_atom("__#{number}")), env } - end - - defp do_translate({:&, _, [{:/, _, [{{:., _, [module_name, function_name]}, _, []}, arity]}]}, env) do - module_name = create_module_name2(module_name, env) - js_ast = case module_name do - {mod, :local} -> - Capture.make_capture(mod, function_name, arity, env) - mod -> - Capture.make_extern_capture(mod, function_name, arity, env) - end - - { js_ast, env } - end - - defp do_translate({:&, _, [{:/, _, [{function_name, _, _}, arity]}]}, env) do - { Capture.make_capture(function_name, arity, env), env } - end - - defp do_translate({:&, _, [body]}, env) do - params = Capture.find_value_placeholders(body) |> List.flatten - Function.make_anonymous_function([{:->, [], [params, body]}], env) - end - - defp do_translate({:@, _, [{name, _, _}]}, env) - when name in @module_attributes_to_ignore do - { %ElixirScript.Translator.Empty{}, env } - end - - defp do_translate({:@, _, [{name, _, [value]}]}, env) do - { Defmodule.make_attribute(name, value, env), env } - end - - defp do_translate({:@, _, [{name, _, _}]}, env) do - { Identifier.make_identifier(name), env } - end - - defp do_translate({:%, _, [alias_info, data]}, env) do - { Struct.new_struct(alias_info, data, env), env } - end - - defp do_translate({:%{}, _, [{:|, _, [map, data]}]}, env) do - Map.make_map_update(map, data, env) - end - - defp do_translate({:%{}, _, properties}, env) do - { Map.make_object(properties, env), env } - end - - defp do_translate({:<<>>, _, elements}, env) do - is_interpolated_string = Enum.all?(elements, fn(x) -> - case x do - b when is_binary(b) -> - true - {:::, _, [_target, {:binary, _, _}]} -> - true - _ -> - false - end - end) - - case is_interpolated_string do - true -> - Bitstring.make_interpolated_string(elements, env) - _ -> - Bitstring.make_bitstring(elements, env) - end - end - - defp do_translate({{:., _, [erlang_module, _]}, _, _} = erlang_function_call, env) when erlang_module in @erlang_modules do - Rewriter.rewrite(erlang_function_call) - |> translate(env) - end - - defp do_translate({{:., _, [Access, :get]}, _, [target, property]}, env) do - { Map.make_get_property(target, property, env), env } - end - - defp do_translate({{:., _, [function_name]}, _, params}, env) do - Call.make_local_function_call(function_name, params, env) - end - - defp do_translate({:., _, [{:__aliases__, _, _} = module_name, function_name]} = ast, env) do - do_translate({{:., [], [module_name, function_name]}, [], []}, env) - end - - defp do_translate({{:., _, [{:__aliases__, _, _} = module_name, function_name]}, _, [] } = ast, env) do - expanded_ast = Macro.expand(ast, env.env) - - if expanded_ast == ast do - module_name = create_module_name2(module_name, env) - case module_name do - {mod, :local} -> - Call.make_module_function_call(mod, function_name, env) - mod -> - Call.make_extern_function_or_property_call(mod, function_name, env) - end - else - translate(expanded_ast, env) - end - end - - defp do_translate({:., _, [module_name, function_name]} = ast, env) do - expanded_ast = Macro.expand(ast, env.env) - - if expanded_ast == ast do - Call.make_function_or_property_call(module_name, function_name, env) - else - translate(expanded_ast, env) - end - end - - defp do_translate({{:., context1, [{:__aliases__, context2, [:Elixir, :Enum]}, function_name]}, context3, params }, env) do - translate({{:., context1, [{:__aliases__, context2, [:Enum]}, function_name]}, context3, params }, env) - end - - defp do_translate({{:., context1, [{:__aliases__, context2, [:Enum]}, function_name]}, context3, params }, env) do - translate({{:., context1, [{:__aliases__, context2, [:Bootstrap, :Enum]}, function_name]}, context3, params }, env) - end - - defp do_translate({{:., _, [{:__aliases__, _, [:JS]}, function_name]}, _, params }, env) when function_name in @generator_types do - do_translate({function_name, [], params}, env) - end - - defp do_translate({{:., _, [{:__aliases__, _, [:JS]}, function_name]}, _, params }, env) do - JSLib.translate_js_function(function_name, params, env) - end - - defp do_translate({{:., _, [{:__aliases__, _, _} = module_name, function_name]}, _, params } = ast, env) do - expanded_ast = Macro.expand(ast, env.env) - - if expanded_ast == ast do - module_name = create_module_name2(module_name, env) - case module_name do - {mod, :local} -> - Call.make_module_function_call(mod, function_name, params, env) - mod -> - Call.make_extern_function_call(mod, function_name, params, env) - end - else - translate(expanded_ast, env) - end - end - - defp do_translate({{:., _, [module_name, function_name]}, _, params} = ast, env) when is_atom(module_name) and is_atom(function_name) do - expanded_ast = Macro.expand(ast, env.env) - - if expanded_ast == ast do - Call.make_function_call(module_name, function_name, params, env) - else - translate(expanded_ast, env) - end - end - - defp do_translate({{:., _, [module_name, function_name]}, _, params } = ast, env) do - expanded_ast = Macro.expand(ast, env.env) - - if expanded_ast == ast do - Call.make_function_call(module_name, function_name, params, env) - else - translate(expanded_ast, env) - end - end - - defp do_translate({:_, _, _}, env) do - { Identifier.make_identifier(:undefined), env } - end - - defp do_translate({:__aliases__, _, aliases} = ast, env) do - module_name = create_module_name2(ast, env) - case module_name do - {mod, :local} -> - Call.make_module_name(mod, env) - mod -> - Call.make_extern_module_name(mod, env) - end - end - - defp do_translate({:__MODULE__, _, _ }, env) do - translate(env.module, env) - end - - defp do_translate({:__block__, _, expressions }, env) do - Block.make_block(expressions, env) - end - - defp do_translate({:__DIR__, _, _}, env) do - case env.file do - nil -> - { JS.identifier(:null), env } - filepath -> - { JS.literal(Path.dirname(filepath)), env } - end - end - - defp do_translate({:try, _, [ blocks ]}, env) do - Try.make_try(blocks, env) - end - - defp do_translate({:with, _, args }, env ) do - With.make_with(args, env) - end - - defp do_translate({:super, _, _expressions }, _ ) do - raise ElixirScript.Translator.UnsupportedError, "super" - end - - defp do_translate({:__CALLER__, _, _expressions }, env) do - env_to_translate = ElixirScript.Translator.LexicalScope.caller(env) - - quoted = Macro.escape(env_to_translate) - translate(quoted, env) - end - - defp do_translate({:__ENV__, _, _expressions }, env) do - env_to_translate = ElixirScript.Translator.LexicalScope.env(env) - - quoted = Macro.escape(env_to_translate) - translate(quoted, env) - end - - defp do_translate({:quote, _, [[do: expr]]}, env) do - { Quote.make_quote([], expr, env), env } - end - - defp do_translate({:quote, _, [opts, [do: expr]]}, env) do - { Quote.make_quote(opts, expr, env), env } - end - - defp do_translate({:import, _, [{{:., _, [{:__aliases__, _, head_import_name}, :{}]}, _, tail_imports }]}, env) do - env = Enum.reduce(tail_imports, env, fn({:__aliases__, context, name}, acc) -> - full_module_name = { :__aliases__, context, head_import_name ++ name } - - module_name = Utils.quoted_to_name(full_module_name) - ElixirScript.Translator.LexicalScope.add_import(acc, module_name) - end) - - { %ElixirScript.Translator.Empty{}, env } - end - - - defp do_translate({:import, _, [{:__aliases__, _, _} = module_name]}, env) do - module_name = Utils.quoted_to_name(module_name) - - env = ElixirScript.Translator.LexicalScope.add_import(env, module_name) - { %ElixirScript.Translator.Empty{}, env } - end - - defp do_translate({:import, _, [{:__aliases__, _, _} = module_name, options]}, env) do - module_name = Utils.quoted_to_name(module_name) - - env = ElixirScript.Translator.LexicalScope.add_import(env, module_name, options) - - { %ElixirScript.Translator.Empty{}, env } - end - - defp do_translate({:alias, _, [{{:., _, [{:__aliases__, _, head_alias_name}, :{}]}, _, tail_aliases }]}, env) do - env = Enum.reduce(tail_aliases, env, fn({:__aliases__, context, name}, acc) -> - full_module_name = { :__aliases__, context, head_alias_name ++ name } - - module_name = Utils.quoted_to_name(full_module_name) - alias_name = Utils.quoted_to_name({:__aliases__, [], [List.last(name)] }) - - ElixirScript.Translator.LexicalScope.add_alias(acc, module_name, alias_name) - end) - - { %ElixirScript.Translator.Empty{}, env } - end - - defp do_translate({:alias, _, [{:__aliases__, _, _} = module_name] }, env) do - {_, _, name} = module_name - name = [List.last(name)] - - module_name = Utils.quoted_to_name(module_name) - alias_name = Utils.quoted_to_name({:__aliases__, [], name }) - - env = ElixirScript.Translator.LexicalScope.add_alias(env, module_name, alias_name) - { %ElixirScript.Translator.Empty{}, env } - end - - defp do_translate({:alias, _, [{:__aliases__, _, _} = module_name, [as: {:__aliases__, _, _} = alias_name]]}, env) do - module_name = Utils.quoted_to_name(module_name) - alias_name = Utils.quoted_to_name(alias_name) - - env = ElixirScript.Translator.LexicalScope.add_alias(env, module_name, alias_name) - { %ElixirScript.Translator.Empty{}, env } - end - - defp do_translate({:require, _, [{{:., _, [{:__aliases__, _, head_require_name}, :{}]}, _, tail_requires }]}, env) do - env = Enum.reduce(tail_requires, env, fn({:__aliases__, context, name}, acc) -> - full_module_name = { :__aliases__, context, head_require_name ++ name } - - module_name = Utils.quoted_to_name(full_module_name) - ElixirScript.Translator.LexicalScope.add_require(acc, module_name) - end) - - { %ElixirScript.Translator.Empty{}, env } - end - - defp do_translate({:require, _, [{:__aliases__, _, _} = module_name] }, env) do - module_name = Utils.quoted_to_name(module_name) - env = ElixirScript.Translator.LexicalScope.add_require(env, module_name) - { %ElixirScript.Translator.Empty{}, env } - end - - defp do_translate({:require, _, [{:__aliases__, _, _} = module_name, [as: {:__aliases__, _, _} = alias_name]]}, env) do - module_name = Utils.quoted_to_name(module_name) - alias_name = Utils.quoted_to_name(alias_name) - - env = ElixirScript.Translator.LexicalScope.add_require(env, module_name, alias_name) - { %ElixirScript.Translator.Empty{}, env } - end - - defp do_translate({:case, _, [condition, [do: clauses]]}, env) do - Case.make_case(condition, clauses, env) - end - - defp do_translate({:cond, _, [[do: clauses]]}, env) do - Cond.make_cond(clauses, env) - end - - defp do_translate({:for, _, generators}, env) do - For.make_for(generators, env) - end - - defp do_translate({:fn, _, clauses}, env) do - Function.make_anonymous_function(clauses, env) - end - - defp do_translate({:receive, _, _ }, _) do - raise ElixirScript.Translator.UnsupportedError, "receive" - end - - defp do_translate({:{}, _, elements}, env) do - quoted = quote do - JS.new(Bootstrap.Core.Tuple, unquote(elements)) - end - - translate(quoted, env) - end - - defp do_translate({:=, _, [left, right]}, env) do - Match.make_match(left, right, env) - end - - defp do_translate({function, _, [{:when, _, [{name, _, _params} | _guards] }, _] } = ast, env) when function in @generator_types do - Def.process_function(name, [ast], %{ env | context: :generator}) - end - - defp do_translate({function, _, [{name, _, params}, _]} = ast, env) when function in @generator_types and is_atom(params) do - Def.process_function(name, [ast], %{ env | context: :generator}) - end - - defp do_translate({function, _, [{name, _, _params}, _]} = ast, env) when function in @generator_types do - Def.process_function(name, [ast], %{ env | context: :generator}) - end - - defp do_translate({function, _, [{:when, _, [{name, _, _params} | _guards] }, _] } = ast, env) when function in @function_types do - Def.process_function(name, [ast], env) - end - - defp do_translate({function, _, [{name, _, params}, _]} = ast, env) when function in @function_types and is_atom(params) do - Def.process_function(name, [ast], env) - end - - defp do_translate({function, _, [{name, _, _params}, _]} = ast, env) when function in @function_types do - Def.process_function(name, [ast], env) - end - - defp do_translate({:defdelegate, _, [{name, _, params}, options]}, env) do - Def.process_delegate(name, params, options, env) - end - - defp do_translate({:defstruct, _, attributes}, env) do - { Struct.make_defstruct(attributes, env), env } - end - - defp do_translate({:defexception, _, attributes}, env) do - { Struct.make_defexception(attributes, env), env } - end - - defp do_translate({:defmodule, _, [{:__aliases__, _, module_name_list}, [do: body]]}, env) do - { Defmodule.make_module(module_name_list, body, env), env } - end - - defp do_translate({:defprotocol, _, _}, env) do - { %ElixirScript.Translator.Empty{}, env } - end - - defp do_translate({:defmacro, _, _}, env) do - { %ElixirScript.Translator.Empty{}, env } - end - - defp do_translate({:defmacrop, _, _}, env) do - { %ElixirScript.Translator.Empty{}, env } - end - - defp do_translate({:defimpl, _, _}, env) do - { %ElixirScript.Translator.Empty{}, env } - end - - defp do_translate({:|, _, [item, list]}, env) do - quoted = quote do - [unquote(item)].concat(unquote(list)) - end - - translate(quoted, env) - end - - defp do_translate({:raise, _, [alias_info, attributes]}, env) when is_list(attributes) do - js_ast = JS.throw_statement( - Struct.new_struct(alias_info, {:%{}, [], attributes }, env) - ) - - { js_ast, env } - end - - defp do_translate({:raise, _, [alias_info, message]}, env) do - js_ast = JS.throw_statement( - Struct.new_struct(alias_info, {:%{}, [], [message: message] }, env) - ) - - { js_ast, env } - end - - defp do_translate({:raise, _, [message]}, env) do - js_ast = JS.throw_statement( - JS.object_expression( - [ - Map.make_property(translate!(:__struct__, env), translate!(:RuntimeError, env)), - Map.make_property(translate!(:__exception__, env), translate!(true, env)), - Map.make_property(translate!(:message, env), translate!(message, env)) - ] - ) - ) - - { js_ast, env } - end - - defp do_translate({name, _, params} = ast, env) when is_list(params) do - if is_from_js_module(name, params, env) do - do_translate({{:., [], [{:__aliases__, [], [:JS]}, name]}, [], params }, env) - else - expanded_ast = Macro.expand(ast, env.env) - if expanded_ast == ast do - name_arity = {name, length(params)} - module = ElixirScript.Translator.State.get_module(env.state, env.module) - - cond do - name_arity in module.functions or name_arity in module.private_functions -> - Call.make_local_function_call(name, params, env) - ElixirScript.Translator.LexicalScope.find_module(env, name_arity) -> - imported_module_name = ElixirScript.Translator.LexicalScope.find_module(env, name_arity) - Call.make_module_function_call(imported_module_name, name, params, env) - true -> - Call.make_local_function_call(name, params, env) - end - - else - translate(expanded_ast, env) - end - end - end - - defp do_translate({ name, _, params }, env) when is_atom(params) do - cond do - is_from_js_module(name, params, env) -> - do_translate({{:., [], [{:__aliases__, [], [:JS]}, name]}, [], params }, env) - ElixirScript.Translator.LexicalScope.has_var?(env, name) -> - { Identifier.make_identifier(name), env } - has_function?(env.module, {name, 0}, env) -> - Call.make_function_call(name, [], env) - ElixirScript.Translator.LexicalScope.find_module(env, {name, 0}) -> - imported_module_name = ElixirScript.Translator.LexicalScope.find_module(env, {name, 0}) - Call.make_module_function_call(imported_module_name, name, params, env) - true -> - { Identifier.make_identifier(name), env } - end - end - - defp is_from_js_module(name, params, env) do - func = if is_list(params) do - {name, length(params)} - else - {name, 0} - end - - {_, macros} = Enum.find(env.env.macros, {nil, []}, fn({k, v}) -> to_string(k) == "Elixir.JS" end) - {_, functions} = Enum.find(env.env.functions, {nil, []}, fn({k, v}) -> to_string(k) == "Elixir.JS" end) - - js = macros ++ functions - - if func in js do - true - else - false - end - end - - def create_module_name(module_name, env) do - case module_name do - {:__aliases__, _, _} -> - candiate_module_name = ElixirScript.Translator.State.get_module_name(env.state, - Utils.quoted_to_name(module_name)) - - if ElixirScript.Translator.LexicalScope.get_module_name(env, candiate_module_name) in ElixirScript.Translator.State.list_module_names(env.state) do - ElixirScript.Translator.LexicalScope.get_module_name(env, candiate_module_name) - else - module_name - end - _ -> - module_name - end - end - - def create_module_name2(module_name, env) do - module_name = Utils.quoted_to_name(module_name) - candiate_module_name = ElixirScript.Translator.State.get_module_name(env.state, module_name) - - if ElixirScript.Translator.LexicalScope.get_module_name(env, candiate_module_name) in ElixirScript.Translator.State.list_module_names(env.state) do - { ElixirScript.Translator.LexicalScope.get_module_name(env, candiate_module_name), :local } - else - module_name - end - end - - def has_function?(module_name, name_arity, env) do - case ElixirScript.Translator.State.get_module(env.state, module_name) do - nil -> - false - module -> - name_arity in module.functions or name_arity in module.private_functions - end - end - -end diff --git a/lib/elixir_script/translator/empty.ex b/lib/elixir_script/translator/empty.ex deleted file mode 100644 index 1456cc4f..00000000 --- a/lib/elixir_script/translator/empty.ex +++ /dev/null @@ -1,8 +0,0 @@ -defmodule ElixirScript.Translator.Empty do - @moduledoc false - - # Represents no translation to JS AST - - @type t :: %ElixirScript.Translator.Empty{} - defstruct type: "Empty" -end diff --git a/lib/elixir_script/translator/group.ex b/lib/elixir_script/translator/group.ex deleted file mode 100644 index 391315ff..00000000 --- a/lib/elixir_script/translator/group.ex +++ /dev/null @@ -1,30 +0,0 @@ -defmodule ElixirScript.Translator.Group do - @moduledoc false - - # Represents a collection of JavaScript AST. - # Contents in body are expanded within outer AST before JS code generation - - @type t :: %ElixirScript.Translator.Group{ - type: binary, - body: [ESTree.Statement.t] - } - defstruct type: "Group", body: [] - - def inflate_groups(body) do - Enum.map(body, fn(x) -> - case x do - %ElixirScript.Translator.Empty{} -> - [] - %ElixirScript.Translator.Group{body: group_body} -> - group_body - %ESTree.BlockStatement{} -> - %ESTree.BlockStatement{ body: inflate_groups(x.body) } - %ESTree.IfStatement{} -> - %{x | consequent: inflate_groups(x.consequent), alternate: inflate_groups(x.alternate) } - _ -> - x - end - end) - |> List.flatten - end -end diff --git a/lib/elixir_script/translator/kernel/def.ex b/lib/elixir_script/translator/kernel/def.ex deleted file mode 100644 index 6fee1fb1..00000000 --- a/lib/elixir_script/translator/kernel/def.ex +++ /dev/null @@ -1,39 +0,0 @@ -defmodule ElixirScript.Translator.Def do - @moduledoc false - alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator.Function - alias ElixirScript.Translator.Identifier - alias ElixirScript.Translator - - def process_function(name, functions, env) do - { result, _ } = Function.make_anonymous_function(functions, env, name) - - declarator = JS.variable_declarator( - Identifier.make_identifier(name), - result - ) - - { JS.variable_declaration([declarator], :const), env } - end - - def process_delegate(name, params, options, env) do - translated_params = Enum.map(params, &Translator.translate!(&1, env)) - to = options[:to] - as = options[:as] || name - - function = JS.function_expression(translated_params, [], - JS.block_statement([ - JS.return_statement( - Translator.translate!({{:., [], [to, as]}, [], params}, env) - ) - ]) - ) - - declarator = JS.variable_declarator( - Identifier.make_identifier(name), - function - ) - - { JS.variable_declaration([declarator], :const), env } - end -end diff --git a/lib/elixir_script/translator/kernel/defimpl.ex b/lib/elixir_script/translator/kernel/defimpl.ex deleted file mode 100644 index 92860e18..00000000 --- a/lib/elixir_script/translator/kernel/defimpl.ex +++ /dev/null @@ -1,128 +0,0 @@ -defmodule ElixirScript.Translator.Defimpl do - @moduledoc false - alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator.Defmodule - alias ElixirScript.Translator.State - alias ElixirScript.Translator.Utils - - def make(name, type, body, env) do - - type = map_to_js(type, env) - {body, export} = Defmodule.process_module(name, body, env) - - protocol_name = Atom.to_string(name) |> String.split(".DefImpl.") |> hd |> String.to_atom - - export = JS.object_expression([ - JS.property( - JS.literal("Type"), - type - ), - JS.property( - JS.literal("Implementation"), - export - ) - ]) - - %{ - name: Utils.quoted_to_name({:__aliases__, [], name }), - exports: export, - body: body, - app_name: State.get_module(env.state, name).app, - protocol: protocol_name, - env: env - } - end - - defp map_to_js({:__aliases__, _, [:Integer]}, _) do - JS.member_expression( - JS.member_expression( - JS.identifier("Bootstrap"), - JS.identifier(:Core) - ), - JS.identifier(:Integer) - ) - end - - defp map_to_js({:__aliases__, _, [:Tuple]}, _) do - JS.member_expression( - JS.member_expression( - JS.identifier("Bootstrap"), - JS.identifier(:Core) - ), - JS.identifier(:Tuple) - ) - end - - defp map_to_js({:__aliases__, _, [:Atom]}, _) do - JS.identifier(:Symbol) - end - - defp map_to_js({:__aliases__, _, [:List]}, _) do - JS.identifier(:Array) - end - - defp map_to_js({:__aliases__, _, [:BitString]}, _) do - JS.member_expression( - JS.member_expression( - JS.identifier("Bootstrap"), - JS.identifier(:Core) - ), - JS.identifier(:BitString) - ) - end - - defp map_to_js({:__aliases__, _, [:Float]}, _) do - JS.member_expression( - JS.member_expression( - JS.identifier("Bootstrap"), - JS.identifier(:Core) - ), - JS.identifier(:Float) - ) - end - - defp map_to_js({:__aliases__, _, [:Function]}, _) do - JS.identifier(:Function) - end - - defp map_to_js({:__aliases__, _, [:PID]}, _) do - JS.member_expression( - JS.member_expression( - JS.identifier("Bootstrap"), - JS.identifier(:Core) - ), - JS.identifier(:PID) - ) - end - - defp map_to_js({:__aliases__, _, [:Port]}, _) do - JS.member_expression( - JS.identifier("Bootstrap"), - JS.identifier(:Port) - ) - end - - defp map_to_js({:__aliases__, _, [:Reference]}, _) do - JS.member_expression( - JS.identifier("Bootstrap"), - JS.identifier(:Reference) - ) - end - - defp map_to_js({:__aliases__, _, [:Map]}, _) do - JS.identifier(:Object) - end - - defp map_to_js({:__aliases__, _, [:Any]}, _) do - JS.identifier(:null) - end - - - defp map_to_js({:__aliases__, _, _} = module, env) do - ElixirScript.Translator.Struct.get_struct_class( - module, - env - ) - end - -end diff --git a/lib/elixir_script/translator/kernel/defmodule.ex b/lib/elixir_script/translator/kernel/defmodule.ex deleted file mode 100644 index 17f1c7c1..00000000 --- a/lib/elixir_script/translator/kernel/defmodule.ex +++ /dev/null @@ -1,235 +0,0 @@ -defmodule ElixirScript.Translator.Defmodule do - @moduledoc false - alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator - alias ElixirScript.Translator.State - alias ElixirScript.Translator.Utils - alias ElixirScript.Translator.Group - alias ElixirScript.Translator.Def - alias ElixirScript.Translator.Identifier - - def make_module(ElixirScript.Temp, body, env) do - { body, _ } = translate_body(body, env) - %{ - name: ElixirScript.Temp, - body: body |> Group.inflate_groups, - exports: nil, - app_name: ElixirScript.Translator.State.get(env.state).compiler_opts.app, - env: env - } - end - - def make_module(module, nil, env) do - %{ - name: module, - body: [], - exports: nil, - app_name: ElixirScript.Translator.State.get(env.state).compiler_opts.app, - env: env - } - end - - def make_module(module, body, env) do - {body, exported_object} = process_module(module, body, env) - app_name = State.get_module(env.state, module).app - - result = %{ - name: Utils.quoted_to_name({:__aliases__, [], module }), - exports: exported_object, - body: body, - app_name: app_name, - env: env - } - - result - end - - def process_module(module, body, env) do - { body, functions } = extract_functions_from_module(body) - - { body, env } = translate_body(body, env) - - { exported_functions, private_functions } = process_functions(functions, env) - - {structs, body} = extract_structs_from_body(body, env) - - body = Enum.map(body, fn(x) -> - case x do - %ESTree.CallExpression{} -> - JS.expression_statement(x) - _ -> - x - end - end) - - body = Group.inflate_groups(body) - - exported_object = JS.object_expression( - make_defstruct_property(module, structs) ++ - Enum.map(exported_functions, fn({key, _value}) -> - JS.property(Identifier.make_identifier(key), Identifier.make_identifier(key), :init, true) - end) - ) - - exported_functions = Enum.map(exported_functions, fn({_key, value}) -> value end) - private_functions = Enum.map(private_functions, fn({_key, value}) -> value end) - - body = structs ++ private_functions ++ exported_functions ++ body - {body, exported_object} - end - - def process_module_refs(module_refs, env) do - Enum.map(module_refs, fn(x) -> - {x, ""} - end) - end - - def translate_body(body, env) do - { body, env } = Translator.translate(body, env) - - body = case body do - [%ESTree.BlockStatement{ body: body }] -> - body - %ESTree.BlockStatement{ body: body } -> - body - _ -> - List.wrap(body) - end - - { body, env } - end - - def extract_functions_from_module({:__block__, meta, body_list}) do - { body_list, functions } = Enum.map_reduce(body_list, - %{exported: Map.new(), private: Map.new(), exported_generators: Map.new(), private_generators: Map.new()}, fn - ({:def, _, [{:when, _, [{name, _, _} | _guards] }, _] } = function, state) -> - { - nil, - %{ state | exported: Map.put(state.exported, name, Map.get(state.exported, name, []) ++ [function]) } - } - ({:def, _, [{name, _, _}, _]} = function, state) -> - { - nil, - %{ state | exported: Map.put(state.exported, name, Map.get(state.exported, name, []) ++ [function]) } - } - ({:defp, _, [{:when, _, [{name, _, _} | _guards] }, _] } = function, state) -> - { - nil, - %{ state | private: Map.put(state.private, name, Map.get(state.private, name, []) ++ [function]) } - } - ({:defp, _, [{name, _, _}, _]} = function, state) -> - { - nil, - %{ state | private: Map.put(state.private, name, Map.get(state.private, name, []) ++ [function]) } - } - ({:defgen, _, [{:when, _, [{name, _, _} | _guards] }, _] } = function, state) -> - { - nil, - %{ state | exported_generators: Map.put(state.exported_generators, name, Map.get(state.exported_generators, name, []) ++ [function]) } - } - ({:defgen, _, [{name, _, _}, _]} = function, state) -> - { - nil, - %{ state | exported_generators: Map.put(state.exported_generators, name, Map.get(state.exported_generators, name, []) ++ [function]) } - } - ({:defgenp, _, [{:when, _, [{name, _, _} | _guards] }, _] } = function, state) -> - { - nil, - %{ state | private_generators: Map.put(state.private_generators, name, Map.get(state.private_generators, name, []) ++ [function]) } - } - ({:defgenp, _, [{name, _, _}, _]} = function, state) -> - { - nil, - %{ state | private_generators: Map.put(state.private_generators, name, Map.get(state.private_generators, name, []) ++ [function]) } - } - (x, state) -> - { x, state } - end) - - body_list = Enum.filter(body_list, fn(x) -> !is_nil(x) end) - body = {:__block__, meta, body_list} - - { body, functions } - end - - def extract_functions_from_module(body) do - extract_functions_from_module({:__block__, [], List.wrap(body)}) - end - - def extract_imports_from_body(body) do - Enum.partition(body, fn(x) -> - case x do - %ESTree.ImportDeclaration{} -> - true - _ -> - false - end - end) - end - - def extract_structs_from_body(body, env) do - module_js_name = Utils.name_to_js_name(env.module) - - Enum.partition(body, fn(x) -> - case x do - %ESTree.VariableDeclaration{declarations: [%ESTree.VariableDeclarator{id: %ESTree.Identifier{name: ^module_js_name} } ] } -> - true - _ -> - false - end - end) - end - - defp make_defstruct_property(_, []) do - [] - end - - defp make_defstruct_property(module_name, [the_struct]) do - module_js_name = Utils.name_to_js_name(module_name) - - case the_struct do - %ESTree.VariableDeclaration{declarations: [%ESTree.VariableDeclarator{id: %ESTree.Identifier{name: ^module_js_name} } ] } -> - [JS.property(JS.identifier(module_js_name), JS.identifier(module_js_name), :init, true)] - end - end - - def process_functions(%{ exported: exported, private: private, exported_generators: exported_generators, private_generators: private_generators }, env) do - exported_functions = Enum.map(Dict.keys(exported), fn(key) -> - functions = Dict.get(exported, key) - - { functions, _ } = Def.process_function(key, functions, env) - { key, functions } - end) - - exported_generators = Enum.map(Dict.keys(exported_generators), fn(key) -> - functions = Dict.get(exported_generators, key) - - { functions, _ } = Def.process_function(key, functions, %{ env | context: :generator}) - { key, functions } - end) - - private_functions = Enum.map(Dict.keys(private), fn(key) -> - functions = Dict.get(private, key) - { functions, _ } = Def.process_function(key, functions, env) - { key, functions } - end) - - private_generators = Enum.map(Dict.keys(private_generators), fn(key) -> - functions = Dict.get(private_generators, key) - { functions, _ } = Def.process_function(key, functions, %{ env | context: :generator}) - { key, functions } - end) - - { exported_functions ++ exported_generators, private_functions ++ private_generators } - end - - def make_attribute(name, value, env) do - declarator = JS.variable_declarator( - Identifier.make_identifier(name), - ElixirScript.Translator.translate!(value, env) - ) - - JS.variable_declaration([declarator], :const) - end - -end diff --git a/lib/elixir_script/translator/kernel/defprotocol.ex b/lib/elixir_script/translator/kernel/defprotocol.ex deleted file mode 100644 index f41ee42b..00000000 --- a/lib/elixir_script/translator/kernel/defprotocol.ex +++ /dev/null @@ -1,93 +0,0 @@ -defmodule ElixirScript.Translator.Defprotocol do - @moduledoc false - - alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator.Defmodule - alias ElixirScript.Translator.Map - alias ElixirScript.Translator.Utils - alias ElixirScript.Translator.State - alias ElixirScript.Translator.Identifier - require Logger - - @doc """ - Takes a protocol and turns it into a module - """ - def make(name, functions, env) do - { body, _ } = Defmodule.translate_body( {:__block__, [], [] }, env) - app_name = State.get_module(env.state, name).app - - object = process_spec_functions(functions) - |> Enum.map(fn({key, value}) -> - Map.make_property(Identifier.make_identifier(key), value) - end) - |> JS.object_expression - - declarator = JS.variable_declarator( - JS.identifier(Utils.name_to_js_name(name)), - JS.call_expression( - JS.member_expression( - JS.identifier("Bootstrap"), - JS.member_expression( - JS.identifier(:Core), - JS.member_expression( - JS.identifier(:Functions), - JS.identifier(:defprotocol) - ) - ) - ), - [object] - ) - ) - - declaration = JS.variable_declaration([declarator], :const) - - implementation_name_split = Module.split(name) ++ ["DefImpl"] - implementation_name = Enum.join(["Elixir"] ++ implementation_name_split, "$") - implementation_name_module = Module.concat(implementation_name_split) - - implementations = JS.for_of_statement( - JS.variable_declaration([JS.variable_declarator( - JS.object_pattern([ - JS.assignment_property(JS.identifier("Type")), - JS.assignment_property(JS.identifier("Implementation")) - ]), - nil - )], :let), - JS.identifier(implementation_name), - JS.call_expression( - JS.member_expression( - JS.identifier("Bootstrap"), - JS.member_expression( - JS.identifier(:Core), - JS.member_expression( - JS.identifier(:Functions), - JS.identifier(:defimpl) - ) - ) - ), - [ - JS.identifier(Utils.name_to_js_name(name)), - JS.identifier("Type"), - JS.identifier("Implementation") - ] - ) - ) - - body = body ++ [declaration] ++ [implementations] - defimpl_import = ElixirScript.ModuleSystems.Namespace.import_module(implementation_name_module) - - %{ - name: name, - body: [defimpl_import] ++ body, - exports: JS.identifier(Utils.name_to_js_name(name)), - app_name: app_name, - env: env - } - end - - defp process_spec_functions(functions) do - Enum.map(Keyword.keys(functions), fn(function_name) -> - {function_name, JS.function_expression([], [], JS.block_statement([]))} - end) - end -end diff --git a/lib/elixir_script/translator/kernel/expression.ex b/lib/elixir_script/translator/kernel/expression.ex deleted file mode 100644 index 583e52a4..00000000 --- a/lib/elixir_script/translator/kernel/expression.ex +++ /dev/null @@ -1,18 +0,0 @@ -defmodule ElixirScript.Translator.Expression do - @moduledoc false - alias ESTree.Tools.Builder - alias ElixirScript.Translator - - def make_unary_expression(operator, expr, env) do - { js_ast, env } = Translator.translate(expr, env) - { Builder.unary_expression(operator, true, js_ast), env } - end - - def make_binary_expression(operator, left, right, env) do - { left, _ } = Translator.translate(left, env) - { right, _ } = Translator.translate(right, env) - - { Builder.binary_expression(operator, left, right), env } - end - -end diff --git a/lib/elixir_script/translator/kernel/js.ex b/lib/elixir_script/translator/kernel/js.ex deleted file mode 100644 index 27acde1d..00000000 --- a/lib/elixir_script/translator/kernel/js.ex +++ /dev/null @@ -1,109 +0,0 @@ -defmodule ElixirScript.Translator.JS do - @moduledoc false - - alias ESTree.Tools.Builder - alias ElixirScript.Translator - alias ElixirScript.Translator.Identifier - alias ElixirScript.Translator.State - - @doc false - def translate_js_function(name, params, env) do - { do_translate({name, [], params}, env), env } - end - - defp do_translate({op, _, [param]}, env) when op in [:typeof, :delete, :void, :-, :+, :!, :"~"] do - Builder.unary_expression( - op, - true, - Translator.translate!(param, env) - ) - end - - defp do_translate({op, _, [value, type]}, env) when op in [:"**", :==, :!=, :===, :!==, :<, :<=, :>, :>=, :"<<", :">>", :<<<, :+, :-, :*, :/, :%, :|, :^, :&, :in, :instanceof] do - Builder.binary_expression( - op, - Translator.translate!(value, env), - Translator.translate!(type, env) - ) - end - - defp do_translate({op, _, [value, type]}, env) when op in [:||, :&&] do - Builder.logical_expression( - op, - Translator.translate!(value, env), - Translator.translate!(type, env) - ) - end - - defp do_translate({:yield, _, []}, env) do - Builder.yield_expression() - end - - defp do_translate({:yield, _, [term]}, env) do - Builder.yield_expression( - Translator.translate!(term, env) - ) - end - - defp do_translate({:yield_to, _, [term]}, env) do - Builder.yield_expression( - Translator.translate!(term, env), - true - ) - end - - defp do_translate({:throw, _, [term]}, env) do - Builder.throw_statement( - Translator.translate!(term, env) - ) - end - - defp do_translate({:new, _, [module_name, params]}, env) when not is_list(params) do - Builder.new_expression( - Translator.translate!(module_name, env), - [Builder.rest_element(Translator.translate!(params, env))] - ) - end - - defp do_translate({:new, _, [module_name, params]}, env) do - Builder.new_expression( - Translator.translate!(module_name, env), - Enum.map(params, &Translator.translate!(&1, env)) - ) - end - - defp do_translate({:update, _, [object, map]}, env) do - quoted = quote do - Object.assign(unquote(object), unquote(map)) - end - - Translator.translate!(quoted, env) - end - - defp do_translate({:import, _, [module_name, from, [default: false]]}, env) do - State.add_javascript_module_reference(env.state, env.module, module_name, from, false) - %ElixirScript.Translator.Empty{} - end - - defp do_translate({:import, _, [module_name, from, [default: true]]}, env) do - State.add_javascript_module_reference(env.state, env.module, module_name, from, true) - %ElixirScript.Translator.Empty{} - end - - defp do_translate({:import, _, [module_name, from]}, env) do - State.add_javascript_module_reference(env.state, env.module, module_name, from, true) - %ElixirScript.Translator.Empty{} - end - - defp do_translate({:object, _, [args]}, env) do - args = Enum.map(args, fn - { k, v } when Kernel.is_atom(k) -> - { Atom.to_string(k), v } - pair -> - pair - end) - - Translator.translate!({ :%{}, [], args }, env) - end - -end diff --git a/lib/elixir_script/translator/kernel/special_forms/bitstring.ex b/lib/elixir_script/translator/kernel/special_forms/bitstring.ex deleted file mode 100644 index 00107d8d..00000000 --- a/lib/elixir_script/translator/kernel/special_forms/bitstring.ex +++ /dev/null @@ -1,147 +0,0 @@ -defmodule ElixirScript.Translator.Bitstring do - @moduledoc false - alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator - - - def make_bitstring(elements, env) do - js_ast = JS.new_expression( - JS.member_expression( - JS.member_expression( - JS.identifier("Bootstrap"), - JS.identifier("Core") - ), - JS.identifier("BitString") - ), - Enum.map(elements, &make_bitstring_element(&1, env)) - ) - - { js_ast, env } - end - - def make_bitstring_element(element, env) when is_number(element) do - do_make_bitstring_element({:integer, Translator.translate!(element, env)}) - end - - def make_bitstring_element(element, env) when is_binary(element) do - do_make_bitstring_element({:binary, Translator.translate!(element, env)}) - end - - def make_bitstring_element({:<<>>, [], elements}, env) do - {ast, _} = make_bitstring(elements, env) - ast - end - - def make_bitstring_element({:::, _, [element, {type, _, _}]}, env) when type in [:integer, :float, :bitstring, :bits, :binary, :bytes, :utf8, :utf16, :utf32, :signed, :unsigned] do - do_make_bitstring_element({type, translate_element(element, env)}) - end - - def make_bitstring_element({:::, _, [element, {type, _, params}]}, env) when type in [:size, :unit] do - do_make_bitstring_element({type, translate_element(element, env), Enum.map(params, &translate_element(&1, env))}) - end - - def make_bitstring_element({:::, _, [element, {:*, _, [size, unit]}]}, env) do - size_ast = do_make_bitstring_element({:size, translate_element(element, env), [translate_element(size, env)]}) - do_make_bitstring_element({:unit, size_ast, [translate_element(unit, env)]}) - end - - def make_bitstring_element({:::, _, [element, {:-, _, types}]}, env) do - handle_type_adjectives({:-, [], types}, translate_element(element, env), env) - end - - def make_bitstring_element({:::, _, [element, size]}, env) do - do_make_bitstring_element({:size, translate_element(element, env), [translate_element(size, env)]}) - end - - def make_bitstring_element(element, env) do - do_make_bitstring_element({:binary, translate_element(element, env)}) - end - - def translate_element(ElixirScript.Translator.PatternMatching, _) do - JS.object_expression([JS.property( - JS.literal("value"), - ElixirScript.Translator.PatternMatching.parameter() - ) - ]) - end - - def translate_element(element, env) do - Translator.translate!(element, env) - end - - defp handle_type_adjectives({:-, _, types}, ast, env) do - Enum.reduce(types, ast, fn(type, current_ast) -> - case type do - {:-, _, sub_types} -> - handle_type_adjectives({:-, [], sub_types}, current_ast, env) - {:*, _, [size, unit]} -> - size_ast = do_make_bitstring_element({:size, current_ast, [Translator.translate!(size, env)]}) - do_make_bitstring_element({:unit, size_ast, [Translator.translate!(unit, env)]}) - {the_type, _, params} when is_list(params) -> - do_make_bitstring_element({the_type, current_ast, Enum.map(params, &Translator.translate!(&1, env))}) - {the_type, _, _} -> - do_make_bitstring_element({the_type, current_ast}) - end - end) - end - - defp bitstring_class() do - JS.member_expression( - JS.member_expression( - JS.identifier("Bootstrap"), - JS.identifier("Core") - ), - JS.identifier("BitString") - ) - end - - defp do_make_bitstring_element({type, ast}) do - JS.call_expression( - JS.member_expression( - bitstring_class, - JS.identifier(type) - ), - [ - ast - ] - ) - end - - defp do_make_bitstring_element({type, ast, params}) when is_list(params) do - JS.call_expression( - JS.member_expression( - bitstring_class, - JS.identifier(type) - ), - [ - ast - ] ++ params - ) - end - - def make_interpolated_string(elements, env) do - translated_elements = Enum.map(elements, fn(x)-> - case x do - elem when is_binary(elem) -> - Translator.translate!(elem, env) - {:::, _, data} -> - Translator.translate!(hd(data), env) - end - end) - - { do_make_interpolated_string(tl(translated_elements), hd(translated_elements), env), env } - end - - defp do_make_interpolated_string([], ast, _) do - ast - end - - defp do_make_interpolated_string(elements, ast, env) do - JS.binary_expression( - :+, - ast, - do_make_interpolated_string(tl(elements), hd(elements), env) - ) - end - -end diff --git a/lib/elixir_script/translator/kernel/special_forms/block.ex b/lib/elixir_script/translator/kernel/special_forms/block.ex deleted file mode 100644 index 52689574..00000000 --- a/lib/elixir_script/translator/kernel/special_forms/block.ex +++ /dev/null @@ -1,14 +0,0 @@ -defmodule ElixirScript.Translator.Block do - @moduledoc false - alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator - - def make_block(expressions, env) do - { list, env } = Enum.map_reduce(expressions, env, fn(x, updated_env) -> - Translator.translate(x, updated_env) - end) - - { JS.block_statement(list), env } - end - -end diff --git a/lib/elixir_script/translator/kernel/special_forms/call.ex b/lib/elixir_script/translator/kernel/special_forms/call.ex deleted file mode 100644 index 9225c00d..00000000 --- a/lib/elixir_script/translator/kernel/special_forms/call.ex +++ /dev/null @@ -1,211 +0,0 @@ -defmodule ElixirScript.Translator.Call do - @moduledoc false - alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator - alias ElixirScript.Translator.Utils - alias ElixirScript.Translator.Identifier - - def make_module_name(module_name, env) do - members = ["Elixir"] ++ Module.split(module_name) - { Identifier.make_namespace_members(members), env } - end - - def make_extern_module_name(module_name, env) do - members = Module.split(module_name) - { Identifier.make_namespace_members(members), env } - end - - def make_local_function_call({fun, _, nil}, params, env) do - ast = JS.call_expression( - Identifier.make_identifier(fun), - Enum.map(params, &Translator.translate!(&1, env)) - ) - - {ast, env} - end - - def make_local_function_call(function_name, params, env) do - ast = JS.call_expression( - Identifier.make_identifier(function_name), - Enum.map(params, &Translator.translate!(&1, env)) - ) - - {ast, env} - end - - def make_module_function_call(module_name, function_name, params, env) do - members = ["Elixir"] ++ Module.split(module_name) ++ ["__load"] - - ast = JS.call_expression( - JS.member_expression( - JS.call_expression( - Identifier.make_namespace_members(members), - [JS.identifier("Elixir")] - ), - Identifier.make_identifier(function_name) - ), - Enum.map(params, &Translator.translate!(&1, env)) - ) - - {ast, env} - end - - def make_module_function_call(module_name, function_name, env) do - make_module_function_call(module_name, function_name, [], env) - end - - def make_extern_function_or_property_call(module_name, function_name, env) do - members = Module.split(module_name) - Identifier.make_namespace_members(members) - - js_ast = JS.call_expression( - JS.member_expression( - JS.member_expression( - JS.identifier("Bootstrap"), - JS.member_expression( - JS.identifier("Core"), - JS.identifier("Functions") - ) - ), - JS.identifier("call_property") - ), - [ - Identifier.make_namespace_members(members), - Translator.translate!(to_string(function_name), env) - ] - ) - - {js_ast, env} - end - - def make_extern_function_call(module_name, function_name, params, env) do - members = Module.split(module_name) ++ [to_string(function_name)] - - ast = JS.call_expression( - Identifier.make_namespace_members(members), - Enum.map(params, &Translator.translate!(&1, env)) - ) - - {ast, env} - end - - def make_function_or_property_call(module_name, function_name, env) do - js_ast = JS.call_expression( - JS.member_expression( - JS.member_expression( - JS.identifier("Bootstrap"), - JS.member_expression( - JS.identifier("Core"), - JS.identifier("Functions") - ) - ), - JS.identifier("call_property") - ), - [ - Translator.translate!(module_name), - Translator.translate!(to_string(function_name), env) - ] - ) - - { js_ast, env } - end - - def make_function_call(module_name, function_name, [], env) when is_atom(module_name) and is_atom(function_name) do - js_ast = JS.call_expression( - JS.member_expression( - JS.member_expression( - JS.identifier("Bootstrap"), - JS.member_expression( - JS.identifier("Core"), - JS.identifier("Functions") - ) - ), - JS.identifier("call_property") - ), - [ - Identifier.make_identifier(module_name), - Translator.translate!(to_string(function_name), env) - ] - ) - - {js_ast, env} - end - - def make_function_call(module_name, function_name, params, env) when is_atom(module_name) and is_atom(function_name) do - js_ast = JS.call_expression( - JS.member_expression( - Identifier.make_identifier(module_name), - Identifier.make_identifier(function_name) - ), - Enum.map(params, &Translator.translate!(&1, env)) - ) - - {js_ast, env} - end - - def make_function_call({{:., _, _}, _, _} = module_name, function_name, [], env) do - js_ast = JS.call_expression( - JS.member_expression( - JS.member_expression( - JS.identifier("Bootstrap"), - JS.member_expression( - JS.identifier("Core"), - JS.identifier("Functions") - ) - ), - JS.identifier("call_property") - ), - [ - Translator.translate!(module_name, env), - Translator.translate!(to_string(function_name), env) - ] - ) - - {js_ast, env} - end - - def make_function_call({{:., _, _}, _, _} = module_name, function_name, params, env) do - js_ast = JS.call_expression( - JS.member_expression( - Translator.translate!(module_name, env), - Identifier.make_identifier(function_name) - ), - Enum.map(params, &Translator.translate!(&1, env)) - ) - - {js_ast, env} - end - - def make_function_call(module_name, function_name, [], env) do - js_ast = JS.call_expression( - JS.member_expression( - JS.member_expression( - JS.identifier("Bootstrap"), - JS.member_expression( - JS.identifier("Core"), - JS.identifier("Functions") - ) - ), - JS.identifier("call_property") - ), - [ - Translator.translate!(module_name, env), - Translator.translate!(to_string(function_name), env) - ] - ) - - {js_ast, env} - end - - def make_function_call(module_name, function_name, params, env) do - call = JS.call_expression( - JS.member_expression( - Translator.translate!(module_name, env), - Identifier.make_identifier(function_name) - ), - Enum.map(params, &Translator.translate!(&1, env)) - ) - - { call, env } - end -end diff --git a/lib/elixir_script/translator/kernel/special_forms/capture.ex b/lib/elixir_script/translator/kernel/special_forms/capture.ex deleted file mode 100644 index ec398f95..00000000 --- a/lib/elixir_script/translator/kernel/special_forms/capture.ex +++ /dev/null @@ -1,44 +0,0 @@ -defmodule ElixirScript.Translator.Capture do - @moduledoc false - - alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator.PatternMatching - alias ElixirScript.Translator.Function - alias ElixirScript.Translator.Call - alias ElixirScript.Translator.Identifier - alias ElixirScript.Translator - - def make_capture(function_name, _, _) do - Identifier.make_identifier(function_name) - end - - def make_capture(module_name, function_name, _, env) do - members = ["Elixir"] ++ Module.split(module_name) ++ ["__load"] - - ast = JS.member_expression( - JS.call_expression( - Identifier.make_namespace_members(members), - [JS.identifier("Elixir")] - ), - Identifier.make_identifier(function_name) - ) - end - - def make_extern_capture(module_name, function_name, _, env) do - members = Module.split(module_name) ++ [to_string(function_name)] - Identifier.make_namespace_members(members) - end - - def find_value_placeholders(ast) do - case ast do - list when is_list(list) -> - Enum.map(list, &find_value_placeholders(&1)) - {:&, _, [number]} when is_number(number) -> - [{String.to_atom("__#{number}"), [], ElixirScript.Translator.Capture}] - tuple when is_tuple(tuple) -> - Enum.map(Tuple.to_list(tuple), &find_value_placeholders(&1)) - _ -> - [] - end - end -end diff --git a/lib/elixir_script/translator/kernel/special_forms/case.ex b/lib/elixir_script/translator/kernel/special_forms/case.ex deleted file mode 100644 index 5d1215e3..00000000 --- a/lib/elixir_script/translator/kernel/special_forms/case.ex +++ /dev/null @@ -1,17 +0,0 @@ -defmodule ElixirScript.Translator.Case do - @moduledoc false - alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator - alias ElixirScript.Translator.Function - - def make_case(condition, clauses, env) do - { func, env } = Function.make_anonymous_function(clauses, env) - - js_ast = JS.call_expression( - JS.member_expression( func, JS.identifier("call")), - [JS.identifier(:this), Translator.translate!(condition, env)] - ) - - { js_ast, env } - end -end diff --git a/lib/elixir_script/translator/kernel/special_forms/cond.ex b/lib/elixir_script/translator/kernel/special_forms/cond.ex deleted file mode 100644 index a9959972..00000000 --- a/lib/elixir_script/translator/kernel/special_forms/cond.ex +++ /dev/null @@ -1,34 +0,0 @@ -defmodule ElixirScript.Translator.Cond do - @moduledoc false - - alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator - alias ElixirScript.Translator.Primitive - alias ElixirScript.Translator.Function - - def make_cond(clauses, env) do - js_ast = JS.call_expression( - JS.member_expression( - Primitive.special_forms(), - JS.identifier("cond") - ), - process_cond(clauses, env) - ) - - { js_ast, env } - end - - defp process_cond(clauses, env) do - Enum.map(clauses, fn({:->, _, [clause, clause_body]}) -> - { translated_body, env } = Function.prepare_function_body(clause_body, env) - - translated_body = JS.block_statement(translated_body) - function = JS.function_expression([], [], translated_body) - translated_clause = Translator.translate!(hd(clause), env) - - - Primitive.make_list_no_translate([translated_clause, function]) - end) - end - -end diff --git a/lib/elixir_script/translator/kernel/special_forms/fn.ex b/lib/elixir_script/translator/kernel/special_forms/fn.ex deleted file mode 100644 index ffd6329a..00000000 --- a/lib/elixir_script/translator/kernel/special_forms/fn.ex +++ /dev/null @@ -1,254 +0,0 @@ -defmodule ElixirScript.Translator.Function do - @moduledoc false - alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator - alias ElixirScript.Translator.Group - alias ElixirScript.Translator.PatternMatching - alias ElixirScript.Translator.Block - - @patterns JS.member_expression( - JS.member_expression( - JS.identifier("Bootstrap"), - JS.identifier("Core") - ), - JS.identifier("Patterns") - ) - - @spec make_anonymous_function(list(), ElixirScript.Translator.LexicalScope.t, binary | atom) :: tuple() - def make_anonymous_function(functions, env, name \\ nil) - - def make_anonymous_function(functions, env, name) do - clauses = functions - |> Enum.map(fn - ({:->, _, [[{:when, _, params}], body ]}) -> - guards = List.last(params) - params = params |> Enum.reverse |> tl |> Enum.reverse - process_function_body(params, body, env, name, guards) - - ({:->, _, [params, body]}) -> - process_function_body(params, body, env, name) - - ({_, _, [{:when, _, [{_, _, params}, guards]}, body]}) -> - body = convert_to_try(body) - process_function_body(params, body, env, name, guards) - - ({_, _, [{_, _, params}, body]}) -> - body = convert_to_try(body) - process_function_body(params, body, env, name) - - ({_, _, [{_, _, params}]}) -> - process_function_body(params, [], env, name) - end) - - {make_defmatch(clauses, env.context == :generator), env} - end - - defp convert_to_try([do: body]) do - body - end - - defp convert_to_try(function_kw_list) do - {:__block__, [], [{:try, [], [function_kw_list]}]} - end - - defp make_defmatch(clauses, true) do - JS.call_expression( - JS.member_expression( - @patterns, - JS.identifier("defmatchgen") - ), - clauses - ) - end - - defp make_defmatch(clauses, _) do - JS.call_expression( - JS.member_expression( - @patterns, - JS.identifier("defmatch") - ), - clauses - ) - end - - defp process_function_body(params, body, env, name, guards \\ nil) do - env = ElixirScript.Translator.LexicalScope.function_scope(env, {name, get_arity(params)}) - - {patterns, params, env} = process_params(params, env) - {body, _} = make_function_body(body, env) - - if guards do - guards = case guards do - {:when, _, whens} -> - whens - wh -> - List.wrap(wh) - end - - guards = guards - |> Enum.reverse - |> process_guards - - {guard_body, _} = prepare_function_body(guards, %{env | context: :guard}) - - guard_body = JS.block_statement(guard_body) - make_function_clause(patterns, params, body, guard_body, env.context == :generator) - else - make_function_clause(patterns, params, body, nil, env.context == :generator) - end - end - - defp process_guards([guard]) do - guard - end - - defp process_guards([head | tail]) do - {:or, [], [process_guards(tail), head]} - end - - defp wrap_params(params) when is_atom(params), do: [] - defp wrap_params(params), do: List.wrap(params) - - @spec make_function_body(list | tuple, ElixirScript.Translator.LexicalScope.t) :: tuple() - def make_function_body(body, env) do - {body, _} = body - |> prepare_function_body(env) - - - {JS.block_statement(body), env} - end - - defp get_arity(params) when is_atom(params), do: 0 - defp get_arity(params) when is_tuple(params), do: 1 - defp get_arity(params), do: length(params) - - defp make_params(params) do - Enum.filter(params, fn - (%ESTree.Identifier{name: :undefined}) -> false - (_) -> true - end) - end - - defp process_params(params, env) do - params = wrap_params(params) - {patterns, params, env} = PatternMatching.process_match(params, env) - {patterns, make_params(params), env} - end - - defp make_function_clause(patterns, params, body, guard_body, is_generator?) do - - arguments = case guard_body do - nil -> - [ - JS.array_expression(patterns), - JS.function_expression(params, [], body, is_generator?) - ] - _ -> - [ - JS.array_expression(patterns), - JS.function_expression(params, [], body, is_generator?), - JS.function_expression(params, [], guard_body) - ] - end - - - JS.call_expression( - JS.member_expression( - @patterns, - JS.identifier("clause") - ), - arguments - ) - end - - def prepare_function_body(body, env) do - {list, env} = case body do - nil -> - {[], env} - list when is_list(list) -> - t = Translator.translate!(list, env) - {[t], env} - {:__block__, _, list} -> - Enum.map_reduce(list, env, fn(x, env) -> - Translator.translate(x, env) - end) - _ -> - - Enum.map_reduce(List.wrap(body), env, fn(x, env) -> - Translator.translate(x, env) - end) - end - - list = Group.inflate_groups(list) - |> return_last_expression - - {list, env} - end - - defp return_last_expression(nil) do - nil - end - - defp return_last_expression([]) do - [JS.return_statement(JS.literal(nil))] - end - - defp return_last_expression(%ESTree.BlockStatement{} = block) do - %ESTree.BlockStatement{block | body: return_last_expression(block.body)} - end - - defp return_last_expression(list) when is_list(list) do - last_item = List.last(list) - - last_item = case last_item do - %ESTree.YieldExpression{} -> - JS.return_statement(last_item) - %ESTree.Literal{} -> - JS.return_statement(last_item) - %ESTree.Identifier{} -> - JS.return_statement(last_item) - %ESTree.VariableDeclaration{} -> - declaration = hd(last_item.declarations).id - - return_statement = case declaration do - %ESTree.ArrayPattern{elements: elements} -> - if(length(elements) == 1) do - JS.return_statement(hd(declaration.elements)) - else - JS.return_statement(JS.array_expression(declaration.elements)) - end - _ -> - JS.return_statement(declaration) - end - - [last_item, return_statement] - %ESTree.BlockStatement{} -> - last_item = %ESTree.BlockStatement{last_item | body: return_last_expression(last_item.body)} - _ -> - if String.contains?(last_item.type, "Expression") do - JS.return_statement(last_item) - else - [last_item, JS.return_statement(JS.literal(nil))] - end - end - - - list = Enum.take(list, length(list)-1) - |> Enum.map(fn(x) -> - case x do - %ESTree.MemberExpression{} -> - JS.expression_statement(x) - %ESTree.CallExpression{} -> - JS.expression_statement(x) - _ -> - x - end - end) - - if is_list(last_item) do - list ++ last_item - else - list ++ [last_item] - end - end -end diff --git a/lib/elixir_script/translator/kernel/special_forms/for.ex b/lib/elixir_script/translator/kernel/special_forms/for.ex deleted file mode 100644 index 45c076da..00000000 --- a/lib/elixir_script/translator/kernel/special_forms/for.ex +++ /dev/null @@ -1,121 +0,0 @@ -defmodule ElixirScript.Translator.For do - @moduledoc false - alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator - alias ElixirScript.Translator.PatternMatching - alias ElixirScript.Translator.Primitive - alias ElixirScript.Translator.Function - alias ElixirScript.Translator.Utils - - def make_for(generators, env) do - ElixirScript.Translator.State.add_module_reference(env.state, env.module, ElixirScript.Collectable) - args = handle_args(generators, env) - - generators = JS.array_expression(args.generators) - - into = args.into || Primitive.make_list_no_translate([]) - filter = args.filter || JS.function_expression([], [], JS.block_statement([JS.return_statement(JS.identifier("true"))])) - fun = args.fun - - expression = JS.call_expression( - JS.member_expression( - JS.member_expression( - JS.member_expression( - JS.identifier("Bootstrap"), - JS.identifier("Core") - ), - JS.identifier("Patterns") - ), - JS.identifier("clause") - ), - [JS.array_expression(args.patterns), fun, filter] - ) - - js_ast = JS.call_expression( - JS.member_expression( - Primitive.special_forms(), - JS.identifier("_for") - ), - [expression, generators, JS.identifier(Utils.name_to_js_name(ElixirScript.Collectable)), into] - ) - - {js_ast, env} - end - - defp handle_args(generators, env) do - Enum.reduce(generators, %{generators: [], args: [], filter: nil, fun: nil, into: nil, patterns: []}, fn - - ({:<<>>, [], body}, state) -> - {bs_parts, collection} = Enum.map_reduce(body, nil, fn - {:::, _, _} = ast, state -> - {ast, state} - {:<-, [], [var, collection]}, _ -> - {var, collection} - end) - - {patterns, params, env} = PatternMatching.process_match([{:<<>>, [], bs_parts}], env) - - gen = JS.call_expression( - JS.member_expression( - JS.member_expression( - JS.member_expression( - JS.identifier("Bootstrap"), - JS.identifier("Core") - ), - JS.identifier("Patterns") - ), - JS.identifier("bitstring_generator") - ), - [hd(patterns), Translator.translate!(collection, env)] - ) - - %{state | generators: state.generators ++ [gen], args: state.args ++ params, patterns: state.patterns ++ patterns} - - ({:<-, _, [identifier, enum]}, state) -> - {patterns, params, env} = PatternMatching.process_match([identifier], env) - - gen = JS.call_expression( - JS.member_expression( - JS.member_expression( - JS.member_expression( - JS.identifier("Bootstrap"), - JS.identifier("Core") - ), - JS.identifier("Patterns") - ), - JS.identifier("list_generator") - ), - [hd(patterns), Translator.translate!(enum, env)] - ) - - %{state | generators: state.generators ++ [gen], args: state.args ++ params, patterns: state.patterns ++ patterns} - ([into: expression], state) -> - %{state | into: Translator.translate(expression, env)} - - ([into: expression, do: expression2], state) -> - fun = create_function_expression(expression2, env, state) - - %{state | into: Translator.translate!(expression, env), fun: fun} - - ([do: expression], state) -> - fun = create_function_expression(expression, env, state) - - %{state | fun: fun} - (filter, state) -> - fun = create_function_expression(filter, env, state) - - %{state | filter: fun} - end) - end - - - defp create_function_expression(ast, env, state) do - {ast, _} = Function.make_function_body(ast, env) - - JS.function_expression( - state.args, - [], - ast - ) - end -end diff --git a/lib/elixir_script/translator/kernel/special_forms/map.ex b/lib/elixir_script/translator/kernel/special_forms/map.ex deleted file mode 100644 index 02f17691..00000000 --- a/lib/elixir_script/translator/kernel/special_forms/map.ex +++ /dev/null @@ -1,79 +0,0 @@ -defmodule ElixirScript.Translator.Map do - @moduledoc false - alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator - alias ElixirScript.Translator.Primitive - - def make_map(object_expression) do - JS.call_expression( - JS.member_expression( - JS.identifier(:Object), - JS.identifier(:freeze) - ), - [object_expression] - ) - end - - def make_get_property(target, property, env) do - JS.member_expression( - Translator.translate!(target, env), - Translator.translate!(property, env), - true - ) - end - - def make_object(properties, env) do - properties - |> Enum.map(fn - ({x, {:__aliases__, _, [value]}}) -> make_property(Translator.translate!(x, env), JS.identifier(value)) - ({x, y}) -> - case x do - {_, _, atom } when is_atom(atom) -> - JS.property(Translator.translate!(x, env), Translator.translate!(y, env), :init, false, false, true) - _ -> - make_property(Translator.translate!(x, env), Translator.translate!(y, env)) - end - end) - |> JS.object_expression - |> make_map - end - - def make_property(%ESTree.Identifier{} = key, value) do - JS.property(key, value) - end - - def make_property(%ESTree.Literal{value: k}, value) when is_binary(k) do - key = case String.contains?(k, "-") do - true -> - JS.literal(k) - false -> - JS.identifier(k) - end - - JS.property(key, value) - end - - def make_property(key, value) do - JS.property(key, value, :init, false, false, true) - end - - def make_shorthand_property(%ESTree.Identifier{} = key) do - JS.property(key, key, :init, true) - end - - def make_map_update(map, data, env) do - map = Translator.translate!(map, env) - data = Translator.translate!({:%{}, [], data}, env) - - js_ast = JS.call_expression( - JS.member_expression( - Primitive.special_forms(), - JS.identifier("map_update") - ), - [map, data] - ) - - { js_ast, env } - end - -end diff --git a/lib/elixir_script/translator/kernel/special_forms/match.ex b/lib/elixir_script/translator/kernel/special_forms/match.ex deleted file mode 100644 index b59ffd64..00000000 --- a/lib/elixir_script/translator/kernel/special_forms/match.ex +++ /dev/null @@ -1,93 +0,0 @@ -defmodule ElixirScript.Translator.Match do - @moduledoc false - alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator - alias ElixirScript.Translator.PatternMatching - alias ElixirScript.Translator.Primitive - - def make_match(left, right, env) do - { right_ast, env } = Translator.translate(right, env) - - { patterns, params, env } = PatternMatching.process_match([left], env) - - declarator = JS.variable_declarator( - JS.array_pattern(params), - JS.call_expression( - JS.member_expression( - JS.member_expression( - JS.member_expression( - JS.identifier("Bootstrap"), - JS.identifier("Core") - ), - JS.identifier("Patterns") - ), - JS.identifier("match") - ), - [hd(patterns), right_ast] - ) - ) - - array_pattern = JS.variable_declaration([declarator], :let) - - js_ast = case left do - list when is_list(list) -> - make_list_ref(array_pattern, params) - { _, _ } -> - make_tuple_ref(array_pattern, params) - {:{}, _, _ } -> - make_tuple_ref(array_pattern, params) - _ -> - array_pattern - end - - { js_ast, env } - end - - defp make_list_ref(array_pattern, params) do - {ref, params} = make_params(params) - - ref_declarator = JS.variable_declarator( - ref, - Primitive.do_make_list(params) - ) - - make_variable_declaration_and_group(ref_declarator, array_pattern) - end - - defp make_tuple_ref(array_pattern, params) do - {ref, params} = make_params(params) - - ref_declarator = JS.variable_declarator( - ref, - JS.new_expression( - JS.member_expression( - JS.identifier("Bootstrap"), - JS.member_expression( - JS.identifier("Core"), - JS.identifier("Tuple") - ) - ), - params - ) - ) - - make_variable_declaration_and_group(ref_declarator, array_pattern) - end - - - defp make_params(params) do - ref = JS.identifier("_ref") - - params = Enum.map(params, fn - (nil) -> JS.identifier(:undefined) - (x) -> x - end) - - { ref, params } - end - - defp make_variable_declaration_and_group(ref_declarator, array_pattern) do - ref_declaration = JS.variable_declaration([ref_declarator], :let) - %ElixirScript.Translator.Group{ body: [array_pattern, ref_declaration] } - end -end diff --git a/lib/elixir_script/translator/kernel/special_forms/primitive.ex b/lib/elixir_script/translator/kernel/special_forms/primitive.ex deleted file mode 100644 index 292ccbcc..00000000 --- a/lib/elixir_script/translator/kernel/special_forms/primitive.ex +++ /dev/null @@ -1,99 +0,0 @@ -defmodule ElixirScript.Translator.Primitive do - @moduledoc false - alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator - alias ElixirScript.Translator.Quote - - def special_forms() do - JS.member_expression( - JS.identifier("Bootstrap"), - JS.member_expression( - JS.identifier("Core"), - JS.identifier("SpecialForms") - ) - ) - end - - def tuple_class() do - JS.member_expression( - JS.member_expression( - JS.identifier("Bootstrap"), - JS.identifier("Core") - ), - JS.identifier("Tuple") - ) - end - - def list_ast() do - JS.member_expression( - JS.member_expression( - JS.identifier("Bootstrap"), - JS.member_expression( - JS.identifier("Core"), - JS.identifier("SpecialForms") - ) - ), - JS.identifier("list") - ) - end - - def make_atom(ast) when is_atom(ast) do - JS.call_expression( - JS.member_expression( - JS.identifier("Symbol"), - JS.identifier("for") - ), - [JS.literal(ast)] - ) - end - - def make_literal(ast) when is_number(ast) or is_binary(ast) or is_boolean(ast) or is_nil(ast) do - JS.literal(ast) - end - - def make_list(ast, env) when is_list(ast) do - js_ast = Enum.map(ast, &Translator.translate!(&1, env)) - |> do_make_list - - { js_ast, env } - end - - def make_list_quoted(opts, ast, env) when is_list(ast) do - Enum.map(ast, fn(x) -> Quote.make_quote(opts, x, env) end) - |> do_make_list - end - - def make_list_no_translate(ast) when is_list(ast) do - do_make_list(ast) - end - - def do_make_list(ast) do - JS.call_expression( - JS.member_expression( - JS.identifier("Object"), - JS.identifier("freeze") - ), - [JS.array_expression(ast)] - ) - end - - def make_tuple({ one, two }, env) do - make_tuple([one, two], env) - end - - def make_tuple(elements, env) do - list = Enum.map(elements, &Translator.translate!(&1, env)) - - js_ast = JS.new_expression(tuple_class, list) - - { js_ast, env } - end - - def make_tuple_quoted(opts, elements, env) do - JS.new_expression( - tuple_class, - Enum.map(elements, fn(x) -> Quote.make_quote(opts, x, env) end) - ) - end - -end diff --git a/lib/elixir_script/translator/kernel/special_forms/quote.ex b/lib/elixir_script/translator/kernel/special_forms/quote.ex deleted file mode 100644 index d0b7d03d..00000000 --- a/lib/elixir_script/translator/kernel/special_forms/quote.ex +++ /dev/null @@ -1,87 +0,0 @@ -defmodule ElixirScript.Translator.Quote do - @moduledoc false - - alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator - alias ElixirScript.Translator.Primitive - - def make_quote(_opts, expr, env) when is_number(expr) or is_binary(expr) or is_boolean(expr) or is_nil(expr) or is_atom(expr) do - Translator.translate!(expr, env) - end - - def make_quote(opts, expr, env) when is_list(expr) do - has_unquote_splicing = Enum.any?(expr, fn - ({:unquote_splicing, _, _}) -> true - (_) -> false - end) - - if(has_unquote_splicing) do - expr = Enum.map(expr, fn - ({:unquote_splicing, _, [param]}) -> - make_unquote_slicing(param, env) - (x) -> - Primitive.make_list_no_translate([make_quote(opts, x, env)]) - end - ) - - JS.call_expression( - JS.member_expression( - JS.identifier("Bootstrap"), - JS.member_expression( - JS.identifier("Enum"), - JS.identifier("concat") - ) - ), - expr - ) - else - Primitive.make_list_quoted(opts, expr, env) - end - end - - def make_quote(opts, {one, two}, env) do - Primitive.make_tuple_quoted(opts, [one, two], env) - end - - def make_quote([unquote: false] = opts, {:unquote, context, params}, env) do - Primitive.make_tuple_quoted(opts, [:unquote, context, params], env) - end - - def make_quote([context: {_, _, [new_context]}] = opts, {name, context, params}, env) do - updated_context = Keyword.put(context, :context, new_context) - Primitive.make_tuple_quoted(opts, [name, updated_context, params], env) - end - - def make_quote(_, {:alias!, _, [the_alias]}, _) do - the_alias - end - - def make_quote(_, {:unquote, _, [param]}, env) do - make_unquote(param, env) - end - - def make_quote(opts, {name, context, elements }, env) do - if is_in_bind_quoted(opts[:bind_quoted], name) do - Translator.translate!({name, context, elements }, env) - else - Primitive.make_tuple_quoted(opts, [name, context, elements], env) - end - end - - def make_unquote(expr, env) do - Translator.translate!(expr, env) - end - - def make_unquote_slicing(expr, env) do - Translator.translate!(expr, env) - end - - defp is_in_bind_quoted(nil, _) do - false - end - - defp is_in_bind_quoted(binds, name) do - binds[name] != nil - end - -end diff --git a/lib/elixir_script/translator/kernel/special_forms/struct.ex b/lib/elixir_script/translator/kernel/special_forms/struct.ex deleted file mode 100644 index 84c5becb..00000000 --- a/lib/elixir_script/translator/kernel/special_forms/struct.ex +++ /dev/null @@ -1,138 +0,0 @@ -defmodule ElixirScript.Translator.Struct do - @moduledoc false - alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator - alias ElixirScript.Translator.Utils - alias ElixirScript.Translator.Map - alias ElixirScript.Translator.Identifier - - def get_struct_class(module_name, env) do - candiate_module_name = ElixirScript.Translator.State.get_module_name(env.state, Utils.quoted_to_name(module_name)) - - if ElixirScript.Translator.LexicalScope.get_module_name(env, candiate_module_name) in ElixirScript.Translator.State.list_module_names(env.state) do - name = ElixirScript.Translator.LexicalScope.get_module_name(env, candiate_module_name) - ident = JS.identifier(Utils.name_to_js_name(name)) - ElixirScript.Translator.State.add_module_reference(env.state, env.module, name) - - members = ["Elixir"] ++ Module.split(name) ++ ["__load"] - - JS.member_expression( - JS.call_expression( - Identifier.make_namespace_members(members), - [JS.identifier("Elixir")] - ), - ident - ) - - else - Identifier.make_identifier(module_name) - end - end - - def new_struct(module_name, data, env) do - JS.call_expression( - JS.member_expression( - get_struct_class(module_name, env), - JS.identifier(:create) - ), - [Translator.translate!(data, env)] - ) - end - - def make_defstruct(attributes, env) when length(attributes) == 1 do - attributes = Enum.flat_map(attributes, fn(x) -> x end) - - defaults = Enum.map(attributes, fn - ({x, y}) -> - Map.make_property( - Translator.translate!(x, env), - Translator.translate!(y, env) - ) - (attribute) -> - Map.make_property( - Translator.translate!(attribute, env), - Translator.translate!(nil, env) - ) - end) - |> JS.object_expression - - do_make_defstruct(:defstruct, defaults, env) - end - - def make_defstruct(attributes, env) do - defaults = Enum.map(attributes, fn(x) -> - Map.make_property( - Translator.translate!(x, env), - Translator.translate!(nil, env) - ) - end) - |> JS.object_expression - - do_make_defstruct(:defstruct, defaults, env) - end - - def make_defexception(attributes, env) when length(attributes) == 1 do - exception_key_value = Map.make_property(Translator.translate!(:__exception__, env), Translator.translate!(true, env)) - - attributes = Enum.flat_map(attributes, fn(x) -> x end) - - defaults = [exception_key_value] ++ Enum.map(attributes, fn - ({x, y}) -> - Map.make_property( - Translator.translate!(x, env), - Translator.translate!(y, env) - ) - (x) -> - Map.make_property( - Translator.translate!(x, env), - Translator.translate!(nil, env) - ) - end) - |> JS.object_expression - - do_make_defstruct(:defexception, defaults, env) - end - - def make_defexceptions(attributes, env) do - exception_key_value = Map.make_property(Translator.translate!(:__exception__, env), Translator.translate!(true, env)) - - defaults = [exception_key_value] ++ Enum.map(attributes, fn - (x) -> - Map.make_property( - Translator.translate!(x, env), - Translator.translate!(nil, env) - ) - end) - |> JS.object_expression - - do_make_defstruct(:defexception, defaults, env) - end - - defp do_make_defstruct(name, defaults, env) do - struct_name = Map.make_property(Translator.translate!(:__struct__, env), Translator.translate!({:__MODULE__, [], []}, env)) - - defaults = %{ defaults | properties: [struct_name] ++ defaults.properties } - - ref = JS.identifier(Utils.name_to_js_name(env.module)) - - ref_declarator = JS.variable_declarator( - ref, - JS.call_expression( - JS.member_expression( - JS.member_expression( - JS.identifier("Bootstrap"), - JS.member_expression( - JS.identifier("Core"), - JS.identifier("Functions") - ) - ), - JS.identifier(name) - ), - [defaults] - ) - ) - - JS.variable_declaration([ref_declarator], :const) - end - -end diff --git a/lib/elixir_script/translator/kernel/special_forms/try.ex b/lib/elixir_script/translator/kernel/special_forms/try.ex deleted file mode 100644 index 81db4a39..00000000 --- a/lib/elixir_script/translator/kernel/special_forms/try.ex +++ /dev/null @@ -1,112 +0,0 @@ -defmodule ElixirScript.Translator.Try do - @moduledoc false - alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator.Function - alias ElixirScript.Translator.Primitive - - def make_try(blocks, env) do - try_block = Dict.get(blocks, :do) - rescue_block = Dict.get(blocks, :rescue, nil) - catch_block = Dict.get(blocks, :catch, nil) - after_block = Dict.get(blocks, :after, nil) - else_block = Dict.get(blocks, :else, nil) - - { translated_body, _ } = Function.prepare_function_body(try_block, env) - - translated_body = JS.block_statement(translated_body) - try_block = JS.function_expression([], [], translated_body) - - rescue_block = if rescue_block do - process_rescue_block(rescue_block, env) - else - JS.identifier(:null) - end - - catch_block = if catch_block do - process_catch_block(catch_block, env) - else - JS.identifier(:null) - end - - after_block = if after_block do - process_after_block(after_block, env) - else - JS.identifier(:null) - end - - else_block = if else_block do - Function.make_anonymous_function(else_block, env) - |> elem(0) - else - JS.identifier(:null) - end - - js_ast = JS.call_expression( - JS.member_expression( - Primitive.special_forms(), - JS.identifier("_try") - ), - [ - try_block, - rescue_block, - catch_block, - else_block, - after_block - ] - ) - - { js_ast, env } - end - - defp process_rescue_block(rescue_block, env) do - { func, _ } = Enum.map(rescue_block, fn(x) -> - case x do - {:->, _, [[{value, _, module}], block]} when not is_list(module) -> - {:->, [], [[{value, [], convert_to_struct(module)}], block]} - {:->, _, [[{:in, meta, [value, error_names]}], block]} -> - error_names = Enum.map(error_names, fn(x) -> - convert_to_struct(x) - end) - - guards = {:in, meta, [value, error_names]} - - {:->, [], [ [{:when, [], [value | [guards]]}], block ]} - {:->, _, [error_names, block]} -> - Enum.map(error_names, fn(x) -> - {:->, [], [[convert_to_struct(x)], block]} - end) - end - end) - |> List.flatten - |> Function.make_anonymous_function(env) - - func - end - - defp process_catch_block(catch_block, env) do - {func, _} = catch_block - |> Function.make_anonymous_function(env) - - func - end - - defp process_after_block(after_block, env) do - { translated_body, _ } = Function.prepare_function_body(after_block, env) - translated_body = JS.block_statement(translated_body) - - JS.function_expression([], [], translated_body) - end - - defp convert_to_struct([module]) do - convert_to_struct(module) - end - - defp convert_to_struct(module) do - case module do - {:__aliases__, _, _} = alias_ast-> - {:%, [], [alias_ast, {:%{}, [], []}]} - ast -> - ast - end - end -end diff --git a/lib/elixir_script/translator/kernel/special_forms/with.ex b/lib/elixir_script/translator/kernel/special_forms/with.ex deleted file mode 100644 index dbd8b7bf..00000000 --- a/lib/elixir_script/translator/kernel/special_forms/with.ex +++ /dev/null @@ -1,52 +0,0 @@ -defmodule ElixirScript.Translator.With do - @moduledoc false - - alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator.Function - alias ElixirScript.Translator.Primitive - alias ElixirScript.Translator.PatternMatching - - def make_with(args, env) do - result = Enum.reduce(args, %{ expressions: [], arguments: [] }, fn - {symbol, _, [pattern, expr] }, state when symbol in [:<-, :=] -> - {body , _} = Function.prepare_function_body(expr, env) - translated_body = JS.block_statement(body) - expr_function = JS.function_expression(state.arguments, [], translated_body) - - { patterns, params, _ } = PatternMatching.process_match([pattern], env) - - %{state | arguments: state.arguments ++ params, - expressions: state.expressions ++ [ JS.array_expression([hd(patterns), expr_function]) ] } - - [do: expr], state -> - expr_function = process_do_block(expr, state.arguments, env) - - %{state | expressions: state.expressions ++ [ expr_function ] } - [do: do_expr, else: else_expr], state -> - do_function = process_do_block(do_expr, state.arguments, env) - - { else_function, _ } = Function.make_anonymous_function(else_expr, env) - - %{state | expressions: state.expressions ++ [ do_function, else_function ] } - end) - - expressions = result.expressions - - js_ast = JS.call_expression( - JS.member_expression( - Primitive.special_forms(), - JS.identifier("_with") - ), - expressions - ) - - { js_ast, env } - - end - - defp process_do_block(expr, arguments, env) do - {body , _} = Function.prepare_function_body(expr, env) - translated_body = JS.block_statement(body) - JS.function_expression(arguments, [], translated_body) - end -end diff --git a/lib/elixir_script/translator/lexical_scope.ex b/lib/elixir_script/translator/lexical_scope.ex deleted file mode 100644 index 0e444c05..00000000 --- a/lib/elixir_script/translator/lexical_scope.ex +++ /dev/null @@ -1,388 +0,0 @@ -defmodule ElixirScript.Translator.LexicalScope do - @moduledoc false - - @type t :: %ElixirScript.Translator.LexicalScope{ - module: atom, - file: binary, - line: non_neg_integer, - function: { atom, non_neg_integer } | nil, - context: :match | :guard | :generator | nil, - aliases: [{atom, atom}], - requires: [atom], - functions: [{atom, [{ atom, non_neg_integer }]}], - macros: [{atom, [{ atom, non_neg_integer }]}], - macro_aliases: [{atom, {integer, atom}}], - context_modules: [atom], - vars: [{atom, atom | non_neg_integer}], - export_vars: [{atom, atom | non_neg_integer}] | nil, - lexical_tracker: nil, - caller: t | nil, - env: nil, - state: pid, - format: atom, - module_formatter: atom - } - - defstruct [ - module: nil, - file: nil, - line: 0, - function: nil, - context: nil, - aliases: [], - requires: [], - functions: [], - macros: [], - macro_aliases: [], - context_modules: [], - vars: [], - export_vars: nil, - lexical_tracker: nil, - caller: nil, - env: nil, - state: nil, - format: :es, - module_formatter: ElixirScript.ModuleSystems.ES - ] - - def env(scope) do - %Macro.Env{ - module: scope.module, - file: scope.file, - line: scope.line, - function: scope.function, - context: scope.context, - aliases: scope.aliases, - requires: scope.requires, - functions: scope.functions, - macros: scope.macros, - macro_aliases: scope.macro_aliases, - context_modules: scope.context_modules, - vars: Enum.map(scope.vars, fn({key, _}) -> {key, nil} end), - export_vars: scope.export_vars, - lexical_tracker: scope.lexical_tracker - } - end - - def caller(scope) do - %Macro.Env{ - module: scope.caller.module, - file: scope.caller.file, - line: scope.caller.line, - function: scope.caller.function, - context: scope.caller.context, - aliases: scope.caller.aliases, - requires: scope.caller.requires, - functions: scope.caller.functions, - macros: scope.caller.macros, - macro_aliases: scope.caller.macro_aliases, - context_modules: scope.caller.context_modules, - vars: Enum.map(scope.vars, fn({key, _}) -> {key, nil} end), - export_vars: scope.caller.export_vars, - lexical_tracker: scope.caller.lexical_tracker - } - end - - def module_scope(ElixirScript.Temp, filename, env, state, opts) do - - env = %ElixirScript.Translator.LexicalScope { - module: ElixirScript.Temp, file: filename, requires: [], - functions: [], - macros: [], - env: env, - state: state, - format: opts.format, - module_formatter: opts.module_formatter - } - - add_import(env, ElixirScript.Kernel) - end - - def module_scope(module_name, filename, env, state, opts) do - module = ElixirScript.Translator.State.get_module(state, module_name) - - env = %ElixirScript.Translator.LexicalScope { - module: module_name, file: filename, requires: [], - functions: [{ module.name, module.functions}], - macros: [{module.name, module.macros}], - env: env, - state: state, - format: opts.format, - module_formatter: opts.module_formatter - } - - env = add_import(env, ElixirScript.Kernel) - - cond do - module_name == JS -> - env - ElixirScript.Translator.State.is_module_loaded?(env.state, module_name) and length(module.macros) > 0 -> - add_import(env, module_name, [only: :macros]) - true -> - env - end - end - - def function_scope(env, { _, _ } = func) do - %{ env | function: func, caller: env, vars: [] } - end - - def function_scope(env, nil) do - %{ env | function: nil, caller: env } - end - - def find_module(env, name_arity) do - result = Enum.find(env.functions ++ env.macros, fn({_, functions}) -> - name_arity in functions - end) - - if result == nil do - nil - else - elem(result, 0) - end - - end - - def add_var(env, variable_name) when is_binary(variable_name) do - add_var(env, String.to_atom(variable_name)) - end - - def add_var(env, variable_name) do - %{ env | vars: Keyword.update(env.vars, variable_name, 0, &(&1 + 1)) } - end - - def get_var(env, variable_name) when is_binary(variable_name) do - get_var(env, String.to_atom(variable_name)) - end - - def get_var(env, variable_name) do - count = Keyword.get(env.vars, variable_name, nil) - - case count do - nil -> - nil - 0 -> - String.to_atom(Atom.to_string(variable_name)) - _ -> - String.to_atom(Atom.to_string(variable_name) <> to_string(count)) - end - end - - def has_var?(env, variable_name) when is_binary(variable_name) do - has_var?(env, String.to_atom(variable_name)) - end - - def has_var?(env, variable_name) do - Keyword.get(env.vars, variable_name, nil) != nil - end - - defp get_module(env, Kernel) do - get_module(env, ElixirScript.Kernel) - end - - defp get_module(env, module_name) do - module = ElixirScript.Translator.State.get_module(env.state, get_module_name(env, module_name)) - - unless module do - module_name = case module_name do - {:__aliases__, _, _} -> - ElixirScript.Translator.Utils.quoted_to_name(module_name) - |> Atom.to_string - |> String.split(".") - |> tl - |> Enum.join(".") - _ -> - module_name - end - - raise "Module #{inspect module_name} not found" - end - - if Map.get(module, :load_only, false) == false do - ElixirScript.Translator.State.add_module_reference(env.state, env.module, module.name) - end - - module - end - - defp has_module?(env, module_name) do - try do - module = get_module(env, module_name) - case module do - %{load_only: true} -> - false - _ -> - true - end - rescue - _ -> - false - end - end - - def add_alias(env, module_name, alias_name) do - module = get_module(env, module_name) - %{ env | aliases: Enum.uniq(env.aliases ++ [{alias_name, module.name}]) } - end - - def add_import(env, module_name) do - check_for_module_existence(env, module_name) - - env = if ElixirScript.Translator.State.is_module_loaded?(env.state, module_name) do - add_import_macro(env, module_name, []) - else - env - end - - if has_module?(env, module_name) do - module = get_module(env, module_name) - %{ env | requires: Enum.uniq(env.requires ++ [module.name]), - functions: env.functions ++ [{ module.name, module.functions }] - } - else - env - end - end - - def add_import(env, module_name, [only: :functions]) do - module = get_module(env, module_name) - - %{ env | functions: List.keydelete(env.functions, module_name, 0) ++ [{ module.name, module.functions }], - requires: Enum.uniq(env.requires ++ [module.name]) - } - end - - def add_import(env, module_name, [only: :macros]) do - if !ElixirScript.Translator.State.is_module_loaded?(env.state, module_name) do - raise "Module #{inspect module_name} not found" - end - - add_import_macro(env, module_name, [only: :macros]) - end - - def add_import(env, module_name, [only: only]) do - check_for_module_existence(env, module_name) - - env = if ElixirScript.Translator.State.is_module_loaded?(env.state, module_name) do - list = module_name.__info__(:macros) - list = Enum.filter(list, fn(mac) -> mac in only end) - add_import_macro(env, module_name, [only: list]) - else - env - end - - if has_module?(env, module_name) do - module = get_module(env, module_name) - - functions = Enum.filter(module.functions, fn(func) -> - func in only - end) - - %{ env | requires: Enum.uniq(env.requires ++ [module.name]), - functions: List.keydelete(env.functions, module.name, 0) ++ [{ module.name, functions }] } - else - env - end - end - - def add_import(env, module_name, [except: except]) do - check_for_module_existence(env, module_name) - - env = if ElixirScript.Translator.State.is_module_loaded?(env.state, module_name) do - list = module_name.__info__(:macros) - list = Enum.filter(list, fn(mac) -> mac in except end) - add_import_macro(env, module_name, [except: list]) - else - env - end - - if has_module?(env, module_name) do - module = get_module(env, module_name) - {_, current_functions } = List.keyfind(env.functions, module.name, 0, { module.name, module.functions }) - - functions = Enum.filter(current_functions, fn(func) -> not(func in except) end) - - %{ env | requires: env.requires ++ [module.name], - functions: List.keydelete(env.functions, module.name, 0) ++ [{ module.name, functions }] } - else - env - end - end - - def add_require(env, module_name) do - check_for_module_existence(env, module_name) - - env = if ElixirScript.Translator.State.is_module_loaded?(env.state, module_name) do - add_require_macro(env, module_name, []) - else - env - end - - if has_module?(env, module_name) do - module = get_module(env, module_name) - %{ env | requires: Enum.uniq(env.requires ++ [module.name]) } - else - env - end - end - - def add_require(env, module_name, alias_name) do - check_for_module_existence(env, module_name) - - env = if ElixirScript.Translator.State.is_module_loaded?(env.state, module_name) do - add_require_macro(env, module_name, [as: alias_name]) - else - env - end - - if has_module?(env, module_name) do - module = get_module(env, module_name) - %{ env | aliases: Enum.uniq(env.aliases ++ [{alias_name, module.name}]), - requires: Enum.uniq(env.requires ++ [module.name]) } - else - env - end - end - - def get_module_name(env, module_name) do - module_name = ElixirScript.Translator.State.get_module_name(env.state, module_name) - - if Keyword.has_key?(env.aliases, module_name) do - Keyword.fetch!(env.aliases, module_name) - else - module_name - end - - end - - defp check_for_module_existence(env, module_name) do - if ElixirScript.Translator.State.is_module_loaded?(env.state, module_name) == false and has_module?(env, module_name) == false do - raise "Module #{inspect module_name} not found" - end - end - - - defp add_import_macro(elixirscript_env, module, opts) do - eval = """ - import #{inspect module}, #{inspect opts} - __ENV__ - """ - - do_macro(eval, elixirscript_env) - end - - defp add_require_macro(elixirscript_env, module, opts) do - eval = """ - require #{inspect module}, #{inspect opts} - __ENV__ - """ - - do_macro(eval, elixirscript_env) - end - - defp do_macro(eval, elixirscript_env) do - {env, _} = Code.eval_string(eval, [], elixirscript_env.env) - %{ elixirscript_env | env: env } - end -end diff --git a/lib/elixir_script/translator/pattern_matching.ex b/lib/elixir_script/translator/pattern_matching.ex deleted file mode 100644 index 241b7f45..00000000 --- a/lib/elixir_script/translator/pattern_matching.ex +++ /dev/null @@ -1,278 +0,0 @@ -defmodule ElixirScript.Translator.PatternMatching do - @moduledoc false - - alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator - alias ElixirScript.Translator.Primitive - alias ElixirScript.Translator.Identifier - alias ElixirScript.Translator.Map - alias ElixirScript.Translator.Struct - alias ElixirScript.Translator.Bitstring - - @patterns JS.member_expression( - JS.member_expression( - JS.identifier("Bootstrap"), - JS.identifier("Core") - ), - JS.identifier("Patterns") - ) - - @wildcard JS.member_expression( - @patterns, - JS.identifier(:wildcard) - ) - - @parameter JS.member_expression( - @patterns, - JS.identifier(:variable) - ) - - @head_tail JS.member_expression( - @patterns, - JS.identifier(:headTail) - ) - - @starts_with JS.member_expression( - @patterns, - JS.identifier(:startsWith) - ) - - @capture JS.member_expression( - @patterns, - JS.identifier(:capture) - ) - - @bound JS.member_expression( - @patterns, - JS.identifier(:bound) - ) - - @_type JS.member_expression( - @patterns, - JS.identifier(:type) - ) - - @bitstring_match JS.member_expression( - @patterns, - JS.identifier(:bitStringMatch) - ) - - def wildcard() do - JS.call_expression( - @wildcard, - [] - ) - end - - def parameter() do - JS.call_expression( - @parameter, - [] - ) - end - - def parameter(default_value) do - JS.call_expression( - @parameter, - [default_value] - ) - end - - def head_tail(headParameter, tailParameter) do - JS.call_expression( - @head_tail, - [headParameter, tailParameter] - ) - end - - def starts_with(prefix) do - JS.call_expression( - @starts_with, - [JS.literal(prefix)] - ) - end - - def capture(value) do - JS.call_expression( - @capture, - [value] - ) - end - - def bound(value) do - JS.call_expression( - @bound, - [value] - ) - end - - def type(prototype, value) do - JS.call_expression( - @_type, - [prototype, value] - ) - end - - def bitstring_match(values) do - JS.call_expression( - @bitstring_match, - values - ) - end - - - def process_match(params, env) do - build_match(params, env) - |> update_env(env) - end - - defp update_env({ patterns, params }, env) do - - { params, env } = Enum.map_reduce(params, env, fn - (%ESTree.Identifier{name: :undefined} = param, env) -> - { param, env } - - (%ESTree.Identifier{} = param, env) -> - env = ElixirScript.Translator.LexicalScope.add_var(env, param.name) - new_name = ElixirScript.Translator.LexicalScope.get_var(env, param.name) - - { %{ param | name: new_name }, env } - - (param, env) -> - { param, env } - end) - - { patterns, params, env } - end - - def build_match(params, env) do - Enum.map(params, &do_build_match(&1, env)) - |> reduce_patterns - end - - defp do_build_match({:^, _, [value]}, env) do - { [bound(Translator.translate!(value, env))], [nil] } - end - - defp do_build_match({:_, _, _}, _) do - { [wildcard()], [JS.identifier(:undefined)] } - end - - defp do_build_match({:<<>>, _, elements}, env) do - params = Enum.reduce(elements, [], fn - ({:::, _, [{ variable, _, params }, _]}, state) when is_atom(params) -> - state ++ [JS.identifier(variable)] - _, state -> - state - end) - - elements = Enum.map(elements, fn - ({:::, context, [{ _, _, params }, options]}) when is_atom(params) -> - Bitstring.make_bitstring_element({:::, context, [ElixirScript.Translator.PatternMatching, options]}, env) - x -> - Bitstring.make_bitstring_element(x, env) - end) - - { [bitstring_match(elements)], params } - end - - defp do_build_match([{:|, _, [head, tail]}], env) do - { head_patterns, head_params } = do_build_match(head, env) - { tail_patterns, tail_params } = do_build_match(tail, env) - params = head_params ++ tail_params - - { [head_tail(hd(head_patterns), hd(tail_patterns))], params } - end - - defp do_build_match({:<>, _, [prefix, value]}, env) do - { [starts_with(prefix)], [Translator.translate!(value, env)] } - end - - defp do_build_match({:%{}, _, props}, env) do - properties = Enum.map(props, fn({key, value}) -> - {pattern, params} = do_build_match(value, env) - property = case key do - {:^, _, [the_key]} -> - JS.property(Translator.translate!(the_key, env), hd(List.wrap(pattern)), :init, false, false, true) - _ -> - Map.make_property(Translator.translate!(key, env), hd(List.wrap(pattern))) - end - - { property, params } - end) - - {props, params} = Enum.reduce(properties, {[], []}, fn({prop, param}, {props, params}) -> - { props ++ [prop], params ++ param } - end) - - { JS.object_expression(List.wrap(props)), params } - end - - defp do_build_match({:%, _, [{:__aliases__, _, _} = name, {:%{}, meta, props}]}, env) do - struct_name = Struct.get_struct_class(name, env) - {pattern, params} = do_build_match({:%{}, meta, props}, env) - - { [type(struct_name, pattern)], params } - end - - defp do_build_match({:=, _, [{name, _, _}, right]}, env) when not name in [:%, :{}, :__aliases__, :^, :%{}] do - unify(name, right, env) - end - - defp do_build_match({:=, _, [left, {name, _, _}]}, env) when not name in [:%, :{}, :__aliases__, :^, :%{}] do - unify(name, left, env) - end - - defp do_build_match(list, env) when is_list(list) do - { patterns, params } = list - |> Enum.map(&build_match([&1], env)) - |> reduce_patterns - - {[Primitive.make_list_no_translate(patterns)], params} - end - - defp do_build_match(term, env) when is_number(term) or is_binary(term) or is_boolean(term) or is_atom(term) or is_nil(term) do - { [Translator.translate!(term, env)], [] } - end - - defp do_build_match({ one, two }, env) do - do_build_match({:{}, [], [one, two]}, env) - end - - defp do_build_match({:{}, _, list}, env) do - { patterns, params } = list - |> Enum.map(&build_match([&1], env)) - |> reduce_patterns - - pattern = JS.object_expression([ - JS.property( - JS.identifier("values"), - JS.array_expression(patterns) - ) - ]) - - { [type(Primitive.tuple_class, pattern)], params } - end - - defp do_build_match({:\\, _, [{name, _, _}, default]}, env) do - { [parameter(Translator.translate!(default, env))], [Identifier.make_identifier(name)] } - end - - - defp do_build_match({name, _, _}, _) do - { [parameter()], [Identifier.make_identifier(name)] } - end - - defp reduce_patterns(patterns) do - patterns - |> Enum.reduce({ [], [] }, fn({ pattern, new_param }, { patterns, new_params }) -> - { patterns ++ List.wrap(pattern), new_params ++ List.wrap(new_param) } - end) - end - - defp unify(target, source, env) do - { patterns, params } = build_match([source], env) - { [capture(hd(patterns))], params ++ [Identifier.make_identifier(target)] } - end - -end diff --git a/lib/elixir_script/translator/rewriter.ex b/lib/elixir_script/translator/rewriter.ex deleted file mode 100644 index c4760a7c..00000000 --- a/lib/elixir_script/translator/rewriter.ex +++ /dev/null @@ -1,523 +0,0 @@ -defmodule ElixirScript.Translator.Rewriter do - @moduledoc false - - # :erlang, :lists, :maps, :beam_lib, :binary, :calendar, :digraph, - # :epp, :erl_lint, :erl_internal, :erl_expand_records, :erl_eval, - # :ets, :filename, :gen_event, :gen_server, :io, :io_lib, :math, - # :ordsets, :proc_lib, :rand, :re, :sets, :supervisor,:sys, :timer, - # :unicode, :os, :application, :code, :gen_tcp, :error_logger, :gen, - # :file - # http://erlang.org/doc/applications.html - - - def rewrite({{:., _, [:erlang, :abs]}, _, [number]}) do - quote do: Math.abs(unquote(number)) - end - - def rewrite({{:., _, [:erlang, :apply]}, _, [fun, args]}) do - quote do: unquote(fun).apply(nil, unquote(args)) - end - - def rewrite({{:., _, [:erlang, :apply]}, _, [module, fun, args]}) do - quote do: unquote(module).unquote(fun).apply(nil, unquote(args)) - end - - def rewrite({{:., _, [:erlang, :binary_part]}, _, [binary, start, length]})do - quote do: unquote(binary).substring(unquote(start), unquote(length)) - end - - def rewrite({{:., _, [:erlang, :bit_size]}, _, [bitstring]})do - quote do: unquote(bitstring).bit_size - end - - def rewrite({{:., _, [:erlang, :byte_size]}, _, [bitstring]})do - quote do: unquote(bitstring).byte_size - end - - def rewrite({{:., _, [:erlang, :div]}, _, [left, right]}) do - quote do: unquote(left) / unquote(right) - end - - def rewrite({{:., _, [:erlang, :exit]}, _, [reason]}) do - # TODO: implement exit - quote do: nil - end - - def rewrite({{:., _, [:erlang, :hd]}, _, [list]}) do - quote do: unquote(list)[0] - end - - def rewrite({{:., _, [:erlang, :is_atom]}, _, [term]}) do - quote do: JS.typeof(unquote(term)) === "symbol" - end - - def rewrite({{:., _, [:erlang, :is_binary]}, _, [term]}) do - quote do: JS.typeof(unquote(term)) === "string" - end - - def rewrite({{:., _, [:erlang, :is_bitstring]}, _, [term]}) do - quote do: is_binary(unquote(term)) || JS.instanceof(unquote(term), Bootstrap.Core.BitString) - end - - def rewrite({{:., _, [:erlang, :is_boolean]}, _, [term]}) do - quote do: JS.typeof(unquote(term)) === "boolean" || JS.instanceof(unquote(term), Boolean) - end - - def rewrite({{:., _, [:erlang, :is_float]}, _, [term]}) do - quote do: (JS.typeof(unquote(term)) === "number" || JS.instanceof(unquote(term), Number)) && !Number.isInteger(unquote(term)) - end - - def rewrite({{:., _, [:erlang, :is_function]}, _, [term]}) do - quote do: JS.typeof(unquote(term)) === "function" || JS.instanceof(unquote(term), Function) - end - - def rewrite({{:., _, [:erlang, :is_function]}, _, [term, _]}) do - quote do: JS.typeof(unquote(term)) === "function" || JS.instanceof(unquote(term), Function) - end - - def rewrite({{:., _, [:erlang, :is_integer]}, _, [term]}) do - quote do: Number.isInteger(unquote(term)) - end - - def rewrite({{:., _, [:erlang, :is_list]}, _, [term]}) do - quote do: Array.isArray(unquote(term)) - end - - def rewrite({{:., _, [:erlang, :is_number]}, _, [term]}) do - quote do: JS.typeof(unquote(term)) === "number" || JS.instanceof(unquote(term), Number) - end - - def rewrite({{:., _, [:erlang, :is_pid]}, _, [term]}) do - quote do: JS.instanceof(unquote(term), Bootstrap.Core.PID) - end - - def rewrite({{:., _, [:erlang, :is_port]}, _, [_term]}) do - #TODO implement is_port - quote do: false - end - - def rewrite({{:., _, [:erlang, :is_reference]}, _, [_term]}) do - #TODO implement is_reference - quote do: false - end - - def rewrite({{:., _, [:erlang, :is_tuple]}, _, [term]}) do - quote do: JS.instanceof(unquote(term), Bootstrap.Core.Tuple) - end - - def rewrite({{:., _, [:erlang, :is_map]}, _, [term]}) do - quote do: JS.typeof(unquote(term)) === "object" || JS.instanceof(unquote(term), Object) - end - - def rewrite({{:., _, [:erlang, :length]}, _, [list]}) do - quote do: unquote(list).length - end - - def rewrite({{:., _, [:erlang, :make_ref]}, _, []}) do - #TODO: implement make_ref - quote do: nil - end - - def rewrite({{:., _, [:erlang, :map_size]}, _, [map]}) do - quote do: Object.keys(unquote(map)).length - end - - def rewrite({{:., _, [:erlang, :max]}, _, [first, second]}) do - quote do: Math.max(unquote(first), unquote(second)) - end - - def rewrite({{:., _, [:erlang, :min]}, _, [first, second]}) do - quote do: Math.min(unquote(first), unquote(second)) - end - - def rewrite({{:., _, [:erlang, :node]}, _, []}) do - quote do: :nonode@nohost - end - - def rewrite({{:., _, [:erlang, :node]}, _, [_]}) do - quote do: :nonode@nohost - end - - def rewrite({{:., _, [:erlang, :rem]}, _, [first, second]}) do - {:%, [], [first, second]} - end - - def rewrite({{:., _, [:erlang, :round]}, _, [number]}) do - quote do: Math.round(unquote(number)) - end - - def rewrite({{:., _, [:erlang, :send]}, _, [dest, msg]}) do - #TODO implement send - quote do: unquote(msg) - end - - def rewrite({{:., _, [:erlang, :self]}, _, []}) do - #TODO: implement self - quote do: nil - end - - def rewrite({{:., _, [:erlang, :spawn]}, _, [_fun]}) do - #TODO: implement spawn - quote do: nil - end - - def rewrite({{:., _, [:erlang, :spawn]}, _, [_module, _fun, _args]}) do - #TODO: implement spawn - quote do: nil - end - - def rewrite({{:., _, [:erlang, :spawn_link]}, _, [_fun]}) do - #TODO: implement spawn_link - quote do: nil - end - - def rewrite({{:., _, [:erlang, :spawn_link]}, _, [_module, _fun, _args]}) do - #TODO: implement spawn_link - quote do: nil - end - - def rewrite({{:., _, [:erlang, :spawn_monitor]}, _, [_fun]}) do - #TODO: implement spawn_monitor - quote do: nil - end - - def rewrite({{:., _, [:erlang, :spawn_monitor]}, _, [_module, _fun, _args]}) do - #TODO: implement spawn_monitor - quote do: nil - end - - def rewrite({{:., _, [:erlang, :throw]}, _, [term]}) do - quote do: JS.throw(unquote(term)) - end - - def rewrite({{:., _, [:erlang, :tl]}, _, [list]}) do - quote do: unquote(list).splice(1) - end - - def rewrite({{:., _, [:erlang, :trunc]}, _, [number]}) do - quote do: Math.floor(unquote(number)) - end - - def rewrite({{:., _, [:erlang, :tuple_size]}, _, [tuple]}) do - quote do: unquote(tuple).length - end - - def rewrite({{:., _, [:erlang, operator]}, _, [left, right]}) when operator in [:+, :-, :*, :/, :<, :>, :>=, :==] do - {operator, [], [left, right]} - end - - def rewrite({{:., _, [:erlang, operator]}, _, [value]}) when operator in [:+, :-] do - {operator, [], [value]} - end - - def rewrite({{:., _, [:erlang, :++]}, _, [left, right]}) do - quote do: unquote(left).concat(unquote(right)) - end - - def rewrite({{:., _, [:erlang, :--]}, _, [list, element]}) do - quote do: unquote(list).slice(unquote(list).indexOf(unquote(element)) + 1) - end - - def rewrite({{:., _, [:erlang, :not]}, _, [value]}) do - {:!, [], [value]} - end - - def rewrite({{:., _, [:erlang, :"=<"]}, _, [left, right]}) do - {:<=, [], [left, right]} - end - - def rewrite({{:., _, [:erlang, :"/="]}, _, [left, right]}) do - {:!=, [], [left, right]} - end - - def rewrite({{:., _, [:erlang, :"=:="]}, _, [left, right]}) do - {:===, [], [left, right]} - end - - def rewrite({{:., _, [:erlang, :"=/="]}, _, [left, right]}) do - {:!==, [], [left, right]} - end - - def rewrite({{:., _, [:erlang, :element]}, _, [index, tuple]}) do - quote do: unquote(tuple).get(unquote(index) - 1) - end - - def rewrite({{:., _, [:erlang, :setelement]}, _, [index, tuple, value]}) do - quote do: unquote(tuple).put_elem(unquote(index) - 1, unquote(value)) - end - - def rewrite({{:., _, [:erlang, :orelse]}, _, [left, right]}) do - {:||, [], [left, right]} - end - - def rewrite({{:., _, [:erlang, :or]}, _, [left, right]}) do - {:||, [], [left, right]} - end - - def rewrite({{:., _, [:erlang, :andalso]}, _, [left, right]}) do - {:&&, [], [left, right]} - end - - def rewrite({{:., _, [:erlang, :error]}, _, [error]}) do - quote do: JS.throw(unquote(error)) - end - - def rewrite({{:., _, [:erlang, :raise]}, _, [_class, reason, _stacktrace]}) do - quote do: JS.throw(unquote(reason)) - end - - def rewrite({{:., _, [:erlang, :atom_to_binary]}, _, [atom, _]}) do - quote do: Symbol.keyFor(unquote(atom)) - end - - def rewrite({{:., _, [:erlang, :atom_to_list]}, _, [atom]}) do - quote do: to_string(unquote(atom)).split("") - end - - def rewrite({{:., _, [:erlang, :bnot]}, _, [expr]}) do - {:"~", [], [expr]} - end - - def rewrite({{:., _, [:erlang, :band]}, _, [left, right]}) do - {:&, [], [left, right]} - end - - def rewrite({{:., _, [:erlang, :bor]}, _, [left, right]}) do - {:|, [], [left, right]} - end - - def rewrite({{:., _, [:erlang, :bxor]}, _, [left, right]}) do - {:^, [], [left, right]} - end - - def rewrite({{:., _, [:erlang, :bsl]}, _, [left, right]}) do - {:"<<", [], [left, right]} - end - - def rewrite({{:., _, [:erlang, :bsr]}, _, [left, right]}) do - {:">>", [], [left, right]} - end - - def rewrite({{:., _, [:erlang, :function_exported]}, _, [_, _, _]}) do - quote do: true - end - - def rewrite({{:., _, [:erlang, :make_tuple]}, _, [size, data]}) do - quote do: JS.new(Bootstrap.Core.Tuple, List.duplicate(unquote(size), unquote(data))) - end - - def rewrite({{:., _, [:erlang, :insert_element]}, _, [index, tuple, term]}) do - quote do: unquote(tuple).put_elem(unquote(index) - 1, unquote(term)) - end - - def rewrite({{:., _, [:erlang, :tuple_to_list]}, _, [tuple]}) do - quote do: unquote(tuple).values - end - - def rewrite({{:., _, [:erlang, :append_element]}, _, [tuple, value]}) do - quote do: unquote(tuple).put_elem(unquote(tuple).length, unquote(value)) - end - - def rewrite({{:., _, [:erlang, :delete_element]}, _, [index, tuple]}) do - quote do: unquote(tuple).remove_elem(unquote(index)) - end - - def rewrite({{:., _, [:lists, :map]}, _, [fun, list]}) do - quote do: unquote(list).map(unquote(fun)) - end - - def rewrite({{:., _, [:lists, :member]}, _, [elem, list]}) do - quote do: unquote(list).indexOf(unquote(elem)) > -1 - end - - def rewrite({{:., _, [:lists, :foldl]}, _, [fun, acc, list]}) do - quote do: Bootstrap.Core.Functions.foldl(unquote(fun), unquote(acc), unquote(list)) - end - - def rewrite({{:., _, [:lists, :foldr]}, _, [fun, acc, list]}) do - quote do: Bootstrap.Core.Functions.foldr(unquote(fun), unquote(acc), unquote(list)) - end - - def rewrite({{:., _, [:lists, :keymember]}, _, [key, n, list]}) do - quote do: Bootstrap.Core.Functions.keymember(unquote(key), unquote(n), unquote(list)) - end - - def rewrite({{:., _, [:lists, :keydelete]}, _, [key, n, list]}) do - quote do: Bootstrap.Core.Functions.keydelete(unquote(key), unquote(n), unquote(list)) - end - - def rewrite({{:., _, [:lists, :keystore]}, _, [key, n, list, newtuple]}) do - quote do: Bootstrap.Core.Functions.keystore(unquote(key), unquote(n), unquote(list), unquote(newtuple)) - end - - def rewrite({{:., _, [:lists, :keytake]}, _, [key, n, list]}) do - quote do: Bootstrap.Core.Functions.keystore(unquote(key), unquote(n), unquote(list)) - end - - def rewrite({{:., _, [:lists, :keyfind]}, _, [key, n, list]}) do - quote do: Bootstrap.Core.Functions.keyfind(unquote(key), unquote(n), unquote(list)) - end - - def rewrite({{:., _, [:lists, :keyreplace]}, _, [key, n, list, newtuple]}) do - quote do: Bootstrap.Core.Functions.keyreplace(unquote(key), unquote(n), unquote(list), unquote(newtuple)) - end - - def rewrite({{:., _, [:lists, :keysort]}, _, [n, tuplelist]}) do - #TODO: implement keysort - quote do: unquote(tuplelist) - end - - def rewrite({{:., _, [:lists, :reverse]}, _, [list]}) do - quote do: Bootstrap.Core.Functions.reverse(unquote(list)) - end - - def rewrite({{:., _, [:lists, :reverse]}, _, [list, tail]}) do - quote do: Bootstrap.Core.Functions.reverse(unquote(list)) ++ unquote(tail) - end - - def rewrite({{:., _, [:lists, :flatten]}, _, [list]}) do - quote do: Bootstrap.Core.Functions.flatten(unquote(list)) - end - - def rewrite({{:., _, [:lists, :flatten]}, _, [list, tail]}) do - quote do: Bootstrap.Core.Functions.flatten(unquote(list), unquote(tail)) - end - - def rewrite({{:., _, [:lists, :delete]}, _, [elem, list]}) do - quote do: Bootstrap.Core.Functions.remove_from_list(unquote(list), unquote(elem)) - end - - def rewrite({{:., _, [:lists, :duplicate]}, _, [n, elem]}) do - quote do: Bootstrap.Core.Functions.duplicate(unquote(n), unquote(elem)) - end - - def rewrite({{:., _, [:lists, :mapfoldl]}, _, [fun, acc, list]}) do - quote do: Bootstrap.Core.Functions.mapfoldl(unquote(fun), unquote(acc), unquote(list)) - end - - def rewrite({{:., _, [:lists, :sort]}, _, [list]}) do - quote do: unquote(list).sort() - end - - #TODO: Implement sort - def rewrite({{:., _, [:lists, :sort]}, _, [_fun, list]}) do - quote do: unquote(list) - end - - def rewrite({{:., _, [:lists, :filter]}, _, [pred, list]}) do - quote do: unquote(list).filter(unquote(pred)) - end - - def rewrite({{:., _, [:lists, :filtermap]}, _, [fun, list]}) do - quote do: Bootstrap.Core.Functions.filtermap(unquote(fun), unquote(list)) - end - - def rewrite({{:., _, [:lists, :concat]}, _, [things]}) do - quote do: unquote(things).join("") - end - - def rewrite({{:., _, [:erlang, :binary_to_atom]}, _, [binary, _]}) do - quote do: Symbol.for(unquote(binary)) - end - - def rewrite({{:., _, [:erlang, :binary_to_existing_atom]}, _, [binary, _]}) do - quote do: Symbol.for(unquote(binary)) - end - - def rewrite({{:., _, [:erlang, :list_to_atom]}, _, [char_list]}) do - quote do: Symbol.for(unquote(char_list)) - end - - def rewrite({{:., _, [:erlang, :list_to_existing_atom]}, _, [char_list]}) do - quote do: Symbol.for(unquote(char_list)) - end - - def rewrite({{:., _, [:erlang, :list_to_tuple]}, _, [list]}) do - quote do: JS.new(Bootstrap.Core.Tuple, unquote(list)) - end - - def rewrite({{:., _, [:erlang, :list_to_float]}, _, [list]}) do - quote do: parseFloat(unquote(list)) - end - - def rewrite({{:., _, [:erlang, :list_to_integer]}, _, [list]}) do - quote do: parseInt(unquote(list)) - end - - def rewrite({{:., _, [:erlang, :list_to_integer]}, _, [list, base]}) do - quote do: parseInt(unquote(list), unquote(base)) - end - - def rewrite({{:., _, [:erlang, :integer_to_binary]}, _, [integer]}) do - quote do: unquote(integer).toString() - end - - def rewrite({{:., _, [:erlang, :integer_to_binary]}, _, [integer, base]}) do - quote do: unquote(integer).toString(unquote(base)) - end - - def rewrite({{:., _, [:erlang, :integer_to_list]}, _, [integer]}) do - quote do: unquote(integer).toString() - end - - def rewrite({{:., _, [:erlang, :integer_to_list]}, _, [integer, base]}) do - quote do: unquote(integer).toString(unquote(base)) - end - - def rewrite({{:., _, [:erlang, :float_to_binary]}, _, [float]}) do - quote do: unquote(float).toString() - end - - def rewrite({{:., _, [:erlang, :float_to_binary]}, _, [float, base]}) do - quote do: unquote(float).toString(unquote(base)) - end - - def rewrite({{:., _, [:erlang, :float_to_list]}, _, [float]}) do - quote do: unquote(float).toString() - end - - def rewrite({{:., _, [:erlang, :float_to_list]}, _, [float, base]}) do - quote do: unquote(float).toString(unquote(base)) - end - - def rewrite({{:., _, [:erlang, :binary_to_float]}, _, [binary]}) do - quote do: parseFloat(unquote(binary)) - end - - def rewrite({{:., _, [:erlang, :binary_to_integer]}, _, [binary]}) do - quote do: parseInt(unquote(binary)) - end - - def rewrite({{:., _, [:erlang, :binary_to_integer]}, _, [binary, base]}) do - quote do: parseInt(unquote(binary), unquote(base)) - end - - def rewrite({{:., _, [:maps, :is_key]}, _, [key, map]}) do - quote do: unquote(key) in Bootstrap.Core.Functions.get_object_keys(unquote(map)) - end - - def rewrite({{:., _, [:maps, :put]}, _, [key, value, map]}) do - quote do: Bootstrap.Core.Functions.add_property_to_map(unquote(map), unquote(key), unquote(value)) - end - - def rewrite({{:., _, [:maps, :update]}, _, [key, value, map]}) do - quote do: Bootstrap.Core.Functions.update_map(unquote(map), unquote(key), unquote(value)) - end - - def rewrite({{:., _, [:maps, :find]}, _, [key, map]}) do - quote do: Bootstrap.Core.Functions.maps_find(unquote(key), unquote(map)) - end - - def rewrite({{:., _, [:maps, :remove]}, _, [key, map]}) do - quote do: Bootstrap.Core.Functions.delete_property_from_map(unquote(map), unquote(key)) - end - - def rewrite({{:., _, [:maps, :fold]}, _, [fun, init, map]}) do - quote do: Bootstrap.Core.Functions.maps_fold(unquote(fun), unquote(init), unquote(map)) - end - - def rewrite({{:., _, [:maps, :from_list]}, _, [list]}) do - quote do: Bootstrap.Core.Functions.maps_fold(unquote(list)) - end - -end diff --git a/lib/elixir_script/translator/state.ex b/lib/elixir_script/translator/state.ex deleted file mode 100644 index 25d038a0..00000000 --- a/lib/elixir_script/translator/state.ex +++ /dev/null @@ -1,201 +0,0 @@ -# This agent holds references to the compiler options, a map all of the modules, and -# a map of modules that define the standard library. -# -# The modules map has the module's name a the key and a ElixirScript.Module struct as the value. -# -# The std_lib_map holds a mapping of the Elixir standard lib module to the -# version implemented here in ElixirScript. -defmodule ElixirScript.Translator.State do - @moduledoc false - alias ElixirScript.Translator.Utils - - def start_link(compiler_opts, loaded_modules) do - Agent.start_link(fn -> - %{ compiler_opts: compiler_opts, modules: Keyword.new, std_lib_map: build_standard_lib_map(), loaded_modules: [JS | loaded_modules] } - end) - end - - def serialize(pid) do - Agent.get(pid, fn(state) -> - modules = state.modules - modules = Enum.map(modules, fn {m, d} -> - d = Map.delete(d, :javascript_ast) - |> Map.delete(:javascript_module) - |> Map.delete(:javascript_code) - |> Map.delete(:javascript_name) - - {m, d} - end) - |> Enum.filter(fn {_, d} -> d.type != :consolidated end) - - state = Map.delete(state, :changed_modules) - |> Map.put(:modules, modules) - - :erlang.term_to_binary(state) - end) - end - - def deserialize(pid, frozen_state, loaded_modules \\ []) do - Agent.update(pid, fn state -> - frozen_state = :erlang.binary_to_term(frozen_state) - modules = Keyword.delete(frozen_state.modules, ElixirScript.Temp) - %{ state | modules: modules, std_lib_map: frozen_state.std_lib_map, loaded_modules: [JS | loaded_modules] } - end) - end - - defp build_standard_lib_map() do - Map.new - |> Map.put(Kernel, ElixirScript.Kernel) - |> Map.put(Tuple, ElixirScript.Tuple) - |> Map.put(Atom, ElixirScript.Atom) - |> Map.put(Collectable, ElixirScript.Collectable) - |> Map.put(String.Chars, ElixirScript.String.Chars) - |> Map.put(Enumerable, ElixirScript.Enumerable) - |> Map.put(Integer, ElixirScript.Integer) - |> Map.put(Macro.Env, ElixirScript.Macro.Env) - |> Map.put(View, ElixirScript.View) - |> Map.put(Agent, ElixirScript.Agent) - |> Map.put(Range, ElixirScript.Range) - |> Map.put(String, ElixirScript.String) - |> Map.put(Base, ElixirScript.Base) - |> Map.put(Module, ElixirScript.Module) - |> Map.put(Map, ElixirScript.Map) - |> Map.put(Keyword, ElixirScript.Keyword) - |> Map.put(Bitwise, ElixirScript.Bitwise) - |> Map.put(MapSet, ElixirScript.MapSet) - |> Map.put(List, ElixirScript.List) - |> Map.put(Process, ElixirScript.Process) - |> Map.put(Regex, ElixirScript.Regex) - end - - def set_module_data(pid, module_data) do - Agent.update(pid, fn state -> - %{ state | modules: Keyword.merge(state.modules, module_data) } - end) - end - - def get_module_data(pid) do - Agent.get(pid, fn state -> - state.modules - end) - end - - def set_loaded_modules(pid, modules) do - Agent.update(pid, fn state -> - %{ state | loaded_modules: [ JS | modules ] } - end) - end - - def get(pid) do - Agent.get(pid, &(&1)) - end - - def get_module_name(pid, {:__aliases__, _, _} = name) do - get_module_name(pid, Utils.quoted_to_name(name)) - end - - def get_module_name(pid, module_name) do - Agent.get(pid, fn(state) -> - do_get_module_name(module_name, state) - end) - end - - defp do_get_module_name(module_name, state) do - std_lib_map = state.std_lib_map - case Map.get(std_lib_map, module_name) do - nil -> - module_name - actual_module_name -> - actual_module_name - end - end - - def is_module_loaded?(pid, module) when is_atom(module) do - Agent.get(pid, fn(state) -> - (module in state.loaded_modules) - end) - end - - def is_module_loaded?(pid, {:__aliases__, _, _} = module) do - - is_module_loaded?(pid, Utils.quoted_to_name(module)) - end - - def get_module(pid, module) when is_atom(module) do - do_get_module(pid, module) - end - - def get_module(pid, {:__aliases__, _, _} = name) do - do_get_module(pid, Utils.quoted_to_name(name)) - end - - def get_module(pid, module_name_list) when is_list(module_name_list) do - do_get_module(pid, Utils.quoted_to_name({:__aliases__, [], module_name_list})) - end - - defp do_get_module(pid, name) do - Agent.get(pid, fn(state) -> - Keyword.get(state.modules, do_get_module_name(name, state)) - end) - end - - def add_module_reference(pid, module_name, module_ref) do - Agent.update(pid, fn(state) -> - case Keyword.get(state.modules, do_get_module_name(module_name, state)) do - nil -> - state - module -> - module = Map.update(module, :deps, [module_ref], fn(x) -> Enum.uniq(x ++ [module_ref]) end) - modules = Keyword.put(state.modules, module.name, module) - %{ state | modules: modules } - end - end) - end - - def get_module_references(pid, module_name) do - case get_module(pid, module_name) do - nil -> - [] - module -> - Map.get(module, :deps, []) - end - end - - def list_modules(pid) do - Agent.get(pid, fn(state) -> - Keyword.values(state.modules) - end) - end - - def list_module_names(pid) do - Agent.get(pid, fn(state) -> - Keyword.keys(state.modules) - end) - end - - def stop(pid) do - Agent.stop(pid) - end - - def add_javascript_module_reference(pid, module_name, name, path, default \\ true) do - Agent.update(pid, fn(state) -> - case Keyword.get(state.modules, do_get_module_name(module_name, state)) do - nil -> - state - module -> - module = Map.update(module, :js_modules, [{name, path, default}], fn(x) -> Enum.uniq(x ++ [{name, path, default}]) end) - modules = Keyword.put(state.modules, module.name, module) - %{ state | modules: modules } - end - end) - end - - def get_javascript_module_references(pid, module_name) do - case get_module(pid, module_name) do - nil -> - [] - module -> - Map.get(module, :js_modules, []) - end - end -end diff --git a/lib/elixir_script/translator/unsupported_error.ex b/lib/elixir_script/translator/unsupported_error.ex deleted file mode 100644 index 34bb1b6d..00000000 --- a/lib/elixir_script/translator/unsupported_error.ex +++ /dev/null @@ -1,8 +0,0 @@ -defmodule ElixirScript.Translator.UnsupportedError do - defexception [:message] - - def exception(value) do - msg = "Currently unsupported #{inspect value}" - %ElixirScript.Translator.UnsupportedError{message: msg} - end -end diff --git a/lib/elixir_script/translator/utils.ex b/lib/elixir_script/translator/utils.ex deleted file mode 100644 index e0611980..00000000 --- a/lib/elixir_script/translator/utils.ex +++ /dev/null @@ -1,65 +0,0 @@ -defmodule ElixirScript.Translator.Utils do - @moduledoc false - - def quoted_to_name(the_alias) do - {name, _} = Code.eval_quoted(the_alias) - name - end - - def name_to_quoted(name) when is_list(name) do - { :__aliases__, [], name } - end - - def name_to_quoted(name) do - name = name - |> Module.split - |> Enum.map(fn x -> String.to_atom(x) end) - - { :__aliases__, [], name } - end - - def name_to_js_name(name) do - { :__aliases__, _, name } = name_to_quoted(name) - Enum.join([:Elixir] ++ name, "$") - end - - def name_to_js_file_name(name) do - { :__aliases__, _, name } = name_to_quoted(name) - Enum.join([:Elixir] ++ name, ".") - end - - def make_local_file_path(module_app_name, file_name, env) do - root = ElixirScript.Translator.State.get(env.state).compiler_opts.root - app_name = if is_binary(module_app_name), do: module_app_name, else: to_string(module_app_name) - - case root do - nil -> - Path.join(["..", app_name, file_name]) - root -> - Path.join([root, app_name, file_name]) - end - end - - def make_local_file_path(file_name, env) do - root = ElixirScript.Translator.State.get(env.state).compiler_opts.root - - case root do - nil -> - Path.join([".", file_name]) - root -> - Path.join([root, file_name]) - end - end - - def make_local_file_path(module_app_name, file_name, root, _) do - app_name = to_string(module_app_name) - - case root do - nil -> - Path.join(["..", app_name, file_name]) - root -> - Path.join([root, app_name, file_name]) - end - end - -end diff --git a/lib/elixir_script/watcher.ex b/lib/elixir_script/watcher.ex deleted file mode 100644 index b54cc03e..00000000 --- a/lib/elixir_script/watcher.ex +++ /dev/null @@ -1,49 +0,0 @@ -defmodule ElixirScript.Watcher do - use GenServer - require Logger - - @moduledoc """ - Watches the input folder for changes and calls the ElixirScript compiler - """ - - - def start_link(input, options) do - GenServer.start_link(__MODULE__, [input: input, options: options]) - end - - def init(args) do - {:ok, _} = Application.ensure_all_started(:elixir_script) - {:ok, _} = Application.ensure_all_started(:fs) - - :fs.subscribe() - {:ok, args} - end - - def handle_info({_pid, {:fs, :file_event}, {path, event}}, state) do - - try do - if input_changed?(to_string(path), state) do - Logger.debug "Event: #{inspect event} Path: #{path}" - ElixirScript.compile_path(state[:input], state[:options]) - end - rescue - x -> - Logger.error(x.message) - end - - {:noreply, state} - end - - defp input_changed?(path, state) do - file = Path.basename(path) - - case file do - "." <> _ -> - false - _ -> - Enum.any?(List.wrap(state[:input]), fn(x) -> - path == Path.absname(Path.join([x, file])) - end) - end - end -end diff --git a/lib/elixir_script_test/test.ex b/lib/elixir_script_test/test.ex new file mode 100644 index 00000000..b531b700 --- /dev/null +++ b/lib/elixir_script_test/test.ex @@ -0,0 +1,111 @@ +defmodule ElixirScript.Test do + @moduledoc """ + Unit Testing Framework for ElixirScript. + + Requires node.js 8.3.0 and above + + Uses assertions from ExUnit as well as has a similar api to ExUnit with a few differences + + ## Example + + An basic setup of a test. Modified from ExUnit's example + + ```elixir + # File: assertion_test.exs + # 1) Create a new test module (test case) and use "ElixirScript.Test". + defmodule AssertionTest do + use ElixirScript.Test + + # 2) Use the "test" macro. + test "the truth" do + assert true + end + end + ``` + + To run the test above, use the `ElixirScript.Test.start/1` function, giving it the path to the test + ``` + ElixirScript.Test.start("assertion_test.exs") + ``` + + ## Integration with Mix + + To run tests using mix, run `mix elixirscript.test`. This will run all tests in the test_elixir_script directory. + + + ## Callbacks + + ElixirScript defines the following callbacks + + * setup/1 + * setup/2 + * setup_all/1 + * setup_all/2 + * teardown/1 + * teardown/2 + * teardown_all/1 + * teardown_all/2 + + The `setup` and `setup_all` callbacks work exactly as they would in ExUnit. Instead of having an `on_exit` callback, + ElixirScript.Test has `teardown` callbacks. `teardown` is called after each test and `teardown_all` after all tests + in the file have run. + + ```elixir + defmodule AssertionTest do + use ElixirScript.Test + + # run before test + setup do + admin = create_admin_function() + [admin: admin] + end + + test "the truth", %{admin: admin} do + assert admin.is_authenticated + end + + # run after test + teardown, %{admin: admin} do + destroy_admin_function(admin) + end + end + ``` + """ + + defmacro __using__(_opts) do + quote do + require ExUnit.Assertions + import ElixirScript.Test.{Callbacks, Assertions} + + def __elixirscript_test_module__, do: true + end + end + + @doc """ + Runs tests found in the given path. Accepts wildcards + """ + @spec start(binary(), map()) :: :ok | :error + def start(path, _opts \\ %{}) do + output = Path.join([System.tmp_dir!(), "elixirscript_tests"]) + File.mkdir_p!(output) + + ElixirScript.Compiler.compile(path, [output: output]) + + js_files = output + |> Path.expand + |> Path.join("Elixir.*.js") + |> Path.wildcard() + + exit_status = ElixirScript.Test.Runner.Node.run(js_files) + + # Delete directory at the end + File.rm_rf!(output) + + case exit_status do + 0 -> + :ok + _ -> + :error + end + end +end diff --git a/lib/elixir_script_test/test/assertion_error.ex b/lib/elixir_script_test/test/assertion_error.ex new file mode 100644 index 00000000..c591a95d --- /dev/null +++ b/lib/elixir_script_test/test/assertion_error.ex @@ -0,0 +1,14 @@ +defmodule ElixirScript.Test.AssertionError do + @moduledoc """ + Raised to signal an assertion error. + """ + + @no_value :ex_unit_no_meaningful_value + + defexception left: @no_value, + right: @no_value, + message: @no_value, + expr: @no_value, + file: @no_value, + line: @no_value +end diff --git a/lib/elixir_script_test/test/assertions.ex b/lib/elixir_script_test/test/assertions.ex new file mode 100644 index 00000000..7e8e53fe --- /dev/null +++ b/lib/elixir_script_test/test/assertions.ex @@ -0,0 +1,215 @@ +defmodule ElixirScript.Test.Assertions do + @moduledoc """ + Defines assertions for use in ElixirScript test. + These are a subset of [ExUnit.Assertions](https://hexdocs.pm/ex_unit/ExUnit.Assertions.html) + """ + + @doc false + def raise_elixir_script_assert(error, file, line) do + reraise(ElixirScript.Test.AssertionError, [ + left: error.left, + right: error.right, + message: error.message, + expr: error.expr, + file: file, + line: line + ], []) + end + + @doc """ + Asserts its argument is a truthy value + """ + defmacro assert(assertion) do + %{file: file, line: line} = __CALLER__ + + quote [file: file, line: line] do + try do + ExUnit.Assertions.assert(unquote(assertion)) + rescue + error in [ExUnit.AssertionError] -> + ElixirScript.Test.Assertions.raise_elixir_script_assert( + error, + unquote(file), + unquote(line) + ) + end + end + end + + @doc """ + Asserts `value` is `true`, displaying the given `message` otherwise. + """ + defmacro assert(value, message) do + %{file: file, line: line} = __CALLER__ + + quote [file: file, line: line] do + try do + ExUnit.Assertions.assert(unquote(value), unquote(message)) + rescue + error in [ExUnit.AssertionError] -> + ElixirScript.Test.Assertions.raise_elixir_script_assert( + error, + unquote(file), + unquote(line) + ) + end + end + end + + @doc """ + Asserts the `exception` is raised during `function` execution. + Returns the rescued exception, fails otherwise. + """ + defmacro assert_raise(exception, function) do + %{file: file, line: line} = __CALLER__ + + quote [file: file, line: line] do + try do + ExUnit.Assertions.assert(unquote(exception), unquote(function)) + rescue + error in [ExUnit.AssertionError] -> + ElixirScript.Test.Assertions.raise_elixir_script_assert( + error, + unquote(file), + unquote(line) + ) + end + end + end + + @doc """ + Asserts the `exception` is raised during `function` execution with + the expected `message`, which can be a `Regex` or an exact `String`. + Returns the rescued exception, fails otherwise. + """ + defmacro assert_raise(exception, message, function) do + %{file: file, line: line} = __CALLER__ + + quote [file: file, line: line] do + try do + ExUnit.Assertions.assert( + unquote(exception), + unquote(message), + unquote(function) + ) + rescue + error in [ExUnit.AssertionError] -> + ElixirScript.Test.Assertions.raise_elixir_script_assert( + error, + unquote(file), + unquote(line) + ) + end + end + end + + @doc """ + Asserts that `value1` and `value2` differ by no more than `delta` + """ + defmacro assert_in_delta(value1, value2, delta, message \\ nil) do + %{file: file, line: line} = __CALLER__ + + quote [file: file, line: line] do + try do + ExUnit.Assertions.assert_in_delta( + unquote(value1), + unquote(value2), + unquote(delta), + unquote(message) + ) + rescue + error in [ExUnit.AssertionError] -> + ElixirScript.Test.Assertions.raise_elixir_script_assert( + error, + unquote(file), + unquote(line) + ) + end + end + end + + @doc """ + A negative assertion, expects the expression to be `false` or `nil`. + """ + defmacro refute(assertion) do + %{file: file, line: line} = __CALLER__ + + quote [file: file, line: line] do + try do + ExUnit.Assertions.assert(unquote(assertion)) + rescue + error in [ExUnit.AssertionError] -> + ElixirScript.Test.Assertions.raise_elixir_script_assert( + error, + unquote(file), + unquote(line) + ) + end + end + end + + @doc """ + Asserts `value` is `nil` or `false` (that is, `value` is not truthy). + """ + defmacro refute(value, message) do + %{file: file, line: line} = __CALLER__ + + quote [file: file, line: line] do + try do + ExUnit.Assertions.assert(unquote(value), unquote(message)) + rescue + error in [ExUnit.AssertionError] -> + ElixirScript.Test.Assertions.raise_elixir_script_assert( + error, + unquote(file), + unquote(line) + ) + end + end + end + + @doc """ + Asserts that `value1` and `value2` are not within `delta` + """ + defmacro refute_in_delta(value1, value2, delta, message \\ nil) do + %{file: file, line: line} = __CALLER__ + + quote [file: file, line: line] do + try do + ExUnit.Assertions.refute_in_delta( + unquote(value1), + unquote(value2), + unquote(delta), + unquote(message) + ) + rescue + error in [ExUnit.AssertionError] -> + ElixirScript.Test.Assertions.raise_elixir_script_assert( + error, + unquote(file), + unquote(line) + ) + end + end + end + + @doc """ + Fails with a message. + """ + defmacro flunk(message \\ "Flunked!") do + %{file: file, line: line} = __CALLER__ + + quote [file: file, line: line] do + try do + ExUnit.Assertions.flunk(unquote(message)) + rescue + error in [ExUnit.AssertionError] -> + ElixirScript.Test.Assertions.raise_elixir_script_assert( + error, + unquote(file), + unquote(line) + ) + end + end + end +end diff --git a/lib/elixir_script_test/test/callbacks.ex b/lib/elixir_script_test/test/callbacks.ex new file mode 100644 index 00000000..f314c1c1 --- /dev/null +++ b/lib/elixir_script_test/test/callbacks.ex @@ -0,0 +1,117 @@ +defmodule ElixirScript.Test.Callbacks do + @moduledoc """ + Defines ElixirScript.Test callbacks + """ + + @doc """ + Called before all tests are run in a test file + """ + defmacro setup_all(context \\ quote(do: _), contents) do + do_setup(context, contents, :__elixirscript_test_setup_all) + end + + @doc """ + Called before each test is run in a test file + """ + defmacro setup(context \\ quote(do: _), contents) do + do_setup(context, contents, :__elixirscript_test_setup) + end + + defp do_setup(context, contents, name) do + contents = + case contents do + [do: block] -> + quote do + unquote(block) + end + _ -> + quote do + try(unquote(contents)) + end + end + + context = Macro.escape(context) + contents = Macro.escape(contents, unquote: true) + + quote bind_quoted: [context: context, contents: contents, name: name] do + def unquote(name)(unquote(context)) do + unquote(contents) + end + end + end + + @doc """ + Called after all tests are run in a test file + """ + defmacro teardown_all(context \\ quote(do: _), contents) do + do_teardown(context, contents, :__elixirscript_test_teardown_all) + end + + @doc """ + Called after each test is run in a test file + """ + defmacro teardown(context \\ quote(do: _), contents) do + do_teardown(context, contents, :__elixirscript_test_teardown) + end + + defp do_teardown(context, contents, name) do + contents = + case contents do + [do: block] -> + quote do + unquote(block) + :ok + end + _ -> + quote do + try(unquote(contents)) + :ok + end + end + + context = Macro.escape(context) + contents = Macro.escape(contents, unquote: true) + + quote bind_quoted: [context: context, contents: contents, name: name] do + def unquote(name)(unquote(context)) do + unquote(contents) + end + end + end + + @doc """ + Defines a test + """ + defmacro test(message, context \\ quote(do: _), contents) do + contents = + case contents do + [do: block] -> + quote do + unquote(block) + :ok + end + _ -> + quote do + try(unquote(contents)) + :ok + end + end + + context = Macro.escape(context) + contents = Macro.escape(contents, unquote: true) + name = message + |> String.replace(" ", "_") + |> String.replace(~r/[^A-Za-z0-9]/, "") + + name = String.to_atom("__elixirscript_test_case_#{name}") + + quote bind_quoted: [context: context, contents: contents, message: message, name: name] do + def unquote(name)() do + %{ + message: unquote(message), + test: fn(context) -> unquote(contents) end + } + end + end + end +end diff --git a/lib/elixir_script_test/test/runner.ex b/lib/elixir_script_test/test/runner.ex new file mode 100644 index 00000000..e746292b --- /dev/null +++ b/lib/elixir_script_test/test/runner.ex @@ -0,0 +1,14 @@ +defmodule ElixirScript.Test.Runner do + @moduledoc """ + Defines a behaviour for an ElixirScript Test runner + """ + + @doc """ + Callback for running the test runner. + Receives a list of JavaScript files from the + compiled Elixir code. Expects an exit status + representing the success or failure of the + tests + """ + @callback run([binary]) :: integer +end diff --git a/lib/elixir_script_test/test/runner/node.ex b/lib/elixir_script_test/test/runner/node.ex new file mode 100644 index 00000000..31e83667 --- /dev/null +++ b/lib/elixir_script_test/test/runner/node.ex @@ -0,0 +1,18 @@ +defmodule ElixirScript.Test.Runner.Node do + @moduledoc """ + Defines an ElixirScript Test runner using node + """ + @behaviour ElixirScript.Test.Runner + + def run(js_files) do + test_script_path = Path.join([:code.priv_dir(:elixir_script), "testrunner", "index.js"]) + test_script_path = [test_script_path] ++ js_files + {_, exit_status} = System.cmd( + "node", + test_script_path, + into: IO.stream(:stdio, :line) + ) + + exit_status + end +end diff --git a/lib/mix/tasks/compile.elixir_script.ex b/lib/mix/tasks/compile.elixir_script.ex index e5d33169..b529251e 100644 --- a/lib/mix/tasks/compile.elixir_script.ex +++ b/lib/mix/tasks/compile.elixir_script.ex @@ -1,5 +1,11 @@ defmodule Mix.Tasks.Compile.ElixirScript do - use Mix.Task + use Mix.Task.Compiler + alias ElixirScript.Manifest + alias ElixirScript.Compiler + + @recursive true + @manifest ".compile.elixir_script" + @manifest_vsn 1 @moduledoc """ Mix compiler to allow mix to compile Elixirscript source files into JavaScript @@ -12,93 +18,113 @@ defmodule Mix.Tasks.Compile.ElixirScript do version: "0.1.0", elixir: "~> 1.0", deps: deps, - elixir_script: [ input: "src/exjs", output: "dest/js"], - compilers: [:elixir_script] ++ Mix.compilers + elixir_script: [ input: Example, output: "dest/js"], + compilers: Mix.compilers ++ [:elixir_script] ] end - + Available options are: - * `input`: The folder to look for Elixirscript files in. (defaults to `lib/elixirscript`) - * `output`: The folder to place generated JavaScript code in. (defaults to `priv/elixirscript`) - * `format`: The module format of generated JavaScript code. (defaults to `:es`). - Choices are: - * `:es` - ES Modules - * `:common` - CommonJS - * `:umd` - UMD + * `input`: The module or modules that are the entry to your application (required) + * `output`: The path of the generated JavaScript file. (defaults to `priv/elixir_script/build`) + + If path ends in `.js` then that will be the name of the file. If a directory is given, + file will be named `elixirscript.build.js` + + * `root`: Optional root for imports of FFI JavaScript modules. + Defaults to `.`. If using output directly in a browser, you may want to make it something like `/js` or some uri. The mix compiler will also compile any dependencies that have the elixirscript compiler in its mix compilers as well """ - - @spec run(any()) :: :ok + @spec run([binary()]) :: + :ok | :noop | {:ok | :noop | :error, [Mix.Task.Compiler.Diagnostic.t()]} def run(_) do - elixirscript_config = get_elixirscript_config() - - elixirscript_base = Path.join([Mix.Project.build_path, "elixirscript"]) - File.mkdir_p!(elixirscript_base) - elixirscript_path = Path.join([elixirscript_base, "#{Mix.Project.config[:app]}"]) - - input_path = elixirscript_config - |> Keyword.get(:input) - |> List.wrap - |> Enum.map(fn(path) -> - Path.absname(path) - end) - |> Enum.join("\n") + {input, opts} = get_compiler_params() + + diagnostics = + try do + result = Compiler.compile(input, opts) + Manifest.write_manifest(manifest(), result) + + result + |> Enum.map(fn {_module, info} -> + Map.get(info, :diagnostics, []) + end) + |> List.flatten() + |> Enum.map(fn x -> + %Mix.Task.Compiler.Diagnostic{ + compiler_name: "elixir_script", + file: x.file, + message: x.message, + position: x.position, + severity: x.severity + } + end) + rescue + x in [ElixirScript.CompileError] -> + [ + %Mix.Task.Compiler.Diagnostic{ + compiler_name: "elixir_script", + message: x.message, + severity: x.severity, + position: nil, + file: nil + } + ] + end - File.write!(elixirscript_path, input_path) + case diagnostics do + [] -> :ok + x -> x + end + end - paths = [elixirscript_base, "*"] - |> Path.join() - |> Path.wildcard - |> Enum.map(fn(path) -> - app = Path.basename(path) - paths = path |> File.read!() |> String.split("\n") - {app, paths} + def clean do + manifest() + |> Manifest.read_manifest() + |> Enum.each(fn {_module, info} -> + File.rm(info.js_path) end) - |> Map.new - output_path = Keyword.get(elixirscript_config, :output) - format = Keyword.get(elixirscript_config, :format) - js_modules = Keyword.get(elixirscript_config, :js_modules, []) - - ElixirScript.compile_path(paths, %{output: output_path, format: format, js_modules: js_modules}) :ok end - def clean do - elixirscript_config = get_elixirscript_config() - output_path = Keyword.get(elixirscript_config, :output) + def manifests, do: [manifest()] + defp manifest, do: Path.join(Mix.Project.manifest_path(), @manifest) - path = Path.join([output_path, "Elixir.App.js"]) + @doc false + def get_compiler_params() do + elixirscript_config = get_elixirscript_config() + input = Keyword.fetch!(elixirscript_config, :input) - if File.exists?(path) do - File.rm!(path) - end + opts = [ + output: Keyword.get(elixirscript_config, :output) + ] - :ok + {input, opts} end defp get_elixirscript_config() do - config = Mix.Project.config - exjs_config = cond do - Keyword.has_key?(config, :elixir_script) -> - Keyword.get(config, :elixir_script, []) - Keyword.has_key?(config, :elixirscript) -> - Keyword.get(config, :elixirscript, []) - true -> - defaults() - end + config = Mix.Project.config() + + exjs_config = + cond do + Keyword.has_key?(config, :elixir_script) -> + Keyword.get(config, :elixir_script, []) + + Keyword.has_key?(config, :elixirscript) -> + Keyword.get(config, :elixirscript, []) + + true -> + defaults() + end Keyword.merge(defaults(), exjs_config) end defp defaults() do [ - input: "lib/elixirscript", - output: "priv/elixirscript", - format: :es + output: "priv/elixir_script/build" ] end - end diff --git a/lib/mix/tasks/elixirscript.test.ex b/lib/mix/tasks/elixirscript.test.ex new file mode 100644 index 00000000..e60899d6 --- /dev/null +++ b/lib/mix/tasks/elixirscript.test.ex @@ -0,0 +1,29 @@ +defmodule Mix.Tasks.Elixirscript.Test do + @moduledoc """ + Runs ElixirScript Tests + """ + use Mix.Task + + @shortdoc "Runs ElixirScript Tests" + @preferred_cli_env :test + + def run(_args) do + Mix.Task.run "app.start" + + path = Path.join([default_test_path(), "**", "*_test.exs"]) + case ElixirScript.Test.start(path) do + :error -> + System.at_exit(fn _ -> exit({:shutdown, 1}) end) + :ok -> + :ok + end + end + + defp default_test_path do + if File.dir?("test_elixir_script") do + "test_elixir_script" + else + "" + end + end +end diff --git a/lib/mix/tasks/elixirscript.watch.ex b/lib/mix/tasks/elixirscript.watch.ex deleted file mode 100644 index ace5bbc6..00000000 --- a/lib/mix/tasks/elixirscript.watch.ex +++ /dev/null @@ -1,64 +0,0 @@ -defmodule Mix.Tasks.Elixirscript.Watch do - use Mix.Task - - @shortdoc "Watches ElixirScript files for changes" - - @moduledoc """ - Watches ElixirScript files for changes - - Looks for the `elixir_script` key in your mix project config - - def project do - [ - app: :my_app, - version: "0.1.0", - elixir: "~> 1.0", - deps: deps, - elixir_script: [ input: "src/exjs", output: "dest/js"], - compilers: [:elixir_script] ++ Mix.compilers - ] - end - """ - - - - def run(_) do - Mix.Task.run "app.start" - - elixirscript_config = get_elixirscript_config() - input_path = Keyword.get(elixirscript_config, :input) - output_path = Keyword.get(elixirscript_config, :output) - format = Keyword.get(elixirscript_config, :format) - js_modules = Keyword.get(elixirscript_config, :js_modules, []) - - {:ok, _} = ElixirScript.Watcher.start_link( - input_path, - %{output: output_path, format: format, js_modules: js_modules} - ) - - :timer.sleep :infinity - end - - defp get_elixirscript_config() do - config = Mix.Project.config - exjs_config = cond do - Keyword.has_key?(config, :elixir_script) -> - Keyword.get(config, :elixir_script, []) - Keyword.has_key?(config, :elixirscript) -> - Keyword.get(config, :elixirscript, []) - true -> - defaults() - end - - Keyword.merge(defaults(), exjs_config) - end - - defp defaults() do - [ - input: "lib/elixirscript", - output: "priv/elixirscript", - format: :es - ] - end - -end diff --git a/mix.exs b/mix.exs index 7369fd35..66184c98 100644 --- a/mix.exs +++ b/mix.exs @@ -4,44 +4,40 @@ defmodule ElixirScript.Mixfile do def project do [ app: :elixir_script, - version: "0.26.0", - elixir: "~> 1.0", - elixirc_paths: elixirc_paths(), - escript: escript_config(), + version: "0.32.1", + elixir: "~> 1.6", + elixirc_paths: elixirc_paths(Mix.env()), deps: deps(), description: description(), package: package(), source_url: "https://github.com/elixirscript/elixirscript", - aliases: aliases(), test_coverage: [tool: ExCoveralls], - preferred_cli_env: [coveralls: :test], docs: [ - extras: ["GettingStarted.md", "FAQ.md"] + main: "ElixirScript", + extras: ["JavaScriptInterop.md", "CompilerInternals.md"] ] ] end def application do [ - applications: [:logger, :estree] + extra_applications: [:logger] ] end defp deps do [ - {:estree, "~> 2.5"}, - {:fs, "~> 2.12"}, - {:ex_doc, "~> 0.14", only: :dev}, - {:excoveralls, "~> 0.5", only: :test}, - {:credo, "~> 0.4", only: [:dev, :test]} + {:estree, "~> 2.6"}, + {:ex_doc, "~> 0.16", only: :dev}, + {:excoveralls, "~> 0.7", only: :test}, + {:credo, "~> 1.0", only: [:dev, :test]}, + {:stream_data, "~> 0.3", only: :test}, + {:poison, "~> 4.0", only: :test} ] end - defp elixirc_paths(), do: ["lib", "priv/std_lib"] - - defp escript_config do - [main_module: ElixirScript.CLI, name: "elixirscript"] - end + defp elixirc_paths(:test), do: ["lib", "test/support"] + defp elixirc_paths(_), do: ["lib"] defp description do """ @@ -60,48 +56,4 @@ defmodule ElixirScript.Mixfile do build_tools: ["mix"] ] end - - defp aliases do - [dist: &dist/1, - install: &install/1] - end - - def dist(_) do - Mix.Task.run "app.start" - - dist_folder = "dist" - folder_name = "#{dist_folder}/elixirscript" - archive_file_name = "#{dist_folder}/elixirscript.tar.gz" - - Mix.Tasks.Escript.Build.run([]) - - if File.exists?(dist_folder) do - File.rm_rf(dist_folder) - end - - File.mkdir_p(folder_name <> "/bin") - File.cp!("elixirscript", "#{folder_name}/bin/elixirscript") - if File.exists?("priv/.DS_Store") do - File.rm!("priv/.DS_Store") - end - File.cp_r!("priv/", "#{folder_name}") - File.cp!("LICENSE", "#{folder_name}/LICENSE") - - System.cmd("tar", ["czf", archive_file_name, folder_name]) - - File.rm_rf(folder_name) - end - - def install(_) do - Mix.Task.run "app.start" - - System.cmd("tar", ["-zxvf", "dist/elixirscript.tar.gz"]) - - File.rm_rf!("/usr/local/elixirscript") - - System.cmd("mv", ["dist/elixirscript", "/usr/local/elixirscript"]) - - IO.puts("installed at /usr/local/elixirscript") - end - end diff --git a/mix.lock b/mix.lock index 2020bc3f..3e10cac4 100644 --- a/mix.lock +++ b/mix.lock @@ -1,15 +1,24 @@ -%{"bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], []}, - "certifi": {:hex, :certifi, "0.7.0", "861a57f3808f7eb0c2d1802afeaae0fa5de813b0df0979153cbafcd853ababaf", [:rebar3], []}, - "credo": {:hex, :credo, "0.6.1", "a941e2591bd2bd2055dc92b810c174650b40b8290459c89a835af9d59ac4a5f8", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, optional: false]}]}, - "earmark": {:hex, :earmark, "1.1.1", "433136b7f2e99cde88b745b3a0cfc3fbc81fe58b918a09b40fce7f00db4d8187", [:mix], []}, - "estree": {:hex, :estree, "2.5.1", "c93a8fa8a29886e6a6f6c489ba6dc949b998d2985b189967e41e69a92b58e846", [:mix], []}, - "ex_doc": {:hex, :ex_doc, "0.14.5", "c0433c8117e948404d93ca69411dd575ec6be39b47802e81ca8d91017a0cf83c", [:mix], [{:earmark, "~> 1.0", [hex: :earmark, optional: false]}]}, - "excoveralls": {:hex, :excoveralls, "0.6.2", "0e993d096f1fbb6e70a3daced5c89aac066bda6bce57829622aa2d1e2b338cfb", [:mix], [{:exjsx, "~> 3.0", [hex: :exjsx, optional: false]}, {:hackney, ">= 0.12.0", [hex: :hackney, optional: false]}]}, - "exjsx": {:hex, :exjsx, "3.2.1", "1bc5bf1e4fd249104178f0885030bcd75a4526f4d2a1e976f4b428d347614f0f", [:mix], [{:jsx, "~> 2.8.0", [hex: :jsx, optional: false]}]}, - "fs": {:hex, :fs, "2.12.0", "ad631efacc9a5683c8eaa1b274e24fa64a1b8eb30747e9595b93bec7e492e25e", [:rebar3], []}, - "hackney": {:hex, :hackney, "1.6.5", "8c025ee397ac94a184b0743c73b33b96465e85f90a02e210e86df6cbafaa5065", [:rebar3], [{:certifi, "0.7.0", [hex: :certifi, optional: false]}, {:idna, "1.2.0", [hex: :idna, optional: false]}, {:metrics, "1.0.1", [hex: :metrics, optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, optional: false]}]}, - "idna": {:hex, :idna, "1.2.0", "ac62ee99da068f43c50dc69acf700e03a62a348360126260e87f2b54eced86b2", [:rebar3], []}, - "jsx": {:hex, :jsx, "2.8.2", "7acc7d785b5abe8a6e9adbde926a24e481f29956dd8b4df49e3e4e7bcc92a018", [:mix, :rebar3], []}, - "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], []}, - "mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [], []}, - "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], []}} +%{ + "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm"}, + "certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"}, + "credo": {:hex, :credo, "1.1.3", "bf31887b8914a4b7e1810ae2b5aab7c657698abbf4cca6a2335a094d57995168", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"}, + "earmark": {:hex, :earmark, "1.3.5", "0db71c8290b5bc81cb0101a2a507a76dca659513984d683119ee722828b424f6", [:mix], [], "hexpm"}, + "estree": {:hex, :estree, "2.7.0", "32cb6ff05c85a93bf6c646b3b184e131f699fc1e7157d2b5be148c17f43ae566", [:mix], [], "hexpm"}, + "ex_doc": {:hex, :ex_doc, "0.21.1", "5ac36660846967cd869255f4426467a11672fec3d8db602c429425ce5b613b90", [:mix], [{:earmark, "~> 1.3", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"}, + "excoveralls": {:hex, :excoveralls, "0.11.2", "0c6f2c8db7683b0caa9d490fb8125709c54580b4255ffa7ad35f3264b075a643", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"}, + "exjsx": {:hex, :exjsx, "4.0.0", "60548841e0212df401e38e63c0078ec57b33e7ea49b032c796ccad8cde794b5c", [:mix], [{:jsx, "~> 2.8.0", [hex: :jsx, repo: "hexpm", optional: false]}], "hexpm"}, + "hackney": {:hex, :hackney, "1.15.1", "9f8f471c844b8ce395f7b6d8398139e26ddca9ebc171a8b91342ee15a19963f4", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.4", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"}, + "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"}, + "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, + "jsx": {:hex, :jsx, "2.8.3", "a05252d381885240744d955fbe3cf810504eb2567164824e19303ea59eef62cf", [:mix, :rebar3], [], "hexpm"}, + "makeup": {:hex, :makeup, "1.0.0", "671df94cf5a594b739ce03b0d0316aa64312cee2574b6a44becb83cd90fb05dc", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"}, + "makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"}, + "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"}, + "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"}, + "nimble_parsec": {:hex, :nimble_parsec, "0.5.1", "c90796ecee0289dbb5ad16d3ad06f957b0cd1199769641c961cfe0b97db190e0", [:mix], [], "hexpm"}, + "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"}, + "poison": {:hex, :poison, "4.0.1", "bcb755a16fac91cad79bfe9fc3585bb07b9331e50cfe3420a24bcc2d735709ae", [:mix], [], "hexpm"}, + "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm"}, + "stream_data": {:hex, :stream_data, "0.4.3", "62aafd870caff0849a5057a7ec270fad0eb86889f4d433b937d996de99e3db25", [:mix], [], "hexpm"}, + "unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"}, +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..58a35a9a --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6511 @@ +{ + "name": "elixirscript", + "version": "0.26.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@ava/babel-plugin-throws-helper": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@ava/babel-plugin-throws-helper/-/babel-plugin-throws-helper-4.0.0.tgz", + "integrity": "sha512-3diBLIVBPPh3j4+hb5lo0I1D+S/O/VDJPI4Y502apBxmwEqjyXG4gTSPFUlm41sSZeZzMarT/Gzovw9kV7An0w==", + "dev": true + }, + "@ava/babel-preset-stage-4": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@ava/babel-preset-stage-4/-/babel-preset-stage-4-4.0.0.tgz", + "integrity": "sha512-lZEV1ZANzfzSYBU6WHSErsy7jLPbD1iIgAboASPMcKo7woVni5/5IKWeT0RxC8rY802MFktur3OKEw2JY1Tv2w==", + "dev": true, + "requires": { + "@babel/plugin-proposal-async-generator-functions": "^7.2.0", + "@babel/plugin-proposal-dynamic-import": "^7.5.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/plugin-transform-modules-commonjs": "^7.5.0" + } + }, + "@ava/babel-preset-transform-test-files": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@ava/babel-preset-transform-test-files/-/babel-preset-transform-test-files-6.0.0.tgz", + "integrity": "sha512-8eKhFzZp7Qcq1VLfoC75ggGT8nQs9q8fIxltU47yCB7Wi7Y8Qf6oqY1Bm0z04fIec24vEgr0ENhDHEOUGVDqnA==", + "dev": true, + "requires": { + "@ava/babel-plugin-throws-helper": "^4.0.0", + "babel-plugin-espower": "^3.0.1" + } + }, + "@babel/code-frame": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/core": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.5.5.tgz", + "integrity": "sha512-i4qoSr2KTtce0DmkuuQBV4AuQgGPUcPXMr9L5MyYAtk06z068lQ10a4O009fe5OB/DfNV+h+qqT7ddNV8UnRjg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.5.5", + "@babel/helpers": "^7.5.5", + "@babel/parser": "^7.5.5", + "@babel/template": "^7.4.4", + "@babel/traverse": "^7.5.5", + "@babel/types": "^7.5.5", + "convert-source-map": "^1.1.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "json5": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", + "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.5.5.tgz", + "integrity": "sha512-ETI/4vyTSxTzGnU2c49XHv2zhExkv9JHLTwDAFz85kmcwuShvYG2H08FwgIguQf4JC75CBnXAUM5PqeF4fj0nQ==", + "dev": true, + "requires": { + "@babel/types": "^7.5.5", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + }, + "dependencies": { + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + } + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz", + "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-function-name": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", + "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", + "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-module-imports": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz", + "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-module-transforms": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.5.5.tgz", + "integrity": "sha512-jBeCvETKuJqeiaCdyaheF40aXnnU1+wkSiUs/IQg3tB85up1LyL8x77ClY8qJpuRJUcXQo+ZtdNESmZl4j56Pw==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/template": "^7.4.4", + "@babel/types": "^7.5.5", + "lodash": "^4.17.13" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", + "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", + "dev": true + }, + "@babel/helper-regex": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.5.5.tgz", + "integrity": "sha512-CkCYQLkfkiugbRDO8eZn6lRuR8kzZoGXCg3149iTk5se7g6qykSpy3+hELSwquhu+TgHn8nkLiBwHvNX8Hofcw==", + "dev": true, + "requires": { + "lodash": "^4.17.13" + } + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz", + "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-wrap-function": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-simple-access": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz", + "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", + "dev": true, + "requires": { + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", + "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", + "dev": true, + "requires": { + "@babel/types": "^7.4.4" + } + }, + "@babel/helper-wrap-function": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz", + "integrity": "sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.2.0" + } + }, + "@babel/helpers": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.5.5.tgz", + "integrity": "sha512-nRq2BUhxZFnfEn/ciJuhklHvFOqjJUD5wpx+1bxUF2axL9C+v4DE/dmp5sT2dKnpOs4orZWzpAZqlCy8QqE/7g==", + "dev": true, + "requires": { + "@babel/template": "^7.4.4", + "@babel/traverse": "^7.5.5", + "@babel/types": "^7.5.5" + } + }, + "@babel/highlight": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + } + } + }, + "@babel/parser": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.5.5.tgz", + "integrity": "sha512-E5BN68cqR7dhKan1SfqgPGhQ178bkVKpXTPEXnFJBrEt8/DKRZlybmy+IgYLTeN7tp1R5Ccmbm2rBk17sHYU3g==", + "dev": true + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz", + "integrity": "sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0", + "@babel/plugin-syntax-async-generators": "^7.2.0" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.5.0.tgz", + "integrity": "sha512-x/iMjggsKTFHYC6g11PL7Qy58IK8H5zqfm9e6hu4z1iH2IRyAp9u9dL80zA6R76yFovETFLKz2VJIC2iIPBuFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-dynamic-import": "^7.2.0" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz", + "integrity": "sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.2.0" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz", + "integrity": "sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.2.0.tgz", + "integrity": "sha512-mVxuJ0YroI/h/tbFTPGZR8cv6ai+STMKNBq0f8hFxsxWjl94qqhsb+wXbpNMDPU3cfR1TIsVFzU3nXyZMqyK4w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz", + "integrity": "sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.4.4.tgz", + "integrity": "sha512-P05YEhRc2h53lZDjRPk/OektxCVevFzZs2Gfjd545Wde3k+yFDbXORgl2e0xpbq8mLcKJ7Idss4fAg0zORN/zg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.5.4" + }, + "dependencies": { + "regexpu-core": { + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.5.5.tgz", + "integrity": "sha512-FpI67+ky9J+cDizQUJlIlNZFKual/lUkFr1AG6zOCpwZ9cLrg8UUVakyUQJD7fCDIe9Z2nwTQJNPyonatNmDFQ==", + "dev": true, + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.1.0", + "regjsgen": "^0.5.0", + "regjsparser": "^0.6.0", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.1.0" + } + }, + "regjsgen": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.0.tgz", + "integrity": "sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==", + "dev": true + }, + "regjsparser": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", + "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + } + } + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.5.0.tgz", + "integrity": "sha512-xmHq0B+ytyrWJvQTc5OWAC4ii6Dhr0s22STOoydokG51JjWhyYo5mRPXoi+ZmtHQhZZwuXNN+GG5jy5UZZJxIQ==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.4.4", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0", + "babel-plugin-dynamic-import-node": "^2.3.0" + } + }, + "@babel/template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", + "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.4.4", + "@babel/types": "^7.4.4" + } + }, + "@babel/traverse": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.5.5.tgz", + "integrity": "sha512-MqB0782whsfffYfSjH4TM+LMjrJnhCNEDMDIjeTpl+ASaUvxcjoiVCo/sM1GhS1pHOXYfWVCYneLjMckuUxDaQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.5.5", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/parser": "^7.5.5", + "@babel/types": "^7.5.5", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz", + "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + }, + "dependencies": { + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + } + } + }, + "@comandeer/babel-plugin-banner": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@comandeer/babel-plugin-banner/-/babel-plugin-banner-5.0.0.tgz", + "integrity": "sha512-sR9Go0U6puXoXyW9UgIiIQhRcJ8jVOvGl4BptUiXAtheMs72WcakZ1udh6J0ZOivr3o8jAM+MTCHLP8FZMbVpQ==", + "dev": true + }, + "@concordance/react": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@concordance/react/-/react-2.0.0.tgz", + "integrity": "sha512-huLSkUuM2/P+U0uy2WwlKuixMsTODD8p4JVQBI4VKeopkiN0C7M3N9XYVawb4M+4spN5RrO/eLhk7KoQX6nsfA==", + "dev": true, + "requires": { + "arrify": "^1.0.1" + }, + "dependencies": { + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + } + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.1.tgz", + "integrity": "sha512-NT/skIZjgotDSiXs0WqYhgcuBKhUMgfekCmCGtkUAiLqZdOnrdjmZr9wRl3ll64J9NF79uZ4fk16Dx0yMc/Xbg==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.1", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.1.tgz", + "integrity": "sha512-+RqhBlLn6YRBGOIoVYthsG0J9dfpO79eJyN7BYBkZJtfqrBwf2KK+rD/M/yjZR6WBmIhAgOV7S60eCgaSWtbFw==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.2.tgz", + "integrity": "sha512-J/DR3+W12uCzAJkw7niXDcqcKBg6+5G5Q/ZpThpGNzAUz70eOR6RV4XnnSN01qHZiVl0eavoxJsBypQoKsV2QQ==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.1", + "fastq": "^1.6.0" + } + }, + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true + }, + "@std/esm": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/@std/esm/-/esm-0.8.3.tgz", + "integrity": "sha512-JZigVxIuy2mCkBZWxwS3Wu9eL0lJzR176Rmzb6hLjGIg3yBVBEK4XhEiFX6k5lXDY+e69XAvEVbp59PfUpfpBA==", + "dev": true + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" + }, + "@types/events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", + "dev": true + }, + "@types/glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", + "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", + "dev": true, + "requires": { + "@types/events": "*", + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "@types/node": { + "version": "12.7.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.2.tgz", + "integrity": "sha512-dyYO+f6ihZEtNPDcWNR1fkoTDf3zAK3lAABDze3mz6POyIercH0lEUawUFXlG8xaQZmm1yEBON/4TsYv/laDYg==", + "dev": true + }, + "@types/resolve": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", + "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "acorn": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.0.0.tgz", + "integrity": "sha512-PaF/MduxijYYt7unVGRuds1vBC9bFxbNf+VWqhOClfdgy7RlVkQqt610ig1/yxTgsDIfW1cWDel5EBbOy3jdtQ==", + "dev": true + }, + "acorn-jsx": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz", + "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==", + "dev": true + }, + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-align": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", + "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", + "dev": true, + "requires": { + "string-width": "^3.0.0" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "ansi-escapes": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.2.1.tgz", + "integrity": "sha512-Cg3ymMAdN10wOk/VYfLV7KCQyv7EDirJ64500sU7n9UlmioEtDuU5Gd+hj73hXSU/ex7tHJSssmyftDdkMLO8Q==", + "dev": true, + "requires": { + "type-fest": "^0.5.2" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.0.0.tgz", + "integrity": "sha512-8zjUtFJ3db/QoPXuuEMloS2AUf79/yeyttJ7Abr3hteopJu9HK8vsgGviGUMq+zyA6cZZO6gAyZoMTF6TgaEjA==", + "dev": true, + "requires": { + "color-convert": "^2.0.0" + }, + "dependencies": { + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, + "anymatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.0.3.tgz", + "integrity": "sha512-c6IvoeBECQlMVuYUjSwimnhmztImpErfxJzWZhIQinIvQWoGOnB0dLIgifbPHQt5heS6mNlaZG16f06H3C8t1g==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "append-transform": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", + "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", + "dev": true, + "requires": { + "default-require-extensions": "^2.0.0" + } + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true + }, + "array-includes": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", + "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.7.0" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "array-uniq": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-2.1.0.tgz", + "integrity": "sha512-bdHxtev7FN6+MXI1YFW0Q8mQ8dTJc2S8AMfju+ZR77pbg2yAdVyDlwkaUI7Har0LyOMRFPHrJ9lYdyjZZswdlQ==", + "dev": true + }, + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "dev": true + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "ava": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ava/-/ava-2.3.0.tgz", + "integrity": "sha512-4VaaSnl13vpTZmqW3aMqioSolT0/ozRkjQxTLi3p8wtyRONuX/uLKL3uF0j50w2BNRoLsJqztnkX2h8xeVp2lg==", + "dev": true, + "requires": { + "@ava/babel-preset-stage-4": "^4.0.0", + "@ava/babel-preset-transform-test-files": "^6.0.0", + "@babel/core": "^7.5.5", + "@babel/generator": "^7.5.5", + "@concordance/react": "^2.0.0", + "ansi-escapes": "^4.2.1", + "ansi-styles": "^4.0.0", + "arr-flatten": "^1.1.0", + "array-union": "^2.1.0", + "array-uniq": "^2.1.0", + "arrify": "^2.0.1", + "bluebird": "^3.5.5", + "chalk": "^2.4.2", + "chokidar": "^3.0.2", + "chunkd": "^1.0.0", + "ci-parallel-vars": "^1.0.0", + "clean-stack": "^2.2.0", + "clean-yaml-object": "^0.1.0", + "cli-cursor": "^3.1.0", + "cli-truncate": "^2.0.0", + "code-excerpt": "^2.1.1", + "common-path-prefix": "^1.0.0", + "concordance": "^4.0.0", + "convert-source-map": "^1.6.0", + "currently-unhandled": "^0.4.1", + "debug": "^4.1.1", + "del": "^4.1.1", + "dot-prop": "^5.1.0", + "emittery": "^0.4.1", + "empower-core": "^1.2.0", + "equal-length": "^1.0.0", + "escape-string-regexp": "^2.0.0", + "esm": "^3.2.25", + "figures": "^3.0.0", + "find-up": "^4.1.0", + "get-port": "^5.0.0", + "globby": "^10.0.1", + "ignore-by-default": "^1.0.0", + "import-local": "^3.0.2", + "indent-string": "^4.0.0", + "is-ci": "^2.0.0", + "is-error": "^2.2.2", + "is-observable": "^2.0.0", + "is-plain-object": "^3.0.0", + "is-promise": "^2.1.0", + "lodash": "^4.17.15", + "loud-rejection": "^2.1.0", + "make-dir": "^3.0.0", + "matcher": "^2.0.0", + "md5-hex": "^3.0.1", + "meow": "^5.0.0", + "micromatch": "^4.0.2", + "ms": "^2.1.2", + "observable-to-promise": "^1.0.0", + "ora": "^3.4.0", + "package-hash": "^4.0.0", + "pkg-conf": "^3.1.0", + "plur": "^3.1.1", + "pretty-ms": "^5.0.0", + "require-precompiled": "^0.1.0", + "resolve-cwd": "^3.0.0", + "slash": "^3.0.0", + "source-map-support": "^0.5.13", + "stack-utils": "^1.0.2", + "strip-ansi": "^5.2.0", + "strip-bom-buf": "^2.0.0", + "supertap": "^1.0.0", + "supports-color": "^7.0.0", + "trim-off-newlines": "^1.0.1", + "trim-right": "^1.0.1", + "unique-temp-dir": "^1.0.0", + "update-notifier": "^3.0.1", + "write-file-atomic": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "babel-core": { + "version": "6.26.3", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", + "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", + "dev": true, + "requires": { + "babel-code-frame": "^6.26.0", + "babel-generator": "^6.26.0", + "babel-helpers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-register": "^6.26.0", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "convert-source-map": "^1.5.1", + "debug": "^2.6.9", + "json5": "^0.5.1", + "lodash": "^4.17.4", + "minimatch": "^3.0.4", + "path-is-absolute": "^1.0.1", + "private": "^0.1.8", + "slash": "^1.0.0", + "source-map": "^0.5.7" + } + }, + "babel-generator": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", + "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "dev": true, + "requires": { + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.7", + "trim-right": "^1.0.1" + }, + "dependencies": { + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "dev": true + } + } + }, + "babel-helper-builder-binary-assignment-operator-visitor": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", + "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=", + "dev": true, + "requires": { + "babel-helper-explode-assignable-expression": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-helper-call-delegate": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", + "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", + "dev": true, + "requires": { + "babel-helper-hoist-variables": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-define-map": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", + "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", + "dev": true, + "requires": { + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "babel-helper-evaluate-path": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.5.0.tgz", + "integrity": "sha512-mUh0UhS607bGh5wUMAQfOpt2JX2ThXMtppHRdRU1kL7ZLRWIXxoV2UIV1r2cAeeNeU1M5SB5/RSUgUxrK8yOkA==", + "dev": true + }, + "babel-helper-explode-assignable-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", + "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-flip-expressions": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.4.3.tgz", + "integrity": "sha1-NpZzahKKwYvCUlS19AoizrPB0/0=", + "dev": true + }, + "babel-helper-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", + "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", + "dev": true, + "requires": { + "babel-helper-get-function-arity": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-get-function-arity": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", + "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-helper-hoist-variables": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", + "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-helper-is-nodes-equiv": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz", + "integrity": "sha1-NOmzALFHnd2Y7HfqC76TQt/jloQ=", + "dev": true + }, + "babel-helper-is-void-0": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-helper-is-void-0/-/babel-helper-is-void-0-0.4.3.tgz", + "integrity": "sha1-fZwBtFYee5Xb2g9u7kj1tg5nMT4=", + "dev": true + }, + "babel-helper-mark-eval-scopes": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.4.3.tgz", + "integrity": "sha1-0kSjvvmESHJgP/tG4izorN9VFWI=", + "dev": true + }, + "babel-helper-optimise-call-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", + "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-helper-regex": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", + "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "babel-helper-remap-async-to-generator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz", + "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=", + "dev": true, + "requires": { + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-remove-or-void": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.4.3.tgz", + "integrity": "sha1-pPA7QAd6D/6I5F0HAQ3uJB/1rmA=", + "dev": true + }, + "babel-helper-replace-supers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", + "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", + "dev": true, + "requires": { + "babel-helper-optimise-call-expression": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-to-multiple-sequence-expressions": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.5.0.tgz", + "integrity": "sha512-m2CvfDW4+1qfDdsrtf4dwOslQC3yhbgyBFptncp4wvtdrDHqueW7slsYv4gArie056phvQFhT2nRcGS4bnm6mA==", + "dev": true + }, + "babel-helpers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-check-es2015-constants": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", + "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz", + "integrity": "sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==", + "dev": true, + "requires": { + "object.assign": "^4.1.0" + } + }, + "babel-plugin-espower": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/babel-plugin-espower/-/babel-plugin-espower-3.0.1.tgz", + "integrity": "sha512-Ms49U7VIAtQ/TtcqRbD6UBmJBUCSxiC3+zPc+eGqxKUIFO1lTshyEDRUjhoAbd2rWfwYf3cZ62oXozrd8W6J0A==", + "dev": true, + "requires": { + "@babel/generator": "^7.0.0", + "@babel/parser": "^7.0.0", + "call-matcher": "^1.0.0", + "core-js": "^2.0.0", + "espower-location-detector": "^1.0.0", + "espurify": "^1.6.0", + "estraverse": "^4.1.1" + } + }, + "babel-plugin-minify-builtins": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.5.0.tgz", + "integrity": "sha512-wpqbN7Ov5hsNwGdzuzvFcjgRlzbIeVv1gMIlICbPj0xkexnfoIDe7q+AZHMkQmAE/F9R5jkrB6TLfTegImlXag==", + "dev": true + }, + "babel-plugin-minify-constant-folding": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.5.0.tgz", + "integrity": "sha512-Vj97CTn/lE9hR1D+jKUeHfNy+m1baNiJ1wJvoGyOBUx7F7kJqDZxr9nCHjO/Ad+irbR3HzR6jABpSSA29QsrXQ==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "^0.5.0" + } + }, + "babel-plugin-minify-dead-code-elimination": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.5.1.tgz", + "integrity": "sha512-x8OJOZIrRmQBcSqxBcLbMIK8uPmTvNWPXH2bh5MDCW1latEqYiRMuUkPImKcfpo59pTUB2FT7HfcgtG8ZlR5Qg==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "^0.5.0", + "babel-helper-mark-eval-scopes": "^0.4.3", + "babel-helper-remove-or-void": "^0.4.3", + "lodash": "^4.17.11" + } + }, + "babel-plugin-minify-flip-comparisons": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.4.3.tgz", + "integrity": "sha1-AMqHDLjxO0XAOLPB68DyJyk8llo=", + "dev": true, + "requires": { + "babel-helper-is-void-0": "^0.4.3" + } + }, + "babel-plugin-minify-guarded-expressions": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.4.4.tgz", + "integrity": "sha512-RMv0tM72YuPPfLT9QLr3ix9nwUIq+sHT6z8Iu3sLbqldzC1Dls8DPCywzUIzkTx9Zh1hWX4q/m9BPoPed9GOfA==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "^0.5.0", + "babel-helper-flip-expressions": "^0.4.3" + } + }, + "babel-plugin-minify-infinity": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.4.3.tgz", + "integrity": "sha1-37h2obCKBldjhO8/kuZTumB7Oco=", + "dev": true + }, + "babel-plugin-minify-mangle-names": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.5.0.tgz", + "integrity": "sha512-3jdNv6hCAw6fsX1p2wBGPfWuK69sfOjfd3zjUXkbq8McbohWy23tpXfy5RnToYWggvqzuMOwlId1PhyHOfgnGw==", + "dev": true, + "requires": { + "babel-helper-mark-eval-scopes": "^0.4.3" + } + }, + "babel-plugin-minify-numeric-literals": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.4.3.tgz", + "integrity": "sha1-jk/VYcefeAEob/YOjF/Z3u6TwLw=", + "dev": true + }, + "babel-plugin-minify-replace": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.5.0.tgz", + "integrity": "sha512-aXZiaqWDNUbyNNNpWs/8NyST+oU7QTpK7J9zFEFSA0eOmtUNMU3fczlTTTlnCxHmq/jYNFEmkkSG3DDBtW3Y4Q==", + "dev": true + }, + "babel-plugin-minify-simplify": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.5.1.tgz", + "integrity": "sha512-OSYDSnoCxP2cYDMk9gxNAed6uJDiDz65zgL6h8d3tm8qXIagWGMLWhqysT6DY3Vs7Fgq7YUDcjOomhVUb+xX6A==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "^0.5.0", + "babel-helper-flip-expressions": "^0.4.3", + "babel-helper-is-nodes-equiv": "^0.0.1", + "babel-helper-to-multiple-sequence-expressions": "^0.5.0" + } + }, + "babel-plugin-minify-type-constructors": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.4.3.tgz", + "integrity": "sha1-G8bxW4f3qxCF1CszC3F2V6IVZQA=", + "dev": true, + "requires": { + "babel-helper-is-void-0": "^0.4.3" + } + }, + "babel-plugin-syntax-async-functions": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", + "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=", + "dev": true + }, + "babel-plugin-syntax-exponentiation-operator": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", + "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=", + "dev": true + }, + "babel-plugin-syntax-trailing-function-commas": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", + "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=", + "dev": true + }, + "babel-plugin-transform-async-to-generator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", + "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=", + "dev": true, + "requires": { + "babel-helper-remap-async-to-generator": "^6.24.1", + "babel-plugin-syntax-async-functions": "^6.8.0", + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-arrow-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", + "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-block-scoped-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", + "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-block-scoping": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", + "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "babel-plugin-transform-es2015-classes": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", + "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", + "dev": true, + "requires": { + "babel-helper-define-map": "^6.24.1", + "babel-helper-function-name": "^6.24.1", + "babel-helper-optimise-call-expression": "^6.24.1", + "babel-helper-replace-supers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-computed-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", + "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-destructuring": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", + "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-duplicate-keys": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", + "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-for-of": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", + "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", + "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", + "dev": true, + "requires": { + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", + "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-modules-amd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", + "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", + "dev": true, + "requires": { + "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-modules-commonjs": { + "version": "6.26.2", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", + "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==", + "dev": true, + "requires": { + "babel-plugin-transform-strict-mode": "^6.24.1", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-types": "^6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-systemjs": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", + "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", + "dev": true, + "requires": { + "babel-helper-hoist-variables": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-modules-umd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", + "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", + "dev": true, + "requires": { + "babel-plugin-transform-es2015-modules-amd": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-object-super": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", + "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", + "dev": true, + "requires": { + "babel-helper-replace-supers": "^6.24.1", + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-parameters": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", + "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", + "dev": true, + "requires": { + "babel-helper-call-delegate": "^6.24.1", + "babel-helper-get-function-arity": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-shorthand-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", + "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-spread": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", + "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-sticky-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", + "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", + "dev": true, + "requires": { + "babel-helper-regex": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-template-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", + "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-typeof-symbol": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", + "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-unicode-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", + "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", + "dev": true, + "requires": { + "babel-helper-regex": "^6.24.1", + "babel-runtime": "^6.22.0", + "regexpu-core": "^2.0.0" + } + }, + "babel-plugin-transform-exponentiation-operator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", + "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=", + "dev": true, + "requires": { + "babel-helper-builder-binary-assignment-operator-visitor": "^6.24.1", + "babel-plugin-syntax-exponentiation-operator": "^6.8.0", + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-inline-consecutive-adds": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.4.3.tgz", + "integrity": "sha1-Mj1Ho+pjqDp6w8gRro5pQfrysNE=", + "dev": true + }, + "babel-plugin-transform-member-expression-literals": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.9.4.tgz", + "integrity": "sha1-NwOcmgwzE6OUlfqsL/OmtbnQOL8=", + "dev": true + }, + "babel-plugin-transform-merge-sibling-variables": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.4.tgz", + "integrity": "sha1-hbQi/DN3tEnJ0c3kQIcgNTJAHa4=", + "dev": true + }, + "babel-plugin-transform-minify-booleans": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.4.tgz", + "integrity": "sha1-rLs+VqNVXdI5KOS1gtKFFi3SsZg=", + "dev": true + }, + "babel-plugin-transform-property-literals": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.4.tgz", + "integrity": "sha1-mMHSHiVXNlc/k+zlRFn2ziSYXTk=", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "babel-plugin-transform-regenerator": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", + "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", + "dev": true, + "requires": { + "regenerator-transform": "^0.10.0" + } + }, + "babel-plugin-transform-regexp-constructors": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.4.3.tgz", + "integrity": "sha1-WLd3W2OvzzMyj66aX4j71PsLSWU=", + "dev": true + }, + "babel-plugin-transform-remove-console": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz", + "integrity": "sha1-uYA2DAZzhOJLNXpYjYB9PINSd4A=", + "dev": true + }, + "babel-plugin-transform-remove-debugger": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.9.4.tgz", + "integrity": "sha1-QrcnYxyXl44estGZp67IShgznvI=", + "dev": true + }, + "babel-plugin-transform-remove-undefined": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.5.0.tgz", + "integrity": "sha512-+M7fJYFaEE/M9CXa0/IRkDbiV3wRELzA1kKQFCJ4ifhrzLKn/9VCCgj9OFmYWwBd8IB48YdgPkHYtbYq+4vtHQ==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "^0.5.0" + } + }, + "babel-plugin-transform-simplify-comparison-operators": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.9.4.tgz", + "integrity": "sha1-9ir+CWyrDh9ootdT/fKDiIRxzrk=", + "dev": true + }, + "babel-plugin-transform-strict-mode": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", + "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-undefined-to-void": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.4.tgz", + "integrity": "sha1-viQcqBQEAwZ4t0hxcyK4nQyP4oA=", + "dev": true + }, + "babel-preset-env": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.7.0.tgz", + "integrity": "sha512-9OR2afuKDneX2/q2EurSftUYM0xGu4O2D9adAhVfADDhrYDaxXV0rBbevVYoY9n6nyX1PmQW/0jtpJvUNr9CHg==", + "dev": true, + "requires": { + "babel-plugin-check-es2015-constants": "^6.22.0", + "babel-plugin-syntax-trailing-function-commas": "^6.22.0", + "babel-plugin-transform-async-to-generator": "^6.22.0", + "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", + "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0", + "babel-plugin-transform-es2015-block-scoping": "^6.23.0", + "babel-plugin-transform-es2015-classes": "^6.23.0", + "babel-plugin-transform-es2015-computed-properties": "^6.22.0", + "babel-plugin-transform-es2015-destructuring": "^6.23.0", + "babel-plugin-transform-es2015-duplicate-keys": "^6.22.0", + "babel-plugin-transform-es2015-for-of": "^6.23.0", + "babel-plugin-transform-es2015-function-name": "^6.22.0", + "babel-plugin-transform-es2015-literals": "^6.22.0", + "babel-plugin-transform-es2015-modules-amd": "^6.22.0", + "babel-plugin-transform-es2015-modules-commonjs": "^6.23.0", + "babel-plugin-transform-es2015-modules-systemjs": "^6.23.0", + "babel-plugin-transform-es2015-modules-umd": "^6.23.0", + "babel-plugin-transform-es2015-object-super": "^6.22.0", + "babel-plugin-transform-es2015-parameters": "^6.23.0", + "babel-plugin-transform-es2015-shorthand-properties": "^6.22.0", + "babel-plugin-transform-es2015-spread": "^6.22.0", + "babel-plugin-transform-es2015-sticky-regex": "^6.22.0", + "babel-plugin-transform-es2015-template-literals": "^6.22.0", + "babel-plugin-transform-es2015-typeof-symbol": "^6.23.0", + "babel-plugin-transform-es2015-unicode-regex": "^6.22.0", + "babel-plugin-transform-exponentiation-operator": "^6.22.0", + "babel-plugin-transform-regenerator": "^6.22.0", + "browserslist": "^3.2.6", + "invariant": "^2.2.2", + "semver": "^5.3.0" + } + }, + "babel-preset-minify": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-minify/-/babel-preset-minify-0.5.1.tgz", + "integrity": "sha512-1IajDumYOAPYImkHbrKeiN5AKKP9iOmRoO2IPbIuVp0j2iuCcj0n7P260z38siKMZZ+85d3mJZdtW8IgOv+Tzg==", + "dev": true, + "requires": { + "babel-plugin-minify-builtins": "^0.5.0", + "babel-plugin-minify-constant-folding": "^0.5.0", + "babel-plugin-minify-dead-code-elimination": "^0.5.1", + "babel-plugin-minify-flip-comparisons": "^0.4.3", + "babel-plugin-minify-guarded-expressions": "^0.4.4", + "babel-plugin-minify-infinity": "^0.4.3", + "babel-plugin-minify-mangle-names": "^0.5.0", + "babel-plugin-minify-numeric-literals": "^0.4.3", + "babel-plugin-minify-replace": "^0.5.0", + "babel-plugin-minify-simplify": "^0.5.1", + "babel-plugin-minify-type-constructors": "^0.4.3", + "babel-plugin-transform-inline-consecutive-adds": "^0.4.3", + "babel-plugin-transform-member-expression-literals": "^6.9.4", + "babel-plugin-transform-merge-sibling-variables": "^6.9.4", + "babel-plugin-transform-minify-booleans": "^6.9.4", + "babel-plugin-transform-property-literals": "^6.9.4", + "babel-plugin-transform-regexp-constructors": "^0.4.3", + "babel-plugin-transform-remove-console": "^6.9.4", + "babel-plugin-transform-remove-debugger": "^6.9.4", + "babel-plugin-transform-remove-undefined": "^0.5.0", + "babel-plugin-transform-simplify-comparison-operators": "^6.9.4", + "babel-plugin-transform-undefined-to-void": "^6.9.4", + "lodash": "^4.17.11" + } + }, + "babel-register": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", + "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", + "dev": true, + "requires": { + "babel-core": "^6.26.0", + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "home-or-tmp": "^2.0.0", + "lodash": "^4.17.4", + "mkdirp": "^0.5.1", + "source-map-support": "^0.4.15" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "dev": true, + "requires": { + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "dev": true + }, + "bluebird": { + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", + "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==", + "dev": true + }, + "blueimp-md5": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/blueimp-md5/-/blueimp-md5-2.11.1.tgz", + "integrity": "sha512-4UiOAmql2XO0Sws07OVzYdCKK0K2Va5g6AVgYXoGhEQiKrdSOefjUCm1frPk6E+xiIOHRqaFg+TUGo7cClKg5g==", + "dev": true + }, + "boxen": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-3.2.0.tgz", + "integrity": "sha512-cU4J/+NodM3IHdSL2yN8bqYqnmlBTidDR4RC7nJs61ZmtGz8VZzM3HLQX0zY5mrSmPtR3xWwsq2jOUQqFZN8+A==", + "dev": true, + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^2.4.2", + "cli-boxes": "^2.2.0", + "string-width": "^3.0.0", + "term-size": "^1.2.0", + "type-fest": "^0.3.0", + "widest-line": "^2.0.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "type-fest": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "dev": true + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz", + "integrity": "sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000844", + "electron-to-chromium": "^1.3.47" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "builtin-modules": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", + "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==", + "dev": true + }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } + } + }, + "caching-transform": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-3.0.2.tgz", + "integrity": "sha512-Mtgcv3lh3U0zRii/6qVgQODdPA4G3zhG+jtbCWj39RXuUFTMzH0vcdMtaJS1jPowd+It2Pqr6y3NJMQqOqCE2w==", + "dev": true, + "requires": { + "hasha": "^3.0.0", + "make-dir": "^2.0.0", + "package-hash": "^3.0.0", + "write-file-atomic": "^2.4.2" + }, + "dependencies": { + "hasha": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-3.0.0.tgz", + "integrity": "sha1-UqMvq4Vp1BymmmH/GiFPjrfIvTk=", + "dev": true, + "requires": { + "is-stream": "^1.0.1" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "package-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-3.0.0.tgz", + "integrity": "sha512-lOtmukMDVvtkL84rJHI7dpTYq+0rli8N2wlnqUcBuDWCfVhRUfOmnR9SsoHFMLpACvEV60dX7rd0rFaYDZI+FA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "hasha": "^3.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + } + } + }, + "call-matcher": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/call-matcher/-/call-matcher-1.1.0.tgz", + "integrity": "sha512-IoQLeNwwf9KTNbtSA7aEBb1yfDbdnzwjCetjkC8io5oGeOmK2CBNdg0xr+tadRYKO0p7uQyZzvon0kXlZbvGrw==", + "dev": true, + "requires": { + "core-js": "^2.0.0", + "deep-equal": "^1.0.0", + "espurify": "^1.6.0", + "estraverse": "^4.0.0" + } + }, + "call-signature": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/call-signature/-/call-signature-0.0.2.tgz", + "integrity": "sha1-qEq8glpV70yysCi9dOIFpluaSZY=", + "dev": true + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "camelcase-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz", + "integrity": "sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=", + "dev": true, + "requires": { + "camelcase": "^4.1.0", + "map-obj": "^2.0.0", + "quick-lru": "^1.0.0" + } + }, + "caniuse-lite": { + "version": "1.0.30000989", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000989.tgz", + "integrity": "sha512-vrMcvSuMz16YY6GSVZ0dWDTJP8jqk3iFQ/Aq5iqblPwxSVVZI+zxDyTX0VPqtQsDnfdrBDcsmhgTEOh5R8Lbpw==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "chokidar": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.0.2.tgz", + "integrity": "sha512-c4PR2egjNjI1um6bamCQ6bUNPDiyofNQruHvKgHQ4gDUP/ITSVSzNsiI5OWtHOsX323i5ha/kk4YmOZ1Ktg7KA==", + "dev": true, + "requires": { + "anymatch": "^3.0.1", + "braces": "^3.0.2", + "fsevents": "^2.0.6", + "glob-parent": "^5.0.0", + "is-binary-path": "^2.1.0", + "is-glob": "^4.0.1", + "normalize-path": "^3.0.0", + "readdirp": "^3.1.1" + } + }, + "chunkd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/chunkd/-/chunkd-1.0.0.tgz", + "integrity": "sha512-xx3Pb5VF9QaqCotolyZ1ywFBgyuJmu6+9dLiqBxgelEse9Xsr3yUlpoX3O4Oh11M00GT2kYMsRByTKIMJW2Lkg==", + "dev": true + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "ci-parallel-vars": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ci-parallel-vars/-/ci-parallel-vars-1.0.0.tgz", + "integrity": "sha512-u6dx20FBXm+apMi+5x7UVm6EH7BL1gc4XrcnQewjcB7HWRcor/V5qWc3RG2HwpgDJ26gIi2DSEu3B7sXynAw/g==", + "dev": true + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "clean-yaml-object": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/clean-yaml-object/-/clean-yaml-object-0.1.0.tgz", + "integrity": "sha1-Y/sRDcLOGoTcIfbZM0h20BCui2g=", + "dev": true + }, + "cli-boxes": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.0.tgz", + "integrity": "sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-spinners": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.2.0.tgz", + "integrity": "sha512-tgU3fKwzYjiLEQgPMD9Jt+JjHVL9kW93FiIMX/l7rivvOD4/LL0Mf7gda3+4U2KJBloybwgj5KEoQgGRioMiKQ==", + "dev": true + }, + "cli-truncate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.0.0.tgz", + "integrity": "sha512-C4hp+8GCIFVsUUiXcw+ce+7wexVWImw8rQrgMBFsqerx9LvvcGlwm6sMjQYAEmV/Xb87xc1b5Ttx505MSpZVqg==", + "dev": true, + "requires": { + "slice-ansi": "^2.1.0", + "string-width": "^4.1.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "code-excerpt": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/code-excerpt/-/code-excerpt-2.1.1.tgz", + "integrity": "sha512-tJLhH3EpFm/1x7heIW0hemXJTUU5EWl2V0EIX558jp05Mt1U6DVryCgkp3l37cxqs+DNbNgxG43SkwJXpQ14Jw==", + "dev": true, + "requires": { + "convert-to-spaces": "^1.0.1" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "dev": true, + "optional": true + }, + "common-path-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-1.0.0.tgz", + "integrity": "sha1-zVL28HEuC6q5fW+XModPIvR3UsA=", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concordance": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/concordance/-/concordance-4.0.0.tgz", + "integrity": "sha512-l0RFuB8RLfCS0Pt2Id39/oCPykE01pyxgAFypWTlaGRgvLkZrtczZ8atEHpTeEIW+zYWXTBuA9cCSeEOScxReQ==", + "dev": true, + "requires": { + "date-time": "^2.1.0", + "esutils": "^2.0.2", + "fast-diff": "^1.1.2", + "js-string-escape": "^1.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.flattendeep": "^4.4.0", + "lodash.islength": "^4.0.1", + "lodash.merge": "^4.6.1", + "md5-hex": "^2.0.0", + "semver": "^5.5.1", + "well-known-symbols": "^2.0.0" + }, + "dependencies": { + "md5-hex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-2.0.0.tgz", + "integrity": "sha1-0FiOnxx0lUSS7NJKwKxs6ZfZLjM=", + "dev": true, + "requires": { + "md5-o-matic": "^0.1.1" + } + } + } + }, + "configstore": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-4.0.0.tgz", + "integrity": "sha512-CmquAXFBocrzaSM8mtGPMM/HiWmyIpr4CcJl/rgY2uCObZ/S7cKU0silxslqJejl+t/T9HS8E0PUNQD81JGUEQ==", + "dev": true, + "requires": { + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" + }, + "dependencies": { + "dot-prop": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", + "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "dev": true, + "requires": { + "is-obj": "^1.0.0" + } + }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true + }, + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + } + } + }, + "confusing-browser-globals": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.8.tgz", + "integrity": "sha512-lI7asCibVJ6Qd3FGU7mu4sfG4try4LX3+GVS+Gv8UlrEf2AeW57piecapnog2UHZSbcX/P/1UDWVaTsblowlZg==", + "dev": true + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, + "convert-source-map": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, + "convert-to-spaces": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/convert-to-spaces/-/convert-to-spaces-1.0.2.tgz", + "integrity": "sha1-fj5Iu+bZl7FBfdyihoIEtNPYVxU=", + "dev": true + }, + "core-js": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz", + "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==", + "dev": true + }, + "cp-file": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-6.2.0.tgz", + "integrity": "sha512-fmvV4caBnofhPe8kOcitBwSn2f39QLjnAnGq3gO9dfd75mUytzKNZB1hde6QHunW2Rt+OwuBOMc3i1tNElbszA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "make-dir": "^2.0.0", + "nested-error-stacks": "^2.0.0", + "pify": "^4.0.1", + "safe-buffer": "^5.0.1" + }, + "dependencies": { + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "crypto-random-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", + "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", + "dev": true + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true, + "requires": { + "array-find-index": "^1.0.1" + } + }, + "date-time": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/date-time/-/date-time-2.1.0.tgz", + "integrity": "sha512-/9+C44X7lot0IeiyfgJmETtRMhBidBYM2QFFIkGa0U1k+hSyY87Nw7PY3eDqpvCBm7I3WCSfPeZskW/YYq6m4g==", + "dev": true, + "requires": { + "time-zone": "^1.0.0" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", + "dev": true, + "requires": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + } + } + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", + "dev": true + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "default-require-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", + "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", + "dev": true, + "requires": { + "strip-bom": "^3.0.0" + } + }, + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, + "defer-to-connect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.0.2.tgz", + "integrity": "sha512-k09hcQcTDY+cwgiwa6PYKLm3jlagNzQ+RSvhjzESOGOx+MNOuXkxTfEvPrO1IOQ81tArCFYQgi631clB70RpQw==", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "del": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" + }, + "dependencies": { + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + }, + "dependencies": { + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + } + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dot-prop": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.1.0.tgz", + "integrity": "sha512-n1oC6NBF+KM9oVXtjmen4Yo7HyAVWV2UUl50dCYJdw2924K6dX9bf9TTTWaKtYlRn0FEtxG27KS80ayVLixxJA==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.236", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.236.tgz", + "integrity": "sha512-LWOvuJ80pLO3FtFqTcGuXB0dxdMtzSCkRmbXdY5mHUvXRQGor3sTVmyfU70aD2yF5i+fbHz52ncWr5T3xUYHlA==", + "dev": true + }, + "emittery": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.4.1.tgz", + "integrity": "sha512-r4eRSeStEGf6M5SKdrQhhLK5bOwOBxQhIE3YSTnZE3GpKiLfnnhE+tPtrJE79+eDJgm39BM6LSoI8SCx4HbwlQ==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "empower-core": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/empower-core/-/empower-core-1.2.0.tgz", + "integrity": "sha512-g6+K6Geyc1o6FdXs9HwrXleCFan7d66G5xSCfSF7x1mJDCes6t0om9lFQG3zOrzh3Bkb/45N0cZ5Gqsf7YrzGQ==", + "dev": true, + "requires": { + "call-signature": "0.0.2", + "core-js": "^2.0.0" + } + }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "equal-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/equal-length/-/equal-length-1.0.1.tgz", + "integrity": "sha1-IcoRLUirJLTh5//A5TOdMf38J0w=", + "dev": true + }, + "erlang-types": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/erlang-types/-/erlang-types-1.1.3.tgz", + "integrity": "sha512-HZWcirSqKIdasr04DT9NnYgVyqvUaefDPp2LhNgtBnM2ovOkUhJ4DEKVQZ71POKsu4wiR64EWhahA8AE9r796g==" + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.2.1.tgz", + "integrity": "sha512-ES7BzEzr0Q6m5TK9i+/iTpKjclXitOdDK4vT07OqbkBT2/VcN/gO9EL1C4HlK3TAOXYv2ItcmbVR9jO1MR0fJg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.2", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.0", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^6.4.1", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "strip-json-comments": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", + "dev": true + } + } + }, + "eslint-config-airbnb-base": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.0.0.tgz", + "integrity": "sha512-2IDHobw97upExLmsebhtfoD3NAKhV4H0CJWP3Uprd/uk+cHuWYOczPVxQ8PxLFUAw7o3Th1RAU8u1DoUpr+cMA==", + "dev": true, + "requires": { + "confusing-browser-globals": "^1.0.7", + "object.assign": "^4.1.0", + "object.entries": "^1.1.0" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", + "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.5.0" + } + }, + "eslint-module-utils": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.1.tgz", + "integrity": "sha512-H6DOj+ejw7Tesdgbfs4jeS4YMFrT8uI8xwd1gtQqXssaR0EQ26L+2O/w6wkYFy2MymON0fTwHmXBvvfLNZVZEw==", + "dev": true, + "requires": { + "debug": "^2.6.8", + "pkg-dir": "^2.0.0" + } + }, + "eslint-plugin-import": { + "version": "2.18.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.18.2.tgz", + "integrity": "sha512-5ohpsHAiUBRNaBWAF08izwUGlbrJoJJ+W9/TBwsGoR1MnlgfwMIKrFeSjWbt6moabiXW9xNvtFz+97KHRfI4HQ==", + "dev": true, + "requires": { + "array-includes": "^3.0.3", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.2", + "eslint-module-utils": "^2.4.0", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.0", + "read-pkg-up": "^2.0.0", + "resolve": "^1.11.0" + }, + "dependencies": { + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + } + } + }, + "eslint-scope": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz", + "integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.0.0" + } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "dev": true + }, + "esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", + "dev": true + }, + "espower-location-detector": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/espower-location-detector/-/espower-location-detector-1.0.0.tgz", + "integrity": "sha1-oXt+zFnTDheeK+9z+0E3cEyzMbU=", + "dev": true, + "requires": { + "is-url": "^1.2.1", + "path-is-absolute": "^1.0.0", + "source-map": "^0.5.0", + "xtend": "^4.0.0" + } + }, + "espree": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.0.tgz", + "integrity": "sha512-boA7CHRLlVWUSg3iL5Kmlt/xT3Q+sXnKoRYYzj1YeM10A76TEJBbotV5pKbnK42hEUIr121zTv+QLRM5LsCPXQ==", + "dev": true, + "requires": { + "acorn": "^7.0.0", + "acorn-jsx": "^5.0.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "espurify": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/espurify/-/espurify-1.8.1.tgz", + "integrity": "sha512-ZDko6eY/o+D/gHCWyHTU85mKDgYcS4FJj7S+YD6WIInm7GQ6AnOjmcL4+buFV/JOztVLELi/7MmuGU5NHta0Mg==", + "dev": true, + "requires": { + "core-js": "^2.0.0" + } + }, + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "dev": true, + "requires": { + "estraverse": "^4.0.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "fast-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.0.4.tgz", + "integrity": "sha512-wkIbV6qg37xTJwqSsdnIphL1e+LaGz4AIQqr00mIubMaEhv1/HEmJ0uuCGZRNRUkZZmOB5mJKO0ZUTVq+SxMQg==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.1", + "@nodelib/fs.walk": "^1.2.1", + "glob-parent": "^5.0.0", + "is-glob": "^4.0.1", + "merge2": "^1.2.3", + "micromatch": "^4.0.2" + } + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fastq": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.6.0.tgz", + "integrity": "sha512-jmxqQ3Z/nXoeyDmWAzF9kH1aGZSis6e/SbfPmJpUnyZ0ogr6iscHQaml4wsEepEWSdtmpy+eVXmCRIMpxaXqOA==", + "dev": true, + "requires": { + "reusify": "^1.0.0" + } + }, + "figures": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.0.0.tgz", + "integrity": "sha512-HKri+WoWoUgr83pehn/SIgLOMZ9nAWC6dcGj26RY2R4F50u4+RTUz0RCrUlOV3nKRAICW1UGzyb+kcX2qK1S/g==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "p-limit": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + } + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "dependencies": { + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "flatted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", + "dev": true + }, + "foreground-child": { + "version": "1.5.6", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", + "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", + "dev": true, + "requires": { + "cross-spawn": "^4", + "signal-exit": "^3.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", + "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + } + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.0.7.tgz", + "integrity": "sha512-a7YT0SV3RB+DjYcppwVDLtn13UQnmg0SWZS7ezZD0UjnLwXmy8Zm21GMVGLaFGimIqcvyMQaOJBrop8MyOp1kQ==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-port": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.0.0.tgz", + "integrity": "sha512-imzMU0FjsZqNa6BqOjbbW6w5BivHIuQKopjpPqcnx0AVHJQKCxK1O+Ab3OrVXhrekqfVMjwA9ZYu062R+KcIsQ==", + "dev": true, + "requires": { + "type-fest": "^0.3.0" + }, + "dependencies": { + "type-fest": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "dev": true + } + } + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz", + "integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "global-dirs": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", + "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", + "dev": true, + "requires": { + "ini": "^1.3.4" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true + }, + "globby": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", + "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + }, + "dependencies": { + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + } + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "dependencies": { + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + } + } + }, + "graceful-fs": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", + "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", + "dev": true + }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==" + }, + "handlebars": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz", + "integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==", + "dev": true, + "requires": { + "neo-async": "^2.6.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "dev": true + }, + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true + }, + "hasha": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.0.0.tgz", + "integrity": "sha512-PqWdhnQhq6tqD32hZv+l1e5mJHNSudjnaAzgAHfkGiU0ABN6lmbZF8abJIulQHbZ7oiHhP8yL6O910ICMc+5pw==", + "dev": true, + "requires": { + "is-stream": "^1.1.0", + "type-fest": "^0.3.0" + }, + "dependencies": { + "type-fest": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "dev": true + } + } + }, + "home-or-tmp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.1" + } + }, + "hosted-git-info": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.4.tgz", + "integrity": "sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ==", + "dev": true + }, + "http-cache-semantics": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz", + "integrity": "sha512-TcIMG3qeVLgDr1TEd2XvHaTnMPwYQUQMIBLy+5pLSDKYFc7UIqj39w8EGzZkaxoLv/l2K8HaI0t5AVA+YYgUew==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", + "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==", + "dev": true + }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", + "dev": true + }, + "import-fresh": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", + "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true + }, + "import-local": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", + "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "inquirer": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.1.tgz", + "integrity": "sha512-uxNHBeQhRXIoHWTSNYUFhQVrHYFThIt6IVo2fFmSe8aBwdR3/w6b58hJpiL/fMukFkvGzjg+hSxFtwvVmKZmXw==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^2.4.2", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^4.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + } + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "irregular-plurals": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-2.0.0.tgz", + "integrity": "sha512-Y75zBYLkh0lJ9qxeHlMjQ7bSbyiSqNW/UOPWDmzC7cXskL1hekSITh1Oc6JV0XCWWZ9DE8VYSB71xocLk3gmGw==", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "is-error": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-error/-/is-error-2.2.2.tgz", + "integrity": "sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-installed-globally": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", + "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", + "dev": true, + "requires": { + "global-dirs": "^0.1.0", + "is-path-inside": "^1.0.0" + }, + "dependencies": { + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "requires": { + "path-is-inside": "^1.0.1" + } + } + } + }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", + "dev": true + }, + "is-npm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-3.0.0.tgz", + "integrity": "sha512-wsigDr1Kkschp2opC4G3yA6r9EgVA6NjRpWzIi9axXqeIaAATPRJc4uLujXe3Nd9uO8KoDyA4MD6aZSeXTADhA==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + }, + "is-observable": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-2.0.0.tgz", + "integrity": "sha512-fhBZv3eFKUbyHXZ1oHujdo2tZ+CNbdpdzzlENgCGZUC8keoGxUew2jYFLYcUB4qo7LDD03o4KK11m/QYD7kEjg==", + "dev": true + }, + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "dev": true + }, + "is-path-in-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", + "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", + "dev": true, + "requires": { + "is-path-inside": "^2.1.0" + } + }, + "is-path-inside": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", + "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", + "dev": true, + "requires": { + "path-is-inside": "^1.0.2" + } + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-plain-object": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.0.tgz", + "integrity": "sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==", + "dev": true, + "requires": { + "isobject": "^4.0.0" + } + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-reference": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.1.3.tgz", + "integrity": "sha512-W1iHHv/oyBb2pPxkBxtaewxa1BC58Pn5J0hogyCdefwUIvb6R+TGbAcIa4qPNYLqLhb3EnOgUf2MQkkF76BcKw==", + "requires": { + "@types/estree": "0.0.39" + } + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "^1.0.1" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz", + "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz", + "integrity": "sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==", + "dev": true, + "requires": { + "append-transform": "^1.0.0" + } + }, + "istanbul-lib-instrument": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "dev": true, + "requires": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "istanbul-lib-report": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", + "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", + "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", + "dev": true, + "requires": { + "handlebars": "^4.1.2" + } + }, + "js-string-escape": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", + "integrity": "sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8=", + "dev": true + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, + "latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dev": true, + "requires": { + "package-json": "^6.3.0" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "dev": true + }, + "lodash.islength": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.islength/-/lodash.islength-4.0.1.tgz", + "integrity": "sha1-Tpho1FJXXXUK/9NYyXlUPcIO1Xc=", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + } + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "loud-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-2.1.0.tgz", + "integrity": "sha512-g/6MQxUXYHeVqZ4PGpPL1fS1fOvlXoi7bay0pizmjAd/3JhyXwxzwrnr74yzdmhuerlslbRJ3x7IOXzFz0cE5w==", + "dev": true, + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.2" + } + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "magic-string": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.3.tgz", + "integrity": "sha512-6QK0OpF/phMz0Q2AxILkX2mFhi7m+WMwTRg0LQKq/WBB0cDP4rYH3Wp4/d3OTXlrPLVJT/RFqj8tFeAR4nk8AA==", + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, + "make-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.0.tgz", + "integrity": "sha512-grNJDhb8b1Jm1qeqW5R/O63wUo4UXo2v2HMic6YT9i/HBlF93S8jkMgH7yugvY9ABDShH4VZMn8I+U8+fCNegw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "map-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz", + "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=", + "dev": true + }, + "matcher": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-2.0.0.tgz", + "integrity": "sha512-nlmfSlgHBFx36j/Pl/KQPbIaqE8Zf0TqmSMjsuddHDg6PMSVgmyW9HpkLs0o0M1n2GIZ/S2BZBLIww/xjhiGng==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, + "md5-hex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-3.0.1.tgz", + "integrity": "sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==", + "dev": true, + "requires": { + "blueimp-md5": "^2.10.0" + } + }, + "md5-o-matic": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/md5-o-matic/-/md5-o-matic-0.1.1.tgz", + "integrity": "sha1-givM1l4RfFFPqxdrJZRdVBAKA8M=", + "dev": true + }, + "meow": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-5.0.0.tgz", + "integrity": "sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig==", + "dev": true, + "requires": { + "camelcase-keys": "^4.0.0", + "decamelize-keys": "^1.0.0", + "loud-rejection": "^1.0.0", + "minimist-options": "^3.0.1", + "normalize-package-data": "^2.3.4", + "read-pkg-up": "^3.0.0", + "redent": "^2.0.0", + "trim-newlines": "^2.0.0", + "yargs-parser": "^10.0.0" + }, + "dependencies": { + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + } + } + } + }, + "merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "merge2": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.4.tgz", + "integrity": "sha512-FYE8xI+6pjFOhokZu0We3S5NKCirLbCzSh2Usf3qEyr4X8U+0jNg9P8RZ4qz+V2UoECLVwSyzU3LxXBaLGtD3A==", + "dev": true + }, + "micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "minimist-options": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-3.0.2.tgz", + "integrity": "sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0" + }, + "dependencies": { + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "dev": true + }, + "nested-error-stacks": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz", + "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-url": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.3.0.tgz", + "integrity": "sha512-0NLtR71o4k6GLP+mr6Ty34c5GA6CMoEsncKJxvQd8NzPxaHRJNnb5gZE8R1XF4CPIS7QPHLJ74IFszwtNVAHVQ==", + "dev": true + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "nyc": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-14.1.1.tgz", + "integrity": "sha512-OI0vm6ZGUnoGZv/tLdZ2esSVzDwUC88SNs+6JoSOMVxA+gKMB8Tk7jBwgemLx4O40lhhvZCVw1C+OYLOBOPXWw==", + "dev": true, + "requires": { + "archy": "^1.0.0", + "caching-transform": "^3.0.2", + "convert-source-map": "^1.6.0", + "cp-file": "^6.2.0", + "find-cache-dir": "^2.1.0", + "find-up": "^3.0.0", + "foreground-child": "^1.5.6", + "glob": "^7.1.3", + "istanbul-lib-coverage": "^2.0.5", + "istanbul-lib-hook": "^2.0.7", + "istanbul-lib-instrument": "^3.3.0", + "istanbul-lib-report": "^2.0.8", + "istanbul-lib-source-maps": "^3.0.6", + "istanbul-reports": "^2.2.4", + "js-yaml": "^3.13.1", + "make-dir": "^2.1.0", + "merge-source-map": "^1.1.0", + "resolve-from": "^4.0.0", + "rimraf": "^2.6.3", + "signal-exit": "^3.0.2", + "spawn-wrap": "^1.4.2", + "test-exclude": "^5.2.3", + "uuid": "^3.3.2", + "yargs": "^13.2.2", + "yargs-parser": "^13.0.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "p-limit": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.entries": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz", + "integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "object.values": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", + "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "observable-to-promise": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/observable-to-promise/-/observable-to-promise-1.0.0.tgz", + "integrity": "sha512-cqnGUrNsE6vdVDTPAX9/WeVzwy/z37vdxupdQXU8vgTXRFH72KCZiZga8aca2ulRPIeem8W3vW9rQHBwfIl2WA==", + "dev": true, + "requires": { + "is-observable": "^2.0.0", + "symbol-observable": "^1.0.4" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + } + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + } + }, + "ora": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-3.4.0.tgz", + "integrity": "sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-spinners": "^2.0.0", + "log-symbols": "^2.2.0", + "strip-ansi": "^5.2.0", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + } + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "package-hash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "hasha": "^5.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + } + }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, + "requires": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "parse-ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", + "integrity": "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "picomatch": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.0.7.tgz", + "integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "pkg-conf": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-3.1.0.tgz", + "integrity": "sha512-m0OTbR/5VPNPqO1ph6Fqbj7Hv6QU7gR/tQW40ZqrL1rjgCU85W6C1bJn0BItuJqnR98PWzw7Z8hHeChD1WrgdQ==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "load-json-file": "^5.2.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "load-json-file": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz", + "integrity": "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "parse-json": "^4.0.0", + "pify": "^4.0.1", + "strip-bom": "^3.0.0", + "type-fest": "^0.3.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "type-fest": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "dev": true + } + } + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "plur": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/plur/-/plur-3.1.1.tgz", + "integrity": "sha512-t1Ax8KUvV3FFII8ltczPn2tJdjqbd1sIzu6t4JL7nQ3EyeL/lTrj5PWKb06ic5/6XYDr65rQ4uzQEGN70/6X5w==", + "dev": true, + "requires": { + "irregular-plurals": "^2.0.0" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + }, + "pretty-ms": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-5.0.0.tgz", + "integrity": "sha512-94VRYjL9k33RzfKiGokPBPpsmloBYSf5Ri+Pq19zlsEcUKFob+admeXr5eFDRuPjFmEOcjJvPGdillYOJyvZ7Q==", + "dev": true, + "requires": { + "parse-ms": "^2.1.0" + } + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "quick-lru": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz", + "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=", + "dev": true + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + }, + "readdirp": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.1.2.tgz", + "integrity": "sha512-8rhl0xs2cxfVsqzreYCvs8EwBfn/DhVdqtoLmw19uI3SC5avYX9teCurlErfpPXGmYtMHReGaP2RsLnFvz/lnw==", + "dev": true, + "requires": { + "picomatch": "^2.0.4" + } + }, + "redent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-2.0.0.tgz", + "integrity": "sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=", + "dev": true, + "requires": { + "indent-string": "^3.0.0", + "strip-indent": "^2.0.0" + }, + "dependencies": { + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + } + } + }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz", + "integrity": "sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==", + "dev": true, + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + }, + "regenerator-transform": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", + "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", + "dev": true, + "requires": { + "babel-runtime": "^6.18.0", + "babel-types": "^6.19.0", + "private": "^0.1.6" + } + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, + "regexpu-core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", + "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", + "dev": true, + "requires": { + "regenerate": "^1.2.1", + "regjsgen": "^0.2.0", + "regjsparser": "^0.1.4" + } + }, + "registry-auth-token": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.0.0.tgz", + "integrity": "sha512-lpQkHxd9UL6tb3k/aHAVfnVtn+Bcs9ob5InuFLLEDqSqeq+AljB8GZW9xY0x7F+xYwEcjKe07nyoxzEYz6yvkw==", + "dev": true, + "requires": { + "rc": "^1.2.8", + "safe-buffer": "^5.0.1" + } + }, + "registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", + "dev": true + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + } + }, + "release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", + "dev": true, + "requires": { + "es6-error": "^4.0.1" + } + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "^1.0.0" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "require-precompiled": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/require-precompiled/-/require-precompiled-0.1.0.tgz", + "integrity": "sha1-WhtS63Dr7UPrmC6XTIWrWVceVvo=", + "dev": true + }, + "resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "rollup": { + "version": "1.19.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.19.4.tgz", + "integrity": "sha512-G24w409GNj7i/Yam2cQla6qV2k6Nug8bD2DZg9v63QX/cH/dEdbNJg8H4lUm5M1bRpPKRUC465Rm9H51JTKOfQ==", + "dev": true, + "requires": { + "@types/estree": "0.0.39", + "@types/node": "^12.6.9", + "acorn": "^6.2.1" + }, + "dependencies": { + "acorn": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", + "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==", + "dev": true + } + } + }, + "rollup-plugin-babel": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-4.3.3.tgz", + "integrity": "sha512-tKzWOCmIJD/6aKNz0H1GMM+lW1q9KyFubbWzGiOG540zxPPifnEAHTZwjo0g991Y+DyOZcLqBgqOdqazYE5fkw==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "rollup-pluginutils": "^2.8.1" + } + }, + "rollup-plugin-babel-minify": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-babel-minify/-/rollup-plugin-babel-minify-9.0.0.tgz", + "integrity": "sha512-5aJVWpuoZUbQrIaRF7Jvjo7bBnYqaChOhrhsGtz72wJ3lyo7ygIL85hsuPkvrk/3Fj5AUlNZV3IaSZ98fHyoTw==", + "dev": true, + "requires": { + "@babel/core": "^7.4.5", + "@babel/plugin-syntax-dynamic-import": "^7.2.0", + "@comandeer/babel-plugin-banner": "^5.0.0", + "babel-preset-minify": "^0.5.0", + "sourcemap-codec": "^1.4.4" + } + }, + "rollup-plugin-commonjs": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.0.2.tgz", + "integrity": "sha512-DxeR4QXTgTOFseYls1V7vgKbrSJmPYNdEMOs0OvH+7+89C3GiIonU9gFrE0u39Vv1KWm3wepq8KAvKugtoM2Zw==", + "requires": { + "estree-walker": "^0.6.1", + "is-reference": "^1.1.2", + "magic-string": "^0.25.2", + "resolve": "^1.11.0", + "rollup-pluginutils": "^2.8.1" + } + }, + "rollup-plugin-node-resolve": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz", + "integrity": "sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==", + "dev": true, + "requires": { + "@types/resolve": "0.0.8", + "builtin-modules": "^3.1.0", + "is-module": "^1.0.0", + "resolve": "^1.11.1", + "rollup-pluginutils": "^2.8.1" + } + }, + "rollup-pluginutils": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.1.tgz", + "integrity": "sha512-J5oAoysWar6GuZo0s+3bZ6sVZAC0pfqKz68De7ZgDi5z63jOVZn1uJL/+z1jeKHNbGII8kAyHF5q8LnxSX5lQg==", + "requires": { + "estree-walker": "^0.6.1" + } + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, + "run-parallel": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", + "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", + "dev": true + }, + "rxjs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", + "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "semver-diff": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", + "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", + "dev": true, + "requires": { + "semver": "^5.0.3" + } + }, + "serialize-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", + "integrity": "sha1-ULZ51WNc34Rme9yOWa9OW4HV9go=", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + } + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "requires": { + "source-map": "^0.5.6" + } + }, + "sourcemap-codec": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.6.tgz", + "integrity": "sha512-1ZooVLYFxC448piVLBbtOxFcXwnymH9oUF8nRd3CuYDVvkRBxRl6pB4Mtas5a4drtL+E8LDgFkQNcgIw6tc8Hg==" + }, + "spawn-wrap": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.2.tgz", + "integrity": "sha512-vMwR3OmmDhnxCVxM8M+xO/FtIp6Ju/mNaDfCMMW7FDcLRTPFWUswec4LXJHTJE2hwTI9O0YBfygu4DalFl7Ylg==", + "dev": true, + "requires": { + "foreground-child": "^1.5.6", + "mkdirp": "^0.5.0", + "os-homedir": "^1.0.1", + "rimraf": "^2.6.2", + "signal-exit": "^3.0.2", + "which": "^1.3.0" + } + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "stack-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", + "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", + "dev": true + }, + "string-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.1.0.tgz", + "integrity": "sha512-NrX+1dVVh+6Y9dnQ19pR0pP4FiEIlUvdTGn8pw6CKTNq5sgib2nIhmUNT5TAmhWmvKr3WcxBcP3E8nWezuipuQ==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^5.2.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + } + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-bom-buf": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-buf/-/strip-bom-buf-2.0.0.tgz", + "integrity": "sha512-gLFNHucd6gzb8jMsl5QmZ3QgnUJmp7qn4uUSHNwEXumAp7YizoGYw19ZUVfuq4aBOQUtyn2k8X/CwzWB73W2lQ==", + "dev": true, + "requires": { + "is-utf8": "^0.2.1" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supertap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supertap/-/supertap-1.0.0.tgz", + "integrity": "sha512-HZJ3geIMPgVwKk2VsmO5YHqnnJYl6bV5A9JW2uzqV43WmpgliNEYbuvukfor7URpaqpxuw3CfZ3ONdVbZjCgIA==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "indent-string": "^3.2.0", + "js-yaml": "^3.10.0", + "serialize-error": "^2.1.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "supports-color": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.0.0.tgz", + "integrity": "sha512-WRt32iTpYEZWYOpcetGm0NPeSvaebccx7hhS/5M6sAiqnhedtFCHFxkjzZlJvFNCPowiKSFGiZk5USQDFy83vQ==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + } + } + }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", + "dev": true + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "tailored": { + "version": "2.7.5", + "resolved": "https://registry.npmjs.org/tailored/-/tailored-2.7.5.tgz", + "integrity": "sha512-5zLODXUWx3P8SPVbFA9RgaUrpTGJMXg67jMaZJmJJwE9jQXuCfJb7bnO/1FuTsrFFZTDDmkYR/PPz9gAN26CmQ==", + "requires": { + "erlang-types": "^1.0.1" + } + }, + "term-size": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", + "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", + "dev": true, + "requires": { + "execa": "^0.7.0" + } + }, + "test-exclude": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", + "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", + "dev": true, + "requires": { + "glob": "^7.1.3", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^2.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" + } + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "time-zone": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-1.0.0.tgz", + "integrity": "sha1-mcW/VZWJZq9tBtg73zgA3IL67F0=", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "trim-newlines": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-2.0.0.tgz", + "integrity": "sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA=", + "dev": true + }, + "trim-off-newlines": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz", + "integrity": "sha1-n5up2e+odkw4dpi8v+sshI8RrbM=", + "dev": true + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-fest": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.5.2.tgz", + "integrity": "sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==", + "dev": true + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "uglify-js": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", + "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", + "dev": true, + "optional": true, + "requires": { + "commander": "~2.20.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } + } + }, + "uid2": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz", + "integrity": "sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I=", + "dev": true + }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz", + "integrity": "sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz", + "integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==", + "dev": true + }, + "unique-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", + "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "dev": true, + "requires": { + "crypto-random-string": "^1.0.0" + } + }, + "unique-temp-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unique-temp-dir/-/unique-temp-dir-1.0.0.tgz", + "integrity": "sha1-bc6VsmgcoAPuv7MEpBX5y6vMU4U=", + "dev": true, + "requires": { + "mkdirp": "^0.5.1", + "os-tmpdir": "^1.0.1", + "uid2": "0.0.3" + } + }, + "update-notifier": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-3.0.1.tgz", + "integrity": "sha512-grrmrB6Zb8DUiyDIaeRTBCkgISYUgETNe7NglEbVsrLWXeESnlCSP50WfRSj/GmzMPl6Uchj24S/p80nP/ZQrQ==", + "dev": true, + "requires": { + "boxen": "^3.0.0", + "chalk": "^2.0.1", + "configstore": "^4.0.0", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.1.0", + "is-npm": "^3.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "requires": { + "prepend-http": "^2.0.0" + } + }, + "uuid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", + "dev": true + }, + "v8-compile-cache": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", + "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "well-known-symbols": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/well-known-symbols/-/well-known-symbols-2.0.0.tgz", + "integrity": "sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "widest-line": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", + "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", + "dev": true, + "requires": { + "string-width": "^2.1.1" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "write-file-atomic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.0.tgz", + "integrity": "sha512-EIgkf60l2oWsffja2Sf2AL384dx328c0B+cIYPTQq5q2rOYuDV00/iPFBOUiDKKwKMOhkymH8AidPaRvzfxY+Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "xdg-basedir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", + "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yargs": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.1" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "yargs-parser": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", + "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + } + } +} diff --git a/package.json b/package.json index efbbd8d5..3acb3b42 100644 --- a/package.json +++ b/package.json @@ -1,17 +1,20 @@ { "name": "elixirscript", - "version": "0.25.0", + "version": "0.26.1", "description": "Convert Elixir to JavaScript", "main": "elixir.js", "bin": { "elixirscript": "./elixirscript" }, + "engines": { + "node": ">=7.1" + }, "scripts": { "lint": "eslint src/javascript/lib/**/*.js src/javascript/tests/**/*.js", "lint:fix": "eslint src/javascript/lib/**/*.js src/javascript/tests/**/*.js --fix", - "build": "rollup -c rollup.config.js", - "clean": "rm -rf priv", - "test": "mocha src/javascript/tests --recursive --compilers js:babel-core/register" + "build": "node rollup.config.js", + "clean": "rm -rf priv/build", + "test": "nyc ava src/javascript/tests" }, "repository": { "type": "git", @@ -20,28 +23,35 @@ "author": "", "license": "MIT", "dependencies": { - "erlang-types": "^1.0.0", - "tailored": "2.3.2" + "erlang-types": "^1.0.1", + "grapheme-splitter": "^1.0.2", + "rollup-plugin-commonjs": "^10.0.2", + "tailored": "^2.7.4" }, "devDependencies": { - "babel": "^6.5.2", - "babel-core": "^6.7.7", - "babel-plugin-transform-class-properties": "^6.9.1", - "babel-preset-es2015": "^6.6.0", - "babel-preset-es2015-rollup": "^1.1.1", - "babel-preset-react": "^6.5.0", - "babel-preset-stage-0": "^6.5.0", - "chai": "^3.5.0", - "eslint": "^3.15.0", - "eslint-config-airbnb-base": "^11.1.0", - "eslint-plugin-import": "^2.2.0", - "gulp": "^3.9.1", - "gulp-babel": "^6.1.2", - "gulp-sourcemaps": "^2.0.0-alpha", - "mocha": "^2.4.5", - "rollup": "^0.41.4", - "rollup-plugin-babel": "^2.7.1", - "rollup-plugin-node-resolve": "^2.0.0", - "rollup-plugin-uglify": "^1.0.1" + "@std/esm": "^0.8.3", + "ava": "^2.3.0", + "babel-core": "^6.26.0", + "babel-preset-env": "^1.6.0", + "babel-register": "^6.26.0", + "eslint": "^6.2.1", + "eslint-config-airbnb-base": "^14.0.0", + "eslint-plugin-import": "^2.7.0", + "nyc": "^14.1.1", + "rollup": "^1.19.4", + "rollup-plugin-babel": "^4.3.3", + "rollup-plugin-babel-minify": "^9.0.0", + "rollup-plugin-node-resolve": "^5.2.0" + }, + "ava": { + "require": [ + "babel-register" + ], + "babel": { + "babelrc": true + } + }, + "@std/esm": { + "esm": "js" } } diff --git a/priv/std_lib/agent.ex b/priv/std_lib/agent.ex deleted file mode 100644 index 6000058f..00000000 --- a/priv/std_lib/agent.ex +++ /dev/null @@ -1,54 +0,0 @@ -defmodule ElixirScript.Agent do - @moduledoc false - require JS - - def start(fun, options \\ []) do - pid = JS.new Bootstrap.Core.PID, [] - - name = if Elixir.Keyword.has_key?(options, :name) do - Elixir.Keyword.get(options, :name) - else - nil - end - - Bootstrap.Core.Store.create(pid, fun.(), name) - { :ok, pid } - end - - def start_link(fun, options \\ []) do - pid = JS.new Bootstrap.Core.PID, [] - - name = if Elixir.Keyword.has_key?(options, :name) do - Elixir.Keyword.get(options, :name) - else - nil - end - - Bootstrap.Core.Store.create(pid, fun.(), name) - { :ok, pid } - end - - def stop(agent) do - Bootstrap.Core.Store.remove(agent) - :ok - end - - def update(agent, fun) do - current_state = Bootstrap.Core.Store.read(agent) - Bootstrap.Core.Store.update(agent, fun.(current_state)) - :ok - end - - def get(agent, fun) do - current_state = Bootstrap.Core.Store.read(agent) - fun.(current_state) - end - - def get_and_update(agent, fun) do - current_state = Bootstrap.Core.Store.read(agent) - {val, new_state} = fun.(current_state) - Bootstrap.Core.Store.update(agent, new_state) - val - end - -end diff --git a/priv/std_lib/atom.ex b/priv/std_lib/atom.ex deleted file mode 100644 index f932c1d2..00000000 --- a/priv/std_lib/atom.ex +++ /dev/null @@ -1,13 +0,0 @@ -defmodule ElixirScript.Atom do - @moduledoc false - import Kernel, except: [to_string: 1] - - def to_char_list(atom) do - to_string(atom).split("") - end - - def to_string(atom) do - Symbol.keyFor(atom) - end - -end diff --git a/priv/std_lib/base.ex b/priv/std_lib/base.ex deleted file mode 100644 index 3e02779f..00000000 --- a/priv/std_lib/base.ex +++ /dev/null @@ -1,20 +0,0 @@ -defmodule ElixirScript.Base do - @moduledoc false - - def encode64(data) do - Bootstrap.Core.b64EncodeUnicode(data) - end - - def decode64(data) do - if Bootstrap.Core.can_decode64(data) do - {:ok, decode64!(data) } - else - :error - end - end - - def decode64!(data) do - Bootstrap.Core.get_global().atob(data) - end - -end diff --git a/priv/std_lib/bitwise.ex b/priv/std_lib/bitwise.ex deleted file mode 100644 index 83d5e1d4..00000000 --- a/priv/std_lib/bitwise.ex +++ /dev/null @@ -1,74 +0,0 @@ -defmodule ElixirScript.Bitwise do - @moduledoc false - defmacro bnot(expr) do - quote do - Bootstrap.Core.bnot(unquote(expr)) - end - end - - defmacro ~~~(expr) do - quote do - Bootstrap.Core.bnot(unquote(expr)) - end - end - - defmacro band(left, right) do - quote do - Bootstrap.Core.band(unquote(left), unquote(right)) - end - end - - defmacro left &&& right do - quote do - Bootstrap.Core.band(unquote(left), unquote(right)) - end - end - - defmacro bor(left, right) do - quote do - Bootstrap.Core.bor(unquote(left), unquote(right)) - end - end - - defmacro left ||| right do - quote do - Bootstrap.Core.bor(unquote(left), unquote(right)) - end - end - - defmacro bxor(left, right) do - quote do - Bootstrap.Core.bxor(unquote(left), unquote(right)) - end - end - - defmacro left ^^^ right do - quote do - Bootstrap.Core.bxor(unquote(left), unquote(right)) - end - end - - defmacro bsl(left, right) do - quote do - Bootstrap.Core.bsl(unquote(left), unquote(right)) - end - end - - defmacro left <<< right do - quote do - Bootstrap.Core.bsl(unquote(left), unquote(right)) - end - end - - defmacro bsr(left, right) do - quote do - Bootstrap.Core.bsr(unquote(left), unquote(right)) - end - end - - defmacro left >>> right do - quote do - Bootstrap.Core.bsr(unquote(left), unquote(right)) - end - end -end diff --git a/priv/std_lib/collectable.ex b/priv/std_lib/collectable.ex deleted file mode 100644 index 6950b962..00000000 --- a/priv/std_lib/collectable.ex +++ /dev/null @@ -1,34 +0,0 @@ -defprotocol ElixirScript.Collectable do - @moduledoc false - def into(collectable) -end - -defimpl ElixirScript.Collectable, for: List do - def into(original) do - {[], fn - list, {:cont, x} -> list ++ [x] - list, :done -> original ++ list - _, :halt -> :ok - end} - end -end - -defimpl ElixirScript.Collectable, for: BitString do - def into(original) do - {original, fn - acc, {:cont, x} when is_bitstring(x) -> <> - acc, :done -> acc - _, :halt -> :ok - end} - end -end - -defimpl ElixirScript.Collectable, for: Map do - def into(original) do - {original, fn - map, {:cont, {k, v}} -> Map.put(map, k, v) - map, :done -> map - _, :halt -> :ok - end} - end -end \ No newline at end of file diff --git a/priv/std_lib/enumerable.ex b/priv/std_lib/enumerable.ex deleted file mode 100644 index 0b6d4928..00000000 --- a/priv/std_lib/enumerable.ex +++ /dev/null @@ -1,42 +0,0 @@ -defprotocol ElixirScript.Enumerable do - @moduledoc false - def reduce(enumerable, acc, fun) - def member?(enumerable, element) - def count(enumerable) -end - -defimpl ElixirScript.Enumerable, for: List do - def count(list), - do: length(list) - - def member?(list, value), - do: value in list - - def reduce(_, {:halt, acc}, _fun), do: {:halted, acc} - def reduce(list, {:suspend, acc}, fun), do: {:suspended, acc, &reduce(list, &1, fun)} - def reduce([], {:cont, acc}, _fun), do: {:done, acc} - def reduce([h | t], {:cont, acc}, fun), do: reduce(t, fun.(h, acc), fun) -end - -defimpl ElixirScript.Enumerable, for: Map do - def count(map) do - {:ok, map_size(map)} - end - - def member?(map, {key, value}) do - {:ok, match?(^value, Map.get(map, key))} - end - - def member?(_, _) do - {:ok, false} - end - - def reduce(map, acc, fun) do - do_reduce(Map.to_list(map), acc, fun) - end - - defp do_reduce(_, {:halt, acc}, _fun), do: {:halted, acc} - defp do_reduce(list, {:suspend, acc}, fun), do: {:suspended, acc, &do_reduce(list, &1, fun)} - defp do_reduce([], {:cont, acc}, _fun), do: {:done, acc} - defp do_reduce([h | t], {:cont, acc}, fun), do: do_reduce(t, fun.(h, acc), fun) -end diff --git a/priv/std_lib/integer.ex b/priv/std_lib/integer.ex deleted file mode 100644 index abfee5a2..00000000 --- a/priv/std_lib/integer.ex +++ /dev/null @@ -1,33 +0,0 @@ -defmodule ElixirScript.Integer do - @moduledoc false - def is_even(number) do - rem(number, 2) == 0 - end - - def is_odd(number) do - rem(number, 2) != 0 - end - - def to_char_list(number) do - to_char_list(number, 10) - end - - def to_char_list(number, base) do - number.toString(base).split('') - end - - def parse(bin) do - result = Bootstrap.Core.Functions.get_global().parseInt(bin) - - if Bootstrap.Core.Functions.get_global().isNaN(result) do - :error - else - case bin.indexOf(".") do - index_of_dot when index_of_dot < 0 -> - {result, ""} - index_of_dot -> - {result, bin.substring(index_of_dot)} - end - end - end -end diff --git a/priv/std_lib/js.ex b/priv/std_lib/js.ex deleted file mode 100644 index c1f44142..00000000 --- a/priv/std_lib/js.ex +++ /dev/null @@ -1,99 +0,0 @@ -defmodule JS do - @moduledoc """ - This module defines macros and functions which implement - JavaScript functionality that may not translate easily to - Elixir. For instance, creating a new object, or updating - an existing one. - """ - - @doc """ - Creates new JavaScript objects. - - ex: - JS.new User, ["first_name", "last_name"] - """ - defmacro new(module, params) - - @doc """ - Updates an existing JavaScript object. - - ex: - JS.update elem, %{"width" => 100} - """ - defmacro update(object, map) - - @doc """ - Returns the type of the given value - """ - defmacro typeof(value) - - @doc """ - Determines if value is an instance of type. - """ - defmacro instanceof(value, type) - - @doc """ - Throws the term given - """ - defmacro throw(term) - - @doc """ - Returns a reference to the global JavaScript object. - - In browsers this would be window or self. - In node this would be the global object. - """ - def global() do - Bootstrap.Core.Functions.get_global() - end - - @doc """ - Defines a generator. This is compiled into a generator function in JavaScript. - defgen and defgenp are currently the only ways to use process in Elixirscript right now. - """ - defmacro defgen(call, expr \\ nil) do - quote do - def unquote(call), unquote(expr) - end - end - - @doc """ - Defines a private generator. This is compiled into a generator function in JavaScript. - """ - defmacro defgenp(call, expr \\ nil) do - quote do - defp unquote(call), unquote(expr) - end - end - - @doc """ - Determines if term is a generator - """ - def is_generator(term) do - term.constructor.name === "GeneratorFunction" - end - - @doc """ - Yields the current generator function - """ - defmacro yield() - - @doc """ - Yields the current generator function with the given term - """ - defmacro yield(term) - - @doc """ - Yields control to the given generator - """ - defmacro yield_to(gen) - - @doc """ - Provides a convenient way to create a string-based map. - - Elixirscript, by default turns the following, `%{a: "b"}` into `{[Symbol.for("a")]: "b"}` in JavaScript. In order to get string keys, - one would have to do `%{"a" => "b"}` which turns into `{a: "b"}` in JavaScript. With `Kernel.object`, you can create string keyed maps - conveniently, `object(a: "b")` which turns into `{a: "b"}` - """ - defmacro object(args) -end diff --git a/priv/std_lib/kernel.ex b/priv/std_lib/kernel.ex deleted file mode 100644 index 33ad1b81..00000000 --- a/priv/std_lib/kernel.ex +++ /dev/null @@ -1,205 +0,0 @@ -defmodule ElixirScript.Kernel do - @moduledoc false - import Kernel, only: [defmodule: 2, def: 1, def: 2, defp: 2, - defmacro: 1, defmacro: 2, defmacrop: 2, ||: 2, !: 1, - ++: 2, in: 2, &&: 2, ===: 2, @: 1, sigil_r: 2] - require JS - - - defmacro if(condition, clauses) do - build_if(condition, clauses) - end - - defp build_if(condition, do: do_clause) do - build_if(condition, do: do_clause, else: nil) - end - - defp build_if(condition, do: do_clause, else: else_clause) do - quote do - case unquote(condition) do - x when x in [false, nil] -> - unquote(else_clause) - _ -> - unquote(do_clause) - end - end - end - - defmacro unless(condition, clauses) do - build_unless(condition, clauses) - end - - defp build_unless(condition, do: do_clause) do - build_unless(condition, do: do_clause, else: nil) - end - - defp build_unless(condition, do: do_clause, else: else_clause) do - quote do - if(unquote(condition), do: unquote(else_clause), else: unquote(do_clause)) - end - end - - def abs(number) do - Math.abs(number) - end - - def apply(fun, args) do - Bootstrap.Core.Functions.apply(fun, args) - end - - def apply(module, fun, args) do - Bootstrap.Core.Functions.apply(module, Atom.to_string(fun), args) - end - - def binary_part(binary, start, len) do - binary.substring(start, len) - end - - def hd(list) do - list[0] - end - - def tl(list) do - list.slice(1) - end - - def is_atom(term) do - JS.typeof(term) === "symbol" - end - - def is_binary(term) do - JS.typeof(term) === "string" - end - - def is_bitstring(term) do - is_binary(term) || JS.instanceof(term, Bootstrap.Core.BitString) - end - - def is_boolean(term) do - JS.typeof(term) === "boolean" || JS.instanceof(term, Boolean) - end - - def is_float(term) do - is_number(term) && !Number.isInteger(term) - end - - def is_function(term) do - is_function(term, 0) - end - - def is_function(term, _) do - JS.typeof(term) === "function" || JS.instanceof(term, Function) - end - - def is_integer(term) do - Number.isInteger(term) - end - - def is_list(term) do - Array.isArray(term) - end - - def is_number(term) do - JS.typeof(term) === "number" || JS.instanceof(term, Number) - end - - def is_pid(term) do - JS.instanceof(term, Bootstrap.Core.PID) - end - - def is_tuple(term) do - JS.instanceof(term, Bootstrap.Core.Tuple) - end - - def is_map(term) do - JS.typeof(term) === "object" || JS.instanceof(term, Object) - end - - def is_port(_) do - false - end - - def is_reference(_) do - false - end - - def length(term) do - term.length - end - - def map_size(term) do - Object.keys(term).length - end - - def max(first, second) do - Math.max(first, second) - end - - def min(first, second) do - Math.min(first, second) - end - - def round(number) do - Math.round(number) - end - - def trunc(number) do - Math.floor(number) - end - - def tuple_size(tuple) do - Bootstrap.Core.Functions.size(tuple) - end - - def elem(tuple, index) do - Bootstrap.Core.Functions.apply(tuple, "get", [index]) - end - - def is_nil(term) do - term === nil - end - - defmacro sigil_r({:<<>>, _meta, [string]}, options) do - str_options = List.to_string(options) - quote do - Regex.compile!(unquote(string), unquote(str_options)) - end - end - - defmacro match?(left, right) do - quote do - case unquote(right) do - unquote(left) -> - true - _ -> - false - end - end - end - - defmacro to_string(arg) when Kernel.is_binary(arg) do - arg - end - - defmacro to_string(arg) do - quote do - String.Chars.to_string(unquote(arg)) - end - end - - defmacro left |> {fun, context, params} do - {fun, context, [left] ++ params } - end - - defmacro left in right do - quote do - Bootstrap.Core.Functions.contains(unquote(left), unquote(right)) - end - end - - defmacro first .. last do - quote do - %ElixirScript.Range{ first: unquote(first), last: unquote(last) } - end - end -end diff --git a/priv/std_lib/keyword.ex b/priv/std_lib/keyword.ex deleted file mode 100644 index c08c71b1..00000000 --- a/priv/std_lib/keyword.ex +++ /dev/null @@ -1,42 +0,0 @@ -defmodule ElixirScript.Keyword do - @moduledoc false - - def has_key?(kw, key) do - do_has_key?(kw, key) - end - - defp do_has_key?([], _) do - false - end - - defp do_has_key?(kw, key) do - case hd(kw) do - {the_key, _} when the_key == key -> - true - _ -> - do_has_key?(tl(kw), key) - end - end - - def get(kw, key) do - get(kw, key, nil) - end - - def get(kw, key, default_value) do - case has_key?(kw, key) do - true -> - do_get(kw, key) - false -> - default_value - end - end - - defp do_get(kw, key) do - case hd(kw) do - { kw_key, value } when kw_key == key -> - value - _ -> - do_get(tl(kw), key) - end - end -end diff --git a/priv/std_lib/list.ex b/priv/std_lib/list.ex deleted file mode 100644 index db553ae6..00000000 --- a/priv/std_lib/list.ex +++ /dev/null @@ -1,252 +0,0 @@ -defmodule ElixirScript.List do - @moduledoc false - require JS - - def duplicate(data, size) do - do_duplicate(data, size, []) - end - - defp do_duplicate(_, 0, list) do - list - end - - defp do_duplicate(data, size, list) do - do_duplicate(data, size - 1, list ++ [data]) - end - - def to_tuple(list) do - JS.new(Bootstrap.Core.Tuple, list) - end - - def wrap(list) when is_list(list), do: list - def wrap(nil), do: [] - def wrap(term), do: [term] - - def append(list, term) do - concat(list, [term]) - end - - def prepend(list, term) do - concat([term], list) - end - - def concat(list_a, list_b) do - list_a.concat(list_b) - end - - def first(list) do - list[0] - end - - def last(list) do - list[length(list) - 1] - end - - def delete(list, item) do - do_delete(list, item, 0, []) - end - - defp do_delete(list, item, current_index, new_list) do - if current_index == length(list) do - new_list - else - updated = case list[current_index] do - ^item -> - new_list - _ -> - new_list ++ [list[current_index]] - end - - do_delete(list, item, current_index + 1, updated) - end - end - - def delete_at(list, index) do - do_delete_at(list, index, 0, []) - end - - defp do_delete_at(list, index, current_index, new_list) do - if current_index == length(list) do - new_list - else - updated = case current_index == index do - true -> - new_list - _ -> - new_list ++ [list[current_index]] - end - - do_delete_at(list, index, current_index + 1, updated) - end - end - - def insert_at(list, index, value) do - do_insert_at(list, index, value, 0, []) - end - - defp do_insert_at(list, index, value, current_index, new_list) do - if current_index == length(list) do - new_list - else - updated = case current_index == index do - true -> - new_list ++ [value, list[current_index]] - _ -> - new_list ++ [list[current_index]] - end - - do_insert_at(list, index, value, current_index + 1, updated) - end - end - - def replace_at(list, index, value) do - do_replace_at(list, index, value, 0, []) - end - - defp do_replace_at(list, index, value, current_index, new_list) do - if current_index == length(list) do - new_list - else - updated = case current_index == index do - true -> - new_list ++ [value] - _ -> - new_list ++ [list[current_index]] - end - - do_replace_at(list, index, value, current_index + 1, updated) - end - end - - - def update_at(list, index, func) do - do_update_at(list, index, func, 0, []) - end - - defp do_update_at(list, index, func, current_index, new_list) do - if current_index == length(list) do - new_list - else - updated = case current_index == index do - true -> - new_list ++ [func.(list[current_index])] - _ -> - new_list ++ [list[current_index]] - end - - do_update_at(list, index, func, current_index + 1, updated) - end - end - - - def foldl(list, acc, func) do - do_foldl(list, acc, func, []) - end - - def foldr(list, acc, func) do - do_foldl(list.concat([]).reverse(), acc, func, []) - end - - defp do_foldl([], acc, _, new_list) do - { acc, new_list } - end - - defp do_foldl(list, acc, func, new_list) do - { acc, value } = func.(hd(list), acc) - do_foldl(tl(list), acc, func, new_list ++ [value]) - end - - def flatten(list) do - do_flatten(list, []) - end - - def flatten(list, tail) do - do_flatten(list, []) ++ tail - end - - defp do_flatten([], flattened_list) do - flattened_list - end - - defp do_flatten(list, flattened_list) do - updated = case hd(list) do - l when is_list(l) -> - flattened_list ++ do_flatten(l, []) - item -> - flattened_list ++ [item] - end - - do_flatten(tl(list), updated) - end - - - def keydelete(list, key, position) do - do_keydelete(list, key, position, []) - end - - defp do_keydelete([], _, _, new_list) do - new_list - end - - defp do_keydelete(list, key, position, new_list) do - current_value = hd(list) - - updated = if elem(current_value, position) == key do - new_list - else - new_list ++ [current_value] - end - - do_keydelete(tl(list), key, position, updated) - end - - def keyfind(list, key, position) do - do_keyfind(list, key, position, nil) - end - - def keyfind(list, key, position, default) do - do_keyfind(list, key, position, default) - end - - defp do_keyfind([], _, _, default) do - default - end - - defp do_keyfind(list, key, position, default) do - current_value = hd(list) - - if elem(current_value, position) == key do - current_value - else - do_keyfind(tl(list), key, position, default) - end - end - - def keymember?(list, key, position) do - keyfind(list, key, position) != nil - end - - def keyreplace(list, key, position, new_tuple) do - do_keyreplace(list, key, position, [], new_tuple) - end - - defp do_keyreplace([], _, _, new_list, _) do - new_list - end - - defp do_keyreplace(list, key, position, new_list, new_tuple) do - current_value = hd(list) - - updated = if elem(current_value, position) == key do - new_list ++ [new_tuple] - else - new_list ++ [current_value] - end - - do_keyreplace(tl(list), key, position, updated, new_tuple) - end - - def zip(list_of_lists) do - Bootstrap.Core.Functions.zip(list_of_lists) - end -end diff --git a/priv/std_lib/macro/env.ex b/priv/std_lib/macro/env.ex deleted file mode 100644 index 1528e2c8..00000000 --- a/priv/std_lib/macro/env.ex +++ /dev/null @@ -1,37 +0,0 @@ -defmodule ElixirScript.Macro.Env do - @moduledoc false - - @type t :: %ElixirScript.Macro.Env{ - module: atom, - file: binary, - line: non_neg_integer, - function: { atom, non_neg_integer } | nil, - context: :match | :guard | :generator | nil, - aliases: [{atom, atom}], - requires: [atom], - functions: [{atom, [{ atom, non_neg_integer }]}], - macros: [{atom, [{ atom, non_neg_integer }]}], - macro_aliases: [{atom, {integer, atom}}], - context_modules: [atom], - vars: [{atom, atom | non_neg_integer}], - export_vars: [{atom, atom | non_neg_integer}] | nil, - lexical_tracker: nil - } - - defstruct [ - module: nil, - file: nil, - line: 0, - function: nil, - context: nil, - aliases: [], - requires: [], - functions: [], - macros: [], - macro_aliases: [], - context_modules: [], - vars: [], - export_vars: nil, - lexical_tracker: nil - ] -end diff --git a/priv/std_lib/map.ex b/priv/std_lib/map.ex deleted file mode 100644 index e2f3b46e..00000000 --- a/priv/std_lib/map.ex +++ /dev/null @@ -1,203 +0,0 @@ -defmodule ElixirScript.Map do - @moduledoc false - - def new() do - %{} - end - - def keys(map) do - Bootstrap.Core.Functions.get_object_keys(map) - end - - def size(map) do - keys(map).length - end - - def to_list(map) do - do_to_list(map, []) - end - - def do_to_list(map, list) do - case size(map) do - 0 -> - list - _ -> - key = hd(keys(map)) - value = map[key] - do_to_list(Map.delete(map, key), list ++ [{key, value}]) - end - end - - def values(map) do - Object.values(map) - end - - def from_struct(struct) do - struct - |> Bootstrap.Core.Functions.class_to_obj - |> delete(:__struct__) - end - - def delete(map, key) do - map - |> Bootstrap.Core.Functions.delete_property_from_map(key) - end - - def equal?(map1, map2) do - map1 === map2 - end - - def fetch!(map, key) do - case key in keys(map) do - true -> - map[key] - false -> - raise "#{key} not found in map" - end - end - - def fetch(map, key) do - case key in keys(map) do - true -> - { :ok, map[key] } - false -> - :error - end - end - - def has_key?(map, key) do - key in keys(map) - end - - def merge(map1, map2) do - Bootstrap.Core.SpecialForms.map_update(map1, map2) - end - - def split(map, keys) do - do_split(map, keys, { %{}, %{} }) - end - - defp do_split(_, [], split_tuple) do - split_tuple - end - - defp do_split(map, keys, { key_map, non_key_map }) do - key = hd(keys) - - new_split_tuple = case key in keys(map) do - true -> - { Map.put(key_map, key, map[key]), non_key_map } - false -> - { key_map, Map.put(non_key_map, key, map[key]) } - end - - do_split(map, tl(keys), new_split_tuple) - end - - def take(map, keys) do - {key_map, _} = split(map, keys) - key_map - end - - def drop(map, keys) do - {_, non_key_map} = split(map, keys) - non_key_map - end - - def put_new(map, key, value) do - case key in keys(map) do - true -> - map - false -> - Map.put(map, key, value) - end - end - - def put_new_lazy(map, key, func) do - case key in keys(map) do - true -> - map - false -> - Map.put(map, key, func.()) - end - end - - def put(map, key, value) do - Bootstrap.Core.Functions.add_property_to_map(map, key, value) - end - - def get(map, key) do - get(map, key, nil) - end - - def get(map, key, default_value) do - case key in keys(map) do - true -> - map[key] - false -> - default_value - end - end - - def get_lazy(map, key, func) do - case key in keys(map) do - true -> - func.(map[key]) - false -> - func.() - end - end - - def get_and_update(map, key, func) do - case key in keys(map) do - true -> - { nil, map } - false -> - new_value = func.(map[key]) - { new_value, Map.put(map, key, new_value) } - end - end - - def pop(map, key) do - pop(map, key, nil) - end - - def pop(map, key, default_value) do - case key in keys(map) do - true -> - { map[key], Map.delete(map, key) } - false -> - { default_value, map } - end - end - - def pop_lazy(map, key, func) do - case key in keys(map) do - true -> - { func.(map[key]), Map.delete(map, key) } - false -> - { func.(), map } - end - end - - - def update!(map, key, func) do - case key in keys(map) do - true -> - Map.put(map, key, func.(map[key])) - false -> - raise "#{key} not found in map" - end - end - - - def update(map, key, initial, func) do - case key in keys(map) do - true -> - Map.put(map, key, func.(map[key])) - false -> - Map.put(map, key, initial) - end - end - -end diff --git a/priv/std_lib/map_set.ex b/priv/std_lib/map_set.ex deleted file mode 100644 index a22fe57b..00000000 --- a/priv/std_lib/map_set.ex +++ /dev/null @@ -1,100 +0,0 @@ -defmodule ElixirScript.MapSet do - @moduledoc false - defstruct set: [] - - def new() do - %MapSet{} - end - - def size(set) do - length(set.set) - end - - def to_list(set) do - set.set - end - - def delete(set, term) do - %{ set | set: Elixir.List.remove(set.set, term) } - end - - def put(set, term) do - case member?(set, term) do - false -> - %{ set | set: set.set ++ term } - true -> - set - end - end - - def member?(set, term) do - set.set.indexOf(term) >= 0 - end - - def equal?(set1, set2) do - set1 === set2 - end - - def difference(set1, set2) do - do_difference(to_list(set1), set2, new()) - end - - def do_difference([], _, difference_set) do - difference_set - end - - def do_difference(set1_list, set2, difference_set) do - term = hd(set1_list) - case member?(set2, term) do - true -> - do_difference(tl(set1_list), set2, difference_set) - false -> - do_difference(tl(set1_list), set2, %{ difference_set | set: difference_set.set ++ [term]}) - end - end - - def intersection(set1, set2) do - do_intersection(to_list(set1), set2, new()) - end - - def do_intersection([], _, intersection_set) do - intersection_set - end - - def do_intersection(set1_list, set2, intersection_set) do - term = hd(set1_list) - case member?(set2, term) do - false -> - do_intersection(tl(set1_list), set2, intersection_set) - true -> - do_intersection(tl(set1_list), set2, %{ intersection_set | set: intersection_set.set ++ [term]}) - end - end - - def union(set1, set2) do - %{ set1 | set: set1.set ++ set2.set} - end - - def disjoint?(set1, set2) do - size(intersection(set1, set2)) == 0 - end - - def subset?(set1, set2) do - do_subset?(to_list(set1), set2) - end - - def do_subset?([], _) do - true - end - - def do_subset?(set1_list, set2) do - term = hd(set1_list) - case member?(set2, term) do - false -> - false - true -> - do_subset?(tl(set1_list), set2) - end - end - -end diff --git a/priv/std_lib/module.ex b/priv/std_lib/module.ex deleted file mode 100644 index f1454a5d..00000000 --- a/priv/std_lib/module.ex +++ /dev/null @@ -1,9 +0,0 @@ -defmodule ElixirScript.Module do - @moduledoc false - - defstruct name: nil, - functions: Keyword.new, private_functions: Keyword.new, - body: nil, js_imports: [], module_refs: [], type: :module, - impls: Map.new, impl_type: nil, app_name: nil - -end diff --git a/priv/std_lib/range.ex b/priv/std_lib/range.ex deleted file mode 100644 index 9ae8bffe..00000000 --- a/priv/std_lib/range.ex +++ /dev/null @@ -1,12 +0,0 @@ -defmodule ElixirScript.Range do - @moduledoc false - defstruct first: nil, last: nil - - def new(first, last) do - %ElixirScript.Range{first: first, last: last} - end - - def range?(%ElixirScript.Range{}), do: true - def range?(_), do: false - -end diff --git a/priv/std_lib/regex.ex b/priv/std_lib/regex.ex deleted file mode 100644 index 17888909..00000000 --- a/priv/std_lib/regex.ex +++ /dev/null @@ -1,71 +0,0 @@ -defmodule ElixirScript.Regex do - @moduledoc false - require JS - - def compile(source, options \\ "") do - try do - {:ok, JS.new(RegExp, [source, options])} - rescue - x -> - {:error, x.message} - end - end - - def compile!(source, options \\ "") do - JS.new(RegExp, [source, options]) - end - - def regex?(term) do - JS.instanceof(term, RegExp) - end - - def match?(regex, string) do - reg = if regex?(regex), do: regex, else: compile!(source(regex), opts(regex)) - reg.test(string) - end - - def source(regex) do - regex.source - end - - def opts(regex) do - regex.opts - end - - def run(regex, string, options \\ []) do - regex.exec(string) - end - - def scan(regex, string, options \\ []) do - reg = make_global(regex) - do_scan(reg, string, options, []) - end - - def replace(regex, string, replacement, options \\ []) do - reg = if Keyword.get(options, :global, true) do - make_global(regex) - else - regex - end - - string.replace(reg, replacement) - end - - defp do_scan(regex, string, options, results) do - case run(regex, string, options) do - nil -> - results - match -> - do_scan(regex, string, options, results ++ match) - end - end - - defp make_global(regex) do - if String.contains?(opts(regex), "g") do - regex - else - JS.new(RegExp, [ source(regex), opts(regex) <> "g" ]) - end - end - -end diff --git a/priv/std_lib/string/chars.ex b/priv/std_lib/string/chars.ex deleted file mode 100644 index ae5d0227..00000000 --- a/priv/std_lib/string/chars.ex +++ /dev/null @@ -1,48 +0,0 @@ -defprotocol ElixirScript.String.Chars do - @moduledoc false - def to_string(item) -end - -defimpl ElixirScript.String.Chars, for: Atom do - def to_string(nil) do - "" - end - - def to_string(atom) do - Atom.to_string(atom) - end -end - -defimpl ElixirScript.String.Chars, for: BitString do - def to_string(thing) when is_binary(thing) do - thing - end - - def to_string(thing) do - thing.toString() - end -end - -defimpl ElixirScript.String.Chars, for: List do - def to_string(list) do - list.toString() - end -end - -defimpl ElixirScript.String.Chars, for: Tuple do - def to_string(tuple) do - tuple.toString() - end -end - -defimpl ElixirScript.String.Chars, for: Integer do - def to_string(integer) do - integer.toString() - end -end - -defimpl ElixirScript.String.Chars, for: Float do - def to_string(float) do - float.toString() - end -end diff --git a/priv/std_lib/tuple.ex b/priv/std_lib/tuple.ex deleted file mode 100644 index bed5e717..00000000 --- a/priv/std_lib/tuple.ex +++ /dev/null @@ -1,63 +0,0 @@ -defmodule ElixirScript.Tuple do - @moduledoc false - require JS - - def duplicate(data, size) do - JS.new(Bootstrap.Core.Tuple, do_duplicate(data, size, [])) - end - - defp do_duplicate(_, 0, list) do - list - end - - defp do_duplicate(data, size, list) do - do_duplicate(data, size - 1, list ++ [data]) - end - - def to_list(tuple) do - tuple["value"] - end - - def insert_at(tuple, index, value) do - JS.new(Bootstrap.Core.Tuple, do_insert_at(tuple, index, value, 0, [])) - end - - defp do_insert_at(tuple, index, value, current_index, list) do - if current_index == length(tuple) do - list - else - list = case index == current_index do - true -> - list ++ [value, tuple.get(current_index)] - false -> - list ++ [tuple.get(current_index)] - end - - do_insert_at(tuple, index, value, current_index + 1, list) - end - end - - def delete_at(tuple, index) do - JS.new(Bootstrap.Core.Tuple, do_delete_at(tuple, index, 0, [])) - end - - defp do_delete_at(tuple, index, current_index, list) do - if current_index == length(tuple) do - list - else - list = case index == current_index do - true -> - list - false -> - list ++ [tuple.get(current_index)] - end - - do_delete_at(tuple, index, current_index + 1, list) - end - end - - def append(tuple, value) do - JS.new(Bootstrap.Core.Tuple, to_list(tuple) ++ [value]) - end - -end diff --git a/priv/testrunner/colors.js b/priv/testrunner/colors.js new file mode 100644 index 00000000..b0b48173 --- /dev/null +++ b/priv/testrunner/colors.js @@ -0,0 +1,31 @@ +export default { + Reset: '\x1b[0m', + Bright: '\x1b[1m', + Dim: '\x1b[2m', + Underscore: '\x1b[4m', + Blink: '\x1b[5m', + Reverse: '\x1b[7m', + Hidden: '\x1b[8m', + fg: { + Black: '\x1b[30m', + Red: '\x1b[31m', + Green: '\x1b[32m', + Yellow: '\x1b[33m', + Blue: '\x1b[34m', + Magenta: '\x1b[35m', + Cyan: '\x1b[36m', + White: '\x1b[37m', + Crimson: '\x1b[38m', + }, + bg: { + Black: '\x1b[40m', + Red: '\x1b[41m', + Green: '\x1b[42m', + Yellow: '\x1b[43m', + Blue: '\x1b[44m', + Magenta: '\x1b[45m', + Cyan: '\x1b[46m', + White: '\x1b[47m', + Crimson: '\x1b[48m', + }, +}; diff --git a/priv/testrunner/esm/LICENSE b/priv/testrunner/esm/LICENSE new file mode 100644 index 00000000..2902552d --- /dev/null +++ b/priv/testrunner/esm/LICENSE @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright @std/esm contributors + +Based on reify, copyright Ben Newman + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/priv/testrunner/esm/README.md b/priv/testrunner/esm/README.md new file mode 100644 index 00000000..83c5c840 --- /dev/null +++ b/priv/testrunner/esm/README.md @@ -0,0 +1,131 @@ +# @std/esm + +This fast, small, zero dependency, package is all you need to enable +ES modules in Node 4+ today! + +:book: See the [release post](https://medium.com/web-on-the-edge/es-modules-in-node-today-32cff914e4b) +for all the details. + +Getting started +--- + + 1. Run `npm i --save @std/esm` in your app or package directory. + 2. Add `.esm-cache` to your `.gitignore`. + 3. Create the ESM loader to import your main ES module: + + **index.js** + ```js + require = require("@std/esm")(module) + module.exports = require("./main.mjs").default + ``` + + By default, `@std/esm` **only** processes files of packages that opt-in + with a `@std/esm` options object or `@std/esm` as a dependency, dev + dependency, or peer dependency in their package.json. However, you can + enable processing **all** files with specific options by passing an options + object as the second argument or passing `true` to use the options from + your package.json. + + ```js + const loader1 = require("@std/esm")(module, { cjs: true, esm: "js" }) + const loader2 = require("@std/esm")(module, true) + ``` + +Enable ESM in the Node CLI by loading `@std/esm` with the [`-r` option](https://nodejs.org/api/cli.html#cli_r_require_module): + +```shell +node -r @std/esm file.mjs +``` + +Enable ESM in the Node REPL by loading `@std/esm` upon entering: + +```shell +$ node +> require("@std/esm") +@std/esm enabled +> import p from "path" +undefined +> p.join("hello", "world") +'hello/world' +``` + +*Note: The `"cjs"` and `"gz"` options are [unlocked](#unlockables) in the Node REPL.* + +Standard Features +--- + +The `@std/esm` loader is as spec-compliant +as possible and follows [Node’s rules](https://github.com/nodejs/node-eps/blob/master/002-es-modules.md). + +:point_right: This means, by default, ESM requires the use of the `.mjs` file +extension.
+:unlock: You can [unlock](#unlockables) ESM with the `.js` file extension using +the `"js"` ESM mode. + +Out of the box `@std/esm` just works, no configuration necessary, and supports: + +* [`import`](https://ponyfoo.com/articles/es6-modules-in-depth#import) / [`export`](https://ponyfoo.com/articles/es6-modules-in-depth#export) +* [Dynamic `import()`](https://github.com/tc39/proposal-dynamic-import) +* [Live bindings](https://ponyfoo.com/articles/es6-modules-in-depth#bindings-not-values) +* [Loading `.mjs` files as ESM](https://github.com/nodejs/node-eps/blob/master/002-es-modules.md#32-determining-if-source-is-an-es-module) +* [The file URI scheme](https://en.wikipedia.org/wiki/File_URI_scheme) +* Node 4+ support + +Unlockables +--- + +Unlock extra features with `"@std/esm":options` or +`"@std":{"esm":options}` in your package.json. + +*Note: All options are **off** by default and may be specified as either an object or ESM mode string.* + + + + + + + + + + + + + + + + + + + + + + + + +
+
{
+  "@std/esm": {
+
"esm": +

A string ESM mode

+
    +
  • "mjs" files as ESM (default)
  • +
  • "all" files as ESM
  • +
  • "js" files with import, export, or "use module" as ESM
  • +
+
"cjs": +

A boolean for CJS features in ESM

+ +
"await":

A boolean for top-level await in the main ES module

"gz": +

A boolean for gzipped module support (i.e. .js.gz, .mjs.gz)

+ +
+
  }
+}
+
diff --git a/priv/testrunner/esm/esm.js.gz b/priv/testrunner/esm/esm.js.gz new file mode 100644 index 00000000..d199117d Binary files /dev/null and b/priv/testrunner/esm/esm.js.gz differ diff --git a/priv/testrunner/esm/index.js b/priv/testrunner/esm/index.js new file mode 100644 index 00000000..5eb27ed1 --- /dev/null +++ b/priv/testrunner/esm/index.js @@ -0,0 +1,48 @@ +/* eslint strict: off, node/no-unsupported-features: ["error", { version: 4 }] */ + +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const util = require('util'); +const vm = require('vm'); +const zlib = require('zlib'); + +const esmPath = path.resolve(__dirname, 'esm.js.gz'); +const inspectKey = util.inspect.custom || 'inspect'; + +const descriptor = Object.create(null); +descriptor.value = () => '@std/esm enabled'; + +const mod = new module.constructor(module.id); +mod.filename = __filename; +mod.parent = module.parent; + +const scriptOptions = Object.create(null); +scriptOptions.filename = __filename; + +const content = + `(function(require,module,__filename){${ + zlib.gunzipSync(fs.readFileSync(esmPath)).toString() + }\n})`; + +const compiled = vm.runInThisContext(content, scriptOptions); + +function makeLoaderFunction() { + compiled(require, mod, __filename); + return mod.exports; +} + +const loader = makeLoaderFunction(); + +module.exports = (mod, options) => { + const type = typeof options; + + if (options === true || type === 'function' || (type === 'object' && options !== null)) { + return makeLoaderFunction()(mod, options); + } + + return loader(mod, options); +}; + +Object.freeze(Object.defineProperty(module.exports, inspectKey, descriptor)); diff --git a/priv/testrunner/esm/package.json b/priv/testrunner/esm/package.json new file mode 100644 index 00000000..fa5bb5c5 --- /dev/null +++ b/priv/testrunner/esm/package.json @@ -0,0 +1,20 @@ +{ + "name": "@std/esm", + "version": "0.8.3", + "description": "Enable ES modules in Node today!", + "keywords": "commonjs, ecmascript, export, import, modules, node, require", + "repository": "standard-things/esm", + "license": "MIT", + "author": "John-David Dalton ", + "main": "index.js", + "engines": { + "node": ">=4" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "files": [ + "index.js", + "esm.js.gz" + ] +} diff --git a/priv/testrunner/index.js b/priv/testrunner/index.js new file mode 100644 index 00000000..9dddc392 --- /dev/null +++ b/priv/testrunner/index.js @@ -0,0 +1,28 @@ +require = require('./esm/index.js')(module, { cjs: true, esm: 'js' }); +const runner = require('./testRunner.js').default; +const Colors = require('./colors.js').default; + +const testFiles = process.argv.slice(2); +console.time('Finished in'); +runner + .start(testFiles) + .then((results) => { + const testsFailed = results.failed > 0; + + process.stdout.write('\n\n'); + console.timeEnd('Finished in'); + console.log( + testsFailed ? Colors.fg.Red : Colors.fg.Green, + `${results.tests} tests, ${results.success} succeeded, ${results.failed} failed\n`, + Colors.Reset, + ); + + if (testsFailed) { + process.exit(1); + } else { + process.exit(0); + } + }) + .catch((e) => { + console.log(e); + }); diff --git a/priv/testrunner/testRunner.js b/priv/testrunner/testRunner.js new file mode 100644 index 00000000..3bdd9a7c --- /dev/null +++ b/priv/testrunner/testRunner.js @@ -0,0 +1,134 @@ +import Colors from './colors.js'; +import Vendor from './vendor.build.js'; + +async function start(files) { + const results = { + tests: 0, + success: 0, + failed: 0, + }; + + for (const file of files) { + const mod = await import(file); + if (mod.default.__elixirscript_test_module__) { + runTests(mod, results); + } + } + + return results; +} + +function runSetup(mod, name, incomingContext = new Map()) { + if (mod.default[name]) { + const result = mod.default[name](incomingContext); + + return resolveContext(result, incomingContext); + } + + return incomingContext; +} + +function runTeardown(mod, name, incomingContext) { + if (mod.default[name]) { + const result = mod.default[name](incomingContext); + } +} + +function resolveContext(context, parentContext) { + if (context === Symbol.for('ok')) { + return parentContext; + } else if (context instanceof Vendor.ErlangTypes.Tuple && context.get(0) === Symbol.for('ok')) { + return resolveContext(context.get(1), parentContext); + } else if (context instanceof Map) { + return new Map([...parentContext, ...context]); + } else if (Array.isArray(context)) { + return mergeContextKeywordList(context, parentContext); + } + + throw new Error('Invalid context'); +} + +function mergeContextKeywordList(context, parentContext) { + const newContext = new Map([...parentContext]); + + for (const entry of context) { + newContext.set(entry.get(0), entry.get(1)); + } + + return newContext; +} + +function runTests(mod, results) { + const contextSetupAll = runSetup(mod, '__elixirscript_test_setup_all'); + + for (const key of Object.keys(mod.default)) { + if (key.startsWith('__elixirscript_test_case')) { + results.tests++; + const test = mod.default[key](); + const result = runTest(mod, test, contextSetupAll, results); + + if (result) { + results.success++; + } else { + results.failed++; + } + } + } + + runTeardown(mod, '__elixirscript_test_teardown_all', contextSetupAll); +} + +function runTest(mod, test, incomingContext, results) { + const context = runSetup(mod, '__elixirscript_test_setup', incomingContext); + let testPassed = true; + try { + test.get(Symbol.for('test'))(context); + process.stdout.write(Colors.fg.Green + '.' + Colors.Reset); + } catch (e) { + process.stdout.write('\n'); + handleError(e, test, results, mod); + testPassed = false; + } + + runTeardown(mod, '__elixirscript_test_teardown', context); + return testPassed; +} + +function handleError(e, test, results, mod) { + if (e.__reason) { + if (e.__reason instanceof Map && e.__reason.get(Symbol.for('message'))) { + const errorMessage = e.__reason.get(Symbol.for('message')); + const expr = e.__reason.get(Symbol.for('expr')); + const left = e.__reason.get(Symbol.for('left')); + const right = e.__reason.get(Symbol.for('right')); + const file = e.__reason.get(Symbol.for('file')); + const line = e.__reason.get(Symbol.for('line')); + const moduleName = Symbol.keyFor(mod.default.__MODULE__).replace('Elixir.', ''); + let testMessage = test.get(Symbol.for('message')); + testMessage = `${results.failed}) ${testMessage} (${moduleName})`; + + printErrorLine(testMessage); + console.log(Colors.fg.Red, errorMessage, Colors.Reset); + printErrorLine(left, 'left'); + printErrorLine(right, 'right'); + printErrorLine(file, 'file'); + printErrorLine(line, 'line'); + } + } else { + console.log(e); + } +} + +function printErrorLine(value, label = null) { + if (value && value !== Symbol.for('ex_unit_no_meaningful_value')) { + if (label) { + console.log(Colors.fg.Cyan, `${label}:`, Colors.Reset, `${value}`); + } else { + console.log(`${value}`, Colors.Reset); + } + } +} + +export default { + start, +}; diff --git a/priv/testrunner/vendor.build.js b/priv/testrunner/vendor.build.js new file mode 100644 index 00000000..f83931bf --- /dev/null +++ b/priv/testrunner/vendor.build.js @@ -0,0 +1,2 @@ +function unwrapExports(a){return a&&a.__esModule&&Object.prototype.hasOwnProperty.call(a,"default")?a["default"]:a}function createCommonjsModule(a,b){return b={exports:{}},a(b,b.exports),b.exports}var tuple=createCommonjsModule(function(a,b){Object.defineProperty(b,"__esModule",{value:!0});class Tuple{constructor(...a){this.values=Object.freeze(a),this.length=this.values.length}get(a){return this.values[a]}count(){return this.values.length}[Symbol.iterator](){return this.values[Symbol.iterator]()}toString(){let a,b="";for(a=0;a"}}});unwrapExports(pid);var pid_1=pid.PID,reference=createCommonjsModule(function(a,b){Object.defineProperty(b,"__esModule",{value:!0});let c=-1;b.Reference=class Reference{constructor(){++c,this.id=c,this.ref=Symbol()}toString(){return"Ref#<0.0.0."+this.id+">"}}});unwrapExports(reference);var reference_1=reference.Reference,bit_string=createCommonjsModule(function(a,b){Object.defineProperty(b,"__esModule",{value:!0});class BitString{constructor(...a){this.value=Object.freeze(this.process(a)),this.length=this.value.length,this.bit_size=8*this.length,this.byte_size=this.length}get(a){return this.value[a]}count(){return this.value.length}slice(a,b=void 0){let c=this.value.slice(a,b),d=c.map(a=>BitString.integer(a));return new BitString(...d)}[Symbol.iterator](){return this.value[Symbol.iterator]()}toString(){var a,b="";for(a=0;a>"}process(a){let b=[];var c;for(c=0;cb?c.push(b):2048>b?c.push(192|b>>6,128|63&b):55296>b||57344<=b?c.push(224|b>>12,128|63&b>>6,128|63&b):(d++,b=65536+((1023&b)<<10|1023&a.charCodeAt(d)),c.push(240|b>>18,128|63&b>>12,128|63&b>>6,128|63&b));return c}static toUTF16Array(a){for(var b,c=[],d=0;d=b?(c.push(0),c.push(b)):(c.push(255&b>>8),c.push(255&b)));return c}static toUTF32Array(a){for(var b,c=[],d=0;d=b?(c.push(0),c.push(0),c.push(0),c.push(b)):(c.push(0),c.push(0),c.push(255&b>>8),c.push(255&b)));return c}//http://stackoverflow.com/questions/2003493/javascript-float-from-to-bits +static float32ToBytes(a){var b=[],c=new ArrayBuffer(4);new Float32Array(c)[0]=a;let d=new Uint32Array(c)[0];return b.push(255&d>>24),b.push(255&d>>16),b.push(255&d>>8),b.push(255&d),b}static float64ToBytes(a){var b=[],c=new ArrayBuffer(8);new Float64Array(c)[0]=a;var d=new Uint32Array(c)[0],e=new Uint32Array(c)[1];return b.push(255&e>>24),b.push(255&e>>16),b.push(255&e>>8),b.push(255&e),b.push(255&d>>24),b.push(255&d>>16),b.push(255&d>>8),b.push(255&d),b}}b.BitString=BitString});unwrapExports(bit_string);var bit_string_1=bit_string.BitString,lib=createCommonjsModule(function(a,b){Object.defineProperty(b,"__esModule",{value:!0}),b.Tuple=tuple.Tuple,b.PID=pid.PID,b.Reference=reference.Reference,b.BitString=bit_string.BitString}),ErlangTypes=unwrapExports(lib),lib_1=lib.Tuple,lib_2=lib.PID,lib_3=lib.Reference,lib_4=lib.BitString,vendor={ErlangTypes};export default vendor; diff --git a/priv/testrunner/vendor.js b/priv/testrunner/vendor.js new file mode 100644 index 00000000..1d79bd80 --- /dev/null +++ b/priv/testrunner/vendor.js @@ -0,0 +1,5 @@ +import ErlangTypes from 'erlang-types'; + +export default { + ErlangTypes, +}; diff --git a/rollup.config.js b/rollup.config.js index 6e2312d3..dbdce767 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,14 +1,52 @@ -import nodeResolve from "rollup-plugin-node-resolve"; -import babel from "rollup-plugin-babel"; +const rollup = require('rollup') +const babel = require('rollup-plugin-babel') +const nodeResolve = require('rollup-plugin-node-resolve') +const commonjs = require('rollup-plugin-commonjs') +const minify = require('rollup-plugin-babel-minify') -export default { - entry: "src/javascript/elixir.js", - moduleName: "Bootstrap", - plugins: [ - nodeResolve({ jsnext: true }), - babel({ - babelrc: false +const plugins = [ + nodeResolve({ + mainFields: ['jsnext', 'main'], + }), + commonjs(), + babel({ + babelrc: false, + }), + minify({ + keepFnName: true, + keepClassName: true, + }), +] + +rollup + .rollup({ + input: 'src/javascript/elixir.js', + output: { + file: 'priv/build/es/ElixirScript.Core.js', + format: 'es', + }, + plugins, + }) + .then(bundle => { + bundle.write({ + format: 'es', + file: 'priv/build/es/ElixirScript.Core.js', + sourcemap: 'inline', + }) + }) + +rollup + .rollup({ + input: 'priv/testrunner/vendor.js', + output: { + file: 'priv/testrunner/vendor.build.js', + format: 'es', + }, + plugins, + }) + .then(bundle => { + bundle.write({ + format: 'es', + file: 'priv/testrunner/vendor.build.js', }) - ], - targets: [{ dest: "priv/build/iife/Elixir.Bootstrap.js", format: "iife" }] -}; + }) diff --git a/src/javascript/elixir.js b/src/javascript/elixir.js index 1972ade5..3f58d0a3 100644 --- a/src/javascript/elixir.js +++ b/src/javascript/elixir.js @@ -1,7 +1,5 @@ import Core from './lib/core'; -import Enum from './lib/enum'; export default { Core, - Enum }; diff --git a/src/javascript/lib/core.js b/src/javascript/lib/core.js index d8bccde4..7f87d1da 100644 --- a/src/javascript/lib/core.js +++ b/src/javascript/lib/core.js @@ -1,20 +1,80 @@ -import Patterns from "tailored"; -import ErlangTypes from "erlang-types"; -import Functions from "./core/functions"; -import SpecialForms from "./core/special_forms"; -import Store from "./core/store"; +import Patterns from 'tailored'; +import ErlangTypes from 'erlang-types'; +import Functions from './core/functions'; +import SpecialForms from './core/special_forms'; +import erlang from './core/erlang_compat/erlang'; +import maps from './core/erlang_compat/maps'; +import lists from './core/erlang_compat/lists'; +import elixir_errors from './core/erlang_compat/elixir_errors'; +import elixir_config from './core/erlang_compat/elixir_config'; +import io from './core/erlang_compat/io'; +import filename from './core/erlang_compat/filename'; +import binary from './core/erlang_compat/binary'; +import unicode from './core/erlang_compat/unicode'; +import Store from './core/store'; +import math from './core/erlang_compat/math'; +import proplists from './core/erlang_compat/proplists'; class Integer {} class Float {} +function get_global() { + if (typeof self !== 'undefined') { + return self; + } else if (typeof window !== 'undefined') { + return window; + } else if (typeof global !== 'undefined') { + return global; + } + + /* As long as the window check precedes this, it won't display in a browser, + unless the ground cracks open and swallows JavaScript whole. */ + /* eslint-disable no-console */ + console.warn('No global state found'); + /* eslint-enable no-console */ + + return null; +} + +function initApp() { + const Elixir = {}; + + Elixir.__table__ = {}; + Elixir.start = (app, args) => { + app.__load(Elixir).start(Symbol.for('normal'), args); + }; + Elixir.load = module => module.__load(Elixir); + + return Elixir; +} + +const globalState = get_global(); + +globalState.__elixirscript_store__ = new Map(); +globalState.__elixirscript_names__ = new Map(); + export default { Tuple: ErlangTypes.Tuple, PID: ErlangTypes.PID, BitString: ErlangTypes.BitString, + Reference: ErlangTypes.Reference, Patterns, Integer, Float, Functions, SpecialForms, - Store + Store, + global: globalState, + erlang, + maps, + lists, + elixir_errors, + io, + filename, + binary, + unicode, + elixir_config, + math, + proplists, + initApp, }; diff --git a/src/javascript/lib/core/erlang_compat/binary.js b/src/javascript/lib/core/erlang_compat/binary.js new file mode 100644 index 00000000..20a7b629 --- /dev/null +++ b/src/javascript/lib/core/erlang_compat/binary.js @@ -0,0 +1,69 @@ +import erlang from './erlang'; +import proplists from './proplists'; + +function at(subject, pos) { + return subject.charAt(pos); +} + +function copy(subject, n = 1) { + return subject.repeat(n); +} + +function first(subject) { + if (subject.length === 0) { + throw new Error('Binary is of length 0'); + } + return at(subject, 0); +} + +function last(subject) { + if (subject.length === 0) { + throw new Error('Binary is of length 0'); + } + return subject.slice(-1); +} + +function list_to_bin(bytelist) { + return erlang.list_to_binary(bytelist); +} + +function part(subject, posOrTuple, len = null) { + if (len === null) { + const [pos, theLen] = posOrTuple.values; + return subject.substr(pos, theLen); + } + + return subject.substr(posOrTuple, len); +} + +// TODO: Support more options +// TODO: pattern cannot be list of strings +function replace(subject, pattern, replacement, options = []) { + const opt_global = proplists.get_value(Symbol.for('global'), options); + + let regex; + if (opt_global !== Symbol.for('undefined')) { + regex = new RegExp(pattern, 'g'); + } else { + regex = new RegExp(pattern, ''); + } + + return subject.replace(regex, replacement); +} + +// TODO: Support more options, global is implied +// TODO: pattern cannot be list of strings +function split(subject, pattern, options = []) { + return subject.split(pattern); +} + +export default { + at, + copy, + first, + last, + list_to_bin, + part, + replace, + split, +}; diff --git a/src/javascript/lib/core/erlang_compat/elixir_config.js b/src/javascript/lib/core/erlang_compat/elixir_config.js new file mode 100644 index 00000000..dba52d2e --- /dev/null +++ b/src/javascript/lib/core/erlang_compat/elixir_config.js @@ -0,0 +1,43 @@ +const MODULE = Symbol.for('elixir_config'); +const ets = new Map(); + +function _new(opts) { + ets.set(MODULE, new Map()); + ets.get(MODULE).set(MODULE, opts); + return MODULE; +} + +function _delete(module) { + ets.delete(module); + return true; +} + +function put(key, value) { + ets.get(MODULE).set(key, value); + return Symbol.for('ok'); +} + +function get(key) { + return ets.get(MODULE).get(key); +} + +function update(key, fun) { + const value = fun(ets.get(MODULE).get(key)); + put(key, value); + return value; +} + +function get_and_put(key, value) { + const oldValue = get(key); + put(key, value); + return oldValue; +} + +export default { + new: _new, + delete: _delete, + put, + get, + update, + get_and_put, +}; diff --git a/src/javascript/lib/core/erlang_compat/elixir_errors.js b/src/javascript/lib/core/erlang_compat/elixir_errors.js new file mode 100644 index 00000000..c6b5d22b --- /dev/null +++ b/src/javascript/lib/core/erlang_compat/elixir_errors.js @@ -0,0 +1,14 @@ +/* It is far too "meta" to warn about including a warning in a warning */ +/* eslint-disable no-console */ + +function warn(message) { + const messageString = message.join(''); + console.warn(`warning: ${messageString}`); + + + return Symbol.for('ok'); +} + +export default { + warn, +}; diff --git a/src/javascript/lib/core/erlang_compat/erlang.js b/src/javascript/lib/core/erlang_compat/erlang.js new file mode 100644 index 00000000..ddece09d --- /dev/null +++ b/src/javascript/lib/core/erlang_compat/erlang.js @@ -0,0 +1,602 @@ +// http://erlang.org/doc/man/erlang.html +import ErlangTypes from 'erlang-types'; +import lists from './lists'; + +const selfPID = new ErlangTypes.PID(); + +function is_boolean(value) { + return typeof value === 'boolean' || value instanceof Boolean; +} + +function atom_to_binary(atom, encoding = Symbol.for('utf8')) { + if (encoding !== Symbol.for('utf8')) { + throw new Error(`unsupported encoding ${encoding}`); + } + + if (atom === null) { + return 'nil'; + } else if (is_boolean(atom)) { + return atom.toString(); + } else if (atom.__MODULE__) { + return Symbol.keyFor(atom.__MODULE__); + } + + return Symbol.keyFor(atom); +} + +function atom_to_list(atom) { + return atom_to_binary(atom); +} + +function binary_to_atom(binary, encoding = Symbol.for('utf8')) { + if (encoding !== Symbol.for('utf8')) { + throw new Error(`unsupported encoding ${encoding}`); + } + + if (binary === 'nil') { + return null; + } else if (binary === 'true') { + return true; + } else if (binary === 'false') { + return false; + } + + return Symbol.for(binary); +} + +function binary_to_existing_atom(binary, encoding = Symbol.for('utf8')) { + return binary_to_atom(binary, encoding); +} + +function list_concatenation(list1, list2) { + return list1.concat(list2); +} + +function list_subtraction(list1, list2) { + const list = [...list1]; + + for (const item of list2) { + const index = list.indexOf(item); + + if (index > -1) { + list.splice(index, 1); + } + } + + return list; +} + +function arrayEquals(left, right) { + if (!Array.isArray(right)) { + return false; + } + + if (left.length !== right.length) { + return false; + } + + for (let i = 0; i < left.length; i++) { + if (equals(left[i], right[i]) === false) { + return false; + } + } + + return true; +} + +function tupleEquals(left, right) { + if (right instanceof ErlangTypes.Tuple === false) { + return false; + } + + if (left.length !== right.length) { + return false; + } + + return arrayEquals(left.values, right.values); +} + +function bitstringEquals(left, right) { + if (right instanceof ErlangTypes.BitString === false) { + return false; + } + + if (left.length !== right.length) { + return false; + } + + return arrayEquals(left.value, right.value); +} + +function pidEquals(left, right) { + if (right instanceof ErlangTypes.PID === false) { + return false; + } + + return left.id === right.id; +} + +function referenceEquals(left, right) { + if (right instanceof ErlangTypes.Reference === false) { + return false; + } + + return left.id === right.id; +} + +function mapEquals(left, right) { + if (right instanceof Map === false) { + return false; + } + + const leftEntries = Array.from(left.entries()); + const rightEntries = Array.from(right.entries()); + + return arrayEquals(leftEntries, rightEntries); +} + +function equals(left, right) { + if (Array.isArray(left)) { + return arrayEquals(left, right); + } + + if (left instanceof ErlangTypes.Tuple) { + return tupleEquals(left, right); + } + + if (left instanceof ErlangTypes.PID) { + return pidEquals(left, right); + } + + if (left instanceof ErlangTypes.BitString) { + return bitstringEquals(left, right); + } + + if (left instanceof ErlangTypes.Reference) { + return referenceEquals(left, right); + } + + if (left instanceof Map) { + return mapEquals(left, right); + } + + return left === right; +} + +function div(left, right) { + return left / right; +} + +function not(x) { + return !x; +} + +function rem(left, right) { + return left % right; +} + +function band(left, right) { + return left & right; +} + +function bor(left, right) { + return left | right; +} + +function bnot(x) { + return ~x; +} + +function bsl(left, right) { + return left << right; +} + +function bsr(left, right) { + return left >> right; +} + +function bxor(left, right) { + return left ^ right; +} + +function is_atom(value) { + if (value === null) { + return true; + } else if (is_boolean(value)) { + return true; + } + + return typeof value === 'symbol' || value instanceof Symbol || value.__MODULE__ != null; +} + +function is_bitstring(value) { + return value instanceof ErlangTypes.BitString; +} + +function is_number(value) { + return typeof value === 'number' || value instanceof Number; +} + +function is_float(value) { + return is_number(value) && !Number.isInteger(value); +} + +function is_function(value) { + return typeof value === 'function' || value instanceof Function; +} + +function is_integer(value) { + return Number.isInteger(value); +} + +function is_list(value) { + return Array.isArray(value); +} + +function is_map(value) { + return value instanceof Map; +} + +function is_pid(value) { + return value instanceof ErlangTypes.PID; +} + +function is_port() { + return false; +} + +function is_reference(value) { + return value instanceof ErlangTypes.Reference; +} + +function is_tuple(value) { + return value instanceof ErlangTypes.Tuple; +} + +function is_binary(value) { + return typeof value === 'string' || value instanceof String; +} + +function element(n, tuple) { + return tuple.get(n - 1); +} + +function setelement(index, tuple1, value) { + const tupleData = [...tuple1.values]; + + tupleData[index - 1] = value; + + return new ErlangTypes.Tuple(...tupleData); +} + +function make_tuple(arity, initialValue) { + const list = []; + + for (let i = 0; i < arity; i++) { + list.push(initialValue); + } + + return new ErlangTypes.Tuple(...list); +} + +function insert_element(index, tuple, term) { + const list = [...tuple.values]; + list.splice(index - 1, 0, term); + + return new ErlangTypes.Tuple(...list); +} + +function append_element(tuple, term) { + const list = [...tuple.values]; + list.push(term); + + return new ErlangTypes.Tuple(...list); +} + +function delete_element(index, tuple) { + const list = [...tuple.values]; + list.splice(index - 1, 1); + + return new ErlangTypes.Tuple(...list); +} + +function tuple_to_list(tuple) { + const list = [...tuple.values]; + return list; +} + +function abs(number) { + return Math.abs(number); +} + +function apply(...args) { + if (args.length === 2) { + return args[0].apply(this, ...args[1]); + } + + return args[0][atom_to_binary(args[1])].apply(this, ...args[2]); +} + +function binary_part(binary, start, _length) { + return binary.substring(start, start + _length); +} + +function bit_size(bitstring) { + return bitstring.bit_size; +} + +function byte_size(bitstring) { + if (typeof bitstring === 'string' || bitstring instanceof String) { + return bitstring.length; + } + return bitstring.byte_size; +} + +function hd(list) { + return list[0]; +} + +function length(list) { + return list.length; +} + +function make_ref() { + return new ErlangTypes.Reference(); +} + +function map_size(map) { + return map.size; +} + +function max(first, second) { + return Math.max(first, second); +} + +function min(first, second) { + return Math.min(first, second); +} + +function round(number) { + return Math.round(number); +} + +function tl(list) { + return list.slice(1); +} + +function trunc(number) { + return Math.trunc(number); +} + +function tuple_size(tuple) { + return tuple.length; +} + +function binary_to_float(str) { + return parseFloat(str); +} + +function binary_to_integer(str, base = 10) { + return parseInt(str, base); +} + +function process_info(pid, item) { + if (item) { + if (item === Symbol.for('current_stacktrace')) { + return new ErlangTypes.Tuple(item, []); + } + + return new ErlangTypes.Tuple(item, null); + } + + return []; +} + +function list_to_binary(iolist) { + const iolistFlattened = lists.flatten(iolist); + + const value = iolistFlattened.reduce((acc, current) => { + if (current === null) { + return acc; + } else if (is_integer(current)) { + return acc + String.fromCodePoint(current); + } else if (is_bitstring(current)) { + return acc + String.fromCodePoint(...current.value); + } + + return acc + current; + }, ''); + + return value; +} + +function iolist_to_binary(ioListOrBinary) { + if (ioListOrBinary === null) { + return ''; + } + + if (is_binary(ioListOrBinary)) { + return ioListOrBinary; + } + + if (is_bitstring(ioListOrBinary)) { + return String.fromCodePoint(...ioListOrBinary.value); + } + + if (is_number(ioListOrBinary)) { + return String.fromCodePoint(ioListOrBinary); + } + + const iolistFlattened = lists.flatten(ioListOrBinary); + + const value = iolistFlattened.reduce((acc, current) => { + if (current === null) { + return acc; + } else if (is_integer(current)) { + return acc + String.fromCodePoint(current); + } else if (is_bitstring(current)) { + return acc + String.fromCodePoint(...current.value); + } + + return acc + iolist_to_binary(current); + }, ''); + + return value; +} + +function io_size(ioListOrBinary) { + return iolist_to_binary(ioListOrBinary).length; +} + +function integer_to_binary(integer, base = 10) { + return integer.toString(base); +} + +function node() { + return Symbol.for('nonode@nohost'); +} + +function nodes(arg = []) { + const nodeTypes = Array.isArray(arg) ? arg : [arg]; + const nodesFound = []; + + for (const nodeType of nodeTypes) { + if (nodeType === Symbol.for('this')) { + nodesFound.push(Symbol.for('nonode@nohost')); + console.log(nodesFound); + } + } + return nodesFound; +} + +function self() { + return selfPID; +} + +function _throw(term) { + throw term; +} + +function error(reason) { + let theError = null; + + if (reason instanceof Map && reason.has(Symbol.for('__exception__'))) { + let name = Symbol.keyFor(reason.get(Symbol.for('__struct__')).__MODULE__); + name = name + .split('.') + .slice(1) + .join('.'); + const message = reason.get(Symbol.for('message')); + theError = new Error(`** (${name}) ${message}`); + } else if (is_binary(reason)) { + theError = new Error(`** (RuntimeError) ${reason}`); + } else { + theError = new Error(`** (ErlangError) Erlang Error ${reason.toString()}`); + } + + theError.__reason = reason; + + throw theError; +} + +function exit(...args) { + if (args.length === 2) { + throw args[1]; + } else { + throw args[0]; + } +} + +function raise(_class, reason) { + if (_class === Symbol.for('throw')) { + _throw(reason); + } else if (_class === Symbol.for('error')) { + error(reason); + } else { + exit(reason); + } +} + +function function_exported(module, _function) { + return module[_function] != null; +} + +function lessThanEqualTo(one, two) { + return one <= two; +} + +function add(one, two) { + return one + two; +} + +export default { + atom_to_binary, + binary_to_atom, + binary_to_existing_atom, + list_concatenation, + list_subtraction, + div, + not, + rem, + band, + bor, + bsl, + bsr, + bxor, + bnot, + is_bitstring, + is_boolean, + is_float, + is_function, + is_integer, + is_list, + is_map, + is_number, + is_pid, + is_port, + is_reference, + is_tuple, + is_atom, + is_binary, + element, + setelement, + make_tuple, + insert_element, + append_element, + delete_element, + tuple_to_list, + abs, + apply, + binary_part, + bit_size, + byte_size, + hd, + length, + make_ref, + map_size, + max, + min, + round, + tl, + trunc, + tuple_size, + binary_to_float, + binary_to_integer, + process_info, + iolist_to_binary, + io_size, + integer_to_binary, + atom_to_list, + node, + self, + throw: _throw, + error, + exit, + raise, + list_to_binary, + nodes, + function_exported, + equals, + lessThanEqualTo, + add, +}; diff --git a/src/javascript/lib/core/erlang_compat/filename.js b/src/javascript/lib/core/erlang_compat/filename.js new file mode 100644 index 00000000..1d2fe0af --- /dev/null +++ b/src/javascript/lib/core/erlang_compat/filename.js @@ -0,0 +1,25 @@ +function join(arg, extra = null) { + const components = Array.isArray(arg) ? arg : [arg, extra]; + let names = []; + for (let i = components.length - 1; i >= 0; i--) { + const name = components[i]; + const normalized_name = name.replace(/\/+/g, '/').replace(/^\/|\/$/g, ''); + names.push(normalized_name); + if (name[0] === '/') { + names.push(''); + break; + } + } + return names.reverse().join('/'); +} + +function dirname(arg) { + const path = join([arg]); + const index = path.lastIndexOf('/'); + return index === -1 ? '.' : (path.substr(0, index) || '/'); +} + +export default { + join, + dirname, +}; diff --git a/src/javascript/lib/core/erlang_compat/io.js b/src/javascript/lib/core/erlang_compat/io.js new file mode 100644 index 00000000..abff3f57 --- /dev/null +++ b/src/javascript/lib/core/erlang_compat/io.js @@ -0,0 +1,19 @@ +/* The purpose of this module is, in fact, to do IO. */ +/* eslint-disable no-console */ +import erlang from './erlang'; + +function put_chars(ioDevice, charData) { + const dataToWrite = erlang.iolist_to_binary(charData); + + if (ioDevice === Symbol.for('stderr')) { + console.error(dataToWrite); + } else { + console.log(dataToWrite); + } + + return Symbol.for('ok'); +} + +export default { + put_chars, +}; diff --git a/src/javascript/lib/core/erlang_compat/lists.js b/src/javascript/lib/core/erlang_compat/lists.js new file mode 100644 index 00000000..066f903a --- /dev/null +++ b/src/javascript/lib/core/erlang_compat/lists.js @@ -0,0 +1,261 @@ +// http://erlang.org/doc/man/lists.html +import ErlangTypes from 'erlang-types'; + +function reverse(list) { + return [...list].reverse(); +} + +function foreach(fun, list) { + list.forEach(x => fun(x)); + + return Symbol.for('ok'); +} + +function duplicate(n, elem) { + const list = []; + + while (list.length < n) { + list.push(elem); + } + + return list; +} + +function flatten(deepList, tail = []) { + const val = deepList.reduce((acc, value) => { + if (Array.isArray(value)) { + return acc.concat(flatten(value)); + } + + return acc.concat(value); + }, []); + + return val.concat(tail); +} + +function foldl(fun, acc0, list) { + return list.reduce((acc, value) => fun(value, acc), acc0); +} + +function foldr(fun, acc0, list) { + return foldl(fun, acc0, reverse(list)); +} + +function keyfind(key, n, list) { + for (const ele of list) { + if (ele instanceof ErlangTypes.Tuple && ele.get(n - 1) === key) { + return ele; + } + } + + return false; +} + +function keymember(key, n, tupleList) { + if (keyfind(key, n, tupleList) === false) { + return false; + } + + return true; +} + +function keyreplace(key, n, tupleList, newTuple) { + const newTupleList = [...tupleList]; + + for (let index = 0; index < newTupleList.length; index++) { + if (newTupleList[index].get(n - 1) === key) { + newTupleList[index] = newTuple; + return newTupleList; + } + } + + return newTupleList; +} + +function keysort(n, tupleList) { + const newTupleList = [...tupleList]; + + return newTupleList.sort((a, b) => { + if (a.get(n - 1) < b.get(n - 1)) { + return -1; + } else if (a.get(n - 1) > b.get(n - 1)) { + return 1; + } + + return 0; + }); +} + +function keystore(key, n, tupleList, newTuple) { + const newTupleList = [...tupleList]; + + for (let index = 0; index < newTupleList.length; index++) { + if (newTupleList[index].get(n - 1) === key) { + newTupleList[index] = newTuple; + return newTupleList; + } + } + + return newTupleList.concat(newTuple); +} + +function keydelete(key, n, tupleList) { + const newTupleList = []; + let deleted = false; + + for (let index = 0; index < tupleList.length; index++) { + if (deleted === false && tupleList[index].get(n - 1) === key) { + deleted = true; + } else { + newTupleList.push(tupleList[index]); + } + } + + return newTupleList; +} + +function keytake(key, n, tupleList) { + const result = keyfind(key, n, tupleList); + + if (result !== false) { + return new ErlangTypes.Tuple(result.get(n - 1), result, keydelete(key, n, tupleList)); + } + + return false; +} + +function mapfoldl(fun, acc0, list1) { + const listResult = []; + let accResult = acc0; + + for (const item of list1) { + const tuple = fun(item, accResult); + listResult.push(tuple.get(0)); + accResult = tuple.get(1); + } + + return new ErlangTypes.Tuple(listResult, accResult); +} + +function concat(things) { + return things.map(v => v.toString()).join(); +} + +function map(fun, list) { + return list.map(value => fun(value)); +} + +function filter(pred, list1) { + return list1.filter(x => pred(x)); +} + +function filtermap(fun, list1) { + const list2 = []; + + for (const item of list1) { + const value = fun(item); + + if (value === true) { + list2.push(item); + } else if (value instanceof ErlangTypes.Tuple && value.get(0) === true) { + list2.push(value.get(1)); + } + } + + return list2; +} + +function member(elem, list) { + for (const item of list) { + if (item === elem) { + return true; + } + } + + return false; +} + +function all(pred, list) { + for (const item of list) { + if (pred(item) === false) { + return false; + } + } + + return true; +} + +function any(pred, list) { + for (const item of list) { + if (pred(item) === true) { + return true; + } + } + + return false; +} + +function splitwith(pred, list) { + let switchToList2 = false; + const list1 = []; + const list2 = []; + + for (const item of list) { + if (switchToList2 === true) { + list2.push(item); + } else if (pred(item) === true) { + list1.push(item); + } else { + switchToList2 = true; + list2.push(item); + } + } + + return new ErlangTypes.Tuple(list1, list2); +} + +function sort(...args) { + if (args.length === 1) { + const list2 = [...args[0]]; + return list2.sort(); + } + + const fun = args[0]; + const list2 = [...args[1]]; + + return list2.sort((a, b) => { + const result = fun(a, b); + + if (result === true) { + return -1; + } + + return 1; + }); +} + +export default { + reverse, + foreach, + duplicate, + flatten, + foldl, + foldr, + keydelete, + keyfind, + keymember, + keyreplace, + keysort, + keystore, + keytake, + mapfoldl, + concat, + map, + filter, + filtermap, + member, + all, + any, + splitwith, + sort, +}; diff --git a/src/javascript/lib/core/erlang_compat/maps.js b/src/javascript/lib/core/erlang_compat/maps.js new file mode 100644 index 00000000..ec8b4e79 --- /dev/null +++ b/src/javascript/lib/core/erlang_compat/maps.js @@ -0,0 +1,238 @@ +// http://erlang.org/doc/man/maps.html +import ErlangTypes from 'erlang-types'; +import erlang from './erlang'; + +const OK = Symbol.for('ok'); +const ERROR = Symbol.for('error'); +const BADMAP = Symbol.for('badmap'); +const BADKEY = Symbol.for('badkey'); + +function is_non_primitive(key) { + return ( + erlang.is_list(key) || + erlang.is_map(key) || + erlang.is_pid(key) || + erlang.is_reference(key) || + erlang.is_bitstring(key) || + erlang.is_tuple(key) + ); +} + +function __put(map, key, value) { + const map2 = new Map(map); + + if (is_non_primitive(key)) { + for (const map_key of map.keys()) { + if (erlang.equals(map_key, key)) { + map2.set(map_key, value); + return map2; + } + } + } + + map2.set(key, value); + return map2; +} + +function __has(map, key) { + if (is_non_primitive(key)) { + for (const map_key of map.keys()) { + if (erlang.equals(map_key, key)) { + return true; + } + } + + return false; + } + + return map.has(key); +} + +function __get(map, key) { + if (is_non_primitive(key)) { + for (const map_key of map.keys()) { + if (erlang.equals(map_key, key)) { + return map.get(map_key); + } + } + + return null; + } + + return map.get(key); +} + +function __delete(map, key) { + if (is_non_primitive(key)) { + for (const map_key of map.keys()) { + if (erlang.equals(map_key, key)) { + map.delete(map_key); + } + } + } else { + map.delete(key); + } +} + +function find(key, map) { + if (erlang.is_map(map) === false) { + return new ErlangTypes.Tuple(BADMAP, map); + } + + const value = __get(map, key); + + if (typeof value !== 'undefined') { + return new ErlangTypes.Tuple(OK, value); + } + + return ERROR; +} + +function fold(fun, init, map) { + let acc = init; + + for (const [key, value] of map.entries()) { + acc = fun(key, value, acc); + } + + return acc; +} + +function remove(key, map1) { + if (erlang.is_map(map1) === false) { + return new ErlangTypes.Tuple(BADMAP, map1); + } + + const map2 = new Map(map1); + + __delete(map2, key); + + return map2; +} + +function to_list(map) { + if (erlang.is_map(map) === false) { + return new ErlangTypes.Tuple(BADMAP, map); + } + + const list = []; + + for (const [key, value] of map.entries()) { + list.push(new ErlangTypes.Tuple(key, value)); + } + + return list; +} + +function from_list(list) { + return list.reduce((acc, item) => { + const [key, value] = item; + acc.set(key, value); + + return acc; + }, new Map()); +} + +function keys(map) { + if (erlang.is_map(map) === false) { + return new ErlangTypes.Tuple(BADMAP, map); + } + + return Array.from(map.keys()); +} + +function values(map) { + if (erlang.is_map(map) === false) { + return new ErlangTypes.Tuple(BADMAP, map); + } + + return Array.from(map.values()); +} + +function is_key(key, map) { + return __has(map, key); +} + +function put(key, value, map1) { + if (erlang.is_map(map1) === false) { + return new ErlangTypes.Tuple(BADMAP, map1); + } + + return __put(map1, key, value); +} + +function merge(map1, map2) { + if (erlang.is_map(map1) === false) { + return new ErlangTypes.Tuple(BADMAP, map1); + } + + if (erlang.is_map(map2) === false) { + return new ErlangTypes.Tuple(BADMAP, map2); + } + + return new Map([...map1, ...map2]); +} + +function update(key, value, map1) { + if (erlang.is_map(map1) === false) { + return new ErlangTypes.Tuple(BADMAP, map1); + } + + if (is_key(key, map1) === false) { + return new ErlangTypes.Tuple(BADKEY, key); + } + + return new Map([...map1, [key, value]]); +} + +function get(...args) { + const key = args[0]; + const map = args[1]; + + if (erlang.is_map(map) === false) { + return new ErlangTypes.Tuple(BADMAP, map); + } + + if (is_key(key, map)) { + return __get(map, key); + } + + if (args.length === 3) { + return args[2]; + } + + return new ErlangTypes.Tuple(BADKEY, key); +} + +function take(key, map1) { + if (erlang.is_map(map1) === false) { + return new ErlangTypes.Tuple(BADMAP, map1); + } + + if (!is_key(key, map1)) { + return ERROR; + } + + const value = __get(map1, key); + const map2 = new Map(map1); + __delete(map2, key); + + return new ErlangTypes.Tuple(value, map2); +} + +export default { + find, + fold, + remove, + to_list, + from_list, + keys, + values, + is_key, + put, + merge, + update, + get, + take, + __has, +}; diff --git a/src/javascript/lib/core/erlang_compat/math.js b/src/javascript/lib/core/erlang_compat/math.js new file mode 100644 index 00000000..57a8275b --- /dev/null +++ b/src/javascript/lib/core/erlang_compat/math.js @@ -0,0 +1,7 @@ +function log2(x) { + return Math.log2(x); +} + +export default { + log2, +}; diff --git a/src/javascript/lib/core/erlang_compat/proplists.js b/src/javascript/lib/core/erlang_compat/proplists.js new file mode 100644 index 00000000..a9673774 --- /dev/null +++ b/src/javascript/lib/core/erlang_compat/proplists.js @@ -0,0 +1,25 @@ +import lists from './lists'; + +function get_value(key, list, defaultv = Symbol.for('undefined')) { + const tuple = lists.keyfind(key, 1, list); + if (tuple) { + const [, value] = tuple.values; + return value; + } else if (lists.member(key, list)) { + return true; + } + return defaultv; +} + +function is_defined(key, list) { + const tuple = lists.keyfind(key, 1, list); + if (tuple) { + return true; + } + return false; +} + +export default { + get_value, + is_defined, +}; diff --git a/src/javascript/lib/core/erlang_compat/unicode.js b/src/javascript/lib/core/erlang_compat/unicode.js new file mode 100644 index 00000000..f4f4083e --- /dev/null +++ b/src/javascript/lib/core/erlang_compat/unicode.js @@ -0,0 +1,33 @@ +import erlang from './erlang'; +import lists from './lists'; + +function characters_to_list(characters, inEncoding = Symbol.for('unicode')) { + let values = characters; + + if (Array.isArray(characters)) { + values = lists.flatten(characters); + } + + if (erlang.is_binary(values)) { + return values.split('').map(c => c.codePointAt(0)); + } + + return values.reduce((acc, c) => { + if (erlang.is_integer(c)) { + return acc.concat(c); + } + + return acc.concat(characters_to_list(c, inEncoding)); + }, []); +} + +function characters_to_binary(characters) { + const values = characters_to_list(characters); + + return String.fromCodePoint(...values); +} + +export default { + characters_to_list, + characters_to_binary, +}; diff --git a/src/javascript/lib/core/functions.js b/src/javascript/lib/core/functions.js index 4ba9945f..91bf31e7 100644 --- a/src/javascript/lib/core/functions.js +++ b/src/javascript/lib/core/functions.js @@ -1,14 +1,41 @@ -import Protocol from "./protocol"; -import Core from "../core"; +import GraphemeSplitter from 'grapheme-splitter'; +import Protocol from './protocol'; +import Core from '../core'; +import proplists from './erlang_compat/proplists'; +import erlang from './erlang_compat/erlang'; function call_property(item, property) { + if (!property) { + if (item instanceof Function || typeof item === 'function') { + return item(); + } + + return item; + } + + if (item instanceof Map) { + let prop = null; + + if (item.has(property)) { + prop = property; + } else if (item.has(Symbol.for(property))) { + prop = Symbol.for(property); + } + + if (prop === null) { + throw new Error(`Property ${property} not found in ${item}`); + } + + return item.get(prop); + } + let prop = null; if ( - typeof item === "number" || - typeof item === "symbol" || - typeof item === "boolean" || - typeof item === "string" + typeof item === 'number' || + typeof item === 'symbol' || + typeof item === 'boolean' || + typeof item === 'string' ) { if (item[property] !== undefined) { prop = property; @@ -25,78 +52,12 @@ function call_property(item, property) { throw new Error(`Property ${property} not found in ${item}`); } - if (item[prop] instanceof Function) { + if (item[prop] instanceof Function || typeof item[prop] === 'function') { return item[prop](); } return item[prop]; } -function apply(...args) { - if (args.length === 2) { - return args[0].apply(args[0], args.slice(1)); - } else { - return args[0][args[1]].apply(args[0], args.slice(2)); - } -} - -function contains(left, right) { - for (const x of right) { - if (Core.Patterns.match_or_default(left, x) != null) { - return true; - } - } - - return false; -} - -function get_global() { - if (typeof self !== "undefined") { - return self; - } else if (typeof window !== "undefined") { - return window; - } else if (typeof global !== "undefined") { - return global; - } - - throw new Error("No global state found"); -} - -function defstruct(defaults) { - return class { - constructor(update = {}) { - const the_values = Object.assign(defaults, update); - Object.assign(this, the_values); - } - - static create(updates = {}) { - const x = new this(updates); - return Object.freeze(x); - } - }; -} - -function defexception(defaults) { - return class extends Error { - constructor(update = {}) { - const message = update.message || ""; - super(message); - - const the_values = Object.assign(defaults, update); - Object.assign(this, the_values); - - this.name = this.constructor.name; - this.message = message; - this[Symbol.for("__exception__")] = true; - Error.captureStackTrace(this, this.constructor.name); - } - - static create(updates = {}) { - const x = new this(updates); - return Object.freeze(x); - } - }; -} - function defprotocol(spec) { return new Protocol(spec); } @@ -105,335 +66,158 @@ function defimpl(protocol, type, impl) { protocol.implementation(type, impl); } -function get_object_keys(obj) { - return Object.keys(obj).concat(Object.getOwnPropertySymbols(obj)); -} +function build_namespace(ns, ns_string) { + let parts = ns_string.split('.'); + const root = ns; + let parent = ns; -function is_valid_character(codepoint) { - try { - return String.fromCodePoint(codepoint) != null; - } catch (e) { - return false; + if (parts[0] === 'Elixir') { + parts = parts.slice(1); } -} - -// https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#Solution_2_%E2%80%93_rewrite_the_DOMs_atob()_and_btoa()_using_JavaScript's_TypedArrays_and_UTF-8 -function b64EncodeUnicode(str) { - return btoa( - encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (match, p1) => - String.fromCharCode(`0x${p1}`)) - ); -} -function delete_property_from_map(map, property) { - const new_map = Object.assign(Object.create(map.constructor.prototype), map); - delete new_map[property]; - - return Object.freeze(new_map); -} - -function class_to_obj(map) { - const new_map = Object.assign({}, map); - return Object.freeze(new_map); -} - -function add_property_to_map(map, property, value) { - const new_map = Object.assign({}, map); - new_map[property] = value; - return Object.freeze(new_map); -} + for (const part of parts) { + if (typeof parent[part] === 'undefined') { + parent[part] = {}; + } -function update_map(map, property, value) { - if (property in get_object_keys(map)) { - return add_property_to_map(map, property, value); + parent = parent[part]; } - throw "map does not have key"; -} - -function bnot(expr) { - return ~expr; -} - -function band(left, right) { - return left & right; -} - -function bor(left, right) { - return left | right; -} + root.__table__ = ns.__table__ || {}; + root.__table__[Symbol.for(ns_string)] = parent; -function bsl(left, right) { - return left << right; -} - -function bsr(left, right) { - return left >> right; -} - -function bxor(left, right) { - return left ^ right; + return parent; } -function zip(list_of_lists) { - if (list_of_lists.length === 0) { - return Object.freeze([]); - } +function map_to_object(map, options = []) { + const opt_keys = proplists.get_value(Symbol.for('keys'), options); + const opt_symbols = proplists.get_value(Symbol.for('symbols'), options); - const new_value = []; - let smallest_length = list_of_lists[0]; + const object = {}; - for (const x of list_of_lists) { - if (x.length < smallest_length) { - smallest_length = x.length; - } - } + for (const entry of map.entries()) { + let key = entry[0]; + const value = entry[1]; - for (let i = 0; i < smallest_length; i++) { - const current_value = []; - for (let j = 0; j < list_of_lists.length; j++) { - current_value.push(list_of_lists[j][i]); + if (opt_keys === Symbol.for('string') && typeof key === 'number') { + key = key.toString(); + } else if ( + (opt_keys === Symbol.for('string') || opt_symbols !== Symbol.for('undefined')) && + typeof key === 'symbol' + ) { + key = erlang.atom_to_binary(key); } - new_value.push(new Core.Tuple(...current_value)); - } - - return Object.freeze(new_value); -} - -function can_decode64(data) { - try { - atob(data); - return true; - } catch (e) { - return false; - } -} - -function remove_from_list(list, element) { - let found = false; - - return list.filter(elem => { - if (!found && elem === element) { - found = true; - return false; + if (value instanceof Map) { + object[key] = map_to_object(value, options); + } else if (opt_symbols !== Symbol.for('undefined') && typeof value === 'symbol') { + object[key] = erlang.atom_to_binary(value); + } else { + object[key] = value; } - - return true; - }); -} - -function foldl(fun, acc, list) { - let acc1 = acc; - - for (const el of list) { - acc1 = fun(el, acc1); } - return acc1; + return object; } -function foldr(fun, acc, list) { - let acc1 = acc; +function object_to_map(object, options = []) { + const opt_atom_keys = proplists.get_value(Symbol.for('keys'), options) === Symbol.for('atom'); + const opt_recurse_array = proplists.get_value(Symbol.for('recurse_array'), options) === true; - for (let i = list.length - 1; i >= 0; i--) { - acc1 = fun(list[i], acc1); - } - - return acc1; -} + if (object.constructor === Object) { + const map = new Map(); + Reflect.ownKeys(object).forEach((key) => { + let key2 = key; + let value = object[key]; + if (opt_atom_keys && typeof key === 'string') { + key2 = Symbol.for(key); + } -function keyfind(key, n, tuplelist) { - for (let i = tuplelist.length - 1; i >= 0; i--) { - if (tuplelist[i].get(n) === key) { - return tuplelist[i]; - } + if ( + value !== null && + (value.constructor === Object || (value instanceof Array && opt_recurse_array)) + ) { + value = object_to_map(value, options); + } + map.set(key2, value); + }); + return map; + } else if (object instanceof Array && opt_recurse_array) { + return object.map((ele) => { + if (ele !== null && (ele.constructor === Object || ele instanceof Array)) { + return object_to_map(ele, options); + } + return ele; + }); } - - return false; + throw new Error(`Object ${object} is not an native object or array`); } -function keydelete(key, n, tuplelist) { - for (let i = tuplelist.length - 1; i >= 0; i--) { - if (tuplelist[i].get(n) === key) { - return tuplelist.concat([]).splice(i, 1); - } +class Recurse { + constructor(func) { + this.func = func; } - - return tuplelist; } -function keystore(key, n, list, newtuple) { - for (let i = list.length - 1; i >= 0; i--) { - if (list[i].get(n) === key) { - return list.concat([]).splice(i, 1, newtuple); - } - } +function trampoline(f) { + let currentValue = f; - return list.concat([]).push(newtuple); -} - -function keymember(key, n, list) { - for (let i = list.length - 1; i >= 0; i--) { - if (list[i].get(n) === key) { - return true; - } + while (currentValue && currentValue instanceof Recurse) { + currentValue = currentValue.func(); } - return false; + return currentValue; } -function keytake(key, n, list) { - if (!keymember(key, n, list)) { - return false; - } +function split_at(value, position) { + const splitter = new GraphemeSplitter(); + const splitValues = splitter.splitGraphemes(value); - const tuple = keyfind(key, n, list); - - return new Core.Tuple(tuple.get(n), tuple, keydelete(key, n, list)); -} - -function keyreplace(key, n, list, newtuple) { - for (let i = list.length - 1; i >= 0; i--) { - if (list[i].get(n) === key) { - return list.concat([]).splice(i, 1, newtuple); + if (position < 0) { + const newPosition = splitValues.length + position; + if (newPosition < 0) { + return new Core.Tuple('', value); } - } - - return list; -} - -function reverse(list) { - return list.concat([]).reverse(); -} -function maps_find(key, map) { - if (key in get_object_keys(map)) { - return new Core.Tuple(Symbol.for("ok"), map[key]); + return split_at(value, newPosition); } - return Symbol.for("error"); -} -function flatten(list, tail = []) { - let new_list = []; + let first = ''; + let second = ''; + let index = 0; - for (const e of list) { - if (Array.isArray(e)) { - new_list = new_list.concat(flatten(e)); + for (const character of splitValues) { + if (index < position) { + first += character; } else { - new_list.push(e); + second += character; } - } - - return Object.freeze(new_list.concat(tail)); -} - -function duplicate(n, elem) { - const list = []; - - for (let i = 0; i < n; i++) { - list.push(elem); - } - - return Object.freeze(list); -} -function mapfoldl(fun, acc, list) { - const newlist = []; - let new_acc = acc; - - for (const x of list) { - const tup = fun(x, new_acc); - newlist.push(tup.get(0)); - new_acc = tup.get(1); - } - - return new Core.Tuple(Object.freeze(newlist), new_acc); -} - -function filtermap(fun, list) { - const newlist = []; - - for (const x of list) { - const result = fun(x); - - if (result === true) { - newlist.push(x); - } else if (result instanceof Core.Tuple) { - newlist.push(result.get(1)); - } + index += 1; } - return Object.freeze(newlist); + return new Core.Tuple(first, second); } -function maps_fold(fun, acc, map) { - let acc1 = acc; - - for (const k of get_object_keys(map)) { - acc1 = fun(k, map[k], acc1); - } - - return acc1; +function graphemes(str) { + const splitter = new GraphemeSplitter(); + return splitter.splitGraphemes(str); } -function build_namespace(ns, ns_string) { - let parts = ns_string.split("."); - let parent = ns; - - if (parts[0] === "Elixir") { - parts = parts.slice(1); - } - - for (const part of parts) { - if (typeof parent[part] === "undefined") { - parent[part] = {}; - } - - parent = parent[part]; - } - - return parent; +function concat(head, tail) { + return [head].concat(tail); } export default { call_property, - apply, - contains, - get_global, - defstruct, - defexception, defprotocol, defimpl, - get_object_keys, - is_valid_character, - b64EncodeUnicode, - delete_property_from_map, - add_property_to_map, - class_to_obj, - can_decode64, - bnot, - band, - bor, - bsl, - bsr, - bxor, - zip, - foldl, - foldr, - remove_from_list, - keydelete, - keystore, - keyfind, - keytake, - keyreplace, - reverse, - update_map, - maps_find, - flatten, - duplicate, - mapfoldl, - filtermap, - maps_fold, - build_namespace + build_namespace, + map_to_object, + object_to_map, + trampoline, + Recurse, + split_at, + graphemes, + concat, }; diff --git a/src/javascript/lib/core/protocol.js b/src/javascript/lib/core/protocol.js index 936fc59e..15466ed8 100644 --- a/src/javascript/lib/core/protocol.js +++ b/src/javascript/lib/core/protocol.js @@ -6,16 +6,14 @@ class Protocol { this.registry = new Map(); this.fallback = null; - for (const funName in spec) { - this[funName] = createFun(funName).bind(this); - } - function createFun(funName) { return function (...args) { const thing = args[0]; let fun = null; - if (Number.isInteger(thing) && this.hasImplementation(Core.Integer)) { + if (thing === null && this.hasImplementation(Symbol('null'))) { + fun = this.registry.get(Symbol)[funName]; + } else if (Number.isInteger(thing) && this.hasImplementation(Core.Integer)) { fun = this.registry.get(Core.Integer)[funName]; } else if ( typeof thing === 'number' && @@ -23,11 +21,16 @@ class Protocol { this.hasImplementation(Core.Float) ) { fun = this.registry.get(Core.Float)[funName]; + } else if (typeof thing === 'string' && this.hasImplementation(Core.BitString)) { + fun = this.registry.get(Core.BitString)[funName]; } else if ( - typeof thing === 'string' && this.hasImplementation(Core.BitString) + thing && + thing instanceof Map && + thing.has(Symbol.for('__struct__')) && + this.hasImplementation(thing) ) { - fun = this.registry.get(Core.BitString)[funName]; - } else if (this.hasImplementation(thing)) { + fun = this.registry.get(thing.get(Symbol.for('__struct__')).__MODULE__)[funName]; + } else if (thing !== null && this.hasImplementation(thing)) { fun = this.registry.get(thing.constructor)[funName]; } else if (this.fallback) { fun = this.fallback[funName]; @@ -41,6 +44,10 @@ class Protocol { throw new Error(`No implementation found for ${thing}`); }; } + + for (const funName in spec) { + this[funName] = createFun(funName).bind(this); + } } implementation(type, implementation) { @@ -52,10 +59,10 @@ class Protocol { } hasImplementation(thing) { - if ( - thing === Core.Integer || thing === Core.Float || thing === Core.BitString - ) { + if (thing === Core.Integer || thing === Core.Float || thing === Core.BitString) { return this.registry.has(thing); + } else if (thing && thing instanceof Map && thing.has(Symbol.for('__struct__'))) { + return this.registry.has(thing.get(Symbol.for('__struct__')).__MODULE__); } return this.registry.has(thing.constructor); diff --git a/src/javascript/lib/core/special_forms.js b/src/javascript/lib/core/special_forms.js index faac7e94..7721612b 100644 --- a/src/javascript/lib/core/special_forms.js +++ b/src/javascript/lib/core/special_forms.js @@ -4,7 +4,7 @@ function _case(condition, clauses) { return Core.Patterns.defmatch(...clauses)(condition); } -function cond(clauses) { +function cond(...clauses) { for (const clause of clauses) { if (clause[0]) { return clause[1](); @@ -14,31 +14,8 @@ function cond(clauses) { throw new Error(); } -function map_update(map, values) { - return Object.freeze( - Object.assign(Object.create(map.constructor.prototype), map, values), - ); -} - -function _for(expression, generators, collectable_protocol, into = []) { - let [result, fun] = collectable_protocol.into(into); - - const generatedValues = run_list_generators(generators.pop()(), generators); - - for (const value of generatedValues) { - if (expression.guard.apply(this, value)) { - result = fun(result, new Core.Tuple( - Symbol.for('cont'), - expression.fn.apply(this, value), - )); - } - } - - return fun(result, Symbol.for('done')); -} - function run_list_generators(generator, generators) { - if (generators.length == 0) { + if (generators.length === 0) { return generator.map((x) => { if (Array.isArray(x)) { return x; @@ -58,28 +35,43 @@ function run_list_generators(generator, generators) { return run_list_generators(next_gen, generators); } -function _try( - do_fun, - rescue_function, - catch_fun, - else_function, - after_function, -) { +function _for(expression, generators, collectable_protocol, into = []) { + const [result, fun] = collectable_protocol.into(into); + let accumulatingResult = result; + + const generatedValues = run_list_generators(generators.pop()(), generators); + + for (const value of generatedValues) { + if (expression.guard.apply(this, value)) { + accumulatingResult = fun( + accumulatingResult, + new Core.Tuple(Symbol.for('cont'), expression.fn.apply(this, value)), + ); + } + } + + return fun(accumulatingResult, Symbol.for('done')); +} + +function _try(do_fun, rescue_function, catch_fun, else_function, after_function) { let result = null; try { result = do_fun(); } catch (e) { let ex_result = null; - if (rescue_function) { try { - ex_result = rescue_function(e); + let value = e; + if (e.__reason) { + value = e.__reason; + value.set('__reason', e.__reason); + } + + ex_result = rescue_function(value); return ex_result; } catch (ex) { - if (ex instanceof Core.Patterns.MatchError) { - throw ex; - } + throw ex; } } @@ -88,9 +80,7 @@ function _try( ex_result = catch_fun(e); return ex_result; } catch (ex) { - if (ex instanceof Core.Patterns.MatchError) { - throw ex; - } + throw ex; } } @@ -140,17 +130,46 @@ function _with(...args) { } return result; } + argsToPass = argsToPass.concat(patternResult); } return successFunction(...argsToPass); } +function receive(clauses, timeout = 0, timeoutFn = () => true) { + /* It's more important to warn developers than follow style guides */ + /* eslint-disable no-console */ + console.warn('Receive not supported'); + /* eslint-enable no-console */ + + const messages = []; // this.mailbox.get(); + const NOMATCH = Symbol('NOMATCH'); + + for (let i = 0; i < messages.length; i++) { + for (const clause of clauses) { + const value = Core.Patterns.match_or_default( + clause.pattern, + messages[i], + clause.guard, + NOMATCH, + ); + + if (value !== NOMATCH) { + this.mailbox.removeAt(i); + return clause.fn.apply(null, value); + } + } + } + + return null; +} + export default { _case, cond, - map_update, _for, _try, _with, + receive, }; diff --git a/src/javascript/lib/core/store.js b/src/javascript/lib/core/store.js index bf8aa04a..231334eb 100644 --- a/src/javascript/lib/core/store.js +++ b/src/javascript/lib/core/store.js @@ -1,46 +1,47 @@ -const store = new Map(); -const names = new Map(); +import Core from '../core'; function get_key(key) { let real_key = key; - if (names.has(key)) { - real_key = names.get(key); + if (Core.global.__elixirscript_names__.has(key)) { + real_key = Core.global.__elixirscript_names__.get(key); } - if (store.has(real_key)) { + if (Core.global.__elixirscript_store__.has(real_key)) { return real_key; } - return new Error('Key Not Found'); + throw new Error(`Key ${real_key} not found`); } -function create(key, value, name = null) { - if (name != null) { - names.set(name, key); +function create(value, name = null) { + const key = new Core.PID(); + + if (name !== null) { + Core.global.__elixirscript_names__.set(name, key); } - store.set(key, value); + return Core.global.__elixirscript_store__.set(key, value); } function update(key, value) { const real_key = get_key(key); - store.set(real_key, value); + return Core.global.__elixirscript_store__.set(real_key, value); } function read(key) { const real_key = get_key(key); - return store.get(real_key); + return Core.global.__elixirscript_store__.get(real_key); } function remove(key) { const real_key = get_key(key); - return store.delete(real_key); + return Core.global.__elixirscript_store__.delete(real_key); } export default { create, - read, update, + read, remove, }; diff --git a/src/javascript/lib/enum.js b/src/javascript/lib/enum.js deleted file mode 100644 index 13916e50..00000000 --- a/src/javascript/lib/enum.js +++ /dev/null @@ -1,203 +0,0 @@ -import Core from './core'; - -let Enum = { - - all__qmark__: function(collection, fun = (x) => x){ - for(let elem of collection){ - if(!fun(elem)){ - return false; - } - } - - return true; - }, - - any__qmark__: function(collection, fun = (x) => x){ - for(let elem of collection){ - if(fun(elem)){ - return true; - } - } - - return false; - }, - - at: function(collection, n, the_default = null){ - if(n > this.count(collection) || n < 0){ - return the_default; - } - - return collection[n]; - }, - - concat: function(...enumables){ - return enumables[0].concat(enumables[1]); - }, - - count: function(collection, fun = null){ - if(fun == null){ - return collection.length; - } else { - return collection.filter(fun).length; - } - }, - - drop: function(collection, count){ - return collection.slice(count); - }, - - drop_while: function(collection, fun){ - let count = 0; - - for(let elem of collection){ - if(fun(elem)){ - count = count + 1; - }else{ - break; - } - } - - return collection.slice(count); - }, - - each: function(collection, fun){ - for(let elem of collection){ - fun(elem); - } - }, - - empty__qmark__: function(collection){ - return collection.length === 0; - }, - - fetch: function(collection, n){ - if(Array.isArray(collection)){ - if(n < this.count(collection) && n >= 0){ - return new Core.Tuple(Symbol.for("ok"), collection[n]); - }else{ - return Symbol.for("error"); - } - } - - throw new Error("collection is not an Enumerable"); - }, - - fetch__emark__: function(collection, n){ - if(Array.isArray(collection)){ - if(n < this.count(collection) && n >= 0){ - return collection[n]; - }else{ - throw new Error("out of bounds error"); - } - } - - throw new Error("collection is not an Enumerable"); - }, - - filter: function(collection, fun){ - let result = []; - - for(let elem of collection){ - if(fun(elem)){ - result.push(elem); - } - } - - return result; - }, - - filter_map: function(collection, filter, mapper){ - return Enum.map(Enum.filter(collection, filter), mapper); - }, - - find: function(collection, if_none = null, fun){ - for(let elem of collection){ - if(fun(elem)){ - return elem; - } - } - - return if_none; - }, - - into: function(collection, list){ - return list.concat(collection); - }, - - map: function(collection, fun){ - let result = []; - - for(let elem of collection){ - result.push(fun(elem)); - } - - return result; - }, - - map_reduce: function(collection, acc, fun){ - let mapped = Object.freeze([]); - let the_acc = acc; - - for (var i = 0; i < this.count(collection); i++) { - let tuple = fun(collection[i], the_acc); - - the_acc = tuple.get(1); - mapped = Object.freeze(mapped.concat([tuple.get(0)])); - } - - return new Core.Tuple(mapped, the_acc); - }, - - member__qmark__: function(collection, value){ - return collection.includes(value); - }, - - reduce: function(collection, acc, fun){ - let the_acc = acc; - - for (var i = 0; i < this.count(collection); i++) { - let tuple = fun(collection[i], the_acc); - - the_acc = tuple.get(1); - } - - return the_acc; - }, - - take: function(collection, count){ - return collection.slice(0, count); - }, - - take_every: function(collection, nth){ - let result = []; - let index = 0; - - for(let elem of collection){ - if(index % nth === 0){ - result.push(elem); - } - } - - return Object.freeze(result); - }, - - take_while: function(collection, fun){ - let count = 0; - - for(let elem of collection){ - if(fun(elem)){ - count = count + 1; - }else{ - break; - } - } - - return collection.slice(0, count); - }, - - to_list: function(collection){ - return collection; - } -}; - -export default Enum; diff --git a/src/javascript/tests/case.spec.js b/src/javascript/tests/case.spec.js index 963c8f0a..8715ae11 100644 --- a/src/javascript/tests/case.spec.js +++ b/src/javascript/tests/case.spec.js @@ -1,32 +1,21 @@ -import Core from "../lib/core"; +import test from 'ava'; +import Core from '../lib/core'; + const Patterns = Core.Patterns; const SpecialForms = Core.SpecialForms; const Tuple = Core.Tuple; -import Enum from "../lib/enum"; - -import chai from 'chai'; -var expect = chai.expect; - - -describe('case', () => { - - it('case', () => { - let clauses = [ - Patterns.clause( - [new Tuple(Symbol.for("selector"), Patterns.variable(), Patterns.variable())], - function(i, value){ return value; }, - function(i){ return Kernel.is_integer(i); } - ), - Patterns.clause( - [Patterns.variable()], - function(value){ return value; } - ) - ]; - - let result = SpecialForms._case("thing", clauses); +test('case', (t) => { + const clauses = [ + Patterns.clause( + [new Tuple(Symbol.for('selector'), Patterns.variable(), Patterns.variable())], + (i, value) => value, + i => Kernel.is_integer(i), + ), + Patterns.clause([Patterns.variable()], value => value), + ]; - expect(result).to.equal("thing"); - }); + const result = SpecialForms._case('thing', clauses); + t.is(result, 'thing'); }); diff --git a/src/javascript/tests/cond.spec.js b/src/javascript/tests/cond.spec.js index 2fea8baa..f1a09736 100644 --- a/src/javascript/tests/cond.spec.js +++ b/src/javascript/tests/cond.spec.js @@ -1,25 +1,16 @@ -import Core from "../lib/core"; -const Patterns = Core.Patterns; -const SpecialForms = Core.SpecialForms; - -import Enum from "../lib/enum"; - -import chai from 'chai'; -var expect = chai.expect; +import test from 'ava'; +import Core from '../lib/core'; +const SpecialForms = Core.SpecialForms; -describe('cond', () => { - - it('cond', () => { - let clauses = [ - [ 1 + 1 == 1, () => "This will never match"], - [ 2 * 2 != 4, () => "Nor this"], - [ true, () => "This will"], - ]; - - let result = SpecialForms.cond(clauses); +test('cond', (t) => { + const clauses = [ + [1 + 1 === 1, () => 'This will never match'], + [2 * 2 !== 4, () => 'Nor this'], + [true, () => 'This will'], + ]; - expect(result).to.equal("This will"); - }); + const result = SpecialForms.cond(...clauses); + t.is(result, 'This will'); }); diff --git a/src/javascript/tests/core/erlang_compat/binary_spec.js b/src/javascript/tests/core/erlang_compat/binary_spec.js new file mode 100644 index 00000000..2bef01af --- /dev/null +++ b/src/javascript/tests/core/erlang_compat/binary_spec.js @@ -0,0 +1,67 @@ +import test from 'ava'; +import Core from '../../../lib/core'; + +test('at/1', (t) => { + const result = Core.binary.at('abc', 0); + t.deepEqual(result, 'a'); +}); + +test('copy/1', (t) => { + const result = Core.binary.copy('h'); + t.deepEqual(result, 'h'); +}); + +test('copy/2', (t) => { + const result = Core.binary.copy('h', 3); + t.deepEqual(result, 'hhh'); +}); + +test('first/1', (t) => { + const result = Core.binary.first('abc'); + t.deepEqual(result, 'a'); +}); + +test('last/1', (t) => { + const result = Core.binary.last('abc'); + t.deepEqual(result, 'c'); +}); + +test('list_to_bin/1', (t) => { + const result = Core.binary.list_to_bin([104, 101, 108, 108, 111]); + t.deepEqual(result, 'hello'); +}); + +test('part/2', (t) => { + let posLen = new Core.Tuple(1, 1); + let result = Core.binary.part('abcde', posLen); + t.deepEqual(result, 'b'); + + posLen = new Core.Tuple(1, 3); + result = Core.binary.part('abcde', posLen); + t.deepEqual(result, 'bcd'); +}); + +test('part/3', (t) => { + let result = Core.binary.part('abcde', 1, 1); + t.deepEqual(result, 'b'); + + result = Core.binary.part('abcde', 1, 3); + t.deepEqual(result, 'bcd'); +}); + +test('replace/3', (t) => { + const result = Core.binary.replace('abcb', 'b', 'c'); + t.deepEqual(result, 'accb'); +}); + +test('replace/4', (t) => { + const result = Core.binary.replace('abcb', 'b', 'c', [ + new Core.Tuple(Symbol.for('global'), true), + ]); + t.deepEqual(result, 'accc'); +}); + +test('split/2', (t) => { + const result = Core.binary.split('abcd', 'b'); + t.deepEqual(result, ['a', 'cd']); +}); diff --git a/src/javascript/tests/core/erlang_compat/elixir_errors_spec.js b/src/javascript/tests/core/erlang_compat/elixir_errors_spec.js new file mode 100644 index 00000000..c4cc10cd --- /dev/null +++ b/src/javascript/tests/core/erlang_compat/elixir_errors_spec.js @@ -0,0 +1,7 @@ +import test from 'ava'; +import Core from '../../../lib/core'; + +test('warn', (t) => { + const result = Core.elixir_errors.warn(['this is a warning']); + t.deepEqual(result, Symbol.for('ok')); +}); diff --git a/src/javascript/tests/core/erlang_compat/erlang_spec.js b/src/javascript/tests/core/erlang_compat/erlang_spec.js new file mode 100644 index 00000000..6e41e6ea --- /dev/null +++ b/src/javascript/tests/core/erlang_compat/erlang_spec.js @@ -0,0 +1,165 @@ +import test from 'ava'; +import Core from '../../../lib/core'; + +test('is_atom', (t) => { + t.is(Core.erlang.is_atom(null), true); + t.is(Core.erlang.is_atom(true), true); + t.is(Core.erlang.is_atom(false), true); + t.is(Core.erlang.is_atom(Symbol.for('error')), true); + t.is(Core.erlang.is_atom('Hello'), false); +}); + +test('is_boolean', (t) => { + t.is(Core.erlang.is_boolean(null), false); + t.is(Core.erlang.is_boolean(true), true); + t.is(Core.erlang.is_boolean(false), true); + t.is(Core.erlang.is_boolean(Symbol.for('error')), false); + t.is(Core.erlang.is_boolean('Hello'), false); +}); + +test('is_number', (t) => { + t.is(Core.erlang.is_number(null), false); + t.is(Core.erlang.is_number(1), true); + t.is(Core.erlang.is_number(2.3), true); + t.is(Core.erlang.is_number(Symbol.for('error')), false); + t.is(Core.erlang.is_number('Hello'), false); +}); + +test('is_float', (t) => { + t.is(Core.erlang.is_float(null), false); + t.is(Core.erlang.is_float(1), false); + t.is(Core.erlang.is_float(2.3), true); + t.is(Core.erlang.is_float(Symbol.for('error')), false); + t.is(Core.erlang.is_float('Hello'), false); +}); + +test('is_integer', (t) => { + t.is(Core.erlang.is_integer(null), false); + t.is(Core.erlang.is_integer(1), true); + t.is(Core.erlang.is_integer(2.3), false); + t.is(Core.erlang.is_integer(Symbol.for('error')), false); + t.is(Core.erlang.is_integer('Hello'), false); +}); + +test('is_function', (t) => { + t.is(Core.erlang.is_function(null), false); + t.is(Core.erlang.is_function(Math.max), true); + t.is(Core.erlang.is_function(2.3), false); + t.is(Core.erlang.is_function(Symbol.for('error')), false); + t.is(Core.erlang.is_function(() => 'hello'), true); +}); + +test('is_list', (t) => { + t.is(Core.erlang.is_list(null), false); + t.is(Core.erlang.is_list([]), true); + t.is(Core.erlang.is_list(2.3), false); + t.is(Core.erlang.is_list(Symbol.for('error')), false); + t.is(Core.erlang.is_list(() => 'hello'), false); +}); + +test('atom_to_binary', (t) => { + t.is(Core.erlang.atom_to_binary(Symbol.for('error')), 'error'); + t.is(Core.erlang.atom_to_binary(Symbol.for('error'), Symbol.for('utf8')), 'error'); + + t.is(Core.erlang.atom_to_binary(null, Symbol.for('utf8')), 'nil'); + + t.is(Core.erlang.atom_to_binary(true, Symbol.for('utf8')), 'true'); + t.is(Core.erlang.atom_to_binary(false, Symbol.for('utf8')), 'false'); + + t.throws(() => Core.erlang.atom_to_binary(Symbol.for('error'), Symbol.for('utf16')), Error); +}); + +test('list_concatenation', (t) => { + t.deepEqual(Core.erlang.list_concatenation([], []), []); + t.deepEqual(Core.erlang.list_concatenation([1], []), [1]); + t.deepEqual(Core.erlang.list_concatenation([1, 2, 3], [4, 5, 6]), [1, 2, 3, 4, 5, 6]); +}); + +test('list_subtraction', (t) => { + t.deepEqual(Core.erlang.list_subtraction([], []), []); + t.deepEqual(Core.erlang.list_subtraction([1], []), [1]); + t.deepEqual(Core.erlang.list_subtraction([1, 2, 3], [4, 5, 6]), [1, 2, 3]); + t.deepEqual(Core.erlang.list_subtraction([1, 2, 3], [1, 2, 3]), []); + t.deepEqual(Core.erlang.list_subtraction([1, 2, 3], [1, 2]), [3]); +}); + +test('node', (t) => { + t.deepEqual(Core.erlang.node(), Symbol.for('nonode@nohost')); +}); + +test('nodes/0', (t) => { + t.deepEqual(Core.erlang.nodes(), []); +}); + +test('nodes/1', (t) => { + t.deepEqual(Core.erlang.nodes(Symbol.for('this')), [Symbol.for('nonode@nohost')]); + + t.deepEqual(Core.erlang.nodes([Symbol.for('this')]), [Symbol.for('nonode@nohost')]); + + t.deepEqual(Core.erlang.nodes([Symbol.for('connected')]), []); +}); + +test('equals', (t) => { + t.is(Core.erlang.equals(1, 1), true); + t.is(Core.erlang.equals(1, 'a'), false); + t.is(Core.erlang.equals('a', 'a'), true); + t.is(Core.erlang.equals('a', 'b'), false); + t.is(Core.erlang.equals(Symbol.for('this'), Symbol.for('this')), true); + t.is(Core.erlang.equals([], []), true); + t.is(Core.erlang.equals([1], []), false); + t.is( + Core.erlang.equals( + new Map([[Symbol.for('nest1'), 'valuenest1']]), + new Map([[Symbol.for('nest2'), 'valuenest2']]), + ), + false, + ); + t.is( + Core.erlang.equals( + new Map([[Symbol.for('nest1'), 'valuenest1']]), + new Map([[Symbol.for('nest1'), 'valuenest1']]), + ), + true, + ); + t.is(Core.erlang.equals(new Core.Tuple('abc'), new Core.Tuple('abc')), true); + t.is(Core.erlang.equals(new Core.Tuple('abc'), new Core.Tuple('abc', 's')), false); + + const pid = new Core.PID(); + t.is(Core.erlang.equals(pid, pid), true); + t.is(Core.erlang.equals(pid, new Core.PID()), false); + + const ref = new Core.Reference(); + t.is(Core.erlang.equals(ref, ref), true); + t.is(Core.erlang.equals(ref, new Core.Reference()), false); +}); + +test('error/1', (t) => { + let error = t.throws(() => { + Core.erlang.error( + new Map([ + [Symbol.for('__exception__'), true], + [Symbol.for('message'), 'hi'], + [ + Symbol.for('__struct__'), + { + __MODULE__: Symbol.for('Elixir.ArgumentError'), + }, + ], + ]), + ); + }, Error); + + t.is(error.message, '** (ArgumentError) hi'); + + error = t.throws(() => { + Core.erlang.error('hi'); + }, Error); + + t.is(error.message, '** (RuntimeError) hi'); + + error = t.throws(() => { + Core.erlang.error(new Core.Tuple('abc', 's')); + }, Error); + + t.is(error.message, '** (ErlangError) Erlang Error {abc, s}'); +}); diff --git a/src/javascript/tests/core/erlang_compat/filename_spec.js b/src/javascript/tests/core/erlang_compat/filename_spec.js new file mode 100644 index 00000000..98bc1ab3 --- /dev/null +++ b/src/javascript/tests/core/erlang_compat/filename_spec.js @@ -0,0 +1,32 @@ +import test from 'ava'; +import Core from '../../../lib/core'; + +test('dirname/1', (t) => { + let result = Core.filename.dirname('/usr/src/kalle.erl'); + t.is(result, '/usr/src'); + + result = Core.filename.dirname('usr/kalle.erl'); + t.is(result, 'usr'); + + result = Core.filename.dirname('kalle.erl'); + t.is(result, '.'); + + result = Core.filename.dirname('/kalle.erl'); + t.is(result, '/'); +}); + +test('join/1', (t) => { + let result = Core.filename.join(['/usr', 'local', 'bin']); + t.is(result, '/usr/local/bin'); + + result = Core.filename.join(['a', '///b/', 'c/']); + t.is(result, '/b/c'); + + result = Core.filename.join(['a/b///c/']); + t.is(result, 'a/b/c'); +}); + +test('join/2', (t) => { + const result = Core.filename.join('/usr', 'bin'); + t.is(result, '/usr/bin'); +}); diff --git a/src/javascript/tests/core/erlang_compat/io_spec.js b/src/javascript/tests/core/erlang_compat/io_spec.js new file mode 100644 index 00000000..def6eab5 --- /dev/null +++ b/src/javascript/tests/core/erlang_compat/io_spec.js @@ -0,0 +1,10 @@ +import test from 'ava'; +import Core from '../../../lib/core'; + +test('put_chars', (t) => { + let result = Core.io.put_chars(Symbol.for('stdio'), 'Hello'); + t.deepEqual(result, Symbol.for('ok')); + + result = Core.io.put_chars(Symbol.for('stderr'), 'Hello'); + t.deepEqual(result, Symbol.for('ok')); +}); diff --git a/src/javascript/tests/core/erlang_compat/lists_spec.js b/src/javascript/tests/core/erlang_compat/lists_spec.js new file mode 100644 index 00000000..7e943b73 --- /dev/null +++ b/src/javascript/tests/core/erlang_compat/lists_spec.js @@ -0,0 +1,41 @@ +import test from 'ava'; +import Core from '../../../lib/core'; + +test('reverse', (t) => { + t.deepEqual(Core.lists.reverse([1, 2, 3]), [3, 2, 1]); +}); + +test('duplicate', (t) => { + t.deepEqual(Core.lists.duplicate(0, 1), []); + t.deepEqual(Core.lists.duplicate(1, 1), [1]); + t.deepEqual(Core.lists.duplicate(2, 1), [1, 1]); +}); + +test('flatten', (t) => { + t.deepEqual(Core.lists.flatten([1, 2, 3]), [1, 2, 3]); + t.deepEqual(Core.lists.flatten([1, [[2], 3]]), [1, 2, 3]); +}); + +test('foldl', (t) => { + t.deepEqual(Core.lists.foldl((v, acc) => acc + v, 0, [1, 2, 3]), 6); +}); + +test('foldr', (t) => { + t.deepEqual(Core.lists.foldr((v, acc) => acc + v.toString(), '', [1, 2, 3]), '321'); +}); + +test('member/2', (t) => { + let result = Core.lists.member('abc', ['abc']); + t.deepEqual(result, true); + + result = Core.lists.member('abc', ['abcd']); + t.deepEqual(result, false); +}); + +test('keyfind/3', (t) => { + let result = Core.lists.keyfind('abc', 1, ['abc']); + t.deepEqual(result, false); + + result = Core.lists.keyfind('abc', 1, [new Core.Tuple('abc')]); + t.deepEqual(result, new Core.Tuple('abc')); +}); diff --git a/src/javascript/tests/core/erlang_compat/maps_spec.js b/src/javascript/tests/core/erlang_compat/maps_spec.js new file mode 100644 index 00000000..31a20dcd --- /dev/null +++ b/src/javascript/tests/core/erlang_compat/maps_spec.js @@ -0,0 +1,83 @@ +import test from 'ava'; +import Core from '../../../lib/core'; + +test('find', (t) => { + let myMap = new Map(); + let result = Core.maps.find('t', myMap); + t.is(result, Symbol.for('error')); + + myMap = 'Hello'; + result = Core.maps.find('t', myMap); + t.deepEqual(result.values, [Symbol.for('badmap'), myMap]); + + myMap = new Map([['t', 'b']]); + result = Core.maps.find('t', myMap); + t.deepEqual(result.values, [Symbol.for('ok'), 'b']); + + myMap = new Map([[[1], 'b']]); + result = Core.maps.find([1], myMap); + t.deepEqual(result.values, [Symbol.for('ok'), 'b']); + + myMap = new Map([[new Map(), 'b']]); + result = Core.maps.find(new Map(), myMap); + t.deepEqual(result.values, [Symbol.for('ok'), 'b']); +}); + +test('fold', (t) => { + const myMap = new Map([['a', 1], ['b', 2]]); + const result = Core.maps.fold((k, v, acc) => acc + v, 0, myMap); + t.is(result, 3); +}); + +test('is_key', (t) => { + const myMap = new Map([['a', 1], ['b', 2]]); + let result = Core.maps.is_key('a', myMap); + t.is(result, true); + + result = Core.maps.is_key('c', myMap); + t.is(result, false); +}); + +test('get/2', (t) => { + const myMap = new Map([['a', 1], ['b', 2]]); + const result = Core.maps.get('a', myMap); + t.is(result, 1); +}); + +test('get/3', (t) => { + let myMap = new Map([['a', 1], ['b', 2]]); + let result = Core.maps.get('a', myMap); + t.is(result, 1); + + myMap = new Map([['a', 1], ['b', 2]]); + result = Core.maps.get('c', myMap, 'undefined'); + t.is(result, 'undefined'); +}); + +test('put/3', (t) => { + const keyMap = new Map([['a', 5]]); + + let myMap = new Map([]); + myMap = Core.maps.put(keyMap, 5, myMap); + myMap = Core.maps.put(new Map([['a', 5]]), 6, myMap); + + const result = Core.maps.get(new Map([['a', 5]]), myMap); + t.is(result, 6); +}); + +test('take/2', (t) => { + const myMap = new Map([['a', 1], ['b', 2]]); + const [a, result] = Core.maps.take('a', myMap); + t.is(a, 1); + t.is(result.has('a'), false); +}); + +test('remove', (t) => { + let myMap = new Map([['a', 1], ['b', 2]]); + let result = Core.maps.remove('a', myMap); + t.is(result.has('a'), false); + + myMap = new Map([[[1], 1], ['b', 2]]); + result = Core.maps.remove([1], myMap); + t.is(Core.maps.__has(result, [1]), false); +}); diff --git a/src/javascript/tests/core/erlang_compat/math_spec.js b/src/javascript/tests/core/erlang_compat/math_spec.js new file mode 100644 index 00000000..ea22fa04 --- /dev/null +++ b/src/javascript/tests/core/erlang_compat/math_spec.js @@ -0,0 +1,13 @@ +import test from 'ava'; +import Core from '../../../lib/core'; + +test('log2/1', (t) => { + let result = Core.math.log2(1); + t.is(result, 0); + + result = Core.math.log2(2); + t.is(result, 1); + + result = Core.math.log2(4); + t.is(result, 2); +}); diff --git a/src/javascript/tests/core/erlang_compat/proplists_spec.js b/src/javascript/tests/core/erlang_compat/proplists_spec.js new file mode 100644 index 00000000..b38e5f98 --- /dev/null +++ b/src/javascript/tests/core/erlang_compat/proplists_spec.js @@ -0,0 +1,26 @@ +import test from 'ava'; +import Core from '../../../lib/core'; + +test('get_value/2', (t) => { + let result = Core.proplists.get_value('abc', [new Core.Tuple('abc', '123')]); + t.deepEqual(result, '123'); + + result = Core.proplists.get_value('abc', ['abc']); + t.deepEqual(result, true); + + result = Core.proplists.get_value('abcd', ['abc']); + t.deepEqual(result, Symbol.for('undefined')); +}); + +test('get_value/3', (t) => { + let result = Core.proplists.get_value('abc', [new Core.Tuple('abc', '123')], 'xyz'); + t.deepEqual(result, '123'); + + result = Core.proplists.get_value('abcd', [new Core.Tuple('abc', '123')], 'xyz'); + t.deepEqual(result, 'xyz'); +}); + +test('is_defined/2', (t) => { + const result = Core.binary.at('abc', 0); + t.deepEqual(result, 'a'); +}); diff --git a/src/javascript/tests/core/erlang_compat/unicode_spec.js b/src/javascript/tests/core/erlang_compat/unicode_spec.js new file mode 100644 index 00000000..0781284f --- /dev/null +++ b/src/javascript/tests/core/erlang_compat/unicode_spec.js @@ -0,0 +1,30 @@ +import test from 'ava'; +import Core from '../../../lib/core'; + +test('characters_to_list', (t) => { + let result = Core.unicode.characters_to_list('hello'); + t.deepEqual(result, [104, 101, 108, 108, 111]); + + result = Core.unicode.characters_to_list(['hello', 'fg']); + t.deepEqual(result, [104, 101, 108, 108, 111, 102, 103]); + + result = Core.unicode.characters_to_list(['hello', 'fg', 34]); + t.deepEqual(result, [104, 101, 108, 108, 111, 102, 103, 34]); + + result = Core.unicode.characters_to_list(['hello', 'fg', 34, ['s']]); + t.deepEqual(result, [104, 101, 108, 108, 111, 102, 103, 34, 115]); +}); + +test('characters_to_binary', (t) => { + let result = Core.unicode.characters_to_binary('hello'); + t.deepEqual(result, 'hello'); + + result = Core.unicode.characters_to_binary(['hello', 'fg']); + t.deepEqual(result, 'hellofg'); + + result = Core.unicode.characters_to_binary(['hello', 'fg', 34]); + t.deepEqual(result, 'hellofg"'); + + result = Core.unicode.characters_to_binary(['hello', 'fg', 34, ['s']]); + t.deepEqual(result, 'hellofg"s'); +}); diff --git a/src/javascript/tests/core/functions.spec.js b/src/javascript/tests/core/functions.spec.js index 698d8c3c..d3ed14e1 100644 --- a/src/javascript/tests/core/functions.spec.js +++ b/src/javascript/tests/core/functions.spec.js @@ -1,18 +1,86 @@ +import test from 'ava'; import Core from '../../lib/core'; + const Functions = Core.Functions; -import chai from 'chai'; -const expect = chai.expect; - -describe('Functions', () => { - it('call_property', () => { - expect(Functions.call_property(1, 'toString')).to.equal('1'); - expect(Functions.call_property([], 'toString')).to.equal(''); - expect(Functions.call_property([], 'length')).to.equal(0); - expect(Functions.call_property('', 'toString')).to.equal(''); - expect(Functions.call_property('', 'length')).to.equal(0); - expect(Functions.call_property(Symbol('test'), 'toString')).to.equal('Symbol(test)'); - expect(Functions.call_property({ completed: false }, 'completed')).to.equal(false); - expect(Functions.call_property({ id: 0 }, 'id')).to.equal(0); - }); +test('call_property', (t) => { + t.is(Functions.call_property(1, 'toString'), '1'); + t.is(Functions.call_property([], 'toString'), ''); + t.is(Functions.call_property([], 'length'), 0); + t.is(Functions.call_property('', 'toString'), ''); + t.is(Functions.call_property('', 'length'), 0); + t.is(Functions.call_property(Symbol('test'), 'toString'), 'Symbol(test)'); + t.is(Functions.call_property({ completed: false }, 'completed'), false); + t.is(Functions.call_property({ id: 0 }, 'id'), 0); +}); + +test('split_at', (t) => { + t.deepEqual(Functions.split_at('sweetelixir', 5).values, ['sweet', 'elixir']); + t.deepEqual(Functions.split_at('sweetelixir', -6).values, ['sweet', 'elixir']); + t.deepEqual(Functions.split_at('abc', 0).values, ['', 'abc']); + t.deepEqual(Functions.split_at('abc', 1000).values, ['abc', '']); + t.deepEqual(Functions.split_at('abc', -1000).values, ['', 'abc']); + t.deepEqual(Functions.split_at('😀abélkm', 4).values, ['😀abé', 'lkm']); + t.deepEqual(Functions.split_at('👨‍👩‍👦‍👦abélkm', 4).values, ['👨‍👩‍👦‍👦abé', 'lkm']); +}); + +test('map_to_object/1', (t) => { + const map = new Map([[Symbol.for('key'), 'value'], [Symbol.for('anotherKey'), 'value2']]); + const result = Functions.map_to_object(map); + const obj = {}; + obj[Symbol.for('key')] = 'value'; + obj[Symbol.for('anotherKey')] = 'value2'; + t.deepEqual(result, obj); +}); + +test('map_to_object/2', (t) => { + const map = new Map([[Symbol.for('key'), 'value'], [Symbol.for('anotherKey'), 'value2']]); + const options = [new Core.Tuple(Symbol.for('keys'), Symbol.for('string'))]; + const result = Functions.map_to_object(map, options); + + t.deepEqual(result, { key: 'value', anotherKey: 'value2' }); +}); + +test('object_to_map/1', (t) => { + let obj = {}; + let result = Functions.object_to_map(obj); + t.deepEqual(result, new Map()); + + obj = { key: 'value', key2: null }; + result = Functions.object_to_map(obj); + t.deepEqual(result, new Map([['key', 'value'], ['key2', null]])); + + obj = {}; + obj[Symbol.for('key')] = 'value'; + result = Functions.object_to_map(obj); + t.deepEqual(result, new Map([[Symbol.for('key'), 'value']])); +}); + +test('object_to_map/2', (t) => { + let obj = {}; + let result = Functions.object_to_map(obj, []); + t.deepEqual(result, new Map()); + + obj = { key: 'value' }; + result = Functions.object_to_map(obj, [new Core.Tuple(Symbol.for('keys'), Symbol.for('atom'))]); + t.deepEqual(result, new Map([[Symbol.for('key'), 'value']])); + + obj = {}; + obj[Symbol.for('key')] = [{ nest1: 'valuenest1' }, { nest2: 'valuenest2' }]; + result = Functions.object_to_map(obj, [ + new Core.Tuple(Symbol.for('keys'), Symbol.for('atom')), + new Core.Tuple(Symbol.for('recurse_array'), true), + ]); + t.deepEqual( + result, + new Map([ + [ + Symbol.for('key'), + [ + new Map([[Symbol.for('nest1'), 'valuenest1']]), + new Map([[Symbol.for('nest2'), 'valuenest2']]), + ], + ], + ]), + ); }); diff --git a/src/javascript/tests/for.spec.js b/src/javascript/tests/for.spec.js index f872d649..9bcd1894 100644 --- a/src/javascript/tests/for.spec.js +++ b/src/javascript/tests/for.spec.js @@ -1,136 +1,126 @@ -import Core from "../lib/core"; +import test from 'ava'; +import Core from '../lib/core'; + const Patterns = Core.Patterns; const SpecialForms = Core.SpecialForms; const Tuple = Core.Tuple; const BitString = Core.BitString; -import Enum from "../lib/enum"; - -import chai from "chai"; -var expect = chai.expect; - const $ = Patterns.variable(); const collectable = { - into: function(original) { + into(original) { const fun = Patterns.defmatch( Patterns.clause( [ $, Patterns.type(Tuple, { - values: [Symbol.for("cont"), Patterns.variable()] - }) + values: [Symbol.for('cont'), Patterns.variable()], + }), ], - (list, x) => list.concat([x]) + (list, x) => list.concat([x]), ), - Patterns.clause([$, Symbol.for("done")], list => list) + Patterns.clause([$, Symbol.for('done')], list => list), ); return new Tuple([], fun); - } + }, }; -describe("for", () => { - it("simple for", () => { - let gen = Patterns.list_generator($, [1, 2, 3, 4]); - let result = SpecialForms._for( - Patterns.clause([$], x => x * 2), - [gen], - collectable - ); - - expect(result).to.eql([2, 4, 6, 8]); - }); +test('simple for', (t) => { + const gen = Patterns.list_generator($, [1, 2, 3, 4]); + const result = SpecialForms._for(Patterns.clause([$], x => x * 2), [gen], collectable); - it("for with multiple generators", () => { - //for x <- [1, 2], y <- [2, 3], do: x*y + t.deepEqual(result, [2, 4, 6, 8]); +}); - let gen = Patterns.list_generator($, [1, 2]); - let gen2 = Patterns.list_generator($, [2, 3]); - let result = SpecialForms._for( - Patterns.clause([$, $], (x, y) => x * y), - [gen, gen2], - collectable - ); +test('for with multiple generators', (t) => { + // for x <- [1, 2], y <- [2, 3], do: x*y - expect(result).to.eql([2, 3, 4, 6]); - }); + const gen = Patterns.list_generator($, [1, 2]); + const gen2 = Patterns.list_generator($, [2, 3]); + const result = SpecialForms._for( + Patterns.clause([$, $], (x, y) => x * y), + [gen, gen2], + collectable, + ); - it("for with filter", () => { - //for n <- [1, 2, 3, 4, 5, 6], rem(n, 2) == 0, do: n - let gen = Patterns.list_generator($, [1, 2, 3, 4, 5, 6]); - let result = SpecialForms._for( - Patterns.clause([$], x => x, x => x % 2 === 0), - [gen], - collectable - ); + t.deepEqual(result, [2, 3, 4, 6]); +}); - expect(result).to.eql([2, 4, 6]); - }); +test('for with filter', (t) => { + // for n <- [1, 2, 3, 4, 5, 6], rem(n, 2) == 0, do: n + const gen = Patterns.list_generator($, [1, 2, 3, 4, 5, 6]); + const result = SpecialForms._for( + Patterns.clause([$], x => x, x => x % 2 === 0), + [gen], + collectable, + ); - it("for with pattern matching", () => { - //for {:user, name} <- [user: "john", admin: "john", user: "meg"], do - // String.upcase(name) - //end + t.deepEqual(result, [2, 4, 6]); +}); - let gen = Patterns.list_generator([Symbol.for("user"), $], [ - [Symbol.for("user"), "john"], - [Symbol.for("admin"), "john"], - [Symbol.for("user"), "meg"] - ]); +test('for with pattern matching', (t) => { + // for {:user, name} <- [user: "john", admin: "john", user: "meg"], do + // String.upcase(name) + // end - let result = SpecialForms._for( - Patterns.clause([[Symbol.for("user"), $]], name => name.toUpperCase()), - [gen], - collectable - ); + const gen = Patterns.list_generator( + [Symbol.for('user'), $], + [[Symbol.for('user'), 'john'], [Symbol.for('admin'), 'john'], [Symbol.for('user'), 'meg']], + ); - expect(result).to.eql(["JOHN", "MEG"]); - }); + const result = SpecialForms._for( + Patterns.clause([[Symbol.for('user'), $]], name => name.toUpperCase()), + [gen], + collectable, + ); - it("for with bitstring", () => { - //for <> >>, do: {r, g, b} + t.deepEqual(result, ['JOHN', 'MEG']); +}); - let gen = Patterns.bitstring_generator( +test('for with bitstring', (t) => { + // for <> >>, do: {r, g, b} + + const gen = Patterns.bitstring_generator( + Patterns.bitStringMatch( + BitString.integer({ value: $ }), + BitString.integer({ value: $ }), + BitString.integer({ value: $ }), + ), + new BitString( + BitString.integer(213), + BitString.integer(45), + BitString.integer(132), + BitString.integer(64), + BitString.integer(76), + BitString.integer(32), + BitString.integer(76), + BitString.integer(0), + BitString.integer(0), + BitString.integer(234), + BitString.integer(32), + BitString.integer(15), + ), + ); + + const expression = Patterns.clause( + [ Patterns.bitStringMatch( BitString.integer({ value: $ }), BitString.integer({ value: $ }), - BitString.integer({ value: $ }) + BitString.integer({ value: $ }), ), - new BitString( - BitString.integer(213), - BitString.integer(45), - BitString.integer(132), - BitString.integer(64), - BitString.integer(76), - BitString.integer(32), - BitString.integer(76), - BitString.integer(0), - BitString.integer(0), - BitString.integer(234), - BitString.integer(32), - BitString.integer(15) - ) - ); - - let expression = Patterns.clause( - [ - Patterns.bitStringMatch( - BitString.integer({ value: $ }), - BitString.integer({ value: $ }), - BitString.integer({ value: $ }) - ) - ], - (r, g, b) => new Tuple(r, g, b) - ); - - let result = SpecialForms._for(expression, [gen], collectable); - - expect(result).to.eql([ - new Tuple(213, 45, 132), - new Tuple(64, 76, 32), - new Tuple(76, 0, 0), - new Tuple(234, 32, 15) - ]); - }); + ], + (r, g, b) => new Tuple(r, g, b), + ); + + const result = SpecialForms._for(expression, [gen], collectable); + + t.deepEqual(result, [ + new Tuple(213, 45, 132), + new Tuple(64, 76, 32), + new Tuple(76, 0, 0), + new Tuple(234, 32, 15), + ]); }); diff --git a/src/javascript/tests/special_forms.spec.js b/src/javascript/tests/special_forms.spec.js deleted file mode 100644 index cc540546..00000000 --- a/src/javascript/tests/special_forms.spec.js +++ /dev/null @@ -1,33 +0,0 @@ -import Core from "../lib/core"; -const SpecialForms = Core.SpecialForms; - -import chai from 'chai'; -var expect = chai.expect; - -describe('SpecialForms', function(){ - - describe('map_update', function(){ - it('creates new object', function(){ - const foo = Object.freeze({foo: "bar", fizz: "buzz"}); - const bar = SpecialForms.map_update(foo, {baz: "bar", fizz: "fizzbuzz"}); - - expect(foo instanceof Object).to.equal(bar instanceof Object); - expect(foo.foo).to.equal(bar.foo); - expect(bar.fizz).to.equal("fizzbuzz"); - expect(foo === bar).to.equal(false); - }); - - it('creates new class', function(){ - function MyClass(foo){ - this.foo = foo; - } - - const foo = new MyClass("bar"); - const bar = SpecialForms.map_update(foo, {baz: "bar", fizz: "fizzbuzz"}); - - expect(foo instanceof MyClass).to.equal(bar instanceof MyClass); - expect(foo.foo).to.equal(bar.foo); - expect(bar.fizz).to.equal("fizzbuzz"); - }); - }); -}); diff --git a/src/javascript/tests/try.spec.js b/src/javascript/tests/try.spec.js index d4b7cf60..fdcbaefd 100644 --- a/src/javascript/tests/try.spec.js +++ b/src/javascript/tests/try.spec.js @@ -1,17 +1,10 @@ -import Core from "../lib/core"; -const Patterns = Core.Patterns; -const SpecialForms = Core.SpecialForms; +import test from 'ava'; +import Core from '../lib/core'; -import Enum from "../lib/enum"; +const { Patterns, SpecialForms } = Core; -import chai from 'chai'; -var expect = chai.expect; - - -describe('try', () => { - - it('try', () => { - /* +test('try', (t) => { + /* try do 1 / x else @@ -23,19 +16,18 @@ describe('try', () => { */ - let x = 1; - - let value = SpecialForms._try(function() { - return 1 / x; - }, null, null, Patterns.defmatch(Patterns.clause([Patterns.variable()], function(y) { - return Symbol.for('small'); - }, function(y) { - return (y < 1) && (y > -1); - }), Patterns.clause([Patterns.wildcard()], function() { - return Symbol.for('large'); - })), null); + const x = 1; - expect(value).to.equal(Symbol.for('large')); - }); + const value = SpecialForms._try( + () => 1 / x, + null, + null, + Patterns.defmatch( + Patterns.clause([Patterns.variable()], () => Symbol.for('small'), y => y < 1 && y > -1), + Patterns.clause([Patterns.wildcard()], () => Symbol.for('large')), + ), + null, + ); + t.is(value, Symbol.for('large')); }); diff --git a/src/javascript/tests/with.spec.js b/src/javascript/tests/with.spec.js index 70f5c233..31fb2c49 100644 --- a/src/javascript/tests/with.spec.js +++ b/src/javascript/tests/with.spec.js @@ -1,28 +1,23 @@ -import Core from "../lib/core"; +import test from 'ava'; +import Core from '../lib/core'; + const Patterns = Core.Patterns; const SpecialForms = Core.SpecialForms; const Tuple = Core.Tuple; const MatchError = Core.Patterns.MatchError; -import Enum from "../lib/enum"; - -import chai from 'chai'; -var expect = chai.expect; - const $ = Patterns.variable(); -function map_fetch(map, key){ - if(key in map){ +function map_fetch(map, key) { + if (key in map) { return new Tuple(Symbol.for('ok'), map[key]); } return Symbol.for('error'); } -describe('with', () => { - - it('normal', () => { - /* +test('with', (t) => { + /* opts = %{width: 10, height: 15} with {:ok, width} <- Map.fetch(opts, :width), @@ -32,20 +27,19 @@ describe('with', () => { {:ok, 150} */ - let opts = { width: 10, height: 15 }; + const opts = { width: 10, height: 15 }; - let value = SpecialForms._with( - [new Tuple(Symbol.for('ok'), $), () => map_fetch(opts, "width")], - [new Tuple(Symbol.for('ok'), $), (width) => map_fetch(opts, "height")], - (width, height) => new Tuple(Symbol.for('ok'), width * height) - ); - - expect(value).to.eql(new Tuple(Symbol.for('ok'), 150)); - }); + const value = SpecialForms._with( + [new Tuple(Symbol.for('ok'), $), () => map_fetch(opts, 'width')], + [new Tuple(Symbol.for('ok'), $), () => map_fetch(opts, 'height')], + (width, height) => new Tuple(Symbol.for('ok'), width * height), + ); + t.deepEqual(value, new Tuple(Symbol.for('ok'), 150)); +}); - it('without match', () => { - /* +test('with without match', (t) => { + /* opts = %{width: 10} with {:ok, width} <- Map.fetch(opts, :width), @@ -55,20 +49,19 @@ describe('with', () => { :error */ - let opts = { width: 10 }; + const opts = { width: 10 }; - let value = SpecialForms._with( - [new Tuple(Symbol.for('ok'), $), () => map_fetch(opts, "width")], - [new Tuple(Symbol.for('ok'), $), (width) => map_fetch(opts, "height")], - (width, height) => new Tuple(Symbol.for('ok'), width * height) - ); - - expect(value).to.eql(Symbol.for('error')); - }); + const value = SpecialForms._with( + [new Tuple(Symbol.for('ok'), $), () => map_fetch(opts, 'width')], + [new Tuple(Symbol.for('ok'), $), () => map_fetch(opts, 'height')], + (width, height) => new Tuple(Symbol.for('ok'), width * height), + ); + t.deepEqual(value, Symbol.for('error')); +}); - it('bare expression', () => { - /* +test('with bare expression', (t) => { + /* opts = %{width: 10} with {:ok, width} <- Map.fetch(opts, :width), @@ -79,21 +72,20 @@ describe('with', () => { {:ok, 300} */ - let opts = { width: 10, height: 15 }; + const opts = { width: 10, height: 15 }; - let value = SpecialForms._with( - [new Tuple(Symbol.for('ok'), $), () => map_fetch(opts, "width")], - [$, (width) => width * 2], - [new Tuple(Symbol.for('ok'), $), (width, double_width) => map_fetch(opts, "height")], - (width, double_width, height) => new Tuple(Symbol.for('ok'), double_width * height) - ); - - expect(value).to.eql(new Tuple(Symbol.for('ok'), 300)); - }); + const value = SpecialForms._with( + [new Tuple(Symbol.for('ok'), $), () => map_fetch(opts, 'width')], + [$, width => width * 2], + [new Tuple(Symbol.for('ok'), $), () => map_fetch(opts, 'height')], + (width, double_width, height) => new Tuple(Symbol.for('ok'), double_width * height), + ); + t.deepEqual(value, new Tuple(Symbol.for('ok'), 300)); +}); - it('with else', () => { - /* +test('with else', (t) => { + /* opts = %{width: 10} with {:ok, width} <- Map.fetch(opts, :width), @@ -106,22 +98,25 @@ describe('with', () => { {:error, :wrong_data} */ - let opts = { width: 10 }; - - let value = SpecialForms._with( - [new Tuple(Symbol.for('ok'), $), () => map_fetch(opts, "width")], - [new Tuple(Symbol.for('ok'), $), (width) => map_fetch(opts, "height")], - (width, height) => new Tuple(Symbol.for('ok'), width * height), - Patterns.defmatch( - Patterns.clause([Symbol.for('error')], () => new Tuple(Symbol.for('error'), Symbol.for('wrong_data'))) - ) - ); - - expect(value).to.eql(new Tuple(Symbol.for('error'), Symbol.for('wrong_data'))); - }); + const opts = { width: 10 }; + + const value = SpecialForms._with( + [new Tuple(Symbol.for('ok'), $), () => map_fetch(opts, 'width')], + [new Tuple(Symbol.for('ok'), $), () => map_fetch(opts, 'height')], + (width, height) => new Tuple(Symbol.for('ok'), width * height), + Patterns.defmatch( + Patterns.clause( + [Symbol.for('error')], + () => new Tuple(Symbol.for('error'), Symbol.for('wrong_data')), + ), + ), + ); + + t.deepEqual(value, new Tuple(Symbol.for('error'), Symbol.for('wrong_data'))); +}); - it('with else that don`t match', () => { - /* +test('with else that don`t match', (t) => { + /* opts = %{width: 10} with {:ok, width} <- Map.fetch(opts, :width), @@ -134,18 +129,20 @@ describe('with', () => { {:error, :wrong_data} */ - let opts = { width: 10 }; - - let withFunction = SpecialForms._with.bind( - null, - [new Tuple(Symbol.for('ok'), $), () => map_fetch(opts, "width")], - [new Tuple(Symbol.for('ok'), $), (width) => map_fetch(opts, "height")], - (width, height) => new Tuple(Symbol.for('ok'), width * height), - Patterns.defmatch( - Patterns.clause([Symbol.for('fail')], () => new Tuple(Symbol.for('error'), Symbol.for('wrong_data'))) - ) - ); - - expect(withFunction).to.throw(MatchError, 'No match for: Symbol(error)'); - }); + const opts = { width: 10 }; + + const withFunction = SpecialForms._with.bind( + null, + [new Tuple(Symbol.for('ok'), $), () => map_fetch(opts, 'width')], + [new Tuple(Symbol.for('ok'), $), () => map_fetch(opts, 'height')], + (width, height) => new Tuple(Symbol.for('ok'), width * height), + Patterns.defmatch( + Patterns.clause( + [Symbol.for('fail')], + () => new Tuple(Symbol.for('error'), Symbol.for('wrong_data')), + ), + ), + ); + + t.throws(withFunction, MatchError); }); diff --git a/test/beam_test.exs b/test/beam_test.exs new file mode 100644 index 00000000..66369a94 --- /dev/null +++ b/test/beam_test.exs @@ -0,0 +1,15 @@ +defmodule ElixirScript.Beam.Test do + use ExUnit.Case + + test "can get ast from beam" do + assert {:ok, _} = ElixirScript.Beam.debug_info(Atom) + end + + test "errors when not found" do + assert {:error, _} = ElixirScript.Beam.debug_info(Some.Module) + end + + test "can get ast from beam that is protocol" do + assert {:ok, Enumerable, _, _} = ElixirScript.Beam.debug_info(Enumerable) + end +end diff --git a/test/cli_test.exs b/test/cli_test.exs new file mode 100644 index 00000000..0a61dbf2 --- /dev/null +++ b/test/cli_test.exs @@ -0,0 +1,33 @@ +defmodule ElixirScript.CLI.Test do + use ExUnit.Case + import ExUnit.CaptureIO + + test "parse_args" do + {_, args} = ElixirScript.CLI.parse_args(["Atom", "--output", "build"]) + assert args == [output: "build"] + end + + test "process help" do + assert capture_io(fn -> + ElixirScript.CLI.process(:help) + end) =~ "usage: elixirscript [options]" + end + + test "process version" do + assert capture_io(fn -> + ElixirScript.CLI.process(:version) + end) =~ Mix.Project.config()[:version] + end + + test "process unknown" do + assert capture_io(fn -> + ElixirScript.CLI.process({"", [unknown: ""]}) + end) =~ "usage: elixirscript [options]" + end + + test "process input" do + assert capture_io(fn -> + ElixirScript.CLI.process({["Atom"], []}) + end) =~ "export default" + end +end diff --git a/test/compiler_test.exs b/test/compiler_test.exs new file mode 100644 index 00000000..b7b05dd3 --- /dev/null +++ b/test/compiler_test.exs @@ -0,0 +1,40 @@ +defmodule ElixirScript.Compiler.Test do + use ExUnit.Case + + test "Can compile one entry module" do + result = ElixirScript.Compiler.compile(Version) + assert result |> Map.to_list() |> hd |> elem(1) |> Map.get(:js_code) |> is_binary + end + + test "Can compile multiple entry modules" do + result = ElixirScript.Compiler.compile([Atom, String, Agent]) + assert result |> Map.to_list() |> hd |> elem(1) |> Map.get(:js_code) |> is_binary + end + + test "Output" do + result = ElixirScript.Compiler.compile(Atom, []) + assert result |> Map.to_list() |> hd |> elem(1) |> Map.get(:js_code) =~ "export default" + end + + test "compile file" do + path = System.tmp_dir() + path = Path.join([path, "Elixir.ElixirScript.Beam.Test.js"]) + + input_path = Path.join([File.cwd!(), "test", "beam_test.exs"]) + + ElixirScript.Compiler.compile(input_path, output: path) + assert File.exists?(path) + assert String.contains?(File.read!(path), "export default") + end + + test "compile wildcard" do + path = System.tmp_dir() + file = Path.join([path, "Elixir.ElixirScript.FFI.Test.js"]) + + input_path = Path.join([File.cwd!(), "test", "*fi_test.exs"]) + + ElixirScript.Compiler.compile(input_path, output: path) + assert File.exists?(file) + assert String.contains?(File.read!(file), "export default") + end +end diff --git a/test/ffi_test.exs b/test/ffi_test.exs new file mode 100644 index 00000000..5b593d52 --- /dev/null +++ b/test/ffi_test.exs @@ -0,0 +1,17 @@ +defmodule ElixirScript.FFI.Test do + use ExUnit.Case + + defmodule MyTestModule do + use ElixirScript.FFI + + defexternal my_test_function(arg1, arg2) + end + + test "FFI module has __foreign_info__ attribute" do + assert Keyword.has_key?(MyTestModule.__info__(:attributes), :__foreign_info__) + end + + test "FFI module makes foreign function" do + assert Keyword.has_key?(MyTestModule.__info__(:functions), :my_test_function) + end +end diff --git a/test/manifest_test.exs b/test/manifest_test.exs new file mode 100644 index 00000000..52efd044 --- /dev/null +++ b/test/manifest_test.exs @@ -0,0 +1,12 @@ +defmodule ElixirScript.Manifest.Test do + use ExUnit.Case + alias ElixirScript.Manifest + + test "write manifest" do + result = ElixirScript.Compiler.compile(Atom) + path = Path.join([System.tmp_dir(), "write_manifest_test", ".compile.elixir_script"]) + Manifest.write_manifest(path, result) + assert File.exists?(path) + end + +end diff --git a/test/passes/translate/form_test.exs b/test/passes/translate/form_test.exs new file mode 100644 index 00000000..07d1b902 --- /dev/null +++ b/test/passes/translate/form_test.exs @@ -0,0 +1,219 @@ +defmodule ElixirScript.Translate.Forms.Test do + use ExUnit.Case + alias ElixirScript.Translate.Form + alias ElixirScript.Translate.Helpers + alias ESTree.Tools.Builder, as: J + use ExUnitProperties + + setup_all do + {:ok, pid} = ElixirScript.State.start_link(%{}) + + state = %{ + pid: pid, + vars: %{} + } + + [state: state] + end + + property "integers, floats, binaries, and booleans translates to a literal JavaScript AST node", + %{state: state} do + check all value <- + StreamData.one_of([ + StreamData.integer(), + StreamData.boolean(), + StreamData.binary(), + StreamData.float() + ]) do + {js_ast, _} = Form.compile(value, state) + assert js_ast == J.literal(value) + end + end + + property "atom translates to Symbol.for call", %{state: state} do + check all atom <- StreamData.atom(:alphanumeric) do + {js_ast, _} = Form.compile(atom, state) + + assert js_ast == + J.call_expression( + J.member_expression( + J.identifier("Symbol"), + J.identifier("for") + ), + [J.literal(atom)] + ) + end + end + + property "tuple translates to new Tuple object", %{state: state} do + check all tuple <- StreamData.tuple({StreamData.integer(), StreamData.binary()}) do + {js_ast, _} = Form.compile(tuple, state) + + assert js_ast == + J.new_expression( + J.member_expression( + J.member_expression( + J.identifier("ElixirScript"), + J.identifier("Core") + ), + J.identifier("Tuple") + ), + [J.literal(elem(tuple, 0)), J.literal(elem(tuple, 1))] + ) + end + end + + property "list translates to a JavaScript Array", %{state: state} do + check all list <- StreamData.list_of(StreamData.binary()) do + {js_ast, _} = Form.compile(list, state) + assert js_ast.type == "ArrayExpression" + assert length(js_ast.elements) == length(list) + + Enum.zip(js_ast.elements, list) + |> Enum.each(fn {ast, original} -> + assert ast == J.literal(original) + end) + end + end + + property "local function call translates to local JavaScript function call", %{state: state} do + check all func <- StreamData.filter(StreamData.atom(:alphanumeric), fn x -> x not in [:fn] end), + params <- StreamData.list_of(StreamData.binary()) do + ast = {func, [], params} + + str_func = + if func in ElixirScript.Translate.Identifier.js_reserved_words() do + "__#{to_string(func)}__" + else + to_string(func) + end + + {js_ast, _} = Form.compile(ast, state) + assert js_ast.type == "CallExpression" + assert length(js_ast.arguments) == length(params) + assert js_ast.callee.type == "Identifier" + assert js_ast.callee.name == str_func + + Enum.zip(js_ast.arguments, params) + |> Enum.each(fn {ast, original} -> + assert ast == J.literal(original) + end) + end + end + + property "super function call translates to local JavaScript function call" do + check all func <- StreamData.atom(:alphanumeric), + params <- StreamData.list_of(StreamData.binary()) do + ast = {:super, [], [{:def, func}] ++ params} + state = %{function: {func, nil}, vars: %{}} + + str_func = + if func in ElixirScript.Translate.Identifier.js_reserved_words() do + "__#{to_string(func)}__" + else + to_string(func) + end + + {js_ast, _} = Form.compile(ast, state) + assert js_ast.type == "CallExpression" + assert length(js_ast.arguments) == length(params) + assert js_ast.callee.type == "Identifier" + assert js_ast.callee.name == str_func + + Enum.zip(js_ast.arguments, params) + |> Enum.each(fn {ast, original} -> + assert ast == J.literal(original) + end) + end + end + + test "module", %{state: state} do + ast = IO + + ElixirScript.State.put_module(state.pid, IO, %{}) + + {js_ast, _} = Form.compile(ast, state) + assert js_ast == %ESTree.Identifier{loc: nil, name: "$IO$", type: "Identifier"} + end + + test "unknown module", %{state: state} do + ast = Enum + + {js_ast, _} = Form.compile(ast, state) + + assert js_ast == %ESTree.ObjectExpression{ + loc: nil, + properties: [], + type: "ObjectExpression" + } + end + + test "function returning an array" do + ast = {:fn, [], [{:foo, [], [], [1, 2, 3]}]} + state = %{function: {:something, nil}} + + {js_ast, _} = Form.compile(ast, state) + + return_statement = Enum.at(Enum.at(hd(js_ast.body.body).body.body, 1).consequent.body, 1) + + assert return_statement.argument == + J.array_expression([ + J.literal(1), + J.literal(2), + J.literal(3) + ]) + end + + test "calling field on field" do + ast = + { + {:., [line: 16], [ + {{:., [line: 16], [{:map, [line: 16], nil}, :token_count]}, [line: 16], []}, + :toLocaleString + ]}, + [line: 16], + [] + } + + state = %{function: {:something, nil}, vars: %{}} + + {js_ast, _} = Form.compile(ast, state) + + assert js_ast == + Helpers.call(ElixirScript.Translate.Forms.JS.call_property(), [ + Helpers.call(ElixirScript.Translate.Forms.JS.call_property(), [ + J.identifier("map"), + J.literal("token_count") + ]), + J.literal("toLocaleString") + ]) + end + + test "make sure counter used in guard", %{state: state} do + state = + Map.merge(state, %{ + anonymous_fn: false, + function: {:filter_names_in_guards, nil}, + in_guard: true, + module: Integration, + vars: %{"has__qmark__" => 0} + }) + + ast = {{:., [], [:erlang, :==]}, [line: 29], [{:has?, [line: 29], nil}, 5]} + + {js_ast, _} = Form.compile(ast, state) + assert hd(js_ast.arguments).name === "has__qmark__0" + end + + test "multi bind", %{state: state} do + ast = + {:=, [line: 35], [ + [{:|, [line: 35], [{:a, [line: 35], nil}, {:_, [line: 35], nil}]}], + {:=, [line: 35], [{:b, [line: 35], nil}, [1, 2, 3, 4, 5]]} + ]} + + {js_ast, _} = Form.compile(ast, state) + + assert length(js_ast) > 1 + end +end diff --git a/test/passes/translate/forms/bitstring_test.exs b/test/passes/translate/forms/bitstring_test.exs new file mode 100644 index 00000000..1d62517d --- /dev/null +++ b/test/passes/translate/forms/bitstring_test.exs @@ -0,0 +1,30 @@ +defmodule ElixirScript.Translate.Forms.Bitstring.Test do + use ExUnit.Case + alias ElixirScript.Translate.Form + alias ESTree.Tools.Builder, as: J + + setup_all do + {:ok, pid} = ElixirScript.State.start_link(%{}) + + state = %{ + pid: pid, + vars: %{} + } + + [state: state] + end + + test "string interpolation", %{state: state} do + ast = {:<<>>, [line: 5], + [{:::, [], ["Hello, ", {:binary, [], []}]}, + {:::, [line: 5], + [{{:., [line: 5], [String.Chars, :to_string]}, [line: 5], + [{:name, [line: 5], nil}]}, {:binary, [], []}]}]} + + {js_ast, _} = Form.compile(ast, state) + assert js_ast.type == "BinaryExpression" + assert js_ast.left == J.literal("Hello, ") + assert js_ast.right.type == "CallExpression" + end + +end diff --git a/test/passes/translate/forms/js_test.exs b/test/passes/translate/forms/js_test.exs new file mode 100644 index 00000000..d3989cb9 --- /dev/null +++ b/test/passes/translate/forms/js_test.exs @@ -0,0 +1,99 @@ +defmodule ElixirScript.Translate.Forms.JS.Test do + use ExUnit.Case + alias ElixirScript.Translate.{Form, Helpers} + alias ESTree.Tools.Builder, as: J + + setup_all do + {:ok, pid} = ElixirScript.State.start_link(%{}) + + state = %{ + pid: pid, + vars: %{} + } + + [state: state] + end + + test "debugger" do + ast = {{:., [], [ElixirScript.JS, :debugger]}, [], []} + state = %{function: {:each, nil}, module: Enum, vars: %{:_ => 0, "entry" => 0, "enumerable" => 0, "fun" => 0}} + + {js_ast, _} = Form.compile(ast, state) + assert js_ast == J.debugger_statement() + end + + test "this" do + ast = {{:., [], [ElixirScript.JS, :this]}, [], []} + state = %{function: {:each, nil}, module: Enum, vars: %{:_ => 0, "entry" => 0, "enumerable" => 0, "fun" => 0}} + + {js_ast, _} = Form.compile(ast, state) + assert js_ast == J.this_expression() + end + + test "new" do + ast = {{:., [], [ElixirScript.JS, :new]}, [], [BLT, ["bacon", "lettuce", "tomato"]]} + state = %{function: {:each, nil}, module: Enum, vars: %{:_ => 0, "entry" => 0, "enumerable" => 0, "fun" => 0}} + + {js_ast, _} = Form.compile(ast, state) + assert js_ast == J.new_expression( + J.identifier("BLT"), + [ + J.literal("bacon"), + J.literal("lettuce"), + J.literal("tomato") + ] + ) + end + + + test "throw" do + ast = {{:., [], [ElixirScript.JS, :throw]}, [], [1]} + state = %{function: {:each, nil}, module: Enum, vars: %{:_ => 0, "entry" => 0, "enumerable" => 0, "fun" => 0}} + + {js_ast, _} = Form.compile(ast, state) + assert js_ast == J.throw_statement(J.literal(1)) + end + + test "import" do + ast = {{:., [], [ElixirScript.JS, :import]}, [], ["react"]} + state = %{function: {:each, nil}, module: Enum, vars: %{:_ => 0, "entry" => 0, "enumerable" => 0, "fun" => 0}} + + {js_ast, _} = Form.compile(ast, state) + assert js_ast == J.call_expression( + J.identifier("import"), + [J.literal("react")] + ) + end + + test "mutate/3" do + ast = {{:., [], [ElixirScript.JS, :mutate]}, [], [{:entry, [], nil}, "a", 2]} + state = %{function: {:each, nil}, module: Enum, vars: %{:_ => 0, "entry" => 0, "enumerable" => 0, "fun" => 0}} + + {js_ast, _} = Form.compile(ast, state) + assert js_ast == J.assignment_expression( + :=, + J.member_expression( + J.identifier("entry0"), + J.literal("a"), + true + ), + J.literal(2) + ) + end + + test "map_to_object/1" do + ast = {{:., [], [ElixirScript.JS, :map_to_object]}, [], [{:entry, [], nil}]} + state = %{function: {:each, nil}, module: Enum, vars: %{:_ => 0, "entry" => 0, "enumerable" => 0, "fun" => 0}} + + {js_ast, _} = Form.compile(ast, state) + assert js_ast == J.call_expression( + J.member_expression( + Helpers.functions(), + J.identifier("map_to_object") + ), + [ + J.identifier("entry0") + ] + ) + end +end diff --git a/test/passes/translate/forms/map_test.exs b/test/passes/translate/forms/map_test.exs new file mode 100644 index 00000000..22eaa6b1 --- /dev/null +++ b/test/passes/translate/forms/map_test.exs @@ -0,0 +1,84 @@ +defmodule ElixirScript.Translate.Forms.Map.Test do + use ExUnit.Case + alias ElixirScript.Translate.Form + alias ESTree.Tools.Builder, as: J + use ExUnitProperties + + setup_all do + {:ok, pid} = ElixirScript.State.start_link(%{}) + + state = %{ + pid: pid + } + + [state: state] + end + + property "maps convert to Map objects", %{state: state} do + check all tuple <- StreamData.tuple({ + StreamData.one_of([ + StreamData.integer(), + StreamData.boolean(), + StreamData.binary(), + StreamData.float() + ]), + StreamData.binary() + }) do + + properties = [tuple] + ast = {:%{}, [], properties} + + {js_ast, _} = Form.compile(ast, state) + assert js_ast == J.new_expression( + J.identifier("Map"), + [ + J.array_expression([ + J.array_expression([ + J.literal(elem(tuple, 0)), + J.literal(elem(tuple, 1)), + ]) + ]) + ] + ) + end + end + + property "maps update converts to new Map objects using old version", %{state: state} do + check all key <- StreamData.binary(), + old_value <- StreamData.integer(), + new_value <- StreamData.integer() do + + properties = [{key, old_value}] + map_ast = {:%{}, [], properties} + new_values = [{key, new_value}] + + ast = {:%{}, [], [{:|, [], [map_ast, new_values]}]} + + map_js_ast = J.new_expression( + J.identifier("Map"), + [ + J.array_expression([ + J.array_expression([ + J.literal(key), + J.literal(old_value), + ]) + ]) + ] + ) + + {js_ast, _} = Form.compile(ast, state) + assert js_ast == J.new_expression( + J.identifier("Map"), + [ + J.array_expression( + [J.spread_element(map_js_ast)] ++ [J.array_expression([ + J.literal(key), + J.literal(new_value) + ])] + ) + ] + ) + end + end + +end diff --git a/test/passes/translate/forms/receive_test.exs b/test/passes/translate/forms/receive_test.exs new file mode 100644 index 00000000..9f8496a7 --- /dev/null +++ b/test/passes/translate/forms/receive_test.exs @@ -0,0 +1,34 @@ +defmodule ElixirScript.Translate.Forms.Receive.Test do + use ExUnit.Case + alias ElixirScript.Translate.{Form, Helpers} + alias ESTree.Tools.Builder, as: J + + setup_all do + {:ok, pid} = ElixirScript.State.start_link(%{}) + + state = %{ + pid: pid, + module: __MODULE__ + } + + [state: state] + end + + test "receive translation", %{state: state} do + clause = {:->, [line: 644], [[], [{:__block__, [], [1]}]]} + ast = {:receive, [line: 644], [[do: [clause], after: nil]]} + + state = + state + |> Map.put(:function, {:each, nil}) + |> Map.put(:anonymous_fn, false) + + {js_ast, _} = Form.compile(ast, state) + + assert js_ast.callee == + J.member_expression( + Helpers.special_forms(), + J.identifier("receive") + ) + end +end diff --git a/test/passes/translate/forms/remote_test.exs b/test/passes/translate/forms/remote_test.exs new file mode 100644 index 00000000..41d15bf4 --- /dev/null +++ b/test/passes/translate/forms/remote_test.exs @@ -0,0 +1,14 @@ +defmodule ElixirScript.Translate.Forms.Remote.Test do + use ExUnit.Case + alias ElixirScript.Translate.Form + alias ESTree.Tools.Builder, as: J + + test "variable counter" do + ast = {:., [line: 644], [{:fun, [line: 644], nil}]} + state = %{function: {:each, nil}, module: Enum, vars: %{:_ => 0, "entry" => 0, "enumerable" => 0, "fun" => 0}} + + {js_ast, _} = Form.compile(ast, state) + assert js_ast == J.identifier("fun0") + end + +end diff --git a/test/prelude/js_test.exs b/test/prelude/js_test.exs deleted file mode 100644 index 3cff3835..00000000 --- a/test/prelude/js_test.exs +++ /dev/null @@ -1,52 +0,0 @@ -defmodule ElixirScript.Lib.JS.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "translate new" do - ex_ast = quote do - require JS - - def execute() do - JS.new A.B, [1, 2, 3] - end - end - - js_code = """ - new A.B(1, 2, 3) - """ - - assert_translation(ex_ast, js_code) - - ex_ast = quote do - require JS - - def execute() do - JS.new A, [1, 2, 3] - end - end - - js_code = """ - new A(1, 2, 3) - """ - - assert_translation(ex_ast, js_code) - end - - test "translate update" do - ex_ast = quote do - require JS - - def execute() do - JS.update A, %{"b" => [1, 2, 3]} - end - end - - js_code = """ - Object.assign(A, Object.freeze({ - b: Object.freeze([1, 2, 3]) - })) - """ - - assert_translation(ex_ast, js_code) - end -end diff --git a/test/prelude/kernel_test.exs b/test/prelude/kernel_test.exs deleted file mode 100644 index c080a158..00000000 --- a/test/prelude/kernel_test.exs +++ /dev/null @@ -1,44 +0,0 @@ -defmodule ElixirScript.Lib.Elixir.Kernel.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "translate range" do - ex_ast = quote do - 1..4 - end - - js_code = """ - - Elixir.ElixirScript.Range.__load(Elixir).Elixir$ElixirScript$Range.create(Object.freeze({ - [Symbol.for('first')]: 1, - [Symbol.for('last')]: 4 - })) - """ - - assert_translation(ex_ast, js_code) - end - - test "translate sigil_r" do - ex_ast = quote do - ~r/foo/ - end - - js_code = """ - Elixir.ElixirScript.Regex.__load(Elixir).compile__emark__('foo', '') - """ - - assert_translation(ex_ast, js_code) - end - - test "translate sigil_r with options" do - ex_ast = quote do - ~r/foo/i - end - - js_code = """ - Elixir.ElixirScript.Regex.__load(Elixir).compile__emark__('foo', 'i') - """ - - assert_translation(ex_ast, js_code) - end -end diff --git a/test/test_helper.exs b/test/test_helper.exs index f23b9de7..30fac768 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1,87 +1,3 @@ exclude = if Node.alive?, do: [], else: [skip: true] ExUnit.start(exclude: exclude) - -defmodule ElixirScript.Math do - defmacro squared(x) do - quote do - unquote(x) * unquote(x) - end - end -end - -defmodule ElixirScript.Using do - defmacro __using__(_) do - quote do - def sandwich() do - end - end - end -end - -defmodule ElixirScript.TestHelper do - use ExUnit.Case - - def make_custom_env do - use ElixirScript - require ElixirScript.Math - require ElixirScript.Using - __ENV__ - end - - def ex_ast_to_js(ex_ast, format) do - ElixirScript.compile_quoted(ex_ast, %{ env: make_custom_env(), import_standard_libs: false, format: format }) - end - - def strip_spaces(js) do - js |> String.replace(~r/\s+/, "") - end - - def assert_translation(ex_ast, js_code) do - assert_translation(ex_ast, js_code, :es) - end - - def assert_translation(ex_ast, js_code, format) do - converted_code = ex_ast_to_js(ex_ast, format) - - assert converted_code |> strip_spaces =~ strip_spaces(js_code), """ - **Code Does Not Match ** - - ***Expected*** - #{js_code} - - ***Actual*** - #{converted_code} - """ - end - - def assert_js_matches(expected_js_code, actual_js_code) do - assert strip_spaces(hd(List.wrap(actual_js_code))) =~ strip_spaces(expected_js_code), """ - **Code Does Not Match ** - - ***Expected*** - #{expected_js_code} - - ***Actual*** - #{actual_js_code} - """ - end - - def refute_translation(ex_ast, js_code) do - refute_translation(ex_ast, js_code, :es) - end - - def refute_translation(ex_ast, js_code, format) do - converted_code = ex_ast_to_js(ex_ast, format) - - refute converted_code |> strip_spaces =~ strip_spaces(js_code), """ - **Code Does Not Match ** - - ***Expected*** - #{js_code} - - ***Actual*** - #{converted_code} - """ - end -end diff --git a/test/translator/access_test.exs b/test/translator/access_test.exs deleted file mode 100644 index 194c24d7..00000000 --- a/test/translator/access_test.exs +++ /dev/null @@ -1,14 +0,0 @@ -defmodule ElixirScript.Translator.Access.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "translate access" do - ex_ast = quote do - a = [] - a[:b] - end - js_code = "a[Symbol.for('b')]" - - assert_translation(ex_ast, js_code) - end -end diff --git a/test/translator/atom_test.exs b/test/translator/atom_test.exs deleted file mode 100644 index 90edfc9d..00000000 --- a/test/translator/atom_test.exs +++ /dev/null @@ -1,14 +0,0 @@ -defmodule ElixirScript.Translator.Atom.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "translate atom" do - ex_ast = quote do: :atom - assert_translation(ex_ast, "Symbol.for('atom')") - end - - test "Call Atom module" do - ex_ast = quote do: Atom.to_string(:atom) - assert_translation(ex_ast, "Elixir.ElixirScript.Atom.__load(Elixir).to_string(Symbol.for('atom'))") - end -end diff --git a/test/translator/bitstring_test.exs b/test/translator/bitstring_test.exs deleted file mode 100644 index 2faef0e2..00000000 --- a/test/translator/bitstring_test.exs +++ /dev/null @@ -1,95 +0,0 @@ -defmodule ElixirScript.Translator.Bitstring.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "translate bitstring" do - ex_ast = quote do: <<1, 2, 3>> - assert_translation(ex_ast, "new Bootstrap.Core.BitString(Bootstrap.Core.BitString.integer(1), Bootstrap.Core.BitString.integer(2), Bootstrap.Core.BitString.integer(3))") - - ex_ast = quote do: <<1, "foo">> - assert_translation(ex_ast, "new Bootstrap.Core.BitString(Bootstrap.Core.BitString.integer(1), Bootstrap.Core.BitString.binary('foo'))") - - ex_ast = quote do: <<1, "foo" :: binary>> - assert_translation(ex_ast, "new Bootstrap.Core.BitString(Bootstrap.Core.BitString.integer(1), Bootstrap.Core.BitString.binary('foo'))") - - ex_ast = quote do: <<1, "foo" :: utf8, "bar" :: utf32>> - assert_translation(ex_ast, "new Bootstrap.Core.BitString(Bootstrap.Core.BitString.integer(1), Bootstrap.Core.BitString.utf8('foo'), Bootstrap.Core.BitString.utf32('bar'))") - - ex_ast = quote do - rest = "oo" - <<102 :: integer-native, rest :: binary>> - end - assert_translation(ex_ast, "new Bootstrap.Core.BitString(Bootstrap.Core.BitString.native(Bootstrap.Core.BitString.integer(102)), Bootstrap.Core.BitString.binary(rest))") - - ex_ast = quote do - rest = "oo" - <<102 :: unsigned-big-integer, rest :: binary>> - end - assert_translation(ex_ast, "new Bootstrap.Core.BitString(Bootstrap.Core.BitString.integer(Bootstrap.Core.BitString.big(Bootstrap.Core.BitString.unsigned(102))), Bootstrap.Core.BitString.binary(rest))") - - ex_ast = quote do - rest = 100 - <<102, rest :: size(16)>> - end - - assert_translation(ex_ast, "new Bootstrap.Core.BitString(Bootstrap.Core.BitString.integer(102), Bootstrap.Core.BitString.size(rest, 16))") - - ex_ast = quote do - rest = 100 - <<102, rest :: size(16)-unit(4)>> - end - - assert_translation(ex_ast, "new Bootstrap.Core.BitString(Bootstrap.Core.BitString.integer(102), Bootstrap.Core.BitString.unit(Bootstrap.Core.BitString.size(rest, 16), 4))") - - ex_ast = quote do - rest = 100 - <<102, rest :: 16 * 4>> - end - - assert_translation(ex_ast, "new Bootstrap.Core.BitString(Bootstrap.Core.BitString.integer(102), Bootstrap.Core.BitString.unit(Bootstrap.Core.BitString.size(rest, 16), 4))") - - ex_ast = quote do - rest = 100 - <<102, rest :: 16>> - end - - assert_translation(ex_ast, "new Bootstrap.Core.BitString(Bootstrap.Core.BitString.integer(102), Bootstrap.Core.BitString.size(rest, 16))") - - ex_ast = quote do: << 1, <<2>> >> - assert_translation(ex_ast, "new Bootstrap.Core.BitString(Bootstrap.Core.BitString.integer(1), new Bootstrap.Core.BitString(Bootstrap.Core.BitString.integer(2)))") - end - - test "translate pattern matching bitstring" do - ex_ast = quote do: <> = <<"Frank the Walrus">> - js_code = """ - let [name,species] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.bitStringMatch(Bootstrap.Core.BitString.size(Bootstrap.Core.BitString.binary({ - 'value': Bootstrap.Core.Patterns.variable() - }),5),Bootstrap.Core.BitString.binary(' the '),Bootstrap.Core.BitString.binary({ - 'value': Bootstrap.Core.Patterns.variable() - })),'Frank the Walrus'); - """ - - assert_translation(ex_ast, js_code) - - - ex_ast = quote do: <> = <<-100>> - js_code = """ - let [int] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.bitStringMatch(Bootstrap.Core.BitString.integer({ - 'value': Bootstrap.Core.Patterns.variable() - })),new Bootstrap.Core.BitString(Bootstrap.Core.BitString.binary(-100))); - """ - - assert_translation(ex_ast, js_code) - - - ex_ast = quote do: <<-100::signed, _rest::binary>> = <<-100, "foo">> - js_code = """ - let [_rest] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.bitStringMatch(Bootstrap.Core.BitString.signed(-100),Bootstrap.Core.BitString.binary({ - 'value': Bootstrap.Core.Patterns.variable() - })),new Bootstrap.Core.BitString(Bootstrap.Core.BitString.binary(-100),Bootstrap.Core.BitString.binary('foo'))); - """ - - assert_translation(ex_ast, js_code) - end - -end diff --git a/test/translator/bitwise_test.exs b/test/translator/bitwise_test.exs deleted file mode 100644 index 0f9f6a57..00000000 --- a/test/translator/bitwise_test.exs +++ /dev/null @@ -1,15 +0,0 @@ -defmodule ElixirScript.Translator.Bitwise.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "bitwise when imported" do - ex_ast = quote do - import Bitwise - 1 &&& 2 - end - - js_code = "1 & 2" - - assert_translation(ex_ast, js_code) - end -end diff --git a/test/translator/bug_test.exs b/test/translator/bug_test.exs deleted file mode 100644 index 6e3820a5..00000000 --- a/test/translator/bug_test.exs +++ /dev/null @@ -1,162 +0,0 @@ -defmodule ElixirScript.Translator.Bug.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "Translate function with 0 arguments" do - ex_ast = quote do - def test do - :atom - end - end - - js_code = """ - const test = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([],function(){ - return Symbol.for('atom'); - })); - """ - - assert_translation(ex_ast, js_code) - end - - test "Translate react element" do - ex_ast = quote do - def execute() do - React.createElement( - React.Text, - %{"style" => ""}, - "Welcome to React Native!" - ) - end - end - - js_code = """ - React.createElement(React.Text,Object.freeze({ - style: '' - }),'Welcome to React Native!') - """ - - assert_translation(ex_ast, js_code) - - end - - test "replace !" do - ex_ast = quote do - def execute(data, i) do - Enum.fetch!(data, i) - end - end - - js_code = """ - Bootstrap.Enum.fetch__emark__(data, i) - """ - - assert_translation(ex_ast, js_code) - end - - test "chain calls correctly" do - ex_ast = quote do - def execute() do - :this.getRawCanvas().getContext("2d") - end - end - - js_code = """ - Bootstrap.Core.Functions.call_property(this, 'getRawCanvas').getContext('2d') - """ - - assert_translation(ex_ast, js_code) - - - ex_ast = quote do - def execute(one) do - :this.getRawCanvas(one).get("fg").getContext("2d") - end - end - - js_code = """ - this.getRawCanvas(one).get('fg').getContext('2d') - """ - - assert_translation(ex_ast, js_code) - end - - test "correctly call multi-module functions" do - ex_ast = quote do - def getDispatcher() do - DeLorean.Flux.createDispatcher(%{ - startPainting: fn() -> :this.dispatch("startPainting") end, - stopPainting: fn() -> :this.dispatch("stopPainting") end, - addPoint: fn(data) -> :this.dispatch("addPoint", data) end, - getStores: fn() -> %{ graphic: GraphicStore } end - }) - end - end - - - js_code = """ - const getDispatcher = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([],function() { - return DeLorean.Flux.createDispatcher(Object.freeze({ - [Symbol.for('startPainting')]: Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([],function() { - return this.dispatch('startPainting'); - })), [Symbol.for('stopPainting')]: Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([],function() { - return this.dispatch('stopPainting'); - })), [Symbol.for('addPoint')]: Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()],function(data) { - return this.dispatch('addPoint',data); - })), [Symbol.for('getStores')]: Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([],function() { - return Object.freeze({ - [Symbol.for('graphic')]: GraphicStore - }); - })) - })); - })); - """ - - assert_translation(ex_ast, js_code) - end - - - test "test array returns correctly" do - ex_ast = quote do - def my_func(x) do - [x.a, x.b] - end - end - - js_code = """ - const my_func = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()],function(x){ - return Object.freeze([Bootstrap.Core.Functions.call_property(x,'a'), Bootstrap.Core.Functions.call_property(x,'b')]); - })); - """ - - assert_translation(ex_ast, js_code) - end - - test "Elixir.Enum.member__qmark__ does not show up in translation" do - ex_ast = quote do - Enum.member?([1, 2, 3], 1) - end - - js_code = """ - Elixir.Enum.member__qmark__ - """ - - refute_translation(ex_ast, js_code) - end - - test "pipe translates correctly" do - ex_ast = quote do - def execute() do - :document.getElementById("main") |> JS.update(%{"innerHTML" => @html}) - end - end - - js_code = """ - Object.assign(document.getElementById('main'), Object.freeze({ - innerHTML: html - })) - """ - - assert_translation(ex_ast, js_code) - end - -end diff --git a/test/translator/capture_test.exs b/test/translator/capture_test.exs deleted file mode 100644 index ea61fc93..00000000 --- a/test/translator/capture_test.exs +++ /dev/null @@ -1,131 +0,0 @@ -defmodule ElixirScript.Translator.Capture.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "translate capture operator with Module, function, and arity" do - ex_ast = quote do - fun = &Elixir.Kernel.is_atom/1 - end - - js_code = """ - let [fun] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(), Elixir.ElixirScript.Kernel.__load(Elixir).is_atom); - """ - - assert_translation(ex_ast, js_code) - - end - - test "translate capture operator with function, and parameters" do - - ex_ast = quote do - fun = &is_atom(&1) - end - - js_code = """ - let [fun] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(),Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()],function(__1) { - return Elixir.ElixirScript.Kernel.__load(Elixir).is_atom(__1); - }))); - """ - - assert_translation(ex_ast, js_code) - - - end - - test "translate capture operator with function, and arity" do - - ex_ast = quote do - fun = &is_atom/1 - end - - js_code = """ - let [fun] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(),is_atom); - """ - - assert_translation(ex_ast, js_code) - - end - - test "translate capture operator with anonymous function" do - - ex_ast = quote do - fun = &(&1 * 2) - end - - js_code = """ - let [fun] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(),Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()],function(__1) { - return __1 * 2; - }))); - """ - - assert_translation(ex_ast, js_code) - - end - - test "translate capture operator with anonymous function tuple" do - - ex_ast = quote do - fun = &{&1, &2} - end - - js_code = """ - let [fun] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(),Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()],function(__1,__2) { - return new Bootstrap.Core.Tuple(__1,__2); - }))); - """ - - assert_translation(ex_ast, js_code) - - ex_ast = quote do - fun = &{&1, &2, &3} - end - - js_code = """ - let [fun] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(),Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()],function(__1,__2,__3) { - return new Bootstrap.Core.Tuple(__1,__2,__3); - }))); - """ - - assert_translation(ex_ast, js_code) - - - end - - test "translate capture operator with anonymous functions as parameters" do - - ex_ast = quote do - def process(a) do - end - - def execute() do - Enum.map([], &process(&1)) - end - end - - js_code = """ - Bootstrap.Enum.map(Object.freeze([]),Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()],function(__1) { - return process(__1); - }))) - """ - - assert_translation(ex_ast, js_code) - - - ex_ast = quote do - def process_event(a) do - end - - def execute() do - Elem.keypress(&process_event(&1)) - end - end - - js_code = """ - Elem.keypress(Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()],function(__1) { - return process_event(__1); - }))) - """ - - assert_translation(ex_ast, js_code) - end -end diff --git a/test/translator/case_test.exs b/test/translator/case_test.exs deleted file mode 100644 index ccdc4161..00000000 --- a/test/translator/case_test.exs +++ /dev/null @@ -1,221 +0,0 @@ -defmodule ElixirScript.Translator.Case.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "translate case" do - - ex_ast = quote do - def execute() do - data = :ok - case data do - :ok -> 1 - :error -> nil - end - end - end - - js_code = """ - Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Symbol.for('ok')],function() { - return 1; - }),Bootstrap.Core.Patterns.clause([Symbol.for('error')],function() { - return null; - })).call(this,data) - """ - - assert_translation(ex_ast, js_code) - - ex_ast = quote do - data = true - case data do - false -> value = 13 - true -> true - end - end - - js_code = """ - Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([false],function() { - let [value] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(),13); - return value; - }),Bootstrap.Core.Patterns.clause([true],function() { - return true; - })).call(this,data) - """ - - assert_translation(ex_ast, js_code) - - - - ex_ast = quote do - data = :ok - case data do - false -> value = 13 - _ -> true - end - end - - js_code = """ - Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([false],function() { - let [value] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(),13); - return value; - }),Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.wildcard()],function() { - return true; - })).call(this,data) - """ - - assert_translation(ex_ast, js_code) - end - - test "translate case with guard" do - ex_ast = quote do - data = :ok - case data do - number when number in [1,2,3,4] -> - value = 13 - _ -> - true - end - end - - js_code = """ - Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()],function(number) { - let [value] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(),13); - return value; - },function(number) { - return Bootstrap.Core.Functions.contains(number,Object.freeze([1, 2, 3, 4])); - }),Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.wildcard()],function() { - return true; - })).call(this,data) - """ - - assert_translation(ex_ast, js_code) - end - - test "translate case with multiple guards" do - ex_ast = quote do - data = :ok - case data do - number when number in [1,2,3,4] when number in [4, 3, 2, 1] -> - value = 13 - _ -> - true - end - end - - js_code = """ - Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()],function(number) { - let [value] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(),13); - return value; - },function(number) { - return Bootstrap.Core.Functions.contains(number,Object.freeze([1, 2, 3, 4])) || Bootstrap.Core.Functions.contains(number,Object.freeze([4, 3, 2, 1])); - }),Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.wildcard()],function() { - return true; - })).call(this,data) - """ - - assert_translation(ex_ast, js_code) - end - - test "translate case with multiple statements in body" do - ex_ast = quote do - def execute() do - data = :ok - case data do - :ok -> - :console.info("info") - Todo.add(data) - :error -> - nil - end - end - end - - js_code = """ - Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Symbol.for('ok')],function() { - console.info('info'); - return Todo.add(data); - }),Bootstrap.Core.Patterns.clause([Symbol.for('error')],function() { - return null; - })).call(this,data) - """ - - assert_translation(ex_ast, js_code) - end - - test "translate case with destructing" do - ex_ast = quote do - def execute() do - data = :ok - case data do - { one, two } -> - :console.info(one) - :error -> - nil - end - end - end - - js_code = """ - Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.type(Bootstrap.Core.Tuple, { - values: [Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()] - })], function(one, two) { - return console.info(one); - }), Bootstrap.Core.Patterns.clause([Symbol.for('error')], function() { - return null; - })).call(this, data) - """ - - assert_translation(ex_ast, js_code) - end - - test "translate case with nested destructing" do - ex_ast = quote do - def execute() do - data = :error - case data do - { {one, two} , three } -> - :console.info(one) - :error -> - nil - end - end - end - - js_code = """ - Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.type(Bootstrap.Core.Tuple, { - values: [Bootstrap.Core.Patterns.type(Bootstrap.Core.Tuple, { - values: [Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()] - }), Bootstrap.Core.Patterns.variable()] - })], function(one, two, three) { - return console.info(one); - }), Bootstrap.Core.Patterns.clause([Symbol.for('error')], function() { - return null; - })).call(this, data) - """ - - assert_translation(ex_ast, js_code) - - ex_ast = quote do - data = :error - case data do - { one, {two, three} } -> - :console.info(one) - :error -> - nil - end - end - - js_code = """ - Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.type(Bootstrap.Core.Tuple, { - values: [Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.type(Bootstrap.Core.Tuple, { - values: [Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()] - })] - })], function(one, two, three) { - return console.info(one); - }), Bootstrap.Core.Patterns.clause([Symbol.for('error')], function() { - return null; - })).call(this, data) - """ - - assert_translation(ex_ast, js_code) - end -end diff --git a/test/translator/commonjs_test.exs b/test/translator/commonjs_test.exs deleted file mode 100644 index 187a9cdd..00000000 --- a/test/translator/commonjs_test.exs +++ /dev/null @@ -1,22 +0,0 @@ -defmodule ElixirScript.Translator.CommonJS.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "translate module to commonjs" do - ex_ast = quote do - defmodule Elephant do - @ul "#todo-list" - - def something() do - @ul - end - end - end - - js_code = """ - module.exports = Elixir - """ - - assert_translation(ex_ast, js_code, :common) - end -end diff --git a/test/translator/cond_test.exs b/test/translator/cond_test.exs deleted file mode 100644 index 8b5f605d..00000000 --- a/test/translator/cond_test.exs +++ /dev/null @@ -1,58 +0,0 @@ -defmodule ElixirScript.Translator.Cond.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "translate cond" do - ex_ast = quote do - cond do - 1 + 1 == 1 -> - "This will never match" - 2 * 2 != 4 -> - "Nor this" - true -> - "This will" - end - end - - js_code = """ - Bootstrap.Core.SpecialForms.cond(Object.freeze([1 + 1 == 1, function() { - return 'This will never match'; - }]),Object.freeze([2 * 2 != 4, function() { - return 'Nor this'; - }]),Object.freeze([true, function() { - return 'This will'; - }])) - """ - - assert_translation(ex_ast, js_code) - - ex_ast = quote do - cond do - 1 + 1 == 1 -> - a = 1 - "This will never match" - 2 * 2 != 4 -> - a = 2 - "Nor this" - true -> - a = 3 - "This will" - end - end - - js_code = """ - Bootstrap.Core.SpecialForms.cond(Object.freeze([1 + 1 == 1, function() { - let [a] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(),1); - return 'This will never match'; - }]),Object.freeze([2 * 2 != 4, function() { - let [a] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(),2); - return 'Nor this'; - }]),Object.freeze([true, function() { - let [a] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(),3); - return 'This will'; - }])) - """ - - assert_translation(ex_ast, js_code) - end -end diff --git a/test/translator/defdelegate_test.exs b/test/translator/defdelegate_test.exs deleted file mode 100644 index d6488ab2..00000000 --- a/test/translator/defdelegate_test.exs +++ /dev/null @@ -1,28 +0,0 @@ -defmodule ElixirScript.Translator.Defdelegate.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "translate defdelegate" do - ex_ast = quote do: defdelegate reverse(list), to: :lists - - js_code = """ - const reverse = function(list) { - return Bootstrap.Core.Functions.reverse(list); - }; - """ - - assert_translation(ex_ast, js_code) - end - - test "translate defdelegate as another name" do - ex_ast = quote do: defdelegate other_reverse(list), to: :lists, as: :reverse - - js_code = """ - const other_reverse = function(list) { - return Bootstrap.Core.Functions.reverse(list); - }; - """ - - assert_translation(ex_ast, js_code) - end -end \ No newline at end of file diff --git a/test/translator/defmodule_test.exs b/test/translator/defmodule_test.exs deleted file mode 100644 index acc965e7..00000000 --- a/test/translator/defmodule_test.exs +++ /dev/null @@ -1,139 +0,0 @@ -defmodule ElixirScript.Translator.Defmodule.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "translate empty module" do - ex_ast = quote do - defmodule Elephant do - end - end - - js_code = """ - const __exports = {}; - """ - - assert_translation(ex_ast, js_code) - end - - test "translate defmodules" do - ex_ast = quote do - defmodule Elephant do - require JS - @ul "#todo-list" - - def something() do - @ul - end - - JS.defgenp something_else() do - end - end - end - - js_code = """ - const something = Bootstrap.Core.Patterns.defmatchgen(Bootstrap.Core.Patterns.clause([], function*() { - return ul; - })); - - const ul = '#todo-list'; - - const something_else = Bootstrap.Core.Patterns.defmatchgen(Bootstrap.Core.Patterns.clause([], function*() { - return null; - })); - - const __exports = { - something - }; - """ - - assert_translation(ex_ast, js_code) - end - - test "translate modules with inner modules" do - ex_ast = quote do - defmodule Animals do - - defmodule Elephant do - defstruct [trunk: true] - end - - def something() do - %Animals.Elephant{} - end - - defp something_else() do - end - - end - end - - js_code = """ - const Elixir$Animals$Elephant = Bootstrap.Core.Functions.defstruct({ - [Symbol.for('__struct__')]: Symbol.for('Elixir.Animals.Elephant'), [Symbol.for('trunk')]: true - }); - """ - - assert_translation(ex_ast, js_code) - end - - - test "translate modules with inner module that has inner module" do - ex_ast = quote do - defmodule Animals do - - defmodule Elephant do - defstruct trunk: true - - defmodule Bear do - defstruct trunk: true - end - end - - - def something() do - %Animals.Elephant{} - end - - defp something_else() do - end - - end - end - - js_code = """ - const Elixir$Animals$Elephant$Bear = Bootstrap.Core.Functions.defstruct({ - [Symbol.for('__struct__')]: Symbol.for('Elixir.Animals.Elephant.Bear'), - [Symbol.for('trunk')]: true - }); - """ - - assert_translation(ex_ast, js_code) - end - - test "Pull out module references and make them into imports if modules listed" do - ex_ast = quote do - defmodule Lions.Tigers.Bears do - def oh_my() do - end - end - - defmodule Lions.Tigers do - def oh_my() do - end - - Lions.Tigers.Bears.oh_my() - end - - defmodule Animals do - Lions.Tigers.oh_my() - end - end - - js_code = """ - Elixir.Lions.Tigers.Bears.__load(Elixir).oh_my() - """ - - assert_translation(ex_ast, js_code) - end - -end diff --git a/test/translator/for_test.exs b/test/translator/for_test.exs deleted file mode 100644 index faec216e..00000000 --- a/test/translator/for_test.exs +++ /dev/null @@ -1,226 +0,0 @@ -defmodule ElixirScript.Translator.For.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "translate simple for" do - ex_ast = quote do - for n <- [1, 2, 3, 4], do: n * 2 - end - - js_code = """ - Bootstrap.Core.SpecialForms._for( - Bootstrap.Core.Patterns.clause( - [Bootstrap.Core.Patterns.variable()], - function(n) { - return n * 2; - }, - function() { - return true; - } - ), - [ - Bootstrap.Core.Patterns.list_generator( - Bootstrap.Core.Patterns.variable(), - Object.freeze([1, 2, 3, 4]) - ) - ], - Elixir$ElixirScript$Collectable, - Object.freeze([]) - ) - """ - - assert_translation(ex_ast, js_code) - end - - test "translate simple for with into" do - ex_ast = quote do - for n <- [1, 2, 3, 4], into: [], do: n * 2 - end - - js_code = """ - Bootstrap.Core.SpecialForms._for( - Bootstrap.Core.Patterns.clause( - [Bootstrap.Core.Patterns.variable()], - function(n) { - return n * 2; - }, - function() { - return true; - } - ), - [ - Bootstrap.Core.Patterns.list_generator( - Bootstrap.Core.Patterns.variable(), - Object.freeze([1, 2, 3, 4]) - ) - ], - Elixir$ElixirScript$Collectable, - Object.freeze([]) - ) - """ - - assert_translation(ex_ast, js_code) - end - - test "translate multiple generator for" do - ex_ast = quote do - for x <- [1, 2], y <- [2, 3], do: x*y - end - - js_code = """ - Bootstrap.Core.SpecialForms._for( - Bootstrap.Core.Patterns.clause( - [Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()], - function(x, y) { - return x * y; - }, - function() { - return true; - } - ), - [ - Bootstrap.Core.Patterns.list_generator( - Bootstrap.Core.Patterns.variable(), - Object.freeze([1, 2]) - ), - Bootstrap.Core.Patterns.list_generator( - Bootstrap.Core.Patterns.variable(), - Object.freeze([2, 3]) - ) - ], - Elixir$ElixirScript$Collectable, - Object.freeze([]) - ) - """ - - assert_translation(ex_ast, js_code) - end - - test "translate multiple generator for, assignment, and do block" do - ex_ast = quote do - r = for x <- [1, 2], y <- [2, 3] do - x*y - end - end - - js_code = """ - let [r] = Bootstrap.Core.Patterns.match( - Bootstrap.Core.Patterns.variable(), - Bootstrap.Core.SpecialForms._for( - Bootstrap.Core.Patterns.clause( - [Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()], - function(x, y) { - return x * y; - }, - function() { - return true; - } - ), - [ - Bootstrap.Core.Patterns.list_generator( - Bootstrap.Core.Patterns.variable(), - Object.freeze([1, 2]) - ), - Bootstrap.Core.Patterns.list_generator( - Bootstrap.Core.Patterns.variable(), - Object.freeze([2, 3]) - ) - ], - Elixir$ElixirScript$Collectable, - Object.freeze([]) - ) - ); - """ - - assert_translation(ex_ast, js_code) - end - - test "translate for with filter" do - ex_ast = quote do - for n <- [1, 2, 3, 4, 5, 6], rem(n, 2) == 0, do: n - end - - js_code = """ - Bootstrap.Core.SpecialForms._for( - Bootstrap.Core.Patterns.clause( - [Bootstrap.Core.Patterns.variable()], - function(n) { - return n; - }, - function(n) { - return n % 2 == 0; - } - ), - [ - Bootstrap.Core.Patterns.list_generator( - Bootstrap.Core.Patterns.variable(), - Object.freeze([1, 2, 3, 4, 5, 6]) - ) - ], - Elixir$ElixirScript$Collectable, - Object.freeze([]) - ) - """ - - assert_translation(ex_ast, js_code) - end - - test "translate for with pattern matched input" do - ex_ast = quote do - for {:user, name} <- [user: "john", admin: "john", user: "meg"] do - Elixir.String.upcase(name) - end - end - - js_code = """ - Bootstrap.Core.SpecialForms._for( - Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.type(Bootstrap.Core.Tuple, { - values: [Symbol.for('user'), Bootstrap.Core.Patterns.variable()] - })], function(name) { - return Elixir.ElixirScript.String.__load(Elixir).upcase(name); - }, function() { - return true; - }), - [ - Bootstrap.Core.Patterns.list_generator(Bootstrap.Core.Patterns.type(Bootstrap.Core.Tuple, { - values: [Symbol.for('user'), Bootstrap.Core.Patterns.variable()] - }), Object.freeze([new Bootstrap.Core.Tuple(Symbol.for('user'), 'john'), new Bootstrap.Core.Tuple(Symbol.for('admin'), 'john'), new Bootstrap.Core.Tuple(Symbol.for('user'), 'meg')])) - ], - Elixir$ElixirScript$Collectable, - Object.freeze([])) - """ - - assert_translation(ex_ast, js_code) - end - - test "translate for with bitstring" do - ex_ast = quote do - pixels = <<1, 2, 3, 4, 5, 6>> - for <> do - {r, g, b} - end - end - - js_code = """ - Bootstrap.Core.SpecialForms._for(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.bitStringMatch(Bootstrap.Core.BitString.size({ - 'value': Bootstrap.Core.Patterns.variable() - }, 8), Bootstrap.Core.BitString.size({ - 'value': Bootstrap.Core.Patterns.variable() - }, 8), Bootstrap.Core.BitString.size({ - 'value': Bootstrap.Core.Patterns.variable() - }, 8))], function(r, g, b) { - return new Bootstrap.Core.Tuple(r, g, b); - }, function() { - return true; - }), [Bootstrap.Core.Patterns.bitstring_generator(Bootstrap.Core.Patterns.bitStringMatch(Bootstrap.Core.BitString.size({ - 'value': Bootstrap.Core.Patterns.variable() - }, 8), Bootstrap.Core.BitString.size({ - 'value': Bootstrap.Core.Patterns.variable() - }, 8), Bootstrap.Core.BitString.size({ - 'value': Bootstrap.Core.Patterns.variable() - }, 8)), pixels)], Elixir$ElixirScript$Collectable, Object.freeze([])) - """ - - assert_translation(ex_ast, js_code) - end -end diff --git a/test/translator/function_test.exs b/test/translator/function_test.exs deleted file mode 100644 index 77748810..00000000 --- a/test/translator/function_test.exs +++ /dev/null @@ -1,809 +0,0 @@ -defmodule ElixirScript.Translator.Function.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "translate functions" do - ex_ast = quote do - def test1() do - end - end - - js_code = """ - const test1 = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([],function() { - return null; - })); - """ - - assert_translation(ex_ast, js_code) - - ex_ast = quote do - def test1(alpha, beta) do - end - end - - js_code = """ - const test1 = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()],function(alpha,beta) { - return null; - })); - """ - - assert_translation(ex_ast, js_code) - - ex_ast = quote do - def test1(alpha, beta) do - a = alpha - end - end - - js_code = """ - const test1 = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()],function(alpha,beta) { - let [a] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(),alpha); - return a; - })); - """ - - assert_translation(ex_ast, js_code) - - ex_ast = quote do - def test1(alpha, beta) do - if 1 == 1 do - 1 - else - 2 - end - end - end - - js_code = """ - const test1 = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()],function(alpha,beta) { - return Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()],function(x) { - return 2; - },function(x) { - return x === null || x === false; - }),Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.wildcard()],function() { - return 1; - })).call(this,1 == 1); - })); - """ - - assert_translation(ex_ast, js_code) - - ex_ast = quote do - def test1(alpha, beta) do - if 1 == 1 do - if 2 == 2 do - 4 - else - a = 1 - end - else - 2 - end - end - end - - js_code = """ - const test1 = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()], function(alpha, beta) { - return Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()], function(x) { - return 2; - }, function(x) { - return x === null || x === false; - }), Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.wildcard()], function() { - return Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()], function(x) { - let [a] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(), 1); - - return a; - }, function(x) { - return x === null || x === false; - }), Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.wildcard()], function() { - return 4; - })).call(this, 2 == 2); - })).call(this, 1 == 1); - })); - """ - - assert_translation(ex_ast, js_code) - - ex_ast = quote do - def test1(alpha, beta) do - {a, b} = {1, 2} - end - end - - js_code = """ - const test1 = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()], function(alpha, beta) { - let [a, b] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.type(Bootstrap.Core.Tuple, { - values: [Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()] - }), new Bootstrap.Core.Tuple(1, 2)); - let _ref = new Bootstrap.Core.Tuple(a, b); - return _ref; - })); - """ - - assert_translation(ex_ast, js_code) - end - - test "translate function calls" do - ex_ast = quote do - defmodule Taco do - def test1() do - end - end - - - Taco.test1() - end - - js_code = "Elixir.Taco.__load(Elixir).test1()" - - assert_translation(ex_ast, js_code) - - ex_ast = quote do - defmodule Taco do - def test1(a, b) do - end - end - - Taco.test1(3, 2) - end - - js_code = "Elixir.Taco.__load(Elixir).test1(3,2)" - - assert_translation(ex_ast, js_code) - - ex_ast = quote do - defmodule Taco do - def test1(a, b) do - end - - def test2(a) do - end - end - - Taco.test1(Taco.test2(1), 2) - end - - js_code = "Elixir.Taco.__load(Elixir).test1(Elixir.Taco.__load(Elixir).test2(1), 2)" - - assert_translation(ex_ast, js_code) - end - - - test "translate anonymous functions" do - ex_ast = quote do - list = [] - Enum.map(list, fn(x) -> x * 2 end) - end - - js_code = """ - Bootstrap.Enum.map(list,Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()],function(x) { - return x * 2; - }))) - """ - - assert_translation(ex_ast, js_code) - end - - test "translate function arity" do - ex_ast = quote do - defmodule Example do - - defp example() do - end - - defp example(oneArg) do - end - - defp example(oneArg, twoArg) do - end - - defp example(oneArg, twoArg, redArg) do - end - - defp example(oneArg, twoArg, redArg, blueArg) do - end - end - end - - js_code = """ - const example = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([],function() { - return null; - }),Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()],function(oneArg) { - return null; - }),Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()],function(oneArg,twoArg) { - return null; - }),Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()],function(oneArg,twoArg,redArg) { - return null; - }),Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()],function(oneArg,twoArg,redArg,blueArg) { - return null; - })); - """ - assert_translation(ex_ast, js_code) - - - ex_ast = quote do - defmodule Example do - def example() do - end - - def example(oneArg) do - end - - def example(oneArg, twoArg) do - end - - def example(oneArg, twoArg, redArg) do - end - - def example(oneArg, twoArg, redArg, blueArg) do - end - end - end - - js_code = """ - const example = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([],function() { - return null; - }),Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()],function(oneArg) { - return null; - }),Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()],function(oneArg,twoArg) { - return null; - }),Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()],function(oneArg,twoArg,redArg) { - return null; - }),Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()],function(oneArg,twoArg,redArg,blueArg) { - return null; - })); - """ - assert_translation(ex_ast, js_code) - - - ex_ast = quote do - defmodule Example do - def example(oneArg) do - end - end - end - - js_code = """ - const example = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()],function(oneArg) { - return null; - })); - """ - assert_translation(ex_ast, js_code) - - end - - test "test Elixir.Kernel function" do - ex_ast = quote do - is_atom(:atom) - end - - js_code = "Elixir.ElixirScript.Kernel.__load(Elixir).is_atom(Symbol.for('atom'))" - - assert_translation(ex_ast, js_code) - end - - test "guards" do - ex_ast = quote do - def something(one) when is_number(one) do - end - end - - - js_code = """ - const something = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()],function(one) { - return null; - },function(one) { - return Elixir.ElixirScript.Kernel.__load(Elixir).is_number(one); - })); - """ - - assert_translation(ex_ast, js_code) - - - ex_ast = quote do - def something(one) when is_number(one) or is_atom(one) do - end - end - - - js_code = """ - const something = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()],function(one) { - return null; - },function(one) { - return Elixir.ElixirScript.Kernel.__load(Elixir).is_number(one) || Elixir.ElixirScript.Kernel.__load(Elixir).is_atom(one); - })); - """ - - assert_translation(ex_ast, js_code) - - ex_ast = quote do - defp something(one) when is_number(one) or is_atom(one) do - end - end - - - js_code = """ - const something = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()],function(one) { - return null; - },function(one) { - return Elixir.ElixirScript.Kernel.__load(Elixir).is_number(one) || Elixir.ElixirScript.Kernel.__load(Elixir).is_atom(one); - })); - """ - - assert_translation(ex_ast, js_code) - - ex_ast = quote do - defp something(one, two) when one in [1, 2, 3] do - end - end - - - js_code = """ - const something = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()],function(one,two) { - return null; - },function(one,two) { - return Bootstrap.Core.Functions.contains(one,Object.freeze([1, 2, 3])); - })); - """ - - assert_translation(ex_ast, js_code) - - ex_ast = quote do - defmodule Example do - def something(one) when one in [1, 2, 3] do - end - - def something(one) when is_number(one) or is_atom(one) do - end - end - end - - js_code = """ - const something = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()],function(one) { - return null; - },function(one) { - return Bootstrap.Core.Functions.contains(one,Object.freeze([1, 2, 3])); - }),Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()],function(one) { - return null; - },function(one) { - return Elixir.ElixirScript.Kernel.__load(Elixir).is_number(one) || Elixir.ElixirScript.Kernel.__load(Elixir).is_atom(one); - })); - """ - assert_translation(ex_ast, js_code) - - end - - test "pattern match function with literal" do - ex_ast = quote do - def something(1) do - end - end - - - js_code = """ - const something = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([1],function() { - return null; - })); - """ - - assert_translation(ex_ast, js_code) - end - - test "pattern match function with list" do - ex_ast = quote do - def something([apple | fruits]) do - end - end - - - js_code = """ - const something = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.headTail(Bootstrap.Core.Patterns.variable(),Bootstrap.Core.Patterns.variable())],function(apple,fruits) { - return null; - })); - """ - - assert_translation(ex_ast, js_code) - end - - test "pattern match function with multiple items in list" do - ex_ast = quote do - def something([apple, pear, banana]) do - end - end - - - js_code = """ - const something = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Object.freeze([Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()])],function(apple,pear,banana) { - return null; - })); - """ - - assert_translation(ex_ast, js_code) - end - - test "pattern match function with tuple" do - ex_ast = quote do - def something({ apple , fruits }) do - end - end - - - js_code = """ - const something = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.type(Bootstrap.Core.Tuple, { - values: [Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()] - })], function(apple, fruits) { - return null; - })); - """ - - assert_translation(ex_ast, js_code) - end - - test "pattern match function with struct" do - ex_ast = quote do - defmodule AStruct do - defstruct [] - end - - def something(%AStruct{}) do - end - end - - - js_code = """ - const something = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.type(Elixir.AStruct.__load(Elixir).Elixir$AStruct, {})], function() { - return null; - })); - """ - - assert_translation(ex_ast, js_code) - end - - test "pattern match function with struct reference" do - ex_ast = quote do - defmodule AStruct do - defstruct [] - end - - def something(%AStruct{} = a) do - end - - end - - js_code = """ - const something = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.capture(Bootstrap.Core.Patterns.type(Elixir.AStruct.__load(Elixir).Elixir$AStruct, {}))], function(a) { - return null; - })); - """ - assert_translation(ex_ast, js_code) - end - - test "pattern match function with map reference" do - ex_ast = quote do - def something(%{ which: 13 } = a) do - end - end - - js_code = """ - const something = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.capture({ - [Symbol.for('which')]: 13 - })],function(a) { - return null; - })); - """ - - assert_translation(ex_ast, js_code) - end - - test "pattern match function with struct decontructed" do - ex_ast = quote do - defmodule AStruct do - defstruct [:key, :key1] - end - - def something(%AStruct{key: value, key1: 2}) do - end - end - - - js_code = """ - const something = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.type(Elixir.AStruct.__load(Elixir).Elixir$AStruct, { - [Symbol.for('key')]: Bootstrap.Core.Patterns.variable(), [Symbol.for('key1')]: 2 - })], function(value) { - return null; - })); - """ - - assert_translation(ex_ast, js_code) - - ex_ast = quote do - defmodule AStruct do - defstruct [:key, :key1] - end - - def something(%AStruct{key: value, key1: 2}) when is_number(value) do - end - end - - - js_code = """ - const something = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.type(Elixir.AStruct.__load(Elixir).Elixir$AStruct, { - [Symbol.for('key')]: Bootstrap.Core.Patterns.variable(), [Symbol.for('key1')]: 2 - })], function(value) { - return null; - }, function(value) { - return Elixir.ElixirScript.Kernel.__load(Elixir).is_number(value); - })); - """ - - assert_translation(ex_ast, js_code) - end - - test "pattern match function with binary part" do - ex_ast = quote do - def something("Bearer " <> token) do - end - end - - - js_code = """ - const something = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.startsWith('Bearer ')],function(token) { - return null; - })); - """ - - assert_translation(ex_ast, js_code) - - ex_ast = quote do - def something("Bearer " <> token, hotel) do - end - end - - - js_code = """ - const something = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.startsWith('Bearer '), Bootstrap.Core.Patterns.variable()],function(token,hotel) { - return null; - })); - """ - - assert_translation(ex_ast, js_code) - - ex_ast = quote do - def something("Bearer " <> token, hotel, 1) do - end - end - - - js_code = """ - const something = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.startsWith('Bearer '), Bootstrap.Core.Patterns.variable(), 1],function(token,hotel) { - return null; - })); - """ - - assert_translation(ex_ast, js_code) - end - - test "combine pattern matched functions of same arity" do - ex_ast = quote do - defmodule Example do - def something(1) do - end - - def something(2) do - end - - def something(one) when is_binary(one) do - end - - def something(one) do - end - end - - end - - - js_code = """ - const something = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([1],function() { - return null; - }),Bootstrap.Core.Patterns.clause([2],function() { - return null; - }),Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()],function(one) { - return null; - },function(one) { - return Elixir.ElixirScript.Kernel.__load(Elixir).is_binary(one); - }),Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()],function(one) { - return null; - })); - """ - - assert_translation(ex_ast, js_code) - - end - - test "translate varible declaration correctly" do - ex_ast = quote do - def test1(alpha, beta) do - a = 1 - a = 2 - end - end - - js_code = """ - const test1 = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()],function(alpha,beta) { - let [a] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(),1); - let [a1] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(),2); - return a1; - })); - """ - - assert_translation(ex_ast, js_code) - - ex_ast = quote do - def test1(alpha, beta) do - a = 1 - a = a - a = 2 - end - end - - js_code = """ - const test1 = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()],function(alpha,beta) { - let [a] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(),1); - let [a1] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(),a); - let [a2] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(),2); - return a2; - })); - """ - - assert_translation(ex_ast, js_code) - - ex_ast = quote do - def test1(alpha, beta) do - a = 1 - [a, b, c] = [a, 2, 3] - end - end - - js_code = """ - const test1 = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()],function(alpha,beta) { - let [a] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(),1); - let [a1,b,c] = Bootstrap.Core.Patterns.match(Object.freeze([Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()]),Object.freeze([a, 2, 3])); - let _ref = Object.freeze([a1, b, c]); - return _ref; - })); - """ - - assert_translation(ex_ast, js_code) - end - - test "translate function variables with ? or !" do - ex_ast = quote do - def test1(alpha?, beta!) do - a? = 1 - b! = 2 - end - end - - js_code = """ - const test1 = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()],function(alpha__qmark__,beta__emark__) { - let [a__qmark__] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(),1); - let [b__emark__] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(),2); - return b__emark__; - })); - """ - - assert_translation(ex_ast, js_code) - end - - test "translate function params with defaults" do - ex_ast = quote do - def test1(alpha, beta \\ 0) do - end - end - - js_code = """ - const test1 = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable(0)],function(alpha,beta) { - return null; - })); - """ - - assert_translation(ex_ast, js_code) - - ex_ast = quote do - def test1(alpha \\ fn x -> x end) do - end - end - - js_code = """ - const test1 = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable(Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()],function(x) { - return x; - })))], - function(alpha) { - return null; - })); - """ - - assert_translation(ex_ast, js_code) - end - - test "def with catch" do - ex_ast = quote do - defp func(param) do - if true do - nil - else - :error - end - catch - :invalid -> :error - end - end - - js_code = """ - const func = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()], - function(param) { - return Bootstrap.Core.SpecialForms._try(function() { - return Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()], function(x) { - return Symbol.for('error'); - }, - function(x) { - return x === null || x === false; - }), - Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.wildcard()], function() { - return null; - })).call(this, true); - }, - null, - Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Symbol.for('invalid')], function() { - return Symbol.for('error'); - })), - null, - null - ); - })); - """ - - assert_translation(ex_ast, js_code) - end - - - test "translate anonymous function with variable bound" do - ex_ast = quote do - key = "test" - fn ^key -> :ok end - end - - js_code = """ - let [key] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(),'test'); - - Bootstrap.Core.Patterns.defmatch( - Bootstrap.Core.Patterns.clause( - [Bootstrap.Core.Patterns.bound(key)], - function() { - return Symbol.for('ok'); - } - ) - ) - """ - - assert_translation(ex_ast, js_code) - end - - test "multiple when guards" do - ex_ast = quote do - def something(one) when is_number(one) when is_atom(one) do - end - end - - - js_code = """ - const something = Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()],function(one) { - return null; - },function(one) { - return Elixir.ElixirScript.Kernel.__load(Elixir).is_number(one) || Elixir.ElixirScript.Kernel.__load(Elixir).is_atom(one); - })); - """ - - assert_translation(ex_ast, js_code) - end -end diff --git a/test/translator/kernel_test.exs b/test/translator/kernel_test.exs deleted file mode 100644 index d0041050..00000000 --- a/test/translator/kernel_test.exs +++ /dev/null @@ -1,89 +0,0 @@ -defmodule ElixirScript.Translator.Kernel.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "raise with bitstring" do - ex_ast = quote do - def execute() do - list = [] - raise ArgumentError, "cannot convert list to string. The list must contain only integers, strings or nested such lists; got: #{inspect list}" - end - end - - js_code = """ - throw ArgumentError.create(Object.freeze({ - [Symbol.for('message')]: 'cannot convert list to string. The list must contain only integers, strings or nested such lists; got: ' + Elixir.ElixirScript.String.Chars.__load(Elixir).to_string(inspect(list)) - })); - """ - - assert_translation(ex_ast, js_code) - end - - test "raise with string" do - ex_ast = quote do - def execute() do - raise ArgumentError, "cannot convert list to string. The list must contain only integers, strings or nested such lists; got" - end - end - - js_code = """ - throw ArgumentError.create(Object.freeze({ - [Symbol.for('message')]: 'cannot convert list to string. The list must contain only integers, strings or nested such lists; got' - })); - """ - - assert_translation(ex_ast, js_code) - end - - test "max" do - ex_ast = quote do - max(1, 2) - end - - js_code = """ - Elixir.ElixirScript.Kernel.__load(Elixir).max(1, 2) - """ - - assert_translation(ex_ast, js_code) - - end - - test "apply/3" do - ex_ast = quote do - apply(Enum, :reverse, [[1, 2, 3]]) - end - - js_code = """ - Elixir.ElixirScript.Kernel.__load(Elixir).apply(Enum, Symbol.for('reverse'), Object.freeze([Object.freeze([1, 2, 3])])) - """ - - assert_translation(ex_ast, js_code) - - end - - test "hd" do - ex_ast = quote do - hd([1, 2, 3]) - end - - js_code = """ - Elixir.ElixirScript.Kernel.__load(Elixir).hd(Object.freeze([1, 2, 3])) - """ - - assert_translation(ex_ast, js_code) - - end - - test "tl" do - ex_ast = quote do - tl([1, 2, 3]) - end - - js_code = """ - Elixir.ElixirScript.Kernel.__load(Elixir).tl(Object.freeze([1, 2, 3])) - """ - - assert_translation(ex_ast, js_code) - - end -end diff --git a/test/translator/list_test.exs b/test/translator/list_test.exs deleted file mode 100644 index c4af1fc4..00000000 --- a/test/translator/list_test.exs +++ /dev/null @@ -1,70 +0,0 @@ -defmodule ElixirScript.Translator.List.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "translate list" do - ex_ast = quote do: [1, 2, 3] - js_code = "Object.freeze([1, 2, 3])" - - assert_translation(ex_ast, js_code) - - ex_ast = quote do: ["a", "b", "c"] - js_code = "Object.freeze(['a', 'b', 'c'])" - - assert_translation(ex_ast, js_code) - - ex_ast = quote do: [:a, :b, :c] - js_code = "Object.freeze([Symbol.for('a'), Symbol.for('b'), Symbol.for('c')])" - - assert_translation(ex_ast, js_code) - - ex_ast = quote do: [:a, 2, "c"] - js_code = "Object.freeze([Symbol.for('a'), 2, 'c'])" - - assert_translation(ex_ast, js_code) - end - - test "concatenate lists" do - ex_ast = quote do: [1, 2, 3] ++ [4, 5, 6] - js_code = "Object.freeze([1, 2, 3]).concat(Object.freeze([4, 5, 6]))" - - assert_translation(ex_ast, js_code) - - ex_ast = quote do - list = [] - list ++ [4, 5, 6] - end - js_code = "list.concat(Object.freeze([4, 5, 6]))" - - assert_translation(ex_ast, js_code) - end - - test "prepend element" do - ex_ast = quote do - x = 1 - list = [] - [x | list] - end - - js_code = "Object.freeze([x]).concat(list)" - - assert_translation(ex_ast, js_code) - end - - test "prepend element in function" do - ex_ast = quote do - x = 1 - list = [] - - fn (_) -> [x|list] end - end - - js_code = """ - Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.wildcard()],function(){ - return Object.freeze([x]).concat(list); - })) - """ - - assert_translation(ex_ast, js_code) - end -end diff --git a/test/translator/map_test.exs b/test/translator/map_test.exs deleted file mode 100644 index 75a237d5..00000000 --- a/test/translator/map_test.exs +++ /dev/null @@ -1,87 +0,0 @@ -defmodule ElixirScript.Translator.Map.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "translate empty map" do - ex_ast = quote do: %{} - js_code = "Object.freeze({})" - - assert_translation(ex_ast, js_code) - end - - test "translate map with elements" do - ex_ast = quote do: %{one: "one", two: "two"} - js_code = "Object.freeze({[Symbol.for('one')]: 'one', [Symbol.for('two')]: 'two'})" - - assert_translation(ex_ast, js_code) - end - - test "translate map within map" do - ex_ast = quote do: %{one: "one", two: %{three: "three"}} - js_code = """ - Object.freeze({ - [Symbol.for('one')]: 'one', - [Symbol.for('two')]: Object.freeze({ - [Symbol.for('three')]: 'three' - }) - }) - """ - - assert_translation(ex_ast, js_code) - end - - test "translate map with string keys" do - ex_ast = quote do: %{"one" => "one", "two" => "two"} - js_code = """ - Object.freeze({ - one: 'one', two: 'two' - }) - """ - - assert_translation(ex_ast, js_code) - end - - - test "translate map update" do - ex_ast = quote do - map = %{value: 2} - %{ map | value: 1 } - end - - js_code = """ - Bootstrap.Core.SpecialForms.map_update(map,Object.freeze({ - [Symbol.for('value')]: 1 - })) - """ - - assert_translation(ex_ast, js_code) - end - - test "translate variable key" do - ex_ast = quote do - key = 1 - value = 2 - %{key => value} - end - - js_code = "Object.freeze({ [key]: value })" - assert_translation(ex_ast, js_code) - end - - test "translate bound map key" do - ex_ast = quote do - key = 1 - value = 2 - %{^key => value} = %{key => value} - end - js_code = """ - let [value1] = Bootstrap.Core.Patterns.match({ - [key]: Bootstrap.Core.Patterns.variable() - }, Object.freeze({ - [key]: value - })); - """ - assert_translation(ex_ast, js_code) - end - -end diff --git a/test/translator/match_test.exs b/test/translator/match_test.exs deleted file mode 100644 index 520dada0..00000000 --- a/test/translator/match_test.exs +++ /dev/null @@ -1,87 +0,0 @@ -defmodule ElixirScript.Translator.Match.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "translate simple match" do - ex_ast = quote do: a = 1 - js_code = "let [a] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(), 1);" - - assert_translation(ex_ast, js_code) - - ex_ast = quote do: a = :atom - js_code = "let [a] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(), Symbol.for('atom'));" - - assert_translation(ex_ast, js_code) - end - - test "translate tuple match" do - ex_ast = quote do - {a, b} = {1, 2} - end - js_code = """ - let [a, b] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.type(Bootstrap.Core.Tuple, { - values: [Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()] - }), new Bootstrap.Core.Tuple(1, 2)); - let _ref = new Bootstrap.Core.Tuple(a, b); - """ - - assert_translation(ex_ast, js_code) - - ex_ast = quote do: {a, _, c} = {1, 2, 3} - js_code = """ - let [a, undefined, c] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.type(Bootstrap.Core.Tuple, { - values: [Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.wildcard(), Bootstrap.Core.Patterns.variable()] - }), new Bootstrap.Core.Tuple(1, 2, 3)); - let _ref = new Bootstrap.Core.Tuple(a, undefined, c); - """ - - assert_translation(ex_ast, js_code) - - - ex_ast = quote do - a = 1 - {^a, _, c} = {1, 2, 3} - end - js_code = """ - let [, undefined, c] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.type(Bootstrap.Core.Tuple, { - values: [Bootstrap.Core.Patterns.bound(a), Bootstrap.Core.Patterns.wildcard(), Bootstrap.Core.Patterns.variable()] - }), new Bootstrap.Core.Tuple(1, 2, 3)); - let _ref = new Bootstrap.Core.Tuple(undefined, undefined, c); - """ - - assert_translation(ex_ast, js_code) - end - - test "translate bound match" do - ex_ast = quote do - a = 1 - ^a = 1 - end - - js_code = """ - let [] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.bound(a),1); - """ - - assert_translation(ex_ast, js_code) - end - - test "translate list match" do - ex_ast = quote do: [a, b] = [1, 2] - js_code = """ - let [a,b] = Bootstrap.Core.Patterns.match(Object.freeze([Bootstrap.Core.Patterns.variable(), Bootstrap.Core.Patterns.variable()]),Object.freeze([1, 2])); - let _ref = Object.freeze([a, b]); - """ - - assert_translation(ex_ast, js_code) - end - - test "translate head/tail match" do - ex_ast = quote do: [a | b] = [1, 2, 3, 4] - js_code = """ - let [a,b] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.headTail(Bootstrap.Core.Patterns.variable(),Bootstrap.Core.Patterns.variable()),Object.freeze([1, 2, 3, 4])); - let _ref = Object.freeze([a, b]); - """ - - assert_translation(ex_ast, js_code) - end -end diff --git a/test/translator/nil_test.exs b/test/translator/nil_test.exs deleted file mode 100644 index 4c77bed1..00000000 --- a/test/translator/nil_test.exs +++ /dev/null @@ -1,9 +0,0 @@ -defmodule ElixirScript.Translator.Nil.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "translate nil" do - ex_ast = quote do: nil - assert_translation(ex_ast, "null") - end -end diff --git a/test/translator/number_test.exs b/test/translator/number_test.exs deleted file mode 100644 index 6d2fe4f4..00000000 --- a/test/translator/number_test.exs +++ /dev/null @@ -1,18 +0,0 @@ -defmodule ElixirScript.Translator.Number.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "translate numbers" do - ex_ast = quote do: 1 - assert_translation(ex_ast, "1") - - ex_ast = quote do: 1_000 - assert_translation(ex_ast, "1000") - - ex_ast = quote do: 1.1 - assert_translation(ex_ast, "1.1") - - ex_ast = quote do: -1.1 - assert_translation(ex_ast, "-1.1") - end -end diff --git a/test/translator/pattern_matching_test.exs b/test/translator/pattern_matching_test.exs deleted file mode 100644 index b32b8ac3..00000000 --- a/test/translator/pattern_matching_test.exs +++ /dev/null @@ -1,245 +0,0 @@ -defmodule ElixirScript.Translator.PatternMatching.Test do - use ExUnit.Case - alias ElixirScript.Translator - alias ElixirScript.Translator.Primitive - alias ElixirScript.Translator.PatternMatching - alias ElixirScript.Translator.Map - alias ESTree.Tools.Builder, as: JS - alias ElixirScript.Translator.State - - setup do - {:ok, pid} = State.start_link(%{env: __ENV__}, []) - - State.set_module_data(pid, [{ - ElixirScript.Kernel, - %{app: :elixir, name: ElixirScript.Kernel, ast: {}, functions: []} - }]) - - scope = ElixirScript.Translator.LexicalScope.module_scope( - ElixirScript.Temp, - "temp.ex", - __ENV__, - pid, - %{ format: :es, module_formatter: ElixirScript.ModuleSystems.ES } - ) - - {:ok, [scope: scope]} - end - - test "match wildcard", %{scope: scope} do - params = [{:_, [], Test}] - result = PatternMatching.build_match(params, scope) - expected_result = {[PatternMatching.wildcard], [JS.identifier(:undefined)]} - - assert result == expected_result - end - - test "match one identifier param", %{scope: scope} do - params = [{:a, [], Test}] - result = PatternMatching.build_match(params, scope ) - expected_result = {[PatternMatching.parameter], [JS.identifier("a")]} - - assert result == expected_result - end - - test "match multiple identifier params", %{scope: scope} do - params = [{:a, [], Test}, {:b, [], Test}, {:c, [], Test}] - result = PatternMatching.build_match(params, scope ) - expected_result = { - List.duplicate(PatternMatching.parameter, 3), - [JS.identifier("a"), JS.identifier("b"), JS.identifier("c")] - } - - assert result == expected_result - end - - test "match head and tail param", %{scope: scope} do - params = [[{:|, [], [{:head, [], Elixir}, {:tail, [], Elixir}]}]] - result = PatternMatching.build_match(params, scope ) - expected_result = { - [PatternMatching.head_tail(PatternMatching.parameter, PatternMatching.parameter)], - [JS.identifier("head"), JS.identifier("tail")] - } - - assert result == expected_result - end - - test "match prefix param", %{scope: scope} do - params = [{:<>, [context: Elixir, import: Elixir.Kernel], ["Bearer ", {:token, [], Elixir}]}] - result = PatternMatching.build_match(params, scope ) - expected_result = { - [PatternMatching.starts_with("Bearer ")], - [JS.identifier("token")] - } - - assert result == expected_result - end - - test "match list", %{scope: scope} do - params = [[{:a, [], Elixir}, {:b, [], Elixir}, {:c, [], Elixir}]] - result = PatternMatching.build_match(params, scope ) - expected_result = { - [Primitive.make_list_no_translate(List.duplicate(PatternMatching.parameter, 3))], - [JS.identifier("a"), JS.identifier("b"), JS.identifier("c")] - } - - assert result == expected_result - end - - test "match list with a literal", %{scope: scope} do - params = [[1, {:b, [], Elixir}, {:c, [], Elixir}]] - result = PatternMatching.build_match(params, scope ) - expected_result = { - [Primitive.make_list_no_translate([JS.literal(1), PatternMatching.parameter, PatternMatching.parameter])], - [JS.identifier("b"), JS.identifier("c")] - } - - assert result == expected_result - end - - test "match number", %{scope: scope} do - params = [1] - result = PatternMatching.build_match(params, scope ) - expected_result = { - [JS.literal(1)], - [] - } - - assert result == expected_result - end - - test "match struct pattern", %{scope: scope} do - params = [{:%, [], [{:__aliases__, [alias: false], [:Hello]}, {:%{}, [], []}]}] - result = PatternMatching.build_match(params, scope ) - expected_result = { - [PatternMatching.type(JS.identifier("Hello"), JS.object_expression([]))], - [] - } - - assert result == expected_result - end - - test "match struct pattern with property", %{scope: scope} do - params = [{:%, [], [{:__aliases__, [alias: false], [:Hello]}, {:%{}, [], [key: 1]}]}] - result = PatternMatching.build_match(params, scope ) - expected_result = { - [PatternMatching.type(JS.identifier("Hello"), JS.object_expression([ - Map.make_property(Translator.translate!(:key, scope ), Translator.translate!(1, scope )) - ])) - ], - [] - } - - assert result == expected_result - end - - test "match struct pattern with property param", %{scope: scope} do - params = [{:%, [], [{:__aliases__, [alias: false], [:Hello]}, {:%{}, [], [key: {:key, [], Elixir}]}]}] - result = PatternMatching.build_match(params, scope ) - expected_result = { - [PatternMatching.type(JS.identifier("Hello"), JS.object_expression([ - Map.make_property(Translator.translate!(:key, scope ), PatternMatching.parameter) - ])) - ], - [JS.identifier("key")] - } - - assert result == expected_result - end - - test "capture parameter when assigning it", %{scope: scope} do - params = [{:=, [], [1, {:a, [], Elixir}]}] - result = PatternMatching.build_match(params, scope ) - expected_result = { - [PatternMatching.capture(JS.literal(1))], - [JS.identifier("a")] - } - - assert result == expected_result - - - params = [{:=, [], [{:a, [], Elixir}, 1]}] - result = PatternMatching.build_match(params, scope ) - expected_result = { - [PatternMatching.capture(JS.literal(1))], - [JS.identifier("a")] - } - - assert result == expected_result - - - params = [{:=, [], [{:%, [], [{:__aliases__, [alias: false], [:AStruct]}, {:%{}, [], []}]}, {:a, [], ElixirScript.Translator.Function.Test}]}] - result = PatternMatching.build_match(params, scope ) - expected_result = { - [PatternMatching.capture(PatternMatching.type(JS.identifier("AStruct"), JS.object_expression([])))], - [JS.identifier("a")] - } - - assert result == expected_result - end - - test "match and assign list", %{scope: scope} do - params = [{:=, [], [[{:a, [], Elixir}, {:b, [], Elixir}, {:c, [], Elixir}], {:d, [], Elixir}]}] - result = PatternMatching.build_match(params, scope ) - expected_result = { - [PatternMatching.capture(Primitive.make_list_no_translate([PatternMatching.parameter, PatternMatching.parameter, PatternMatching.parameter]))], - [JS.identifier("a"), JS.identifier("b"), JS.identifier("c"), JS.identifier("d")] - } - - assert result == expected_result - end - - test "match on tuple", %{scope: scope} do - params = [{:{}, [], [1, {:b, [], Elixir}, 3]}] - result = PatternMatching.build_match(params, scope ) - expected_result = { - [PatternMatching.type(Primitive.tuple_class, JS.object_expression([JS.property( - JS.identifier("values"), - JS.array_expression([JS.literal(1), PatternMatching.parameter, JS.literal(3)]) - ) ] )) ], - [JS.identifier("b")] - } - - assert result == expected_result - - params = [{1, {:b, [], Elixir}}] - result = PatternMatching.build_match(params, scope ) - expected_result = { - [PatternMatching.type(Primitive.tuple_class, JS.object_expression([JS.property( - JS.identifier("values"), - JS.array_expression([JS.literal(1), PatternMatching.parameter]) - ) ] )) ], - [JS.identifier("b")] - } - - assert result == expected_result - end - - test "match on map", %{scope: scope} do - params = [{:%{}, [], [which: 13]}] - result = PatternMatching.build_match(params, scope ) - - expected_result = { - [JS.object_expression([ - Map.make_property(Translator.translate!(:which, scope ), JS.literal(13)) - ])], - [] - } - - assert result == expected_result - end - - - test "match on bound value", %{scope: scope} do - params = [{:^, [], [{:a, [], Elixir}]}] - result = PatternMatching.build_match(params, scope ) - - expected_result = { - [PatternMatching.bound(JS.identifier("a"))], - [nil] - } - - assert result == expected_result - end - -end diff --git a/test/translator/quote_test.exs b/test/translator/quote_test.exs deleted file mode 100644 index 2728ea69..00000000 --- a/test/translator/quote_test.exs +++ /dev/null @@ -1,142 +0,0 @@ -defmodule ElixirScript.Translator.Quote.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "quote number" do - ex_ast = quote do - quote do: 1 - end - - js_code = "1" - - assert_translation(ex_ast, js_code) - end - - test "quote atom" do - ex_ast = quote do - quote do: :time - end - - js_code = "Symbol.for('time')" - - assert_translation(ex_ast, js_code) - end - - - test "quote 2 element tuple" do - ex_ast = quote do - quote do: {1, 2} - end - - js_code = "new Bootstrap.Core.Tuple(1, 2)" - - assert_translation(ex_ast, js_code) - end - - - test "quote 3 element tuple" do - ex_ast = quote do - quote do: {1, 2, 3} - end - - js_code = "new Bootstrap.Core.Tuple(Symbol.for('{}'), Object.freeze([]), Object.freeze([1, 2, 3]))" - - assert_translation(ex_ast, js_code) - end - - - test "quote function call" do - ex_ast = quote do - quote do: test(1) - end - - js_code = """ - new Bootstrap.Core.Tuple( - Symbol.for('test'), - Object.freeze([new Bootstrap.Core.Tuple(Symbol.for('context'),Symbol.for('Elixir.ElixirScript.Translator.Quote.Test')), new Bootstrap.Core.Tuple(Symbol.for('import'),Symbol.for('Elixir.ExUnit.Case'))]),Object.freeze([1]) - ) - """ - - assert_translation(ex_ast, js_code) - end - - - test "quote function with variable" do - ex_ast = quote do - quote do: test(x) - end - - js_code = """ - new Bootstrap.Core.Tuple( - Symbol.for('test'), - Object.freeze([new Bootstrap.Core.Tuple(Symbol.for('context'), Symbol.for('Elixir.ElixirScript.Translator.Quote.Test')), new Bootstrap.Core.Tuple(Symbol.for('import'),Symbol.for('Elixir.ExUnit.Case'))]),Object.freeze([new Bootstrap.Core.Tuple(Symbol.for('x'),Object.freeze([]),Symbol.for('Elixir.ElixirScript.Translator.Quote.Test'))])) - """ - - assert_translation(ex_ast, js_code) - end - - - test "quote function call with unquote" do - ex_ast = quote do - x = 1 - quote do: test(unquote(x)) - end - - js_code = """ - new Bootstrap.Core.Tuple( - Symbol.for('test'), - Object.freeze([new Bootstrap.Core.Tuple(Symbol.for('context'),Symbol.for('Elixir.ElixirScript.Translator.Quote.Test')), new Bootstrap.Core.Tuple(Symbol.for('import'),Symbol.for('Elixir.ExUnit.Case'))]),Object.freeze([x]) - ) - """ - - assert_translation(ex_ast, js_code) - end - - - test "quote function call with unquote_slicing" do - ex_ast = quote do - quote do: sum(1, unquote_splicing([1, 2, 3]), 5) - end - - js_code = """ - new Bootstrap.Core.Tuple(Symbol.for('sum'), Object.freeze([]), Bootstrap.Enum.concat(Object.freeze([1]), Object.freeze([1, 2, 3]), Object.freeze([5]))) - """ - - assert_translation(ex_ast, js_code) - end - - test "bind_quoted" do - ex_ast = quote do - x = 1 - quote bind_quoted: [x: x] do - x * x - end - end - - js_code = """ - new Bootstrap.Core.Tuple( - Symbol.for('*'), - Object.freeze([new Bootstrap.Core.Tuple(Symbol.for('context'), Symbol.for('Elixir.ElixirScript.Translator.Quote.Test')), new Bootstrap.Core.Tuple(Symbol.for('import'),Symbol.for('Elixir.ElixirScript.Kernel'))]),Object.freeze([x, x]) - ) - """ - - assert_translation(ex_ast, js_code) - end - - test "quote with context option" do - ex_ast = quote do - quote context: Elixir do - test(1) - end - end - - js_code = """ - new Bootstrap.Core.Tuple( - Symbol.for('test'), - Object.freeze([new Bootstrap.Core.Tuple(Symbol.for('context'),Symbol.for('Elixir')), new Bootstrap.Core.Tuple(Symbol.for('import'),Symbol.for('Elixir.ExUnit.Case'))]),Object.freeze([1]) - ) - """ - - assert_translation(ex_ast, js_code) - end -end diff --git a/test/translator/string_test.exs b/test/translator/string_test.exs deleted file mode 100644 index 3eb79606..00000000 --- a/test/translator/string_test.exs +++ /dev/null @@ -1,43 +0,0 @@ -defmodule ElixirScript.Translator.String.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "translate string" do - ex_ast = quote do: "Hello" - assert_translation(ex_ast, "'Hello'") - end - - test "translate multiline string" do - ex_ast = quote do: """ - Hello - This is another line - """ - assert_translation(ex_ast, "'Hello\\nThis is another line\\n'") - end - - test "translate string concatenation" do - ex_ast = quote do: "Hello" <> "World" - assert_translation(ex_ast, "'Hello' + 'World'") - end - - test "translate string interpolation" do - ex_ast = quote do: "Hello #{"world"}" - assert_translation(ex_ast, "'Hello ' + Elixir.ElixirScript.String.Chars.__load(Elixir).to_string('world')") - - ex_ast = quote do: "Hello #{length([])}" - assert_translation(ex_ast, "'Hello ' + Elixir.ElixirScript.String.Chars.__load(Elixir).to_string(Elixir.ElixirScript.Kernel.__load(Elixir).length(Object.freeze([])))") - end - - test "translate multiline string interpolation" do - ex_ast = quote do: """ - Hello #{length([])} - """ - assert_translation(ex_ast, "'Hello ' + (Elixir.ElixirScript.String.Chars.__load(Elixir).to_string(Elixir.ElixirScript.Kernel.__load(Elixir).length(Object.freeze([]))) + '\\n')") - - ex_ast = quote do: """ - Hello #{length([])} - How are you, #{length([])}? - """ - assert_translation(ex_ast, "'Hello ' + (Elixir.ElixirScript.String.Chars.__load(Elixir).to_string(Elixir.ElixirScript.Kernel.__load(Elixir).length(Object.freeze([]))) + ('\\nHow are you, ' + (Elixir.ElixirScript.String.Chars.__load(Elixir).to_string(Elixir.ElixirScript.Kernel.__load(Elixir).length(Object.freeze([]))) + '?\\n')))") - end -end diff --git a/test/translator/struct_test.exs b/test/translator/struct_test.exs deleted file mode 100644 index dcc07631..00000000 --- a/test/translator/struct_test.exs +++ /dev/null @@ -1,185 +0,0 @@ -defmodule ElixirScript.Translator.Struct.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "translate struct with default values" do - ex_ast = quote do - defmodule User do - defstruct name: "john", age: 27 - end - end - - js_code = """ - const Elixir$User = Bootstrap.Core.Functions.defstruct({ - [Symbol.for('__struct__')]: Symbol.for('Elixir.User'), - [Symbol.for('name')]: 'john', - [Symbol.for('age')]: 27 - }); - """ - - assert_translation(ex_ast, js_code) - end - - test "translate struct without default values" do - - ex_ast = quote do - defmodule User do - defstruct [:name, :age] - end - end - - js_code = """ - const Elixir$User = Bootstrap.Core.Functions.defstruct({ - [Symbol.for('__struct__')]: Symbol.for('Elixir.User'), - [Symbol.for('name')]: null, - [Symbol.for('age')]: null - }); - """ - - assert_translation(ex_ast, js_code) - - end - - test "translate struct creation" do - ex_ast = quote do - defmodule User do - defstruct [:name, :age] - end - - user = %User{} - end - - js_code = """ - const Elixir$User = Bootstrap.Core.Functions.defstruct({ - [Symbol.for('__struct__')]: Symbol.for('Elixir.User'), - [Symbol.for('name')]: null, - [Symbol.for('age')]: null - }); - """ - - assert_translation(ex_ast, js_code) - - ex_ast = quote do - defmodule User do - defstruct [:name, :age] - end - - user = %User{name: "John"} - end - - js_code = """ - const Elixir$User = Bootstrap.Core.Functions.defstruct({ - [Symbol.for('__struct__')]: Symbol.for('Elixir.User'), - [Symbol.for('name')]: null, - [Symbol.for('age')]: null - }); - - """ - - assert_translation(ex_ast, js_code) - end - - test "translate struct update" do - ex_ast = quote do - map = %{key: nil} - user = %{ map | key: 1 } - end - - js_code = """ - let [user] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(),Bootstrap.Core.SpecialForms.map_update(map,Object.freeze({ - [Symbol.for('key')]: 1 - }))); - """ - - assert_translation(ex_ast, js_code) - - - ex_ast = quote do - map = %{key: nil, key1: nil} - user = %{ map | key: 1, key1: 11 } - end - - js_code = """ - let [user] = Bootstrap.Core.Patterns.match(Bootstrap.Core.Patterns.variable(),Bootstrap.Core.SpecialForms.map_update(map,Object.freeze({ - [Symbol.for('key')]: 1, [Symbol.for('key1')]: 11 - }))); - """ - - assert_translation(ex_ast, js_code) - end - - test "translate defexception" do - ex_ast = quote do - defmodule MyAppError do - defexception message: "This is a message" - end - end - - js_code = """ - const Elixir$MyAppError = Bootstrap.Core.Functions.defexception({ - [Symbol.for('__struct__')]: Symbol.for('Elixir.MyAppError'), - [Symbol.for('__exception__')]: true, - [Symbol.for('message')]: 'This is a message' - }); - """ - - assert_translation(ex_ast, js_code) - - ex_ast = quote do - defmodule MyAppError do - defexception [:message] - end - end - - js_code = """ - const Elixir$MyAppError = Bootstrap.Core.Functions.defexception({ - [Symbol.for('__struct__')]: Symbol.for('Elixir.MyAppError'), - [Symbol.for('__exception__')]: true, - [Symbol.for('message')]: null - }); - """ - - assert_translation(ex_ast, js_code) - - end - - test "translate raise exception" do - ex_ast = quote do - defmodule MyAppError do - defexception [:message] - - def do_it() do - raise MyAppError, message: "did not get what was expected" - end - - end - end - - js_code = """ - throw Elixir.MyAppError.__load(Elixir).Elixir$MyAppError.create(Object.freeze({ - [Symbol.for('message')]: 'did not get what was expected' - })); - """ - - assert_translation(ex_ast, js_code) - - - ex_ast = quote do - def do_it() do - raise "did not get what was expected" - end - - end - - js_code = """ - throw { - [Symbol.for('__struct__')]: Symbol.for('RuntimeError'), - [Symbol.for('__exception__')]: true, - [Symbol.for('message')]: 'did not get what was expected' - }; - """ - - assert_translation(ex_ast, js_code) - - end -end diff --git a/test/translator/try_test.exs b/test/translator/try_test.exs deleted file mode 100644 index 72c24681..00000000 --- a/test/translator/try_test.exs +++ /dev/null @@ -1,221 +0,0 @@ -defmodule ElixirScript.Translator.Try.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "translate with a rescue with one match" do - ex_ast = quote do - try do - 1 - rescue - ArgumentError -> - IO.puts "Invalid argument given" - end - end - - js_code = """ - Bootstrap.Core.SpecialForms._try(function() { - return 1; - }, Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.type(ArgumentError, {})], function() { - return IO.puts('Invalid argument given'); - })), null, null, null) - """ - - assert_translation(ex_ast, js_code) - end - - test "translate with a rescue with a list match" do - ex_ast = quote do - - try do - 1 - rescue - [ArgumentError] -> - IO.puts "Invalid argument given" - end - end - - js_code = """ - Bootstrap.Core.SpecialForms._try(function() { - return 1; - }, Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.type(ArgumentError, {})], function() { - return IO.puts('Invalid argument given'); - })), null, null, null) - """ - - assert_translation(ex_ast, js_code) - end - - test "translate with a rescue with an in guard" do - ex_ast = quote do - - try do - 1 - rescue - x in [ArgumentError] -> - IO.puts "Invalid argument given" - end - end - - js_code = """ - Bootstrap.Core.SpecialForms._try(function() { - return 1; - },Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()],function(x) { - return IO.puts('Invalid argument given'); - },function(x) { - return Bootstrap.Core.Functions.contains(x,Object.freeze([ArgumentError.create(Object.freeze({}))])); - })),null,null,null) - """ - - assert_translation(ex_ast, js_code) - end - - test "translate with a rescue with an identifier" do - ex_ast = quote do - - try do - 1 - rescue - x -> - IO.puts "Invalid argument given" - end - end - - js_code = """ - Bootstrap.Core.SpecialForms._try(function() { - return 1; - },Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()],function(x) { - return IO.puts('Invalid argument given'); - })),null,null,null) - """ - - assert_translation(ex_ast, js_code) - end - - - test "translate with a rescue with multiple patterns" do - ex_ast = quote do - - try do - 1 - rescue - [ArgumentError] -> - IO.puts "ArgumentError" - x -> - IO.puts "x" - end - end - - js_code = """ - Bootstrap.Core.SpecialForms._try(function() { - return 1; - }, Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.type(ArgumentError, {})], function() { - return IO.puts('ArgumentError'); - }), Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()], function(x) { - return IO.puts('x'); - })), null, null, null) - """ - - assert_translation(ex_ast, js_code) - end - - test "translate with a rescue and after clause" do - ex_ast = quote do - - try do - 1 - rescue - ArgumentError -> - IO.puts "Invalid argument given" - after - IO.puts "This is printed regardless if it failed or succeed" - end - end - - js_code = """ - Bootstrap.Core.SpecialForms._try(function() { - return 1; - }, Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.type(ArgumentError, {})], function() { - return IO.puts('Invalid argument given'); - })), null, null, function() { - return IO.puts('This is printed regardless if it failed or succeed'); - }) - """ - - assert_translation(ex_ast, js_code) - end - - test "translate with an after clause" do - ex_ast = quote do - - try do - 1 - after - IO.puts "This is printed regardless if it failed or succeed" - end - end - - js_code = """ - Bootstrap.Core.SpecialForms._try(function() { - return 1; - },null,null,null,function() { - return IO.puts('This is printed regardless if it failed or succeed'); - }) - """ - - assert_translation(ex_ast, js_code) - end - - test "translate else" do - ex_ast = quote do - x = 1 - try do - 1 / x - else - y when y < 1 and y > -1 -> - :small - _ -> - :large - end - end - - js_code = """ - Bootstrap.Core.SpecialForms._try(function() { - return 1 / x; - }, null, null, Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.variable()], function(y) { - return Symbol.for('small'); - }, function(y) { - return y < 1 && y > -1; - }), Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.wildcard()], function() { - return Symbol.for('large'); - })), null) - """ - - assert_translation(ex_ast, js_code) - end - - test "translate catch" do - ex_ast = quote do - try do - 1 - rescue - ArgumentError -> - IO.puts "Invalid argument given" - catch - :throw, :Error -> - IO.puts "caught error" - end - end - - js_code = """ - Bootstrap.Core.SpecialForms._try(function() { - return 1; - }, Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Bootstrap.Core.Patterns.type(ArgumentError, {})], function() { - return IO.puts('Invalid argument given'); - })), Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Symbol.for('throw'), Symbol.for('Error')], function() { - return IO.puts('caught error'); - })), null, null) - """ - - assert_translation(ex_ast, js_code) - end -end diff --git a/test/translator/tuple_test.exs b/test/translator/tuple_test.exs deleted file mode 100644 index 189c1de9..00000000 --- a/test/translator/tuple_test.exs +++ /dev/null @@ -1,35 +0,0 @@ -defmodule ElixirScript.Translator.Tuple.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "translate 2 item tuple" do - ex_ast = quote do: {1, 2} - js_code = "new Bootstrap.Core.Tuple(1, 2)" - - assert_translation(ex_ast, js_code) - end - - test "translate multiple item tuple" do - ex_ast = quote do: {1, 2, 3, 4, 5} - js_code = "new Bootstrap.Core.Tuple(1, 2, 3, 4, 5)" - - assert_translation(ex_ast, js_code) - end - - test "translate tuples of different typed items" do - ex_ast = quote do: {"a", "b", "c"} - js_code = "new Bootstrap.Core.Tuple('a', 'b', 'c')" - - assert_translation(ex_ast, js_code) - - ex_ast = quote do: {:a, :b, :c} - js_code = "new Bootstrap.Core.Tuple(Symbol.for('a'), Symbol.for('b'), Symbol.for('c'))" - - assert_translation(ex_ast, js_code) - - ex_ast = quote do: {:a, 2, "c"} - js_code = "new Bootstrap.Core.Tuple(Symbol.for('a'), 2, 'c')" - - assert_translation(ex_ast, js_code) - end -end diff --git a/test/translator/umd_test.exs b/test/translator/umd_test.exs deleted file mode 100644 index 0acd353a..00000000 --- a/test/translator/umd_test.exs +++ /dev/null @@ -1,29 +0,0 @@ -defmodule ElixirScript.Translator.UMD.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "translate module to umd" do - ex_ast = quote do - defmodule Elephant do - @ul "#todo-list" - - def something() do - @ul - end - end - end - - js_code = """ - (function(root, factory) { - if (typeof define === 'function' && define.amd) { - define([], factory) - } else if (typeof exports === 'object') { - module.exports = factory() - } else { - root.Elixir = factory() - } - """ - - assert_translation(ex_ast, js_code, :umd) - end -end \ No newline at end of file diff --git a/test/translator/with_test.exs b/test/translator/with_test.exs deleted file mode 100644 index 74133f03..00000000 --- a/test/translator/with_test.exs +++ /dev/null @@ -1,87 +0,0 @@ -defmodule ElixirScript.Translator.With.Test do - use ExUnit.Case - import ElixirScript.TestHelper - - test "translate with" do - ex_ast = quote do - opts = %{} - with {:ok, width} <- Map.fetch(opts, :width), - {:ok, height} <- Map.fetch(opts, :height), - do: {:ok, width * height} - end - - js_code = """ - Bootstrap.Core.SpecialForms._with([Bootstrap.Core.Patterns.type(Bootstrap.Core.Tuple,{ - values: [Symbol.for('ok'), Bootstrap.Core.Patterns.variable()] - }), function() { - return Elixir.ElixirScript.Map.__load(Elixir).fetch(opts,Symbol.for('width')); - }],[Bootstrap.Core.Patterns.type(Bootstrap.Core.Tuple,{ - values: [Symbol.for('ok'), Bootstrap.Core.Patterns.variable()] - }), function(width) { - return Elixir.ElixirScript.Map.__load(Elixir).fetch(opts,Symbol.for('height')); - }],function(width,height) { - return new Bootstrap.Core.Tuple(Symbol.for('ok'),width * height); - }) - """ - - assert_translation(ex_ast, js_code) - end - - test "translate with with bare expression" do - ex_ast = quote do - opts = %{} - with {:ok, width} <- Map.fetch(opts, :width), - double_width = width * 2, - {:ok, height} <- Map.fetch(opts, :height), - do: {:ok, double_width * height} - end - - js_code = """ - Bootstrap.Core.SpecialForms._with([Bootstrap.Core.Patterns.type(Bootstrap.Core.Tuple,{ - values: [Symbol.for('ok'), Bootstrap.Core.Patterns.variable()] - }), function() { - return Elixir.ElixirScript.Map.__load(Elixir).fetch(opts,Symbol.for('width')); - }],[Bootstrap.Core.Patterns.variable(), function(width) { - return width * 2; - }],[Bootstrap.Core.Patterns.type(Bootstrap.Core.Tuple,{ - values: [Symbol.for('ok'), Bootstrap.Core.Patterns.variable()] - }), function(width,double_width) { - return Elixir.ElixirScript.Map.__load(Elixir).fetch(opts,Symbol.for('height')); - }],function(width,double_width,height) { - return new Bootstrap.Core.Tuple(Symbol.for('ok'),double_width * height); - }) - """ - - assert_translation(ex_ast, js_code) - end - - test "translate with with else" do - ex_ast = quote do - opts = %{} - with {:ok, width} <- Map.fetch(opts, :width), - {:ok, height} <- Map.fetch(opts, :height) do - {:ok, width * height} - else - :error -> {:error, :wrong_data} - end - end - - js_code = """ - Bootstrap.Core.SpecialForms._with([Bootstrap.Core.Patterns.type(Bootstrap.Core.Tuple,{ - values: [Symbol.for('ok'), Bootstrap.Core.Patterns.variable()] - }), function() { - return Elixir.ElixirScript.Map.__load(Elixir).fetch(opts,Symbol.for('width')); - }],[Bootstrap.Core.Patterns.type(Bootstrap.Core.Tuple,{ - values: [Symbol.for('ok'), Bootstrap.Core.Patterns.variable()] - }), function(width) { - return Elixir.ElixirScript.Map.__load(Elixir).fetch(opts,Symbol.for('height')); - }],function(width,height) { - return new Bootstrap.Core.Tuple(Symbol.for('ok'),width * height); - },Bootstrap.Core.Patterns.defmatch(Bootstrap.Core.Patterns.clause([Symbol.for('error')],function() { - return new Bootstrap.Core.Tuple(Symbol.for('error'),Symbol.for('wrong_data')); - }))) - """ - - assert_translation(ex_ast, js_code) - end -end diff --git a/test_elixir_script/integration_test.exs b/test_elixir_script/integration_test.exs new file mode 100644 index 00000000..ca30430f --- /dev/null +++ b/test_elixir_script/integration_test.exs @@ -0,0 +1,66 @@ +defmodule ElixirScript.Integration.Test do + use ElixirScript.Test + + test "Something" do + assert {:ok, _} = {:ok, 1} + end + + test "Atom.to_string" do + val = Atom.to_string(:atom) + assert val == "atom" + end + + test "String interpolation with number" do + val = "#{5}" + assert val == "5" + end + + test "shorthand failure" do + orders = [%{email: "test@hotmail.com"}, %{email: "test2@hotmail.com"}] + + val = Enum.reduce(orders, [], + &(&2 ++ [ [:option, %{value: &1.email}, &1.email] ])) + + assert val == [ + [:option, %{value: "test@hotmail.com"}, "test@hotmail.com"], + [:option, %{value: "test2@hotmail.com"}, "test2@hotmail.com"] + ] + end + + test "map equals" do + map1 = %{test: "map"} + map2 = %{test: "map"} + + assert map1 == map2 + end + + test "multi-remote call" do + map = %{token_count: 5_000_000} + val = map.token_count.toLocaleString() + + assert val == "5,000,000" + end + + test "filter names in guards" do + has? = 5 + + val = case 5 do + _ when has? == 5 -> + true + end + + assert val == true + end + + test "tuple_get" do + map = %{{1} => 5} + val = Map.get(map, {1}) + + assert val == 5 + end + + test "multi_bind" do + [_a | _] = val = [1, 2, 3, 4, 5] + assert val == [1, 2, 3, 4, 5] + end +end diff --git a/test_elixir_script/try_test.exs b/test_elixir_script/try_test.exs new file mode 100644 index 00000000..0e73cd8b --- /dev/null +++ b/test_elixir_script/try_test.exs @@ -0,0 +1,48 @@ +defmodule ElixirScript.Try.Test do + use ElixirScript.Test + + test "returns value in try if no error" do + value = try do + 1 + 1 + rescue + _ -> + 3 + end + + assert value == 2 + end + + test "returns rescue value on error" do + value = try do + raise ArithmeticError + rescue + _ -> + 3 + end + + assert value == 3 + end + + test "returns rescue value from matching error" do + value = try do + raise ArithmeticError + rescue + ArithmeticError -> + 3 + end + + assert value == 3 + end + + test "returns rescue value from matching errors" do + value = try do + raise ArithmeticError + rescue + _ in [ArithmeticError, ArgumentError] -> + 3 + end + + assert value == 3 + end + +end diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index 57960d44..00000000 --- a/yarn.lock +++ /dev/null @@ -1,2885 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -acorn-jsx@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" - dependencies: - acorn "^3.0.4" - -acorn@4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.4.tgz#17a8d6a7a6c4ef538b814ec9abac2779293bf30a" - -acorn@4.X: - version "4.0.11" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0" - -acorn@^3.0.4: - version "3.3.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" - -ajv-keywords@^1.0.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" - -ajv@^4.7.0: - version "4.11.3" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.3.tgz#ce30bdb90d1254f762c75af915fb3a63e7183d22" - dependencies: - co "^4.6.0" - json-stable-stringify "^1.0.1" - -align-text@^0.1.1, align-text@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" - dependencies: - kind-of "^3.0.2" - longest "^1.0.1" - repeat-string "^1.5.2" - -amdefine@>=0.0.4: - version "1.0.1" - resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" - -ansi-escapes@^1.1.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - -archy@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" - -argparse@^1.0.7: - version "1.0.9" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" - dependencies: - sprintf-js "~1.0.2" - -arr-diff@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" - dependencies: - arr-flatten "^1.0.1" - -arr-flatten@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b" - -array-differ@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031" - -array-union@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - dependencies: - array-uniq "^1.0.1" - -array-uniq@^1.0.1, array-uniq@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - -array-unique@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" - -arrify@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - -assertion-error@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" - -async@~0.2.6: - version "0.2.10" - resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" - -atob@~1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/atob/-/atob-1.1.3.tgz#95f13629b12c3a51a5d215abdce2aa9f32f80773" - -babel-code-frame@^6.16.0, babel-code-frame@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4" - dependencies: - chalk "^1.1.0" - esutils "^2.0.2" - js-tokens "^3.0.0" - -babel-core@6, babel-core@^6.0.2, babel-core@^6.23.0, babel-core@^6.7.7: - version "6.23.1" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.23.1.tgz#c143cb621bb2f621710c220c5d579d15b8a442df" - dependencies: - babel-code-frame "^6.22.0" - babel-generator "^6.23.0" - babel-helpers "^6.23.0" - babel-messages "^6.23.0" - babel-register "^6.23.0" - babel-runtime "^6.22.0" - babel-template "^6.23.0" - babel-traverse "^6.23.1" - babel-types "^6.23.0" - babylon "^6.11.0" - convert-source-map "^1.1.0" - debug "^2.1.1" - json5 "^0.5.0" - lodash "^4.2.0" - minimatch "^3.0.2" - path-is-absolute "^1.0.0" - private "^0.1.6" - slash "^1.0.0" - source-map "^0.5.0" - -babel-generator@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.23.0.tgz#6b8edab956ef3116f79d8c84c5a3c05f32a74bc5" - dependencies: - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-types "^6.23.0" - detect-indent "^4.0.0" - jsesc "^1.3.0" - lodash "^4.2.0" - source-map "^0.5.0" - trim-right "^1.0.1" - -babel-helper-bindify-decorators@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.22.0.tgz#d7f5bc261275941ac62acfc4e20dacfb8a3fe952" - dependencies: - babel-runtime "^6.22.0" - babel-traverse "^6.22.0" - babel-types "^6.22.0" - -babel-helper-builder-binary-assignment-operator-visitor@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.22.0.tgz#29df56be144d81bdeac08262bfa41d2c5e91cdcd" - dependencies: - babel-helper-explode-assignable-expression "^6.22.0" - babel-runtime "^6.22.0" - babel-types "^6.22.0" - -babel-helper-builder-react-jsx@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.23.0.tgz#d53fc8c996e0bc56d0de0fc4cc55a7138395ea4b" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.23.0" - esutils "^2.0.0" - lodash "^4.2.0" - -babel-helper-call-delegate@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.22.0.tgz#119921b56120f17e9dae3f74b4f5cc7bcc1b37ef" - dependencies: - babel-helper-hoist-variables "^6.22.0" - babel-runtime "^6.22.0" - babel-traverse "^6.22.0" - babel-types "^6.22.0" - -babel-helper-define-map@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.23.0.tgz#1444f960c9691d69a2ced6a205315f8fd00804e7" - dependencies: - babel-helper-function-name "^6.23.0" - babel-runtime "^6.22.0" - babel-types "^6.23.0" - lodash "^4.2.0" - -babel-helper-explode-assignable-expression@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.22.0.tgz#c97bf76eed3e0bae4048121f2b9dae1a4e7d0478" - dependencies: - babel-runtime "^6.22.0" - babel-traverse "^6.22.0" - babel-types "^6.22.0" - -babel-helper-explode-class@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.22.0.tgz#646304924aa6388a516843ba7f1855ef8dfeb69b" - dependencies: - babel-helper-bindify-decorators "^6.22.0" - babel-runtime "^6.22.0" - babel-traverse "^6.22.0" - babel-types "^6.22.0" - -babel-helper-function-name@^6.22.0, babel-helper-function-name@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.23.0.tgz#25742d67175c8903dbe4b6cb9d9e1fcb8dcf23a6" - dependencies: - babel-helper-get-function-arity "^6.22.0" - babel-runtime "^6.22.0" - babel-template "^6.23.0" - babel-traverse "^6.23.0" - babel-types "^6.23.0" - -babel-helper-get-function-arity@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.22.0.tgz#0beb464ad69dc7347410ac6ade9f03a50634f5ce" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.22.0" - -babel-helper-hoist-variables@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.22.0.tgz#3eacbf731d80705845dd2e9718f600cfb9b4ba72" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.22.0" - -babel-helper-optimise-call-expression@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.23.0.tgz#f3ee7eed355b4282138b33d02b78369e470622f5" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.23.0" - -babel-helper-regex@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.22.0.tgz#79f532be1647b1f0ee3474b5f5c3da58001d247d" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.22.0" - lodash "^4.2.0" - -babel-helper-remap-async-to-generator@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.22.0.tgz#2186ae73278ed03b8b15ced089609da981053383" - dependencies: - babel-helper-function-name "^6.22.0" - babel-runtime "^6.22.0" - babel-template "^6.22.0" - babel-traverse "^6.22.0" - babel-types "^6.22.0" - -babel-helper-replace-supers@^6.22.0, babel-helper-replace-supers@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.23.0.tgz#eeaf8ad9b58ec4337ca94223bacdca1f8d9b4bfd" - dependencies: - babel-helper-optimise-call-expression "^6.23.0" - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-template "^6.23.0" - babel-traverse "^6.23.0" - babel-types "^6.23.0" - -babel-helpers@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.23.0.tgz#4f8f2e092d0b6a8808a4bde79c27f1e2ecf0d992" - dependencies: - babel-runtime "^6.22.0" - babel-template "^6.23.0" - -babel-messages@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-check-es2015-constants@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-external-helpers@^6.4.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-external-helpers/-/babel-plugin-external-helpers-6.22.0.tgz#2285f48b02bd5dede85175caf8c62e86adccefa1" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-syntax-async-functions@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" - -babel-plugin-syntax-async-generators@^6.5.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz#6bc963ebb16eccbae6b92b596eb7f35c342a8b9a" - -babel-plugin-syntax-class-constructor-call@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz#9cb9d39fe43c8600bec8146456ddcbd4e1a76416" - -babel-plugin-syntax-class-properties@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" - -babel-plugin-syntax-decorators@^6.13.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" - -babel-plugin-syntax-do-expressions@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-do-expressions/-/babel-plugin-syntax-do-expressions-6.13.0.tgz#5747756139aa26d390d09410b03744ba07e4796d" - -babel-plugin-syntax-dynamic-import@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" - -babel-plugin-syntax-exponentiation-operator@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" - -babel-plugin-syntax-export-extensions@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz#70a1484f0f9089a4e84ad44bac353c95b9b12721" - -babel-plugin-syntax-flow@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" - -babel-plugin-syntax-function-bind@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-function-bind/-/babel-plugin-syntax-function-bind-6.13.0.tgz#48c495f177bdf31a981e732f55adc0bdd2601f46" - -babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" - -babel-plugin-syntax-object-rest-spread@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" - -babel-plugin-syntax-trailing-function-commas@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" - -babel-plugin-transform-async-generator-functions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.22.0.tgz#a720a98153a7596f204099cd5409f4b3c05bab46" - dependencies: - babel-helper-remap-async-to-generator "^6.22.0" - babel-plugin-syntax-async-generators "^6.5.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-async-to-generator@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.22.0.tgz#194b6938ec195ad36efc4c33a971acf00d8cd35e" - dependencies: - babel-helper-remap-async-to-generator "^6.22.0" - babel-plugin-syntax-async-functions "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-class-constructor-call@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.22.0.tgz#11a4d2216abb5b0eef298b493748f4f2f4869120" - dependencies: - babel-plugin-syntax-class-constructor-call "^6.18.0" - babel-runtime "^6.22.0" - babel-template "^6.22.0" - -babel-plugin-transform-class-properties@^6.22.0, babel-plugin-transform-class-properties@^6.9.1: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.23.0.tgz#187b747ee404399013563c993db038f34754ac3b" - dependencies: - babel-helper-function-name "^6.23.0" - babel-plugin-syntax-class-properties "^6.8.0" - babel-runtime "^6.22.0" - babel-template "^6.23.0" - -babel-plugin-transform-decorators@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.22.0.tgz#c03635b27a23b23b7224f49232c237a73988d27c" - dependencies: - babel-helper-explode-class "^6.22.0" - babel-plugin-syntax-decorators "^6.13.0" - babel-runtime "^6.22.0" - babel-template "^6.22.0" - babel-types "^6.22.0" - -babel-plugin-transform-do-expressions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-do-expressions/-/babel-plugin-transform-do-expressions-6.22.0.tgz#28ccaf92812d949c2cd1281f690c8fdc468ae9bb" - dependencies: - babel-plugin-syntax-do-expressions "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-arrow-functions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-block-scoping@^6.22.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.23.0.tgz#e48895cf0b375be148cd7c8879b422707a053b51" - dependencies: - babel-runtime "^6.22.0" - babel-template "^6.23.0" - babel-traverse "^6.23.0" - babel-types "^6.23.0" - lodash "^4.2.0" - -babel-plugin-transform-es2015-classes@^6.22.0, babel-plugin-transform-es2015-classes@^6.9.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.23.0.tgz#49b53f326202a2fd1b3bbaa5e2edd8a4f78643c1" - dependencies: - babel-helper-define-map "^6.23.0" - babel-helper-function-name "^6.23.0" - babel-helper-optimise-call-expression "^6.23.0" - babel-helper-replace-supers "^6.23.0" - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-template "^6.23.0" - babel-traverse "^6.23.0" - babel-types "^6.23.0" - -babel-plugin-transform-es2015-computed-properties@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.22.0.tgz#7c383e9629bba4820c11b0425bdd6290f7f057e7" - dependencies: - babel-runtime "^6.22.0" - babel-template "^6.22.0" - -babel-plugin-transform-es2015-destructuring@^6.22.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-duplicate-keys@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.22.0.tgz#672397031c21610d72dd2bbb0ba9fb6277e1c36b" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.22.0" - -babel-plugin-transform-es2015-for-of@^6.22.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-function-name@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.22.0.tgz#f5fcc8b09093f9a23c76ac3d9e392c3ec4b77104" - dependencies: - babel-helper-function-name "^6.22.0" - babel-runtime "^6.22.0" - babel-types "^6.22.0" - -babel-plugin-transform-es2015-literals@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-modules-amd@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.22.0.tgz#bf69cd34889a41c33d90dfb740e0091ccff52f21" - dependencies: - babel-plugin-transform-es2015-modules-commonjs "^6.22.0" - babel-runtime "^6.22.0" - babel-template "^6.22.0" - -babel-plugin-transform-es2015-modules-commonjs@^6.22.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.23.0.tgz#cba7aa6379fb7ec99250e6d46de2973aaffa7b92" - dependencies: - babel-plugin-transform-strict-mode "^6.22.0" - babel-runtime "^6.22.0" - babel-template "^6.23.0" - babel-types "^6.23.0" - -babel-plugin-transform-es2015-modules-systemjs@^6.22.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.23.0.tgz#ae3469227ffac39b0310d90fec73bfdc4f6317b0" - dependencies: - babel-helper-hoist-variables "^6.22.0" - babel-runtime "^6.22.0" - babel-template "^6.23.0" - -babel-plugin-transform-es2015-modules-umd@^6.22.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.23.0.tgz#8d284ae2e19ed8fe21d2b1b26d6e7e0fcd94f0f1" - dependencies: - babel-plugin-transform-es2015-modules-amd "^6.22.0" - babel-runtime "^6.22.0" - babel-template "^6.23.0" - -babel-plugin-transform-es2015-object-super@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.22.0.tgz#daa60e114a042ea769dd53fe528fc82311eb98fc" - dependencies: - babel-helper-replace-supers "^6.22.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-parameters@^6.22.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.23.0.tgz#3a2aabb70c8af945d5ce386f1a4250625a83ae3b" - dependencies: - babel-helper-call-delegate "^6.22.0" - babel-helper-get-function-arity "^6.22.0" - babel-runtime "^6.22.0" - babel-template "^6.23.0" - babel-traverse "^6.23.0" - babel-types "^6.23.0" - -babel-plugin-transform-es2015-shorthand-properties@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.22.0.tgz#8ba776e0affaa60bff21e921403b8a652a2ff723" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.22.0" - -babel-plugin-transform-es2015-spread@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-sticky-regex@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.22.0.tgz#ab316829e866ee3f4b9eb96939757d19a5bc4593" - dependencies: - babel-helper-regex "^6.22.0" - babel-runtime "^6.22.0" - babel-types "^6.22.0" - -babel-plugin-transform-es2015-template-literals@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-typeof-symbol@^6.22.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-unicode-regex@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.22.0.tgz#8d9cc27e7ee1decfe65454fb986452a04a613d20" - dependencies: - babel-helper-regex "^6.22.0" - babel-runtime "^6.22.0" - regexpu-core "^2.0.0" - -babel-plugin-transform-exponentiation-operator@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.22.0.tgz#d57c8335281918e54ef053118ce6eb108468084d" - dependencies: - babel-helper-builder-binary-assignment-operator-visitor "^6.22.0" - babel-plugin-syntax-exponentiation-operator "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-export-extensions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.22.0.tgz#53738b47e75e8218589eea946cbbd39109bbe653" - dependencies: - babel-plugin-syntax-export-extensions "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-flow-strip-types@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz#84cb672935d43714fdc32bce84568d87441cf7cf" - dependencies: - babel-plugin-syntax-flow "^6.18.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-function-bind@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-function-bind/-/babel-plugin-transform-function-bind-6.22.0.tgz#c6fb8e96ac296a310b8cf8ea401462407ddf6a97" - dependencies: - babel-plugin-syntax-function-bind "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-object-rest-spread@^6.22.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.23.0.tgz#875d6bc9be761c58a2ae3feee5dc4895d8c7f921" - dependencies: - babel-plugin-syntax-object-rest-spread "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-react-display-name@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.23.0.tgz#4398910c358441dc4cef18787264d0412ed36b37" - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-react-jsx-self@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz#df6d80a9da2612a121e6ddd7558bcbecf06e636e" - dependencies: - babel-plugin-syntax-jsx "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-react-jsx-source@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz#66ac12153f5cd2d17b3c19268f4bf0197f44ecd6" - dependencies: - babel-plugin-syntax-jsx "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-react-jsx@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.23.0.tgz#23e892f7f2e759678eb5e4446a8f8e94e81b3470" - dependencies: - babel-helper-builder-react-jsx "^6.23.0" - babel-plugin-syntax-jsx "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-regenerator@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.22.0.tgz#65740593a319c44522157538d690b84094617ea6" - dependencies: - regenerator-transform "0.9.8" - -babel-plugin-transform-strict-mode@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.22.0.tgz#e008df01340fdc87e959da65991b7e05970c8c7c" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.22.0" - -babel-preset-es2015-rollup@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/babel-preset-es2015-rollup/-/babel-preset-es2015-rollup-1.2.0.tgz#feedf80346e01fa22d4de15e72cde1cefc59bf67" - dependencies: - babel-plugin-external-helpers "^6.4.0" - babel-preset-es2015 "^6.3.13" - modify-babel-preset "^2.1.1" - -babel-preset-es2015@^6.3.13, babel-preset-es2015@^6.6.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.22.0.tgz#af5a98ecb35eb8af764ad8a5a05eb36dc4386835" - dependencies: - babel-plugin-check-es2015-constants "^6.22.0" - babel-plugin-transform-es2015-arrow-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoping "^6.22.0" - babel-plugin-transform-es2015-classes "^6.22.0" - babel-plugin-transform-es2015-computed-properties "^6.22.0" - babel-plugin-transform-es2015-destructuring "^6.22.0" - babel-plugin-transform-es2015-duplicate-keys "^6.22.0" - babel-plugin-transform-es2015-for-of "^6.22.0" - babel-plugin-transform-es2015-function-name "^6.22.0" - babel-plugin-transform-es2015-literals "^6.22.0" - babel-plugin-transform-es2015-modules-amd "^6.22.0" - babel-plugin-transform-es2015-modules-commonjs "^6.22.0" - babel-plugin-transform-es2015-modules-systemjs "^6.22.0" - babel-plugin-transform-es2015-modules-umd "^6.22.0" - babel-plugin-transform-es2015-object-super "^6.22.0" - babel-plugin-transform-es2015-parameters "^6.22.0" - babel-plugin-transform-es2015-shorthand-properties "^6.22.0" - babel-plugin-transform-es2015-spread "^6.22.0" - babel-plugin-transform-es2015-sticky-regex "^6.22.0" - babel-plugin-transform-es2015-template-literals "^6.22.0" - babel-plugin-transform-es2015-typeof-symbol "^6.22.0" - babel-plugin-transform-es2015-unicode-regex "^6.22.0" - babel-plugin-transform-regenerator "^6.22.0" - -babel-preset-flow@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz#e71218887085ae9a24b5be4169affb599816c49d" - dependencies: - babel-plugin-transform-flow-strip-types "^6.22.0" - -babel-preset-react@^6.5.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-preset-react/-/babel-preset-react-6.23.0.tgz#eb7cee4de98a3f94502c28565332da9819455195" - dependencies: - babel-plugin-syntax-jsx "^6.3.13" - babel-plugin-transform-react-display-name "^6.23.0" - babel-plugin-transform-react-jsx "^6.23.0" - babel-plugin-transform-react-jsx-self "^6.22.0" - babel-plugin-transform-react-jsx-source "^6.22.0" - babel-preset-flow "^6.23.0" - -babel-preset-stage-0@^6.5.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-preset-stage-0/-/babel-preset-stage-0-6.22.0.tgz#707eeb5b415da769eff9c42f4547f644f9296ef9" - dependencies: - babel-plugin-transform-do-expressions "^6.22.0" - babel-plugin-transform-function-bind "^6.22.0" - babel-preset-stage-1 "^6.22.0" - -babel-preset-stage-1@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-preset-stage-1/-/babel-preset-stage-1-6.22.0.tgz#7da05bffea6ad5a10aef93e320cfc6dd465dbc1a" - dependencies: - babel-plugin-transform-class-constructor-call "^6.22.0" - babel-plugin-transform-export-extensions "^6.22.0" - babel-preset-stage-2 "^6.22.0" - -babel-preset-stage-2@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.22.0.tgz#ccd565f19c245cade394b21216df704a73b27c07" - dependencies: - babel-plugin-syntax-dynamic-import "^6.18.0" - babel-plugin-transform-class-properties "^6.22.0" - babel-plugin-transform-decorators "^6.22.0" - babel-preset-stage-3 "^6.22.0" - -babel-preset-stage-3@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.22.0.tgz#a4e92bbace7456fafdf651d7a7657ee0bbca9c2e" - dependencies: - babel-plugin-syntax-trailing-function-commas "^6.22.0" - babel-plugin-transform-async-generator-functions "^6.22.0" - babel-plugin-transform-async-to-generator "^6.22.0" - babel-plugin-transform-exponentiation-operator "^6.22.0" - babel-plugin-transform-object-rest-spread "^6.22.0" - -babel-register@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.23.0.tgz#c9aa3d4cca94b51da34826c4a0f9e08145d74ff3" - dependencies: - babel-core "^6.23.0" - babel-runtime "^6.22.0" - core-js "^2.4.0" - home-or-tmp "^2.0.0" - lodash "^4.2.0" - mkdirp "^0.5.1" - source-map-support "^0.4.2" - -babel-runtime@^6.18.0, babel-runtime@^6.22.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b" - dependencies: - core-js "^2.4.0" - regenerator-runtime "^0.10.0" - -babel-template@^6.22.0, babel-template@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.23.0.tgz#04d4f270adbb3aa704a8143ae26faa529238e638" - dependencies: - babel-runtime "^6.22.0" - babel-traverse "^6.23.0" - babel-types "^6.23.0" - babylon "^6.11.0" - lodash "^4.2.0" - -babel-traverse@^6.22.0, babel-traverse@^6.23.0, babel-traverse@^6.23.1: - version "6.23.1" - resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.23.1.tgz#d3cb59010ecd06a97d81310065f966b699e14f48" - dependencies: - babel-code-frame "^6.22.0" - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-types "^6.23.0" - babylon "^6.15.0" - debug "^2.2.0" - globals "^9.0.0" - invariant "^2.2.0" - lodash "^4.2.0" - -babel-types@^6.19.0, babel-types@^6.22.0, babel-types@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.23.0.tgz#bb17179d7538bad38cd0c9e115d340f77e7e9acf" - dependencies: - babel-runtime "^6.22.0" - esutils "^2.0.2" - lodash "^4.2.0" - to-fast-properties "^1.0.1" - -babel@^6.5.2: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel/-/babel-6.23.0.tgz#d0d1e7d803e974765beea3232d4e153c0efb90f4" - -babylon@^6.11.0, babylon@^6.15.0: - version "6.16.1" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.16.1.tgz#30c5a22f481978a9e7f8cdfdf496b11d94b404d3" - -balanced-match@^0.4.1: - version "0.4.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" - -beeper@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/beeper/-/beeper-1.1.1.tgz#e6d5ea8c5dad001304a70b22638447f69cb2f809" - -brace-expansion@^1.0.0: - version "1.1.6" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" - dependencies: - balanced-match "^0.4.1" - concat-map "0.0.1" - -braces@^1.8.2: - version "1.8.5" - resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" - dependencies: - expand-range "^1.8.1" - preserve "^0.2.0" - repeat-element "^1.1.2" - -browser-resolve@^1.11.0: - version "1.11.2" - resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce" - dependencies: - resolve "1.1.7" - -buffer-shims@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" - -builtin-modules@^1.1.0, builtin-modules@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" - -caller-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" - dependencies: - callsites "^0.2.0" - -callsites@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" - -camelcase@^1.0.2: - version "1.2.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" - -center-align@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" - dependencies: - align-text "^0.1.3" - lazy-cache "^1.0.3" - -chai@^3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" - dependencies: - assertion-error "^1.0.1" - deep-eql "^0.1.3" - type-detect "^1.0.0" - -chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -circular-json@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" - -cli-cursor@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" - dependencies: - restore-cursor "^1.0.1" - -cli-width@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" - -cliui@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" - dependencies: - center-align "^0.1.1" - right-align "^0.1.1" - wordwrap "0.0.2" - -clone-stats@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1" - -clone@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" - -clone@^1.0.0, clone@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149" - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - -commander@0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" - -commander@2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - -concat-stream@^1.4.6: - version "1.6.0" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" - dependencies: - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -contains-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" - -convert-source-map@1.X, convert-source-map@^1.1.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.4.0.tgz#e3dad195bf61bfe13a7a3c73e9876ec14a0268f3" - -core-js@^2.4.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" - -core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - -css@2.X: - version "2.2.1" - resolved "https://registry.yarnpkg.com/css/-/css-2.2.1.tgz#73a4c81de85db664d4ee674f7d47085e3b2d55dc" - dependencies: - inherits "^2.0.1" - source-map "^0.1.38" - source-map-resolve "^0.3.0" - urix "^0.1.0" - -d@^0.1.1, d@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309" - dependencies: - es5-ext "~0.10.2" - -dateformat@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-2.0.0.tgz#2743e3abb5c3fc2462e527dca445e04e9f4dee17" - -debug-fabulous@0.0.X: - version "0.0.4" - resolved "https://registry.yarnpkg.com/debug-fabulous/-/debug-fabulous-0.0.4.tgz#fa071c5d87484685424807421ca4b16b0b1a0763" - dependencies: - debug "2.X" - lazy-debug-legacy "0.0.X" - object-assign "4.1.0" - -debug@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" - dependencies: - ms "0.7.1" - -debug@2.X, debug@^2.1.1, debug@^2.2.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.1.tgz#79855090ba2c4e3115cc7d8769491d58f0491351" - dependencies: - ms "0.7.2" - -decamelize@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - -deep-eql@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" - dependencies: - type-detect "0.1.1" - -deep-is@~0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - -defaults@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" - dependencies: - clone "^1.0.2" - -del@^2.0.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" - dependencies: - globby "^5.0.0" - is-path-cwd "^1.0.0" - is-path-in-cwd "^1.0.0" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - rimraf "^2.2.8" - -deprecated@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/deprecated/-/deprecated-0.0.1.tgz#f9c9af5464afa1e7a971458a8bdef2aa94d5bb19" - -detect-file@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63" - dependencies: - fs-exists-sync "^0.1.0" - -detect-indent@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" - dependencies: - repeating "^2.0.0" - -detect-newline@2.X: - version "2.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" - -diff@1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" - -doctrine@1.5.0, doctrine@^1.2.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" - dependencies: - esutils "^2.0.2" - isarray "^1.0.0" - -duplexer2@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db" - dependencies: - readable-stream "~1.1.9" - -end-of-stream@~0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-0.1.5.tgz#8e177206c3c80837d85632e8b9359dfe8b2f6eaf" - dependencies: - once "~1.3.0" - -erlang-types@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/erlang-types/-/erlang-types-1.0.0.tgz#e555bd091667498a01d340d18203231dc96d962f" - -es5-ext@^0.10.7, es5-ext@^0.10.8, es5-ext@~0.10.11, es5-ext@~0.10.2, es5-ext@~0.10.7: - version "0.10.12" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.12.tgz#aa84641d4db76b62abba5e45fd805ecbab140047" - dependencies: - es6-iterator "2" - es6-symbol "~3.1" - -es6-iterator@2: - version "2.0.0" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.0.tgz#bd968567d61635e33c0b80727613c9cb4b096bac" - dependencies: - d "^0.1.1" - es5-ext "^0.10.7" - es6-symbol "3" - -es6-map@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.4.tgz#a34b147be224773a4d7da8072794cefa3632b897" - dependencies: - d "~0.1.1" - es5-ext "~0.10.11" - es6-iterator "2" - es6-set "~0.1.3" - es6-symbol "~3.1.0" - event-emitter "~0.3.4" - -es6-set@~0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.4.tgz#9516b6761c2964b92ff479456233a247dc707ce8" - dependencies: - d "~0.1.1" - es5-ext "~0.10.11" - es6-iterator "2" - es6-symbol "3" - event-emitter "~0.3.4" - -es6-symbol@3, es6-symbol@~3.1, es6-symbol@~3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.0.tgz#94481c655e7a7cad82eba832d97d5433496d7ffa" - dependencies: - d "~0.1.1" - es5-ext "~0.10.11" - -es6-weak-map@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.1.tgz#0d2bbd8827eb5fb4ba8f97fbfea50d43db21ea81" - dependencies: - d "^0.1.1" - es5-ext "^0.10.8" - es6-iterator "2" - es6-symbol "3" - -escape-string-regexp@1.0.2, escape-string-regexp@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - -escope@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" - dependencies: - es6-map "^0.1.3" - es6-weak-map "^2.0.1" - esrecurse "^4.1.0" - estraverse "^4.1.1" - -eslint-config-airbnb-base@^11.1.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-11.1.0.tgz#dc9b3ec70b8c74dcbe6d6257c9da3992c39ca2ca" - -eslint-import-resolver-node@^0.2.0: - version "0.2.3" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.2.3.tgz#5add8106e8c928db2cba232bcd9efa846e3da16c" - dependencies: - debug "^2.2.0" - object-assign "^4.0.1" - resolve "^1.1.6" - -eslint-module-utils@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.0.0.tgz#a6f8c21d901358759cdc35dbac1982ae1ee58bce" - dependencies: - debug "2.2.0" - pkg-dir "^1.0.0" - -eslint-plugin-import@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.2.0.tgz#72ba306fad305d67c4816348a4699a4229ac8b4e" - dependencies: - builtin-modules "^1.1.1" - contains-path "^0.1.0" - debug "^2.2.0" - doctrine "1.5.0" - eslint-import-resolver-node "^0.2.0" - eslint-module-utils "^2.0.0" - has "^1.0.1" - lodash.cond "^4.3.0" - minimatch "^3.0.3" - pkg-up "^1.0.0" - -eslint@^3.15.0: - version "3.16.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.16.1.tgz#9bc31fc7341692cf772e80607508f67d711c5609" - dependencies: - babel-code-frame "^6.16.0" - chalk "^1.1.3" - concat-stream "^1.4.6" - debug "^2.1.1" - doctrine "^1.2.2" - escope "^3.6.0" - espree "^3.4.0" - estraverse "^4.2.0" - esutils "^2.0.2" - file-entry-cache "^2.0.0" - glob "^7.0.3" - globals "^9.14.0" - ignore "^3.2.0" - imurmurhash "^0.1.4" - inquirer "^0.12.0" - is-my-json-valid "^2.10.0" - is-resolvable "^1.0.0" - js-yaml "^3.5.1" - json-stable-stringify "^1.0.0" - levn "^0.3.0" - lodash "^4.0.0" - mkdirp "^0.5.0" - natural-compare "^1.4.0" - optionator "^0.8.2" - path-is-inside "^1.0.1" - pluralize "^1.2.1" - progress "^1.1.8" - require-uncached "^1.0.2" - shelljs "^0.7.5" - strip-bom "^3.0.0" - strip-json-comments "~2.0.1" - table "^3.7.8" - text-table "~0.2.0" - user-home "^2.0.0" - -espree@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.0.tgz#41656fa5628e042878025ef467e78f125cb86e1d" - dependencies: - acorn "4.0.4" - acorn-jsx "^3.0.0" - -esprima@^3.1.1: - version "3.1.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" - -esrecurse@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" - dependencies: - estraverse "~4.1.0" - object-assign "^4.0.1" - -estraverse@^4.1.1, estraverse@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" - -estraverse@~4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" - -estree-walker@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.2.1.tgz#bdafe8095383d8414d5dc2ecf4c9173b6db9412e" - -esutils@^2.0.0, esutils@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" - -event-emitter@~0.3.4: - version "0.3.4" - resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.4.tgz#8d63ddfb4cfe1fae3b32ca265c4c720222080bb5" - dependencies: - d "~0.1.1" - es5-ext "~0.10.7" - -exit-hook@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" - -expand-brackets@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" - dependencies: - is-posix-bracket "^0.1.0" - -expand-range@^1.8.1: - version "1.8.2" - resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" - dependencies: - fill-range "^2.1.0" - -expand-tilde@^1.2.1, expand-tilde@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449" - dependencies: - os-homedir "^1.0.1" - -extend@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" - -extglob@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" - dependencies: - is-extglob "^1.0.0" - -fancy-log@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.0.tgz#45be17d02bb9917d60ccffd4995c999e6c8c9948" - dependencies: - chalk "^1.1.1" - time-stamp "^1.0.0" - -fast-levenshtein@~2.0.4: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - -figures@^1.3.5: - version "1.7.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" - dependencies: - escape-string-regexp "^1.0.5" - object-assign "^4.1.0" - -file-entry-cache@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" - dependencies: - flat-cache "^1.2.1" - object-assign "^4.0.1" - -filename-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" - -fill-range@^2.1.0: - version "2.2.3" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" - dependencies: - is-number "^2.1.0" - isobject "^2.0.0" - randomatic "^1.1.3" - repeat-element "^1.1.2" - repeat-string "^1.5.2" - -find-index@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/find-index/-/find-index-0.1.1.tgz#675d358b2ca3892d795a1ab47232f8b6e2e0dde4" - -find-up@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" - dependencies: - path-exists "^2.0.0" - pinkie-promise "^2.0.0" - -findup-sync@^0.4.2: - version "0.4.3" - resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12" - dependencies: - detect-file "^0.1.0" - is-glob "^2.0.1" - micromatch "^2.3.7" - resolve-dir "^0.1.0" - -fined@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/fined/-/fined-1.0.2.tgz#5b28424b760d7598960b7ef8480dff8ad3660e97" - dependencies: - expand-tilde "^1.2.1" - lodash.assignwith "^4.0.7" - lodash.isempty "^4.2.1" - lodash.isplainobject "^4.0.4" - lodash.isstring "^4.0.1" - lodash.pick "^4.2.1" - parse-filepath "^1.0.1" - -first-chunk-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz#59bfb50cd905f60d7c394cd3d9acaab4e6ad934e" - -flagged-respawn@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-0.3.2.tgz#ff191eddcd7088a675b2610fffc976be9b8074b5" - -flat-cache@^1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96" - dependencies: - circular-json "^0.3.1" - del "^2.0.2" - graceful-fs "^4.1.2" - write "^0.2.1" - -for-in@^0.1.5: - version "0.1.6" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.6.tgz#c9f96e89bfad18a545af5ec3ed352a1d9e5b4dc8" - -for-own@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.4.tgz#0149b41a39088c7515f51ebe1c1386d45f935072" - dependencies: - for-in "^0.1.5" - -fs-exists-sync@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - -function-bind@^1.0.2: - version "1.1.0" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771" - -gaze@^0.5.1: - version "0.5.2" - resolved "https://registry.yarnpkg.com/gaze/-/gaze-0.5.2.tgz#40b709537d24d1d45767db5a908689dfe69ac44f" - dependencies: - globule "~0.1.0" - -generate-function@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" - -generate-object-property@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" - dependencies: - is-property "^1.0.0" - -glob-base@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" - dependencies: - glob-parent "^2.0.0" - is-glob "^2.0.0" - -glob-parent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" - dependencies: - is-glob "^2.0.0" - -glob-stream@^3.1.5: - version "3.1.18" - resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-3.1.18.tgz#9170a5f12b790306fdfe598f313f8f7954fd143b" - dependencies: - glob "^4.3.1" - glob2base "^0.0.12" - minimatch "^2.0.1" - ordered-read-streams "^0.1.0" - through2 "^0.6.1" - unique-stream "^1.0.0" - -glob-watcher@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/glob-watcher/-/glob-watcher-0.0.6.tgz#b95b4a8df74b39c83298b0c05c978b4d9a3b710b" - dependencies: - gaze "^0.5.1" - -glob2base@^0.0.12: - version "0.0.12" - resolved "https://registry.yarnpkg.com/glob2base/-/glob2base-0.0.12.tgz#9d419b3e28f12e83a362164a277055922c9c0d56" - dependencies: - find-index "^0.1.1" - -glob@3.2.11: - version "3.2.11" - resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.11.tgz#4a973f635b9190f715d10987d5c00fd2815ebe3d" - dependencies: - inherits "2" - minimatch "0.3" - -glob@^4.3.1: - version "4.5.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" - dependencies: - inflight "^1.0.4" - inherits "2" - minimatch "^2.0.1" - once "^1.3.0" - -glob@^7.0.0, glob@^7.0.3, glob@^7.0.5: - version "7.1.1" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.2" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@~3.1.21: - version "3.1.21" - resolved "https://registry.yarnpkg.com/glob/-/glob-3.1.21.tgz#d29e0a055dea5138f4d07ed40e8982e83c2066cd" - dependencies: - graceful-fs "~1.2.0" - inherits "1" - minimatch "~0.2.11" - -global-modules@^0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" - dependencies: - global-prefix "^0.1.4" - is-windows "^0.2.0" - -global-prefix@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f" - dependencies: - homedir-polyfill "^1.0.0" - ini "^1.3.4" - is-windows "^0.2.0" - which "^1.2.12" - -globals@^9.0.0, globals@^9.14.0: - version "9.16.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-9.16.0.tgz#63e903658171ec2d9f51b1d31de5e2b8dc01fb80" - -globby@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" - dependencies: - array-union "^1.0.1" - arrify "^1.0.0" - glob "^7.0.3" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -globule@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/globule/-/globule-0.1.0.tgz#d9c8edde1da79d125a151b79533b978676346ae5" - dependencies: - glob "~3.1.21" - lodash "~1.0.1" - minimatch "~0.2.11" - -glogg@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.0.tgz#7fe0f199f57ac906cf512feead8f90ee4a284fc5" - dependencies: - sparkles "^1.0.0" - -graceful-fs@4.X, graceful-fs@^4.1.2: - version "4.1.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" - -graceful-fs@^3.0.0: - version "3.0.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818" - dependencies: - natives "^1.1.0" - -graceful-fs@~1.2.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-1.2.3.tgz#15a4806a57547cb2d2dbf27f42e89a8c3451b364" - -growl@1.9.2: - version "1.9.2" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" - -gulp-babel@^6.1.2: - version "6.1.2" - resolved "https://registry.yarnpkg.com/gulp-babel/-/gulp-babel-6.1.2.tgz#7c0176e4ba3f244c60588a0c4b320a45d1adefce" - dependencies: - babel-core "^6.0.2" - gulp-util "^3.0.0" - object-assign "^4.0.1" - replace-ext "0.0.1" - through2 "^2.0.0" - vinyl-sourcemaps-apply "^0.2.0" - -gulp-sourcemaps@^2.0.0-alpha: - version "2.4.1" - resolved "https://registry.yarnpkg.com/gulp-sourcemaps/-/gulp-sourcemaps-2.4.1.tgz#8f65dc5c0d07b2fd5c88bc60ec7f13e56716bf74" - dependencies: - acorn "4.X" - convert-source-map "1.X" - css "2.X" - debug-fabulous "0.0.X" - detect-newline "2.X" - graceful-fs "4.X" - source-map "0.X" - strip-bom "3.X" - through2 "2.X" - vinyl "1.X" - -gulp-util@^3.0.0: - version "3.0.8" - resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-3.0.8.tgz#0054e1e744502e27c04c187c3ecc505dd54bbb4f" - dependencies: - array-differ "^1.0.0" - array-uniq "^1.0.2" - beeper "^1.0.0" - chalk "^1.0.0" - dateformat "^2.0.0" - fancy-log "^1.1.0" - gulplog "^1.0.0" - has-gulplog "^0.1.0" - lodash._reescape "^3.0.0" - lodash._reevaluate "^3.0.0" - lodash._reinterpolate "^3.0.0" - lodash.template "^3.0.0" - minimist "^1.1.0" - multipipe "^0.1.2" - object-assign "^3.0.0" - replace-ext "0.0.1" - through2 "^2.0.0" - vinyl "^0.5.0" - -gulp@^3.9.1: - version "3.9.1" - resolved "https://registry.yarnpkg.com/gulp/-/gulp-3.9.1.tgz#571ce45928dd40af6514fc4011866016c13845b4" - dependencies: - archy "^1.0.0" - chalk "^1.0.0" - deprecated "^0.0.1" - gulp-util "^3.0.0" - interpret "^1.0.0" - liftoff "^2.1.0" - minimist "^1.1.0" - orchestrator "^0.3.0" - pretty-hrtime "^1.0.0" - semver "^4.1.0" - tildify "^1.0.0" - v8flags "^2.0.2" - vinyl-fs "^0.3.0" - -gulplog@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/gulplog/-/gulplog-1.0.0.tgz#e28c4d45d05ecbbed818363ce8f9c5926229ffe5" - dependencies: - glogg "^1.0.0" - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - dependencies: - ansi-regex "^2.0.0" - -has-gulplog@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/has-gulplog/-/has-gulplog-0.1.0.tgz#6414c82913697da51590397dafb12f22967811ce" - dependencies: - sparkles "^1.0.0" - -has@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" - dependencies: - function-bind "^1.0.2" - -home-or-tmp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.1" - -homedir-polyfill@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" - dependencies: - parse-passwd "^1.0.0" - -ignore@^3.2.0: - version "3.2.4" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.4.tgz#4055e03596729a8fabe45a43c100ad5ed815c4e8" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-1.0.2.tgz#ca4309dadee6b54cc0b8d247e8d7c7a0975bdc9b" - -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - -ini@^1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" - -inquirer@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" - dependencies: - ansi-escapes "^1.1.0" - ansi-regex "^2.0.0" - chalk "^1.0.0" - cli-cursor "^1.0.1" - cli-width "^2.0.0" - figures "^1.3.5" - lodash "^4.3.0" - readline2 "^1.0.1" - run-async "^0.1.0" - rx-lite "^3.1.2" - string-width "^1.0.1" - strip-ansi "^3.0.0" - through "^2.3.6" - -interpret@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.1.tgz#d579fb7f693b858004947af39fa0db49f795602c" - -invariant@^2.2.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" - dependencies: - loose-envify "^1.0.0" - -is-absolute@^0.2.3: - version "0.2.6" - resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-0.2.6.tgz#20de69f3db942ef2d87b9c2da36f172235b1b5eb" - dependencies: - is-relative "^0.2.1" - is-windows "^0.2.0" - -is-buffer@^1.0.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b" - -is-dotfile@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" - -is-equal-shallow@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" - dependencies: - is-primitive "^2.0.0" - -is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - -is-extglob@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" - -is-finite@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - -is-glob@^2.0.0, is-glob@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" - dependencies: - is-extglob "^1.0.0" - -is-my-json-valid@^2.10.0: - version "2.16.0" - resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz#f079dd9bfdae65ee2038aae8acbc86ab109e3693" - dependencies: - generate-function "^2.0.0" - generate-object-property "^1.1.0" - jsonpointer "^4.0.0" - xtend "^4.0.0" - -is-number@^2.0.2, is-number@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" - dependencies: - kind-of "^3.0.2" - -is-path-cwd@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" - -is-path-in-cwd@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" - dependencies: - is-path-inside "^1.0.0" - -is-path-inside@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" - dependencies: - path-is-inside "^1.0.1" - -is-posix-bracket@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" - -is-primitive@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" - -is-property@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" - -is-relative@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-0.2.1.tgz#d27f4c7d516d175fb610db84bbeef23c3bc97aa5" - dependencies: - is-unc-path "^0.1.1" - -is-resolvable@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" - dependencies: - tryit "^1.0.1" - -is-unc-path@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-0.1.2.tgz#6ab053a72573c10250ff416a3814c35178af39b9" - dependencies: - unc-path-regex "^0.1.0" - -is-utf8@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" - -is-windows@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" - -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - -isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - -isexe@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-1.1.2.tgz#36f3e22e60750920f5e7241a476a8c6a42275ad0" - -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - dependencies: - isarray "1.0.0" - -jade@0.26.3: - version "0.26.3" - resolved "https://registry.yarnpkg.com/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c" - dependencies: - commander "0.6.1" - mkdirp "0.3.0" - -js-tokens@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" - -js-yaml@^3.5.1: - version "3.8.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.1.tgz#782ba50200be7b9e5a8537001b7804db3ad02628" - dependencies: - argparse "^1.0.7" - esprima "^3.1.1" - -jsesc@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" - -jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - -json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - dependencies: - jsonify "~0.0.0" - -json5@^0.5.0: - version "0.5.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" - -jsonify@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - -jsonpointer@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" - -kind-of@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47" - dependencies: - is-buffer "^1.0.2" - -lazy-cache@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" - -lazy-debug-legacy@0.0.X: - version "0.0.1" - resolved "https://registry.yarnpkg.com/lazy-debug-legacy/-/lazy-debug-legacy-0.0.1.tgz#537716c0776e4cf79e3ed1b621f7658c2911b1b1" - -levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - -liftoff@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-2.3.0.tgz#a98f2ff67183d8ba7cfaca10548bd7ff0550b385" - dependencies: - extend "^3.0.0" - findup-sync "^0.4.2" - fined "^1.0.1" - flagged-respawn "^0.3.2" - lodash.isplainobject "^4.0.4" - lodash.isstring "^4.0.1" - lodash.mapvalues "^4.4.0" - rechoir "^0.6.2" - resolve "^1.1.7" - -lodash._basecopy@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" - -lodash._basetostring@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz#d1861d877f824a52f669832dcaf3ee15566a07d5" - -lodash._basevalues@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz#5b775762802bde3d3297503e26300820fdf661b7" - -lodash._getnative@^3.0.0: - version "3.9.1" - resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" - -lodash._isiterateecall@^3.0.0: - version "3.0.9" - resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" - -lodash._reescape@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reescape/-/lodash._reescape-3.0.0.tgz#2b1d6f5dfe07c8a355753e5f27fac7f1cde1616a" - -lodash._reevaluate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz#58bc74c40664953ae0b124d806996daca431e2ed" - -lodash._reinterpolate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" - -lodash._root@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" - -lodash.assignwith@^4.0.7: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.assignwith/-/lodash.assignwith-4.2.0.tgz#127a97f02adc41751a954d24b0de17e100e038eb" - -lodash.cond@^4.3.0: - version "4.5.2" - resolved "https://registry.yarnpkg.com/lodash.cond/-/lodash.cond-4.5.2.tgz#f471a1da486be60f6ab955d17115523dd1d255d5" - -lodash.escape@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698" - dependencies: - lodash._root "^3.0.0" - -lodash.isarguments@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" - -lodash.isarray@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" - -lodash.isempty@^4.2.1: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e" - -lodash.isplainobject@^4.0.4: - version "4.0.6" - resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" - -lodash.isstring@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" - -lodash.keys@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" - dependencies: - lodash._getnative "^3.0.0" - lodash.isarguments "^3.0.0" - lodash.isarray "^3.0.0" - -lodash.mapvalues@^4.4.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz#1bafa5005de9dd6f4f26668c30ca37230cc9689c" - -lodash.pick@^4.2.1: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" - -lodash.restparam@^3.0.0: - version "3.6.1" - resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" - -lodash.template@^3.0.0: - version "3.6.2" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-3.6.2.tgz#f8cdecc6169a255be9098ae8b0c53d378931d14f" - dependencies: - lodash._basecopy "^3.0.0" - lodash._basetostring "^3.0.0" - lodash._basevalues "^3.0.0" - lodash._isiterateecall "^3.0.0" - lodash._reinterpolate "^3.0.0" - lodash.escape "^3.0.0" - lodash.keys "^3.0.0" - lodash.restparam "^3.0.0" - lodash.templatesettings "^3.0.0" - -lodash.templatesettings@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz#fb307844753b66b9f1afa54e262c745307dba8e5" - dependencies: - lodash._reinterpolate "^3.0.0" - lodash.escape "^3.0.0" - -lodash@^4.0.0, lodash@^4.2.0, lodash@^4.3.0: - version "4.17.4" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" - -lodash@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.0.2.tgz#8f57560c83b59fc270bd3d561b690043430e2551" - -longest@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" - -loose-envify@^1.0.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" - dependencies: - js-tokens "^3.0.0" - -lru-cache@2: - version "2.7.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" - -map-cache@^0.2.0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - -micromatch@^2.3.7: - version "2.3.11" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" - dependencies: - arr-diff "^2.0.0" - array-unique "^0.2.1" - braces "^1.8.2" - expand-brackets "^0.1.4" - extglob "^0.3.1" - filename-regex "^2.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.1" - kind-of "^3.0.2" - normalize-path "^2.0.1" - object.omit "^2.0.0" - parse-glob "^3.0.4" - regex-cache "^0.4.2" - -minimatch@0.3: - version "0.3.0" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.3.0.tgz#275d8edaac4f1bb3326472089e7949c8394699dd" - dependencies: - lru-cache "2" - sigmund "~1.0.0" - -minimatch@^2.0.1: - version "2.0.10" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" - dependencies: - brace-expansion "^1.0.0" - -minimatch@^3.0.2, minimatch@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" - dependencies: - brace-expansion "^1.0.0" - -minimatch@~0.2.11: - version "0.2.14" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a" - dependencies: - lru-cache "2" - sigmund "~1.0.0" - -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - -minimist@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - -mkdirp@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" - -mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - dependencies: - minimist "0.0.8" - -mocha@^2.4.5: - version "2.5.3" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-2.5.3.tgz#161be5bdeb496771eb9b35745050b622b5aefc58" - dependencies: - commander "2.3.0" - debug "2.2.0" - diff "1.4.0" - escape-string-regexp "1.0.2" - glob "3.2.11" - growl "1.9.2" - jade "0.26.3" - mkdirp "0.5.1" - supports-color "1.2.0" - to-iso-string "0.0.2" - -modify-babel-preset@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/modify-babel-preset/-/modify-babel-preset-2.1.1.tgz#2d3190162ee62fb67aaa3325c242f026322ebbac" - dependencies: - require-relative "^0.8.7" - -ms@0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" - -ms@0.7.2: - version "0.7.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" - -multipipe@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-0.1.2.tgz#2a8f2ddf70eed564dff2d57f1e1a137d9f05078b" - dependencies: - duplexer2 "0.0.2" - -mute-stream@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" - -natives@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.0.tgz#e9ff841418a6b2ec7a495e939984f78f163e6e31" - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - -normalize-path@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - -object-assign@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" - -object-assign@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" - -object-assign@^4.0.1, object-assign@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - -object.omit@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" - dependencies: - for-own "^0.1.4" - is-extendable "^0.1.1" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - dependencies: - wrappy "1" - -once@~1.3.0: - version "1.3.3" - resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" - dependencies: - wrappy "1" - -onetime@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" - -optionator@^0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.4" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - wordwrap "~1.0.0" - -orchestrator@^0.3.0: - version "0.3.8" - resolved "https://registry.yarnpkg.com/orchestrator/-/orchestrator-0.3.8.tgz#14e7e9e2764f7315fbac184e506c7aa6df94ad7e" - dependencies: - end-of-stream "~0.1.5" - sequencify "~0.0.7" - stream-consume "~0.1.0" - -ordered-read-streams@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz#fd565a9af8eb4473ba69b6ed8a34352cb552f126" - -os-homedir@^1.0.0, os-homedir@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - -os-tmpdir@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - -parse-filepath@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.1.tgz#159d6155d43904d16c10ef698911da1e91969b73" - dependencies: - is-absolute "^0.2.3" - map-cache "^0.2.0" - path-root "^0.1.1" - -parse-glob@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" - dependencies: - glob-base "^0.3.0" - is-dotfile "^1.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.0" - -parse-passwd@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" - -path-exists@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" - dependencies: - pinkie-promise "^2.0.0" - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - -path-is-inside@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - -path-parse@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" - -path-root-regex@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d" - -path-root@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7" - dependencies: - path-root-regex "^0.1.0" - -pify@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - -pkg-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" - dependencies: - find-up "^1.0.0" - -pkg-up@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-1.0.0.tgz#3e08fb461525c4421624a33b9f7e6d0af5b05a26" - dependencies: - find-up "^1.0.0" - -pluralize@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" - -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - -preserve@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" - -pretty-hrtime@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" - -private@^0.1.6: - version "0.1.7" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1" - -process-nextick-args@~1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" - -progress@^1.1.8: - version "1.1.8" - resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" - -randomatic@^1.1.3: - version "1.1.6" - resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" - dependencies: - is-number "^2.0.2" - kind-of "^3.0.2" - -"readable-stream@>=1.0.33-1 <1.1.0-0": - version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@^2.1.5, readable-stream@^2.2.2: - version "2.2.3" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.3.tgz#9cf49463985df016c8ae8813097a9293a9b33729" - dependencies: - buffer-shims "^1.0.0" - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - string_decoder "~0.10.x" - util-deprecate "~1.0.1" - -readable-stream@~1.1.9: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readline2@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - mute-stream "0.0.5" - -rechoir@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" - dependencies: - resolve "^1.1.6" - -regenerate@^1.2.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" - -regenerator-runtime@^0.10.0: - version "0.10.3" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz#8c4367a904b51ea62a908ac310bf99ff90a82a3e" - -regenerator-transform@0.9.8: - version "0.9.8" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.9.8.tgz#0f88bb2bc03932ddb7b6b7312e68078f01026d6c" - dependencies: - babel-runtime "^6.18.0" - babel-types "^6.19.0" - private "^0.1.6" - -regex-cache@^0.4.2: - version "0.4.3" - resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" - dependencies: - is-equal-shallow "^0.1.3" - is-primitive "^2.0.0" - -regexpu-core@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" - dependencies: - regenerate "^1.2.1" - regjsgen "^0.2.0" - regjsparser "^0.1.4" - -regjsgen@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" - -regjsparser@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" - dependencies: - jsesc "~0.5.0" - -repeat-element@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" - -repeat-string@^1.5.2: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - -repeating@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - dependencies: - is-finite "^1.0.0" - -replace-ext@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924" - -require-relative@^0.8.7: - version "0.8.7" - resolved "https://registry.yarnpkg.com/require-relative/-/require-relative-0.8.7.tgz#7999539fc9e047a37928fa196f8e1563dabd36de" - -require-uncached@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" - dependencies: - caller-path "^0.1.0" - resolve-from "^1.0.0" - -resolve-dir@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e" - dependencies: - expand-tilde "^1.2.2" - global-modules "^0.2.3" - -resolve-from@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" - -resolve-url@~0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - -resolve@1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" - -resolve@^1.1.6, resolve@^1.1.7: - version "1.3.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.1.tgz#5d0a1632609b6b00a22284293db1d5d973676314" - dependencies: - path-parse "^1.0.5" - -restore-cursor@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" - dependencies: - exit-hook "^1.0.0" - onetime "^1.0.0" - -right-align@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" - dependencies: - align-text "^0.1.1" - -rimraf@^2.2.8: - version "2.6.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" - dependencies: - glob "^7.0.5" - -rollup-plugin-babel@^2.7.1: - version "2.7.1" - resolved "https://registry.yarnpkg.com/rollup-plugin-babel/-/rollup-plugin-babel-2.7.1.tgz#16528197b0f938a1536f44683c7a93d573182f57" - dependencies: - babel-core "6" - babel-plugin-transform-es2015-classes "^6.9.0" - object-assign "^4.1.0" - rollup-pluginutils "^1.5.0" - -rollup-plugin-node-resolve@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-2.0.0.tgz#07e0ae94ac002a3ea36e8f33ca121d9f836b1309" - dependencies: - browser-resolve "^1.11.0" - builtin-modules "^1.1.0" - resolve "^1.1.6" - -rollup-plugin-uglify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/rollup-plugin-uglify/-/rollup-plugin-uglify-1.0.1.tgz#11d0b0c8bcd2d07e6908f74fd16b0152390b922a" - dependencies: - uglify-js "^2.6.1" - -rollup-pluginutils@^1.5.0: - version "1.5.2" - resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-1.5.2.tgz#1e156e778f94b7255bfa1b3d0178be8f5c552408" - dependencies: - estree-walker "^0.2.1" - minimatch "^3.0.2" - -rollup@^0.41.4: - version "0.41.4" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-0.41.4.tgz#a970580176329f9ead86854d7fd4c46de752aef8" - dependencies: - source-map-support "^0.4.0" - -run-async@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" - dependencies: - once "^1.3.0" - -rx-lite@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" - -semver@^4.1.0: - version "4.3.6" - resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" - -sequencify@~0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/sequencify/-/sequencify-0.0.7.tgz#90cff19d02e07027fd767f5ead3e7b95d1e7380c" - -shelljs@^0.7.5: - version "0.7.6" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.6.tgz#379cccfb56b91c8601e4793356eb5382924de9ad" - dependencies: - glob "^7.0.0" - interpret "^1.0.0" - rechoir "^0.6.2" - -sigmund@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" - -slash@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" - -slice-ansi@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" - -source-map-resolve@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.3.1.tgz#610f6122a445b8dd51535a2a71b783dfc1248761" - dependencies: - atob "~1.1.0" - resolve-url "~0.2.1" - source-map-url "~0.3.0" - urix "~0.1.0" - -source-map-support@^0.4.0, source-map-support@^0.4.2: - version "0.4.11" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.11.tgz#647f939978b38535909530885303daf23279f322" - dependencies: - source-map "^0.5.3" - -source-map-url@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" - -source-map@0.X, source-map@^0.5.0, source-map@^0.5.1, source-map@^0.5.3, source-map@~0.5.1: - version "0.5.6" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" - -source-map@^0.1.38: - version "0.1.43" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" - dependencies: - amdefine ">=0.0.4" - -sparkles@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.0.tgz#1acbbfb592436d10bbe8f785b7cc6f82815012c3" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - -stream-consume@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/stream-consume/-/stream-consume-0.1.0.tgz#a41ead1a6d6081ceb79f65b061901b6d8f3d1d0f" - -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -string-width@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e" - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^3.0.0" - -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - -strip-ansi@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - dependencies: - ansi-regex "^2.0.0" - -strip-bom@3.X, strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - -strip-bom@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-1.0.0.tgz#85b8862f3844b5a6d5ec8467a93598173a36f794" - dependencies: - first-chunk-stream "^1.0.0" - is-utf8 "^0.2.0" - -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - -supports-color@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - -table@^3.7.8: - version "3.8.3" - resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" - dependencies: - ajv "^4.7.0" - ajv-keywords "^1.0.0" - chalk "^1.1.1" - lodash "^4.0.0" - slice-ansi "0.0.4" - string-width "^2.0.0" - -tailored@2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/tailored/-/tailored-2.3.2.tgz#4081db326b339dd31048c142d52cda3f95c6a135" - dependencies: - erlang-types "^1.0.0" - -text-table@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - -through2@2.X, through2@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" - dependencies: - readable-stream "^2.1.5" - xtend "~4.0.1" - -through2@^0.6.1: - version "0.6.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48" - dependencies: - readable-stream ">=1.0.33-1 <1.1.0-0" - xtend ">=4.0.0 <4.1.0-0" - -through@^2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - -tildify@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/tildify/-/tildify-1.2.0.tgz#dcec03f55dca9b7aa3e5b04f21817eb56e63588a" - dependencies: - os-homedir "^1.0.0" - -time-stamp@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.0.1.tgz#9f4bd23559c9365966f3302dbba2b07c6b99b151" - -to-fast-properties@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" - -to-iso-string@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/to-iso-string/-/to-iso-string-0.0.2.tgz#4dc19e664dfccbe25bd8db508b00c6da158255d1" - -trim-right@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" - -tryit@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" - -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - dependencies: - prelude-ls "~1.1.2" - -type-detect@0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" - -type-detect@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" - -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - -uglify-js@^2.6.1: - version "2.7.5" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8" - dependencies: - async "~0.2.6" - source-map "~0.5.1" - uglify-to-browserify "~1.0.0" - yargs "~3.10.0" - -uglify-to-browserify@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" - -unc-path-regex@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa" - -unique-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-1.0.0.tgz#d59a4a75427447d9aa6c91e70263f8d26a4b104b" - -urix@^0.1.0, urix@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - -user-home@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" - -user-home@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" - dependencies: - os-homedir "^1.0.0" - -util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - -v8flags@^2.0.2: - version "2.0.11" - resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.0.11.tgz#bca8f30f0d6d60612cc2c00641e6962d42ae6881" - dependencies: - user-home "^1.1.1" - -vinyl-fs@^0.3.0: - version "0.3.14" - resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-0.3.14.tgz#9a6851ce1cac1c1cea5fe86c0931d620c2cfa9e6" - dependencies: - defaults "^1.0.0" - glob-stream "^3.1.5" - glob-watcher "^0.0.6" - graceful-fs "^3.0.0" - mkdirp "^0.5.0" - strip-bom "^1.0.0" - through2 "^0.6.1" - vinyl "^0.4.0" - -vinyl-sourcemaps-apply@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz#ab6549d61d172c2b1b87be5c508d239c8ef87705" - dependencies: - source-map "^0.5.1" - -vinyl@1.X: - version "1.2.0" - resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884" - dependencies: - clone "^1.0.0" - clone-stats "^0.0.1" - replace-ext "0.0.1" - -vinyl@^0.4.0: - version "0.4.6" - resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.4.6.tgz#2f356c87a550a255461f36bbeb2a5ba8bf784847" - dependencies: - clone "^0.2.0" - clone-stats "^0.0.1" - -vinyl@^0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.5.3.tgz#b0455b38fc5e0cf30d4325132e461970c2091cde" - dependencies: - clone "^1.0.0" - clone-stats "^0.0.1" - replace-ext "0.0.1" - -which@^1.2.12: - version "1.2.12" - resolved "https://registry.yarnpkg.com/which/-/which-1.2.12.tgz#de67b5e450269f194909ef23ece4ebe416fa1192" - dependencies: - isexe "^1.1.1" - -window-size@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" - -wordwrap@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" - -wordwrap@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - -write@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" - dependencies: - mkdirp "^0.5.1" - -"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@~4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" - -yargs@~3.10.0: - version "3.10.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" - dependencies: - camelcase "^1.0.2" - cliui "^2.1.0" - decamelize "^1.0.0" - window-size "0.1.0"