From a8a8ac24dc540f904e6b85ced70927ed2e64e48b Mon Sep 17 00:00:00 2001 From: yarastqt Date: Sat, 19 Dec 2020 22:30:33 +0300 Subject: [PATCH 01/15] chore: init package --- .../feature-flags-webpack-plugin/.gitignore | 1 + .../feature-flags-webpack-plugin/README.md | 17 +++++++++++++++ .../package-lock.json | 14 +++++++++++++ .../feature-flags-webpack-plugin/package.json | 21 +++++++++++++++++++ .../feature-flags-webpack-plugin/src/index.ts | 5 +++++ .../tsconfig.json | 21 +++++++++++++++++++ 6 files changed, 79 insertions(+) create mode 100644 packages/feature-flags-webpack-plugin/.gitignore create mode 100644 packages/feature-flags-webpack-plugin/README.md create mode 100644 packages/feature-flags-webpack-plugin/package-lock.json create mode 100644 packages/feature-flags-webpack-plugin/package.json create mode 100644 packages/feature-flags-webpack-plugin/src/index.ts create mode 100644 packages/feature-flags-webpack-plugin/tsconfig.json diff --git a/packages/feature-flags-webpack-plugin/.gitignore b/packages/feature-flags-webpack-plugin/.gitignore new file mode 100644 index 00000000..a65b4177 --- /dev/null +++ b/packages/feature-flags-webpack-plugin/.gitignore @@ -0,0 +1 @@ +lib diff --git a/packages/feature-flags-webpack-plugin/README.md b/packages/feature-flags-webpack-plugin/README.md new file mode 100644 index 00000000..c9f5f6e0 --- /dev/null +++ b/packages/feature-flags-webpack-plugin/README.md @@ -0,0 +1,17 @@ +# @bem-react/feature-flags-webpack-plugin + +## Motivation + +## ✈️ Install + +via npm: + +```sh +npm i -DE @bem-react/feature-flags-webpack-plugin +``` + +## ☄️ Usage + +```ts +TODO +``` diff --git a/packages/feature-flags-webpack-plugin/package-lock.json b/packages/feature-flags-webpack-plugin/package-lock.json new file mode 100644 index 00000000..0b3ada5a --- /dev/null +++ b/packages/feature-flags-webpack-plugin/package-lock.json @@ -0,0 +1,14 @@ +{ + "name": "@bem/feature-flags-webpack-plugin", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "typescript": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", + "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", + "dev": true + } + } +} diff --git a/packages/feature-flags-webpack-plugin/package.json b/packages/feature-flags-webpack-plugin/package.json new file mode 100644 index 00000000..06b7089a --- /dev/null +++ b/packages/feature-flags-webpack-plugin/package.json @@ -0,0 +1,21 @@ +{ + "name": "@bem/feature-flags-webpack-plugin", + "version": "1.0.0", + "description": "Webpack plugin for resolving feature flags", + "license": "MPL-2.0", + "homepage": "https://github.com/bem/bem-react/tree/master/packages/feature-flags-webpack-plugin", + "repository": "https://github.com/bem/bem-react", + "bugs": { + "url": "https://github.com/bem/bem-react/issues" + }, + "keywords": ["webpack", "feature-flags", "flags", "feature-toggles"], + "main": "lib/index.js", + "typings": "lib/index.d.ts", + "scripts": { + "build": "tsc", + "unit": "exit 0" + }, + "devDependencies": { + "typescript": "4.1.3" + } +} diff --git a/packages/feature-flags-webpack-plugin/src/index.ts b/packages/feature-flags-webpack-plugin/src/index.ts new file mode 100644 index 00000000..690796ac --- /dev/null +++ b/packages/feature-flags-webpack-plugin/src/index.ts @@ -0,0 +1,5 @@ +class FeatureFlagsWebpackPlugin { + apply(_compiler: any) {} +} + +module.exports = FeatureFlagsWebpackPlugin diff --git a/packages/feature-flags-webpack-plugin/tsconfig.json b/packages/feature-flags-webpack-plugin/tsconfig.json new file mode 100644 index 00000000..d845ebbf --- /dev/null +++ b/packages/feature-flags-webpack-plugin/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + /* Basic Options */ + "rootDir": "./src", + "outDir": "./lib", + "moduleResolution": "node", + "target": "ES2017", + "module": "CommonJS", + "declaration": true, + /* Module Resolution Options */ + "esModuleInterop": true, + /* Strict Type-Checking Options */ + "strict": true, + /* Additional Checks */ + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "noUnusedLocals": true, + "noUnusedParameters": true + } +} From 4d3782a958ef37fbed323a697abe3fb545b2fe56 Mon Sep 17 00:00:00 2001 From: yarastqt Date: Sat, 19 Dec 2020 22:36:30 +0300 Subject: [PATCH 02/15] chore: add @types/webpack deps --- .../package-lock.json | 72 +++++++++++++++++++ .../feature-flags-webpack-plugin/package.json | 1 + 2 files changed, 73 insertions(+) diff --git a/packages/feature-flags-webpack-plugin/package-lock.json b/packages/feature-flags-webpack-plugin/package-lock.json index 0b3ada5a..e38ebb87 100644 --- a/packages/feature-flags-webpack-plugin/package-lock.json +++ b/packages/feature-flags-webpack-plugin/package-lock.json @@ -4,6 +4,78 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@types/anymatch": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz", + "integrity": "sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==", + "dev": true + }, + "@types/node": { + "version": "14.14.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.14.tgz", + "integrity": "sha512-UHnOPWVWV1z+VV8k6L1HhG7UbGBgIdghqF3l9Ny9ApPghbjICXkUJSd/b9gOgQfjM1r+37cipdw/HJ3F6ICEnQ==", + "dev": true + }, + "@types/source-list-map": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", + "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==", + "dev": true + }, + "@types/tapable": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.6.tgz", + "integrity": "sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA==", + "dev": true + }, + "@types/uglify-js": { + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.11.1.tgz", + "integrity": "sha512-7npvPKV+jINLu1SpSYVWG8KvyJBhBa8tmzMMdDoVc2pWUYHN8KIXlPJhjJ4LT97c4dXJA2SHL/q6ADbDriZN+Q==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + } + }, + "@types/webpack": { + "version": "4.41.25", + "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.25.tgz", + "integrity": "sha512-cr6kZ+4m9lp86ytQc1jPOJXgINQyz3kLLunZ57jznW+WIAL0JqZbGubQk4GlD42MuQL5JGOABrxdpqqWeovlVQ==", + "dev": true, + "requires": { + "@types/anymatch": "*", + "@types/node": "*", + "@types/tapable": "*", + "@types/uglify-js": "*", + "@types/webpack-sources": "*", + "source-map": "^0.6.0" + } + }, + "@types/webpack-sources": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-2.1.0.tgz", + "integrity": "sha512-LXn/oYIpBeucgP1EIJbKQ2/4ZmpvRl+dlrFdX7+94SKRUV3Evy3FsfMZY318vGhkWUS5MPhtOM3w1/hCOAOXcg==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/source-list-map": "*", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, "typescript": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", diff --git a/packages/feature-flags-webpack-plugin/package.json b/packages/feature-flags-webpack-plugin/package.json index 06b7089a..866e988e 100644 --- a/packages/feature-flags-webpack-plugin/package.json +++ b/packages/feature-flags-webpack-plugin/package.json @@ -16,6 +16,7 @@ "unit": "exit 0" }, "devDependencies": { + "@types/webpack": "4.41.25", "typescript": "4.1.3" } } From 7004caafdee4cbbfa76c6e56e46d8d13092ea179 Mon Sep 17 00:00:00 2001 From: yarastqt Date: Sat, 19 Dec 2020 22:36:48 +0300 Subject: [PATCH 03/15] feat: impl FeatureFlagsWebpackPlugin --- .../feature-flags-webpack-plugin/src/index.ts | 71 ++++++++++++++++++- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/packages/feature-flags-webpack-plugin/src/index.ts b/packages/feature-flags-webpack-plugin/src/index.ts index 690796ac..bd56ebd9 100644 --- a/packages/feature-flags-webpack-plugin/src/index.ts +++ b/packages/feature-flags-webpack-plugin/src/index.ts @@ -1,5 +1,72 @@ -class FeatureFlagsWebpackPlugin { - apply(_compiler: any) {} +import { Plugin, Compiler } from 'webpack' + +const featureFlagsFunctionName = 'isFeatureEnabled' + +function isFeatureFlagFunction(expression: any) { + if (expression.callee.property) { + return expression.callee.property.name === featureFlagsFunctionName + } + return expression.callee.name === featureFlagsFunctionName +} + +function getFeatureProperties(expression: any) { + if (!expression || !expression.arguments.length) return [] + return expression.arguments[0].properties +} + +function getFeatureFlag(properties: any) { + return properties.reduce((result: any, property: any) => { + const key = property.key.name + const value = property.value.value + result[key] = value + return result + }, {}) +} + +function isEnabledFlag(flag: any, options: any) { + return options.some( + (option: any) => option.value === flag.value && option.component === flag.component, + ) +} + +class FeatureFlagsWebpackPlugin extends Plugin { + options: any[] + + constructor(options: any[]) { + super() + this.options = options || [] + } + + apply(compiler: Compiler) { + const options = this.options + + compiler.hooks.thisCompilation.tap( + 'FeatureFlagsWebpackPlugin', + (_, { normalModuleFactory }) => { + normalModuleFactory.hooks.parser + .for('javascript/auto') + .tap('FeatureFlagsWebpackPlugin', (parser) => { + // @ts-expect-error + const getTrue = () => parser.evaluate(true) + // @ts-expect-error + const getFalse = () => parser.evaluate(false) + + parser.hooks.evaluate + .for('CallExpression') + .tap('FeatureFlagsWebpackPlugin', (expression) => { + if (!isFeatureFlagFunction(expression)) return + + const properties = getFeatureProperties(expression) + const flag = getFeatureFlag(properties) + const isEnabled = isEnabledFlag(flag, options) + const result = isEnabled ? getTrue() : getFalse() + result.setRange(expression.range) + return result + }) + }) + }, + ) + } } module.exports = FeatureFlagsWebpackPlugin From abe3f6de1d32eafafb3ca38b6161410d128caf2b Mon Sep 17 00:00:00 2001 From: yarastqt Date: Sun, 20 Dec 2020 00:14:06 +0300 Subject: [PATCH 04/15] chore: prepare pgk for publish --- .../package-lock.json | 701 +++++++++++++++++- .../feature-flags-webpack-plugin/package.json | 12 +- 2 files changed, 673 insertions(+), 40 deletions(-) diff --git a/packages/feature-flags-webpack-plugin/package-lock.json b/packages/feature-flags-webpack-plugin/package-lock.json index e38ebb87..82fe014e 100644 --- a/packages/feature-flags-webpack-plugin/package-lock.json +++ b/packages/feature-flags-webpack-plugin/package-lock.json @@ -1,13 +1,39 @@ { "name": "@bem/feature-flags-webpack-plugin", - "version": "1.0.0", + "version": "0.0.1-beta.0", "lockfileVersion": 1, "requires": true, "dependencies": { - "@types/anymatch": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz", - "integrity": "sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==", + "@types/eslint": { + "version": "7.2.6", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.6.tgz", + "integrity": "sha512-I+1sYH+NPQ3/tVqCeUSBwTE/0heyvtXqpIopUUArlBm0Kpocb8FbMa3AZ/ASKIFpN3rnEx932TTXDbt9OXsNDw==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.0.tgz", + "integrity": "sha512-O/ql2+rrCUe2W2rs7wMR+GqPRcgB6UiqN5RhrR5xruFlY7l9YLMn0ZkDzjoHLeiFkR8MCQZVudUuuvQ2BLC9Qw==", + "dev": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "0.0.45", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.45.tgz", + "integrity": "sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g==", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", + "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", "dev": true }, "@types/node": { @@ -16,50 +42,570 @@ "integrity": "sha512-UHnOPWVWV1z+VV8k6L1HhG7UbGBgIdghqF3l9Ny9ApPghbjICXkUJSd/b9gOgQfjM1r+37cipdw/HJ3F6ICEnQ==", "dev": true }, - "@types/source-list-map": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", - "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==", + "@webassemblyjs/ast": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.1.tgz", + "integrity": "sha512-uMu1nCWn2Wxyy126LlGqRVlhdTOsO/bsBRI4dNq3+6SiSuRKRQX6ejjKgh82LoGAPSq72lDUiQ4FWVaf0PecYw==", + "dev": true, + "requires": { + "@webassemblyjs/helper-module-context": "1.9.1", + "@webassemblyjs/helper-wasm-bytecode": "1.9.1", + "@webassemblyjs/wast-parser": "1.9.1" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.1.tgz", + "integrity": "sha512-5VEKu024RySmLKTTBl9q1eO/2K5jk9ZS+2HXDBLA9s9p5IjkaXxWiDb/+b7wSQp6FRdLaH1IVGIfOex58Na2pg==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.1.tgz", + "integrity": "sha512-y1lGmfm38djrScwpeL37rRR9f1D6sM8RhMpvM7CYLzOlHVboouZokXK/G88BpzW0NQBSvCCOnW5BFhten4FPfA==", "dev": true }, - "@types/tapable": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.6.tgz", - "integrity": "sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA==", + "@webassemblyjs/helper-buffer": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.1.tgz", + "integrity": "sha512-uS6VSgieHbk/m4GSkMU5cqe/5TekdCzQso4revCIEQ3vpGZgqSSExi4jWpTWwDpAHOIAb1Jfrs0gUB9AA4n71w==", "dev": true }, - "@types/uglify-js": { - "version": "3.11.1", - "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.11.1.tgz", - "integrity": "sha512-7npvPKV+jINLu1SpSYVWG8KvyJBhBa8tmzMMdDoVc2pWUYHN8KIXlPJhjJ4LT97c4dXJA2SHL/q6ADbDriZN+Q==", + "@webassemblyjs/helper-code-frame": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.1.tgz", + "integrity": "sha512-ZQ2ZT6Evk4DPIfD+92AraGYaFIqGm4U20e7FpXwl7WUo2Pn1mZ1v8VGH8i+Y++IQpxPbQo/UyG0Khs7eInskzA==", "dev": true, "requires": { - "source-map": "^0.6.1" + "@webassemblyjs/wast-printer": "1.9.1" } }, - "@types/webpack": { - "version": "4.41.25", - "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.25.tgz", - "integrity": "sha512-cr6kZ+4m9lp86ytQc1jPOJXgINQyz3kLLunZ57jznW+WIAL0JqZbGubQk4GlD42MuQL5JGOABrxdpqqWeovlVQ==", + "@webassemblyjs/helper-fsm": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.1.tgz", + "integrity": "sha512-J32HGpveEqqcKFS0YbgicB0zAlpfIxJa5MjxDxhu3i5ltPcVfY5EPvKQ1suRguFPehxiUs+/hfkwPEXom/l0lw==", + "dev": true + }, + "@webassemblyjs/helper-module-context": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.1.tgz", + "integrity": "sha512-IEH2cMmEQKt7fqelLWB5e/cMdZXf2rST1JIrzWmf4XBt3QTxGdnnLvV4DYoN8pJjOx0VYXsWg+yF16MmJtolZg==", "dev": true, "requires": { - "@types/anymatch": "*", - "@types/node": "*", - "@types/tapable": "*", - "@types/uglify-js": "*", - "@types/webpack-sources": "*", - "source-map": "^0.6.0" + "@webassemblyjs/ast": "1.9.1" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.1.tgz", + "integrity": "sha512-i2rGTBqFUcSXxyjt2K4vm/3kkHwyzG6o427iCjcIKjOqpWH8SEem+xe82jUk1iydJO250/CvE5o7hzNAMZf0dQ==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.1.tgz", + "integrity": "sha512-FetqzjtXZr2d57IECK+aId3D0IcGweeM0CbAnJHkYJkcRTHP+YcMb7Wmc0j21h5UWBpwYGb9dSkK/93SRCTrGg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.1", + "@webassemblyjs/helper-buffer": "1.9.1", + "@webassemblyjs/helper-wasm-bytecode": "1.9.1", + "@webassemblyjs/wasm-gen": "1.9.1" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.1.tgz", + "integrity": "sha512-EvTG9M78zP1MmkBpUjGQHZc26DzPGZSLIPxYHCjQsBMo60Qy2W34qf8z0exRDtxBbRIoiKa5dFyWer/7r1aaSQ==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.1.tgz", + "integrity": "sha512-Oc04ub0vFfLnF+2/+ki3AE+anmW4sv9uNBqb+79fgTaPv6xJsOT0dhphNfL3FrME84CbX/D1T9XT8tjFo0IIiw==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.1.tgz", + "integrity": "sha512-llkYtppagjCodFjo0alWOUhAkfOiQPQDIc5oA6C9sFAXz7vC9QhZf/f8ijQIX+A9ToM3c9Pq85X0EX7nx9gVhg==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.1.tgz", + "integrity": "sha512-S2IaD6+x9B2Xi8BCT0eGsrXXd8UxAh2LVJpg1ZMtHXnrDcsTtIX2bDjHi40Hio6Lc62dWHmKdvksI+MClCYbbw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.1", + "@webassemblyjs/helper-buffer": "1.9.1", + "@webassemblyjs/helper-wasm-bytecode": "1.9.1", + "@webassemblyjs/helper-wasm-section": "1.9.1", + "@webassemblyjs/wasm-gen": "1.9.1", + "@webassemblyjs/wasm-opt": "1.9.1", + "@webassemblyjs/wasm-parser": "1.9.1", + "@webassemblyjs/wast-printer": "1.9.1" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.1.tgz", + "integrity": "sha512-bqWI0S4lBQsEN5FTZ35vYzfKUJvtjNnBobB1agCALH30xNk1LToZ7Z8eiaR/Z5iVECTlBndoRQV3F6mbEqE/fg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.1", + "@webassemblyjs/helper-wasm-bytecode": "1.9.1", + "@webassemblyjs/ieee754": "1.9.1", + "@webassemblyjs/leb128": "1.9.1", + "@webassemblyjs/utf8": "1.9.1" } }, - "@types/webpack-sources": { + "@webassemblyjs/wasm-opt": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.1.tgz", + "integrity": "sha512-gSf7I7YWVXZ5c6XqTEqkZjVs8K1kc1k57vsB6KBQscSagDNbAdxt6MwuJoMjsE1yWY1tsuL+pga268A6u+Fdkg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.1", + "@webassemblyjs/helper-buffer": "1.9.1", + "@webassemblyjs/wasm-gen": "1.9.1", + "@webassemblyjs/wasm-parser": "1.9.1" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.1.tgz", + "integrity": "sha512-ImM4N2T1MEIond0MyE3rXvStVxEmivQrDKf/ggfh5pP6EHu3lL/YTAoSrR7shrbKNPpeKpGesW1LIK/L4kqduw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.1", + "@webassemblyjs/helper-api-error": "1.9.1", + "@webassemblyjs/helper-wasm-bytecode": "1.9.1", + "@webassemblyjs/ieee754": "1.9.1", + "@webassemblyjs/leb128": "1.9.1", + "@webassemblyjs/utf8": "1.9.1" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.1.tgz", + "integrity": "sha512-2xVxejXSvj3ls/o2TR/zI6p28qsGupjHhnHL6URULQRcXmryn3w7G83jQMcT7PHqUfyle65fZtWLukfdLdE7qw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.1", + "@webassemblyjs/floating-point-hex-parser": "1.9.1", + "@webassemblyjs/helper-api-error": "1.9.1", + "@webassemblyjs/helper-code-frame": "1.9.1", + "@webassemblyjs/helper-fsm": "1.9.1", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.1.tgz", + "integrity": "sha512-tDV8V15wm7mmbAH6XvQRU1X+oPGmeOzYsd6h7hlRLz6QpV4Ec/KKxM8OpLtFmQPLCreGxTp+HuxtH4pRIZyL9w==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.1", + "@webassemblyjs/wast-parser": "1.9.1", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "acorn": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.0.4.tgz", + "integrity": "sha512-XNP0PqF1XD19ZlLKvB7cMmnZswW4C/03pRHgirB30uSJTaS3A3V1/P4sS3HPvFmjoriPCJQs+JDSbm4bL1TxGQ==", + "dev": true + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true + }, + "browserslist": { + "version": "4.16.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.0.tgz", + "integrity": "sha512-/j6k8R0p3nxOC6kx5JGAxsnhc9ixaWJfYc+TNTzxg6+ARaESAvQGV7h0uNOB4t+pLQJZWzcrMxXOxjgsCj3dqQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001165", + "colorette": "^1.2.1", + "electron-to-chromium": "^1.3.621", + "escalade": "^3.1.1", + "node-releases": "^1.1.67" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001168", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001168.tgz", + "integrity": "sha512-P2zmX7swIXKu+GMMR01TWa4csIKELTNnZKc+f1CjebmZJQtTAEXmpQSoKVJVVcvPGAA0TEYTOUp3VehavZSFPQ==", + "dev": true + }, + "chrome-trace-event": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", + "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "colorette": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz", + "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.629", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.629.tgz", + "integrity": "sha512-iSPPJtPvHrMAvYOt+9cdbDmTasPqwnwz4lkP8Dn200gDNUBQOLQ96xUsWXBwXslAo5XxdoXAoQQ3RAy4uao9IQ==", + "dev": true + }, + "enhanced-resolve": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.4.0.tgz", + "integrity": "sha512-ZmqfWURB2lConOBM1JdCVfPyMRv5RdKWktLXO6123p97ovVm2CLBgw9t5MBj3jJWA6eHyOeIws9iJQoGFR4euQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.0.0" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "events": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", + "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-json-stable-stringify": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-2.1.0.tgz", - "integrity": "sha512-LXn/oYIpBeucgP1EIJbKQ2/4ZmpvRl+dlrFdX7+94SKRUV3Evy3FsfMZY318vGhkWUS5MPhtOM3w1/hCOAOXcg==", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "fs-monkey": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.1.tgz", + "integrity": "sha512-fcSa+wyTqZa46iWweI7/ZiUfegOZl0SG8+dltIwFXo7+zYU9J9kpS3NB6pZcSlJdhvIwp81Adx2XhZorncxiaA==", + "dev": true + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", "dev": true, "requires": { "@types/node": "*", - "@types/source-list-map": "*", - "source-map": "^0.7.3" + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + } + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "loader-runner": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.1.0.tgz", + "integrity": "sha512-oR4lB4WvwFoC70ocraKhn5nkKSs23t57h9udUgw8o0iH8hMXeEoRuUgfcvgUwAJ1ZpRqBvcou4N2SMvM1DwMrA==", + "dev": true + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "memfs": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.2.0.tgz", + "integrity": "sha512-f/xxz2TpdKv6uDn6GtHee8ivFyxwxmPuXatBb1FBwxYNuVpbM3k/Y1Z+vC0mH/dIXXrukYfe3qe5J32Dfjg93A==", + "dev": true, + "requires": { + "fs-monkey": "1.0.1" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "dev": true + }, + "mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "dev": true, + "requires": { + "mime-db": "1.44.0" + } + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node-releases": { + "version": "1.1.67", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.67.tgz", + "integrity": "sha512-V5QF9noGFl3EymEwUYzO+3NTDpGfQB4ve6Qfnzf3UNydMhjQRVPR1DZTuvWiLzaFJYw2fmDwAfnRNEVb64hSIg==", + "dev": true + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "pkg-dir": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", + "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", + "dev": true, + "requires": { + "find-up": "^5.0.0" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + }, + "serialize-javascript": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "tapable": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz", + "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==", + "dev": true + }, + "terser": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.5.1.tgz", + "integrity": "sha512-6VGWZNVP2KTUcltUQJ25TtNjx/XgdDsBDKGt8nN0MpydU36LmbPPcMBd2kmtZNNGVVDLg44k7GKeHHj+4zPIBQ==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.7.2", + "source-map-support": "~0.5.19" }, "dependencies": { "source-map": { @@ -70,10 +616,24 @@ } } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "terser-webpack-plugin": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.0.3.tgz", + "integrity": "sha512-zFdGk8Lh9ZJGPxxPE6jwysOlATWB8GMW8HcfGULWA/nPal+3VdATflQvSBSLQJRCmYZnfFJl6vkRTiwJGNgPiQ==", + "dev": true, + "requires": { + "jest-worker": "^26.6.1", + "p-limit": "^3.0.2", + "schema-utils": "^3.0.0", + "serialize-javascript": "^5.0.1", + "source-map": "^0.6.1", + "terser": "^5.3.8" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, "typescript": { @@ -81,6 +641,73 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", "dev": true + }, + "uri-js": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "watchpack": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.1.0.tgz", + "integrity": "sha512-UjgD1mqjkG99+3lgG36at4wPnUXNvis2v1utwTgQ43C22c4LD71LsYMExdWXh4HZ+RmW+B0t1Vrg2GpXAkTOQw==", + "dev": true, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "webpack": { + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.11.0.tgz", + "integrity": "sha512-ubWv7iP54RqAC/VjixgpnLLogCFbAfSOREcSWnnOlZEU8GICC5eKmJSu6YEnph2N2amKqY9rvxSwgyHxVqpaRw==", + "dev": true, + "requires": { + "@types/eslint-scope": "^3.7.0", + "@types/estree": "^0.0.45", + "@webassemblyjs/ast": "1.9.1", + "@webassemblyjs/helper-module-context": "1.9.1", + "@webassemblyjs/wasm-edit": "1.9.1", + "@webassemblyjs/wasm-parser": "1.9.1", + "acorn": "^8.0.4", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.3.1", + "eslint-scope": "^5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.4", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^4.1.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "pkg-dir": "^5.0.0", + "schema-utils": "^3.0.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.0.3", + "watchpack": "^2.0.0", + "webpack-sources": "^2.1.1" + } + }, + "webpack-sources": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.2.0.tgz", + "integrity": "sha512-bQsA24JLwcnWGArOKUxYKhX3Mz/nK1Xf6hxullKERyktjNMC4x8koOeaDNTA2fEJ09BdWLbM/iTW0ithREUP0w==", + "dev": true, + "requires": { + "source-list-map": "^2.0.1", + "source-map": "^0.6.1" + } + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true } } } diff --git a/packages/feature-flags-webpack-plugin/package.json b/packages/feature-flags-webpack-plugin/package.json index 866e988e..5565b189 100644 --- a/packages/feature-flags-webpack-plugin/package.json +++ b/packages/feature-flags-webpack-plugin/package.json @@ -1,6 +1,6 @@ { - "name": "@bem/feature-flags-webpack-plugin", - "version": "1.0.0", + "name": "@bem-react/feature-flags-webpack-plugin", + "version": "0.0.1-beta.0", "description": "Webpack plugin for resolving feature flags", "license": "MPL-2.0", "homepage": "https://github.com/bem/bem-react/tree/master/packages/feature-flags-webpack-plugin", @@ -9,11 +9,17 @@ "url": "https://github.com/bem/bem-react/issues" }, "keywords": ["webpack", "feature-flags", "flags", "feature-toggles"], + "publishConfig": { + "access": "public" + }, + "files": ["lib"], "main": "lib/index.js", "typings": "lib/index.d.ts", "scripts": { "build": "tsc", - "unit": "exit 0" + "cleanup": "rm -rf lib", + "prepublishOnly": "npm run cleanup && npm run build", + "unit": "../../node_modules/.bin/jest --config ../../.config/jest/jest.config.js" }, "devDependencies": { "@types/webpack": "4.41.25", From 74e2aae0df885c82d8e90f2e8a1ac66c4fe5bf59 Mon Sep 17 00:00:00 2001 From: yarastqt Date: Sun, 20 Dec 2020 00:14:42 +0300 Subject: [PATCH 05/15] build: include only src dir for ts --- packages/feature-flags-webpack-plugin/tsconfig.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/feature-flags-webpack-plugin/tsconfig.json b/packages/feature-flags-webpack-plugin/tsconfig.json index d845ebbf..1db5cbc7 100644 --- a/packages/feature-flags-webpack-plugin/tsconfig.json +++ b/packages/feature-flags-webpack-plugin/tsconfig.json @@ -17,5 +17,6 @@ "noImplicitReturns": true, "noUnusedLocals": true, "noUnusedParameters": true - } + }, + "include": ["src"] } From e1095d3281df8b6178cd6e1829308145d09c1edc Mon Sep 17 00:00:00 2001 From: yarastqt Date: Sun, 20 Dec 2020 18:29:45 +0300 Subject: [PATCH 06/15] chore: fix eslint no-use-before-define --- .eslintrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslintrc b/.eslintrc index 21353683..514f590c 100644 --- a/.eslintrc +++ b/.eslintrc @@ -52,7 +52,7 @@ "semi": [2, "never"], "semi-spacing": [2, { "before": false, "after": true }], "wrap-iife": [2, "inside"], - "no-use-before-define": [2, { "functions": true, "classes": true, "variables": true }], + "no-use-before-define": [2, { "functions": false, "classes": true, "variables": true }], "no-caller": 2, "no-cond-assign": [2, "except-parens"], "no-constant-condition": 2, From 5d423dfd47572236ebe4702a0f80eb2032ec2b29 Mon Sep 17 00:00:00 2001 From: yarastqt Date: Sun, 20 Dec 2020 18:30:40 +0300 Subject: [PATCH 07/15] refactor: separate cb hell to fns --- .../feature-flags-webpack-plugin/src/index.ts | 117 +++++++++--------- 1 file changed, 59 insertions(+), 58 deletions(-) diff --git a/packages/feature-flags-webpack-plugin/src/index.ts b/packages/feature-flags-webpack-plugin/src/index.ts index bd56ebd9..85ed249d 100644 --- a/packages/feature-flags-webpack-plugin/src/index.ts +++ b/packages/feature-flags-webpack-plugin/src/index.ts @@ -1,72 +1,73 @@ -import { Plugin, Compiler } from 'webpack' +import { Expression, CallExpression, Identifier, SpreadElement } from 'estree' +import { Compilation, Compiler, javascript } from 'webpack' -const featureFlagsFunctionName = 'isFeatureEnabled' +type PluginOptions = { + /** + * Function name for match + * + * @default 'isFeatureEnabled' + */ + isFeatureEnabledFnName: string + /** + * Object with flags + */ + flags: Record +} -function isFeatureFlagFunction(expression: any) { - if (expression.callee.property) { - return expression.callee.property.name === featureFlagsFunctionName +class FeatureFlagsWebpackPlugin { + constructor(public options: PluginOptions) { + Object.assign(this.options, { isFeatureEnabledFnName: 'isFeatureEnabled' }) } - return expression.callee.name === featureFlagsFunctionName -} -function getFeatureProperties(expression: any) { - if (!expression || !expression.arguments.length) return [] - return expression.arguments[0].properties -} + apply(compiler: Compiler) { + const { isFeatureEnabledFnName, flags } = this.options -function getFeatureFlag(properties: any) { - return properties.reduce((result: any, property: any) => { - const key = property.key.name - const value = property.value.value - result[key] = value - return result - }, {}) -} + function onCallExpression(expression: Expression, parser: javascript.JavascriptParser) { + if (isFeatureFlagFunction(expression, isFeatureEnabledFnName)) { + const argument = expression.arguments[0] + if (isIdentifier(argument)) { + const isEnabled = flags[argument.name] !== undefined + const result = isEnabled ? parser.evaluate(true) : parser.evaluate(false) + if (result !== undefined) { + result.setRange(expression.range) + } + return result + } + } + return undefined + } -function isEnabledFlag(flag: any, options: any) { - return options.some( - (option: any) => option.value === flag.value && option.component === flag.component, - ) -} + function onParseJavascript(parser: javascript.JavascriptParser) { + parser.hooks.evaluate + .for('CallExpression') + .tap('FeatureFlagsWebpackPlugin', (expression) => onCallExpression(expression, parser)) + } -class FeatureFlagsWebpackPlugin extends Plugin { - options: any[] + function onThisCompilation(_compilation: Compilation, compilationParams: any) { + compilationParams.normalModuleFactory.hooks.parser + .for('javascript/auto') + .tap('FeatureFlagsWebpackPlugin', onParseJavascript) + } - constructor(options: any[]) { - super() - this.options = options || [] + compiler.hooks.thisCompilation.tap('FeatureFlagsWebpackPlugin', onThisCompilation) } +} - apply(compiler: Compiler) { - const options = this.options - - compiler.hooks.thisCompilation.tap( - 'FeatureFlagsWebpackPlugin', - (_, { normalModuleFactory }) => { - normalModuleFactory.hooks.parser - .for('javascript/auto') - .tap('FeatureFlagsWebpackPlugin', (parser) => { - // @ts-expect-error - const getTrue = () => parser.evaluate(true) - // @ts-expect-error - const getFalse = () => parser.evaluate(false) - - parser.hooks.evaluate - .for('CallExpression') - .tap('FeatureFlagsWebpackPlugin', (expression) => { - if (!isFeatureFlagFunction(expression)) return +function isFeatureFlagFunction( + expression: Expression, + isFeatureEnabledFnName: string, +): expression is CallExpression { + // prettier-ignore + return ( + expression.type === 'CallExpression' + && expression.arguments.length > 0 + && expression.callee.type === 'Identifier' + && expression.callee.name === isFeatureEnabledFnName + ) +} - const properties = getFeatureProperties(expression) - const flag = getFeatureFlag(properties) - const isEnabled = isEnabledFlag(flag, options) - const result = isEnabled ? getTrue() : getFalse() - result.setRange(expression.range) - return result - }) - }) - }, - ) - } +function isIdentifier(expression: Expression | SpreadElement): expression is Identifier { + return expression.type === 'Identifier' } module.exports = FeatureFlagsWebpackPlugin From 1f52a1f65ff684a6aed216e5e0523a6d8adbedf0 Mon Sep 17 00:00:00 2001 From: yarastqt Date: Sun, 20 Dec 2020 18:31:23 +0300 Subject: [PATCH 08/15] chore: infra for units --- .../__tests__/__internal__/compiler.ts | 38 +++++++++++++++++++ .../__tests__/index.test.ts | 9 +++++ .../package-lock.json | 2 +- .../feature-flags-webpack-plugin/package.json | 6 ++- 4 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 packages/feature-flags-webpack-plugin/__tests__/__internal__/compiler.ts create mode 100644 packages/feature-flags-webpack-plugin/__tests__/index.test.ts diff --git a/packages/feature-flags-webpack-plugin/__tests__/__internal__/compiler.ts b/packages/feature-flags-webpack-plugin/__tests__/__internal__/compiler.ts new file mode 100644 index 00000000..abad9f0d --- /dev/null +++ b/packages/feature-flags-webpack-plugin/__tests__/__internal__/compiler.ts @@ -0,0 +1,38 @@ +import path from 'path' +import webpack from 'webpack' +import { createFsFromVolume, Volume } from 'memfs' + +export function compiler(fixture: any, options: any = {}) { + const $compiler = webpack({ + context: __dirname, + entry: `./${fixture}`, + output: { + path: path.resolve(__dirname), + filename: 'bundle.js', + }, + module: { + rules: [ + { + test: /\.txt$/, + use: { + loader: path.resolve(__dirname, '../src/loader.js'), + options, + }, + }, + ], + }, + plugins: options.plugins, + }) + + $compiler.outputFileSystem = createFsFromVolume(new Volume()) + $compiler.outputFileSystem.join = path.join.bind(path) + + return new Promise((resolve, reject) => { + $compiler.run((err, stats) => { + if (err) reject(err) + if (stats.hasErrors()) reject(new Error(stats.toJson().errors)) + + resolve(stats) + }) + }) +} diff --git a/packages/feature-flags-webpack-plugin/__tests__/index.test.ts b/packages/feature-flags-webpack-plugin/__tests__/index.test.ts new file mode 100644 index 00000000..716b31f6 --- /dev/null +++ b/packages/feature-flags-webpack-plugin/__tests__/index.test.ts @@ -0,0 +1,9 @@ +import FeatureFlagsWebpackPlugin from '../src/index' +import { compiler } from './__internal__/compiler' + +test('yyy', async () => { + const plugin = new FeatureFlagsWebpackPlugin() + await compiler('', { plugins: [plugin] }) + + expect(1).toBe(1) +}) diff --git a/packages/feature-flags-webpack-plugin/package-lock.json b/packages/feature-flags-webpack-plugin/package-lock.json index 82fe014e..fead01ee 100644 --- a/packages/feature-flags-webpack-plugin/package-lock.json +++ b/packages/feature-flags-webpack-plugin/package-lock.json @@ -1,5 +1,5 @@ { - "name": "@bem/feature-flags-webpack-plugin", + "name": "@bem-react/feature-flags-webpack-plugin", "version": "0.0.1-beta.0", "lockfileVersion": 1, "requires": true, diff --git a/packages/feature-flags-webpack-plugin/package.json b/packages/feature-flags-webpack-plugin/package.json index 5565b189..9ef0ca8b 100644 --- a/packages/feature-flags-webpack-plugin/package.json +++ b/packages/feature-flags-webpack-plugin/package.json @@ -18,11 +18,13 @@ "scripts": { "build": "tsc", "cleanup": "rm -rf lib", + "dev": "tsc -w", "prepublishOnly": "npm run cleanup && npm run build", "unit": "../../node_modules/.bin/jest --config ../../.config/jest/jest.config.js" }, "devDependencies": { - "@types/webpack": "4.41.25", - "typescript": "4.1.3" + "memfs": "3.2.0", + "typescript": "4.1.3", + "webpack": "5.11.0" } } From 0529bf469afee1e91d53437c1970e2a3c972e690 Mon Sep 17 00:00:00 2001 From: yarastqt Date: Mon, 21 Dec 2020 01:26:48 +0300 Subject: [PATCH 09/15] chore: use type-cast for required options --- packages/feature-flags-webpack-plugin/src/index.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/feature-flags-webpack-plugin/src/index.ts b/packages/feature-flags-webpack-plugin/src/index.ts index 85ed249d..1bb97e8a 100644 --- a/packages/feature-flags-webpack-plugin/src/index.ts +++ b/packages/feature-flags-webpack-plugin/src/index.ts @@ -7,7 +7,7 @@ type PluginOptions = { * * @default 'isFeatureEnabled' */ - isFeatureEnabledFnName: string + isFeatureEnabledFnName?: string /** * Object with flags */ @@ -20,7 +20,7 @@ class FeatureFlagsWebpackPlugin { } apply(compiler: Compiler) { - const { isFeatureEnabledFnName, flags } = this.options + const { isFeatureEnabledFnName, flags } = this.options as Required function onCallExpression(expression: Expression, parser: javascript.JavascriptParser) { if (isFeatureFlagFunction(expression, isFeatureEnabledFnName)) { @@ -70,4 +70,5 @@ function isIdentifier(expression: Expression | SpreadElement): expression is Ide return expression.type === 'Identifier' } +export default FeatureFlagsWebpackPlugin module.exports = FeatureFlagsWebpackPlugin From b93101b06ffd5a086087c1121e1bd061d5723054 Mon Sep 17 00:00:00 2001 From: yarastqt Date: Mon, 21 Dec 2020 01:27:25 +0300 Subject: [PATCH 10/15] chore: setup jest config for js files --- .config/jest/jest.config.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.config/jest/jest.config.js b/.config/jest/jest.config.js index 182eed58..1af61aef 100644 --- a/.config/jest/jest.config.js +++ b/.config/jest/jest.config.js @@ -11,4 +11,16 @@ module.exports = { preset: 'ts-jest', testMatch: ['/**/*.test.{ts,tsx}'], collectCoverageFrom: ['**/*.{ts,tsx}', '!**/*.d.ts', '!**/*.test.{ts,tsx}'], + transform: { + '^.+\\.jsx?$': 'ts-jest', + }, + globals: { + 'ts-jest': { + tsConfig: { + noUnusedLocals: false, + noUnusedParameters: false, + allowJs: true, + }, + }, + }, } From a353f06ff262709692f7e67dc698d997c8d4ab12 Mon Sep 17 00:00:00 2001 From: yarastqt Date: Mon, 21 Dec 2020 01:28:29 +0300 Subject: [PATCH 11/15] test: add units for FeatureFlagsWebpackPlugin --- .../__tests__/__internal__/compiler.ts | 38 ------------------- .../__tests__/fixtures/component-a.js | 8 ++++ .../__tests__/fixtures/component-b.js | 10 +++++ .../__tests__/fixtures/features.js | 11 ++++++ .../__tests__/index.test.ts | 32 +++++++++++++--- .../__tests__/internal/compiler.ts | 32 ++++++++++++++++ .../__tests__/internal/getResult.ts | 10 +++++ 7 files changed, 98 insertions(+), 43 deletions(-) delete mode 100644 packages/feature-flags-webpack-plugin/__tests__/__internal__/compiler.ts create mode 100644 packages/feature-flags-webpack-plugin/__tests__/fixtures/component-a.js create mode 100644 packages/feature-flags-webpack-plugin/__tests__/fixtures/component-b.js create mode 100644 packages/feature-flags-webpack-plugin/__tests__/fixtures/features.js create mode 100644 packages/feature-flags-webpack-plugin/__tests__/internal/compiler.ts create mode 100644 packages/feature-flags-webpack-plugin/__tests__/internal/getResult.ts diff --git a/packages/feature-flags-webpack-plugin/__tests__/__internal__/compiler.ts b/packages/feature-flags-webpack-plugin/__tests__/__internal__/compiler.ts deleted file mode 100644 index abad9f0d..00000000 --- a/packages/feature-flags-webpack-plugin/__tests__/__internal__/compiler.ts +++ /dev/null @@ -1,38 +0,0 @@ -import path from 'path' -import webpack from 'webpack' -import { createFsFromVolume, Volume } from 'memfs' - -export function compiler(fixture: any, options: any = {}) { - const $compiler = webpack({ - context: __dirname, - entry: `./${fixture}`, - output: { - path: path.resolve(__dirname), - filename: 'bundle.js', - }, - module: { - rules: [ - { - test: /\.txt$/, - use: { - loader: path.resolve(__dirname, '../src/loader.js'), - options, - }, - }, - ], - }, - plugins: options.plugins, - }) - - $compiler.outputFileSystem = createFsFromVolume(new Volume()) - $compiler.outputFileSystem.join = path.join.bind(path) - - return new Promise((resolve, reject) => { - $compiler.run((err, stats) => { - if (err) reject(err) - if (stats.hasErrors()) reject(new Error(stats.toJson().errors)) - - resolve(stats) - }) - }) -} diff --git a/packages/feature-flags-webpack-plugin/__tests__/fixtures/component-a.js b/packages/feature-flags-webpack-plugin/__tests__/fixtures/component-a.js new file mode 100644 index 00000000..13c55092 --- /dev/null +++ b/packages/feature-flags-webpack-plugin/__tests__/fixtures/component-a.js @@ -0,0 +1,8 @@ +/* eslint-disable no-console */ +import { FEATURE_A, isFeatureEnabled } from './features' + +if (isFeatureEnabled(FEATURE_A)) { + console.log('enabled') +} else { + console.log('disabled') +} diff --git a/packages/feature-flags-webpack-plugin/__tests__/fixtures/component-b.js b/packages/feature-flags-webpack-plugin/__tests__/fixtures/component-b.js new file mode 100644 index 00000000..871dff54 --- /dev/null +++ b/packages/feature-flags-webpack-plugin/__tests__/fixtures/component-b.js @@ -0,0 +1,10 @@ +/* eslint-disable no-console */ +import { FEATURE_A, FEATURE_B, isFeatureEnabled } from './features' + +if (isFeatureEnabled(FEATURE_A)) { + console.log('enabled FEATURE_A') +} + +if (isFeatureEnabled(FEATURE_B)) { + console.log('enabled FEATURE_B') +} diff --git a/packages/feature-flags-webpack-plugin/__tests__/fixtures/features.js b/packages/feature-flags-webpack-plugin/__tests__/fixtures/features.js new file mode 100644 index 00000000..15875b21 --- /dev/null +++ b/packages/feature-flags-webpack-plugin/__tests__/fixtures/features.js @@ -0,0 +1,11 @@ +export const FEATURE_A = { + value: true, +} + +export const FEATURE_B = { + value: true, +} + +export function isFeatureEnabled(_flag) { + return false +} diff --git a/packages/feature-flags-webpack-plugin/__tests__/index.test.ts b/packages/feature-flags-webpack-plugin/__tests__/index.test.ts index 716b31f6..58674e40 100644 --- a/packages/feature-flags-webpack-plugin/__tests__/index.test.ts +++ b/packages/feature-flags-webpack-plugin/__tests__/index.test.ts @@ -1,9 +1,31 @@ +/* eslint-disable quotes */ + import FeatureFlagsWebpackPlugin from '../src/index' -import { compiler } from './__internal__/compiler' +import { compile } from './internal/compiler' +import { getResult } from './internal/getResult' +import { FEATURE_A, FEATURE_B } from './fixtures/features' + +describe('FeatureFlagsWebpackPlugin', () => { + test('should compile code with disabled feature', async () => { + const { compiler } = await compile('./component-a.js') + expect(getResult(compiler)).toMatchInlineSnapshot( + `"(()=>{\\"use strict\\";console.log(\\"disabled\\")})();"`, + ) + }) -test('yyy', async () => { - const plugin = new FeatureFlagsWebpackPlugin() - await compiler('', { plugins: [plugin] }) + test('should compile code with enabled feature', async () => { + const plugin = new FeatureFlagsWebpackPlugin({ flags: { FEATURE_A } }) + const { compiler } = await compile('./component-a.js', { plugins: [plugin] }) + expect(getResult(compiler)).toMatchInlineSnapshot( + `"(()=>{\\"use strict\\";console.log(\\"enabled\\")})();"`, + ) + }) - expect(1).toBe(1) + test('should compile code with two enabled features', async () => { + const plugin = new FeatureFlagsWebpackPlugin({ flags: { FEATURE_A, FEATURE_B } }) + const { compiler } = await compile('./component-b.js', { plugins: [plugin] }) + expect(getResult(compiler)).toMatchInlineSnapshot( + `"(()=>{\\"use strict\\";console.log(\\"enabled FEATURE_A\\"),console.log(\\"enabled FEATURE_B\\")})();"`, + ) + }) }) diff --git a/packages/feature-flags-webpack-plugin/__tests__/internal/compiler.ts b/packages/feature-flags-webpack-plugin/__tests__/internal/compiler.ts new file mode 100644 index 00000000..9283983e --- /dev/null +++ b/packages/feature-flags-webpack-plugin/__tests__/internal/compiler.ts @@ -0,0 +1,32 @@ +import path from 'path' +import webpack, { WebpackPluginInstance } from 'webpack' +import { createFsFromVolume, Volume } from 'memfs' + +type Options = { + plugins?: WebpackPluginInstance[] +} + +export function compile(fixture: string, options: Options = {}): Promise { + const compiler = webpack({ + context: path.resolve(__dirname, '../fixtures'), + mode: 'production', + entry: fixture, + output: { + path: path.resolve(__dirname, '../fixtures'), + filename: 'bundle.js', + }, + plugins: options.plugins, + }) + + // @ts-expect-error + compiler.outputFileSystem = createFsFromVolume(new Volume()) + + return new Promise((resolve, reject) => { + compiler.run((err, stats) => { + if (err) reject(err) + if (stats && stats.hasErrors()) reject(new Error(stats.toJson().errors)) + + resolve({ compiler, stats }) + }) + }) +} diff --git a/packages/feature-flags-webpack-plugin/__tests__/internal/getResult.ts b/packages/feature-flags-webpack-plugin/__tests__/internal/getResult.ts new file mode 100644 index 00000000..668ef7ff --- /dev/null +++ b/packages/feature-flags-webpack-plugin/__tests__/internal/getResult.ts @@ -0,0 +1,10 @@ +import fs from 'fs' +import { resolve } from 'path' +import { Compiler } from 'webpack' + +export function getResult(compiler: Compiler): string { + return (compiler.outputFileSystem as typeof fs).readFileSync( + resolve(__dirname, '../fixtures/bundle.js'), + 'utf-8', + ) +} From d5d1fc67494ed1e077c0751372cadf3134f5d1b6 Mon Sep 17 00:00:00 2001 From: yarastqt Date: Mon, 21 Dec 2020 01:33:32 +0300 Subject: [PATCH 12/15] fix: fix setting default options --- packages/feature-flags-webpack-plugin/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/feature-flags-webpack-plugin/src/index.ts b/packages/feature-flags-webpack-plugin/src/index.ts index 1bb97e8a..6742f357 100644 --- a/packages/feature-flags-webpack-plugin/src/index.ts +++ b/packages/feature-flags-webpack-plugin/src/index.ts @@ -16,7 +16,7 @@ type PluginOptions = { class FeatureFlagsWebpackPlugin { constructor(public options: PluginOptions) { - Object.assign(this.options, { isFeatureEnabledFnName: 'isFeatureEnabled' }) + this.options = Object.assign({ isFeatureEnabledFnName: 'isFeatureEnabled' }, this.options) } apply(compiler: Compiler) { From 80453ebe3c24bd72123ea0be79a4f229e41c9314 Mon Sep 17 00:00:00 2001 From: yarastqt Date: Mon, 21 Dec 2020 01:33:48 +0300 Subject: [PATCH 13/15] test: add unit for isFeatureEnabledFnName case --- .../__tests__/fixtures/component-c.js | 6 ++++++ .../__tests__/fixtures/features.js | 4 ++++ .../__tests__/index.test.ts | 11 +++++++++++ 3 files changed, 21 insertions(+) create mode 100644 packages/feature-flags-webpack-plugin/__tests__/fixtures/component-c.js diff --git a/packages/feature-flags-webpack-plugin/__tests__/fixtures/component-c.js b/packages/feature-flags-webpack-plugin/__tests__/fixtures/component-c.js new file mode 100644 index 00000000..1f62fe38 --- /dev/null +++ b/packages/feature-flags-webpack-plugin/__tests__/fixtures/component-c.js @@ -0,0 +1,6 @@ +/* eslint-disable no-console */ +import { FEATURE_A, isEnabled } from './features' + +if (isEnabled(FEATURE_A)) { + console.log('enabled FEATURE_A') +} diff --git a/packages/feature-flags-webpack-plugin/__tests__/fixtures/features.js b/packages/feature-flags-webpack-plugin/__tests__/fixtures/features.js index 15875b21..72482a58 100644 --- a/packages/feature-flags-webpack-plugin/__tests__/fixtures/features.js +++ b/packages/feature-flags-webpack-plugin/__tests__/fixtures/features.js @@ -9,3 +9,7 @@ export const FEATURE_B = { export function isFeatureEnabled(_flag) { return false } + +export function isEnabled(_flag) { + return false +} diff --git a/packages/feature-flags-webpack-plugin/__tests__/index.test.ts b/packages/feature-flags-webpack-plugin/__tests__/index.test.ts index 58674e40..e31a7090 100644 --- a/packages/feature-flags-webpack-plugin/__tests__/index.test.ts +++ b/packages/feature-flags-webpack-plugin/__tests__/index.test.ts @@ -28,4 +28,15 @@ describe('FeatureFlagsWebpackPlugin', () => { `"(()=>{\\"use strict\\";console.log(\\"enabled FEATURE_A\\"),console.log(\\"enabled FEATURE_B\\")})();"`, ) }) + + test('should compile code with enabled feature and custom feature name', async () => { + const plugin = new FeatureFlagsWebpackPlugin({ + isFeatureEnabledFnName: 'isEnabled', + flags: { FEATURE_A }, + }) + const { compiler } = await compile('./component-c.js', { plugins: [plugin] }) + expect(getResult(compiler)).toMatchInlineSnapshot( + `"(()=>{\\"use strict\\";console.log(\\"enabled FEATURE_A\\")})();"`, + ) + }) }) From 5f11a1dc96bde14d02225fd8af3df2288b0e9a1e Mon Sep 17 00:00:00 2001 From: yarastqt Date: Mon, 21 Dec 2020 01:38:25 +0300 Subject: [PATCH 14/15] chore: fix ts issue for any type --- .../__tests__/internal/compiler.ts | 2 +- packages/feature-flags-webpack-plugin/src/index.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/feature-flags-webpack-plugin/__tests__/internal/compiler.ts b/packages/feature-flags-webpack-plugin/__tests__/internal/compiler.ts index 9283983e..ef5ef17d 100644 --- a/packages/feature-flags-webpack-plugin/__tests__/internal/compiler.ts +++ b/packages/feature-flags-webpack-plugin/__tests__/internal/compiler.ts @@ -18,7 +18,7 @@ export function compile(fixture: string, options: Options = {}): Promise { plugins: options.plugins, }) - // @ts-expect-error + // @ts-ignore compiler.outputFileSystem = createFsFromVolume(new Volume()) return new Promise((resolve, reject) => { diff --git a/packages/feature-flags-webpack-plugin/src/index.ts b/packages/feature-flags-webpack-plugin/src/index.ts index 6742f357..e5a1ffde 100644 --- a/packages/feature-flags-webpack-plugin/src/index.ts +++ b/packages/feature-flags-webpack-plugin/src/index.ts @@ -40,7 +40,9 @@ class FeatureFlagsWebpackPlugin { function onParseJavascript(parser: javascript.JavascriptParser) { parser.hooks.evaluate .for('CallExpression') - .tap('FeatureFlagsWebpackPlugin', (expression) => onCallExpression(expression, parser)) + .tap('FeatureFlagsWebpackPlugin', (expression: Expression) => + onCallExpression(expression, parser), + ) } function onThisCompilation(_compilation: Compilation, compilationParams: any) { From bed3b99af7ffd3af016d3c1cea0a28e43f749d24 Mon Sep 17 00:00:00 2001 From: yarastqt Date: Mon, 21 Dec 2020 01:48:06 +0300 Subject: [PATCH 15/15] wip --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 52b1954c..5262a813 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,9 @@ "lint": "eslint --ext .js,.ts,.tsx .", "postinstall": "npm run bootstrap", "publish:next": "lerna publish --canary --preid dev --npm-tag next --no-git-tag-version", - "unit:coverage": "npm run unit -- --coverage", - "unit": "jest --config .config/jest/jest.config.js" + "__unit:coverage": "npm run unit -- --coverage", + "__unit": "jest --config .config/jest/jest.config.js", + "unit": "lerna run unit" }, "devDependencies": { "@commitlint/cli": "7.2.1",