├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── example ├── bar.js ├── bat.js ├── baz.coffee ├── baz.litcoffee ├── error.coffee ├── foo.coffee ├── foo.litcoffee ├── multiline_error.coffee ├── neat-ui.coffee └── rad-component.cjsx ├── index.js ├── package.json ├── test ├── bundle.js ├── cjsx.js ├── error.js └── transform.js └── update.sh /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src/ 2 | test/ 3 | examples/ 4 | Cakefile 5 | *.sh -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.8 4 | - 0.10 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 James Friend 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # coffee-reactify 2 | 3 | # STATUS: DEPRECATED 4 | 5 | This tool is no longer maintained. If you need to transition your codebase from 6 | it, a codemod is available to do so: [cjsx-codemod](https://github.com/jsdf/cjsx-codemod) 7 | 8 | This project started as a way for me to explore how JSX could fit into 9 | Coffeescript syntax, as a quickly hacked together prototype. While I never 10 | really promoted it, it quickly took on a life of its own, and before long people 11 | were asking for it to support all kinds of different use cases. On top of that I 12 | had no experience writing parsers, so the result is something with 13 | [insurmountable limitations](https://github.com/jsdf/coffee-react/issues/32). 14 | 15 | As I eventually stopped using Coffeescript I ended up neglecting this project, 16 | but as people were using it I didn't want to kill it. I really should have, 17 | however, because it meant that people were using a crappy, ill-conceived, 18 | unmaintained tool. Now, long overdue, I'm putting it out to pasture. 19 | 20 | Original readme follows: 21 | 22 | browserify v2 plugin for compiling [coffee-react-transform](https://github.com/jsdf/coffee-react-transform) CJSX markup in Coffeescript. 23 | 24 | # example 25 | 26 | given some files written in a mix of `coffee` and `cjsx`: 27 | 28 | neat-ui.coffee: 29 | ``` coffee 30 | require './rad-component.cjsx' 31 | 32 | React.renderComponent RadComponent({rad:"mos def"}), 33 | document.getElementById('container') 34 | ``` 35 | 36 | rad-component.cjsx: 37 | ``` coffee 38 | # @cjsx React.DOM 39 | 40 | React = require('react') 41 | 42 | RadComponent = React.createClass 43 | render: -> 44 |
45 |

is this component rad? {@props.rad}

