diff --git a/.gitignore b/.gitignore
index 5e5b5337d..25efed593 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,9 +8,6 @@ npm-debug.log
# code coverage
coverage
-# build
-lib
-
# tests results
**/__tests__/_output*
diff --git a/lib/Link/index.js b/lib/Link/index.js
new file mode 100644
index 000000000..02a1dfc2f
--- /dev/null
+++ b/lib/Link/index.js
@@ -0,0 +1,22 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.Link = undefined;
+
+var _chalk = require("chalk");
+
+var _chalk2 = _interopRequireDefault(_chalk);
+
+var _Link = require("../components/Link");
+
+var _Link2 = _interopRequireDefault(_Link);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+// deprecated
+console.log("⚠️ " + _chalk2.default.yellow("'phenomic/lib/Link' reference is deprecated.\n" + "Please use `import { Link } from \"phenomic\" instead`."));
+
+exports.Link = _Link2.default;
+exports.default = _Link2.default;
\ No newline at end of file
diff --git a/lib/PageContainer/index.js b/lib/PageContainer/index.js
new file mode 100644
index 000000000..cb1d1442c
--- /dev/null
+++ b/lib/PageContainer/index.js
@@ -0,0 +1,20 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _chalk = require("chalk");
+
+var _chalk2 = _interopRequireDefault(_chalk);
+
+var _PageContainer = require("../components/PageContainer");
+
+var _PageContainer2 = _interopRequireDefault(_PageContainer);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+// deprecated
+console.log("⚠️ " + _chalk2.default.yellow("'phenomic/lib/PageContainer' reference is deprecated.\n" + "Please use `import { PageContainer } from \"phenomic\" instead`."));
+
+exports.default = _PageContainer2.default;
\ No newline at end of file
diff --git a/lib/_utils/array-unique/index.js b/lib/_utils/array-unique/index.js
new file mode 100644
index 000000000..761103966
--- /dev/null
+++ b/lib/_utils/array-unique/index.js
@@ -0,0 +1,15 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
+
+// @ flow
+// flow is not enabled because of the issue with set and spread
+// https://github.com/facebook/flow/issues/1059
+
+exports.default = function (array) {
+ return [].concat(_toConsumableArray(new Set(array)));
+};
\ No newline at end of file
diff --git a/lib/_utils/beautify-html/index.js b/lib/_utils/beautify-html/index.js
new file mode 100644
index 000000000..38e975c1d
--- /dev/null
+++ b/lib/_utils/beautify-html/index.js
@@ -0,0 +1,13 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _jsBeautify = require("js-beautify");
+
+exports.default = function (html) {
+ return (0, _jsBeautify.html)(html, _extends({}, _jsBeautify.default_options, { indent_size: 2 }));
+};
\ No newline at end of file
diff --git a/lib/_utils/bins.js b/lib/_utils/bins.js
new file mode 100644
index 000000000..849cbba63
--- /dev/null
+++ b/lib/_utils/bins.js
@@ -0,0 +1,13 @@
+"use strict";
+
+// ⚠️ Used in postinstall, so es6 - imports - not transpiled
+
+var resolve = require("path").resolve;
+
+var platformSuffix = process.platform === "win32" ? ".cmd" : "";
+
+module.exports = {
+ babelNode: resolve("./node_modules/.bin/babel-node" + platformSuffix),
+ npm: "npm" + platformSuffix,
+ yarn: "yarn" + platformSuffix
+};
\ No newline at end of file
diff --git a/lib/_utils/cache/webpack.js b/lib/_utils/cache/webpack.js
new file mode 100644
index 000000000..ddf8fa80e
--- /dev/null
+++ b/lib/_utils/cache/webpack.js
@@ -0,0 +1,43 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _path = require("path");
+
+var _hardSourceWebpackPlugin = require("hard-source-webpack-plugin");
+
+var _hardSourceWebpackPlugin2 = _interopRequireDefault(_hardSourceWebpackPlugin);
+
+var _nodeObjectHash = require("node-object-hash");
+
+var _nodeObjectHash2 = _interopRequireDefault(_nodeObjectHash);
+
+var _findCacheDir = require("find-cache-dir");
+
+var _findCacheDir2 = _interopRequireDefault(_findCacheDir);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = function (config) {
+ if (!config.cache) {
+ return [];
+ }
+
+ var cacheDir = (0, _findCacheDir2.default)({
+ name: "phenomic/webpack-hard-source-cache/[confighash]/"
+ });
+
+ return [new _hardSourceWebpackPlugin2.default({
+ cacheDirectory: (0, _path.join)(cacheDir),
+ recordsPath: (0, _path.join)(cacheDir, "records.json"),
+ configHash: function configHash(config) {
+ return new _nodeObjectHash2.default().hash(config);
+ },
+ environmentPaths: {
+ root: config.cwd,
+ files: ["package.json", "webpack.config.js"]
+ }
+ })];
+};
\ No newline at end of file
diff --git a/lib/_utils/catch-links/index.js b/lib/_utils/catch-links/index.js
new file mode 100644
index 000000000..80c8b2f69
--- /dev/null
+++ b/lib/_utils/catch-links/index.js
@@ -0,0 +1,63 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+exports.default = function (elements, cb) {
+ var eventCallback = catchLinks(cb);
+ elements.map(function (el) {
+ return el.addEventListener("click", eventCallback);
+ });
+
+ return function () {
+ elements.map(function (el) {
+ return el.removeEventListener("click", eventCallback);
+ });
+ };
+};
+
+var _url = require("url");
+
+var _url2 = _interopRequireDefault(_url);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var catchLinks = function catchLinks(cb) {
+ return function (ev) {
+ if (ev.altKey || ev.ctrlKey || ev.metaKey || ev.shiftKey || ev.defaultPrevented) {
+ return;
+ }
+
+ var anchor = null;
+ for (var n = ev.target; n.parentNode; n = n.parentNode) {
+ if (n.nodeName === "A") {
+ anchor = n;
+ break;
+ }
+ }
+ if (!anchor) {
+ return;
+ }
+ var href = anchor.getAttribute("href");
+
+ // Don't intercerpt anchor
+ if (!href || href.startsWith("#")) {
+ return;
+ }
+
+ var u = _url2.default.parse(href);
+
+ if (u.host && u.host !== window.location.host) {
+ return;
+ }
+
+ var finalUrl = _url2.default.resolve(window.location.pathname, u.path || "") + (u.hash || "");
+
+ if (!cb(finalUrl)) {
+ return;
+ }
+
+ ev.preventDefault();
+ };
+};
\ No newline at end of file
diff --git a/lib/_utils/error-formatter/index.js b/lib/_utils/error-formatter/index.js
new file mode 100644
index 000000000..77bcdbfcc
--- /dev/null
+++ b/lib/_utils/error-formatter/index.js
@@ -0,0 +1,71 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.help = exports.cwd = undefined;
+
+var _os = require("os");
+
+var _os2 = _interopRequireDefault(_os);
+
+var _path = require("path");
+
+var _path2 = _interopRequireDefault(_path);
+
+var _chalk = require("chalk");
+
+var _chalk2 = _interopRequireDefault(_chalk);
+
+var _multili = require("multili");
+
+var _multili2 = _interopRequireDefault(_multili);
+
+var _configNode = require("../../builder/webpack/config.node.js");
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var normalizeWinPath = function normalizeWinPath(path) {
+ return path.replace(/\\/g, "\\\\");
+};
+
+var cwd = exports.cwd = normalizeWinPath(process.cwd());
+var cache = normalizeWinPath(_configNode.cacheDir);
+
+var reSep = normalizeWinPath(_path2.default.sep);
+var webpackNodeModulesRE = new RegExp("webpack:" + reSep + reSep + "?~", "gm");
+var cleanStaticBuildPathRE = new RegExp(cache + reSep, "gm");
+var cwdRE = new RegExp(cwd + reSep, "g");
+var homeRE = new RegExp(_os2.default.homedir(), "g");
+
+var cleanPaths = function cleanPaths(string) {
+ return string
+ // normalize windows path
+ .replace(/\\+g/, "/")
+ // cleanup
+ .replace(cleanStaticBuildPathRE, "").replace(webpackNodeModulesRE, "node_modules").replace(cwdRE, "").replace(homeRE, "~");
+};
+
+var notDefinedRE = /\s+(.*)( is not defined.*)/gm;
+var help = exports.help = _chalk2.default.yellow("\n\n" + "If you are seeing this message during the static build, that means you are" + "probably using an API only available in the browser (such as 'window', " + "'document', 'Element'...). Note that a module can be responsible for this." + "\n" + "In order to prevent this error, you can simply avoid calling the code " + "responsible when the dependency is not available. " + "\n\n" + "Examples:\n" +
+/* eslint-disable max-len */
+(0, _multili2.default)("\nFor a single API:\n\n const element = (typeof document !== \"undefined\") ? document.querySelector(\".something\") : null\n\n if (element) {\n // do your thing with your element\n }\n\nFor a module:\n\n const clipboard = (typeof window !== \"undefined\") ? require(\"clipboard\") : null\n\n // then later\n\n if (clipboard) {\n // do your thing using the module\n }\n ")
+/* eslint-enable max-len */
+);
+var enhanceError = function enhanceError(error) {
+ if (error.message.match(notDefinedRE) || error.stack.match(notDefinedRE)) {
+ error.stack += help;
+ }
+};
+
+exports.default = function (error) {
+ error.message = "\n\n" + _chalk2.default.red(error.message) + "\n";
+
+ // sometimes paths are in message
+ // eg: errors thrown by webpack loaders/plugin
+ error.message = cleanPaths(error.message);
+ error.stack = cleanPaths(error.stack);
+ enhanceError(error);
+
+ return error;
+};
\ No newline at end of file
diff --git a/lib/_utils/jsdom/index.js b/lib/_utils/jsdom/index.js
new file mode 100644
index 000000000..5e081ce73
--- /dev/null
+++ b/lib/_utils/jsdom/index.js
@@ -0,0 +1,30 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+exports.default = function (url) {
+ global.document = _jsdom2.default.jsdom("
", {
+ url: url
+ });
+ global.window = document.defaultView;
+ global.navigator = window.navigator;
+ window.localStorage = window.sessionStorage = {
+ getItem: function getItem(key) {
+ return this[key];
+ },
+ setItem: function setItem(key, value) {
+ this[key] = value;
+ },
+ removeItem: function removeItem(key) {
+ delete this[key];
+ }
+ };
+};
+
+var _jsdom = require("jsdom");
+
+var _jsdom2 = _interopRequireDefault(_jsdom);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
\ No newline at end of file
diff --git a/lib/_utils/log/index.js b/lib/_utils/log/index.js
new file mode 100644
index 000000000..c5e0620dc
--- /dev/null
+++ b/lib/_utils/log/index.js
@@ -0,0 +1,105 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.plainLog = exports.totalElapsedTime = exports.elapsedTime = exports.formatTime = exports.setTime = exports.setStartTime = exports.start = undefined;
+
+var _chalk = require("chalk");
+
+var _chalk2 = _interopRequireDefault(_chalk);
+
+var _logSymbols = require("log-symbols");
+
+var _logSymbols2 = _interopRequireDefault(_logSymbols);
+
+var _ora = require("ora");
+
+var _ora2 = _interopRequireDefault(_ora);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var symbolOrSuccess = function symbolOrSuccess(symbol) {
+ return _logSymbols2.default[symbol ? symbol : "success"];
+};
+
+// eslint-disable-next-line import/no-mutable-exports
+
+
+var start = exports.start = new Date();
+var lastTime = new Date();
+
+// for testing
+var setStartTime = exports.setStartTime = function setStartTime(t) {
+ exports.start = start = t;
+};
+var setTime = exports.setTime = function setTime(t) {
+ lastTime = t;
+};
+
+var formatTime = exports.formatTime = function formatTime(time) {
+ return Math.round(time * 100) / 100 + "s";
+};
+
+var elapsedTime = exports.elapsedTime = function elapsedTime() {
+ var now = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new Date();
+ var time = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : lastTime;
+
+ var diff = (now.getTime() - time.getTime()) / 1000;
+ lastTime = now;
+ if (diff < 0.1) {
+ return "";
+ }
+
+ var color = diff < 1 ? _chalk2.default.gray : _chalk2.default.blue;
+ return color("+" + formatTime(diff));
+};
+
+var totalElapsedTime = exports.totalElapsedTime = function totalElapsedTime() {
+ var now = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new Date();
+
+ return elapsedTime(now, start);
+};
+
+var plainLog = exports.plainLog = function plainLog(message) {
+ var symbol = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "info";
+
+ console.log(_logSymbols2.default[symbol], message);
+};
+
+exports.default = function (message, action) {
+ // the space is used to avoid shitty collapsed message from other modules
+ // that can happen during a loading...
+ var spinner = (0, _ora2.default)(message + " ");
+
+ if (action && action.then) {
+ spinner.start();
+ // $FlowFixMe when we use .start() above, flow miss the action.then test...
+ return action.then(function (res) {
+ spinner.text += elapsedTime();
+ spinner.succeed();
+ return res;
+ }, function (res) {
+ spinner.text += elapsedTime();
+ spinner.fail();
+ return res;
+ });
+ }
+ if (typeof action === "function") {
+ spinner.start();
+ try {
+ var res = action();
+ spinner.text += elapsedTime();
+ spinner.succeed();
+ return res;
+ } catch (e) {
+ spinner.text += elapsedTime();
+ spinner.fail();
+ throw e;
+ }
+ }
+
+ // else
+ spinner.text += elapsedTime();
+ spinner.stopAndPersist(symbolOrSuccess(action && String(action)));
+};
\ No newline at end of file
diff --git a/lib/_utils/normalize-base-url/index.js b/lib/_utils/normalize-base-url/index.js
new file mode 100644
index 000000000..59dc2bf57
--- /dev/null
+++ b/lib/_utils/normalize-base-url/index.js
@@ -0,0 +1,35 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _url = require("url");
+
+exports.default = function (baseUrl) {
+ // ensure trailing slash
+ if (baseUrl.pathname && !baseUrl.pathname.endsWith("/")) {
+ baseUrl.pathname = baseUrl.pathname + "/";
+ }
+
+ // update baseUrl.href since pathname has been updated
+ // the usage of the spread operator is to avoid having the "magic" Object
+ // returned by node (eg: make assertions difficult)
+ return _extends({}, (0, _url.parse)((0, _url.format)({
+ // baseUrl cannot just be passed directly
+ // https://github.com/facebook/flow/issues/908
+ href: baseUrl.href,
+ protocol: baseUrl.protocol,
+ slashes: baseUrl.slashes,
+ auth: baseUrl.auth,
+ hostname: baseUrl.hostname,
+ port: baseUrl.port,
+ host: baseUrl.host,
+ pathname: baseUrl.pathname,
+ search: baseUrl.search,
+ query: baseUrl.query,
+ hash: baseUrl.hash
+ })));
+};
\ No newline at end of file
diff --git a/lib/_utils/offline/runtime.js b/lib/_utils/offline/runtime.js
new file mode 100644
index 000000000..7127fe7e6
--- /dev/null
+++ b/lib/_utils/offline/runtime.js
@@ -0,0 +1,36 @@
+"use strict";
+
+var _runtime = require("offline-plugin/runtime");
+
+var _runtime2 = _interopRequireDefault(_runtime);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+console.log("SW Event:", "Installing");
+
+// Install ServiceWorker and AppCache in the end since it's not most important
+// operation and if main code fails, we do not want it installed
+
+_runtime2.default.install({
+ // you can specify here some code to respond to events
+ // see here for more informations
+ // https://www.npmjs.com/package/offline-plugin#runtime
+ onInstalled: function onInstalled() {
+ console.log("SW Event:", "onInstalled");
+ },
+ onUpdating: function onUpdating() {
+ console.log("SW Event:", "onUpdating");
+ },
+ onUpdateReady: function onUpdateReady() {
+ console.log("SW Event:", "onUpdateReady");
+ _runtime2.default.applyUpdate();
+ },
+ onUpdated: function onUpdated() {
+ console.log("SW Event:", "onUpdated");
+ window.location.reload();
+ },
+ onUninstalled: function onUninstalled() {
+ console.log("SW Event:", "onUninstalled");
+ }
+});
+// See webpack configuration file for more offline options
\ No newline at end of file
diff --git a/lib/_utils/offline/webpack.js b/lib/_utils/offline/webpack.js
new file mode 100644
index 000000000..82f6ce5c7
--- /dev/null
+++ b/lib/_utils/offline/webpack.js
@@ -0,0 +1,106 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.offlineEntry = exports.offlinePlugin = undefined;
+
+var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
+
+var _path = require("path");
+
+var _globby = require("globby");
+
+var _offlinePlugin = require("offline-plugin");
+
+var _offlinePlugin2 = _interopRequireDefault(_offlinePlugin);
+
+var _urlJoin = require("url-join");
+
+var _urlJoin2 = _interopRequireDefault(_urlJoin);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
+
+var runtimeEntry = (0, _path.resolve)(__dirname, "runtime.js");
+
+var offlinePlugin = exports.offlinePlugin = function offlinePlugin(config) {
+ if (!config.offline) {
+ return [];
+ }
+ var assets = [];
+
+ if (_typeof(config.assets) === "object") {
+ var configAssets = config.assets;
+
+ assets = (0, _globby.sync)(["**/*"], {
+ cwd: configAssets.path,
+ nodir: true
+ }).map(function (asset) {
+ return (0, _urlJoin2.default)(configAssets.route, asset);
+ });
+ }
+
+ function preparePatterns(patterns) {
+ if (!patterns) {
+ return [];
+ }
+
+ return patterns.reduce(function (acc, pattern) {
+ return pattern === ":assets:" ? [].concat(_toConsumableArray(acc), _toConsumableArray(assets)) : [].concat(_toConsumableArray(acc), [pattern]);
+ }, []);
+ }
+
+ return [new _offlinePlugin2.default({
+ publicPath: config.baseUrl.pathname,
+ relativePaths: false,
+ responseStrategy: "network-first",
+
+ // Use this option to explicitely cache files not generated by webpack
+ externals: ["/"].concat(_toConsumableArray(assets)),
+
+ // every webpack generated assets have hashes, so we can safely
+ // inform OfflinePlugin about that
+ safeToUseOptionalCaches: true,
+
+ caches: {
+ // `main` files will be loaded during SW install
+ main: preparePatterns(config.offlineConfig.cachePatterns.onInstall),
+
+ // `additional` files are loaded after main section
+ // and do not prevent SW to install.
+ additional: preparePatterns(config.offlineConfig.cachePatterns.afterInstall),
+
+ // `optional` files will be cached only when requested
+ optional: preparePatterns(config.offlineConfig.cachePatterns.onDemand)
+ },
+ // for more advanced usage, see documentation of the plugin
+ // https://github.com/NekR/offline-plugin/blob/master/docs/caches.md
+
+ excludes: config.offlineConfig.cachePatterns.excludes,
+
+ ServiceWorker: {
+ events: true,
+ navigateFallbackURL: "/"
+ },
+
+ // Appcache Fallback for browser that does not support Service Worker
+ // (eg: Safari, IE, Edge...)
+ AppCache: {
+ events: true,
+ FALLBACK: {
+ "/": "/index.html"
+ }
+ }
+
+ })];
+};
+
+var offlineEntry = exports.offlineEntry = function offlineEntry(config) {
+ if (!config.offline) {
+ return [];
+ }
+
+ return [runtimeEntry];
+};
\ No newline at end of file
diff --git a/lib/_utils/path-to-uri/index.js b/lib/_utils/path-to-uri/index.js
new file mode 100644
index 000000000..6e638c80c
--- /dev/null
+++ b/lib/_utils/path-to-uri/index.js
@@ -0,0 +1,16 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _path = require("path");
+
+/**
+ * Normalize path into uri
+ * Join, replace multiple / or \ to single /
+ */
+var pathToUri = function pathToUri() {
+ return _path.join.apply(undefined, arguments).replace(/(\/|\\)+/g, "/");
+};
+exports.default = pathToUri;
\ No newline at end of file
diff --git a/lib/_utils/serialize/index.js b/lib/_utils/serialize/index.js
new file mode 100644
index 000000000..3eedf88df
--- /dev/null
+++ b/lib/_utils/serialize/index.js
@@ -0,0 +1,9 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+exports.default = function (value) {
+ return JSON.stringify(value).replace(/\<\/script>/g, "<\\/script>");
+};
\ No newline at end of file
diff --git a/lib/_utils/urlify/index.js b/lib/_utils/urlify/index.js
new file mode 100644
index 000000000..e2301541f
--- /dev/null
+++ b/lib/_utils/urlify/index.js
@@ -0,0 +1,55 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.fileExtensionRE = undefined;
+exports.default = urlify;
+
+var _pathToUri = require("../path-to-uri");
+
+var _pathToUri2 = _interopRequireDefault(_pathToUri);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var fileExtensionRE = exports.fileExtensionRE = /\.html?$/;
+function urlify(string) {
+ var full = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
+
+ var hasExtension = string.match(fileExtensionRE);
+
+ var url = string;
+
+ // replace windows backslash by slash
+ // before playing more with the url
+ url = url.replace(/\\/g, "/");
+
+ url = url
+ // something-else.md => something-else
+ // something-else.markdown => something-else
+ .replace(/\.(md|markdown|txt|tex|textile|t2t|asciidoc|asc|adoc)$/, "")
+
+ // something/index.md => something
+ // something/index.markdown => something
+ .replace(/\bindex$/, "");
+
+ // if url is not and html file, we will tweak it a little bit depending on the
+ // length wanted (full url or folder url)
+ if (!hasExtension) {
+ if (full) {
+ // url without extension => folder => index.html
+ url = (0, _pathToUri2.default)(url, "index.html");
+ } else {
+ // url without extension => folder
+ if (url.length && !url.endsWith("/")) {
+ url += "/";
+ }
+ }
+ }
+ // else, url with a file extension, don't touch
+
+ // no relative url
+ url = url.replace(/^\.\//, "");
+
+ return url;
+}
\ No newline at end of file
diff --git a/lib/bin/check-engine.js b/lib/bin/check-engine.js
new file mode 100644
index 000000000..524932cad
--- /dev/null
+++ b/lib/bin/check-engine.js
@@ -0,0 +1,43 @@
+"use strict";
+
+var _child_process = require("child_process");
+
+var _semver = require("semver");
+
+var _semver2 = _interopRequireDefault(_semver);
+
+var _chalk = require("chalk");
+
+var _chalk2 = _interopRequireDefault(_chalk);
+
+var _bins = require("../_utils/bins.js");
+
+var _package = require("../../package.json");
+
+var _package2 = _interopRequireDefault(_package);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+module.exports = function (nodeVersion, npmVersion, yarnVersion) {
+ var requirements = _package2.default.engines;
+ nodeVersion = nodeVersion || process.version;
+
+ npmVersion = npmVersion || (0, _child_process.execSync)(_bins.npm + " --version").toString().trim();
+
+ try {
+ yarnVersion = yarnVersion !== undefined ? yarnVersion : (0, _child_process.execSync)(_bins.yarn + " --version").toString().trim();
+ } catch (e) {
+ // nothing, assuming yarn does not exist
+ }
+
+ if (!(_semver2.default.satisfies(nodeVersion, requirements.node) && (_semver2.default.satisfies(npmVersion, requirements.npm) || yarnVersion && _semver2.default.satisfies(yarnVersion, requirements.yarn)))) {
+ var errorMessage = _chalk2.default.yellow("\n⚠️ " + "Phenomic requires at least " + "node@" + requirements.node + " and " + "npm@" + requirements.npm + " (or yarn@" + requirements.yarn + ")" + "\n\n" + "Your node version is " + nodeVersion + (yarnVersion ? ", " : " and ") + "your npm version is " + npmVersion + (!yarnVersion ? "" : " and " + "your yarn version is " + yarnVersion) + "\n\n" + _chalk2.default.yellow("See 'Setup' instruction in documentation.") + " " + "https://phenomic.io/docs/setup/");
+
+ if (process.env.TESTING) {
+ throw new Error(errorMessage);
+ }
+
+ console.error(errorMessage);
+ process.exit(1);
+ }
+};
\ No newline at end of file
diff --git a/lib/bin/commands/setup/index.js b/lib/bin/commands/setup/index.js
new file mode 100644
index 000000000..c3584dbc5
--- /dev/null
+++ b/lib/bin/commands/setup/index.js
@@ -0,0 +1,136 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _path = require("path");
+
+var _chalk = require("chalk");
+
+var _chalk2 = _interopRequireDefault(_chalk);
+
+var _fsPromise = require("fs-promise");
+
+var _fsPromise2 = _interopRequireDefault(_fsPromise);
+
+var _globby = require("globby");
+
+var _globby2 = _interopRequireDefault(_globby);
+
+var _inquirer = require("inquirer");
+
+var _package = require("../../../../package.json");
+
+var _package2 = require("../../../../themes/phenomic-theme-base/package.json");
+
+var _package3 = _interopRequireDefault(_package2);
+
+var _log = require("../../../_utils/log");
+
+var _questions = require("./questions");
+
+var _questions2 = _interopRequireDefault(_questions);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
+
+function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
+
+var themePath = (0, _path.join)(__dirname, "../../../../themes/phenomic-theme-base");
+
+exports.default = function () {
+ var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(argv) {
+ var cwd, testMode, answers, name, homepage, twitter, repository, phenomic, devDependencies, pkg, files;
+ return regeneratorRuntime.wrap(function _callee$(_context) {
+ while (1) {
+ switch (_context.prev = _context.next) {
+ case 0:
+ cwd = process.cwd();
+ testMode = argv.test;
+
+
+ (0, _log.plainLog)("Note: All values can be adjusted later.");
+
+ _context.prev = 3;
+
+ if (!testMode) {
+ _context.next = 8;
+ break;
+ }
+
+ _context.t0 = _questions.defaultTestAnswers;
+ _context.next = 11;
+ break;
+
+ case 8:
+ _context.next = 10;
+ return (0, _inquirer.prompt)(_questions2.default);
+
+ case 10:
+ _context.t0 = _context.sent;
+
+ case 11:
+ answers = _context.t0;
+ name = answers.name, homepage = answers.homepage, twitter = answers.twitter, repository = answers.repository, phenomic = _objectWithoutProperties(answers, ["name", "homepage", "twitter", "repository"]);
+ devDependencies = _extends({}, _package3.default.devDependencies, !testMode && {
+ phenomic: "^" + _package.version
+ });
+ pkg = _extends({}, _package3.default, {
+ name: name,
+ homepage: homepage,
+ phenomic: phenomic,
+ twitter: twitter,
+ repository: repository,
+ devDependencies: devDependencies
+ });
+ _context.next = 17;
+ return _fsPromise2.default.writeJson((0, _path.join)(cwd, "package.json"), pkg);
+
+ case 17:
+ (0, _log.plainLog)("`package.json` generated");
+
+ files = _globby2.default.sync(["*",
+ // node_modules is excluded because can be present during tests
+ // (but will never be in public package)
+ "!node_modules",
+ // already generated
+ "!package.json",
+ // we assume it's up to the user
+ "!yarn.lock"], { dot: true, cwd: themePath });
+ _context.next = 21;
+ return Promise.all(files.map(function (file) {
+ return _fsPromise2.default.copy((0, _path.join)(themePath, file), (0, _path.join)(cwd, file));
+ }));
+
+ case 21:
+ (0, _log.plainLog)("Base theme installed");
+
+ (0, _log.plainLog)("Project ready. Only one `npm install` and you are good to go!", "success");
+ _context.next = 29;
+ break;
+
+ case 25:
+ _context.prev = 25;
+ _context.t1 = _context["catch"](3);
+
+ console.error(_chalk2.default.red(_context.t1));
+ process.exit(1);
+
+ case 29:
+ case "end":
+ return _context.stop();
+ }
+ }
+ }, _callee, this, [[3, 25]]);
+ }));
+
+ function setup(_x) {
+ return _ref.apply(this, arguments);
+ }
+
+ return setup;
+}();
\ No newline at end of file
diff --git a/lib/bin/commands/setup/questions.js b/lib/bin/commands/setup/questions.js
new file mode 100644
index 000000000..8abb54241
--- /dev/null
+++ b/lib/bin/commands/setup/questions.js
@@ -0,0 +1,72 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.defaultTestAnswers = undefined;
+
+var _validUrl = require("valid-url");
+
+var _validUrl2 = _interopRequireDefault(_validUrl);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var defaultTestAnswers = exports.defaultTestAnswers = {
+ name: "phenomic-theme-base",
+ homepage: "https://phenomic.io/themes/base/demo",
+ twitter: "Phenomic_app",
+ repository: "https://github.com/MoOx/phenomic",
+ CNAME: false
+};
+
+var packageJsonNameRE = /^[a-zA-Z0-9\-]+$/;
+var twitterRE = /^[a-zA-Z0-9\-_]+$/;
+
+var questions = [{
+ type: "input",
+ name: "name",
+ message: "Dashed name of your project (eg: my-project)",
+ validate: function validate(value) {
+ if (packageJsonNameRE.test(value)) {
+ return true;
+ }
+ return "Only letters, numbers and dashes are allowed.";
+ }
+}, {
+ type: "input",
+ name: "homepage",
+ message: "Website url (eg: http://abc.xyz/)",
+ validate: function validate(value) {
+ if (_validUrl2.default.isWebUri(value)) {
+ return true;
+ }
+ return "Please provide a valid url";
+ }
+}, {
+ type: "input",
+ name: "repository",
+ message: "Repository url" + " (eg: https://github.com/MoOx/phenomic.git, optional)",
+ validate: function validate(value) {
+ if (value === "" || _validUrl2.default.isWebUri(value)) {
+ return true;
+ }
+ return "Please provide a valid url for repository";
+ }
+}, {
+ type: "input",
+ name: "twitter",
+ message: "Twitter nickname (eg: MoOx, optional)",
+ validate: function validate(value) {
+ if (value === "" || twitterRE.test(value)) {
+ return true;
+ }
+ return "Only letters, numbers, dashes & underscores are allowed.";
+ }
+}, {
+ type: "confirm",
+ name: "CNAME",
+ message: "Do you want a CNAME file (eg: for GitHub Pages)?",
+ default: false
+}];
+
+exports.default = questions;
\ No newline at end of file
diff --git a/lib/bin/index.js b/lib/bin/index.js
new file mode 100755
index 000000000..df1be1040
--- /dev/null
+++ b/lib/bin/index.js
@@ -0,0 +1,11 @@
+#!/usr/bin/env node
+"use strict";
+
+require("babel-register")();
+
+// Check for node and npm version
+// If it doesn't sastify the requirements
+// The process will exits immediately
+require("./check-engine")();
+
+require("./phenomic.js");
\ No newline at end of file
diff --git a/lib/bin/phenomic.js b/lib/bin/phenomic.js
new file mode 100644
index 000000000..205033d5d
--- /dev/null
+++ b/lib/bin/phenomic.js
@@ -0,0 +1,75 @@
+"use strict";
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+require("babel-polyfill");
+
+var _path = require("path");
+
+var _yargs = require("../configurator/yargs.js");
+
+var _yargs2 = _interopRequireDefault(_yargs);
+
+var _index = require("../configurator/index.js");
+
+var _index2 = _interopRequireDefault(_index);
+
+var _log = require("../_utils/log");
+
+var _log2 = _interopRequireDefault(_log);
+
+var _index3 = require("./commands/setup/index.js");
+
+var _index4 = _interopRequireDefault(_index3);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var runner = function runner() {
+ (0, _log2.default)("Phenomic is starting", "info");
+ var cwd = process.cwd();
+ var pkg = require((0, _path.join)(cwd, "package.json"));
+ var config = (0, _index2.default)({ argv: process.argv, pkg: pkg });
+
+ // lazyload builder to avoid issue when webpack is no installed yet
+ // @todo move runner() out of this file so setup can work without
+ // lazyloading via "require()"
+ var builder = require("../builder/index.js").default;
+ builder(config);
+};
+
+var startAndBuildOptions = {
+ "webpack-config": {
+ type: "string",
+ describe: "Webpack config (must export a function)",
+ default: "webpack.config.js"
+ },
+ "script-browser": {
+ type: "string",
+ describe: "Phenomic entry point (browser)",
+ default: (0, _path.join)("scripts", "phenomic.browser.js")
+ },
+ "script-node": {
+ type: "string",
+ describe: "Phenomic entry point (node)",
+ default: (0, _path.join)("scripts", "phenomic.node.js")
+ }
+};
+
+_yargs2.default.command("setup", "setup a project", {
+ test: {
+ describe: "Test mode (don't use this option)."
+ }
+}, _index4.default);
+
+_yargs2.default.command("start", "start your project (server / development mode)", _extends({}, startAndBuildOptions, {
+ dev: { default: true },
+ server: { default: true },
+ open: { default: true }
+}), runner);
+
+_yargs2.default.command("build", "build your project (static / production mode)", _extends({}, startAndBuildOptions, {
+ production: { default: true },
+ static: { default: true }
+}), runner);
+
+_yargs2.default.parse(process.argv);
\ No newline at end of file
diff --git a/lib/builder/dynamic-require.js b/lib/builder/dynamic-require.js
new file mode 100644
index 000000000..5709add0e
--- /dev/null
+++ b/lib/builder/dynamic-require.js
@@ -0,0 +1,10 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+// @ flow
+// flow does not like require(var), so I am just doing this ugly trick to skip
+// flow warning.
+
+exports.default = require;
\ No newline at end of file
diff --git a/lib/builder/index.js b/lib/builder/index.js
new file mode 100644
index 000000000..4e4596e25
--- /dev/null
+++ b/lib/builder/index.js
@@ -0,0 +1,147 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+// module.exports is used
+// eslint-disable-next-line import/default
+
+
+exports.default = function (config) {
+ // log(JSON.stringify(config, null, 2))
+
+ var makeWebpackConfigModule = (0, _dynamicRequire2.default)((0, _path.join)(config.cwd, config["webpackConfig"]));
+ var makeWebpackConfig = typeof makeWebpackConfigModule.default === "function" ? makeWebpackConfigModule.default
+ // : makeWebpackConfigModule
+ // @todo remove block below and uncomment line above
+ : typeof makeWebpackConfigModule === "function" ? makeWebpackConfigModule
+ // deprecated
+ : makeWebpackConfigModule.makeConfig;
+
+ // deprecated
+ if (makeWebpackConfigModule.makeConfig) {
+ (0, _log2.default)("Your webpack config should now directly export a function.\n" + "No need to export a makeConfig() function anymore as webpack@2 " + "natively support a function. " + "(makeConfig() is currently deprecated and support will be remove in a " + "futur release). ", "warning");
+ }
+
+ if (typeof makeWebpackConfig !== "function") {
+ throw new Error("Your webpack config must export a function. " + "This function will be called with a single argument " + "(Phenomic configuration object) and must return a valid webpack config.");
+ }
+
+ config.webpackConfig = makeWebpackConfig(config);
+ config.webpackConfigBrowser = (0, _configBrowser2.default)(config);
+ config.webpackConfigNode = (0, _configNode2.default)(config);
+
+ var destination = (0, _path.join)(config.cwd, config.destination);
+ _fsExtra2.default.emptyDirSync(destination);
+
+ process.env.BABEL_ENV = "webpack-" + (process.env.NODE_ENV || "development");
+
+ if (config.static) {
+ // Copy static assets to build folder
+ if (config.assets) {
+ (0, _log2.default)("Copying assets", function () {
+ var copyDest = (0, _path.join)(destination, config.assets.route);
+ _fsExtra2.default.copySync(config.assets.path, copyDest);
+ });
+ }
+
+ var webpackPromise = function webpackPromise(webpackConfig) {
+ return new Promise(function (resolve, reject) {
+ try {
+ (0, _webpack2.default)(webpackConfig, _log2.default, resolve);
+ } catch (e) {
+ reject(e);
+ }
+ });
+ };
+
+ (0, _log2.default)("Building client files", webpackPromise(config.webpackConfigBrowser)).then(function (clientBundleStats) {
+ // Sometimes, webpack does not throw an error, but send it in the
+ // callback... PRETTY WEIRD RIGHT?
+ // https://github.com/webpack/webpack/issues/2217#issuecomment-249364851
+ if (clientBundleStats instanceof Error) {
+ throw clientBundleStats;
+ }
+ return (0, _log2.default)("Preparing static build", webpackPromise(config.webpackConfigNode)).then(function () {
+ return clientBundleStats;
+ });
+ }).then(function (clientBundleStats) {
+ return (0, _log2.default)("Building static files", function () {
+ var staticBuild = (0, _dynamicRequire2.default)((0, _path.join)(config.webpackConfigNode.output.path, config.webpackConfigNode.output.filename));
+ // transpilation shit
+ // https://github.com/webpack/webpack/issues/4039
+ return (typeof staticBuild.default === "function" ? staticBuild.default : staticBuild)(_extends({}, config, {
+ collection: _plugin2.default.collection,
+ assetsFiles: (0, _sortAssets2.default)(clientBundleStats.toJson().assetsByChunkName)
+ }));
+ });
+ }).then(function (files) {
+ return (0, _postBuild2.default)(config, files);
+ }).then(function () {
+ return config.server && (0, _server2.default)(config);
+ }).catch(function (err) {
+ (0, _log2.default)(_chalk2.default.red("Build failed"), "error");
+ setTimeout(function () {
+ throw (0, _errorFormatter2.default)(err);
+ }, 1);
+ });
+ } else if (config.server) {
+ (0, _server2.default)(config);
+ } else {
+ throw new Error(_chalk2.default.red("phenomic: CLI needs --static or --server"));
+ }
+};
+
+var _path = require("path");
+
+var _fsExtra = require("fs-extra");
+
+var _fsExtra2 = _interopRequireDefault(_fsExtra);
+
+var _chalk = require("chalk");
+
+var _chalk2 = _interopRequireDefault(_chalk);
+
+var _log = require("../_utils/log");
+
+var _log2 = _interopRequireDefault(_log);
+
+var _errorFormatter = require("../_utils/error-formatter");
+
+var _errorFormatter2 = _interopRequireDefault(_errorFormatter);
+
+var _plugin = require("../loader/plugin.js");
+
+var _plugin2 = _interopRequireDefault(_plugin);
+
+var _webpack = require("./webpack");
+
+var _webpack2 = _interopRequireDefault(_webpack);
+
+var _sortAssets = require("./webpack/sortAssets.js");
+
+var _sortAssets2 = _interopRequireDefault(_sortAssets);
+
+var _server = require("./server.js");
+
+var _server2 = _interopRequireDefault(_server);
+
+var _postBuild = require("./post-build.js");
+
+var _postBuild2 = _interopRequireDefault(_postBuild);
+
+var _configBrowser = require("./webpack/config.browser.js");
+
+var _configBrowser2 = _interopRequireDefault(_configBrowser);
+
+var _configNode = require("./webpack/config.node.js");
+
+var _configNode2 = _interopRequireDefault(_configNode);
+
+var _dynamicRequire = require("./dynamic-require.js");
+
+var _dynamicRequire2 = _interopRequireDefault(_dynamicRequire);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
\ No newline at end of file
diff --git a/lib/builder/openChrome.applescript b/lib/builder/openChrome.applescript
new file mode 100644
index 000000000..64b1033be
--- /dev/null
+++ b/lib/builder/openChrome.applescript
@@ -0,0 +1,45 @@
+(*
+Ripped from https://gist.github.com/mayoff/1138816
+*)
+
+on run argv
+ set theURL to item 1 of argv
+
+ tell application "Chrome"
+
+ if (count every window) = 0 then
+ make new window
+ end if
+
+ -- Find a tab currently running the debugger
+ set found to false
+ set theTabIndex to -1
+ repeat with theWindow in every window
+ set theTabIndex to 0
+ repeat with theTab in every tab of theWindow
+ set theTabIndex to theTabIndex + 1
+ # found url from the same path, not only exact urls
+ # if theTab's URL is theURL then
+ if theTab's URL contains theURL then
+ set found to true
+ exit repeat
+ end if
+ end repeat
+
+ if found then
+ exit repeat
+ end if
+ end repeat
+
+ if found then
+ tell theTab to reload
+ set index of theWindow to 1
+ set theWindow's active tab index to theTabIndex
+ else
+ tell window 1
+ activate
+ make new tab with properties {URL:theURL}
+ end tell
+ end if
+ end tell
+end run
diff --git a/lib/builder/post-build.js b/lib/builder/post-build.js
new file mode 100644
index 000000000..c1b718484
--- /dev/null
+++ b/lib/builder/post-build.js
@@ -0,0 +1,50 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+exports.default = function (config, files) {
+ (0, _log2.default)(files.length + " files written", "info");
+
+ var promises = [];
+
+ if (config.CNAME) {
+ promises.push(writeFile((0, _path.join)(config.cwd, config.destination, "CNAME"), config.baseUrl.hostname).then(function () {
+ return (0, _log2.default)("CNAME created with '" + config.baseUrl.hostname + "'");
+ }));
+ }
+
+ if (config.nojekyll) {
+ promises.push(writeFile((0, _path.join)(config.cwd, config.destination, ".nojekyll"), "").then(function () {
+ return (0, _log2.default)(".nojekyll created");
+ }));
+ }
+
+ return Promise.all(promises).then(function () {
+ return (0, _log.plainLog)(_chalk2.default.green("Build successful") + " " + (0, _log.totalElapsedTime)());
+ });
+};
+
+var _path = require("path");
+
+var _fs = require("fs");
+
+var _fs2 = _interopRequireDefault(_fs);
+
+var _pify2 = require("pify");
+
+var _pify3 = _interopRequireDefault(_pify2);
+
+var _chalk = require("chalk");
+
+var _chalk2 = _interopRequireDefault(_chalk);
+
+var _log = require("../_utils/log");
+
+var _log2 = _interopRequireDefault(_log);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var _pify = (0, _pify3.default)(_fs2.default),
+ writeFile = _pify.writeFile;
\ No newline at end of file
diff --git a/lib/builder/server.js b/lib/builder/server.js
new file mode 100644
index 000000000..b59cfeb79
--- /dev/null
+++ b/lib/builder/server.js
@@ -0,0 +1,204 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+// module.exports is used
+// eslint-disable-next-line import/default
+
+
+var _path = require("path");
+
+var _child_process = require("child_process");
+
+var _express = require("express");
+
+var _express2 = _interopRequireDefault(_express);
+
+var _webpack = require("webpack");
+
+var _webpack2 = _interopRequireDefault(_webpack);
+
+var _webpackDevMiddleware = require("webpack-dev-middleware");
+
+var _webpackDevMiddleware2 = _interopRequireDefault(_webpackDevMiddleware);
+
+var _webpackHotMiddleware = require("webpack-hot-middleware");
+
+var _webpackHotMiddleware2 = _interopRequireDefault(_webpackHotMiddleware);
+
+var _connectHistoryApiFallback = require("connect-history-api-fallback");
+
+var _connectHistoryApiFallback2 = _interopRequireDefault(_connectHistoryApiFallback);
+
+var _portfinder = require("portfinder");
+
+var _portfinder2 = _interopRequireDefault(_portfinder);
+
+var _opn = require("opn");
+
+var _opn2 = _interopRequireDefault(_opn);
+
+var _log = require("../_utils/log");
+
+var _log2 = _interopRequireDefault(_log);
+
+var _plugin = require("../loader/plugin.js");
+
+var _plugin2 = _interopRequireDefault(_plugin);
+
+var _minify = require("../loader/minify");
+
+var _minify2 = _interopRequireDefault(_minify);
+
+var _serialize = require("../_utils/serialize");
+
+var _serialize2 = _interopRequireDefault(_serialize);
+
+var _pathToUri = require("../_utils/path-to-uri");
+
+var _pathToUri2 = _interopRequireDefault(_pathToUri);
+
+var _logFormatter = require("./webpack/log-formatter.js");
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
+function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
+
+var devServerNoScript = "Phenomic development server requires JavaScript.\nIf you want to check our your website works without JavaScript, you need to\nbuild the static version and server the result.\nYou can do this by doing: npm run build -- --serve
\n";
+
+exports.default = function (config) {
+ var webpackConfig = config.webpackConfigBrowser;
+
+
+ if (!config.baseUrl) {
+ throw new Error("You must provide a 'baseUrl' object that contains the following keys:" + "'href', 'port', 'hostname'. See https://nodejs.org/api/url.html");
+ }
+
+ var server = (0, _express2.default)();
+
+ if (config.static && config.server) {
+ server.use(config.baseUrl.pathname, _express2.default.static((0, _path.join)(config.cwd, config.destination)));
+ } else {
+ var devEntries = [require.resolve("webpack-hot-middleware/client")];
+
+ var devConfig = _extends({}, webpackConfig, {
+ entry: _extends({}, Object.keys(webpackConfig.entry).reduce(function (acc, key) {
+ return _extends({}, acc, _defineProperty({}, key, [].concat(devEntries, _toConsumableArray(Array.isArray(webpackConfig.entry[key]) ? webpackConfig.entry[key] : [webpackConfig.entry[key]]))));
+ }, {})),
+ plugins: [].concat(_toConsumableArray(webpackConfig.plugins || []), [
+
+ // for hot-middleware
+ new _webpack2.default.optimize.OccurrenceOrderPlugin(), new _webpack2.default.HotModuleReplacementPlugin(), new _webpack2.default.NoEmitOnErrorsPlugin()])
+ });
+
+ // webpack dev + hot middlewares
+ var webpackCompiler = (0, _webpack2.default)(devConfig);
+
+ server.use((0, _webpackDevMiddleware2.default)(webpackCompiler, _extends({
+ publicPath: webpackConfig.output.publicPath,
+ // skip compilation logs if !verbose
+ noInfo: !config.verbose,
+ quiet: !config.verbose
+ }, devConfig.devServer)));
+ server.use((0, _webpackHotMiddleware2.default)(webpackCompiler, {
+ // skip hot middleware logs if !verbose
+ log: config.verbose ? undefined : function () {}
+ }));
+
+ var entries = [];
+ webpackCompiler.plugin("done", function (stats) {
+ entries = [];
+ var namedChunks = stats.compilation.namedChunks;
+ Object.keys(namedChunks).forEach(function (chunkName) {
+ entries = [].concat(_toConsumableArray(entries), _toConsumableArray(namedChunks[chunkName].files.filter(function (file) {
+ return !file.endsWith(".hot-update.js");
+ })));
+ });
+ });
+
+ // if !verbose, use our custom minimal output
+ if (!config.verbose) {
+ (0, _logFormatter.handleInvalid)(); // start "Updating"
+ webpackCompiler.plugin("invalid", _logFormatter.handleInvalid);
+ webpackCompiler.plugin("done", _logFormatter.handleDone);
+ }
+
+ // user static assets
+ if (config.assets) {
+ server.use(config.baseUrl.pathname + config.assets.route, _express2.default.static(config.assets.path));
+ }
+
+ // routing for the part we want (starting to the baseUrl pathname)
+ var router = (0, _express.Router)();
+ server.use(config.baseUrl.pathname, router);
+
+ // fallback to index for unknow pages?
+ router.use((0, _connectHistoryApiFallback2.default)({
+ // https://github.com/MoOx/phenomic/issues/808
+ disableDotRule: true
+ }));
+
+ // webpack static ressources
+ router.get("*", _express2.default.static(webpackConfig.output.path));
+
+ // hardcoded entry point
+ router.get("/index.html", function (req, res) {
+ var collectionMin = (0, _minify2.default)(_plugin2.default.collection);
+ res.setHeader("Content-Type", "text/html");
+ /* eslint-disable max-len */
+ res.end("\n \n \n \n \n
\n \n \n
\n
\n \n " + entries.map(function (fileName) {
+ return "";
+ }) + "\n \n "
+ /* eslint-enable max-len */
+ );
+ });
+ }
+
+ // THAT'S IT
+ var devHost = config.devHost,
+ devPort = config.devPort;
+
+
+ _portfinder2.default.basePort = devPort;
+
+ _portfinder2.default.getPort(function (err, port) {
+ if (err) {
+ throw err;
+ }
+
+ if (port !== devPort) {
+ (0, _log2.default)("Port " + devPort + " is not available. Using port " + port + " instead.");
+ }
+
+ server.listen(port, devHost, function (err) {
+ if (err) {
+ throw err;
+ }
+ var href = "http://" + devHost + ":" + port + config.baseUrl.pathname;
+ (0, _log2.default)("Development server listening on " + href);
+
+ if (config.open) {
+ var openUrl = href.replace(devHost, "localhost");
+ if (process.platform === "darwin") {
+ try {
+ // Try our best to reuse existing tab
+ // on OS X Google Chrome with AppleScript
+ (0, _child_process.execSync)("ps cax | grep \"Google Chrome\"");
+ (0, _child_process.execSync)("osascript openChrome.applescript " + openUrl, { cwd: __dirname, stdio: "ignore" });
+ return true;
+ } catch (err) {
+ // Ignore errors.
+ }
+ }
+ // Fallback to opn
+ // (It will always open new tab)
+ (0, _opn2.default)(openUrl);
+ }
+ });
+ });
+};
\ No newline at end of file
diff --git a/lib/builder/webpack/config.browser.js b/lib/builder/webpack/config.browser.js
new file mode 100644
index 000000000..03319094c
--- /dev/null
+++ b/lib/builder/webpack/config.browser.js
@@ -0,0 +1,41 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+// module.exports is used
+// eslint-disable-next-line import/default
+
+
+var _path = require("path");
+
+var _webpack = require("../../_utils/offline/webpack.js");
+
+var _plugin = require("../../loader/plugin.js");
+
+var _plugin2 = _interopRequireDefault(_plugin);
+
+var _configCommon = require("./config.common.js");
+
+var _configCommon2 = _interopRequireDefault(_configCommon);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
+function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
+
+var chunkNameBrowser = "phenomic.browser";
+
+exports.default = function (config) {
+
+ var webpackConfig = (0, _configCommon2.default)(config);
+
+ return _extends({}, webpackConfig, {
+ plugins: [new _plugin2.default()].concat(_toConsumableArray(webpackConfig.plugins), _toConsumableArray((0, _webpack.offlinePlugin)(config))),
+
+ entry: _extends({}, config.webpackConfig ? config.webpackConfig.entry : {}, _defineProperty({}, chunkNameBrowser, [(0, _path.join)(config.cwd, config.scriptBrowser)].concat(_toConsumableArray((0, _webpack.offlineEntry)(config)))))
+ });
+};
\ No newline at end of file
diff --git a/lib/builder/webpack/config.common.js b/lib/builder/webpack/config.common.js
new file mode 100644
index 000000000..83e0d5f8a
--- /dev/null
+++ b/lib/builder/webpack/config.common.js
@@ -0,0 +1,49 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.chunkNameBrowser = undefined;
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _url = require("url");
+
+var _url2 = _interopRequireDefault(_url);
+
+var _webpack = require("webpack");
+
+var _package = require("../../../package.json");
+
+var _package2 = _interopRequireDefault(_package);
+
+var _webpack2 = require("../../_utils/cache/webpack.js");
+
+var _webpack3 = _interopRequireDefault(_webpack2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
+
+var chunkNameBrowser = exports.chunkNameBrowser = "phenomic.browser";
+
+var wrap = JSON.stringify;
+
+exports.default = function (config) {
+ var _config$webpackConfig = config.webpackConfig,
+ webpackConfig = _config$webpackConfig === undefined ? {} : _config$webpackConfig;
+
+
+ return _extends({}, webpackConfig, {
+ plugins: [].concat(_toConsumableArray(webpackConfig.plugins ? webpackConfig.plugins : []), _toConsumableArray((0, _webpack3.default)(config)), [new _webpack.DefinePlugin({ "process.env": {
+ NODE_ENV: wrap(config.production ? "production" : process.env.NODE_ENV),
+
+ PHENOMIC_USER_PATHNAME: wrap(process.env.PHENOMIC_USER_PATHNAME),
+ PHENOMIC_USER_URL: wrap(_url2.default.format(config.baseUrl)),
+ PHENOMIC_NAME: wrap(_package2.default.name[0].toUpperCase() + _package2.default.name.slice(1)),
+ PHENOMIC_VERSION: wrap(_package2.default.version),
+ PHENOMIC_HOMEPAGE: wrap(_package2.default.homepage),
+ PHENOMIC_REPOSITORY: wrap(_package2.default.repository)
+ } })])
+ });
+};
\ No newline at end of file
diff --git a/lib/builder/webpack/config.node.js b/lib/builder/webpack/config.node.js
new file mode 100644
index 000000000..e97d20f16
--- /dev/null
+++ b/lib/builder/webpack/config.node.js
@@ -0,0 +1,84 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.cacheDir = undefined;
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _path = require("path");
+
+var _webpack = require("webpack");
+
+var _findCacheDir = require("find-cache-dir");
+
+var _findCacheDir2 = _interopRequireDefault(_findCacheDir);
+
+var _configCommon = require("./config.common.js");
+
+var _configCommon2 = _interopRequireDefault(_configCommon);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
+
+function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
+var UglifyJsPlugin = _webpack.optimize.UglifyJsPlugin;
+
+var chunkNameNode = "phenomic.node";
+var cacheDir = exports.cacheDir = (0, _findCacheDir2.default)({ name: "phenomic/webpack-node-build" });
+
+var defaultExternals = [
+// we could consider node_modules as externals deps
+// and so use something like
+// /^[A-Za-z0-9-_]/
+// to not bundle all deps in the static build (for perf)
+// the problem is that if people rely on node_modules for stuff
+// like css, this breaks their build.
+
+// Glamor integration
+"glamor", "glamor/server",
+
+// Aprodite integration
+"aphrodite"];
+
+var sourceMapSupport = require.resolve("source-map-support/register")
+// windows support
+.replace(/\\/g, "/");
+
+var requireSourceMapSupport = "require('" + sourceMapSupport + "');";
+
+exports.default = function (config) {
+ var webpackConfig = (0, _configCommon2.default)(config);
+
+ return _extends({}, webpackConfig, {
+
+ entry: _defineProperty({}, chunkNameNode, (0, _path.join)(config.cwd, config.scriptNode)),
+
+ output: _extends({}, webpackConfig.output, {
+ path: cacheDir,
+ libraryTarget: "commonjs2",
+ filename: (0, _path.basename)(config.scriptNode, ".js") + ".bundle.js"
+ }),
+
+ target: "node",
+
+ // externals for package/relative name
+ externals: [].concat(_toConsumableArray(webpackConfig.externals || defaultExternals), [
+
+ // keep the loader plugin cache in memory
+ "phenomic/lib/loader/index", "phenomic/lib/loader/plugin"]),
+
+ // sourcemaps
+ devtool: "#source-map",
+ plugins: [].concat(_toConsumableArray(webpackConfig.plugins.filter(function (plugin) {
+ return !(plugin instanceof UglifyJsPlugin);
+ }) || []), [new _webpack.BannerPlugin({
+ banner: requireSourceMapSupport,
+ raw: true,
+ entryOnly: false
+ })])
+ });
+};
\ No newline at end of file
diff --git a/lib/builder/webpack/index.js b/lib/builder/webpack/index.js
new file mode 100644
index 000000000..f6768f075
--- /dev/null
+++ b/lib/builder/webpack/index.js
@@ -0,0 +1,38 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+exports.default = function (webpackConfig, log, cb) {
+ (0, _webpack2.default)(webpackConfig, function (err, stats) {
+ if (err) {
+ throw err;
+ }
+
+ if (stats.hasErrors()) {
+ stats.compilation.errors.forEach(function (item) {
+ return log(_chalk2.default.red(item.stack || item));
+ });
+ throw new Error("webpack build failed with errors");
+ }
+
+ if (stats.hasWarnings()) {
+ stats.compilation.warnings.forEach(function (item) {
+ return log(_chalk2.default.yellow("Warning: %s", item.message));
+ });
+ }
+
+ cb(stats);
+ });
+};
+
+var _webpack = require("webpack");
+
+var _webpack2 = _interopRequireDefault(_webpack);
+
+var _chalk = require("chalk");
+
+var _chalk2 = _interopRequireDefault(_chalk);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
\ No newline at end of file
diff --git a/lib/builder/webpack/log-formatter.js b/lib/builder/webpack/log-formatter.js
new file mode 100644
index 000000000..a8b05d370
--- /dev/null
+++ b/lib/builder/webpack/log-formatter.js
@@ -0,0 +1,76 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.handleInvalid = handleInvalid;
+exports.handleDone = handleDone;
+
+var _chalk = require("chalk");
+
+var _chalk2 = _interopRequireDefault(_chalk);
+
+var _ora = require("ora");
+
+var _ora2 = _interopRequireDefault(_ora);
+
+var _logSymbols = require("log-symbols");
+
+var _logSymbols2 = _interopRequireDefault(_logSymbols);
+
+var _log = require("../../_utils/log");
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var spinner = (0, _ora2.default)();
+
+// remove noize from messages
+var betterMsg = function betterMsg(msg) {
+ return msg.replace(process.cwd(), ".")
+
+ // Webpack "Module not found" noize
+ .replace(/Error: Cannot resolve 'file' or 'directory'/, "")
+
+ // loader path for css
+ .replace(/.\/~\/(css|postcss|sass|less|stylus)-loader(.*)!/g, "");
+};
+
+function handleInvalid() {
+ spinner.text = "Updating";
+ spinner.start();
+}
+
+var isSyntaxError = function isSyntaxError(msg) {
+ return msg.includes("SyntaxError");
+};
+
+function handleDone(webpackStats) {
+ spinner.stop();
+
+ var stats = webpackStats.toJson({}, true);
+ if (!webpackStats.hasErrors() && !webpackStats.hasWarnings()) {
+ spinner.stream.write(_logSymbols2.default.success + _chalk2.default.green(" Updated ") + ("(in " + (0, _log.formatTime)(stats.time / 1000) + ")"));
+ return;
+ }
+
+ if (stats.errors.length) {
+ spinner.text = _chalk2.default.red("Update failed") + "\n";
+ spinner.fail();
+ spinner = (0, _ora2.default)();
+
+ var errors = stats.errors.some(isSyntaxError)
+ // Show syntax error first
+ ? stats.errors.filter(isSyntaxError) : stats.errors;
+ errors.forEach(function (msg) {
+ return (0, _log.plainLog)("Error in " + betterMsg(msg) + "\n", "error");
+ });
+ return;
+ }
+
+ spinner.text = _chalk2.default.yellow("Updated with warnings") + "\n";
+ spinner.fail();
+ spinner = (0, _ora2.default)();
+ stats.warnings.forEach(function (msg) {
+ return (0, _log.plainLog)("Warning in " + betterMsg(msg) + " \n", "warning");
+ });
+}
\ No newline at end of file
diff --git a/lib/builder/webpack/sortAssets.js b/lib/builder/webpack/sortAssets.js
new file mode 100644
index 000000000..3cb0bd8f8
--- /dev/null
+++ b/lib/builder/webpack/sortAssets.js
@@ -0,0 +1,24 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+exports.default = function (assets) {
+ var assetsFiles = { css: [], js: [] };
+
+ Object.keys(assets).reduce(function (result, key) {
+ var chunkAssets = assets[key];
+ return result.concat(chunkAssets);
+ }, []).sort(function (a, b) {
+ return a.toLowerCase() > b.toLowerCase() ? 1 : -1;
+ }).forEach(function (name) {
+ if (name.endsWith(".js")) {
+ assetsFiles.js.push(name);
+ } else if (name.endsWith(".css")) {
+ assetsFiles.css.push(name);
+ }
+ });
+
+ return assetsFiles;
+};
\ No newline at end of file
diff --git a/lib/client/hot-md.js b/lib/client/hot-md.js
new file mode 100644
index 000000000..9f4346b5c
--- /dev/null
+++ b/lib/client/hot-md.js
@@ -0,0 +1,25 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _pages = require("../redux/modules/pages");
+
+var pageActions = _interopRequireWildcard(_pages);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+exports.default = function (mdContext, collection, store) {
+ return function (file) {
+ var item = collection.find(function (item) {
+ return item.__filename === file.slice("./".length);
+ });
+ var dataUrl = mdContext(file);
+ if (dataUrl !== item.__dataUrl) {
+ item.__dataUrl = dataUrl;
+ console.log(file, " hot update");
+ store.dispatch(pageActions.refresh(item.__url, item.__dataUrl));
+ }
+ };
+}; // eslint-disable-next-line import/no-namespace
\ No newline at end of file
diff --git a/lib/client/index.js b/lib/client/index.js
new file mode 100644
index 000000000..1321b7272
--- /dev/null
+++ b/lib/client/index.js
@@ -0,0 +1,70 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.browserHistory = undefined;
+exports.default = phenomic;
+
+var _react = require("react");
+
+var _react2 = _interopRequireDefault(_react);
+
+var _reactDom = require("react-dom");
+
+var _reactDom2 = _interopRequireDefault(_reactDom);
+
+var _reactRouter = require("react-router");
+
+var _createBrowserHistory = require("history/lib/createBrowserHistory");
+
+var _createBrowserHistory2 = _interopRequireDefault(_createBrowserHistory);
+
+var _useScroll = require("react-router-scroll/lib/useScroll");
+
+var _useScroll2 = _interopRequireDefault(_useScroll);
+
+var _reactRedux = require("react-redux");
+
+var _ContextProvider = require("../components/ContextProvider");
+
+var _ContextProvider2 = _interopRequireDefault(_ContextProvider);
+
+var _shouldUpdateScroll = require("./should-update-scroll.js");
+
+var _shouldUpdateScroll2 = _interopRequireDefault(_shouldUpdateScroll);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+// App
+var browserHistory = exports.browserHistory = typeof window !== "undefined" // just for node testing
+? (0, _reactRouter.useRouterHistory)(_createBrowserHistory2.default)({
+ // basename don't like having a trailing slash
+ // https://github.com/reactjs/react-router/issues/3184
+ basename: process.env.PHENOMIC_USER_PATHNAME.replace(/\/$/, "")
+}) : null;
+
+function phenomic(_ref) {
+ var metadata = _ref.metadata,
+ routes = _ref.routes,
+ store = _ref.store;
+
+ var collection = typeof window !== "undefined" ? window.__COLLECTION__ : [];
+
+ _reactDom2.default.render(_react2.default.createElement(
+ _ContextProvider2.default,
+ {
+ collection: collection,
+ metadata: metadata
+ },
+ _react2.default.createElement(
+ _reactRedux.Provider,
+ { store: store },
+ _react2.default.createElement(_reactRouter.Router, {
+ history: browserHistory,
+ routes: routes,
+ render: (0, _reactRouter.applyRouterMiddleware)((0, _useScroll2.default)(_shouldUpdateScroll2.default))
+ })
+ )
+ ), document.getElementById("phenomic"));
+}
\ No newline at end of file
diff --git a/lib/client/should-update-scroll.js b/lib/client/should-update-scroll.js
new file mode 100644
index 000000000..65faed75e
--- /dev/null
+++ b/lib/client/should-update-scroll.js
@@ -0,0 +1,83 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+
+var lookForElement = function lookForElement(id) {
+ var element = document.getElementById(id);
+ if (element === null) {
+ var elementsSet = document.getElementsByName(id);
+ if (elementsSet.length) {
+ element = elementsSet[0];
+ }
+ }
+
+ return element;
+};
+
+var retryTimeout = null;
+var retryCount = 0;
+var retryDelay = 100;
+var retryMax = 1000; // 1000 * retryDelay = retry during 10s
+
+var moveToHash = function moveToHash(id) {
+ var element = lookForElement(id);
+ if (element) {
+ if (element.scrollIntoViewA) {
+ element.scrollIntoView();
+ } else {
+ var coords = element.getBoundingClientRect();
+ // $FlowFixMe window
+ window.scrollTo(
+ // $FlowFixMe window
+ coords.left + window.pageXOffset,
+ // $FlowFixMe window
+ coords.top + window.pageYOffset);
+ }
+ return true;
+ }
+ if (retryCount < retryMax) {
+ retryTimeout = setTimeout(function () {
+ retryCount++;
+ moveToHash(id);
+ }, retryDelay);
+ }
+
+ return false;
+};
+
+// only scroll when complete url changes
+// (except for hash change - this example provide a natural feeling when you
+// use simple link to internal anchor (eg: a table of content that use hashes
+// inside a page))
+
+var shouldUpdateScroll = function shouldUpdateScroll(prevProps, props) {
+ var hash = props.location.hash;
+
+ // if there is a page + hash,
+ // it's probably not already in the page since we load page data
+ // asynchronously, AFTER react-router does his job
+ // so here we will handle the work ourselves
+ // (and tell react-router-scroll to not handle it)
+ if (
+ // if page is the same, browser will handle the scroll automatically
+ // so we execute our logic for the scroll only if location change
+ // and include a hash
+ prevProps && prevProps.location.pathname + prevProps.location.search !== props.location.pathname + props.location.search && hash.length > 1) {
+ retryCount = 1;
+ clearTimeout(retryTimeout);
+ var hasScrolled = moveToHash(hash.slice(1));
+
+ // scroll to top until dom is ready,
+ // code above might handle the scroll LATER
+ // if it does we know it and tell react-router to scroll to top until dom
+ // is ready to avoid weird UX (eg: click, no scroll at all)
+ return !hasScrolled;
+ }
+
+ return Boolean(prevProps) && hash === "";
+};
+
+exports.default = shouldUpdateScroll;
\ No newline at end of file
diff --git a/lib/components/BodyContainer/index.js b/lib/components/BodyContainer/index.js
new file mode 100644
index 000000000..f74596b88
--- /dev/null
+++ b/lib/components/BodyContainer/index.js
@@ -0,0 +1,83 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _react = require("react");
+
+var _react2 = _interopRequireDefault(_react);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var BodyContainer = function (_Component) {
+ _inherits(BodyContainer, _Component);
+
+ function BodyContainer() {
+ _classCallCheck(this, BodyContainer);
+
+ return _possibleConstructorReturn(this, (BodyContainer.__proto__ || Object.getPrototypeOf(BodyContainer)).apply(this, arguments));
+ }
+
+ _createClass(BodyContainer, [{
+ key: "render",
+ value: function render() {
+ var props = this.props;
+
+ var children = props.children,
+ otherProps = _objectWithoutProperties(props, ["children"]);
+
+ var child = void 0;
+ if (typeof children === "string") {
+ child = children;
+ } else {
+ try {
+ child = _react2.default.Children.only(children);
+ } catch (e) {
+ console.log("phenomic: BodyContainer: multiple childs");
+ }
+ }
+
+ if (child) {
+ return _react2.default.createElement("div", _extends({
+ className: "phenomic-BodyContainer",
+ dangerouslySetInnerHTML: { __html: child }
+ }, otherProps));
+ }
+
+ return _react2.default.createElement(
+ "div",
+ otherProps,
+ _react2.default.Children.map(children, function (child, i) {
+ if (typeof child === "string") {
+ return _react2.default.createElement("div", {
+ key: i,
+ className: "phenomic-BodyContainer",
+ dangerouslySetInnerHTML: { __html: child }
+ });
+ }
+ return child;
+ })
+ );
+ }
+ }]);
+
+ return BodyContainer;
+}(_react.Component);
+
+BodyContainer.propTypes = {
+ children: require("react").PropTypes.any.isRequired
+};
+exports.default = BodyContainer;
\ No newline at end of file
diff --git a/lib/components/ContextProvider/index.js b/lib/components/ContextProvider/index.js
new file mode 100644
index 000000000..d6bc8b415
--- /dev/null
+++ b/lib/components/ContextProvider/index.js
@@ -0,0 +1,58 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _react = require("react");
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var PhenomicContext = function (_Component) {
+ _inherits(PhenomicContext, _Component);
+
+ function PhenomicContext() {
+ _classCallCheck(this, PhenomicContext);
+
+ return _possibleConstructorReturn(this, (PhenomicContext.__proto__ || Object.getPrototypeOf(PhenomicContext)).apply(this, arguments));
+ }
+
+ _createClass(PhenomicContext, [{
+ key: "getChildContext",
+ value: function getChildContext() {
+ return {
+ collection: this.props.collection,
+ metadata: this.props.metadata
+ };
+ }
+ }, {
+ key: "render",
+ value: function render() {
+ return _react.Children.only(this.props.children);
+ }
+ }]);
+
+ return PhenomicContext;
+}(_react.Component);
+
+PhenomicContext.propTypes = {
+ collection: _react.PropTypes.array,
+ metadata: _react.PropTypes.object,
+ children: _react.PropTypes.node
+};
+PhenomicContext.childContextTypes = {
+ collection: _react.PropTypes.array,
+ metadata: _react.PropTypes.object
+};
+PhenomicContext.propTypes = {
+ collection: require("react").PropTypes.any.isRequired,
+ metadata: require("react").PropTypes.object.isRequired,
+ children: require("react").PropTypes.any
+};
+exports.default = PhenomicContext;
\ No newline at end of file
diff --git a/lib/components/Html/index.js b/lib/components/Html/index.js
new file mode 100644
index 000000000..c42d7ee20
--- /dev/null
+++ b/lib/components/Html/index.js
@@ -0,0 +1,120 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _react = require("react");
+
+var _react2 = _interopRequireDefault(_react);
+
+var _server = require("react-dom/server");
+
+var _reactHelmet = require("react-helmet");
+
+var _reactHelmet2 = _interopRequireDefault(_reactHelmet);
+
+var _styledComponents = require("styled-components");
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var Html = function Html(props) {
+
+ // Glamor integration
+ // https://github.com/threepointone/glamor/blob/master/docs/server.md
+ var glamorRenderStatic = void 0;
+ try {
+ // $FlowFixMe just ignore glamor as we don't have it as a dep
+ glamorRenderStatic = require("glamor/server").renderStatic;
+ } catch (e) {}
+ // skip glamor if not working
+
+
+ // Aprodite
+ // https://github.com/Khan/aphrodite#server-side-rendering
+ var aproditeRenderStatic = void 0;
+ try {
+ // $FlowFixMe just ignore aprodite as we don't have it as a dep
+ aproditeRenderStatic = require("aphrodite").StyleSheetServer.renderStatic;
+ } catch (e) {}
+ // skip aprodite if not working
+
+
+ // render body
+ var body = void 0;
+ if (glamorRenderStatic) {
+ var glamorResult = glamorRenderStatic(function () {
+ return props.renderBody();
+ });
+
+ (0, _server.renderToString)(_react2.default.createElement(_reactHelmet2.default, {
+ style: [{ "cssText": glamorResult.css }],
+ script: [{ "innerHTML": "window._glamor = " + JSON.stringify(glamorResult.ids) }]
+ }));
+ body = glamorResult.html;
+ } else if (aproditeRenderStatic) {
+ var aproditeResult = aproditeRenderStatic(function () {
+ return props.renderBody();
+ });
+
+ (0, _server.renderToString)(_react2.default.createElement(_reactHelmet2.default, {
+ style: [{
+ "cssText": aproditeResult.css.content,
+ "data-aphrodite": undefined
+ }],
+ script: [{ "innerHTML": "window._aphrodite = " + JSON.stringify(aproditeResult.css.renderedClassNames) + ";" }]
+ }));
+ body = aproditeResult.html;
+ }
+
+ body = body || props.renderBody();
+ var styledComponentsStyles = props.sheet.getStyleElement();
+
+ // rewind html metas
+ var head = _reactHelmet2.default.rewind();
+
+ // is automatically prepended
+ return _react2.default.createElement(
+ "html",
+ _extends({
+ lang: "en"
+ }, head.htmlAttributes.toComponent()),
+ _react2.default.createElement(
+ "head",
+ null,
+ head.base.toComponent(),
+ head.title.toComponent(),
+ _react2.default.createElement("meta", { charSet: "utf-8" }),
+ _react2.default.createElement("meta", { httpEquiv: "X-UA-Compatible", content: "IE=edge" }),
+ _react2.default.createElement("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }),
+ head.meta.toComponent(),
+ head.style.toComponent(),
+ head.link.toComponent(),
+ props.css.map(function (file, i) {
+ return _react2.default.createElement("link", { key: "phenomic.css." + i, rel: "stylesheet", href: file });
+ }),
+ styledComponentsStyles,
+ head.script.toComponent()
+ ),
+ _react2.default.createElement(
+ "body",
+ null,
+ _react2.default.createElement("div", { id: "phenomic", dangerouslySetInnerHTML: { __html: body } }),
+ props.renderScript(),
+ props.js.map(function (file, i) {
+ return _react2.default.createElement("script", { key: "phenomic.js." + i, src: file });
+ })
+ )
+ );
+};
+
+Html.propTypes = {
+ css: require("react").PropTypes.arrayOf(require("react").PropTypes.string).isRequired,
+ js: require("react").PropTypes.arrayOf(require("react").PropTypes.string).isRequired,
+ renderBody: require("react").PropTypes.func.isRequired,
+ renderScript: require("react").PropTypes.func.isRequired,
+ sheet: require("react").PropTypes.any.isRequired
+};
+exports.default = Html;
\ No newline at end of file
diff --git a/lib/components/Link/index.js b/lib/components/Link/index.js
new file mode 100644
index 000000000..1ec83e776
--- /dev/null
+++ b/lib/components/Link/index.js
@@ -0,0 +1,91 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _react = require("react");
+
+var _react2 = _interopRequireDefault(_react);
+
+var _classnames = require("classnames");
+
+var _classnames2 = _interopRequireDefault(_classnames);
+
+var _reactRouter = require("react-router");
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
+function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
+
+var origin = function origin(location) {
+ return location.origin ||
+
+ // IE does not correctly handle origin, maybe Edge does...
+ location.protocol + "//" + location.hostname + (location.port ? ":" + location.port : "");
+};
+
+function Link(props, _ref) {
+ var router = _ref.router;
+
+ var to = props.to,
+ otherProps = _objectWithoutProperties(props, ["to"]);
+
+ var simpleLink = _react2.default.createElement("a", _extends({}, otherProps, {
+ href: to,
+ className: props.className
+ }));
+
+ // static rendering
+ if (typeof document === "undefined") {
+ return simpleLink;
+ }
+
+ var toLink = document.createElement("a");
+ toLink.href = to;
+
+ if (
+ // parent absolute url with the same domain
+ // should not be Link
+ to.indexOf("://") > -1 && to.indexOf(process.env.PHENOMIC_USER_URL) === -1) {
+ return simpleLink;
+ }
+
+ if (origin(toLink) === origin(window.location)
+ // we might want to restrict Link to path including the pathname
+ // but this will require to preprend pathname to all Links from the
+ // collection, which sucks.
+ // If people wants to use Link for a same domain, but in the parent path,
+ // you will need to includes the entire url, / won't work at it will use
+ // the react-router basename defined by Phenomic.
+ // &&
+ // toLink.pathname.includes(process.env.PHENOMIC_USER_PATHNAME)
+ // toLink.pathname.indexOf(process.env.PHENOMIC_USER_PATHNAME) > -1
+ ) {
+ return _react2.default.createElement(_reactRouter.Link, _extends({}, otherProps, {
+ to: to,
+ className: (0, _classnames2.default)(props.className, _defineProperty({}, props.activeClassName, router && (router.isActive({ pathname: props.to }) || router.isActive({ pathname: props.to + "index.html" })) && props.activeClassName))
+ }));
+ }
+
+ return simpleLink;
+}
+
+Link.propTypes = {
+ children: _react.PropTypes.node,
+ to: _react.PropTypes.string.isRequired,
+ className: _react.PropTypes.string,
+ activeClassName: _react.PropTypes.string
+};
+
+Link.contextTypes = {
+ router: _react.PropTypes.object.isRequired
+};
+
+Link.displayName = "Link";
+
+exports.default = Link;
\ No newline at end of file
diff --git a/lib/components/PageContainer/component.js b/lib/components/PageContainer/component.js
new file mode 100644
index 000000000..b37557ebe
--- /dev/null
+++ b/lib/components/PageContainer/component.js
@@ -0,0 +1,288 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _react = require("react");
+
+var _react2 = _interopRequireDefault(_react);
+
+var _reactDom = require("react-dom");
+
+var _urlify = require("../../_utils/urlify");
+
+var _urlify2 = _interopRequireDefault(_urlify);
+
+var _catchLinks = require("../../_utils/catch-links");
+
+var _catchLinks2 = _interopRequireDefault(_catchLinks);
+
+var _client = require("../../client");
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+/* eslint-disable react/sort-comp */
+
+
+var logPrefix = "phenomic: PageContainer:";
+
+// react-router does not return leading and trailing slashes
+// so we need to normalize according to collection data
+var splatToUrl = function splatToUrl(string) {
+ var url = "/" + (0, _urlify2.default)(string);
+ return url === "//" ? "/" : url;
+};
+
+function find(collection, pageUrl) {
+ return collection.find(function (item) {
+ return item.__url === pageUrl || item.__url === pageUrl + "/" || item.__resourceUrl === pageUrl;
+ });
+}
+
+function getBase(location) {
+ return location.protocol + "//" + location.host + process.env.PHENOMIC_USER_PATHNAME;
+}
+
+function adjustCurrentUrl(location, item, props) {
+ // adjust url (eg: missing trailing slash)
+ var currentExactPageUrl = location.href.replace(getBase(location), "/");
+ var itemURL = item.__url + location.search + location.hash;
+
+ if (currentExactPageUrl !== itemURL) {
+ props.logger.info(logPrefix + " replacing by '" + currentExactPageUrl + "' to '" + itemURL + "'");
+ if (_client.browserHistory) {
+ _client.browserHistory.replace(itemURL);
+ }
+ }
+}
+
+function getLayout(layout, props) {
+ if (props.layouts && props.layouts[layout]) {
+ return props.layouts[layout];
+ }
+}
+
+var PageContainer = function (_Component) {
+ _inherits(PageContainer, _Component);
+
+ function PageContainer() {
+ _classCallCheck(this, PageContainer);
+
+ return _possibleConstructorReturn(this, (PageContainer.__proto__ || Object.getPrototypeOf(PageContainer)).apply(this, arguments));
+ }
+
+ _createClass(PageContainer, [{
+ key: "componentWillMount",
+ value: function componentWillMount() {
+ var props = this.props;
+
+ if (!getLayout(props.defaultLayout, props)) {
+ props.logger.error(logPrefix + " default layout \"" + props.defaultLayout + "\" not provided.");
+ }
+ this.preparePage(this.props, this.context);
+ }
+ }, {
+ key: "componentDidMount",
+ value: function componentDidMount() {
+ this.catchInternalLink();
+ }
+ }, {
+ key: "componentWillReceiveProps",
+ value: function componentWillReceiveProps(nextProps) {
+ this.preparePage(nextProps, this.context);
+ }
+ }, {
+ key: "componentDidUpdate",
+ value: function componentDidUpdate() {
+ this.catchInternalLink();
+ }
+ }, {
+ key: "catchInternalLink",
+ value: function catchInternalLink() {
+ var _this2 = this;
+
+ var layoutDOMElement = (0, _reactDom.findDOMNode)(this);
+
+ if (layoutDOMElement) {
+ var bodyContainers = Array.prototype.slice.call(layoutDOMElement.querySelectorAll(".phenomic-BodyContainer"));
+ if (!bodyContainers.length) {
+ bodyContainers = [layoutDOMElement];
+ }
+
+ // as soon as we listened to something, we should carefully unlisten
+ // because
+ // - it can be listening in the layoutDOMElement (a parent)
+ // - it can be listening in a might be catched (but they are not supposed to)
+ if (this.cleanupInternalLinks) {
+ this.cleanupInternalLinks();
+ }
+ this.cleanupInternalLinks = (0, _catchLinks2.default)(bodyContainers, function (href) {
+ // do not catch links that are under the current base path
+ if (href.indexOf(process.env.PHENOMIC_USER_PATHNAME) === -1) {
+ // === if (!href.includes(process.env.PHENOMIC_USER_PATHNAME)) {
+ return false;
+ }
+
+ // lookup in collection by adjusting the link with our stored links
+ var pageUrl = href
+ // remove pathname as collection links don't have pathname included
+ .replace(process.env.PHENOMIC_USER_PATHNAME, "/");
+ if (!find(_this2.context.collection, pageUrl
+ // remove hash for the lookup as it's not necessary
+ .replace(/#.*/, ""))) {
+ return false;
+ }
+ if (_client.browserHistory) {
+ _client.browserHistory.push(pageUrl);
+ }
+ return true;
+ });
+ }
+ }
+ }, {
+ key: "preparePage",
+ value: function preparePage(props, context) {
+ var pageUrl = splatToUrl(props.params.splat);
+ if (process.env.NODE_ENV !== "production") {
+ props.logger.info(logPrefix + " '" + pageUrl + "' rendering...");
+ }
+
+ var item = find(context.collection, pageUrl);
+ if (typeof window !== "undefined" && typeof window.location !== "undefined" && item) {
+ adjustCurrentUrl(window.location, item, props);
+ }
+
+ var page = props.pages[pageUrl];
+ if (!page) {
+ if (item) {
+ props.getPage(item.__url, item.__dataUrl);
+ } else {
+ props.logger.error(logPrefix + " " + pageUrl + " is a page not found.");
+ props.setPageNotFound(pageUrl);
+ }
+ } else {
+ if (page.error) {
+ return;
+ }
+
+ var Layout = getLayout(page.type, props);
+ if (page.type !== undefined && !Layout) {
+ props.logger.error(logPrefix + " Unkown page type: \"" + page.type + "\"" + "component not available in \"layouts\" property." + ("Please check the \"layout\" or \"type\" of page \"" + page + "\" header."));
+ }
+ }
+ }
+ }, {
+ key: "render",
+ value: function render() {
+ var props = this.props;
+ var collection = this.context.collection;
+
+
+ var pageUrl = splatToUrl(props.params.splat);
+ // page url from redux store
+ var page = props.pages[pageUrl];
+ var partialPageHead = collection.find(function (pageData) {
+ return pageUrl === pageData.__url;
+ }) || {};
+
+ if (!page) {
+ if (process.env.NODE_ENV !== "production") {
+ props.logger.info(logPrefix + " '" + pageUrl + "' no data");
+ }
+ // return null
+ }
+ if (process.env.NODE_ENV !== "production") {
+ props.logger.info(logPrefix + " '" + pageUrl + "'", page);
+ }
+
+ if ((typeof page === "undefined" ? "undefined" : _typeof(page)) !== "object" || page.toString() !== "[object Object]") {
+ props.logger.info(logPrefix + " page " + pageUrl + " should be an object");
+ return null;
+ }
+ var PageLoading = getLayout("PageLoading", props);
+ var PageError = getLayout("PageError", props);
+ var LayoutFallback = getLayout(props.defaultLayout, props);
+ var Layout = getLayout(partialPageHead.type || partialPageHead.layout ||
+ // page.type is head type||layout too
+ page.type, props) || LayoutFallback;
+
+ if (page.error) {
+ if (!PageError) {
+ return _react2.default.createElement(
+ "div",
+ { style: { "text-align": "center" } },
+ _react2.default.createElement(
+ "h1",
+ null,
+ page.error
+ ),
+ _react2.default.createElement(
+ "p",
+ null,
+ page.errorText
+ )
+ );
+ }
+ return _react2.default.createElement(PageError, page);
+ } else if (page.isLoading && PageLoading && Layout && !Layout.hasLoadingState) {
+ return _react2.default.createElement(PageLoading, null);
+ } else if (Layout) {
+ return _react2.default.createElement(Layout
+ // head will be overwritten by "page"
+ // (since page contains a head when loaded)
+ , _extends({ head: partialPageHead
+ }, page));
+ }
+
+ if (process.env.NODE_ENV !== "production") {
+ return _react2.default.createElement(
+ "div",
+ null,
+ "No layout can be rendered. See console for more information."
+ );
+ }
+
+ return null;
+ }
+ }]);
+
+ return PageContainer;
+}(_react.Component);
+
+PageContainer.contextTypes = {
+ collection: _react.PropTypes.arrayOf(_react.PropTypes.object),
+ layouts: _react.PropTypes.object
+};
+PageContainer.defaultProps = {
+ layouts: {},
+ defaultLayout: "Page",
+ logger: console
+};
+PageContainer.propTypes = {
+ pages: require("react").PropTypes.object.isRequired,
+ params: require("react").PropTypes.shape({
+ splat: require("react").PropTypes.string.isRequired
+ }).isRequired,
+ layouts: require("react").PropTypes.object.isRequired,
+ defaultLayout: require("react").PropTypes.string.isRequired,
+ getPage: require("react").PropTypes.func.isRequired,
+ setPageNotFound: require("react").PropTypes.func.isRequired,
+ logger: require("react").PropTypes.object.isRequired
+};
+exports.default = PageContainer;
\ No newline at end of file
diff --git a/lib/components/PageContainer/index.js b/lib/components/PageContainer/index.js
new file mode 100644
index 000000000..867d6ba39
--- /dev/null
+++ b/lib/components/PageContainer/index.js
@@ -0,0 +1,35 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _reactRedux = require("react-redux");
+
+var _pages = require("../../redux/modules/pages");
+
+var pageActions = _interopRequireWildcard(_pages);
+
+var _component = require("./component");
+
+var _component2 = _interopRequireDefault(_component);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+// eslint-disable-next-line import/no-namespace
+exports.default = (0, _reactRedux.connect)(function (_ref) {
+ var pages = _ref.pages;
+
+ return { pages: pages };
+}, function (dispatch) {
+ return {
+ getPage: function getPage() {
+ return dispatch(pageActions.get.apply(pageActions, arguments));
+ },
+ setPageNotFound: function setPageNotFound() {
+ return dispatch(pageActions.setNotFound.apply(pageActions, arguments));
+ }
+ };
+})(_component2.default);
\ No newline at end of file
diff --git a/lib/configurator/definitions.js b/lib/configurator/definitions.js
new file mode 100644
index 000000000..14b0a041f
--- /dev/null
+++ b/lib/configurator/definitions.js
@@ -0,0 +1,96 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = {
+ "cwd": {
+ type: "string",
+ description: "base directory (eg: where 'source' and 'destination' should be",
+ default: process.cwd()
+ },
+ "source": {
+ type: "string",
+ description: "source folder of your content (md, assets, etc)",
+ default: "content"
+ },
+ "destination": {
+ type: "string",
+ description: "destination folder of your build",
+ default: "dist"
+ },
+ "assets": {
+ // types: string, objects, boolean and falsy value
+ description: "path to static assets (images, media etc)",
+ default: "assets"
+ },
+ "offline": {
+ // types: boolean, object
+ description: "flag to enable offline usage via appcache and service worker"
+ },
+ "force-offline": {
+ type: "boolean",
+ description: "flag to force offline mode (for development)",
+ default: false
+ },
+ "CNAME": {
+ type: "boolean",
+ description: "flag to enable automatic generation of a CNAME file",
+ default: false
+ },
+ "nojekyll": {
+ type: "boolean",
+ description: "flag to generate a .nojekyll file, to avoid Jekyll automatic step on" + "GitHub Pages",
+ default: true
+ },
+ "devHost": {
+ type: "string",
+ description: "host used during development",
+ default: "0.0.0.0"
+ },
+ "devPort": {
+ type: "number",
+ description: "port used during development",
+ default: 3333
+ },
+ "verbose": {
+ type: "boolean",
+ description: "flag to enable a more verbose output",
+ default: false
+ },
+ "dev": {
+ type: "boolean",
+ description: "flag to enable dev mode (hot loading)",
+ default: false
+ },
+ "production": {
+ type: "boolean",
+ description: "flag to enable production (optimized) mode",
+ default: false
+ },
+ "static": {
+ type: "boolean",
+ description: "flag to enable static build",
+ default: false
+ },
+ "server": {
+ type: "boolean",
+ description: "flag to enable development server",
+ default: false
+ },
+ "open": {
+ type: "boolean",
+ description: "flag to automatically open development server",
+ default: true
+ },
+ "cache": {
+ type: "boolean",
+ description: "flag to enable hard cache for webpack " + "(hard-source-webpack-plugin)",
+ default: false
+ },
+ "clientScripts": {
+ type: "boolean",
+ description: "flag to disable client side JavaScript in HTML files",
+ default: true
+ }
+};
\ No newline at end of file
diff --git a/lib/configurator/index.js b/lib/configurator/index.js
new file mode 100644
index 000000000..99ef1ef47
--- /dev/null
+++ b/lib/configurator/index.js
@@ -0,0 +1,96 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+exports.default = config;
+exports.testConfig = testConfig;
+
+var _path = require("path");
+
+var _chalk = require("chalk");
+
+var _chalk2 = _interopRequireDefault(_chalk);
+
+var _yargs = require("./yargs.js");
+
+var _yargs2 = _interopRequireDefault(_yargs);
+
+var _definitions = require("./definitions.js");
+
+var _definitions2 = _interopRequireDefault(_definitions);
+
+var _minimalValidator = require("./minimal-validator.js");
+
+var _minimalValidator2 = _interopRequireDefault(_minimalValidator);
+
+var _validators = require("./validators.js");
+
+var validators = _interopRequireWildcard(_validators);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
+// eslint-disable-next-line import/no-namespace
+
+
+function config() {
+ var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
+ _ref$argv = _ref.argv,
+ argv = _ref$argv === undefined ? [] : _ref$argv,
+ _ref$pkg = _ref.pkg,
+ pkg = _ref$pkg === undefined ? {} : _ref$pkg;
+
+ var userJSConfig = pkg.phenomic || {};
+
+ _yargs2.default.strict();
+
+ var defaultAndCLIconfig = _yargs2.default.parse(argv);
+
+ // delete unwanted yargs parameters
+ delete defaultAndCLIconfig.$0;
+ delete defaultAndCLIconfig._;
+ delete defaultAndCLIconfig.help;
+ delete defaultAndCLIconfig.version;
+
+ // validate user parameters
+ var errors = [].concat(_toConsumableArray((0, _minimalValidator2.default)(userJSConfig, _definitions2.default)));
+
+ var config = _extends({}, defaultAndCLIconfig, userJSConfig, process.env.TESTING && userJSConfig.cwd === undefined && {
+ cwd: (0, _path.join)(__dirname, "__tests__")
+ });
+
+ // validation/adjustement for each options
+ Object.keys(validators).forEach(function (key) {
+ // eslint-disable-next-line import/namespace
+ validators[key]({
+ pkg: pkg,
+ config: config,
+ definitions: _definitions2.default,
+ errors: errors
+ });
+ });
+
+ if (errors.length > 0) {
+ var errorMessage = "\n⚠️ " + "phenomic: " + _chalk2.default.yellow("your config is invalid. Please fix the errors:") + "\n\n" + _chalk2.default.red("- " + errors.join("\n- ")) + "\n\n" + _chalk2.default.yellow("See 'Configuration' section in documentation.") + " " + "https://phenomic.io/docs/usage/configuration/";
+ if (process.env.TESTING) {
+ throw new Error(errorMessage);
+ }
+ // else
+ console.error(errorMessage);
+ process.exit(1);
+ }
+
+ return config;
+}
+
+function testConfig(cfg) {
+ return config({
+ pkg: { phenomic: cfg }
+ });
+}
\ No newline at end of file
diff --git a/lib/configurator/minimal-validator.js b/lib/configurator/minimal-validator.js
new file mode 100644
index 000000000..bb11b4be2
--- /dev/null
+++ b/lib/configurator/minimal-validator.js
@@ -0,0 +1,21 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
+
+exports.default = function (config, definitions) {
+ var errors = [];
+
+ Object.keys(config).forEach(function (key) {
+ if (!definitions[key]) {
+ errors.push("Unknow option '" + key + "'.");
+ } else if (definitions[key].type !== undefined && definitions[key].type !== _typeof(config[key])) {
+ errors.push("Wrong type for '" + key + "': expected '" + definitions[key].type + "', " + ("got '" + _typeof(config[key]) + "'."));
+ }
+ });
+
+ return errors;
+};
\ No newline at end of file
diff --git a/lib/configurator/validators.js b/lib/configurator/validators.js
new file mode 100644
index 000000000..3423d3a7a
--- /dev/null
+++ b/lib/configurator/validators.js
@@ -0,0 +1,35 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.production = exports.offline = exports.devPort = exports.baseUrl = exports.assets = undefined;
+
+var _assets2 = require("./validators/assets.js");
+
+var _assets3 = _interopRequireDefault(_assets2);
+
+var _baseUrl2 = require("./validators/baseUrl.js");
+
+var _baseUrl3 = _interopRequireDefault(_baseUrl2);
+
+var _devPort2 = require("./validators/devPort.js");
+
+var _devPort3 = _interopRequireDefault(_devPort2);
+
+var _offline2 = require("./validators/offline.js");
+
+var _offline3 = _interopRequireDefault(_offline2);
+
+var _production2 = require("./validators/production.js");
+
+var _production3 = _interopRequireDefault(_production2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.assets = _assets3.default;
+exports.baseUrl = _baseUrl3.default;
+exports.devPort = _devPort3.default;
+exports.offline = _offline3.default; // ! must be after baseUrl
+
+exports.production = _production3.default;
\ No newline at end of file
diff --git a/lib/configurator/validators/assets.js b/lib/configurator/validators/assets.js
new file mode 100644
index 000000000..d1329987e
--- /dev/null
+++ b/lib/configurator/validators/assets.js
@@ -0,0 +1,69 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
+
+exports.default = function (_ref) {
+ var config = _ref.config,
+ errors = _ref.errors;
+
+ // Prepare config.assets path and route
+ if (config.assets) {
+
+ // normalize simple string options
+ if (["boolean", "string", "object"].indexOf(_typeof(config.assets)) < 0) {
+ errors.push("You provided a " + _typeof(config.assets) + " for 'assets' option." + "This option accept a boolean value, a string, or an object.");
+ } else if (_typeof(config.assets) === "object" && (typeof config.assets.path !== "string" || typeof config.assets.route !== "string")) {
+ var configAssets = config.assets;
+ errors.push("You provided an object for 'assets' option." + "You need to provide 2 keys: " + "'path' (string, path of your assets, relative to 'source') " + "and 'route' (string, path of your assets folder in the destination)." + "\n" + "You provided the following keys: " + Object.keys(configAssets).map(function (k) {
+ return "'" + k + "' (" + _typeof(configAssets[k]) + ")";
+ }).toString());
+ } else {
+ if (typeof config.assets === "string") {
+ config.assets = {
+ path: config.assets,
+ route: config.assets
+ };
+ } else if (typeof config.assets === "boolean") {
+ // === true
+ config.assets = {
+ path: _definitions2.default.assets.default,
+ route: _definitions2.default.assets.default
+ };
+ }
+
+ var _configAssets = config.assets;
+ // adjust path and validate
+ config.assets = {
+ path: (0, _path.join)(config.cwd, config.source, _configAssets.path),
+ route: _configAssets.route
+ };
+
+ // Test folder
+ try {
+ var stats = _fs2.default.lstatSync(config.assets.path);
+ if (!stats.isDirectory()) {
+ // Just throw a dump error
+ throw new Error("This is not a folder");
+ }
+ } catch (e) {
+ errors.push(config.assets.path + " doesn't exist or isn't a folder. " + "Please check your 'assets' configuration. " + "Note that if you don't need this option, " + "you can set it up to `false`.");
+ }
+ }
+ }
+};
+
+var _path = require("path");
+
+var _fs = require("fs");
+
+var _fs2 = _interopRequireDefault(_fs);
+
+var _definitions = require("../definitions.js");
+
+var _definitions2 = _interopRequireDefault(_definitions);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
\ No newline at end of file
diff --git a/lib/configurator/validators/baseUrl.js b/lib/configurator/validators/baseUrl.js
new file mode 100644
index 000000000..9fee91bd1
--- /dev/null
+++ b/lib/configurator/validators/baseUrl.js
@@ -0,0 +1,32 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+exports.default = function (_ref) {
+ var pkg = _ref.pkg,
+ config = _ref.config;
+
+ var devUrl = "http://" + config.devHost + ":" + config.devPort + "/";
+ var prodBaseUrl = (0, _url.parse)(pkg.homepage ? pkg.homepage : devUrl);
+ config.baseUrl = config.production ? prodBaseUrl : _extends({}, (0, _url.parse)(devUrl), {
+ // get base from prod url
+ pathname: prodBaseUrl.path ? prodBaseUrl.path : "/"
+ });
+
+ config.baseUrl = (0, _index2.default)(config.baseUrl);
+
+ // Set basename to process.env for universal usage
+ process.env.PHENOMIC_USER_PATHNAME = config.baseUrl.pathname;
+};
+
+var _url = require("url");
+
+var _index = require("../../_utils/normalize-base-url/index.js");
+
+var _index2 = _interopRequireDefault(_index);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
\ No newline at end of file
diff --git a/lib/configurator/validators/devPort.js b/lib/configurator/validators/devPort.js
new file mode 100644
index 000000000..17e8b5cb4
--- /dev/null
+++ b/lib/configurator/validators/devPort.js
@@ -0,0 +1,18 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+exports.default = function (_ref) {
+ var config = _ref.config,
+ errors = _ref.errors;
+
+ var port = Math.trunc(config.devPort);
+
+ if (port > 0) {
+ config.devPort = port;
+ } else {
+ errors.push("`devPort` must be a legal http port number");
+ }
+};
\ No newline at end of file
diff --git a/lib/configurator/validators/offline.js b/lib/configurator/validators/offline.js
new file mode 100644
index 000000000..513536988
--- /dev/null
+++ b/lib/configurator/validators/offline.js
@@ -0,0 +1,110 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.defaultOfflineConfig = undefined;
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
+
+var _url = require("url");
+
+var _chalk = require("chalk");
+
+var _log = require("../../_utils/log");
+
+var _log2 = _interopRequireDefault(_log);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var defaultOfflineConfig = exports.defaultOfflineConfig = {
+ serviceWorker: true,
+ appcache: true,
+ cachePatterns: {
+ onInstall: ["/", "phenomic.*"],
+ afterInstall: ["**", ":assets:"],
+ onDemand: [],
+ excludes: ["**/.*", "**/*.map", "**/*.html"]
+ }
+};
+
+var knownKeys = Object.keys(defaultOfflineConfig);
+
+exports.default = function (_ref) {
+ var pkg = _ref.pkg,
+ config = _ref.config,
+ errors = _ref.errors;
+
+
+ if (!config.offline) {
+ config.offline = false;
+ return;
+ }
+
+ if (config.offline === true) {
+ config.offlineConfig = defaultOfflineConfig;
+ } else if (_typeof(config.offline) !== "object") {
+ var keys = Object.keys(defaultOfflineConfig);
+ errors.push("Your provided an '" + _typeof(config.offline) + "'" + "for 'phenomic.offline'." + "This option accepts a boolean or an object" + ("with " + keys.length + " keys: ") + keys.join(", "));
+
+ return;
+ } else {
+ var userOfflineConfig = config.offline;
+
+ var allKeys = Object.keys(userOfflineConfig);
+ var incorrectKeys = allKeys.filter(function (key) {
+ return knownKeys.indexOf(key) === -1;
+ });
+ if (incorrectKeys.length) {
+ errors.push("You provided some key(s) " + "for 'phenomic.offline' option " + "that are not recognized " + ("(" + incorrectKeys.join(", ") + "). ") + "");
+ }
+
+ if (typeof userOfflineConfig.serviceWorker !== "boolean") {
+ errors.push("You provided an incorrect type" + (" ('" + _typeof(userOfflineConfig.serviceWorker) + "') ") + "for 'phenomic.offline.serviceWorker' option. " + "This option accepts a boolean value.");
+ }
+
+ if (typeof userOfflineConfig.appcache !== "boolean") {
+ errors.push("You provided an incorrect type" + (" ('" + _typeof(userOfflineConfig.appcache) + "') ") + "for 'phenomic.offline.appcache' option. " + "This option accepts a boolean value.");
+ }
+
+ // Validate patterns
+ var cachePatternsKeys = Object.keys(defaultOfflineConfig.cachePatterns);
+ var error = void 0;
+ if (_typeof(userOfflineConfig.cachePatterns) !== "object") {
+ error = "You provided an incorrect type" + (" ('" + _typeof(userOfflineConfig.cachePatterns) + "') ") + "for 'phenomic.offline.cachePatterns' option. ";
+ } else {
+ var _incorrectKeys = Object.keys(userOfflineConfig.cachePatterns).filter(function (key) {
+ return !(cachePatternsKeys.indexOf(key) > -1) || !Array.isArray(userOfflineConfig.cachePatterns[key]);
+ });
+ if (_incorrectKeys.length) {
+ error = "You provided some key(s) " + "for 'phenomic.offline.cachePatterns' option " + "that are not recognized or with incorrect types " + ("(" + _incorrectKeys.join(", ") + "). ") + "";
+ }
+ }
+ if (error) {
+ errors.push(error + "This option accepts a object with " + ("with " + cachePatternsKeys.length + " keys: ") + cachePatternsKeys.join(", ") + " " + "that accept array of glob patterns.");
+ }
+
+ // Merge config with default config
+ config.offlineConfig = _extends({}, defaultOfflineConfig, userOfflineConfig, {
+ cachePatterns: _extends({}, defaultOfflineConfig.cachePatterns, userOfflineConfig.cachePatterns)
+ });
+ }
+
+ if (pkg.homepage && (0, _url.parse)(pkg.homepage).protocol !== "https:" && config.offlineConfig.serviceWorker) {
+ console.warn((0, _chalk.yellow)("ServiceWorker (for Offline access) only works with HTTPS protocol." + "You are currently using HTTP, so ServiceWorker will be ignored by " + "browsers."));
+ }
+
+ // Disable offline for development if user defined offline config
+ if (config.dev && config.offline && !config.forceOffline) {
+ config.offline = false;
+ config.offlineConfig = {
+ serviceWorker: false,
+ appcache: false,
+ cachePatterns: {}
+ };
+ (0, _log2.default)((0, _chalk.gray)("Offline support disabled during development " + "(to avoid some false positives)"), "warning");
+ return;
+ }
+};
\ No newline at end of file
diff --git a/lib/configurator/validators/production.js b/lib/configurator/validators/production.js
new file mode 100644
index 000000000..3de3428d1
--- /dev/null
+++ b/lib/configurator/validators/production.js
@@ -0,0 +1,18 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+exports.default = function (_ref) {
+ var pkg = _ref.pkg,
+ config = _ref.config,
+ errors = _ref.errors;
+
+ if (config.production) {
+ process.env.NODE_ENV = "production";
+ if (!pkg.homepage) {
+ errors.push("Your package.json require a 'homepage' field.");
+ }
+ }
+};
\ No newline at end of file
diff --git a/lib/configurator/yargs.js b/lib/configurator/yargs.js
new file mode 100644
index 000000000..a5360d788
--- /dev/null
+++ b/lib/configurator/yargs.js
@@ -0,0 +1,53 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _yargs = require("yargs");
+
+var _yargs2 = _interopRequireDefault(_yargs);
+
+var _package = require("../../package.json");
+
+var _definitions = require("./definitions.js");
+
+var _definitions2 = _interopRequireDefault(_definitions);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+// import * as validators from "./validators.js"
+
+_yargs2.default.version(function () {
+ return _package.version;
+}).help().showHelpOnFail().epilogue("For more information about the configuration, " + "https://phenomic.io/");
+
+Object.keys(_definitions2.default).forEach(function (optName) {
+ var option = _definitions2.default[optName];
+
+ // for now all flags are common
+ _yargs2.default.global(optName);
+
+ // check type
+ // eg: yargs.boolean(someflag) to ensure that the type is correct
+ if (option.type && _yargs2.default[option.type]) {
+ _yargs2.default[option.type](optName);
+ }
+
+ if (option.default) {
+ _yargs2.default.default(optName, option.default);
+ }
+
+ if (option.description) {
+ _yargs2.default.describe(optName, option.description);
+ }
+
+ // made by hand for now, we might revisit option this later
+ // if (validators[optName]) {
+ // yargs.check(() => {
+ //
+ // })
+ // }
+});
+
+exports.default = _yargs2.default;
\ No newline at end of file
diff --git a/lib/enhance-collection/index.js b/lib/enhance-collection/index.js
new file mode 100644
index 000000000..6f394ebd6
--- /dev/null
+++ b/lib/enhance-collection/index.js
@@ -0,0 +1,192 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+exports.filter = filter;
+exports.sort = sort;
+exports.reverse = reverse;
+exports.limit = limit;
+exports.addSiblingReferences = addSiblingReferences;
+
+var _lruMemoize = require("lru-memoize");
+
+var _lruMemoize2 = _interopRequireDefault(_lruMemoize);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
+
+var defaultConsole = console;
+
+exports.default = (0, _lruMemoize2.default)(100)(enhanceCollection);
+
+
+function enhanceCollection(collection, options) {
+ var console = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : defaultConsole;
+
+ options = _extends({}, options);
+
+ if (options.filter) {
+ collection = filter(collection, [options.filter], console);
+ }
+
+ if (options.filters) {
+ collection = filter(collection, options.filters, console);
+ }
+
+ if (options.sort) {
+ collection = sort(collection, options.sort);
+ }
+
+ if (options.reverse) {
+ collection = reverse(collection);
+ }
+
+ if (options.limit) {
+ collection = limit(collection, options.limit);
+ }
+
+ if (options.addSiblingReferences) {
+ collection = addSiblingReferences(collection);
+ }
+
+ return collection;
+}
+
+function filter(collection, filters) {
+ var console = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : defaultConsole;
+
+ return collection.reduce(function (acc, item) {
+ var include = true;
+
+ var _loop = function _loop(_filter) {
+ switch (typeof _filter === "undefined" ? "undefined" : _typeof(_filter)) {
+ case "function":
+ {
+ var flag = _filter(item);
+ if (typeof flag !== "boolean") {
+ console.warn("Function passed to filter item in 'enhanceCollection' should " + "return a boolean value. \n" + ("You returned '" + (typeof flag === "undefined" ? "undefined" : _typeof(flag)) + "'."));
+ }
+ if (!flag) {
+ include = false;
+ }
+ break;
+ }
+ case "object":
+ {
+ var keys = Object.keys(_filter);
+ if (!keys.reduce(function (acc, key) {
+ return acc && (typeof _filter[key] === "string" && item[key] === _filter[key] || _filter[key] instanceof RegExp && item[key] && item[key].match(_filter[key]));
+ }, true)) {
+ include = false;
+ }
+ break;
+ }
+ case "string":
+ default:
+ if (!item[_filter]) {
+ include = false;
+ }
+ break;
+ }
+
+ // break asap
+ if (!include) {
+ return "break";
+ }
+ };
+
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = filters[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var _filter = _step.value;
+
+ var _ret = _loop(_filter);
+
+ if (_ret === "break") break;
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator.return) {
+ _iterator.return();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ if (include) {
+ acc.push(item);
+ }
+
+ return acc;
+ }, []);
+}
+
+function sort(collection) {
+ var sort = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "date";
+
+ collection = [].concat(_toConsumableArray(collection));
+
+ if (typeof sort === "function") {
+ collection.sort(sort);
+ } else {
+ collection.sort(function (a, b) {
+ a = a[sort];
+ b = b[sort];
+ if (!a && !b) return 0;
+ if (!a) return -1;
+ if (!b) return 1;
+ if (b > a) return -1;
+ if (a > b) return 1;
+ return 0;
+ });
+ }
+
+ return collection;
+}
+
+function reverse(collection) {
+ collection = [].concat(_toConsumableArray(collection));
+ collection.reverse();
+ return collection;
+}
+
+function limit(collection, limit) {
+ return collection.slice(0, limit);
+}
+
+function addSiblingReferences(collection) {
+ var last = collection.length - 1;
+ // TODO: Use commented code when flow can understand it
+ // return collection.map((item, i) => ({
+ // ...item,
+ // ...(0 != i) && { previous: collection[i-1] },
+ // ...(last != i) && { next: collection[i+1] },
+ // }))
+ return collection.map(function (item, i) {
+ var newItem = _extends({}, item);
+ if (0 != i) {
+ newItem.previous = collection[i - 1];
+ }
+ if (last != i) {
+ newItem.next = collection[i + 1];
+ }
+
+ return newItem;
+ });
+}
\ No newline at end of file
diff --git a/lib/eslint-config-recommended/index.js b/lib/eslint-config-recommended/index.js
new file mode 100644
index 000000000..04ccc638b
--- /dev/null
+++ b/lib/eslint-config-recommended/index.js
@@ -0,0 +1,20 @@
+"use strict";
+
+module.exports = {
+ "parser": "babel-eslint",
+ "extends": ["eslint:recommended", "plugin:react/recommended"],
+ "env": {
+ "browser": true,
+ "node": true
+ },
+ "plugins": ["react"],
+ "parserOptions": {
+ "ecmaVersion": 6,
+ "sourceType": "module",
+ "ecmaFeatures": {
+ "jsx": true,
+ "generators": true,
+ "experimentalObjectRestSpread": true
+ }
+ }
+};
\ No newline at end of file
diff --git a/lib/index.js b/lib/index.js
new file mode 100644
index 000000000..847263754
--- /dev/null
+++ b/lib/index.js
@@ -0,0 +1,45 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _PageContainer = require("./components/PageContainer");
+
+Object.defineProperty(exports, "PageContainer", {
+ enumerable: true,
+ get: function get() {
+ return _interopRequireDefault(_PageContainer).default;
+ }
+});
+
+var _BodyContainer = require("./components/BodyContainer");
+
+Object.defineProperty(exports, "BodyContainer", {
+ enumerable: true,
+ get: function get() {
+ return _interopRequireDefault(_BodyContainer).default;
+ }
+});
+
+var _Link = require("./components/Link");
+
+Object.defineProperty(exports, "Link", {
+ enumerable: true,
+ get: function get() {
+ return _interopRequireDefault(_Link).default;
+ }
+});
+
+var _urlJoin = require("url-join");
+
+Object.defineProperty(exports, "joinUri", {
+ enumerable: true,
+ get: function get() {
+ return _interopRequireDefault(_urlJoin).default;
+ }
+});
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var phenomicLoader = exports.phenomicLoader = "phenomic/lib/loader";
\ No newline at end of file
diff --git a/lib/loader-feed-webpack-plugin/feed.js b/lib/loader-feed-webpack-plugin/feed.js
new file mode 100644
index 000000000..59b0c4f59
--- /dev/null
+++ b/lib/loader-feed-webpack-plugin/feed.js
@@ -0,0 +1,47 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; // @todo @ flow
+
+var _url = require("url");
+
+var _url2 = _interopRequireDefault(_url);
+
+var _rss = require("rss");
+
+var _rss2 = _interopRequireDefault(_rss);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.default = function () {
+ var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+
+ var _feedOptions$options = _extends({
+ feedOptions: {}
+ }, options),
+ feedOptions = _feedOptions$options.feedOptions,
+ destination = _feedOptions$options.destination,
+ collection = _feedOptions$options.collection,
+ xmlOptions = _feedOptions$options.xmlOptions;
+
+ if (!feedOptions.site_url) {
+ throw new Error("feed site_url must be configured");
+ }
+
+ if (feedOptions.feed_url == null) {
+ feedOptions.feed_url = _url2.default.resolve(feedOptions.site_url, destination);
+ }
+
+ var feed = new _rss2.default(feedOptions);
+ collection.forEach(function (item) {
+ feed.item(_extends({}, item, {
+ url: item.__url ? _url2.default.resolve(feedOptions.site_url, item.__url) : undefined
+
+ }));
+ });
+
+ return feed.xml(xmlOptions);
+};
\ No newline at end of file
diff --git a/lib/loader-feed-webpack-plugin/index.js b/lib/loader-feed-webpack-plugin/index.js
new file mode 100644
index 000000000..ce1e1504f
--- /dev/null
+++ b/lib/loader-feed-webpack-plugin/index.js
@@ -0,0 +1,69 @@
+"use strict";
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+// module.exports is used
+// eslint-disable-next-line import/default
+
+
+var _webpackSources = require("webpack-sources");
+
+var _enhanceCollection = require("../enhance-collection");
+
+var _enhanceCollection2 = _interopRequireDefault(_enhanceCollection);
+
+var _minify = require("../loader/minify.js");
+
+var _minify2 = _interopRequireDefault(_minify);
+
+var _plugin = require("../loader/plugin.js");
+
+var _plugin2 = _interopRequireDefault(_plugin);
+
+var _feed = require("./feed");
+
+var _feed2 = _interopRequireDefault(_feed);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function PhenomicLoaderFeedWebpackPlugin(options) {
+ this.options = options;
+}
+
+PhenomicLoaderFeedWebpackPlugin.prototype.apply = function (compiler) {
+ var _this = this;
+
+ compiler.plugin("compilation", function (compilation /* , params */) {
+ compilation.plugin("additional-assets", function (callback) {
+ if (!_plugin2.default.collection) {
+ throw new Error("Missing Phenomic collection in webpack compilation object. " + "This probably means you are playing with fire.");
+ }
+ var collection = (0, _minify2.default)(_plugin2.default.collection);
+
+ var feeds = _this.options.feeds || [];
+ var feedsOptions = _this.options.feedsOptions || {};
+ Object.keys(feeds).forEach(function (name) {
+ var _feeds$name = feeds[name],
+ feedOptions = _feeds$name.feedOptions,
+ collectionOptions = _feeds$name.collectionOptions;
+
+ compilation.assets[name] = new _webpackSources.RawSource((0, _feed2.default)({
+ feedOptions: _extends({}, feedsOptions, feedOptions),
+ destination: name,
+ collection: (0, _enhanceCollection2.default)(collection, collectionOptions).map(function (item) {
+ var fullItem = _plugin2.default.collection.find(function (fullItem) {
+ return item.__url === fullItem.__url;
+ });
+ return _extends({}, item, {
+ // null should not happen, but flow ask for secure code :)
+ description: fullItem ? fullItem.body : null
+ });
+ })
+ }));
+ });
+
+ callback();
+ });
+ });
+};
+
+module.exports = PhenomicLoaderFeedWebpackPlugin;
\ No newline at end of file
diff --git a/lib/loader-plugin-init-body-property-from-content/index.js b/lib/loader-plugin-init-body-property-from-content/index.js
new file mode 100644
index 000000000..20f1cded4
--- /dev/null
+++ b/lib/loader-plugin-init-body-property-from-content/index.js
@@ -0,0 +1,16 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+exports.default = function (_ref) {
+ var result = _ref.result,
+ frontMatter = _ref.frontMatter;
+
+ return _extends({}, result, {
+ body: frontMatter.content
+ });
+};
\ No newline at end of file
diff --git a/lib/loader-plugin-init-head-property-from-config/index.js b/lib/loader-plugin-init-head-property-from-config/index.js
new file mode 100644
index 000000000..4c34261a6
--- /dev/null
+++ b/lib/loader-plugin-init-head-property-from-config/index.js
@@ -0,0 +1,16 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+exports.default = function (_ref) {
+ var result = _ref.result,
+ options = _ref.options;
+
+ return _extends({}, result, options && options.defaultHead && {
+ head: _extends({}, options.defaultHead, result.head)
+ });
+};
\ No newline at end of file
diff --git a/lib/loader-plugin-init-head-property-from-content/index.js b/lib/loader-plugin-init-head-property-from-content/index.js
new file mode 100644
index 000000000..035da5b72
--- /dev/null
+++ b/lib/loader-plugin-init-head-property-from-content/index.js
@@ -0,0 +1,16 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+exports.default = function (_ref) {
+ var result = _ref.result,
+ frontMatter = _ref.frontMatter;
+
+ return _extends({}, result, {
+ head: _extends({}, result.head, JSON.parse(JSON.stringify(frontMatter.data)))
+ });
+};
\ No newline at end of file
diff --git a/lib/loader-plugin-init-raw-property-from-content/index.js b/lib/loader-plugin-init-raw-property-from-content/index.js
new file mode 100644
index 000000000..06024656f
--- /dev/null
+++ b/lib/loader-plugin-init-raw-property-from-content/index.js
@@ -0,0 +1,16 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+exports.default = function (_ref) {
+ var result = _ref.result,
+ frontMatter = _ref.frontMatter;
+
+ return _extends({}, result, {
+ raw: frontMatter.orig
+ });
+};
\ No newline at end of file
diff --git a/lib/loader-plugin-init-rawBody-property-from-content/index.js b/lib/loader-plugin-init-rawBody-property-from-content/index.js
new file mode 100644
index 000000000..0745bc495
--- /dev/null
+++ b/lib/loader-plugin-init-rawBody-property-from-content/index.js
@@ -0,0 +1,16 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+exports.default = function (_ref) {
+ var result = _ref.result,
+ frontMatter = _ref.frontMatter;
+
+ return _extends({}, result, {
+ rawBody: frontMatter.content
+ });
+};
\ No newline at end of file
diff --git a/lib/loader-plugin-markdown-init-head.description-property-from-content/index.js b/lib/loader-plugin-markdown-init-head.description-property-from-content/index.js
new file mode 100644
index 000000000..218be63ac
--- /dev/null
+++ b/lib/loader-plugin-markdown-init-head.description-property-from-content/index.js
@@ -0,0 +1,56 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _remark = require("remark");
+
+var _remark2 = _interopRequireDefault(_remark);
+
+var _stripMarkdown = require("strip-markdown");
+
+var _stripMarkdown2 = _interopRequireDefault(_stripMarkdown);
+
+var _prune = require("./prune");
+
+var _prune2 = _interopRequireDefault(_prune);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var defaultOpts = {
+ pruneLength: 140,
+ pruneString: "…"
+};
+
+function description(text) {
+ var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+
+ opts = _extends({}, defaultOpts, opts);
+
+ if (opts.pruneLength === 0) {
+ console.warn("You defined 'description.pruneLength' of phenomic loader " + "with an zero value. This does not make sense, " + ("so the default value " + defaultOpts.pruneLength + " has been used."));
+
+ opts.pruneLength = defaultOpts.pruneLength;
+ }
+
+ return (0, _prune2.default)((0, _remark2.default)().use(_stripMarkdown2.default).process(text).toString().replace(/\n+/g, " ") // Avoid useless new lines
+ .trim(), opts.pruneLength, opts.pruneString);
+}
+
+exports.default = function (_ref) {
+ var result = _ref.result,
+ frontMatter = _ref.frontMatter,
+ options = _ref.options;
+
+ if (result.head && result.head.description) {
+ return result;
+ }
+ return _extends({}, result, {
+ head: _extends({}, result.head, {
+ description: description(frontMatter.content, options)
+ })
+ });
+};
\ No newline at end of file
diff --git a/lib/loader-plugin-markdown-init-head.description-property-from-content/prune/index.js b/lib/loader-plugin-markdown-init-head.description-property-from-content/prune/index.js
new file mode 100644
index 000000000..15af4c48c
--- /dev/null
+++ b/lib/loader-plugin-markdown-init-head.description-property-from-content/prune/index.js
@@ -0,0 +1,17 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+exports.default = function (s, maxLength) {
+ var end = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "…";
+
+ var trimmed = s.substr(0, maxLength);
+
+ if (trimmed === s) {
+ return s;
+ }
+
+ return trimmed.substr(0, Math.min(trimmed.length, trimmed.lastIndexOf(" "))) + end;
+};
\ No newline at end of file
diff --git a/lib/loader-plugin-markdown-transform-body-property-to-html/index.js b/lib/loader-plugin-markdown-transform-body-property-to-html/index.js
new file mode 100644
index 000000000..984fd8631
--- /dev/null
+++ b/lib/loader-plugin-markdown-transform-body-property-to-html/index.js
@@ -0,0 +1,72 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _remark = require("remark");
+
+var _remark2 = _interopRequireDefault(_remark);
+
+var _remarkSlug = require("remark-slug");
+
+var _remarkSlug2 = _interopRequireDefault(_remarkSlug);
+
+var _remarkAutolinkHeadings = require("remark-autolink-headings");
+
+var _remarkAutolinkHeadings2 = _interopRequireDefault(_remarkAutolinkHeadings);
+
+var _remarkHighlight = require("remark-highlight.js");
+
+var _remarkHighlight2 = _interopRequireDefault(_remarkHighlight);
+
+var _remarkToc = require("remark-toc");
+
+var _remarkToc2 = _interopRequireDefault(_remarkToc);
+
+var _remarkHtml = require("remark-html");
+
+var _remarkHtml2 = _interopRequireDefault(_remarkHtml);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function mdify(text) {
+ return (0, _remark2.default)()
+ // https://github.com/wooorm/remark-slug
+ .use(_remarkSlug2.default)
+
+ // https://github.com/ben-eb/remark-autolink-headings
+ .use(_remarkAutolinkHeadings2.default, {
+ content: {
+ type: "text",
+ value: "#"
+ },
+ linkProperties: {
+ className: "phenomic-HeadingAnchor"
+ }
+ })
+
+ // https://github.com/wooorm/remark-html
+ .use(_remarkHtml2.default, { entities: "escape" })
+
+ // https://github.com/ben-eb/remark-highlight.js
+ .use(_remarkHighlight2.default)
+
+ // https://github.com/wooorm/remark-toc
+ .use(_remarkToc2.default)
+
+ // render
+ .process(text, {
+ commonmark: true
+ }).toString();
+}
+
+exports.default = function (_ref) {
+ var result = _ref.result;
+
+ return _extends({}, result, {
+ body: mdify(result.body)
+ });
+};
\ No newline at end of file
diff --git a/lib/loader-preset-default/index.js b/lib/loader-preset-default/index.js
new file mode 100644
index 000000000..dba4250a4
--- /dev/null
+++ b/lib/loader-preset-default/index.js
@@ -0,0 +1,23 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _loaderPluginInitHeadPropertyFromConfig = require("../loader-plugin-init-head-property-from-config");
+
+var _loaderPluginInitHeadPropertyFromConfig2 = _interopRequireDefault(_loaderPluginInitHeadPropertyFromConfig);
+
+var _loaderPluginInitHeadPropertyFromContent = require("../loader-plugin-init-head-property-from-content");
+
+var _loaderPluginInitHeadPropertyFromContent2 = _interopRequireDefault(_loaderPluginInitHeadPropertyFromContent);
+
+var _loaderPluginInitBodyPropertyFromContent = require("../loader-plugin-init-body-property-from-content");
+
+var _loaderPluginInitBodyPropertyFromContent2 = _interopRequireDefault(_loaderPluginInitBodyPropertyFromContent);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var plugins = [_loaderPluginInitHeadPropertyFromConfig2.default, _loaderPluginInitHeadPropertyFromContent2.default, _loaderPluginInitBodyPropertyFromContent2.default];
+
+exports.default = plugins;
\ No newline at end of file
diff --git a/lib/loader-preset-markdown/index.js b/lib/loader-preset-markdown/index.js
new file mode 100644
index 000000000..3f4945d12
--- /dev/null
+++ b/lib/loader-preset-markdown/index.js
@@ -0,0 +1,23 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _loaderPresetDefault = require("../loader-preset-default");
+
+var _loaderPresetDefault2 = _interopRequireDefault(_loaderPresetDefault);
+
+var _loaderPluginMarkdownInitHead = require("../loader-plugin-markdown-init-head.description-property-from-content");
+
+var _loaderPluginMarkdownInitHead2 = _interopRequireDefault(_loaderPluginMarkdownInitHead);
+
+var _loaderPluginMarkdownTransformBodyPropertyToHtml = require("../loader-plugin-markdown-transform-body-property-to-html");
+
+var _loaderPluginMarkdownTransformBodyPropertyToHtml2 = _interopRequireDefault(_loaderPluginMarkdownTransformBodyPropertyToHtml);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
+
+exports.default = [].concat(_toConsumableArray(_loaderPresetDefault2.default), [_loaderPluginMarkdownInitHead2.default, _loaderPluginMarkdownTransformBodyPropertyToHtml2.default]);
\ No newline at end of file
diff --git a/lib/loader-sitemap-webpack-plugin/index.js b/lib/loader-sitemap-webpack-plugin/index.js
new file mode 100644
index 000000000..07d14a25d
--- /dev/null
+++ b/lib/loader-sitemap-webpack-plugin/index.js
@@ -0,0 +1,63 @@
+"use strict";
+
+var _webpackSources = require("webpack-sources");
+
+var _sitemap = require("sitemap");
+
+var _sitemap2 = _interopRequireDefault(_sitemap);
+
+var _enhanceCollection = require("../enhance-collection");
+
+var _enhanceCollection2 = _interopRequireDefault(_enhanceCollection);
+
+var _minify = require("../loader/minify.js");
+
+var _minify2 = _interopRequireDefault(_minify);
+
+var _plugin = require("../loader/plugin.js");
+
+var _plugin2 = _interopRequireDefault(_plugin);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function PhenomicLoaderSitemapWebpackPlugin(options) {
+ this.options = options;
+}
+// module.exports is used
+// eslint-disable-next-line import/default
+
+
+PhenomicLoaderSitemapWebpackPlugin.prototype.apply = function (compiler) {
+ var _this = this;
+
+ compiler.plugin("compilation", function (compilation /* , params */) {
+ compilation.plugin("additional-assets", function (callback) {
+ if (!_plugin2.default.collection) {
+ throw new Error("Missing Phenomic collection in webpack compilation object. " + "This probably means you are playing with fire.");
+ }
+
+ var collection = (0, _minify2.default)(_plugin2.default.collection);
+
+ var _ref = _this.options || {},
+ site_url = _ref.site_url,
+ collectionOptions = _ref.collectionOptions;
+
+ if (!site_url) {
+ throw new Error("Missing `site_url` option in sitemap configuration. ");
+ }
+
+ var sitemap = _sitemap2.default.createSitemap({
+ hostname: site_url,
+ urls: (0, _enhanceCollection2.default)(collection, collectionOptions).map(function (item) {
+ return { url: item.__url };
+ })
+ });
+
+ compilation.assets["sitemap.xml"] = new _webpackSources.RawSource(sitemap.toString());
+
+ callback();
+ });
+ });
+};
+
+module.exports = PhenomicLoaderSitemapWebpackPlugin;
\ No newline at end of file
diff --git a/lib/loader/index.js b/lib/loader/index.js
new file mode 100644
index 000000000..1bffaf9cc
--- /dev/null
+++ b/lib/loader/index.js
@@ -0,0 +1,95 @@
+"use strict";
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _fs = require("fs");
+
+var _fs2 = _interopRequireDefault(_fs);
+
+var _path = require("path");
+
+var _path2 = _interopRequireDefault(_path);
+
+var _loaderUtils = require("loader-utils");
+
+var _loaderUtils2 = _interopRequireDefault(_loaderUtils);
+
+var _grayMatter = require("gray-matter");
+
+var _grayMatter2 = _interopRequireDefault(_grayMatter);
+
+var _pathToUri = require("../_utils/path-to-uri");
+
+var _pathToUri2 = _interopRequireDefault(_pathToUri);
+
+var _urlify = require("../_utils/urlify");
+
+var _urlify2 = _interopRequireDefault(_urlify);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+// Use the path of the loader directory to avoid conflicts on the loaderContext
+var NS = _fs2.default.realpathSync(__dirname);
+
+var loader = function loader(input) {
+ var _this = this;
+
+ var webpackInstance = this;
+
+ loader.getCollection = function () {
+ return _this[NS];
+ };
+
+ var options = _extends({}, webpackInstance.options.phenomic, _loaderUtils2.default.getOptions(webpackInstance));
+
+ // removed
+ if (options.feeds) {
+ throw new Error("Phenomic loader `feed` option has been changed since 0.17.0. " + "The changelog was not mentionning this breaking change. " + "Sorry about that. " + "Please visit https://phenomic.io/docs/usage/feeds/ to know how to " + "migrate (spoiler: it's easy). ");
+ }
+
+ var context = options.context || webpackInstance.options.context;
+ var plugins = options.plugins || require("../loader-preset-markdown").default;
+
+ var relativePath = _path2.default.relative(context, webpackInstance.resourcePath);
+
+ var frontMatter = (0, _grayMatter2.default)(input);
+ var pluginsResult = plugins.reduce(function (result, plugin) {
+ return plugin({
+ frontMatter: frontMatter,
+ result: result,
+ options: options
+ });
+ }, {});
+
+ var tmpUrl = (0, _urlify2.default)(pluginsResult.head && pluginsResult.head.route
+ // custom route
+ ? pluginsResult.head.route
+ // default route
+ : relativePath);
+ tmpUrl = tmpUrl.substring(0, 1) === "/" ? tmpUrl.slice(1) : tmpUrl;
+
+ var url = (0, _urlify2.default)(tmpUrl);
+ var resourceUrl = (0, _urlify2.default)(tmpUrl, true);
+ var contentHash = _loaderUtils2.default.getHashDigest(input);
+ var dataUrl = resourceUrl + "." + contentHash + ".json";
+
+ var metadata = {
+ __filename: (0, _pathToUri2.default)(relativePath),
+ __url: (0, _pathToUri2.default)("/", url),
+ __resourceUrl: (0, _pathToUri2.default)("/", resourceUrl),
+ __dataUrl: (0, _pathToUri2.default)("/", dataUrl)
+ };
+
+ var result = _extends({}, pluginsResult, metadata);
+
+ webpackInstance.emitFile(dataUrl, JSON.stringify(result));
+
+ if (typeof webpackInstance[NS] !== "function") {
+ throw new Error("You are using phenomic loader without the corresponding plugin. " + "This plugin should be added automatically by Phenomic, so if you are " + "facing this issue, you are probably playing with the fire. " + "To get more information, you can reach us on our community chat. " + "https://phenomic.io/");
+ }
+ webpackInstance[NS](result);
+
+ return "module.exports = " + JSON.stringify((0, _pathToUri2.default)("/", dataUrl));
+};
+
+module.exports = loader;
\ No newline at end of file
diff --git a/lib/loader/minify.js b/lib/loader/minify.js
new file mode 100644
index 000000000..817f9e37c
--- /dev/null
+++ b/lib/loader/minify.js
@@ -0,0 +1,24 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
+
+exports.default = function (collection) {
+ if (!Array.isArray(collection)) {
+ throw new Error("minify expect a valid collection instead of " + (typeof collection === "undefined" ? "undefined" : _typeof(collection)));
+ }
+
+ return collection.map(function (item) {
+ return _extends({}, item.head, {
+ __filename: item.__filename,
+ __url: item.__url,
+ __resourceUrl: item.__resourceUrl,
+ __dataUrl: item.__dataUrl
+ });
+ });
+};
\ No newline at end of file
diff --git a/lib/loader/plugin.js b/lib/loader/plugin.js
new file mode 100644
index 000000000..93fbdb3bb
--- /dev/null
+++ b/lib/loader/plugin.js
@@ -0,0 +1,50 @@
+"use strict";
+
+var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
+
+var _fs = require("fs");
+
+var _fs2 = _interopRequireDefault(_fs);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+// import { RawSource } from "webpack-sources"
+
+// Use the path of the plugin/loader directory to avoid conflicts on the
+// loaderContext
+var NS = _fs2.default.realpathSync(__dirname);
+
+function PhenomicLoaderWebpackPlugin() {}
+
+// Phenomic collection cache: it avoid to have to re-read content files
+// between client and static build!
+// We can do without this (eg: emitting a json + read the json later),
+// but this will be an issue to consider for big websites.
+PhenomicLoaderWebpackPlugin.collection = [];
+
+PhenomicLoaderWebpackPlugin.prototype.apply = function (compiler) {
+ compiler.plugin("compilation", function (compilation /* , params */) {
+ compilation.plugin("normal-module-loader", function (loaderContext, module) {
+ loaderContext[NS] = function (loaderResult) {
+ return module.meta[NS] = loaderResult;
+ };
+ });
+
+ compilation.plugin("additional-assets", function (callback) {
+ var results = compilation.modules.map(function (module) {
+ return module && module.meta && module.meta[NS];
+ }).filter(function (result) {
+ return result && (typeof result === "undefined" ? "undefined" : _typeof(result)) === "object";
+ });
+
+ PhenomicLoaderWebpackPlugin.collection = results;
+ // const collection = JSON.stringify(results, null, 2)
+ // compilation.assets["phenomic.collection.json"] =
+ // new RawSource(collection)
+
+ callback();
+ });
+ });
+};
+
+module.exports = PhenomicLoaderWebpackPlugin;
\ No newline at end of file
diff --git a/lib/redux/createStore/index.js b/lib/redux/createStore/index.js
new file mode 100644
index 000000000..c0449fabf
--- /dev/null
+++ b/lib/redux/createStore/index.js
@@ -0,0 +1,26 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+exports.default = function () {
+ var reducer = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+ var initialState = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+ var extraMiddlewares = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
+ var extraStoreEnhancers = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
+
+ var finalCreateStore = _redux.compose.apply(undefined, [_redux.applyMiddleware.apply(undefined, [_promise2.default].concat(_toConsumableArray(extraMiddlewares)))].concat(_toConsumableArray(extraStoreEnhancers)))(_redux.createStore);
+
+ return finalCreateStore(reducer, initialState);
+};
+
+var _redux = require("redux");
+
+var _promise = require("../middlewares/promise");
+
+var _promise2 = _interopRequireDefault(_promise);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
\ No newline at end of file
diff --git a/lib/redux/middlewares/promise.js b/lib/redux/middlewares/promise.js
new file mode 100644
index 000000000..754a2c785
--- /dev/null
+++ b/lib/redux/middlewares/promise.js
@@ -0,0 +1,41 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
+
+exports.default = promiseMiddleware;
+
+function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
+
+function promiseMiddleware() {
+ return function (next) {
+ return function (action) {
+ var promise = action.promise,
+ types = action.types,
+ rest = _objectWithoutProperties(action, ["promise", "types"]);
+
+ if (!promise) {
+ return next(action);
+ } else if (!promise.then) {
+ throw new Error("promiseMiddleware expects a promise object that implements then()");
+ }
+
+ var _types = _slicedToArray(types, 3),
+ REQUEST = _types[0],
+ SUCCESS = _types[1],
+ FAILURE = _types[2];
+
+ next(_extends({}, rest, { type: REQUEST }));
+ return promise.then(function (response) {
+ return next(_extends({}, rest, { response: response, type: SUCCESS }));
+ }, function (response) {
+ return next(_extends({}, rest, { response: response, type: FAILURE }));
+ });
+ };
+ };
+}
\ No newline at end of file
diff --git a/lib/redux/modules/README.md b/lib/redux/modules/README.md
new file mode 100644
index 000000000..d4728bb2b
--- /dev/null
+++ b/lib/redux/modules/README.md
@@ -0,0 +1 @@
+https://github.com/erikras/ducks-modular-redux
diff --git a/lib/redux/modules/index.js b/lib/redux/modules/index.js
new file mode 100644
index 000000000..65be3da48
--- /dev/null
+++ b/lib/redux/modules/index.js
@@ -0,0 +1,14 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.pages = undefined;
+
+var _pages2 = require("./pages");
+
+var _pages3 = _interopRequireDefault(_pages2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.pages = _pages3.default;
\ No newline at end of file
diff --git a/lib/redux/modules/pages.js b/lib/redux/modules/pages.js
new file mode 100644
index 000000000..077db4bb0
--- /dev/null
+++ b/lib/redux/modules/pages.js
@@ -0,0 +1,100 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.ERROR = exports.FORGET = exports.SET_TYPE = exports.SET = exports.GET = exports.NOOP = undefined;
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+exports.default = reducer;
+exports.get = get;
+exports.refresh = refresh;
+exports.setNotFound = setNotFound;
+
+var _simpleJsonFetch = require("simple-json-fetch");
+
+var _simpleJsonFetch2 = _interopRequireDefault(_simpleJsonFetch);
+
+var _pathToUri = require("../../_utils/path-to-uri");
+
+var _pathToUri2 = _interopRequireDefault(_pathToUri);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
+var NOOP = exports.NOOP = "phenomic/pages/NOOP";
+var GET = exports.GET = "phenomic/pages/GET";
+var SET = exports.SET = "phenomic/pages/SET";
+var SET_TYPE = exports.SET_TYPE = "phenomic/pages/SET_TYPE";
+var FORGET = exports.FORGET = "phenomic/pages/FORGET";
+var ERROR = exports.ERROR = "phenomic/pages/ERROR";
+
+// redux reducer
+function reducer() {
+ var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+ var action = arguments[1];
+
+
+ switch (action.type) {
+ case GET:
+ return _extends({}, state, _defineProperty({}, action.page, {
+ isLoading: true
+ }));
+
+ case SET:
+ {
+ var json = action.response.json;
+
+ return _extends({}, state, _defineProperty({}, action.page, _extends({}, json, {
+ type: json.head ? json.head.layout || json.head.type : undefined
+ })));
+ }
+
+ case FORGET:
+ return _extends({}, state, _defineProperty({}, action.page, undefined));
+
+ case ERROR:
+ return _extends({}, state, _defineProperty({}, action.page, action.response ? action.response.status ? {
+ error: action.response.status,
+ errorText: action.response.statusText
+ } : {
+ error: "Unexpected Error",
+ errorText: action.response.message || action.response.error && action.response.error.message ||
+ // here we are just in a deseperate case
+ "Seriously, this is weird. Please report this page."
+ } :
+ // no response, it's certainly a 404
+ {
+ error: 404
+ }));
+
+ default:
+ return state;
+ }
+}
+
+// redux actions
+function get(page, url) {
+ return {
+ types: [GET, SET, ERROR],
+ page: page,
+ promise: (0, _simpleJsonFetch2.default)((0, _pathToUri2.default)(process.env.PHENOMIC_USER_PATHNAME, url))
+ };
+}
+
+function refresh(page, url) {
+ return {
+ types: [NOOP, SET, ERROR],
+ page: page,
+ promise: (0, _simpleJsonFetch2.default)((0, _pathToUri2.default)(process.env.PHENOMIC_USER_PATHNAME, url))
+ };
+}
+
+function setNotFound(page) {
+ return {
+ type: ERROR,
+ page: page
+ };
+}
\ No newline at end of file
diff --git a/lib/static/index.js b/lib/static/index.js
new file mode 100644
index 000000000..81b97a5c9
--- /dev/null
+++ b/lib/static/index.js
@@ -0,0 +1,115 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+// eslint-disable-next-line import/no-namespace
+
+
+exports.setPageData = setPageData;
+exports.forgetPageData = forgetPageData;
+exports.writeHTMLFile = writeHTMLFile;
+exports.writeAllHTMLFiles = writeAllHTMLFiles;
+
+var _path = require("path");
+
+var _path2 = _interopRequireDefault(_path);
+
+var _fsPromise = require("fs-promise");
+
+var _fsPromise2 = _interopRequireDefault(_fsPromise);
+
+var _urlify = require("../_utils/urlify");
+
+var _urlify2 = _interopRequireDefault(_urlify);
+
+var _pages = require("../redux/modules/pages");
+
+var pagesActions = _interopRequireWildcard(_pages);
+
+var _routesToUrls = require("./routes-to-urls");
+
+var _routesToUrls2 = _interopRequireDefault(_routesToUrls);
+
+var _urlAsHtml = require("./url-as-html");
+
+var _urlAsHtml2 = _interopRequireDefault(_urlAsHtml);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+if (pagesActions.SET === undefined) {
+ throw new Error("pages SET action is undefined");
+}
+if (pagesActions.FORGET === undefined) {
+ throw new Error("pages FORGET action is undefined");
+}
+
+function setPageData(url, collection, store) {
+ var json = collection.find(function (item) {
+ return item.__url === url;
+ });
+ if (json) {
+ // prepare page data
+ store.dispatch({
+ type: pagesActions.SET,
+ page: url,
+ response: { json: json }
+ });
+ }
+}
+
+function forgetPageData(url, store) {
+ // forget page data to avoid having all pages data in all pages
+ store.dispatch({
+ type: pagesActions.FORGET,
+ page: url
+ });
+}
+
+function writeHTMLFile(filename, html) {
+ return _fsPromise2.default.mkdirs(_path2.default.dirname(filename)).then(function () {
+ return Promise.all([_fsPromise2.default.writeFile(filename, html)]);
+ }).then(function () {
+ return filename;
+ });
+}
+
+function writeAllHTMLFiles(options, testing) {
+ var routes = options.routes,
+ collection = options.collection,
+ destination = options.destination,
+ store = options.store,
+ Html = options.Html,
+ setPageData = options.setPageData,
+ forgetPageData = options.forgetPageData,
+ writeHTMLFile = options.writeHTMLFile;
+
+ var urls = (0, _routesToUrls2.default)(routes, collection);
+
+ // create all html files
+ return Promise.all(urls.map(function (url) {
+ var item = collection.find(function (item) {
+ return item.__url === url;
+ });
+ var filename = decodeURIComponent(item ? _path2.default.join(destination, item.__resourceUrl) : _path2.default.join(destination, (0, _urlify2.default)(url, true)));
+ setPageData(url, collection, store);
+ return (0, _urlAsHtml2.default)(url, options, Html, testing).then(function (html) {
+ return writeHTMLFile(filename, html);
+ }).then(function (filename) {
+ forgetPageData(url, store);
+ return filename;
+ });
+ }));
+}
+
+exports.default = function (options, testing) {
+ return writeAllHTMLFiles(_extends({}, options, {
+ setPageData: setPageData,
+ forgetPageData: forgetPageData,
+ writeHTMLFile: writeHTMLFile
+ }), testing);
+};
\ No newline at end of file
diff --git a/lib/static/routes-to-urls/index.js b/lib/static/routes-to-urls/index.js
new file mode 100644
index 000000000..5536f2fb8
--- /dev/null
+++ b/lib/static/routes-to-urls/index.js
@@ -0,0 +1,169 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _reactRouter = require("react-router");
+
+var _chalk = require("chalk");
+
+var _chalk2 = _interopRequireDefault(_chalk);
+
+var _urlJoin = require("url-join");
+
+var _urlJoin2 = _interopRequireDefault(_urlJoin);
+
+var _arrayUnique = require("../../_utils/array-unique");
+
+var _arrayUnique2 = _interopRequireDefault(_arrayUnique);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
+function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
+
+var defaultConsole = console.log;
+
+var flattenRoute = function flattenRoute(route) {
+ // @todo remove the default route.path, user should use IndexRoute instead?
+ var routesUrls = route.path ? [route.path] : [];
+
+ if (route.indexRoute) {
+ routesUrls.push(route.path);
+ }
+ if (route.childRoutes) {
+ var root = route.path;
+ route.childRoutes.forEach(function (route) {
+ routesUrls = [].concat(_toConsumableArray(routesUrls), _toConsumableArray(flattenRoute(route).map(function (r) {
+ return root ? (0, _urlJoin2.default)(root, r) : r;
+ })));
+ });
+ }
+
+ return routesUrls;
+};
+
+// only simple types will be accepted
+// array | string | number
+// other will be skipped
+var paramsListFromCollection = function paramsListFromCollection(collection) {
+ var params = {};
+
+ collection.forEach(function (item) {
+ if (!item.head) {
+ return;
+ }
+
+ Object.keys(item.head).forEach(function (key) {
+ // array
+ if (Array.isArray(item.head[key]) && item.head[key].length && (typeof item.head[key][0] === "string" || typeof item.head[key][0] === "number")) {
+ var k = key
+ // categories => category
+ .replace(/ies$/, "y")
+ // tags => tag
+ .replace(/s$/, "");
+
+ if (!params[k]) {
+ params[k] = [];
+ }
+ params[k] = [].concat(_toConsumableArray(params[k]), _toConsumableArray(item.head[key]));
+ }
+
+ // string, number
+ if (typeof item.head[key] === "string" || typeof item.head[key] === "number") {
+ if (!params[key]) {
+ params[key] = [];
+ }
+ params[key].push(item.head[key]);
+ }
+ });
+ });
+
+ params.splat = collection.map(function (item) {
+ return item.__url;
+ });
+
+ return params;
+};
+
+var createUrlsFromParamsReplacementInUrl = function createUrlsFromParamsReplacementInUrl(url, params, log) {
+ // don't compute anything if url doesn't seems to have dynamic parameters
+ // react-router url params are like ``:that`` (or splat *)
+ if (url.indexOf(":") === -1 && url.indexOf("*") === -1) {
+ return [url];
+ }
+
+ var urls = [];
+
+ var possibleErrorEnd = "parameter for path \"" + url + "\"";
+
+ var missingKeys = [];
+ var nonMissingKeys = [];
+
+ Object.keys(params).forEach(function (paramName) {
+ params[paramName].forEach(function (paramValue) {
+ var urlParams = _defineProperty({}, paramName, paramValue);
+ try {
+ var hydratedUrl = (0, _reactRouter.formatPattern)(url, urlParams);
+ urls.push(hydratedUrl);
+ nonMissingKeys.push(paramName);
+ } catch (e) {
+ // log(paramName, e.message)
+
+ var matches = e.message.match(/Missing \"(.*)\" parameter for path/);
+ if (matches && matches[1]) {
+ missingKeys.push(matches[1]);
+ }
+
+ if (e.message.indexOf("Missing") === 0 && e.message.lastIndexOf(possibleErrorEnd) === e.message.length - possibleErrorEnd.length - 1) {
+ throw e;
+ }
+ }
+ });
+ });
+
+ nonMissingKeys = (0, _arrayUnique2.default)(nonMissingKeys);
+ missingKeys = (0, _arrayUnique2.default)(missingKeys).filter(function (key) {
+ return nonMissingKeys.indexOf(key) === -1;
+ });
+ if (missingKeys.length) {
+ log("⚠️ " + _chalk2.default.red("It looks like some parameters can't be mapped to create routes: ", missingKeys.map(function (key) {
+ return ":" + key;
+ }).join(", ")));
+ }
+
+ // @todo improve the algorithm to avoid duplicates,
+ // we will probably get better perfs
+
+ return (0, _arrayUnique2.default)(urls.sort());
+};
+
+var hydrateRoutesUrls = function hydrateRoutesUrls(routesUrls, collection, log) {
+ var paramsList = paramsListFromCollection(collection);
+
+ return routesUrls.reduce(function (acc, url) {
+ return [].concat(_toConsumableArray(acc), _toConsumableArray(createUrlsFromParamsReplacementInUrl(url, paramsList, log)));
+ }, []);
+};
+
+exports.default = function (routes, collection) {
+ var log = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : defaultConsole;
+
+ var flattenedRoutes = (0, _arrayUnique2.default)((0, _reactRouter.createRoutes)(routes).reduce(function (acc, r) {
+ return [].concat(_toConsumableArray(acc), _toConsumableArray(flattenRoute(r)));
+ }, []));
+
+ if (flattenedRoutes.filter(function (url) {
+ return url.indexOf("*") > -1;
+ }).length > 1) {
+ throw new Error("Phenomic can only handle one splat (*) in react-router routes. \n" + "You must use only one splat. If you have a specific need, do not " + "hesitate to open an issue at " + "https://github.com/MoOx/phenomic/issues/new");
+ }
+
+ var normalizedRoutes = flattenedRoutes.map(function (route) {
+ return "/" + route.replace(/^\/+/, "").replace(/\/+$/, "");
+ });
+
+ return hydrateRoutesUrls(normalizedRoutes, collection, log);
+};
\ No newline at end of file
diff --git a/lib/static/url-as-html.js b/lib/static/url-as-html.js
new file mode 100644
index 000000000..1d0517153
--- /dev/null
+++ b/lib/static/url-as-html.js
@@ -0,0 +1,133 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+exports.default = function (url, options) {
+ var Html = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : _Html2.default;
+ var baseUrl = options.baseUrl,
+ assetsFiles = options.assetsFiles,
+ routes = options.routes,
+ collection = options.collection,
+ metadata = options.metadata,
+ store = options.store;
+
+
+ var render = _server2.default[!options.clientScripts ? "renderToStaticMarkup" : "renderToString"];
+
+ return new Promise(function (resolve, reject) {
+ try {
+ (0, _reactRouter.match)({
+ routes: routes,
+ location: url,
+ basename: baseUrl.pathname
+ }, function (error, redirectLocation, renderProps) {
+ if (error) {
+ return reject(error);
+ } else if (redirectLocation) {
+ // TODO add a redirect page à la "jekyll redirect plugin"
+ throw new Error("phenomic (static) doesn't handle redirection yet");
+ } else if (!renderProps) {
+ throw new Error("phenomic (static) doesn't handle page not found yet. " + "You are not supposed so see this message because this code is " + "not supposed to be executed the way thing are, so this can " + "be a react-router issue. Check out opened issue to find a " + "workaround: https://github.com/MoOx/phenomic/issues");
+ }
+
+ var collectionMin = (0, _minify2.default)(collection);
+
+ /* eslint-disable react/no-multi-comp */
+
+ var sheet = new _styledComponents.ServerStyleSheet();
+ var renderBody = function renderBody() {
+ return render(_react2.default.createElement(
+ _styledComponents.StyleSheetManager,
+ { sheet: sheet.instance },
+ _react2.default.createElement(
+ _ContextProvider2.default,
+ {
+ collection: collectionMin,
+ metadata: metadata
+ },
+ _react2.default.createElement(
+ _reactRedux.Provider,
+ { store: store },
+ _react2.default.createElement(_reactRouter.RouterContext, renderProps)
+ )
+ )
+ ));
+ };
+
+ var renderScript = function renderScript() {
+ if (options.clientScripts) {
+ var initialState = _extends({}, store.getState(), {
+ // only keep current page as others are not necessary
+ pages: _defineProperty({}, url, store.getState().pages[url])
+ });
+ var script = "window.__COLLECTION__ = " + (0, _serialize2.default)(collectionMin) + ";" + ("window.__INITIAL_STATE__ = " + (0, _serialize2.default)(initialState));
+
+ return _react2.default.createElement("script", { dangerouslySetInnerHTML: { __html: script } });
+ }
+
+ return null;
+ };
+
+ // write htmlString as html files
+ return resolve(
+ // render html document as simple html
+ "" + _server2.default.renderToStaticMarkup(_react2.default.createElement(Html, _extends({}, assetsFiles && {
+ css: assetsFiles.css ? assetsFiles.css.map(function (fileName) {
+ return (0, _pathToUri2.default)(baseUrl.pathname, fileName);
+ }) : [],
+ js: options.clientScripts && assetsFiles.js ? assetsFiles.js.map(function (fileName) {
+ return (0, _pathToUri2.default)(baseUrl.pathname, fileName);
+ }) : []
+ }, {
+ renderBody: renderBody,
+ renderScript: renderScript,
+ sheet: sheet
+ }))));
+ });
+ } catch (err) {
+ reject(err);
+ }
+ });
+};
+
+var _react = require("react");
+
+var _react2 = _interopRequireDefault(_react);
+
+var _server = require("react-dom/server");
+
+var _server2 = _interopRequireDefault(_server);
+
+var _reactRouter = require("react-router");
+
+var _reactRedux = require("react-redux");
+
+var _Html = require("../components/Html");
+
+var _Html2 = _interopRequireDefault(_Html);
+
+var _pathToUri = require("../_utils/path-to-uri");
+
+var _pathToUri2 = _interopRequireDefault(_pathToUri);
+
+var _ContextProvider = require("../components/ContextProvider");
+
+var _ContextProvider2 = _interopRequireDefault(_ContextProvider);
+
+var _serialize = require("../_utils/serialize");
+
+var _serialize2 = _interopRequireDefault(_serialize);
+
+var _minify = require("../loader/minify");
+
+var _minify2 = _interopRequireDefault(_minify);
+
+var _styledComponents = require("styled-components");
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
\ No newline at end of file
diff --git a/lib/stylelint-config-recommended/index.js b/lib/stylelint-config-recommended/index.js
new file mode 100644
index 000000000..6139e2304
--- /dev/null
+++ b/lib/stylelint-config-recommended/index.js
@@ -0,0 +1,13 @@
+"use strict";
+
+module.exports = {
+ // too many opinionated rules
+ // "extends": "stylelint-config-standard",
+ rules: {
+ // only prevent user errors
+ "string-no-newline": true,
+ "unit-no-unknown": true,
+ "property-no-unknown": true,
+ "declaration-block-no-duplicate-properties": [true, { "ignore": ["consecutive-duplicates-with-different-values"] }]
+ }
+};
\ No newline at end of file
diff --git a/package.json b/package.json
index 2bd5daa04..5edaf949c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "phenomic",
- "version": "0.21.1",
+ "version": "0.21.2-0",
"description": "Modern website generator based on the React and Webpack ecosystem.",
"keywords": [
"webpack",
@@ -81,6 +81,7 @@
"sitemap": "^1.8.2",
"source-map-support": "^0.4.0",
"strip-markdown": "^0.3.1",
+ "styled-components": "^2.1.0",
"url-join": "^1.1.0",
"valid-url": "^1.0.9",
"webpack-dev-middleware": "^1.10.1",
@@ -144,7 +145,6 @@
"webpack": "^2.3.0"
},
"scripts": {
- "postinstall": "node npm/postinstall.js",
"transpile": "babel --ignore __tests__ --copy-files src --out-dir lib",
"prepublish": "rimraf lib && npm run transpile",
"#lint:js:eslint": "https://github.com/eslint/eslint/issues/5679",
diff --git a/src/components/Html/index.js b/src/components/Html/index.js
index d3d9bf5ae..a7838c396 100644
--- a/src/components/Html/index.js
+++ b/src/components/Html/index.js
@@ -4,11 +4,14 @@ import React from "react"
import { renderToString } from "react-dom/server"
import Helmet from "react-helmet"
+import { ServerStyleSheet } from "styled-components"
+
type Props = {
css: Array,
js: Array,
renderBody: () => React$Element,
renderScript: () => React$Element,
+ sheet: any
}
const Html = (props: Props) => {
@@ -76,6 +79,7 @@ const Html = (props: Props) => {
}
body = body || props.renderBody()
+ const styledComponentsStyles = props.sheet.getStyleElement()
// rewind html metas
const head = Helmet.rewind()
@@ -100,6 +104,7 @@ const Html = (props: Props) => {
))
}
+ { styledComponentsStyles }
{ head.script.toComponent() }
diff --git a/src/static/url-as-html.js b/src/static/url-as-html.js
index a75d4986e..453a0ee85 100644
--- a/src/static/url-as-html.js
+++ b/src/static/url-as-html.js
@@ -11,6 +11,8 @@ import PhenomicContextProvider from "../components/ContextProvider"
import serialize from "../_utils/serialize"
import minifyCollection from "../loader/minify"
+import { ServerStyleSheet, StyleSheetManager } from "styled-components"
+
export default function(
url: string,
options: PhenomicStaticConfig,
@@ -64,15 +66,18 @@ export default function(
/* eslint-disable react/no-multi-comp */
+ const sheet = new ServerStyleSheet()
const renderBody = () => render(
-
-
-
-
-
+
+
+
+
+
+
+
)
const renderScript = () => {
@@ -119,6 +124,7 @@ export default function(
},
renderBody,
renderScript,
+ sheet
}
)
)
diff --git a/yarn.lock b/yarn.lock
index 9adbeedea..6598ec95e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1231,6 +1231,13 @@ buffer@^4.3.0:
ieee754 "^1.1.4"
isarray "^1.0.0"
+buffer@^5.0.3:
+ version "5.0.6"
+ resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.0.6.tgz#2ea669f7eec0b6eda05b08f8b5ff661b28573588"
+ dependencies:
+ base64-js "^1.0.2"
+ ieee754 "^1.1.4"
+
builtin-modules@^1.0.0, builtin-modules@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
@@ -1660,6 +1667,10 @@ crypto-browserify@^3.11.0:
public-encrypt "^4.0.0"
randombytes "^2.0.0"
+css-color-keywords@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
+
css-color-names@0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.3.tgz#de0cef16f4d8aa8222a320d5b6d7e9bbada7b9f6"
@@ -1673,6 +1684,14 @@ css-rule-stream@^1.1.0:
ldjson-stream "^1.2.1"
through2 "^0.6.3"
+css-to-react-native@^2.0.3:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-2.0.4.tgz#cf4cc407558b3474d4ba8be1a2cd3b6ce713101b"
+ dependencies:
+ css-color-keywords "^1.0.0"
+ fbjs "^0.8.5"
+ postcss-value-parser "^3.3.0"
+
css-tokenize@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/css-tokenize/-/css-tokenize-1.0.1.tgz#4625cb1eda21c143858b7f81d6803c1d26fc14be"
@@ -2411,7 +2430,7 @@ fb-watchman@^2.0.0:
dependencies:
bser "^2.0.0"
-fbjs@^0.8.1, fbjs@^0.8.4:
+fbjs@^0.8.1, fbjs@^0.8.4, fbjs@^0.8.5, fbjs@^0.8.9:
version "0.8.12"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.12.tgz#10b5d92f76d45575fd63a217d4ea02bea2f8ed04"
dependencies:
@@ -3251,6 +3270,10 @@ 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-function@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5"
+
is-generator-function@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.6.tgz#9e71653cd15fff341c79c4151460a131d31e9fc4"
@@ -4066,7 +4089,7 @@ 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, loose-envify@^1.1.0, loose-envify@^1.2.0:
+loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
dependencies:
@@ -4265,13 +4288,6 @@ mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0:
dependencies:
minimist "0.0.8"
-mock-fs@^3.9.0:
- version "3.12.1"
- resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-3.12.1.tgz#ff27824cd6ab263a7eb05a115239d41d3631f5f8"
- dependencies:
- rewire "2.5.2"
- semver "5.3.0"
-
mount-point@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/mount-point/-/mount-point-1.2.0.tgz#f7712295e1ecd8df2e42ecbe23e07a3660807851"
@@ -4844,7 +4860,7 @@ postcss-selector-parser@^2.0.0, postcss-selector-parser@^2.1.1:
indexes-of "^1.0.1"
uniq "^1.0.1"
-postcss-value-parser@^3.1.1, postcss-value-parser@^3.2.3:
+postcss-value-parser@^3.1.1, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15"
@@ -4911,6 +4927,13 @@ promise@^7.1.1:
dependencies:
asap "~2.0.3"
+prop-types@^15.5.4:
+ version "15.5.10"
+ resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154"
+ dependencies:
+ fbjs "^0.8.9"
+ loose-envify "^1.3.1"
+
property-information@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/property-information/-/property-information-3.1.0.tgz#1581bf8a445dfbfef759775a86700e8dda18b4a1"
@@ -5430,10 +5453,6 @@ restore-cursor@^1.0.1:
exit-hook "^1.0.0"
onetime "^1.0.0"
-rewire@2.5.2:
- version "2.5.2"
- resolved "https://registry.yarnpkg.com/rewire/-/rewire-2.5.2.tgz#6427de7b7feefa7d36401507eb64a5385bc58dc7"
-
right-align@^0.1.1:
version "0.1.3"
resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
@@ -5511,7 +5530,7 @@ scroll-behavior@^0.8.0:
dom-helpers "^2.4.0"
invariant "^2.2.1"
-"semver@2 || 3 || 4 || 5", semver@5.3.0, semver@^5.3.0:
+"semver@2 || 3 || 4 || 5", semver@^5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
@@ -5884,6 +5903,20 @@ style-search@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902"
+styled-components@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-2.1.0.tgz#425805fca7efa5880aad2171f986bfd8a2f0808f"
+ dependencies:
+ buffer "^5.0.3"
+ css-to-react-native "^2.0.3"
+ fbjs "^0.8.9"
+ hoist-non-react-statics "^1.2.0"
+ is-function "^1.0.1"
+ is-plain-object "^2.0.1"
+ prop-types "^15.5.4"
+ stylis "^3.0.19"
+ supports-color "^3.2.3"
+
stylehacks@^2.3.0:
version "2.3.2"
resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-2.3.2.tgz#64c83e0438a68c9edf449e8c552a7d9ab6009b0b"
@@ -5943,6 +5976,10 @@ stylelint@^7.2.0:
svg-tags "^1.0.0"
table "^4.0.1"
+stylis@^3.0.19:
+ version "3.1.9"
+ resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.1.9.tgz#638370451f980437f57c59e58d2e296be29fafb7"
+
sugarss@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/sugarss/-/sugarss-0.2.0.tgz#ac34237563327c6ff897b64742bf6aec190ad39e"