diff --git a/.gitignore b/.gitignore index e113725..00e0c72 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ __snapshots__ .DS_Store /lib +.idea +yarn.lock diff --git a/CHANGELOG.md b/CHANGELOG.md index e8ef5d1..105fdc1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGE-LOG +## 0.4.0 +- Add support for directory-level flavors +- Fix all the security warnings on libraries + ## 0.3.0 - Add `getFlavor` macro - Fix the unmet dependency warnings on installing the library diff --git a/README.md b/README.md index 2c160ab..8c92642 100644 --- a/README.md +++ b/README.md @@ -40,21 +40,31 @@ Here the the flavors-key is `layout-theme`. The current flavor being `green`. If, for some reason, you cannot include the `.babel-plugin-macrosrc.json` file to your project, you can use any of the methods mentioned [here](https://github.com/kentcdodds/babel-plugin-macros/blob/master/other/docs/author.md#config-experimental). -You can then use the flavor-key in any class by adding the macro-key as the last element, in the name of the import string or just before the extension. Also make sure to call the `flavor()` function. In the below example, the flavor-key `layout-theme`, configured above, is being used - +You can then use the flavor-key in any class by adding the macro-key as the last element, in the name of the import string or just before the extension. You can use flavors in the directory-level as well. Just make sure to call the `flavor()` function, after all the import statements. + +In the below example, the flavor-key `layout-theme`, configured above, is being used - ```js +// Import flavors on top import flavors from 'flavors.macro' + import Hello from './hello.layout-theme.js' import Bye from './bye.layout-theme' +import Constants from './constants.layout-theme/theme' +import Config from './layout-theme.config/config' +import Theme from './layout-theme/theme' // ... other imports -// Add this right after all the imports are declared +// Add this right after all the imports are declared (won't work otherwise) flavors(); ``` -When the application is built, the above class will evaluate to - +When the application is built, the above statements will evaluate to - ```js import Hello from './hello.green.js' import Bye from './bye.green' +import Constants from './constants.green/theme' +import Config from './green.config/config' +import Theme from './green/theme' // ... other imports ``` @@ -87,6 +97,11 @@ switch (currFlavor) { ``` `getFlavor` will return an empty string if the flavor-key is incorrect. +## Building and running locally +- All the source-code is inside the `src` directory. +- Ideally any change that's made needs to have a test. Running the tests - `npm test`. +- Whenever testing out in the example-app, make sure to run `npm run-script build` in the project-root, since it'll be picking up from the local-env. NOTE: `lib` dir is git-ignored, so you'll not be able to see any-change tracked by git. +- Deploy to npm using - `npm publish` ## License MIT. See license file diff --git a/example-app/src/App.js b/example-app/src/App.js index 9fc8f59..6e7fbb9 100755 --- a/example-app/src/App.js +++ b/example-app/src/App.js @@ -1,5 +1,7 @@ import React, { Component } from 'react'; import Hello from './hello.layout-theme' +import ContentLayout from './contents.layout-theme/content' +import ContentStyled from './contents.style-theme/content' import flavors from 'flavors.macro' flavors(); @@ -7,6 +9,8 @@ class App extends Component { render() { return (
+ +
); diff --git a/example-app/src/contents.black/content.js b/example-app/src/contents.black/content.js new file mode 100644 index 0000000..d12dfcf --- /dev/null +++ b/example-app/src/contents.black/content.js @@ -0,0 +1,13 @@ +import React, { Component } from 'react'; + +class App extends Component { + render() { + return ( +
+ Content from inside the black flavor +
+ ); + } +} + +export default App; \ No newline at end of file diff --git a/example-app/src/contents.green/content.js b/example-app/src/contents.green/content.js new file mode 100644 index 0000000..d6fe02b --- /dev/null +++ b/example-app/src/contents.green/content.js @@ -0,0 +1,13 @@ +import React, { Component } from 'react'; + +class App extends Component { + render() { + return ( +
+ Content from inside the green flavor +
+ ); + } +} + +export default App; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 15d1150..481e206 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "flavors.macro", - "version": "0.3.0", + "version": "0.4.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -2871,12 +2871,12 @@ "dev": true }, "handlebars": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.0.tgz", - "integrity": "sha512-l2jRuU1NAWK6AW5qqcTATWQJvNPEwkM7NEKSiv/gqOsoSQbVoWyqVEY5GS+XPQ88zLNmqASRpzfdm8d79hJS+w==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz", + "integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==", "dev": true, "requires": { - "async": "^2.5.0", + "neo-async": "^2.6.0", "optimist": "^0.6.1", "source-map": "^0.6.1", "uglify-js": "^3.1.4" @@ -3848,9 +3848,9 @@ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "js-yaml": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz", - "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "dev": true, "requires": { "argparse": "^1.0.7", @@ -4019,9 +4019,9 @@ } }, "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + "version": "4.17.14", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz", + "integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==" }, "lodash.get": { "version": "4.4.2", @@ -4030,9 +4030,9 @@ "dev": true }, "lodash.merge": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz", - "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==", + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, "lodash.sortby": { @@ -4175,9 +4175,9 @@ "dev": true }, "mixin-deep": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "dev": true, "requires": { "for-in": "^1.0.2", @@ -4249,6 +4249,12 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "dev": true + }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -5052,9 +5058,9 @@ "dev": true }, "set-value": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "dev": true, "requires": { "extend-shallow": "^2.0.1", @@ -5642,38 +5648,15 @@ "integrity": "sha512-2WSLa6OdYd2ng8oqiGIWnJqyFArvhn+5vgx5GTxMbUYjCYKUcuKS62YLFF0R/BDGlB1yzXjQOLtPAfHsgirEpg==" }, "union-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "dev": true, "requires": { "arr-union": "^3.1.0", "get-value": "^2.0.6", "is-extendable": "^0.1.1", - "set-value": "^0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" - } - } + "set-value": "^2.0.1" } }, "unset-value": { diff --git a/package.json b/package.json index 760980c..581975f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "flavors.macro", - "version": "0.3.0", + "version": "0.4.0", "description": "Macro for building different flavors of a react-app ", "keywords": [ "babel-plugin-macros" diff --git a/src/processor.js b/src/processor.js index 217a35f..9f0545a 100644 --- a/src/processor.js +++ b/src/processor.js @@ -16,6 +16,10 @@ export default class Processor { importVal: importVal, } + if (Utils.isNull(importVal)) { + return resp + } + // Fetch the flavor-map var flavorMap = Processor.getFlavorMapForConfig(config) @@ -23,16 +27,20 @@ export default class Processor { var isMatched = false; var replacementVal = null; var matchedKey = null; + var matchedPathChar = null; + for (var flavorKey in flavorMap) { if (false === flavorMap.hasOwnProperty(flavorKey)) { continue } - var isDefaultRegex = new RegExp(`^.+\\.${Utils.escapeRegExp(flavorKey)}(?:\\.[^.]+)?$`) - if (true === isDefaultRegex.test(importVal)) { + var isDefaultRegex = new RegExp(`^.+([./])${Utils.escapeRegExp(flavorKey)}(?:[./].+)?$`) + var regexResults = importVal.match(isDefaultRegex) + if (false === Utils.isNull(regexResults) && regexResults.length >= 2) { isMatched = true; matchedKey = flavorKey replacementVal = flavorMap[matchedKey] + matchedPathChar = regexResults[1] break; } } @@ -50,9 +58,9 @@ export default class Processor { "" => abc.js */ if (replacementVal !== "") { - replacementVal = `.${replacementVal}` + replacementVal = `${matchedPathChar}${replacementVal}` } - var defaultReplaceRegex = new RegExp(`\\.${Utils.escapeRegExp(matchedKey)}\\b`) + var defaultReplaceRegex = new RegExp(`[./]${Utils.escapeRegExp(matchedKey)}\\b`) importVal = importVal.replace(defaultReplaceRegex, `${replacementVal}`); diff --git a/tests/configs.test.js b/tests/configs.test.js index 1a91a02..7c1df0a 100644 --- a/tests/configs.test.js +++ b/tests/configs.test.js @@ -116,6 +116,26 @@ it('Config test', () => { }, [EXPECTED_MODIFIED_KEY]: false, }, + // Directory flavors + { + [IP_KEY]: "abc/styleFlavor/theme.js", + [EXPECTED_KEY]: "abc/green/theme.js", + [CONFIG_KEY]: flavorConfig, + [EXPECTED_MODIFIED_KEY]: true, + }, + { + [IP_KEY]: "abc/constants.layoutFlavor/theme.js", + [EXPECTED_KEY]: "abc/constants.red/theme.js", + [CONFIG_KEY]: flavorConfig, + [EXPECTED_MODIFIED_KEY]: true, + }, + // The reversed-flavors should also work + { + [IP_KEY]: "abc/layoutFlavor.constants/theme.js", + [EXPECTED_KEY]: "abc/red.constants/theme.js", + [CONFIG_KEY]: flavorConfig, + [EXPECTED_MODIFIED_KEY]: true, + }, ] ipList.forEach(entry => {