46 |
47 | ``` 48 | 49 | install coffee-reactify: 50 | 51 | ```bash 52 | $ npm install -g coffee-reactify 53 | ``` 54 | 55 | version compatibility: 56 | 57 | - 2.1.x - React 0.12.1 58 | - 2.x - React 0.12 59 | - 1.x - React 0.11.2 60 | - 0.x - React 0.11 and below 61 | 62 | when you compile your app, pass `-t coffee-reactify` to browserify: 63 | 64 | ```bash 65 | $ browserify -t coffee-reactify neat-ui.coffee > bundle.js 66 | ``` 67 | 68 | you can omit the `.coffee` or `.cjsx` extension from your requires if you add the extension to browserify's module extensions: 69 | 70 | ``` coffee 71 | require './component' 72 | ... 73 | ``` 74 | 75 | ```bash 76 | $ browserify -t coffee-reactify --extension=".cjsx" --extension=".coffee" neat-ui.coffee > bundle.js 77 | ``` 78 | 79 | providing the transform option `coffeeout: true` will passthrough the transformed 80 | output of `.coffee` files with the `@cjsx` pragma without compiling them to javascript. 81 | this means you can use a different coffee compiler transform such as [icsify](https://github.com/maxtaco/icsify) or [coffeeify](https://github.com/jnordberg/coffeeify) in conjunction with this transform. 82 | 83 | **note:** at this stage, `.cjsx` files will still be compiled even with `--coffeeout`. 84 | this is a workaround for the fact that other transform modules like `coffeeify` will 85 | ignore `.cjsx` files due to the different file extension. 86 | 87 | ```bash 88 | $ browserify -t [ coffee-reactify --coffeeout ] -t coffeeify neat-ui.coffee > bundle.js 89 | ``` 90 | 91 | # install 92 | 93 | With [npm](https://npmjs.org) do: 94 | 95 | ```bash 96 | npm install coffee-reactify 97 | ``` 98 | 99 | # license 100 | 101 | MIT 102 | -------------------------------------------------------------------------------- /example/bar.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./baz.coffee')(5) 2 | -------------------------------------------------------------------------------- /example/bat.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./baz.litcoffee')(5) 2 | -------------------------------------------------------------------------------- /example/baz.coffee: -------------------------------------------------------------------------------- 1 | module.exports = (n) -> n * 111 2 | -------------------------------------------------------------------------------- /example/baz.litcoffee: -------------------------------------------------------------------------------- 1 | Multiply all the things with 111 2 | 3 | module.exports = (n) -> n * 111 4 | -------------------------------------------------------------------------------- /example/error.coffee: -------------------------------------------------------------------------------- 1 | #----------------------------------# 2 | # hello, my name is: SµNTtaX E®Rör # 3 | #----------------------------------# 4 | 5 | thisIsWrong = , 'waaa' 6 | -------------------------------------------------------------------------------- /example/foo.coffee: -------------------------------------------------------------------------------- 1 | console.log(require './bar.js') 2 | -------------------------------------------------------------------------------- /example/foo.litcoffee: -------------------------------------------------------------------------------- 1 | Here is a bat 2 | 3 | console.log(require './bat.js') 4 | -------------------------------------------------------------------------------- /example/multiline_error.coffee: -------------------------------------------------------------------------------- 1 | #----------------------------------# 2 | # hello, my name is: SµNTtaX E®Rör # 3 | #----------------------------------# 4 | 5 | 6 | 'this is very wrong. notice that the first line is'' 7 | longer' -------------------------------------------------------------------------------- /example/neat-ui.coffee: -------------------------------------------------------------------------------- 1 | React = require 'react' 2 | 3 | RadComponent = require './rad-component' 4 | 5 | console.log React.renderToStaticMarkup React.createElement(RadComponent, rad: 'mos def') 6 | -------------------------------------------------------------------------------- /example/rad-component.cjsx: -------------------------------------------------------------------------------- 1 | # @cjsx React.DOM 2 | 3 | React = require 'react' 4 | 5 | RadComponent = React.createClass 6 | render: -> 7 |
8 |

is this component rad? {@props.rad}

9 |
10 | 11 | module.exports = RadComponent -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var through = require('through'); 3 | var convert = require('convert-source-map'); 4 | var coffeereact = require('coffee-react'); 5 | 6 | function hasCoffeeExtension (file) { 7 | return (/\.((lit)?coffee|coffee\.md)$/).test(file); 8 | } 9 | 10 | function hasLiterateExtension (file) { 11 | return (/\.(litcoffee|coffee\.md)$/).test(file); 12 | } 13 | 14 | function ParseError(error, src, file) { 15 | /* Creates a ParseError from a CoffeeScript SyntaxError 16 | modeled after substack's syntax-error module */ 17 | SyntaxError.call(this); 18 | 19 | this.message = error.message; 20 | 21 | this.line = error.location.first_line + 1; // cs linenums are 0-indexed 22 | this.column = error.location.first_column + 1; // same with columns 23 | 24 | var markerLen = 2; 25 | if(error.location.first_line === error.location.last_line) { 26 | markerLen += error.location.last_column - error.location.first_column; 27 | } 28 | this.annotated = [ 29 | file + ':' + this.line, 30 | src.split('\n')[this.line - 1], 31 | Array(this.column).join(' ') + Array(markerLen).join('^'), 32 | 'ParseError: ' + this.message 33 | ].join('\n'); 34 | } 35 | 36 | ParseError.prototype = Object.create(SyntaxError.prototype); 37 | 38 | ParseError.prototype.toString = function () { 39 | return this.annotated; 40 | }; 41 | 42 | ParseError.prototype.inspect = function () { 43 | return this.annotated; 44 | }; 45 | 46 | function compile(file, data, callback) { 47 | var compiled; 48 | try { 49 | compiled = coffeereact.compile(data, { 50 | sourceMap: true, 51 | generatedFile: file, 52 | inline: true, 53 | bare: true, 54 | literate: hasLiterateExtension(file) 55 | }); 56 | } catch (e) { 57 | var error = e; 58 | if (e.location) { 59 | error = new ParseError(e, data, file); 60 | } 61 | callback(error); 62 | return; 63 | } 64 | 65 | var map = convert.fromJSON(compiled.v3SourceMap); 66 | map.setProperty('sources', [file]); 67 | 68 | callback(null, compiled.js + '\n' + map.toComment() + '\n'); 69 | } 70 | 71 | function coffeereactify(file, opts) { 72 | opts = opts || {}; 73 | var passthroughCoffee = opts['coffeeout'] || false; 74 | var hasCoffeeExt = hasCoffeeExtension(file); 75 | var hasCJSXExt = coffeereact.hasCJSXExtension(file); 76 | 77 | if (!(hasCoffeeExt || hasCJSXExt)) { 78 | return through(); 79 | } 80 | 81 | var data = '', stream = through(write, end); 82 | 83 | return stream; 84 | 85 | function write(buf) { 86 | data += buf; 87 | } 88 | 89 | function end() { 90 | if (hasCoffeeExt && passthroughCoffee) { 91 | // passthrough un-compiled coffeescript 92 | var transformed; 93 | try { 94 | transformed = coffeereact.transform(data); 95 | } catch (error) { 96 | return stream.emit('error', error); 97 | } 98 | stream.queue(transformed || data); 99 | stream.queue(null); 100 | } else { 101 | // otherwise compile either cjsx or pure coffee 102 | compile(file, data, function(error, result) { 103 | if (error) stream.emit('error', error); 104 | stream.queue(result); 105 | stream.queue(null); 106 | }); 107 | } 108 | } 109 | } 110 | 111 | coffeereactify.compile = compile; 112 | coffeereactify.isCoffee = hasCoffeeExtension; 113 | coffeereactify.isLiterate = hasLiterateExtension; 114 | coffeereactify.hasCJSXExtension = coffeereact.hasCJSXExtension; 115 | coffeereactify.hasCJSXPragma = coffeereact.hasCJSXPragma; 116 | 117 | module.exports = coffeereactify; 118 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "coffee-reactify", 3 | "version": "5.1.0", 4 | "description": "browserify v2 plugin for coffee-react cjsx", 5 | "main": "index.js", 6 | "dependencies": { 7 | "coffee-react": "^5.0.0", 8 | "convert-source-map": "~0.3.3", 9 | "through": "~2.3.4" 10 | }, 11 | "devDependencies": { 12 | "tap": "~0.4.0", 13 | "browserify": "^3.38.0", 14 | "react": "^0.12.0" 15 | }, 16 | "scripts": { 17 | "test": "tap test/*.js" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git://github.com/jsdf/coffee-reactify.git" 22 | }, 23 | "homepage": "https://github.com/jsdf/coffee-reactify", 24 | "keywords": [ 25 | "coffee-script", 26 | "react", 27 | "browserify", 28 | "transform" 29 | ], 30 | "contributors": [ 31 | { 32 | "name": "James Halliday", 33 | "email": "mail@substack.net", 34 | "url": "http://substack.net" 35 | }, 36 | { 37 | "name": "Johan Nordberg", 38 | "email": "code@johan-nordberg.com", 39 | "url": "http://johan-nordberg.com" 40 | }, 41 | { 42 | "name": "James Friend", 43 | "email": "james@jsdf.co", 44 | "url": "http://jsdf.co" 45 | } 46 | ], 47 | "license": "MIT" 48 | } 49 | -------------------------------------------------------------------------------- /test/bundle.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | var browserify = require('browserify'); 3 | var vm = require('vm'); 4 | 5 | function bundle (file) { 6 | test('bundle transform', function (t) { 7 | t.plan(1); 8 | 9 | var b = browserify(); 10 | b.add(__dirname + file); 11 | b.transform(__dirname + '/..'); 12 | b.bundle(function (err, src) { 13 | if (err) t.fail(err); 14 | vm.runInNewContext(src, { 15 | console: { log: log } 16 | }); 17 | }); 18 | 19 | function log (msg) { 20 | t.equal(msg, 555); 21 | } 22 | }); 23 | } 24 | 25 | bundle('/../example/foo.coffee'); 26 | bundle('/../example/foo.litcoffee'); 27 | -------------------------------------------------------------------------------- /test/cjsx.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | var browserify = require('browserify'); 3 | var vm = require('vm'); 4 | var fs = require('fs'); 5 | 6 | function bundle (file, opts) { 7 | test('bundle transform', function (t) { 8 | t.plan(1); 9 | 10 | var b = browserify({extensions: ['.coffee', '.cjsx']}); 11 | b.add(__dirname + file); 12 | b.transform((opts||{}),__dirname + '/..'); 13 | b.bundle(function (err, src) { 14 | if (err) t.fail(err); 15 | vm.runInNewContext(src, { 16 | console: { log: log } 17 | }); 18 | }); 19 | 20 | function log (msg) { 21 | var expected = "

is this component rad? mos def

"; 22 | 23 | t.equal(JSON.stringify(msg), JSON.stringify(expected)); 24 | } 25 | }); 26 | } 27 | 28 | bundle('/../example/neat-ui.coffee'); 29 | -------------------------------------------------------------------------------- /test/error.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | var browserify = require('browserify'); 3 | var path = require('path'); 4 | var fs = require('fs'); 5 | 6 | var file = path.resolve(__dirname, '../example/error.coffee'); 7 | var multilineFile = path.resolve(__dirname, '../example/multiline_error.coffee'); 8 | var transform = path.join(__dirname, '..'); 9 | 10 | test('transform error', function (t) { 11 | t.plan(5); 12 | 13 | var b = browserify([file]); 14 | b.transform(transform); 15 | 16 | b.bundle(function (error) { 17 | t.ok(error !== undefined, "bundle should callback with an error"); 18 | t.ok(error.line !== undefined, "error.line should be defined"); 19 | t.ok(error.column !== undefined, "error.column should be defined"); 20 | t.equal(error.line, 5, "error should be on line 5"); 21 | t.equal(error.column, 15, "error should be on column 15"); 22 | }); 23 | }); 24 | 25 | test('multiline transform error', function (t) { 26 | t.plan(1); 27 | 28 | var b = browserify([multilineFile]); 29 | b.transform(transform); 30 | b.bundle(function (error) { 31 | t.ok(error !== undefined, "bundle should callback with an error"); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /test/transform.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | var fs = require('fs'); 3 | var path = require('path'); 4 | var through = require('through'); 5 | var convert = require('convert-source-map'); 6 | var transform = require('..'); 7 | 8 | test('transform adds sourcemap comment', function (t) { 9 | t.plan(1); 10 | var data = ''; 11 | 12 | var file = path.join(__dirname, '../example/foo.coffee') 13 | fs.createReadStream(file) 14 | .pipe(transform(file)) 15 | .pipe(through(write, end)); 16 | 17 | function write (buf) { data += buf } 18 | function end () { 19 | var sourceMap = convert.fromSource(data).toObject(); 20 | 21 | t.deepEqual( 22 | sourceMap, 23 | { version: 3, 24 | file: file, 25 | sourceRoot: '', 26 | sources: [ file ], 27 | names: [], 28 | mappings: 'AAAA,OAAO,CAAC,GAAR,CAAY,OAAA,CAAQ,UAAR,CAAZ', 29 | sourcesContent: [ 'console.log(require \'./bar.js\')\n' ] }, 30 | 'adds sourcemap comment including original source' 31 | ); 32 | } 33 | }); 34 | -------------------------------------------------------------------------------- /update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | git pull origin master 4 | DEPENDENCY="coffee-react" 5 | VERSION=`npm view ${DEPENDENCY} version` 6 | echo "updating to $VERSION" 7 | npm install --save "${DEPENDENCY}@${VERSION}" 8 | npm test 9 | git add ./package.json 10 | git commit -m "updated ${DEPENDENCY} to v${VERSION}" 11 | npm version $VERSION 12 | read -p "will publish $VERSION. are you sure? " -n 1 -r 13 | echo 14 | if [[ $REPLY =~ ^[Yy]$ ]] 15 | then 16 | git push origin master 17 | npm publish . 18 | fi --------------------------------------------------------------------------------