Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multicompile - per fragment compilation of file in different scripting languages #50

Closed
wants to merge 8 commits into from
Closed
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ lib/coffee-script/*.tmp
lib/bootstrap
coffee-script-redux-*.tgz
*.gem
*.log
11 changes: 11 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
## Changelog

### 0.0.15 (20. sept 2014)

Author: kmandrup@gmail.com

- Split CLI into smaller parts (Single Responsibility)
- Added ability to prepend/append code to output depending on input (using code fragments)
- Code fragments resolve issue #42 (ability to prepend code before ember output)
- Fragmentation turned on by default (can be turned off via options --fragmented switch)
- Added multi-compiler that can be integrated with CLI (see contribution notes)
67 changes: 67 additions & 0 deletions Contributing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
## Contributing to EmberScript

### General recommendations

- Only make changes in the `/src` folder
- Most behavior changes are to be done in `compiler.coffee`
- Make sure the changed file compiles before you do an entire build
- Always make sure all tests pass before you do a pull request

### Running tests

```bash
$ make build -j
$ make test
```

All tests should pass (green)

### Debugging changes

For debugging changes in general, it is often easier to do it directly by examining output to stdout.
This way, any `console.log`s are displayed without the "pollution" of test suite output.

It is often useful to run ember-script with the `-j` switch, returning bare javascript (without function scope wrapper). Again to avoid "pollution" and keep it clean.

Reading input directly from CLI (string)

```bash
$ make build -j
$ bin/ember-script -j --cli "a = 2"
```

Reading input from a file

```bash
$ make build -j
$ bin/ember-script -j --input sandbox/test-fragmented.em
```

### Architecture

bin/ember-script loads the `ember-runtime` and the `cli` in order to execute. The cli parses the cli commands, reads some input from a file or string and generates some output.

```javascript
#!/usr/bin/env node
require(require('path').join(__dirname, '..', 'lib', 'ember-runtime'));
require(require('path').join(__dirname, '..', 'lib', 'cli'));
```

### CLI architecture

`cli-exclusions`: attempts to resolve cli options where conflicts might occur.
`cli-fragmenter`: used to turn code into fragments that can be treated individually.
`cli-help`: displays help on how to use cli
`cli-input-source-chooser`: determines how to read the input source (file, cli string, ...)
`cli-output`: writes the output to an output target (file, stdout, ...)
`cli-process-input`: processes the input using some strategy depending on options
`cli`: the main cli

The fragmenter is currently turned on by default but can be easily turned off in `cli.coffee`:

```coffeescript
# false to disable script fragments
options.fragmented = true
```

See more in [[Script-Fragmentation]]
58 changes: 58 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,61 @@ ember-script --help
```
make -j build test
```

## Script fragments and Multi compilation

This branch support compilation of script fragments (multi compilation).
It was added in order to better support environments where you need more control of the compilation, such
as with ember-cli and ES6 modules.

```coffeescript
var a = "js";

# (coffee)

y = "coffee with a"

# (ember)

class Post
trimmedPosts: ~>
@content?.slice(0, 3)

# (live)

x = "milk and y"
```

Valid aliases are:

- coffeescript:
`cs`, `coffee`
- javascript:
`js`, `ecma`
- livescript:
`ls`, `live`
- emberscript:
`em`, `ember`

The first block is (by default) assumed to be *coffeescript* (unless you have a script identifier comment as the first line of code).

### Customization

For your own customizations, go to the end of `cli-multi-compile.coffee` and change `compilers` or `codeEmitter`. You can also send an extra `mcOptions` object as the last argument. This object can
take a `transformer` function (f.ex to prepend each compiled fragment with a custom comment) and a `lang` (string) argument to override `coffeescript` as the default/first fragment script language.

```coffeescript
multiCompile = require './multi-compiler'

module.exports = (code, options) ->
mcOptions = {
lang: 'coffee'
}
codeEmitter = options.codeEmitter || createCodeEmitter(options)
multiCompile code, compilers, codeEmitter, mcOptions
```





114 changes: 114 additions & 0 deletions Script-Fragmentation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
### Script fragmentation

The fragmenter is currently used to enable prepending of javascript before ember-script generated code (resolves issue #42). The fragmenter has been designed to be easy to customize and also allows appending code using the same pattern if necessary. You could even extend it to compile each code fragment separately and merge them all at the end...

### CoffeeScript/LiveScript compilation

See `process-input.coffee` for examples of usage checkout the Coffeescript npm site/repo

To compile *CoffeeScript* to bare *JavaScript* simply do:

`CoffeeScript.compile source, { bare: true }`

Similar for LiveScript (since a fork of coffeescript):

```coffeescript
# https://github.com/gkz/LiveScript/blob/master/src/index.ls#L20
# Compiles a string of LiveScript code to JavaScript.
compile: (code, options = {}) ->
```

`LiveScript.compile code, { bare: true }`

This could be used for a multi-fragment solution:

### Multi-script fragmentation

Allow for a mix of scripting languages in one file:

`# (ember)` emberscript fragment starts
`# (js)` javascript
`# (coffee)` coffeescript
`# (live)` livescript

The infrastructure for this has already been enabled with `src/multi-compiler.coffee`

Furthermore, we should be able to compile bare EmberScript via:

```coffeescript
# as found in register.coffee

# some text input
input = fs.readFileSync filename, 'utf8'

csAst = EmberScript.parse input, raw: yes, literate: yes
jsAst = EmberScript.compile csAst
js = EmberScript.js jsAst
```

Some sample code: (perhaps not so suitable for Editors, unless they respect this convention in the near future!)

```
var a = js;

# (coffee)
y = coffee with a

# (ember)
class Post
trimmedPosts: ~>
@content?.slice(0, 3)

# (live)
x = milk and y
```

Testing:

`$ bin/ember-script -j --input sandbox/multicompile-code.em`

For the multi-compiler, we could do sth like:

```coffeescript
EmberScript = require './module'
CoffeeScript = require './module'

LiveScript = require('livescript')

EmberScript.compileCode = (input, options) ->
csAst = EmberScript.parse input,
jsAst = EmberScript.compile csAst
EmberScript.js jsAst

compilers =
js: (source) ->
source

coffee: (source) ->
CoffeeScript.compile source, { bare: true }

live: (source) ->
LivesScript.compile source, { bare: true }

ember: (source) ->
EmberScript.compileCode, {raw: yes, literate: yes}
}

# emit the code to a file or stdout
# depending on options

createCodeEmitter = (options)
(code) ->
if options.output
fs.writeFile options.output, code, (err) ->
throw err if err?
else
process.stdout.write code


multiCompile = require './multi-compiler'

multiCompile code, compilers, createCodeEmitter(options)
```

Sweet :)
Loading