From 59362292e0b06ef3abf72ba16c2fdc133bd1ac47 Mon Sep 17 00:00:00 2001 From: Eugene Kashida Date: Thu, 23 Jan 2020 07:36:21 +0900 Subject: [PATCH] feat(features): runtime flags can only be imported by compiler (#1690) * feat(features): runtime flags can only be imported by compiler * chore: review feedback * test: update error message test --- .../@lwc/features/src/__tests__/flags.spec.ts | 103 +++--------------- .../@lwc/features/src/babel-plugin/index.js | 5 + 2 files changed, 18 insertions(+), 90 deletions(-) diff --git a/packages/@lwc/features/src/__tests__/flags.spec.ts b/packages/@lwc/features/src/__tests__/flags.spec.ts index 8c621680e8..5bc45b10b9 100644 --- a/packages/@lwc/features/src/__tests__/flags.spec.ts +++ b/packages/@lwc/features/src/__tests__/flags.spec.ts @@ -49,30 +49,6 @@ pluginTester({ } `, }, - 'should not transform null runtime flags': { - code: ` - import { runtimeFlags } from '@lwc/features'; - - if (runtimeFlags.ENABLE_FEATURE_NULL) { - console.log('runtimeFlags.ENABLE_FEATURE_NULL'); - } - - if (!runtimeFlags.ENABLE_FEATURE_NULL) { - console.log('!runtimeFlags.ENABLE_FEATURE_NULL'); - } - `, - output: ` - import { runtimeFlags } from '@lwc/features'; - - if (runtimeFlags.ENABLE_FEATURE_NULL) { - console.log('runtimeFlags.ENABLE_FEATURE_NULL'); - } - - if (!runtimeFlags.ENABLE_FEATURE_NULL) { - console.log('!runtimeFlags.ENABLE_FEATURE_NULL'); - } - `, - }, 'should transform boolean-true compile-time flags': { code: ` import features from '@lwc/features'; @@ -97,30 +73,6 @@ pluginTester({ } `, }, - 'should not transform boolean-true runtime flags': { - code: ` - import { runtimeFlags } from '@lwc/features'; - - if (runtimeFlags.ENABLE_FEATURE_TRUE) { - console.log('runtimeFlags.ENABLE_FEATURE_TRUE'); - } - - if (!runtimeFlags.ENABLE_FEATURE_TRUE) { - console.log('!runtimeFlags.ENABLE_FEATURE_TRUE'); - } - `, - output: ` - import { runtimeFlags } from '@lwc/features'; - - if (runtimeFlags.ENABLE_FEATURE_TRUE) { - console.log('runtimeFlags.ENABLE_FEATURE_TRUE'); - } - - if (!runtimeFlags.ENABLE_FEATURE_TRUE) { - console.log('!runtimeFlags.ENABLE_FEATURE_TRUE'); - } - `, - }, 'should transform boolean-false compile-time flags': { code: ` import features from '@lwc/features'; @@ -145,30 +97,6 @@ pluginTester({ } `, }, - 'should not transform boolean-false runtime flags': { - code: ` - import { runtimeFlags } from '@lwc/features'; - - if (runtimeFlags.ENABLE_FEATURE_FALSE) { - console.log('runtimeFlags.ENABLE_FEATURE_FALSE'); - } - - if (!runtimeFlags.ENABLE_FEATURE_FALSE) { - console.log('!runtimeFlags.ENABLE_FEATURE_FALSE'); - } - `, - output: ` - import { runtimeFlags } from '@lwc/features'; - - if (runtimeFlags.ENABLE_FEATURE_FALSE) { - console.log('runtimeFlags.ENABLE_FEATURE_FALSE'); - } - - if (!runtimeFlags.ENABLE_FEATURE_FALSE) { - console.log('!runtimeFlags.ENABLE_FEATURE_FALSE'); - } - `, - }, 'should not transform if-tests that are not member expressions (compile-time)': { code: ` import FEATURES from '@lwc/features'; @@ -185,22 +113,6 @@ pluginTester({ } `, }, - 'should not transform if-tests that are not member expressions (runtime)': { - code: ` - import { runtimeFlags } from '@lwc/features'; - - if (isTrue(runtimeFlags.ENABLE_FEATURE_TRUE)) { - console.log('runtimeFlags.ENABLE_FEATURE_TRUE'); - } - `, - output: ` - import { runtimeFlags } from '@lwc/features'; - - if (isTrue(runtimeFlags.ENABLE_FEATURE_TRUE)) { - console.log('runtimeFlags.ENABLE_FEATURE_TRUE'); - } - `, - }, 'should not transform feature flags when used with a ternary operator': { code: ` import feats from '@lwc/features'; @@ -211,6 +123,17 @@ pluginTester({ console.log(feats.ENABLE_FEATURE_NULL ? 'foo' : 'bar'); `, }, + 'should throw an error if runtimeFlags are imported': { + error: + 'Invalid import of "runtimeFlags" from "@lwc/features". Use the default export from "@lwc/features" instead of the "runtimeFlags" export when implementing your feature behind a flag.', + code: ` + import { runtimeFlags } from '@lwc/features'; + + if (runtimeFlags.ENABLE_FEATURE_NULL) { + console.log('runtimeFlags.ENABLE_FEATURE_NULL'); + } + `, + }, 'should throw an error if the flag is undefined': { error: 'Invalid feature flag "ENABLE_THE_BEER". Flag is undefined.', code: ` @@ -302,14 +225,14 @@ pluginTester({ }, 'should not transform member expressions that are not runtime flag lookups': { code: ` - import { runtimeFlags } from '@lwc/features'; + import featureFlags from '@lwc/features'; if (churroteria.ENABLE_FEATURE_TRUE) { console.log('churroteria.ENABLE_FEATURE_TRUE'); } `, output: ` - import { runtimeFlags } from '@lwc/features'; + import featureFlags, { runtimeFlags } from '@lwc/features'; if (churroteria.ENABLE_FEATURE_TRUE) { console.log('churroteria.ENABLE_FEATURE_TRUE'); diff --git a/packages/@lwc/features/src/babel-plugin/index.js b/packages/@lwc/features/src/babel-plugin/index.js index d1b6d013c8..72a5053340 100644 --- a/packages/@lwc/features/src/babel-plugin/index.js +++ b/packages/@lwc/features/src/babel-plugin/index.js @@ -38,6 +38,11 @@ module.exports = function({ types: t }) { const didImportRuntimeFlags = specifiers.some(specifier => { return specifier.local && specifier.local.name === RUNTIME_FLAGS_IDENTIFIER; }); + if (didImportRuntimeFlags && !this.opts.prod) { + throw new Error( + `Invalid import of "${RUNTIME_FLAGS_IDENTIFIER}" from "${FEATURES_PACKAGE_NAME}". Use the default export from "${FEATURES_PACKAGE_NAME}" instead of the "${RUNTIME_FLAGS_IDENTIFIER}" export when implementing your feature behind a flag.` + ); + } if (!didImportRuntimeFlags) { // Blindly import a binding for `runtimeFlags` if we haven't // already. Tree-shaking will simply remove it if unused.