diff --git a/packages/babel-plugin-react-server/.babelrc b/packages/babel-plugin-react-server/.babelrc new file mode 100644 index 000000000..eaf32387b --- /dev/null +++ b/packages/babel-plugin-react-server/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["es2015", "stage-0"] +} diff --git a/packages/babel-plugin-react-server/.gitignore b/packages/babel-plugin-react-server/.gitignore new file mode 100644 index 000000000..45f722230 --- /dev/null +++ b/packages/babel-plugin-react-server/.gitignore @@ -0,0 +1,3 @@ +node_modules +*.log +lib diff --git a/packages/babel-plugin-react-server/.npmignore b/packages/babel-plugin-react-server/.npmignore new file mode 100644 index 000000000..cace0d6dd --- /dev/null +++ b/packages/babel-plugin-react-server/.npmignore @@ -0,0 +1,3 @@ +node_modules +*.log +src diff --git a/packages/babel-plugin-react-server/README.md b/packages/babel-plugin-react-server/README.md new file mode 100644 index 000000000..765ded6e6 --- /dev/null +++ b/packages/babel-plugin-react-server/README.md @@ -0,0 +1,90 @@ +# babel-plugin-react-server + +React Server transpilation + +## Example + +**In** + +```js +var logger = require('react-server').logging.getLogger(__LOGGER__); +``` + +**Out** + +```js +"use strict"; + +var logger = require('react-server').logging.getLogger({ name: 'module.name', color: {} }); +``` + +## Installation + +```sh +$ npm install babel-plugin-react-server +``` + +## Usage + +### Via `.babelrc` (Recommended) + +**.babelrc** + +```json +{ + "plugins": ["react-server"] +} +``` + +### Via CLI + +```sh +$ babel --plugins react-server script.js +``` + +### Via Node API + +```javascript +require("babel-core").transform("code", { + plugins: ["react-server"] +}); +``` + + +## Configuration + +A fully configured babel plugin in your babelrc would look be + +```json +{ + "plugins": [ + ["react-server", { + "trim": "my-project.components.", + "token": "__LOGGER__" + }] + ] +} +``` + + +### Trim + +A substring to trim off the front of the module name + +```javascript +{ + trim: "my-project.pages." +} +``` + +### Token + +The token to replace in the source code with the module tag. By default, uses +the default logger token `__LOGGER__`, and two future reserved tokens, +`__CHANNEL__` and + +```javascript +{ + token: "__LOGGER__" +} +``` diff --git a/packages/babel-plugin-react-server/package.json b/packages/babel-plugin-react-server/package.json new file mode 100644 index 000000000..84a18e853 --- /dev/null +++ b/packages/babel-plugin-react-server/package.json @@ -0,0 +1,31 @@ +{ + "name": "babel-plugin-react-server", + "version": "0.0.1", + "description": "Babel plugin for React Server transpilation", + "repository": "redfin/babel-plugin-react-server", + "author": "Doug Wade ", + "main": "lib/index.js", + "dependencies": { + "react-server-module-tagger": "^0.0.1" + }, + "devDependencies": { + "babel-core": "^6.3.17", + "babel-preset-es2015": "^6.3.13", + "babel-preset-stage-0": "^6.3.13", + "mocha": "^2.2.5" + }, + "scripts": { + "clean": "rm -rf lib npm-debug.log*", + "build": "babel src -d lib", + "test": "mocha --compilers js:babel-register", + "test:watch": "npm run test -- --watch", + "prepublish": "npm run clean && npm run build" + }, + "keywords": [ + "react", + "server", + "babel", + "plugin", + "babel-plugin" + ] +} diff --git a/packages/babel-plugin-react-server/src/index.js b/packages/babel-plugin-react-server/src/index.js new file mode 100644 index 000000000..9a96b8b38 --- /dev/null +++ b/packages/babel-plugin-react-server/src/index.js @@ -0,0 +1,34 @@ +import loggerSpec from 'react-server-module-tagger'; +import path from 'path'; + +module.exports = function({types: t }) { + return { + visitor: { + Identifier(p, state) { + const {node} = p; + const {name, type} = node; + + const config = { trim: state.opts.trim }; + const parent = path.resolve(path.join(process.cwd(), '..')) + path.sep; + const fp = this.file.opts.filename.replace(parent, ''); + const file = { path: fp }; + //TODO: Support labels + const moduleTag = loggerSpec.bind({ file, config })(fp); + + let tokens; + if (state.opts.tokens) { + tokens = new Set(state.opts.tokens); + } else { + tokens = new Set(["__LOGGER__", "__CHANNEL__", "__CACHE__"]); + } + + if (tokens.has(name)) { + // this strikes me as a dirty, nasty hack. I think it would be better + // to parse the object as json and coerce it to an array of + // ObjectProperties to construct an ObjectExpression + p.node.name = moduleTag; + } + } + } + }; +} diff --git a/packages/babel-plugin-react-server/test/fixtures/configurable-token/.babelrc b/packages/babel-plugin-react-server/test/fixtures/configurable-token/.babelrc new file mode 100644 index 000000000..b665985c3 --- /dev/null +++ b/packages/babel-plugin-react-server/test/fixtures/configurable-token/.babelrc @@ -0,0 +1,5 @@ +{ + "plugins": [ + ["../../../src", { "tokens": ["BAR"] }] + ] +} diff --git a/packages/babel-plugin-react-server/test/fixtures/configurable-token/actual.js b/packages/babel-plugin-react-server/test/fixtures/configurable-token/actual.js new file mode 100644 index 000000000..b79db47ce --- /dev/null +++ b/packages/babel-plugin-react-server/test/fixtures/configurable-token/actual.js @@ -0,0 +1 @@ +var logger = require('react-server').logging.getLogger(BAR); diff --git a/packages/babel-plugin-react-server/test/fixtures/configurable-token/expected.js b/packages/babel-plugin-react-server/test/fixtures/configurable-token/expected.js new file mode 100644 index 000000000..ad5807635 --- /dev/null +++ b/packages/babel-plugin-react-server/test/fixtures/configurable-token/expected.js @@ -0,0 +1 @@ +var logger = require('react-server').logging.getLogger({"name":"babel-plugin-react-server.test.fixtures.configurable-token.actual","color":{"server":133,"client":"rgb(127,42,127)"}}); diff --git a/packages/babel-plugin-react-server/test/fixtures/example/.babelrc b/packages/babel-plugin-react-server/test/fixtures/example/.babelrc new file mode 100644 index 000000000..e624888ed --- /dev/null +++ b/packages/babel-plugin-react-server/test/fixtures/example/.babelrc @@ -0,0 +1,5 @@ +{ + "plugins": [ + ["../../../src"] + ] +} diff --git a/packages/babel-plugin-react-server/test/fixtures/example/actual.js b/packages/babel-plugin-react-server/test/fixtures/example/actual.js new file mode 100644 index 000000000..861cdc1c7 --- /dev/null +++ b/packages/babel-plugin-react-server/test/fixtures/example/actual.js @@ -0,0 +1 @@ +var logger = require('react-server').logging.getLogger(__LOGGER__); diff --git a/packages/babel-plugin-react-server/test/fixtures/example/expected.js b/packages/babel-plugin-react-server/test/fixtures/example/expected.js new file mode 100644 index 000000000..1786e179c --- /dev/null +++ b/packages/babel-plugin-react-server/test/fixtures/example/expected.js @@ -0,0 +1 @@ +var logger = require('react-server').logging.getLogger({"name":"babel-plugin-react-server.test.fixtures.example.actual","color":{"server":131,"client":"rgb(127,42,42)"}}); diff --git a/packages/babel-plugin-react-server/test/fixtures/reserved-future-tokens/.babelrc b/packages/babel-plugin-react-server/test/fixtures/reserved-future-tokens/.babelrc new file mode 100644 index 000000000..e624888ed --- /dev/null +++ b/packages/babel-plugin-react-server/test/fixtures/reserved-future-tokens/.babelrc @@ -0,0 +1,5 @@ +{ + "plugins": [ + ["../../../src"] + ] +} diff --git a/packages/babel-plugin-react-server/test/fixtures/reserved-future-tokens/actual.js b/packages/babel-plugin-react-server/test/fixtures/reserved-future-tokens/actual.js new file mode 100644 index 000000000..4d86c7533 --- /dev/null +++ b/packages/babel-plugin-react-server/test/fixtures/reserved-future-tokens/actual.js @@ -0,0 +1,2 @@ +__CHANNEL__ +__CACHE__ diff --git a/packages/babel-plugin-react-server/test/fixtures/reserved-future-tokens/expected.js b/packages/babel-plugin-react-server/test/fixtures/reserved-future-tokens/expected.js new file mode 100644 index 000000000..93c600a0b --- /dev/null +++ b/packages/babel-plugin-react-server/test/fixtures/reserved-future-tokens/expected.js @@ -0,0 +1,2 @@ +{"name":"babel-plugin-react-server.test.fixtures.reserved-future-tokens.actual","color":{"server":159,"client":"rgb(127,212,212)"}}; +{"name":"babel-plugin-react-server.test.fixtures.reserved-future-tokens.actual","color":{"server":159,"client":"rgb(127,212,212)"}}; diff --git a/packages/babel-plugin-react-server/test/fixtures/trim/.babelrc b/packages/babel-plugin-react-server/test/fixtures/trim/.babelrc new file mode 100644 index 000000000..d6b576f6a --- /dev/null +++ b/packages/babel-plugin-react-server/test/fixtures/trim/.babelrc @@ -0,0 +1,5 @@ +{ + "plugins": [ + ["../../../src", { "trim": "babel-plugin-react-server.test.fixtures." }] + ] +} diff --git a/packages/babel-plugin-react-server/test/fixtures/trim/actual.js b/packages/babel-plugin-react-server/test/fixtures/trim/actual.js new file mode 100644 index 000000000..861cdc1c7 --- /dev/null +++ b/packages/babel-plugin-react-server/test/fixtures/trim/actual.js @@ -0,0 +1 @@ +var logger = require('react-server').logging.getLogger(__LOGGER__); diff --git a/packages/babel-plugin-react-server/test/fixtures/trim/expected.js b/packages/babel-plugin-react-server/test/fixtures/trim/expected.js new file mode 100644 index 000000000..7e6a51df3 --- /dev/null +++ b/packages/babel-plugin-react-server/test/fixtures/trim/expected.js @@ -0,0 +1 @@ +var logger = require('react-server').logging.getLogger({"name":"trim.actual","color":{"server":207,"client":"rgb(212,42,212)"}}); diff --git a/packages/babel-plugin-react-server/test/index.js b/packages/babel-plugin-react-server/test/index.js new file mode 100644 index 000000000..9ee8d81b9 --- /dev/null +++ b/packages/babel-plugin-react-server/test/index.js @@ -0,0 +1,26 @@ +import path from 'path'; +import fs from 'fs'; +import assert from 'assert'; +import { transformFileSync } from 'babel-core'; +import plugin from '../src'; + +function trim(str) { + return str.replace(/^\s+|\s+$/, ''); +} + +describe('React Server transpilation', () => { + const fixturesDir = path.join(__dirname, 'fixtures'); + fs.readdirSync(fixturesDir).map((caseName) => { + it(`should ${caseName.split('-').join(' ')}`, () => { + const fixtureDir = path.join(fixturesDir, caseName); + const actualPath = path.join(fixtureDir, 'actual.js'); + const actual = transformFileSync(actualPath).code; + + const expected = fs.readFileSync( + path.join(fixtureDir, 'expected.js') + ).toString(); + + assert.equal(trim(actual), trim(expected)); + }); + }); +}); diff --git a/packages/babel-preset-react-server/index.js b/packages/babel-preset-react-server/index.js index e75605d2f..d306467c1 100644 --- a/packages/babel-preset-react-server/index.js +++ b/packages/babel-preset-react-server/index.js @@ -1,19 +1,11 @@ module.exports = { plugins: [ - require('babel-plugin-transform-es2015-arrow-functions'), - require('babel-plugin-transform-es2015-block-scoping'), - require('babel-plugin-transform-es2015-classes'), - require('babel-plugin-transform-es2015-computed-properties'), - require('babel-plugin-transform-es2015-constants'), - require('babel-plugin-transform-es2015-destructuring'), - require('babel-plugin-transform-es2015-modules-commonjs'), - require('babel-plugin-transform-es2015-parameters'), - require('babel-plugin-transform-es2015-shorthand-properties'), - require('babel-plugin-transform-es2015-spread'), - require('babel-plugin-transform-es2015-template-literals'), - require('babel-plugin-transform-object-rest-spread'), + require('babel-plugin-react-server'), + require('babel-plugin-transform-runtime'), ], presets: [ + require('babel-preset-es2015'), require('babel-preset-react'), + require('babel-preset-stage-0'), ], } diff --git a/packages/babel-preset-react-server/package.json b/packages/babel-preset-react-server/package.json index 703d9c8d3..10789a263 100644 --- a/packages/babel-preset-react-server/package.json +++ b/packages/babel-preset-react-server/package.json @@ -18,21 +18,15 @@ "author": "Doug Wade ", "license": "Apache License 2.0", "dependencies": { - "babel-plugin-transform-es2015-arrow-functions": "^6.3.13", - "babel-plugin-transform-es2015-block-scoping": "^6.3.13", - "babel-plugin-transform-es2015-classes": "^6.3.13", - "babel-plugin-transform-es2015-computed-properties": "^6.3.13", - "babel-plugin-transform-es2015-constants": "^6.1.4", - "babel-plugin-transform-es2015-destructuring": "^6.3.13", - "babel-plugin-transform-es2015-modules-commonjs": "^6.3.13", - "babel-plugin-transform-es2015-parameters": "^6.3.13", - "babel-plugin-transform-es2015-shorthand-properties": "^6.3.13", - "babel-plugin-transform-es2015-spread": "^6.3.13", - "babel-plugin-transform-es2015-template-literals": "^6.3.13", - "babel-plugin-transform-object-rest-spread": "^6.3.13", - "babel-preset-react": "^6.5.0" + "babel-plugin-transform-runtime": "^6.9.0", + "babel-plugin-react-server": "^0.0.1", + "babel-preset-es2015": "^6.5.0", + "babel-preset-react": "^6.5.0", + "babel-preset-stage-0": "^6.5.0" }, "devDependencies": { + "ava": "^0.15.2", + "babel-core": "^6.10.4", "rimraf": "^2.5.2" } } diff --git a/packages/babel-preset-react-server/test.js b/packages/babel-preset-react-server/test.js new file mode 100644 index 000000000..df93cdaea --- /dev/null +++ b/packages/babel-preset-react-server/test.js @@ -0,0 +1,37 @@ +import test from 'ava'; +import fs from 'fs'; +import { transform } from 'babel-core'; + +test('module can be required', t => { + try { + require('.'); + t.pass(); + } catch (e) { + console.error(e); + t.fail(); + } +}); + +test('transpiles as expected', async t => { + const source = await readFile('tst/source.js'); + const actual = transform(source, { presets: [require('.')] }).code; + const expected = await readFile('tst/expected.js'); + t.is(trim(actual), trim(expected)); +}); + +function readFile(filename) { + return new Promise((resolve, reject) => { + fs.readFile(filename, (err, data) => { + if (err) { + console.error(err); + reject(err); + } else { + resolve(data.toString()); + } + }); + }); +} + +function trim(str) { + return str.replace(/^\s+|\s+$/, ''); +} diff --git a/packages/babel-preset-react-server/tst/expected.js b/packages/babel-preset-react-server/tst/expected.js new file mode 100644 index 000000000..a262de628 --- /dev/null +++ b/packages/babel-preset-react-server/tst/expected.js @@ -0,0 +1,7 @@ +'use strict'; + +var _reactServer = require('react-server'); + +var label = 'foo'; +var logger = _reactServer.logging.getLogger({"name":"unknown","color":{"server":207,"client":"rgb(212,42,212)"}}); +var fooLogger = _reactServer.logging.getLogger({"name":"unknown","color":{"server":207,"client":"rgb(212,42,212)"}}({ label: label })); diff --git a/packages/babel-preset-react-server/tst/source.js b/packages/babel-preset-react-server/tst/source.js new file mode 100644 index 000000000..9217358d9 --- /dev/null +++ b/packages/babel-preset-react-server/tst/source.js @@ -0,0 +1,5 @@ +import {logging} from 'react-server'; + +const label = 'foo'; +const logger = logging.getLogger(__LOGGER__); +const fooLogger = logging.getLogger(__LOGGER__({ label }));