diff --git a/package.json b/package.json index c8daf33e..b2ad2c88 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,10 @@ "eslint-plugin-flowtype": "^2.25.0", "nyc": "^10.0.0", "rimraf": "^2.4.3", + "react": "^15.1.0", + "react-intl":"^2.1.2", + "babel-plugin-react-intl": "^2.1.3", + "react-intl-webpack-plugin":"^0.0.3", "webpack": "^2.2.0-rc" }, "scripts": { diff --git a/src/index.js b/src/index.js index 2d196abc..3b1c7e98 100644 --- a/src/index.js +++ b/src/index.js @@ -67,6 +67,7 @@ const transpile = function(source, options) { } const code = result.code; const map = result.map; + const metadata = result.metadata; if (map && (!map.sourcesContent || !map.sourcesContent.length)) { map.sourcesContent = [source]; @@ -77,9 +78,16 @@ const transpile = function(source, options) { return { code: code, map: map, + metadata: metadata, }; }; +function passMetadata(s, context, metadata) { + if (context[s]) { + context[s](metadata); + } +} + module.exports = function(source, inputSourceMap) { // Handle filenames (#106) const webpackRemainingChain = loaderUtils.getRemainingRequest(this).split("!"); @@ -90,6 +98,7 @@ module.exports = function(source, inputSourceMap) { const loaderOptions = loaderUtils.parseQuery(this.query); const userOptions = assign({}, globalOptions, loaderOptions); const defaultOptions = { + metadataSubscribers: [], inputSourceMap: inputSourceMap, sourceRoot: process.cwd(), filename: filename, @@ -118,11 +127,14 @@ module.exports = function(source, inputSourceMap) { const cacheDirectory = options.cacheDirectory; const cacheIdentifier = options.cacheIdentifier; + const metadataSubscribers = options.metadataSubscribers; delete options.cacheDirectory; delete options.cacheIdentifier; + delete options.metadataSubscribers; this.cacheable(); + const context = this; if (cacheDirectory) { const callback = this.async(); @@ -134,10 +146,16 @@ module.exports = function(source, inputSourceMap) { transform: transpile, }, function(err, result) { if (err) { return callback(err); } + metadataSubscribers.forEach(function (s) { + passMetadata(s, context, result.metadata); + }); return callback(null, result.code, result.map); }); } const result = transpile(source, options); + metadataSubscribers.forEach(function (s) { + passMetadata(s, context, result.metadata); + }); this.callback(null, result.code, result.map); }; diff --git a/test/fixtures/metadata.js b/test/fixtures/metadata.js new file mode 100644 index 00000000..bc093acb --- /dev/null +++ b/test/fixtures/metadata.js @@ -0,0 +1,15 @@ +import {defineMessages} from 'react-intl'; +class App { + constructor(arg='test') { + var m = defineMessages({ + greeting: { + id: 'greetingId', + defaultMessage: 'Hello World!' + }, + }); + + this.result = arg; + } +} + +export default App; diff --git a/test/fixtures/metadataErr.js b/test/fixtures/metadataErr.js new file mode 100644 index 00000000..1b05d3e0 --- /dev/null +++ b/test/fixtures/metadataErr.js @@ -0,0 +1,16 @@ +import {defineMessages} from 'react-intl'; +class App { + constructor(arg='test') { + var m = defineMessages({ + greeting: { + id: 'greetingId', + defaultMessage: 'Hello World!' + }, + }); + + bla bla + this.result = arg; + } +} + +export default App; diff --git a/test/metadata.test.js b/test/metadata.test.js new file mode 100644 index 00000000..80490460 --- /dev/null +++ b/test/metadata.test.js @@ -0,0 +1,154 @@ +import test from "ava"; +import fs from "fs"; +import path from "path"; +import assign from "object-assign"; +import rimraf from "rimraf"; +import webpack from "webpack"; +import createTestDirectory from "./helpers/createTestDirectory"; + +const ReactIntlPlugin = require("react-intl-webpack-plugin"); + +const cacheDir = path.join(__dirname, "output/cache/cachefiles"); +const outputDir = path.join(__dirname, "output/metadata"); +const babelLoader = path.join(__dirname, "../lib"); +const globalConfig = { + entry: "./test/fixtures/metadata.js", + output: { + path: outputDir, + filename: "[id].metadata.js", + }, + plugins: [new ReactIntlPlugin(), ], + module: { + loaders: [ + { + test: /\.jsx?/, + loader: babelLoader, + query: { + metadataSubscribers: [ReactIntlPlugin.metadataContextFunctionName], + plugins: [ + ["react-intl", { enforceDescriptions: false, }, ], + ], + presets: [], + }, + exclude: /node_modules/, + }, + ], + }, +}; + +// Create a separate directory for each test so that the tests +// can run in parallel +test.cb.beforeEach((t) => { + createTestDirectory(outputDir, t.title, (err, directory) => { + if (err) return t.end(err); + t.context.directory = directory; + t.end(); + }); +}); + +test.cb.afterEach((t) => rimraf(t.context.directory, t.end)); + + +test.cb("should pass metadata code snippet", (t) => { + const config = assign({}, globalConfig, { + output: { + path: t.context.directory, + filename: "[id].metadata.js", + }, + }); + + webpack(config, (err) => { + t.is(err, null); + + fs.readdir(t.context.directory, (err, files) => { + t.is(err, null); + t.true(files.length > 0); + fs.readFile(path.resolve(t.context.directory, "reactIntlMessages.json"), + function(err, data) { + t.is(err, null); + const text = data.toString(); + const jsonText = JSON.parse(text); + t.true(jsonText.length == 1); + t.true(jsonText[0].id == "greetingId"); + t.true(jsonText[0].defaultMessage == "Hello World!"); + t.end(); + }); + }); + }); +}); + +test.cb("should not throw error", (t) => { + const config = assign({}, globalConfig, { + output: { + path: t.context.directory, + filename: "[id].metadata.js", + }, + }); + + webpack(config, (err, stats) => { + t.is(err, null); + t.is(stats.compilation.errors.length, 0); + t.end(); + }); +}); + +test.cb("should throw error", (t) => { + const config = assign({}, globalConfig, { + output: { + path: t.context.directory, + filename: "[id].metadata.js", + }, + entry: "./test/fixtures/metadataErr.js", + }); + + webpack(config, (err, stats) => { + t.is(err, null); + t.true(stats.compilation.errors.length > 0); + t.end(); + }); +}); + +test.cb("should pass metadata code snippet ( cache version )", (t) => { + const config = assign({}, globalConfig, { + output: { + path: t.context.directory, + filename: "[id].metadata.js", + }, + module: { + loaders: [ + { + test: /\.jsx?/, + loader: babelLoader, + query: { + metadataSubscribers: [ReactIntlPlugin.metadataContextFunctionName], + plugins: [ + ["react-intl", { enforceDescriptions: false, }, ], + ], + cacheDirectory: cacheDir, + presets: [], + }, + exclude: /node_modules/, + }, + ], + }, + }); + + webpack(config, (err) => { + t.is(err, null); + + fs.readdir(t.context.directory, (err, files) => { + t.is(err, null); + t.true(files.length > 0); + fs.readFile(path.resolve(t.context.directory, "reactIntlMessages.json"), + function(err, data) { + t.is(err, null); + const text = data.toString(); + const jsonText = JSON.parse(text); + t.true(jsonText.length == 1); + t.true(jsonText[0].id == "greetingId"); + t.true(jsonText[0].defaultMessage == "Hello World!"); + t.end(); + }); + }); + }); +});