From 9a1983d50fc5fcd55f3810a30643d286ceb7543d Mon Sep 17 00:00:00 2001 From: Daniel OBrien Date: Thu, 8 Feb 2024 07:27:25 -0500 Subject: [PATCH] add interfaces to fix circular import move commands to consts --- src/api.ts | 32 ++-- src/commands/clearGlobalContext.ts | 2 +- src/commands/configureLaunchDarkly.ts | 5 +- .../configureLaunchDarklyEnvironment.ts | 56 +++--- src/commands/createFlag.ts | 9 +- src/commands/enableCodeLens.ts | 9 +- src/commands/evaluateFlag.ts | 2 +- src/commands/flagActions.ts | 15 +- src/commands/generalCommands.ts | 4 +- src/commands/openLaunchDarkly.ts | 11 +- src/commands/selectRule.ts | 14 +- src/commands/setGlobal.ts | 5 +- src/commands/setMaintainer.ts | 9 +- src/commands/setWorkspaceEnabled.ts | 6 +- src/commands/toggleFlagContext.ts | 9 +- src/configurationMenu.ts | 8 +- src/createFlagMenu.ts | 7 +- src/extension.ts | 16 +- src/flagStore.ts | 25 ++- src/{utils.ts => generalUtils.ts} | 61 ++---- src/ldExtensionConfiguration.ts | 53 +++--- src/models.ts | 179 +++++++++++++++++- src/providers.ts | 7 +- src/providers/authProvider.ts | 12 +- src/providers/codeRefs.ts | 8 +- src/providers/completion.ts | 12 +- src/providers/flagLens.ts | 10 +- src/providers/flagListView.ts | 11 +- src/providers/flagsView.ts | 43 +++-- src/providers/hover.ts | 6 +- src/providers/metricsView.ts | 3 +- src/providers/quickLinksView.ts | 15 +- src/providers/releaseViewProvider.ts | 9 +- src/utils/FlagNode.ts | 5 +- src/utils/checkCoderefs.ts | 2 +- src/utils/commands.ts | 26 +++ src/utils/flagCodeSearch.ts | 24 +++ src/utils/hover.ts | 5 +- src/utils/legacyAuth.ts | 4 + src/utils/registerCommand.ts | 12 ++ test/providers.test.ts | 3 +- 41 files changed, 486 insertions(+), 268 deletions(-) rename src/{utils.ts => generalUtils.ts} (83%) create mode 100644 src/utils/commands.ts create mode 100644 src/utils/flagCodeSearch.ts create mode 100644 src/utils/legacyAuth.ts create mode 100644 src/utils/registerCommand.ts diff --git a/src/api.ts b/src/api.ts index 3c21b80f..baaf15b8 100644 --- a/src/api.ts +++ b/src/api.ts @@ -5,14 +5,23 @@ const axios = require('axios').default; import axiosRetry from 'axios-retry'; import retry from 'axios-retry-after'; -import { Configuration } from './configuration'; -import { FlagLink, InstructionPatch, NewFlag, ProjectAPI, ReleasePhase, ReleasePipeline } from './models'; +import { + FlagLink, + IConfiguration, + ILDExtensionConfiguration, + InstructionPatch, + LaunchDarklyAuthenticationSession, + NewFlag, + ProjectAPI, + ReleasePhase, + ReleasePipeline, +} from './models'; import { Resource, Project, FeatureFlag, Environment, PatchOperation, PatchComment, Metric } from './models'; import { RepositoryRep } from 'launchdarkly-api-typescript'; import { LDExtensionConfiguration } from './ldExtensionConfiguration'; -import { LaunchDarklyAuthenticationSession } from './providers/authProvider'; import { debuglog } from 'util'; -import { legacyAuth } from './utils'; +import { CMD_LD_CONFIG } from './utils/commands'; +import { legacyAuth } from './utils/legacyAuth'; interface CreateOptionsParams { method?: string; @@ -83,10 +92,10 @@ axiosRetry(axios, { retries: 2, retryDelay: axiosRetry.exponentialDelay }); // LaunchDarklyAPI is a wrapper around request-promise-native for requesting data from LaunchDarkly's REST API. The caller is expected to catch all exceptions. export class LaunchDarklyAPI { - private readonly config: Configuration; - private readonly ldConfig: LDExtensionConfiguration; + private readonly config: IConfiguration; + private readonly ldConfig: ILDExtensionConfiguration; - constructor(config: Configuration, ldConfig: LDExtensionConfiguration) { + constructor(config: IConfiguration, ldConfig: ILDExtensionConfiguration) { this.config = config; this.ldConfig = ldConfig; } @@ -151,8 +160,7 @@ export class LaunchDarklyAPI { 'Configure LaunchDarkly Extension', ) .then((selection) => { - if (selection === 'Configure LaunchDarkly Extension') - commands.executeCommand('extension.configureLaunchDarkly'); + if (selection === 'Configure LaunchDarkly Extension') commands.executeCommand(CMD_LD_CONFIG); }); } } @@ -195,8 +203,7 @@ export class LaunchDarklyAPI { 'Configure LaunchDarkly Extension', ) .then((selection) => { - if (selection === 'Configure LaunchDarkly Extension') - commands.executeCommand('extension.configureLaunchDarkly'); + if (selection === 'Configure LaunchDarkly Extension') commands.executeCommand(CMD_LD_CONFIG); }); } } @@ -214,8 +221,7 @@ export class LaunchDarklyAPI { 'Configure LaunchDarkly Extension', ) .then((selection) => { - if (selection === 'Configure LaunchDarkly Extension') - commands.executeCommand('extension.configureLaunchDarkly'); + if (selection === 'Configure LaunchDarkly Extension') commands.executeCommand(CMD_LD_CONFIG); }); } } diff --git a/src/commands/clearGlobalContext.ts b/src/commands/clearGlobalContext.ts index 5ed990fe..bc7bdc33 100644 --- a/src/commands/clearGlobalContext.ts +++ b/src/commands/clearGlobalContext.ts @@ -1,5 +1,5 @@ import { commands, Disposable, window } from 'vscode'; -import { extensionReload } from '../utils'; +import { extensionReload } from '../generalUtils'; import { LDExtensionConfiguration } from '../ldExtensionConfiguration'; export default async function globalClearCmd(config: LDExtensionConfiguration) { diff --git a/src/commands/configureLaunchDarkly.ts b/src/commands/configureLaunchDarkly.ts index babf50f0..8874139b 100644 --- a/src/commands/configureLaunchDarkly.ts +++ b/src/commands/configureLaunchDarkly.ts @@ -2,10 +2,11 @@ import { Disposable, ProgressLocation, window } from 'vscode'; import { ConfigurationMenu } from '../configurationMenu'; import { FlagStore } from '../flagStore'; import { LDExtensionConfiguration } from '../ldExtensionConfiguration'; -import { registerCommand } from '../utils'; +import { CMD_LD_CONFIG } from '../utils/commands'; +import { registerCommand } from '../utils/registerCommand'; export default function configureLaunchDarkly(config: LDExtensionConfiguration) { - const configureExtension: Disposable = registerCommand('extension.configureLaunchDarkly', async () => { + const configureExtension: Disposable = registerCommand(CMD_LD_CONFIG, async () => { try { const configurationMenu = new ConfigurationMenu(config); await configurationMenu.configure(); diff --git a/src/commands/configureLaunchDarklyEnvironment.ts b/src/commands/configureLaunchDarklyEnvironment.ts index f870f679..5b76a4d4 100644 --- a/src/commands/configureLaunchDarklyEnvironment.ts +++ b/src/commands/configureLaunchDarklyEnvironment.ts @@ -1,36 +1,34 @@ import { commands, Disposable, window } from 'vscode'; //import { sortNameCaseInsensitive } from '../api'; -import { extensionReload } from '../utils'; -import { LDExtensionConfiguration } from '../ldExtensionConfiguration'; +import { extensionReload } from '../generalUtils'; +import { CMD_LD_CONFIG_ENV } from '../utils/commands'; +import { ILDExtensionConfiguration } from '../models'; -export default async function configureEnvironmentCmd(config: LDExtensionConfiguration): Promise { - const configureEnvironmentCmd = commands.registerCommand( - 'launchdarkly.configureLaunchDarklyEnvironment', - async () => { - try { - //const intConfig = config.getConfig(); - const api = config.getApi(); - if (!config.getConfig()) { - return; - } - const project = await api?.getProject(config.getConfig().project); - if (!project) { - window.showErrorMessage(`[LaunchDarkly] Please Configure LaunchDarkly Extension`); - return; - } - //const environments = project.environments.sort(sortNameCaseInsensitive); - const environments = project.environments.items; - const newEnvironment = await window.showQuickPick(environments.map((env) => env.key)); - if (newEnvironment) { - await config.getConfig().update('env', newEnvironment, false); - await extensionReload(config, true); - } - } catch (err) { - console.log(err); - window.showErrorMessage(`[LaunchDarkly] ${err}`); +export default async function configureEnvironmentCmd(config: ILDExtensionConfiguration): Promise { + const configureEnvironmentCmd = commands.registerCommand(CMD_LD_CONFIG_ENV, async () => { + try { + //const intConfig = config.getConfig(); + const api = config.getApi(); + if (!config.getConfig()) { + return; } - }, - ); + const project = await api?.getProject(config.getConfig().project); + if (!project) { + window.showErrorMessage(`[LaunchDarkly] Please Configure LaunchDarkly Extension`); + return; + } + //const environments = project.environments.sort(sortNameCaseInsensitive); + const environments = project.environments.items; + const newEnvironment = await window.showQuickPick(environments.map((env) => env.key)); + if (newEnvironment) { + await config.getConfig().update('env', newEnvironment, false); + await extensionReload(config, true); + } + } catch (err) { + console.log(err); + window.showErrorMessage(`[LaunchDarkly] ${err}`); + } + }); config.getCtx().subscriptions.push(configureEnvironmentCmd); diff --git a/src/commands/createFlag.ts b/src/commands/createFlag.ts index 793109ff..3c35e204 100644 --- a/src/commands/createFlag.ts +++ b/src/commands/createFlag.ts @@ -1,10 +1,11 @@ import { Disposable } from 'vscode'; import { CreateFlagMenu } from '../createFlagMenu'; -import { LDExtensionConfiguration } from '../ldExtensionConfiguration'; -import { registerCommand } from '../utils'; +import { CMD_LD_CREATE_FLAG } from '../utils/commands'; +import { registerCommand } from '../utils/registerCommand'; +import { ILDExtensionConfiguration } from '../models'; -export default function createFlagCmd(config: LDExtensionConfiguration): Disposable { - const createFlagCmd = registerCommand('launchdarkly.createFlag', async () => { +export default function createFlagCmd(config: ILDExtensionConfiguration): Disposable { + const createFlagCmd = registerCommand(CMD_LD_CREATE_FLAG, async () => { const configurationMenu = new CreateFlagMenu(config); await configurationMenu.collectInputs(); }); diff --git a/src/commands/enableCodeLens.ts b/src/commands/enableCodeLens.ts index 2bc73a24..41d34129 100644 --- a/src/commands/enableCodeLens.ts +++ b/src/commands/enableCodeLens.ts @@ -1,9 +1,10 @@ import { Disposable, workspace } from 'vscode'; -import { LDExtensionConfiguration } from '../ldExtensionConfiguration'; -import { registerCommand } from '../utils'; +import { CMD_LD_ENABLE_LENS } from '../utils/commands'; +import { registerCommand } from '../utils/registerCommand'; +import { ILDExtensionConfiguration } from '../models'; -export default function enableCodeLensConfig(config: LDExtensionConfiguration): Disposable { - const enableCodeLens: Disposable = registerCommand('launchdarkly.enableCodeLens', async () => { +export default function enableCodeLensConfig(config: ILDExtensionConfiguration): Disposable { + const enableCodeLens: Disposable = registerCommand(CMD_LD_ENABLE_LENS, async () => { workspace.getConfiguration('launchdarkly').update('enableCodeLens', !config.getConfig().enableCodeLens); config.getConfig().enableCodeLens = !config.getConfig().enableCodeLens; }); diff --git a/src/commands/evaluateFlag.ts b/src/commands/evaluateFlag.ts index 76e4ecf8..473d327d 100644 --- a/src/commands/evaluateFlag.ts +++ b/src/commands/evaluateFlag.ts @@ -4,7 +4,7 @@ import os from 'os'; import { LDExtensionConfiguration } from '../ldExtensionConfiguration'; import { LDMultiKindContext, LDSingleKindContext } from '@launchdarkly/node-server-sdk'; import { YamlContextReader } from '../utils/contextYAML'; -import { registerCommand } from '../utils'; +import { registerCommand } from '../utils/registerCommand'; // Not officially implemented. Leaving for future decision. diff --git a/src/commands/flagActions.ts b/src/commands/flagActions.ts index becdda23..0089cfbf 100644 --- a/src/commands/flagActions.ts +++ b/src/commands/flagActions.ts @@ -1,13 +1,16 @@ import { QuickPickItemKind, Disposable, commands, window } from 'vscode'; -import { LDExtensionConfiguration } from '../ldExtensionConfiguration'; import { FlagQuickPickItem, targetFlag } from './selectRule'; import { ToggleCache } from '../toggleCache'; -import { flagCodeSearch, flagOffFallthroughPatch, registerCommand, toggleFlag } from '../utils'; +import { flagOffFallthroughPatch, toggleFlag } from '../generalUtils'; +import { CMD_LD_FLAG_ACTION, CMD_LD_OPEN_BROWSER } from '../utils/commands'; +import { flagCodeSearch } from '../utils/flagCodeSearch'; +import { registerCommand } from '../utils/registerCommand'; +import { ILDExtensionConfiguration } from '../models'; const cache = new ToggleCache(); -export default function flagCmd(config: LDExtensionConfiguration): Disposable { - const flagCmd = registerCommand('launchdarkly.quickFlag', async () => { +export default function flagCmd(config: ILDExtensionConfiguration): Disposable { + const flagCmd = registerCommand(CMD_LD_FLAG_ACTION, async () => { const flags = await config.getFlagStore()?.allFlagsMetadata(); if (flags === undefined) { // Errors would be handled in the flagStore @@ -79,7 +82,7 @@ export default function flagCmd(config: LDExtensionConfiguration): Disposable { const linkUrl = `${config.getSession().fullUri}/${config.getConfig().project}/${ config.getConfig().env }/features/${flagWindow.value}`; - commands.executeCommand('launchdarkly.openBrowser', linkUrl); + commands.executeCommand(CMD_LD_OPEN_BROWSER, linkUrl); break; } case 'Toggle Flag': @@ -102,7 +105,7 @@ export default function flagCmd(config: LDExtensionConfiguration): Disposable { return flagCmd; } -function revealFlag(config: LDExtensionConfiguration, key: string) { +function revealFlag(config: ILDExtensionConfiguration, key: string) { const node = config.getFlagView().flagNodes.filter((node) => node.flagKey === key)[0]; config.getFlagTreeProvider().reveal(node, { select: true, focus: true, expand: true }); } diff --git a/src/commands/generalCommands.ts b/src/commands/generalCommands.ts index a99568e5..0e847d6a 100644 --- a/src/commands/generalCommands.ts +++ b/src/commands/generalCommands.ts @@ -6,11 +6,11 @@ import enableCodeLensConfig from './enableCodeLens'; import configureEnvironmentCmd from './configureLaunchDarklyEnvironment'; import selectRuleCmd from './selectRule'; import setMaintainerCmd from './setMaintainer'; -import { LDExtensionConfiguration } from '../ldExtensionConfiguration'; import { SetGlobalCmd } from './setGlobal'; import flagCmd from './flagActions'; +import { ILDExtensionConfiguration } from '../models'; -export default async function generalCommands(LDExtenConfig: LDExtensionConfiguration) { +export default async function generalCommands(LDExtenConfig: ILDExtensionConfiguration) { const createFlag = createFlagCmd(LDExtenConfig); const toggleFlagCmd = toggleFlagCtxCmd(LDExtenConfig); const setMaintainerCmd1 = setMaintainerCmd(LDExtenConfig); diff --git a/src/commands/openLaunchDarkly.ts b/src/commands/openLaunchDarkly.ts index 810ca2cd..c649f0df 100644 --- a/src/commands/openLaunchDarkly.ts +++ b/src/commands/openLaunchDarkly.ts @@ -1,14 +1,13 @@ import { commands, Disposable, window } from 'vscode'; import { FLAG_KEY_REGEX } from '../providers'; import { kebabCase } from 'lodash'; -import { FlagStore } from '../flagStore'; -import { FeatureFlagConfig } from '../models'; +import { FeatureFlagConfig, FlagStoreInterface, ILDExtensionConfiguration } from '../models'; import * as url from 'url'; import opn = require('opn'); -import { LDExtensionConfiguration } from '../ldExtensionConfiguration'; +import { CMD_LD_OPEN } from '../utils/commands'; -export default function openInLdCmd(config: LDExtensionConfiguration): Disposable { - const openInLdCmd = commands.registerTextEditorCommand('launchdarkly.openInLaunchDarkly', async (editor) => { +export default function openInLdCmd(config: ILDExtensionConfiguration): Disposable { + const openInLdCmd = commands.registerTextEditorCommand(CMD_LD_OPEN, async (editor) => { const flagKey = editor.document.getText( editor.document.getWordRangeAtPosition(editor.selection.anchor, FLAG_KEY_REGEX), ); @@ -52,7 +51,7 @@ export default function openInLdCmd(config: LDExtensionConfiguration): Disposabl return openInLdCmd; } -const openFlagInBrowser = async (config: LDExtensionConfiguration, flagKey: string, flagStore: FlagStore) => { +const openFlagInBrowser = async (config: ILDExtensionConfiguration, flagKey: string, flagStore: FlagStoreInterface) => { const { flag } = await flagStore.getFeatureFlag(flagKey); // Default to first environment diff --git a/src/commands/selectRule.ts b/src/commands/selectRule.ts index b407a526..9ba9ba31 100644 --- a/src/commands/selectRule.ts +++ b/src/commands/selectRule.ts @@ -2,12 +2,12 @@ import { Disposable, ProgressLocation, QuickPickItem, QuickPickItemKind, window import { YAMLIndividualTarget, YamlReader, YAMLRuleTarget } from '../utils/rulesYaml'; import { ToggleCache } from '../toggleCache'; import os from 'os'; -import { LDExtensionConfiguration } from '../ldExtensionConfiguration'; import { Dictionary, isArray } from 'lodash'; import crypto from 'crypto'; -import { Clause, FeatureFlag, InstructionPatch } from '../models'; -import { registerCommand } from '../utils'; +import { Clause, FeatureFlag, ILDExtensionConfiguration, InstructionPatch } from '../models'; import { logDebugMessage } from '../utils/logDebugMessage'; +import { CMD_LD_PICK_RULES } from '../utils/commands'; +import { registerCommand } from '../utils/registerCommand'; const cache = new ToggleCache(); const revertLastCmd = {}; @@ -26,8 +26,8 @@ export interface FlagQuickPickItem extends QuickPickItem { value: string; } -export default function selectRuleCmd(config: LDExtensionConfiguration): Disposable { - const selectRuleCmd = registerCommand('launchdarkly.quickPickRules', async () => { +export default function selectRuleCmd(config: ILDExtensionConfiguration): Disposable { + const selectRuleCmd = registerCommand(CMD_LD_PICK_RULES, async () => { const flags = await config.getFlagStore()?.allFlagsMetadata(); if (flags === undefined) { // Errors would be handled in the flagStore @@ -147,7 +147,7 @@ function removeRuleInstruction( async function updateFlag( flagWindow: FlagQuickPickItem, cache: ToggleCache, - config: LDExtensionConfiguration, + config: ILDExtensionConfiguration, instruction: InstructionPatch, origFlag?: FeatureFlag, ): Promise { @@ -394,7 +394,7 @@ function generateRefFromClauses(clauses) { export async function targetFlag( flagWindow, cache: ToggleCache, - config: LDExtensionConfiguration, + config: ILDExtensionConfiguration, flags: Dictionary, ) { const addRemove: Array = []; diff --git a/src/commands/setGlobal.ts b/src/commands/setGlobal.ts index 56763643..e0578855 100644 --- a/src/commands/setGlobal.ts +++ b/src/commands/setGlobal.ts @@ -1,10 +1,11 @@ import { ExtensionContext, window } from 'vscode'; -import { registerCommand } from '../utils'; +import { CMD_LD_SET_GLOBAL_DEFAULT } from '../utils/commands'; +import { registerCommand } from '../utils/registerCommand'; export function SetGlobalCmd(ctx: ExtensionContext) { const proj = ctx.workspaceState.get('project'); const env = ctx.workspaceState.get('env'); - const disposable = registerCommand('launchdarkly.setGlobalDefaults', () => { + const disposable = registerCommand(CMD_LD_SET_GLOBAL_DEFAULT, () => { // The code you want to run when the command is executed window .showInformationMessage( diff --git a/src/commands/setMaintainer.ts b/src/commands/setMaintainer.ts index 01a98a66..047cfae3 100644 --- a/src/commands/setMaintainer.ts +++ b/src/commands/setMaintainer.ts @@ -1,11 +1,12 @@ import { Disposable, window } from 'vscode'; -import { LDExtensionConfiguration } from '../ldExtensionConfiguration'; -import { registerCommand } from '../utils'; +import { CMD_LD_SET_MAINTAINER } from '../utils/commands'; +import { registerCommand } from '../utils/registerCommand'; +import { ILDExtensionConfiguration } from '../models'; // This function is only called from a location that already checks if a team is available. // If that changes more logic needs to be moved here -export default function setMaintainerCmd(config: LDExtensionConfiguration): Disposable { - const setMaintainerCmd = registerCommand('launchdarkly.setMaintainer', async (args) => { +export default function setMaintainerCmd(config: ILDExtensionConfiguration): Disposable { + const setMaintainerCmd = registerCommand(CMD_LD_SET_MAINTAINER, async (args) => { try { const key = args; if (key) { diff --git a/src/commands/setWorkspaceEnabled.ts b/src/commands/setWorkspaceEnabled.ts index b1aecde3..2b886aa2 100644 --- a/src/commands/setWorkspaceEnabled.ts +++ b/src/commands/setWorkspaceEnabled.ts @@ -1,8 +1,10 @@ import { LDExtensionConfiguration } from '../ldExtensionConfiguration'; -import { extensionReload, registerCommand } from '../utils'; +import { extensionReload } from '../generalUtils'; +import { CMD_LD_ENABLE_WORKSPACE } from '../utils/commands'; +import { registerCommand } from '../utils/registerCommand'; export function SetWorkspaceCmd(config: LDExtensionConfiguration) { - const disposable = registerCommand('launchdarkly.enableWorkspace', async () => { + const disposable = registerCommand(CMD_LD_ENABLE_WORKSPACE, async () => { // The code you want to run when the command is executed if ( config.getCtx().workspaceState.get('isDisabledForWorkspace') !== false || diff --git a/src/commands/toggleFlagContext.ts b/src/commands/toggleFlagContext.ts index 2e45cfa0..01acb697 100644 --- a/src/commands/toggleFlagContext.ts +++ b/src/commands/toggleFlagContext.ts @@ -1,9 +1,10 @@ import { Disposable, window } from 'vscode'; -import { LDExtensionConfiguration } from '../ldExtensionConfiguration'; -import { registerCommand } from '../utils'; +import { CMD_LD_TOGGLE_CTX } from '../utils/commands'; +import { registerCommand } from '../utils/registerCommand'; +import { ILDExtensionConfiguration } from '../models'; -export default function toggleFlagCtxCmd(config: LDExtensionConfiguration): Disposable { - const toggleFlagCtxCmd = registerCommand('launchdarkly.toggleFlagContext', async (args) => { +export default function toggleFlagCtxCmd(config: ILDExtensionConfiguration): Disposable { + const toggleFlagCtxCmd = registerCommand(CMD_LD_TOGGLE_CTX, async (args) => { try { const key = args ? args : (config.getCtx().workspaceState.get('LDFlagKey') as string); diff --git a/src/configurationMenu.ts b/src/configurationMenu.ts index b910efa8..79eeaade 100644 --- a/src/configurationMenu.ts +++ b/src/configurationMenu.ts @@ -10,12 +10,10 @@ import { } from 'vscode'; import { MultiStepInput } from './multiStepInput'; -import { LaunchDarklyAPI } from './api'; -import { Resource, Project, Environment } from './models'; -import { extensionReload } from './utils'; +import { Resource, Project, Environment, LaunchDarklyAuthenticationSession, LaunchDarklyAPIInterface } from './models'; +import { extensionReload } from './generalUtils'; import { logDebugMessage } from './utils/logDebugMessage'; import { LDExtensionConfiguration } from './ldExtensionConfiguration'; -import { LaunchDarklyAuthenticationSession } from './providers/authProvider'; interface CMState { baseUri: string; env: string; @@ -23,7 +21,7 @@ interface CMState { } export class ConfigurationMenu { private readonly config: LDExtensionConfiguration; - private api: LaunchDarklyAPI; + private api: LaunchDarklyAPIInterface; private readonly ctx: ExtensionContext; private title: string; private totalSteps: number; diff --git a/src/createFlagMenu.ts b/src/createFlagMenu.ts index e3c126d7..f7f43cf5 100644 --- a/src/createFlagMenu.ts +++ b/src/createFlagMenu.ts @@ -3,8 +3,7 @@ import { ProgressLocation, QuickInput, QuickPickItem, env, tasks, window, worksp import { MultiStepInput, QuickPickParameters } from './multiStepInput'; import { LaunchDarklyAPI } from './api'; import { kebabCase } from 'lodash'; -import { FeatureFlag, NewFlag, ReleasePipeline } from './models'; -import { LDExtensionConfiguration } from './ldExtensionConfiguration'; +import { FeatureFlag, ILDExtensionConfiguration, NewFlag, ReleasePipeline } from './models'; export interface State { name: string; key: string; @@ -35,7 +34,7 @@ interface PipelineQuickPickItem extends QuickPickItem { /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ export class CreateFlagMenu { - private readonly config: LDExtensionConfiguration; + private readonly config: ILDExtensionConfiguration; private api: LaunchDarklyAPI; private title: string; private totalSteps: number; @@ -43,7 +42,7 @@ export class CreateFlagMenu { public flag: FeatureFlag; private pipelines: Array; - constructor(config: LDExtensionConfiguration, defaults?: flagDefaultSettings) { + constructor(config: ILDExtensionConfiguration, defaults?: flagDefaultSettings) { this.config = config; this.defaults = defaults || undefined; this.title = 'Create Feature Flag'; diff --git a/src/extension.ts b/src/extension.ts index 1345409f..1e2fe578 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -8,11 +8,13 @@ import { register as registerProviders } from './providers'; import { LaunchDarklyAPI } from './api'; import { CodeRefsDownloader } from './coderefs/codeRefsDownloader'; import { CodeRefs as cr } from './coderefs/codeRefsVersion'; -import { LaunchDarklyAuthenticationProvider, LaunchDarklyAuthenticationSession } from './providers/authProvider'; -import { extensionReload } from './utils'; +import { LaunchDarklyAuthenticationProvider } from './providers/authProvider'; +import { extensionReload } from './generalUtils'; import { LDExtensionConfiguration } from './ldExtensionConfiguration'; import * as semver from 'semver'; import { SetWorkspaceCmd } from './commands/setWorkspaceEnabled'; +import { CMD_LD_CONFIG, CMD_LD_SIGNIN } from './utils/commands'; +import { LaunchDarklyAuthenticationSession } from './models'; export async function activate(ctx: ExtensionContext): Promise { const storedVersion = ctx.globalState.get('version', '5.0.0'); @@ -40,7 +42,7 @@ export async function activate(ctx: ExtensionContext): Promise { ) .then((item) => { item === 'Configure' - ? commands.executeCommand('extension.configureLaunchDarkly') + ? commands.executeCommand(CMD_LD_CONFIG) : LDExtConfig.getCtx().workspaceState.update('isDisabledForWorkspace', true); }); } @@ -53,7 +55,7 @@ export async function activate(ctx: ExtensionContext): Promise { ) .then((item) => { item === 'Configure' - ? commands.executeCommand('extension.configureLaunchDarkly') + ? commands.executeCommand(CMD_LD_CONFIG) : LDExtConfig.getCtx().globalState.update('legacyNotificationDismissed', true); }); break; @@ -62,7 +64,7 @@ export async function activate(ctx: ExtensionContext): Promise { } LDExtConfig.getCtx().subscriptions.push( - commands.registerCommand('vscode-launchdarkly-authprovider.signIn', async () => { + commands.registerCommand(CMD_LD_SIGNIN, async () => { const session = (await authentication.getSession('launchdarkly', ['writer'], { createIfNone: true, })) as LaunchDarklyAuthenticationSession; @@ -71,7 +73,7 @@ export async function activate(ctx: ExtensionContext): Promise { window .showInformationMessage(`Click Configure below to finish setting up the LaunchDarkly extension`, `Configure`) .then((item) => { - item === 'Configure' ? commands.executeCommand('extension.configureLaunchDarkly') : null; + item === 'Configure' ? commands.executeCommand(CMD_LD_CONFIG) : null; }); } else { window.showInformationMessage(`You are now signed in to LaunchDarkly & Project is configured.`); @@ -114,7 +116,7 @@ export async function activate(ctx: ExtensionContext): Promise { .then(async (item) => { switch (item) { case 'Sign In': - commands.executeCommand('vscode-launchdarkly-authprovider.signIn'); + commands.executeCommand(CMD_LD_SIGNIN); break; } }); diff --git a/src/flagStore.ts b/src/flagStore.ts index 29c61466..61a69f2a 100644 --- a/src/flagStore.ts +++ b/src/flagStore.ts @@ -5,8 +5,16 @@ import { LDClient } from '@launchdarkly/node-server-sdk/dist/src/api'; import { LDOptions } from '@launchdarkly/node-server-sdk/dist/src/index'; import { debounce, Dictionary, keyBy } from 'lodash'; -import { FeatureFlag, FlagConfiguration, FlagWithConfiguration, InstructionPatch, PatchComment } from './models'; -import { LDExtensionConfiguration } from './ldExtensionConfiguration'; +import { + FeatureFlag, + FlagConfiguration, + FlagStoreInterface, + FlagWithConfiguration, + ILDExtensionConfiguration, + InstructionPatch, + PatchComment, +} from './models'; +import { CMD_LD_CONFIG } from './utils/commands'; const DATA_KIND = { namespace: 'features' }; @@ -14,15 +22,14 @@ type FlagUpdateCallback = (flag: string) => void; type LDClientResolve = (LDClient: LDClient) => void; type LDClientReject = () => void; -export class FlagStore { - private readonly config: LDExtensionConfiguration; +export class FlagStore implements FlagStoreInterface { + private readonly config: ILDExtensionConfiguration; private readonly store: LaunchDarkly.LDFeatureStore; private flagMetadata: Dictionary; public readonly storeUpdates: EventEmitter = new EventEmitter(); // We fire a storeReady event because this will always exist compared to 'ready' listener on LDClient // which may be reinitialized public readonly storeReady: EventEmitter = new EventEmitter(); - //private readonly api: LaunchDarklyAPI; private resolveLDClient: LDClientResolve; private rejectLDClient: LDClientReject; private ldClient: Promise = new Promise((resolve, reject) => { @@ -33,9 +40,8 @@ export class FlagStore { private offlineTimerSet = false; public readonly ready: EventEmitter = new EventEmitter(); - constructor(config: LDExtensionConfiguration) { + constructor(config: ILDExtensionConfiguration) { this.config = config; - //this.api = api; this.store = new InMemoryFeatureStore(); this.reload(); } @@ -101,8 +107,7 @@ export class FlagStore { window .showErrorMessage('[LaunchDarkly] Failed to setup LaunchDarkly client', 'Configure LaunchDarkly Extension') .then((selection) => { - if (selection === 'Configure LaunchDarkly Extension') - commands.executeCommand('extension.configureLaunchDarkly'); + if (selection === 'Configure LaunchDarkly Extension') commands.executeCommand(CMD_LD_CONFIG); }); this.rejectLDClient(); console.error(`Failed to setup client: ${err}`); @@ -208,7 +213,7 @@ export class FlagStore { 'Your configured LaunchDarkly environment does not exist. Please reconfigure the extension.', 'Configure', ) - .then((item) => item && commands.executeCommand('extension.configureLaunchDarkly')); + .then((item) => item && commands.executeCommand(CMD_LD_CONFIG)); } throw err; } diff --git a/src/utils.ts b/src/generalUtils.ts similarity index 83% rename from src/utils.ts rename to src/generalUtils.ts index fcad8b9f..6f6349ca 100644 --- a/src/utils.ts +++ b/src/generalUtils.ts @@ -1,6 +1,5 @@ import { authentication, - commands, ConfigurationChangeEvent, Disposable, DocumentFilter, @@ -23,14 +22,15 @@ import { LaunchDarklyHoverProvider } from './providers/hover'; import { QuickLinksListProvider } from './providers/quickLinksView'; import { setTimeout } from 'timers/promises'; import { ToggleCache } from './toggleCache'; -import { LDExtensionConfiguration } from './ldExtensionConfiguration'; import { LaunchDarklyReleaseProvider } from './providers/releaseViewProvider'; -import { InstructionPatch } from './models'; +import { ILDExtensionConfiguration, InstructionPatch } from './models'; import { logDebugMessage } from './utils/logDebugMessage'; +import { CMD_LD_CONFIG, CMD_LD_OPEN_FLAG, CMD_LD_REFRESH_LENS, CMD_LD_TOGGLE_CMD_PROMPT } from './utils/commands'; +import { registerCommand } from './utils/registerCommand'; const cache = new ToggleCache(); -export async function extensionReload(config: LDExtensionConfiguration, reload = false) { +export async function extensionReload(config: ILDExtensionConfiguration, reload = false) { const session = await authentication.getSession('launchdarkly', ['writer'], { createIfNone: false }); if (session !== undefined) { // TODO: determine if this reload call to config is needed @@ -43,7 +43,7 @@ export async function extensionReload(config: LDExtensionConfiguration, reload = } } -export async function setupComponents(config: LDExtensionConfiguration, reload = false) { +export async function setupComponents(config: ILDExtensionConfiguration, reload = false) { const cmds = config.getCtx().globalState.get('commands'); if (typeof cmds?.dispose === 'function') { cmds.dispose(); @@ -63,7 +63,7 @@ export async function setupComponents(config: LDExtensionConfiguration, reload = } config.setStatusBar(window.createStatusBarItem(StatusBarAlignment.Left)); - config.getStatusBar().command = 'extension.configureLaunchDarkly'; + config.getStatusBar().command = CMD_LD_CONFIG; const workspaceConfig = workspace.getConfiguration('launchdarkly'); if (workspaceConfig.get('enableStatusBar')) { config.getStatusBar().text = `$(launchdarkly-logo) ${config.getConfig().project} / ${config.getConfig().env}`; @@ -105,7 +105,7 @@ export async function setupComponents(config: LDExtensionConfiguration, reload = const listView = new LaunchDarklyFlagListProvider(config, codeLens); window.registerTreeDataProvider('launchdarklyFlagList', listView); if (!reload) { - listViewDisp = registerCommand('launchdarkly.refreshFlagLens', () => listView.setFlagsInDocument()); + listViewDisp = registerCommand(CMD_LD_REFRESH_LENS, () => listView.setFlagsInDocument()); config.getCtx().subscriptions.push(listViewDisp); } @@ -152,10 +152,10 @@ export async function setupComponents(config: LDExtensionConfiguration, reload = codeLens.start(); - const flagToggle = registerCommand('launchdarkly.toggleFlagCmdPrompt', async () => { + const flagToggle = registerCommand(CMD_LD_TOGGLE_CMD_PROMPT, async () => { await showToggleMenu(config); }); - const openFlag = registerCommand('launchdarkly.OpenFlag', (node: FlagItem) => + const openFlag = registerCommand(CMD_LD_OPEN_FLAG, (node: FlagItem) => window.activeTextEditor.revealRange(node.range), ); @@ -176,7 +176,7 @@ export async function setupComponents(config: LDExtensionConfiguration, reload = } } -async function showToggleMenu(config: LDExtensionConfiguration) { +async function showToggleMenu(config: ILDExtensionConfiguration) { let flags; try { flags = await config.getFlagStore().allFlagsMetadata(); @@ -222,7 +222,7 @@ async function showToggleMenu(config: LDExtensionConfiguration) { } } -export async function toggleFlag(config: LDExtensionConfiguration, key: string) { +export async function toggleFlag(config: ILDExtensionConfiguration, key: string) { await window.withProgress( { location: ProgressLocation.Notification, @@ -257,30 +257,8 @@ export async function toggleFlag(config: LDExtensionConfiguration, key: string) ); } -export function flagCodeSearch(config: LDExtensionConfiguration, key: string) { - let aliases; - let findAliases: string; - if (config.getAliases()) { - aliases = config.getAliases()?.getKeys(); - } - if (aliases && aliases[key]) { - const tempSearch = [...aliases[key]]; - tempSearch.push(key); - findAliases = tempSearch.join('|'); - } else { - findAliases = key; - } - commands.executeCommand('workbench.action.findInFiles', { - query: findAliases, - triggerSearch: true, - matchWholeWord: true, - isCaseSensitive: true, - isRegex: true, - }); -} - export async function flagOffFallthroughPatch( - config: LDExtensionConfiguration, + config: ILDExtensionConfiguration, kind: string, key: string, ): Promise { @@ -329,18 +307,3 @@ function createFallthroughOrOffInstruction(kind: string, variationId: string) { variationId: variationId, }; } - -export function legacyAuth() { - return true; - //workspace.getConfiguration('launchdarkly').get('legacyAuth', false) -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function registerCommand(command: string, callback: (...args: any[]) => any) { - try { - return commands.registerCommand(command, callback); - } catch (err) { - logDebugMessage(err); - return Disposable.from(); - } -} diff --git a/src/ldExtensionConfiguration.ts b/src/ldExtensionConfiguration.ts index d8e1e4a5..3f2e16cb 100644 --- a/src/ldExtensionConfiguration.ts +++ b/src/ldExtensionConfiguration.ts @@ -1,22 +1,25 @@ import { ExtensionContext, StatusBarItem, TreeView } from 'vscode'; -import { Configuration } from './configuration'; -import { LaunchDarklyAPI } from './api'; -import { FlagStore } from './flagStore'; -import { FlagAliases } from './providers/codeRefs'; -import { LaunchDarklyAuthenticationSession } from './providers/authProvider'; -import { FlagTreeInterface, LaunchDarklyTreeViewProvider } from './providers/flagsView'; -import { LaunchDarklyReleaseProvider } from './providers/releaseViewProvider'; +import { + FlagStoreInterface, + FlagTreeInterface, + IConfiguration, + IFlagAliases, + ILaunchDarklyReleaseProvider, + LaunchDarklyAPIInterface, + LaunchDarklyAuthenticationSession, + LaunchDarklyTreeViewProviderInterface, +} from './models'; export class LDExtensionConfiguration { private static instance: LDExtensionConfiguration; - private config?: Configuration; + private config?: IConfiguration; private ctx: ExtensionContext; - private api?: LaunchDarklyAPI; - private flagStore?: FlagStore; + private api?: LaunchDarklyAPIInterface; + private flagStore?: FlagStoreInterface; private flagTreeView: TreeView; - private flagView: LaunchDarklyTreeViewProvider; - private aliases?: FlagAliases; - private releaseView?: LaunchDarklyReleaseProvider; + private flagView: LaunchDarklyTreeViewProviderInterface; + private aliases?: IFlagAliases; + private releaseView?: ILaunchDarklyReleaseProvider; private session?: LaunchDarklyAuthenticationSession; private statusBar?: StatusBarItem; @@ -31,27 +34,27 @@ export class LDExtensionConfiguration { return LDExtensionConfiguration.instance; } - getAliases(): FlagAliases | undefined { + getAliases(): IFlagAliases | undefined { return this.aliases; } - setAliases(aliases: FlagAliases): void { + setAliases(aliases: IFlagAliases): void { this.aliases = aliases; } - getApi(): LaunchDarklyAPI | undefined { + getApi(): LaunchDarklyAPIInterface | undefined { return this.api; } - setApi(api: LaunchDarklyAPI): void { + setApi(api: LaunchDarklyAPIInterface): void { this.api = api; } - getConfig(): Configuration | undefined { + getConfig(): IConfiguration | undefined { return this.config; } - setConfig(config: Configuration): void { + setConfig(config: IConfiguration): void { this.config = config; } @@ -63,11 +66,11 @@ export class LDExtensionConfiguration { this.ctx = ctx; } - getFlagStore(): FlagStore | undefined { + getFlagStore(): FlagStoreInterface | undefined { return this.flagStore; } - setFlagStore(flagStore: FlagStore): void { + setFlagStore(flagStore: FlagStoreInterface): void { this.flagStore = flagStore; } @@ -79,19 +82,19 @@ export class LDExtensionConfiguration { this.flagTreeView = flagTreeProvider; } - getFlagView(): LaunchDarklyTreeViewProvider | undefined { + getFlagView(): LaunchDarklyTreeViewProviderInterface | undefined { return this.flagView; } - setFlagView(flagView: LaunchDarklyTreeViewProvider): void { + setFlagView(flagView: LaunchDarklyTreeViewProviderInterface): void { this.flagView = flagView; } - getReleaseView(): LaunchDarklyReleaseProvider | undefined { + getReleaseView(): ILaunchDarklyReleaseProvider | undefined { return this.releaseView; } - setReleaseView(releaseView: LaunchDarklyReleaseProvider): void { + setReleaseView(releaseView: ILaunchDarklyReleaseProvider): void { this.releaseView = releaseView; } diff --git a/src/models.ts b/src/models.ts index 00e5a12e..3d0fcb88 100644 --- a/src/models.ts +++ b/src/models.ts @@ -1,4 +1,19 @@ -import { ClientSideAvailability } from 'launchdarkly-api-typescript'; +import { LDContext, LDEvaluationDetail, LDFeatureStoreKindData } from '@launchdarkly/node-server-sdk'; +import { ExecOptions } from 'child_process'; +import { ClientSideAvailability, RepositoryRep } from 'launchdarkly-api-typescript'; +import { Dictionary } from 'lodash'; +import { + AuthenticationSession, + ConfigurationChangeEvent, + EventEmitter, + ExtensionContext, + MarkdownString, + StatusBarItem, + TreeDataProvider, + TreeItem, + TreeView, + WorkspaceFolder, +} from 'vscode'; export class Resource { name: string; @@ -561,3 +576,165 @@ export interface MemberTeamSummaryRep { */ name: string; } + +export interface FlagStoreInterface { + storeUpdates: EventEmitter; + // We fire a storeReady event because this will always exist compared to 'ready' listener on LDClient + // which may be reinitialized + storeReady: EventEmitter; + ready: EventEmitter; + reload(): Promise; + start(): Promise; + on(event: string, cb: (keys: string) => void): void; + removeAllListeners(): Promise; + stop(): Promise; + getFeatureFlag(flag: string, fullFlag?: boolean): Promise; + forceFeatureFlagUpdate(flagKey: string): Promise; + allFlags(): Promise; + getFlagConfig(flag: string): Promise; + getFlagMetadata(flag: string): Promise; + allFlagsMetadata(): Promise>; + listFlags(): Promise>; + executeAndUpdateFlagStore( + func: ( + projectKey: string, + flagKey: string, + value?: PatchComment | InstructionPatch, + ) => Promise, + projectKey: string, + flagKey: string, + value?: PatchComment | InstructionPatch, + ): Promise; + allFlags(): Promise; + variationDetail(flag: string, context: LDContext): Promise; + // Add other methods as needed... +} + +export interface LaunchDarklyTreeViewProviderInterface + extends TreeDataProvider { + flagNodes: Array | null; + start(): void; + treeLoader(): void; + registerCommands(): void; + refresh(): void; + stop(): void; + // Add other methods as needed... +} + +export interface FlagTreeInterface { + children: unknown; + command?: unknown; + flagKey?: string; + flagVersion?: number; +} + +export interface LaunchDarklyAuthenticationSession extends AuthenticationSession { + refreshToken: string; + baseUri: string; + fullUri: string; + teams: Team[]; + apiToken?: string; +} + +export interface IFlagAliases { + aliasUpdates: EventEmitter; + codeRefsVersionCheck(): Promise; + setupStatusBar(): void; + exec(command: string, options: ExecOptions): Promise<{ stdout: string; stderr: string }>; + generateAndReadAliases(directory?: WorkspaceFolder): Promise; + getListOfMapKeys(): Array | undefined; + getMap(): Map | undefined; + getKeys(): Map | undefined; + start(): Promise; +} + +export interface ILDExtensionConfiguration { + getAliases(): IFlagAliases | undefined; + setAliases(aliases: IFlagAliases): void; + getApi(): LaunchDarklyAPIInterface | undefined; + setApi(api: LaunchDarklyAPIInterface): void; + getConfig(): IConfiguration | undefined; + setConfig(config: IConfiguration): void; + getCtx(): ExtensionContext; + setCtx(ctx: ExtensionContext): void; + getFlagStore(): FlagStoreInterface | undefined; + setFlagStore(flagStore: FlagStoreInterface): void; + getFlagTreeProvider(): TreeView | undefined; + setFlagTreeProvider(flagTreeProvider: TreeView): void; + getFlagView(): LaunchDarklyTreeViewProviderInterface | undefined; + setFlagView(flagView: LaunchDarklyTreeViewProviderInterface): void; + getReleaseView(): ILaunchDarklyReleaseProvider | undefined; + setReleaseView(releaseView: ILaunchDarklyReleaseProvider): void; + getSession(): LaunchDarklyAuthenticationSession | undefined; + setSession(session: LaunchDarklyAuthenticationSession): void; + getStatusBar(): StatusBarItem | undefined; + setStatusBar(statusBar: StatusBarItem): void; +} + +export interface LaunchDarklyAPIInterface { + getProjects(url?: string): Promise>; + getProject(projectKey: string, url?: string): Promise; + getEnvironments(url: string): Promise>; + getEnvironment(projectKey: string, envKey: string): Promise; + getMetrics(projectKey: string): Promise>; + getFeatureFlag(projectKey: string, flagKey: string, envKey?: string, fullFlag?: boolean): Promise; + getFlagCodeRefs(projectKey: string, repo: string, flag?: string): Promise>; + getFlagLinks(projectKey: string, flag: string): Promise>; + getReleasePipelines(projectKey: string): Promise>; + getReleases(projectKey: string, pipelineKey: string, pipelineId: string): Promise>; + getCompletedReleases(projectKey: string, pipelineKey: string): Promise>; + postFeatureFlag(projectKey: string, flag: NewFlag): Promise; + getFeatureFlags(projectKey: string, envKey?: string, url?: string): Promise>; + patchFeatureFlag(projectKey: string, flagKey: string, value?: PatchComment): Promise; + patchFeatureFlagOn(projectKey: string, flagKey: string, enabled: boolean): Promise; + patchFeatureFlagSem(projectKey: string, flagKey: string, value?: InstructionPatch): Promise; +} + +export interface IConfiguration { + project: string; + env: string; + codeRefsPath?: string; + codeRefsRefreshRate: number; + enableAliases: boolean; + enableFlagExplorer: boolean; + refreshRate: number; + accessToken: string; + enableHover: boolean; + enableAutocomplete: boolean; + enableMetricExplorer: boolean; + enableCodeLens: boolean; + baseUri: string; + streamUri?: string; + isConfigured(): Promise; + clearLocalConfig(): Promise; + clearGlobalConfig(): Promise; + copyWorkspaceToGlobal(): Promise; + setGlobalDefault(): Promise; + getState(key: string): Promise; + reload(): Promise; + streamingConfigReloadCheck(e: ConfigurationChangeEvent): boolean; + update(key: string, value: string | boolean, global: boolean): Promise; + validate(): Promise; + validateRefreshInterval(interval: number): boolean; +} + +export interface ILaunchDarklyReleaseProvider extends TreeDataProvider { + config: ILDExtensionConfiguration; + releasedFlags: Set; + refresh(): void; + start(): void; + reload(): void; + periodicRefresh(): void; + getReleases(): Promise; +} + +export interface IReleasePhaseParentNode extends TreeItem { + children: IReleaseFlagNode[] | undefined; + tooltip?: string | MarkdownString; +} + +export interface IReleaseFlagNode { + flagKey?: string; + contextValue?: string; + tooltip?: string | MarkdownString; +} diff --git a/src/providers.ts b/src/providers.ts index e5c75dea..d2779c58 100644 --- a/src/providers.ts +++ b/src/providers.ts @@ -2,8 +2,9 @@ import { commands, window, workspace } from 'vscode'; import globalClearCmd from './commands/clearGlobalContext'; import configureLaunchDarkly from './commands/configureLaunchDarkly'; -import { extensionReload, setupComponents } from './utils'; +import { extensionReload, setupComponents } from './generalUtils'; import { LDExtensionConfiguration } from './ldExtensionConfiguration'; +import { CMD_LD_MIGRATE_CONFIGURATION } from './utils/commands'; export const FLAG_KEY_REGEX = /[A-Za-z0-9][.A-Za-z_\-0-9]*/; @@ -13,7 +14,7 @@ export async function register(config: LDExtensionConfiguration): Promise // Handle manual changes to extension configuration // workspace.onDidChangeConfiguration(async (e: ConfigurationChangeEvent) => { - // if (e.affectsConfiguration('launchdarkly') && e.affectsConfiguration('launchdarkly.enableCodeLens')) { + // if (e.affectsConfiguration('launchdarkly') && e.affectsConfiguration(CMD_LD_ENABLE_LENS)) { // await extensionReload(config, true); // } // }); @@ -33,7 +34,7 @@ export async function register(config: LDExtensionConfiguration): Promise ); config.getCtx().subscriptions.push( - commands.registerCommand('launchdarkly.migrateConfiguration', async () => { + commands.registerCommand(CMD_LD_MIGRATE_CONFIGURATION, async () => { try { const localConfig = workspace.getConfiguration('launchdarkly'); await config.getCtx().workspaceState.update('project', localConfig['project']); diff --git a/src/providers/authProvider.ts b/src/providers/authProvider.ts index cc26a6ae..fcb25e9a 100644 --- a/src/providers/authProvider.ts +++ b/src/providers/authProvider.ts @@ -17,8 +17,8 @@ import { import { v4 as uuid } from 'uuid'; import { PromiseAdapter, promiseFromEvent } from '../utils/common'; import fetch from 'node-fetch'; -import { Member, Team } from '../models'; -import { legacyAuth } from '../utils'; +import { LaunchDarklyAuthenticationSession, Member, Team } from '../models'; +import { legacyAuth } from '../utils/legacyAuth'; export const AUTH_TYPE = `launchdarkly`; const AUTH_NAME = `LaunchDarkly`; @@ -32,14 +32,6 @@ class UriEventHandler extends EventEmitter implements UriHandler { } } -export interface LaunchDarklyAuthenticationSession extends AuthenticationSession { - refreshToken: string; - baseUri: string; - fullUri: string; - teams: Team[]; - apiToken?: string; -} - interface TokenInformation { access_token: string; refresh_token: string; diff --git a/src/providers/codeRefs.ts b/src/providers/codeRefs.ts index 90e88a01..04e7fea2 100644 --- a/src/providers/codeRefs.ts +++ b/src/providers/codeRefs.ts @@ -5,8 +5,8 @@ import { join } from 'path'; import { tmpdir } from 'os'; import csv from 'csv-parser'; import { CodeRefs } from '../coderefs/codeRefsVersion'; -import { LDExtensionConfiguration } from '../ldExtensionConfiguration'; -import { legacyAuth } from '../utils'; +import { legacyAuth } from '../utils/legacyAuth'; +import { ILDExtensionConfiguration } from '../models'; // eslint-disable-next-line @typescript-eslint/no-var-requires const { promises: Fs } = require('fs'); @@ -22,14 +22,14 @@ type FlagAlias = { }; export class FlagAliases { - private config: LDExtensionConfiguration; + private config: ILDExtensionConfiguration; private ctx: ExtensionContext; public readonly aliasUpdates: EventEmitter = new EventEmitter(); map = new Map(); keys = new Map(); private statusBar: StatusBarItem; - constructor(config: LDExtensionConfiguration) { + constructor(config: ILDExtensionConfiguration) { this.config = config; // this.ctx = ctx; // this.ldConfig = ldConfig; diff --git a/src/providers/completion.ts b/src/providers/completion.ts index af7d056a..886df505 100644 --- a/src/providers/completion.ts +++ b/src/providers/completion.ts @@ -1,17 +1,15 @@ import { CompletionItemProvider, TextDocument, Position, CompletionItem, CompletionItemKind, Range } from 'vscode'; -import { Configuration } from '../configuration'; -import { FlagStore } from '../flagStore'; import { FLAG_KEY_REGEX } from '../providers'; -import { FlagAliases } from './codeRefs'; +import { FlagStoreInterface, IConfiguration, IFlagAliases } from '../models'; export const STRING_DELIMITERS = ['"', "'", '`']; export default class LaunchDarklyCompletionItemProvider implements CompletionItemProvider { - private readonly flagStore: FlagStore; - private readonly config: Configuration; - private readonly aliases?: FlagAliases; + private readonly flagStore: FlagStoreInterface; + private readonly config: IConfiguration; + private readonly aliases?: IFlagAliases; - constructor(config: Configuration, flagStore: FlagStore, aliases?: FlagAliases) { + constructor(config: IConfiguration, flagStore: FlagStoreInterface, aliases?: IFlagAliases) { this.config = config; this.flagStore = flagStore; this.aliases = aliases; diff --git a/src/providers/flagLens.ts b/src/providers/flagLens.ts index b5d72fea..f5af3af1 100644 --- a/src/providers/flagLens.ts +++ b/src/providers/flagLens.ts @@ -1,12 +1,12 @@ import * as vscode from 'vscode'; import { Configuration } from '../configuration'; -import { Fallthrough, FeatureFlag, FlagConfiguration, WeightedVariation } from '../models'; +import { Fallthrough, FeatureFlag, FlagConfiguration, ILDExtensionConfiguration, WeightedVariation } from '../models'; import { FlagStore } from '../flagStore'; import { FlagAliases } from './codeRefs'; import { CancellationToken, CancellationTokenSource, CodeLens, ConfigurationChangeEvent, workspace } from 'vscode'; -import { LDExtensionConfiguration } from '../ldExtensionConfiguration'; import { Dictionary } from 'lodash'; import { logDebugMessage } from '../utils/logDebugMessage'; +import { CMD_LD_ENABLE_LENS } from '../utils/commands'; // Most Lens are read only, so leaving a longer cache. There is an optimistic delete if we receive a flag update. const LENS_CACHE_TTL = 300000; @@ -16,7 +16,7 @@ const MAX_CODELENS_VALUE = 20; * CodelensProvider */ export class FlagCodeLensProvider implements vscode.CodeLensProvider { - private config: LDExtensionConfiguration; + private config: ILDExtensionConfiguration; private regex: RegExp; private flagStore: FlagStore | null; private aliases: FlagAliases; @@ -26,12 +26,12 @@ export class FlagCodeLensProvider implements vscode.CodeLensProvider { private _onDidChangeCodeLenses: vscode.EventEmitter = new vscode.EventEmitter(); public readonly onDidChangeCodeLenses: vscode.Event = this._onDidChangeCodeLenses.event; - constructor(config: LDExtensionConfiguration) { + constructor(config: ILDExtensionConfiguration) { this.config = config; this.regex = /(.+)/g; // eslint-disable-next-line @typescript-eslint/no-unused-vars vscode.workspace.onDidChangeConfiguration(async (e: ConfigurationChangeEvent) => { - if (e.affectsConfiguration('launchdarkly.enableCodeLens')) { + if (e.affectsConfiguration(CMD_LD_ENABLE_LENS)) { this._onDidChangeCodeLenses.fire(undefined); } }); diff --git a/src/providers/flagListView.ts b/src/providers/flagListView.ts index 9a2f65e8..afff8c53 100644 --- a/src/providers/flagListView.ts +++ b/src/providers/flagListView.ts @@ -17,20 +17,19 @@ import { import { Configuration } from '../configuration'; import { flagToValues } from '../utils/FlagNode'; import { FlagCodeLensProvider, SimpleCodeLens } from './flagLens'; -import { FlagTreeInterface } from './flagsView'; import { FlagNode } from '../utils/FlagNode'; -import { LDExtensionConfiguration } from '../ldExtensionConfiguration'; -import { FeatureFlag } from '../models'; +import { FeatureFlag, FlagTreeInterface, ILDExtensionConfiguration } from '../models'; import { logDebugMessage } from '../utils/logDebugMessage'; +import { CMD_LD_ENABLE_LENS } from '../utils/commands'; export class LaunchDarklyFlagListProvider implements TreeDataProvider { - private ldConfig: LDExtensionConfiguration; + private ldConfig: ILDExtensionConfiguration; private lens: FlagCodeLensProvider; private flagNodes: Array | null; private _onDidChangeTreeData: EventEmitter = new EventEmitter(); readonly onDidChangeTreeData: Event = this._onDidChangeTreeData.event; private flagMap: Map = new Map(); - constructor(ldConfig: LDExtensionConfiguration, lens: FlagCodeLensProvider) { + constructor(ldConfig: ILDExtensionConfiguration, lens: FlagCodeLensProvider) { this.ldConfig = ldConfig; this.lens = lens; this.setFlagsInDocument(); @@ -197,7 +196,7 @@ export class LaunchDarklyFlagListProvider implements TreeDataProvider const CodeLensCmd = new TreeItem('Toggle Flag lens'); CodeLensCmd.command = { title: 'Command', - command: 'launchdarkly.enableCodeLens', + command: CMD_LD_ENABLE_LENS, }; items.push(CodeLensCmd); diff --git a/src/providers/flagsView.ts b/src/providers/flagsView.ts index a279f154..3de939d2 100644 --- a/src/providers/flagsView.ts +++ b/src/providers/flagsView.ts @@ -1,20 +1,30 @@ import * as vscode from 'vscode'; -import { FeatureFlag, FlagConfiguration, PatchComment } from '../models'; +import { FeatureFlag, FlagConfiguration, FlagTreeInterface, ILDExtensionConfiguration, PatchComment } from '../models'; import { debounce, map } from 'lodash'; import checkExistingCommand from '../utils/common'; import { authentication } from 'vscode'; import { FlagNode, FlagParentNode, flagToValues } from '../utils/FlagNode'; import { generateHoverString } from '../utils/hover'; -import { LDExtensionConfiguration } from '../ldExtensionConfiguration'; -import { flagCodeSearch, registerCommand } from '../utils'; import { logDebugMessage } from '../utils/logDebugMessage'; import { ReleaseFlagNode } from './releaseViewProvider'; +import { + CMD_LD_REFRESH_FLAG_VIEW, + CMD_LD_COPY_KEY, + CMD_LD_OPEN_BROWSER, + CMD_LD_REFRESH_ENTRY, + CMD_LD_FLAG_SEARCH, + CMD_LD_TOGGLE_FLAG, + CMD_LD_UPDATE_FALLTHROUGH, + CMD_LD_UPDATE_OFF, +} from '../utils/commands'; +import { flagCodeSearch } from '../utils/flagCodeSearch'; +import { registerCommand } from '../utils/registerCommand'; const COLLAPSED = vscode.TreeItemCollapsibleState.Collapsed; const NON_COLLAPSED = vscode.TreeItemCollapsibleState.None; export class LaunchDarklyTreeViewProvider implements vscode.TreeDataProvider { - private readonly ldConfig: LDExtensionConfiguration; + private readonly ldConfig: ILDExtensionConfiguration; public flagNodes: Array | null; private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter(); @@ -22,7 +32,7 @@ export class LaunchDarklyTreeViewProvider implements vscode.TreeDataProvider = new vscode.EventEmitter(); private lastTreeEvent: string; - constructor(ldConfig: LDExtensionConfiguration) { + constructor(ldConfig: ILDExtensionConfiguration) { this.ldConfig = ldConfig; this.registerCommands(); this.start(); @@ -197,7 +207,7 @@ export class LaunchDarklyTreeViewProvider implements vscode.TreeDataProvider { + return registerCommand(CMD_LD_REFRESH_FLAG_VIEW, (): void => { this.reload(); vscode.commands.executeCommand( 'setContext', @@ -209,28 +219,28 @@ export class LaunchDarklyTreeViewProvider implements vscode.TreeDataProvider { // Check Copy Key only, if it exists the rest should also and registering commands should be skipped. - const copyKeyCmd = 'launchdarkly.copyKey'; + const copyKeyCmd = CMD_LD_COPY_KEY; if (await checkExistingCommand(copyKeyCmd)) { return; } this.ldConfig.getCtx().subscriptions.push( registerCommand(copyKeyCmd, (node: FlagNode) => vscode.env.clipboard.writeText(node.flagKey)), - registerCommand('launchdarkly.openBrowser', (node: FlagNode | string) => { + registerCommand(CMD_LD_OPEN_BROWSER, (node: FlagNode | string) => { if (typeof node === 'string') { vscode.env.openExternal(vscode.Uri.parse(node)); } else if (node.uri) { vscode.env.openExternal(vscode.Uri.parse(node.uri)); } }), - registerCommand('launchdarkly.refreshEntry', () => this.reload()), + registerCommand(CMD_LD_REFRESH_ENTRY, () => this.reload()), this.registerTreeviewRefreshCommand(), - registerCommand('launchdarkly.flagMultipleSearch', (node: FlagNode | ReleaseFlagNode) => { + registerCommand(CMD_LD_FLAG_SEARCH, (node: FlagNode | ReleaseFlagNode) => { if (!node.flagKey) { return; } flagCodeSearch(this.ldConfig, node.flagKey); }), - registerCommand('launchdarkly.toggleFlag', async (node: FlagParentNode) => { + registerCommand(CMD_LD_TOGGLE_FLAG, async (node: FlagParentNode) => { try { if (!node.flagKey) { logDebugMessage('Flag key not found'); @@ -247,7 +257,7 @@ export class LaunchDarklyTreeViewProvider implements vscode.TreeDataProvider { + registerCommand(CMD_LD_UPDATE_FALLTHROUGH, async (node: FlagNode) => { try { await this.flagPatch( node, @@ -258,7 +268,7 @@ export class LaunchDarklyTreeViewProvider implements vscode.TreeDataProvider { + registerCommand(CMD_LD_UPDATE_OFF, async (node: FlagNode) => { try { await this.flagPatch(node, `/environments/${this.ldConfig.getConfig()?.env}/offVariation`, node.contextValue); } catch (err) { @@ -433,10 +443,3 @@ export class LaunchDarklyTreeViewProvider implements vscode.TreeDataProvider { - const metricSearchCmd = 'launchdarkly.metricMultipleSearch'; + const metricSearchCmd = CMD_LD_METRIC_SEARCH; if (await checkExistingCommand(metricSearchCmd)) { return; } diff --git a/src/providers/quickLinksView.ts b/src/providers/quickLinksView.ts index 6c718694..dac55cfb 100644 --- a/src/providers/quickLinksView.ts +++ b/src/providers/quickLinksView.ts @@ -12,17 +12,18 @@ import { commands, } from 'vscode'; import checkExistingCommand from '../utils/common'; -import { LDExtensionConfiguration } from '../ldExtensionConfiguration'; -import { registerCommand } from '../utils'; +import { CMD_LD_CREATE_FLAG, CMD_LD_OPEN_BROWSER } from '../utils/commands'; +import { registerCommand } from '../utils/registerCommand'; +import { ILDExtensionConfiguration } from '../models'; const NON_COLLAPSED = TreeItemCollapsibleState.None; export class QuickLinksListProvider implements TreeDataProvider { - private config: LDExtensionConfiguration; + private config: ILDExtensionConfiguration; private _onDidChangeTreeData: EventEmitter = new EventEmitter(); readonly onDidChangeTreeData: Event = this._onDidChangeTreeData.event; - constructor(config: LDExtensionConfiguration) { + constructor(config: ILDExtensionConfiguration) { this.config = config; if (this.config.getSession() !== undefined) { this.start(); @@ -59,7 +60,7 @@ export class QuickLinksListProvider implements TreeDataProvider { const linkUrl = `${this.config.getSession().fullUri}/${this.config.getConfig().project}/${ this.config.getConfig().env }/features/${quickPick.selectedItems[0].label}/compare-flag`; - commands.executeCommand('launchdarkly.openBrowser', linkUrl); + commands.executeCommand(CMD_LD_OPEN_BROWSER, linkUrl); quickPick.dispose(); }); quickPick.show(); @@ -104,7 +105,7 @@ export class QuickLinksListProvider implements TreeDataProvider { items.push( new LinkNode(`Create Boolean Feature Flag`, NON_COLLAPSED, '', { title: 'Create Boolean Feature Flag', - command: 'launchdarkly.createFlag', + command: CMD_LD_CREATE_FLAG, }), ); items.push(new LinkNode(`Create Non-boolean Feature Flag`, NON_COLLAPSED, addUtm(`${baseUrl}/features/create`))); @@ -146,7 +147,7 @@ export class LinkNode extends TreeItem { ? command : { title: 'Open In Browser', - command: 'launchdarkly.openBrowser', + command: CMD_LD_OPEN_BROWSER, arguments: [this.uri], }; } diff --git a/src/providers/releaseViewProvider.ts b/src/providers/releaseViewProvider.ts index be4eed0b..c0d38b92 100644 --- a/src/providers/releaseViewProvider.ts +++ b/src/providers/releaseViewProvider.ts @@ -1,17 +1,16 @@ import { TreeDataProvider, TreeItem, Event, EventEmitter, TreeItemCollapsibleState, MarkdownString } from 'vscode'; -import { LDExtensionConfiguration } from '../ldExtensionConfiguration'; -import { FeatureFlag, ReleasePhase, ReleasePipeline } from '../models'; +import { FeatureFlag, ILDExtensionConfiguration, ReleasePhase, ReleasePipeline } from '../models'; import * as url from 'url'; //import { setTimeout } from 'timers/promises'; export class LaunchDarklyReleaseProvider implements TreeDataProvider { private _onDidChangeTreeData: EventEmitter = new EventEmitter(); readonly onDidChangeTreeData: Event = this._onDidChangeTreeData.event; - readonly config: LDExtensionConfiguration; + readonly config: ILDExtensionConfiguration; private nodes: ReleasePhaseParentNode[] | TreeItem[] = []; private updateTimer: NodeJS.Timeout | undefined; releasedFlags = new Set(); - constructor(config: LDExtensionConfiguration) { + constructor(config: ILDExtensionConfiguration) { this.config = config; this.start(); this.periodicRefresh(); @@ -197,7 +196,7 @@ function generateReleaseTooltip(release: ReleasePipeline): MarkdownString { function generateGlobalFlagHoverString( flag: FeatureFlag, - config: LDExtensionConfiguration, + config: ILDExtensionConfiguration, completedDate?: number, ): MarkdownString { let env; diff --git a/src/utils/FlagNode.ts b/src/utils/FlagNode.ts index 06b0f73e..1524b34d 100644 --- a/src/utils/FlagNode.ts +++ b/src/utils/FlagNode.ts @@ -12,9 +12,8 @@ import { TreeItemLabel, Uri, } from 'vscode'; -import { FeatureFlag, FlagConfiguration } from '../models'; +import { FeatureFlag, FlagConfiguration, ILDExtensionConfiguration } from '../models'; import { generateHoverString } from './hover'; -import { LDExtensionConfiguration } from '../ldExtensionConfiguration'; const COLLAPSED = TreeItemCollapsibleState.Collapsed; const NON_COLLAPSED = TreeItemCollapsibleState.None; @@ -104,7 +103,7 @@ export class FlagNode extends TreeItem { export async function flagToValues( flag: FeatureFlag, env: FlagConfiguration = null, - ldConfig: LDExtensionConfiguration, + ldConfig: ILDExtensionConfiguration, flagParent?: FlagParentNode, label?: boolean, ): Promise { diff --git a/src/utils/checkCoderefs.ts b/src/utils/checkCoderefs.ts index ae643cc0..04555436 100644 --- a/src/utils/checkCoderefs.ts +++ b/src/utils/checkCoderefs.ts @@ -1,6 +1,6 @@ import path from 'path'; import { ExtensionContext, FileType, Uri, window, workspace } from 'vscode'; -import { registerCommand } from '../utils'; +import { registerCommand } from './registerCommand'; export function checkCodeRefs(ctx: ExtensionContext) { const disposable = registerCommand('extension.checkLaunchDarkly', async () => { diff --git a/src/utils/commands.ts b/src/utils/commands.ts new file mode 100644 index 00000000..7b60f615 --- /dev/null +++ b/src/utils/commands.ts @@ -0,0 +1,26 @@ +export const CMD_LD_CONFIG = 'extension.configureLaunchDarkly'; +export const CMD_LD_CONFIG_ENV = 'launchdarkly.configureLaunchDarklyEnvironment'; +export const CMD_LD_MIGRATE_CONFIGURATION = 'launchdarkly.migrateConfiguration'; +export const CMD_LD_OPEN = 'launchdarkly.openInLaunchDarkly'; +export const CMD_LD_OPEN_BROWSER = 'launchdarkly.openBrowser'; +export const CMD_LD_OPEN_FLAG = 'launchdarkly.OpenFlag'; +export const CMD_LD_TOGGLE_CTX = 'launchdarkly.toggleFlagContext'; +export const CMD_LD_TOGGLE_FLAG = 'launchdarkly.toggleFlag'; +export const CMD_LD_TOGGLE_CMD_PROMPT = 'launchdarkly.toggleFlagCmdPrompt'; +export const CMD_LD_REFRESH_ENTRY = 'launchdarkly.refreshEntry'; +export const CMD_LD_REFRESH_LENS = 'launchdarkly.refreshFlagLens'; +export const CMD_LD_REFRESH_FLAG_VIEW = 'launchdarkly.treeviewrefresh'; +export const CMD_LD_COPY_KEY = 'launchdarkly.copyKey'; +export const CMD_LD_CREATE_FLAG = 'launchdarkly.createFlag'; +export const CMD_LD_UPDATE_FALLTHROUGH = 'launchdarkly.fallthroughChange'; +export const CMD_LD_UPDATE_OFF = 'launchdarkly.offChange'; +export const CMD_LD_ENABLE_WORKSPACE = 'launchdarkly.enableWorkspace'; +export const CMD_LD_FLAG_SEARCH = 'launchdarkly.flagMultipleSearch'; +export const CMD_LD_METRIC_SEARCH = 'launchdarkly.metricMultipleSearch'; +export const CMD_LD_ENABLE_LENS = 'launchdarkly.enableCodeLens'; +export const CMD_LD_PICK_RULES = 'launchdarkly.quickPickRules'; +export const CMD_LD_SIGNIN = 'vscode-launchdarkly-authprovider.signIn'; +export const CMD_LD_SET_MAINTAINER = 'launchdarkly.setMaintainer'; +export const CMD_LD_SET_GLOBAL_DEFAULT = 'launchdarkly.setGlobalDefaults'; +export const CMD_LD_CLEAR_GLOBAL_CTX = 'launchdarkly.clearGlobalContext'; +export const CMD_LD_FLAG_ACTION = 'launchdarkly.quickFlag'; diff --git a/src/utils/flagCodeSearch.ts b/src/utils/flagCodeSearch.ts new file mode 100644 index 00000000..d4ca1106 --- /dev/null +++ b/src/utils/flagCodeSearch.ts @@ -0,0 +1,24 @@ +import { commands } from 'vscode'; +import { ILDExtensionConfiguration } from '../models'; + +export function flagCodeSearch(config: ILDExtensionConfiguration, key: string) { + let aliases; + let findAliases: string; + if (config.getAliases()) { + aliases = config.getAliases()?.getKeys(); + } + if (aliases && aliases[key]) { + const tempSearch = [...aliases[key]]; + tempSearch.push(key); + findAliases = tempSearch.join('|'); + } else { + findAliases = key; + } + commands.executeCommand('workbench.action.findInFiles', { + query: findAliases, + triggerSearch: true, + matchWholeWord: true, + isCaseSensitive: true, + isRegex: true, + }); +} diff --git a/src/utils/hover.ts b/src/utils/hover.ts index efa081f5..2c309c68 100644 --- a/src/utils/hover.ts +++ b/src/utils/hover.ts @@ -1,15 +1,14 @@ import { ColorThemeKind, ExtensionContext, MarkdownString, window } from 'vscode'; -import { FeatureFlag, FlagConfiguration } from '../models'; +import { FeatureFlag, FlagConfiguration, ILDExtensionConfiguration } from '../models'; import * as fs from 'fs'; import * as url from 'url'; -import { LDExtensionConfiguration } from '../ldExtensionConfiguration'; const FLAG_STATUS_CACHE = new Map(); export function generateHoverString( flag: FeatureFlag, c: FlagConfiguration, - config: LDExtensionConfiguration, + config: ILDExtensionConfiguration, ): MarkdownString { let env; try { diff --git a/src/utils/legacyAuth.ts b/src/utils/legacyAuth.ts new file mode 100644 index 00000000..5598aae5 --- /dev/null +++ b/src/utils/legacyAuth.ts @@ -0,0 +1,4 @@ +export function legacyAuth() { + return true; + //workspace.getConfiguration('launchdarkly').get('legacyAuth', false) +} diff --git a/src/utils/registerCommand.ts b/src/utils/registerCommand.ts new file mode 100644 index 00000000..9be3fd5d --- /dev/null +++ b/src/utils/registerCommand.ts @@ -0,0 +1,12 @@ +import { Disposable, commands } from 'vscode'; +import { logDebugMessage } from './logDebugMessage'; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function registerCommand(command: string, callback: (...args: any[]) => any) { + try { + return commands.registerCommand(command, callback); + } catch (err) { + logDebugMessage(err); + return Disposable.from(); + } +} diff --git a/test/providers.test.ts b/test/providers.test.ts index 433bd6f3..166c174e 100644 --- a/test/providers.test.ts +++ b/test/providers.test.ts @@ -8,11 +8,10 @@ const toMatchSnapshot = require('expect-mocha-snapshot'); expect.extend({ toMatchSnapshot }); import { generateHoverString } from '../src/utils/hover'; -import { FeatureFlag, FlagConfiguration } from '../src/models'; +import { FeatureFlag, FlagConfiguration, LaunchDarklyAuthenticationSession } from '../src/models'; import { isPrecedingCharStringDelimiter } from '../src/providers/completion'; import { LDExtensionConfiguration } from '../src/ldExtensionConfiguration'; import { Configuration } from '../src/configuration'; -import { LaunchDarklyAuthenticationSession } from '../src/providers/authProvider'; function resolveSrcTestPath(ctx) { return Object.assign(ctx, { test: { file: ctx.test.file.replace('/out', '') } });