| // Copyright 2022 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import * as vscode from 'vscode'; |
| import * as flags from './all-feature-flags'; |
| |
| /// the current base stability level -- will be autodetected |
| /// based on version number & config on #init, but can be overriden |
| /// with the `fuchsia.featurePreview` flag (can change at runtime). |
| let stabilityLevel: flags.Stability = 'stable'; |
| |
| /// the current default stability, as detected by the extension version |
| let defaultStability: flags.Stability = 'stable'; |
| |
| let watcher: vscode.Disposable; |
| |
| export class FeatureFlagChangeEvent { |
| private global; |
| constructor(private original: vscode.ConfigurationChangeEvent, global?: boolean) { |
| this.global = global ?? false; |
| } |
| affectsFlag(name: string): boolean { |
| if (this.global) { |
| // it'd be complicated to figure out which flags would've flipped, so prob fine to just tell everyone |
| // that they're affected |
| return true; |
| } |
| return this.original.affectsConfiguration(`fuchsia.features.${name}`); |
| } |
| } |
| const onDidChangeFeatureFlagEmitter: vscode.EventEmitter<FeatureFlagChangeEvent> |
| = new vscode.EventEmitter(); |
| |
| /** |
| * Event emitted when a feature flag changes value. |
| * |
| * If you need to activate or deactivate features based on flags, listen to this. |
| */ |
| export const onDidChangeFeatureFlag: vscode.Event<FeatureFlagChangeEvent> |
| = onDidChangeFeatureFlagEmitter.event; |
| |
| /** |
| * activates the feature flag system, assuming the given extension version. |
| * |
| * You can get the extension version with `ctx.extension.packageJSON.version`. |
| */ |
| export function activate(extensionVersion: string) { |
| const [_major, minor, _patch] = extensionVersion.split('.'); |
| const isPrerelease = parseInt(minor) % 2 === 1; // prerelease versions are always odd |
| |
| defaultStability = isPrerelease ? 'nightly' : 'stable'; |
| |
| setStabilityFromConfig(); |
| watcher = vscode.workspace.onDidChangeConfiguration((evt) => { |
| if (evt.affectsConfiguration('fuchsia.featurePreview')) { |
| setStabilityFromConfig(); |
| onDidChangeFeatureFlagEmitter.fire(new FeatureFlagChangeEvent(evt, true)); |
| return; |
| } |
| |
| if (evt.affectsConfiguration('fuchsia.features')) { |
| onDidChangeFeatureFlagEmitter.fire(new FeatureFlagChangeEvent(evt)); |
| } |
| }); |
| } |
| |
| /** |
| * deactives the feature flag system |
| */ |
| export function deactivate() { |
| if (watcher) { |
| watcher.dispose(); |
| } |
| } |
| |
| /** |
| * resets #stabilityLevel from either the #defaultStability or the override configuration |
| * (fuchsia.featurePreview) |
| */ |
| function setStabilityFromConfig() { |
| const override = vscode.workspace.getConfiguration('fuchsia').get('featurePreview'); |
| if (override === 'auto') { |
| stabilityLevel = defaultStability; |
| } else { |
| stabilityLevel = override as flags.Stability; |
| } |
| } |
| |
| /** checks if lhs >= rhs, in stability terms */ |
| function isAtLeast(lhs: flags.Stability, rhs: flags.Stability): boolean { |
| const levels = { |
| 'never': -1, |
| 'nightly': 0, |
| 'stable': 1, |
| }; |
| return levels[lhs] >= levels[rhs]; |
| } |
| |
| /** |
| * Check if the given flag with with the given stability level would be enabled |
| * in the current environment, either by configuration override or current |
| * global stability level. |
| * |
| * Generally, you don't want to use this outside of generated code. Use the |
| * functions from feature-flags.ts instead, like |
| */ |
| export function enabled(flagName: flags.Known): boolean { |
| const opt = vscode.workspace.getConfiguration('fuchsia.features').get(flagName); |
| switch (opt) { |
| case 'auto': |
| const stability = flags.features[flagName].stability; |
| return isAtLeast(stability, stabilityLevel); |
| case 'enabled': |
| return true; |
| case 'disabled': |
| return false; |
| default: |
| throw new Error( |
| `feature flag ${flagName} set to invalid value "${opt}" (must be enabled|disabled|auto)`); |
| } |
| } |
| |
| // NB(sollyross): these are in a separate file so that we can load it in |
| // our build generator and inject the corresponding JSON into package.json |
| |
| /** |
| * The list of all feature flags. |
| */ |
| export { Stability, features } from './all-feature-flags'; |