From 9da8aa90025c6cb48fa175ffcbad87dd52ff8910 Mon Sep 17 00:00:00 2001 From: "a.jashari" Date: Thu, 9 Jul 2026 10:07:29 +0200 Subject: [PATCH 1/6] SP-1383: gate early-access commands behind feature flag, replace beta Co-Authored-By: Claude Opus 4.8 --- src/commands/deployment/module.ts | 14 +-- src/content-cli.ts | 6 -- src/core/command/CustomHelp.ts | 19 ---- src/core/command/module-handler.ts | 67 ++++++++------ .../feature-flag/early-access-features.ts | 13 +++ src/core/feature-flag/feature-flag.service.ts | 34 +++++++ tests/core/command/module-handler.spec.ts | 90 +++++++++++++++++++ .../feature-flag/feature-flag.service.spec.ts | 37 ++++++++ .../integration/commands/early-access.spec.ts | 62 +++++++++++++ tests/utls/configurator-mock.ts | 6 +- 10 files changed, 286 insertions(+), 62 deletions(-) delete mode 100644 src/core/command/CustomHelp.ts create mode 100644 src/core/feature-flag/early-access-features.ts create mode 100644 src/core/feature-flag/feature-flag.service.ts create mode 100644 tests/core/feature-flag/feature-flag.service.spec.ts create mode 100644 tests/integration/commands/early-access.spec.ts diff --git a/src/commands/deployment/module.ts b/src/commands/deployment/module.ts index 00f2220c..1925c2d1 100644 --- a/src/commands/deployment/module.ts +++ b/src/commands/deployment/module.ts @@ -6,10 +6,10 @@ import { DeploymentService } from "./deployment.service"; class Module extends IModule { public register(context: Context, configurator: Configurator): void { - const deploymentCommand = configurator.command("deployment").beta(); + const deploymentCommand = configurator.command("deployment").earlyAccess(); deploymentCommand.command("create") - .beta() + .earlyAccess() .description("Create a new deployment") .requiredOption("--packageKey ", "Identifier of the package to deploy") .requiredOption("--packageVersion ", "Version of the package to deploy") @@ -18,10 +18,10 @@ class Module extends IModule { .option("--json", "Return the response as a JSON file") .action(this.createDeployment); - const listCommand = deploymentCommand.command("list").beta(); + const listCommand = deploymentCommand.command("list").earlyAccess(); listCommand.command("history") - .beta() + .earlyAccess() .description("List deployment history") .option("--packageKey ", "Filter deployment history by package key") .option("--targetId ", "Filter deployment history by target ID") @@ -34,7 +34,7 @@ class Module extends IModule { .action(this.listDeploymentHistory); listCommand.command("active") - .beta() + .earlyAccess() .description("Get the active deployment(s) for a given target or package.\n"+ "You can use the command to list the active deployment(s) for a specific target or for a specific package.\n" + "The targetIds filter is available only for getting the active deployments for a given package. \n" + @@ -48,14 +48,14 @@ class Module extends IModule { .action(this.listActiveDeployments); listCommand.command("deployables") - .beta() + .earlyAccess() .description("List all deployables") .option("--flavor ", "Filter deployables by flavor") .option("--json", "Return the response as a JSON file") .action(this.listDeployables); listCommand.command("targets") - .beta() + .earlyAccess() .description("List all targets for a given deployable type and package key") .requiredOption("--deployableType ", "The type of the deployable") .requiredOption("--packageKey ", "Identifier of the package to list targets for") diff --git a/src/content-cli.ts b/src/content-cli.ts index b1ecfa41..b5fdc62e 100644 --- a/src/content-cli.ts +++ b/src/content-cli.ts @@ -6,7 +6,6 @@ import { Configurator, IModuleConstructor, ModuleHandler } from "./core/command/ import { Context } from "./core/command/cli-context"; import { VersionUtils } from "./core/utils/version"; import { logger } from "./core/utils/logger"; -import { ContentCLIHelp } from "./core/command/CustomHelp"; /** * Celonis Content CLI. @@ -38,11 +37,6 @@ function addDefaultOptions(program: Command): void { */ export function createProgram(context: Context, opts: CreateProgramOptions = {}): Command { const program = new Command(); - program.configureHelp({ - formatHelp: (cmd, helper) => new ContentCLIHelp().formatHelp(cmd, helper), - subcommandTerm: cmd => new ContentCLIHelp().subcommandTerm(cmd), - optionTerm: opt => new ContentCLIHelp().optionTerm(opt), - }); program.version(VersionUtils.getCurrentCliVersion()); addDefaultOptions(program); diff --git a/src/core/command/CustomHelp.ts b/src/core/command/CustomHelp.ts deleted file mode 100644 index f5f38364..00000000 --- a/src/core/command/CustomHelp.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Command, Help } from "commander"; -import * as chalk from "chalk"; - -export class ContentCLIHelp extends Help { - - public subcommandTerm(cmd: Command): string { - const base = super.subcommandTerm(cmd); - return (cmd as any).isBeta === true - ? `${base} ${chalk.yellow("(beta)")}` - : base; - } - - public optionTerm(option: any): string { - const term = super.optionTerm(option); - return (option as any).isBeta === true - ? `${term} ${chalk.yellow("(beta)")}` - : term; - } -} diff --git a/src/core/command/module-handler.ts b/src/core/command/module-handler.ts index d4853679..4575f898 100644 --- a/src/core/command/module-handler.ts +++ b/src/core/command/module-handler.ts @@ -1,9 +1,9 @@ import path = require("path"); import * as fs from "fs"; -import { Command, CommandOptions, Option, OptionValues } from "commander"; +import { Command, CommandOptions, OptionValues } from "commander"; import { Context } from "./cli-context"; import { GracefulError, logger } from "../utils/logger"; -import * as chalk from "chalk"; +import { FeatureFlagService } from "../feature-flag/feature-flag.service"; export abstract class IModule { public abstract register(context: Context, commandConfig: Configurator): void; @@ -186,13 +186,6 @@ export class CommandConfig { return this; } - public betaOption(flags: string, description?: string, defaultValue?: string | boolean | string[]): CommandConfig { - const option = new Option(flags, description).default(defaultValue); - (option as any).isBeta = true; - this.cmd.addOption(option); - return this; - } - public requiredOption(flags: string, description?: string, defaultValue?: string | boolean | string[]): CommandConfig { this.cmd.requiredOption(flags, description, defaultValue); return this; @@ -203,17 +196,25 @@ export class CommandConfig { return this; } - public beta(): CommandConfig { - (this.cmd as any).isBeta = true; + /** + * Marks a command as early access (non-GA). Purely internal — it is not shown + * in help. When a feature key is provided, the command is gated at run time: + * before it executes, the CLI checks whether that backend feature flag is + * enabled for the team, and stops with a clear message if it is not. + */ + public earlyAccess(featureKey?: string): CommandConfig { + (this.cmd as any).isEarlyAccess = true; + if (featureKey) { + (this.cmd as any).earlyAccessFeatureKey = featureKey; + } return this; } public action(handler: CommandHandler): void { this.cmd.action(async (): Promise => { try { - this.printBetaNoticeIfBetaCommand(); - this.printBetaNoticeIfBetaOptions(); this.printDeprecationNoticeIfDeprecated(); + await this.checkEarlyAccessFeatureFlag(); await handler(this.ctx, this.cmd, this.cmd.optsWithGlobals()); } catch (error) { if (error instanceof GracefulError) { @@ -232,22 +233,36 @@ export class CommandConfig { } } - private printBetaNoticeIfBetaCommand(): void { - if ((this.cmd as any).isBeta) { - logger.info(chalk.yellow("This command is in beta and may change in future releases.")); - } - } - - private printBetaNoticeIfBetaOptions(): void { - if ((this.cmd as any).isBeta) { + /** + * For early-access commands that carry a feature key, verify the backend + * feature flag is enabled for the team before the command runs. Throws a + * GracefulError with a clear message when it is not enabled (or cannot be + * verified). Commands with no feature key are left untouched. + */ + private async checkEarlyAccessFeatureFlag(): Promise { + const featureKey = (this.cmd as any).earlyAccessFeatureKey; + if (!featureKey) { return; } - const providedOptions = this.cmd.optsWithGlobals(); - for (const option of this.cmd.options) { - const optionName = option.attributeName(); - if ((option as any).isBeta && Object.hasOwn(providedOptions, optionName)) { - logger.info(chalk.yellow(`The option '${option.long}' is in beta and may change in future releases.`)); + + let enabled: boolean; + try { + enabled = await new FeatureFlagService(this.ctx).isEnabled(featureKey); + } catch (error) { + // With no profile, surface the standard "no profile provided" error + // rather than masking it with an early-access message. + if (!this.ctx.profile) { + throw error; } + throw new GracefulError( + `Could not verify whether '${this.cmd.name()}' is enabled for your team. Please try again later or contact support.` + ); + } + + if (!enabled) { + throw new GracefulError( + `'${this.cmd.name()}' is not enabled for your team. Contact support to request access.` + ); } } } diff --git a/src/core/feature-flag/early-access-features.ts b/src/core/feature-flag/early-access-features.ts new file mode 100644 index 00000000..2e586b5f --- /dev/null +++ b/src/core/feature-flag/early-access-features.ts @@ -0,0 +1,13 @@ +/** + * Backend feature-flag keys for early-access commands. + * + * These mirror the backend `FeatureToggle` keys and are the values passed to + * `CommandConfig.earlyAccess(...)`. Keeping them here gives a single place to + * see every early-access feature key even though the wiring lives on the + * individual commands. + */ +export const EarlyAccessFeature = { + BRANCHING: "pacman.branching", +} as const; + +export type EarlyAccessFeatureKey = (typeof EarlyAccessFeature)[keyof typeof EarlyAccessFeature]; diff --git a/src/core/feature-flag/feature-flag.service.ts b/src/core/feature-flag/feature-flag.service.ts new file mode 100644 index 00000000..8ff26682 --- /dev/null +++ b/src/core/feature-flag/feature-flag.service.ts @@ -0,0 +1,34 @@ +import { Context } from "../command/cli-context"; +import { HttpClient } from "../http/http-client"; + +/** + * A backend ("paid") feature flag as returned by the team-features endpoint. + * Only the key is needed here — presence in the list means the flag is enabled + * for the calling team. + */ +interface TeamFeature { + key: string; +} + +/** + * Queries whether a backend feature flag is enabled for the current team. + * + * Uses the same endpoint the web frontend relies on to resolve backend/per-team + * ("paid") feature flags: `GET /api/team/features` returns the list of flags + * enabled for the team behind the profile's token. A flag is considered enabled + * when an entry with a matching key is present in that list. + */ +export class FeatureFlagService { + private static readonly TEAM_FEATURES_URL = "/api/team/features"; + + private httpClient: () => HttpClient; + + constructor(context: Context) { + this.httpClient = () => context.httpClient; + } + + public async isEnabled(featureKey: string): Promise { + const features: TeamFeature[] = await this.httpClient().get(FeatureFlagService.TEAM_FEATURES_URL); + return Array.isArray(features) && features.some(feature => feature?.key === featureKey); + } +} diff --git a/tests/core/command/module-handler.spec.ts b/tests/core/command/module-handler.spec.ts index 956851d9..df58d23b 100644 --- a/tests/core/command/module-handler.spec.ts +++ b/tests/core/command/module-handler.spec.ts @@ -1,8 +1,16 @@ import { Command } from "commander"; import { Configurator } from "../../../src/core/command/module-handler"; +import { Context } from "../../../src/core/command/cli-context"; import { GracefulError } from "../../../src/core/utils/logger"; import { loggingTestTransport } from "../../jest.setup"; import { testContext } from "../../utls/test-context"; +import { mockAxiosGet, mockAxiosGetError } from "../../utls/http-requests-mock"; + +const TEAM_FEATURES_URL = "https://myTeam.celonis.cloud/api/team/features"; + +function loggedMessages(): string[] { + return loggingTestTransport.logMessages.map(entry => String(entry.message)); +} describe("CommandConfig action error handling", () => { let previousExitCode: number | undefined; @@ -60,3 +68,85 @@ describe("CommandConfig action error handling", () => { ).toBe(true); }); }); + +describe("CommandConfig early access gating", () => { + let previousExitCode: number | undefined; + + beforeEach(() => { + previousExitCode = process.exitCode; + process.exitCode = 0; + loggingTestTransport.logMessages = []; + }); + + afterEach(() => { + process.exitCode = previousExitCode; + }); + + async function runEarlyAccessCommand( + featureKey: string | undefined, + context: Context, + handler: () => Promise + ): Promise { + const program = new Command(); + const configurator = new Configurator(program, context); + + configurator + .command("ea-command") + .earlyAccess(featureKey) + .action(async () => { + await handler(); + }); + + program.exitOverride(); + await program.parseAsync(["node", "content-cli", "ea-command"]); + } + + it("runs the command when the feature flag is enabled", async () => { + mockAxiosGet(TEAM_FEATURES_URL, [{ key: "pacman.branching" }]); + const handler = jest.fn(async () => undefined); + + await runEarlyAccessCommand("pacman.branching", testContext, handler); + + expect(handler).toHaveBeenCalled(); + }); + + it("blocks with a clear message when the feature flag is disabled", async () => { + mockAxiosGet(TEAM_FEATURES_URL, []); + const handler = jest.fn(async () => undefined); + + await runEarlyAccessCommand("pacman.branching", testContext, handler); + + expect(handler).not.toHaveBeenCalled(); + expect(process.exitCode ?? 0).toBe(0); + expect(loggedMessages().some(message => message.includes("is not enabled for your team"))).toBe(true); + }); + + it("shows a could-not-verify message when the feature check fails", async () => { + mockAxiosGetError(TEAM_FEATURES_URL, 500, { error: "boom" }); + const handler = jest.fn(async () => undefined); + + await runEarlyAccessCommand("pacman.branching", testContext, handler); + + expect(handler).not.toHaveBeenCalled(); + expect(loggedMessages().some(message => message.includes("Could not verify"))).toBe(true); + }); + + it("surfaces the no-profile error, not the early-access message, when no profile is set", async () => { + const noProfileContext = new Context({}); + const handler = jest.fn(async () => undefined); + + await runEarlyAccessCommand("pacman.branching", noProfileContext, handler); + + expect(handler).not.toHaveBeenCalled(); + expect(loggedMessages().some(message => message.includes("No profile provided"))).toBe(true); + expect(loggedMessages().some(message => message.includes("is not enabled for your team"))).toBe(false); + }); + + it("does not gate commands marked early access without a feature key", async () => { + const handler = jest.fn(async () => undefined); + + await runEarlyAccessCommand(undefined, testContext, handler); + + expect(handler).toHaveBeenCalled(); + }); +}); diff --git a/tests/core/feature-flag/feature-flag.service.spec.ts b/tests/core/feature-flag/feature-flag.service.spec.ts new file mode 100644 index 00000000..108cc449 --- /dev/null +++ b/tests/core/feature-flag/feature-flag.service.spec.ts @@ -0,0 +1,37 @@ +import { FeatureFlagService } from "../../../src/core/feature-flag/feature-flag.service"; +import { testContext } from "../../utls/test-context"; +import { mockAxiosGet, mockAxiosGetError } from "../../utls/http-requests-mock"; + +const TEAM_FEATURES_URL = "https://myTeam.celonis.cloud/api/team/features"; + +describe("FeatureFlagService", () => { + it("returns true when the feature key is present in the team features", async () => { + mockAxiosGet(TEAM_FEATURES_URL, [{ key: "pacman.branching" }, { key: "some.other.flag" }]); + + const enabled = await new FeatureFlagService(testContext).isEnabled("pacman.branching"); + + expect(enabled).toBe(true); + }); + + it("returns false when the feature key is not present", async () => { + mockAxiosGet(TEAM_FEATURES_URL, [{ key: "some.other.flag" }]); + + const enabled = await new FeatureFlagService(testContext).isEnabled("pacman.branching"); + + expect(enabled).toBe(false); + }); + + it("returns false when the team has no features enabled", async () => { + mockAxiosGet(TEAM_FEATURES_URL, []); + + const enabled = await new FeatureFlagService(testContext).isEnabled("pacman.branching"); + + expect(enabled).toBe(false); + }); + + it("rejects when the team features endpoint fails", async () => { + mockAxiosGetError(TEAM_FEATURES_URL, 500, { error: "boom" }); + + await expect(new FeatureFlagService(testContext).isEnabled("pacman.branching")).rejects.toBeDefined(); + }); +}); diff --git a/tests/integration/commands/early-access.spec.ts b/tests/integration/commands/early-access.spec.ts new file mode 100644 index 00000000..23605e14 --- /dev/null +++ b/tests/integration/commands/early-access.spec.ts @@ -0,0 +1,62 @@ +import { IModule, Configurator } from "../../../src/core/command/module-handler"; +import { Context } from "../../../src/core/command/cli-context"; +import { CliRunResult, runCli as runCliProcess } from "../../utls/cli-runner"; +import { mockAxiosGet, mockAxiosGetError } from "../../utls/http-requests-mock"; + +const TEAM_FEATURES_URL = "https://myTeam.celonis.cloud/api/team/features"; + +const handlerSpy = jest.fn(async () => undefined); + +/** + * Throwaway module that registers a single early-access command gated on the + * branching feature flag, so we can exercise the gate end-to-end through the + * real CLI program via runCli. + */ +class EarlyAccessTestModule extends IModule { + public register(_context: Context, configurator: Configurator): void { + configurator + .command("ea-test") + .earlyAccess("pacman.branching") + .action(handlerSpy); + } +} + +describe("early access command integration", () => { + beforeEach(() => { + handlerSpy.mockClear(); + }); + + async function runCli(args: string[]): Promise { + return runCliProcess(args, [EarlyAccessTestModule]); + } + + it("runs the command when the feature flag is enabled for the team", async () => { + mockAxiosGet(TEAM_FEATURES_URL, [{ key: "pacman.branching" }]); + + const result = await runCli(["ea-test"]); + + expect(result.exitCode).toBe(0); + expect(handlerSpy).toHaveBeenCalled(); + }); + + it("blocks with a clear message when the feature flag is disabled", async () => { + mockAxiosGet(TEAM_FEATURES_URL, []); + + const result = await runCli(["ea-test"]); + + expect(result.exitCode).toBe(0); + expect(handlerSpy).not.toHaveBeenCalled(); + expect(result.output).toContain("is not enabled for your team"); + expect(result.output).toContain("Contact support to request access"); + }); + + it("shows a could-not-verify message when the feature check fails", async () => { + mockAxiosGetError(TEAM_FEATURES_URL, 500, { error: "boom" }); + + const result = await runCli(["ea-test"]); + + expect(result.exitCode).toBe(0); + expect(handlerSpy).not.toHaveBeenCalled(); + expect(result.output).toContain("Could not verify whether 'ea-test' is enabled"); + }); +}); diff --git a/tests/utls/configurator-mock.ts b/tests/utls/configurator-mock.ts index a22fe19d..cb141810 100644 --- a/tests/utls/configurator-mock.ts +++ b/tests/utls/configurator-mock.ts @@ -17,9 +17,8 @@ export interface MockConfigurator extends Configurator { requiredOption: jest.Mock; alias: jest.Mock; argument: jest.Mock; - betaOption: jest.Mock; deprecationNotice: jest.Mock; - beta: jest.Mock; + earlyAccess: jest.Mock; action: jest.Mock; } @@ -32,9 +31,8 @@ export function createMockConfigurator(): MockConfigurator { chain.requiredOption = jest.fn(() => chain); chain.alias = jest.fn(() => chain); chain.argument = jest.fn(() => chain); - chain.betaOption = jest.fn(() => chain); chain.deprecationNotice = jest.fn(() => chain); - chain.beta = jest.fn(() => chain); + chain.earlyAccess = jest.fn(() => chain); chain.action = jest.fn(); return chain as MockConfigurator; From 5e063e6341c23acf5319e36a17585172e8a9eb41 Mon Sep 17 00:00:00 2001 From: "a.jashari" Date: Thu, 9 Jul 2026 13:54:33 +0200 Subject: [PATCH 2/6] SP-1383: cover early-access constants and feature-flag branches Co-Authored-By: Claude Opus 4.8 --- coverage/base.css | 224 +++++ coverage/block-navigation.js | 87 ++ coverage/command/index.html | 116 +++ coverage/command/module-handler.ts.html | 889 ++++++++++++++++++ coverage/favicon.png | Bin 0 -> 445 bytes .../early-access-features.ts.html | 124 +++ .../feature-flag/feature-flag.service.ts.html | 187 ++++ coverage/feature-flag/index.html | 131 +++ coverage/index.html | 131 +++ coverage/lcov-report/base.css | 224 +++++ coverage/lcov-report/block-navigation.js | 87 ++ coverage/lcov-report/command/index.html | 116 +++ .../command/module-handler.ts.html | 889 ++++++++++++++++++ coverage/lcov-report/favicon.png | Bin 0 -> 445 bytes .../early-access-features.ts.html | 124 +++ .../feature-flag/feature-flag.service.ts.html | 187 ++++ coverage/lcov-report/feature-flag/index.html | 131 +++ coverage/lcov-report/index.html | 131 +++ coverage/lcov-report/prettify.css | 1 + coverage/lcov-report/prettify.js | 2 + coverage/lcov-report/sort-arrow-sprite.png | Bin 0 -> 138 bytes coverage/lcov-report/sorter.js | 196 ++++ coverage/lcov.info | 427 +++++++++ coverage/prettify.css | 1 + coverage/prettify.js | 2 + coverage/sort-arrow-sprite.png | Bin 0 -> 138 bytes coverage/sorter.js | 196 ++++ .../feature-flag/feature-flag.service.spec.ts | 16 + .../integration/commands/early-access.spec.ts | 5 +- 29 files changed, 4622 insertions(+), 2 deletions(-) create mode 100644 coverage/base.css create mode 100644 coverage/block-navigation.js create mode 100644 coverage/command/index.html create mode 100644 coverage/command/module-handler.ts.html create mode 100644 coverage/favicon.png create mode 100644 coverage/feature-flag/early-access-features.ts.html create mode 100644 coverage/feature-flag/feature-flag.service.ts.html create mode 100644 coverage/feature-flag/index.html create mode 100644 coverage/index.html create mode 100644 coverage/lcov-report/base.css create mode 100644 coverage/lcov-report/block-navigation.js create mode 100644 coverage/lcov-report/command/index.html create mode 100644 coverage/lcov-report/command/module-handler.ts.html create mode 100644 coverage/lcov-report/favicon.png create mode 100644 coverage/lcov-report/feature-flag/early-access-features.ts.html create mode 100644 coverage/lcov-report/feature-flag/feature-flag.service.ts.html create mode 100644 coverage/lcov-report/feature-flag/index.html create mode 100644 coverage/lcov-report/index.html create mode 100644 coverage/lcov-report/prettify.css create mode 100644 coverage/lcov-report/prettify.js create mode 100644 coverage/lcov-report/sort-arrow-sprite.png create mode 100644 coverage/lcov-report/sorter.js create mode 100644 coverage/lcov.info create mode 100644 coverage/prettify.css create mode 100644 coverage/prettify.js create mode 100644 coverage/sort-arrow-sprite.png create mode 100644 coverage/sorter.js diff --git a/coverage/base.css b/coverage/base.css new file mode 100644 index 00000000..f418035b --- /dev/null +++ b/coverage/base.css @@ -0,0 +1,224 @@ +body, html { + margin:0; padding: 0; + height: 100%; +} +body { + font-family: Helvetica Neue, Helvetica, Arial; + font-size: 14px; + color:#333; +} +.small { font-size: 12px; } +*, *:after, *:before { + -webkit-box-sizing:border-box; + -moz-box-sizing:border-box; + box-sizing:border-box; + } +h1 { font-size: 20px; margin: 0;} +h2 { font-size: 14px; } +pre { + font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; + margin: 0; + padding: 0; + -moz-tab-size: 2; + -o-tab-size: 2; + tab-size: 2; +} +a { color:#0074D9; text-decoration:none; } +a:hover { text-decoration:underline; } +.strong { font-weight: bold; } +.space-top1 { padding: 10px 0 0 0; } +.pad2y { padding: 20px 0; } +.pad1y { padding: 10px 0; } +.pad2x { padding: 0 20px; } +.pad2 { padding: 20px; } +.pad1 { padding: 10px; } +.space-left2 { padding-left:55px; } +.space-right2 { padding-right:20px; } +.center { text-align:center; } +.clearfix { display:block; } +.clearfix:after { + content:''; + display:block; + height:0; + clear:both; + visibility:hidden; + } +.fl { float: left; } +@media only screen and (max-width:640px) { + .col3 { width:100%; max-width:100%; } + .hide-mobile { display:none!important; } +} + +.quiet { + color: #7f7f7f; + color: rgba(0,0,0,0.5); +} +.quiet a { opacity: 0.7; } + +.fraction { + font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; + font-size: 10px; + color: #555; + background: #E8E8E8; + padding: 4px 5px; + border-radius: 3px; + vertical-align: middle; +} + +div.path a:link, div.path a:visited { color: #333; } +table.coverage { + border-collapse: collapse; + margin: 10px 0 0 0; + padding: 0; +} + +table.coverage td { + margin: 0; + padding: 0; + vertical-align: top; +} +table.coverage td.line-count { + text-align: right; + padding: 0 5px 0 20px; +} +table.coverage td.line-coverage { + text-align: right; + padding-right: 10px; + min-width:20px; +} + +table.coverage td span.cline-any { + display: inline-block; + padding: 0 5px; + width: 100%; +} +.missing-if-branch { + display: inline-block; + margin-right: 5px; + border-radius: 3px; + position: relative; + padding: 0 4px; + background: #333; + color: yellow; +} + +.skip-if-branch { + display: none; + margin-right: 10px; + position: relative; + padding: 0 4px; + background: #ccc; + color: white; +} +.missing-if-branch .typ, .skip-if-branch .typ { + color: inherit !important; +} +.coverage-summary { + border-collapse: collapse; + width: 100%; +} +.coverage-summary tr { border-bottom: 1px solid #bbb; } +.keyline-all { border: 1px solid #ddd; } +.coverage-summary td, .coverage-summary th { padding: 10px; } +.coverage-summary tbody { border: 1px solid #bbb; } +.coverage-summary td { border-right: 1px solid #bbb; } +.coverage-summary td:last-child { border-right: none; } +.coverage-summary th { + text-align: left; + font-weight: normal; + white-space: nowrap; +} +.coverage-summary th.file { border-right: none !important; } +.coverage-summary th.pct { } +.coverage-summary th.pic, +.coverage-summary th.abs, +.coverage-summary td.pct, +.coverage-summary td.abs { text-align: right; } +.coverage-summary td.file { white-space: nowrap; } +.coverage-summary td.pic { min-width: 120px !important; } +.coverage-summary tfoot td { } + +.coverage-summary .sorter { + height: 10px; + width: 7px; + display: inline-block; + margin-left: 0.5em; + background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; +} +.coverage-summary .sorted .sorter { + background-position: 0 -20px; +} +.coverage-summary .sorted-desc .sorter { + background-position: 0 -10px; +} +.status-line { height: 10px; } +/* yellow */ +.cbranch-no { background: yellow !important; color: #111; } +/* dark red */ +.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } +.low .chart { border:1px solid #C21F39 } +.highlighted, +.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ + background: #C21F39 !important; +} +/* medium red */ +.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } +/* light red */ +.low, .cline-no { background:#FCE1E5 } +/* light green */ +.high, .cline-yes { background:rgb(230,245,208) } +/* medium green */ +.cstat-yes { background:rgb(161,215,106) } +/* dark green */ +.status-line.high, .high .cover-fill { background:rgb(77,146,33) } +.high .chart { border:1px solid rgb(77,146,33) } +/* dark yellow (gold) */ +.status-line.medium, .medium .cover-fill { background: #f9cd0b; } +.medium .chart { border:1px solid #f9cd0b; } +/* light yellow */ +.medium { background: #fff4c2; } + +.cstat-skip { background: #ddd; color: #111; } +.fstat-skip { background: #ddd; color: #111 !important; } +.cbranch-skip { background: #ddd !important; color: #111; } + +span.cline-neutral { background: #eaeaea; } + +.coverage-summary td.empty { + opacity: .5; + padding-top: 4px; + padding-bottom: 4px; + line-height: 1; + color: #888; +} + +.cover-fill, .cover-empty { + display:inline-block; + height: 12px; +} +.chart { + line-height: 0; +} +.cover-empty { + background: white; +} +.cover-full { + border-right: none !important; +} +pre.prettyprint { + border: none !important; + padding: 0 !important; + margin: 0 !important; +} +.com { color: #999 !important; } +.ignore-none { color: #999; font-weight: normal; } + +.wrapper { + min-height: 100%; + height: auto !important; + height: 100%; + margin: 0 auto -48px; +} +.footer, .push { + height: 48px; +} diff --git a/coverage/block-navigation.js b/coverage/block-navigation.js new file mode 100644 index 00000000..cc121302 --- /dev/null +++ b/coverage/block-navigation.js @@ -0,0 +1,87 @@ +/* eslint-disable */ +var jumpToCode = (function init() { + // Classes of code we would like to highlight in the file view + var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; + + // Elements to highlight in the file listing view + var fileListingElements = ['td.pct.low']; + + // We don't want to select elements that are direct descendants of another match + var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` + + // Selecter that finds elements on the page to which we can jump + var selector = + fileListingElements.join(', ') + + ', ' + + notSelector + + missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` + + // The NodeList of matching elements + var missingCoverageElements = document.querySelectorAll(selector); + + var currentIndex; + + function toggleClass(index) { + missingCoverageElements + .item(currentIndex) + .classList.remove('highlighted'); + missingCoverageElements.item(index).classList.add('highlighted'); + } + + function makeCurrent(index) { + toggleClass(index); + currentIndex = index; + missingCoverageElements.item(index).scrollIntoView({ + behavior: 'smooth', + block: 'center', + inline: 'center' + }); + } + + function goToPrevious() { + var nextIndex = 0; + if (typeof currentIndex !== 'number' || currentIndex === 0) { + nextIndex = missingCoverageElements.length - 1; + } else if (missingCoverageElements.length > 1) { + nextIndex = currentIndex - 1; + } + + makeCurrent(nextIndex); + } + + function goToNext() { + var nextIndex = 0; + + if ( + typeof currentIndex === 'number' && + currentIndex < missingCoverageElements.length - 1 + ) { + nextIndex = currentIndex + 1; + } + + makeCurrent(nextIndex); + } + + return function jump(event) { + if ( + document.getElementById('fileSearch') === document.activeElement && + document.activeElement != null + ) { + // if we're currently focused on the search input, we don't want to navigate + return; + } + + switch (event.which) { + case 78: // n + case 74: // j + goToNext(); + break; + case 66: // b + case 75: // k + case 80: // p + goToPrevious(); + break; + } + }; +})(); +window.addEventListener('keydown', jumpToCode); diff --git a/coverage/command/index.html b/coverage/command/index.html new file mode 100644 index 00000000..f07df22b --- /dev/null +++ b/coverage/command/index.html @@ -0,0 +1,116 @@ + + + + + + Code coverage report for command + + + + + + + + + +
+
+

All files command

+
+ +
+ 66.79% + Statements + 179/268 +
+ + +
+ 100% + Branches + 37/37 +
+ + +
+ 87.5% + Functions + 14/16 +
+ + +
+ 66.79% + Lines + 179/268 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
module-handler.ts +
+
66.79%179/268100%37/3787.5%14/1666.79%179/268
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/command/module-handler.ts.html b/coverage/command/module-handler.ts.html new file mode 100644 index 00000000..d04f020a --- /dev/null +++ b/coverage/command/module-handler.ts.html @@ -0,0 +1,889 @@ + + + + + + Code coverage report for command/module-handler.ts + + + + + + + + + +
+
+

All files / command module-handler.ts

+
+ +
+ 66.79% + Statements + 179/268 +
+ + +
+ 100% + Branches + 37/37 +
+ + +
+ 87.5% + Functions + 14/16 +
+ + +
+ 66.79% + Lines + 179/268 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +2691x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +80x +80x +80x +80x +80x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +87x +87x +87x +1x +1x +1x +1x +1x +1x +1x +227x +60x +60x +167x +167x +167x +167x +167x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1923x +1923x +1923x +1x +1x +1756x +1756x +1756x +1x +1x +80x +80x +80x +1x +1x +1913x +1913x +1913x +1x +1x +  +  +  +1x +1x +6460x +6460x +6460x +1x +1x +1465x +1465x +1465x +1x +1x +300x +300x +300x +1x +1x +1x +1x +1x +1x +1x +1x +8x +8x +7x +7x +8x +8x +1x +1x +1389x +85x +85x +85x +80x +85x +30x +6x +6x +6x +24x +24x +24x +1389x +1389x +1x +1x +85x +31x +31x +85x +1x +1x +1x +1x +1x +1x +1x +1x +85x +85x +78x +78x +7x +7x +7x +7x +5x +3x +3x +3x +1x +1x +2x +2x +2x +2x +4x +10x +2x +2x +2x +2x +85x +1x + 
import path = require("path");
+import * as fs from "fs";
+import { Command, CommandOptions, OptionValues } from "commander";
+import { Context } from "./cli-context";
+import { GracefulError, logger } from "../utils/logger";
+import { FeatureFlagService } from "../feature-flag/feature-flag.service";
+ 
+export abstract class IModule {
+    public abstract register(context: Context, commandConfig: Configurator): void;
+}
+ 
+export type IModuleConstructor = new () => IModule;
+ 
+export class ModuleHandler {
+    public configurator: Configurator;
+ 
+    constructor(
+        public program: Command,
+        public context: Context
+    ) {
+        this.configurator = new Configurator(this.program, this.context);
+    }
+ 
+    // Store registered module instances if needed later
+    public registeredModules: IModule[] = [];
+ 
+    /**
+     * Discovers modules in the specified directory, imports them,
+     * instantiates the default exported class, and calls its register method.
+     *
+     * @param {any} rootPath - __dirname when invoked from the main entry file
+     * @param devMode        - Use uncompiled modules for development debug mode
+     */
+    public discoverAndRegisterModules(rootPath: string, devMode: boolean = false): void {
+        const modulesDirPath = path.resolve(rootPath, "commands");
+
+        try {
+            const moduleFolders = fs.readdirSync(modulesDirPath, { withFileTypes: true });
+
+            for (const dirent of moduleFolders) {
+                if (dirent.isDirectory()) {
+                    const moduleFolderName = dirent.name;
+
+                    const moduleFileName = devMode ? "module.ts" : "module.js";
+
+                    // Calculate path relative to *this file's location in dist*
+                    let potentialModuleJsPath: any;
+                    potentialModuleJsPath = path.resolve(
+                        rootPath,
+                        "commands",
+                        moduleFolderName,
+                        moduleFileName // Look for the compiled JS file
+                    );
+                    try {
+                        fs.accessSync(potentialModuleJsPath);
+                    } catch (err) {
+                        // apparently the file does not exist of is not accessible
+                        potentialModuleJsPath = null;
+                    }
+
+                    if (!potentialModuleJsPath) {
+                        logger.debug(
+                            `Module folder ${moduleFolderName} does not contain a valid entry point and is skipped.`
+                        );
+                    } else {
+                        // Check if the compiled JS file exists
+                        try {
+                            logger.debug(`Found potential module definition: ${potentialModuleJsPath}`);
+
+                            // Dynamically require the module
+                            const requiredModule = require(potentialModuleJsPath);
+
+                            // With 'export =' or 'module.exports =', the required value *is* the class
+                            const ModuleClass = requiredModule as IModuleConstructor; // Cast for TS check
+
+                            // Basic check: Is it a class (function)?
+                            if (typeof ModuleClass === "function" && ModuleClass.prototype) {
+                                const moduleInstance: IModule = new ModuleClass(); // Instantiate
+
+                                // Check if the instance has the register method
+                                if (typeof moduleInstance.register === "function") {
+                                    logger.debug(`Registering module: ${moduleFolderName}`);
+                                    // Call register - can still be async even if require() is sync
+                                    moduleInstance.register(this.context, this.configurator);
+                                    this.registeredModules.push(moduleInstance);
+                                } else {
+                                    logger.warn(`Module ${moduleFolderName} export does not have a 'register' method.`);
+                                }
+                            } else {
+                                logger.warn(`Module ${moduleFolderName} export is not a class/constructor function.`);
+                            }
+                        } catch (error: any) {
+                            if (error.code === "ENOENT") {
+                                // Compiled module.js not found, maybe folder doesn't contain a valid module
+                                logger.warn(
+                                    `Directory ${moduleFolderName} does not contain a compiled module.js file.`
+                                );
+                            } else if (error.code === "MODULE_NOT_FOUND") {
+                                logger.debug("Error details", error);
+                                logger.warn(
+                                    `Could not require module ${moduleFolderName}. Check dependencies or compilation. Path: ${potentialModuleJsPath}`
+                                );
+                            } else {
+                                logger.error(`Error processing module in ${moduleFolderName}:`, error);
+                            }
+                        }
+                    }
+                }
+            }
+        } catch (error: any) {
+            if (error.code === "ENOENT") {
+                logger.error(
+                    `Modules directory not found relative to JS output: ${path.resolve(path.dirname(__filename), "commands")}`
+                );
+            } else {
+                logger.error("Failed to read modules directory:", error);
+            }
+        }
+        logger.debug(`Module discovery complete. ${this.registeredModules.length} modules registered.`);
+    }
+}
+ 
+type CommandHandler = (context: Context, command: Command, options: OptionValues) => Promise<void>;
+ 
+/**
+ * Allows the creation of root level commands.
+ */
+export class Configurator {
+    public rootCommandMap = new Map<string, CommandConfig>();
+ 
+    constructor(
+        private program: Command,
+        private ctx: Context
+    ) {}
+ 
+    /**
+     * Get or create a root level command.
+     * @param name
+     * @returns
+     */
+    public command(name: string): CommandConfig {
+        if (this.rootCommandMap.has(name)) {
+            return this.rootCommandMap.get(name);
+        }
+        const cmd = this.program.command(name);
+        const cmdConfig = new CommandConfig(cmd, this.ctx);
+        this.rootCommandMap.set(name, cmdConfig);
+        return cmdConfig;
+    }
+}
+ 
+/**
+ * Delegate wrapper around the Command object, to simply change the way the program is
+ * executed.
+ */
+export class CommandConfig {
+    private deprecationMessage: string;
+ 
+    constructor(
+        private cmd: Command,
+        private ctx: Context
+    ) {}
+ 
+    public command(nameAndArgs: string, opts?: CommandOptions): CommandConfig {
+        return new CommandConfig(this.cmd.command(nameAndArgs, opts), this.ctx)
+            .option("-p, --profile <profile>", "Profile which you want to use");
+    }
+ 
+    public alias(alias: string): CommandConfig {
+        this.cmd.alias(alias);
+        return this;
+    }
+ 
+    public description(description: string): CommandConfig {
+        this.cmd.description(description);
+        return this;
+    }
+ 
+    public argument(name: string, description?: string, defaultValue?: unknown): CommandConfig {
+        this.cmd.argument(name, description, defaultValue);
+        return this;
+    }
+ 
+    public option(flags: string, description?: string, defaultValue?: string | boolean | string[]): CommandConfig {
+        this.cmd.option(flags, description, defaultValue);
+        return this;
+    }
+ 
+    public requiredOption(flags: string, description?: string, defaultValue?: string | boolean | string[]): CommandConfig {
+        this.cmd.requiredOption(flags, description, defaultValue);
+        return this;
+    }
+ 
+    public deprecationNotice(deprecationMessage: string): CommandConfig {
+        this.deprecationMessage = deprecationMessage;
+        return this;
+    }
+ 
+    /**
+     * Marks a command as early access (non-GA). Purely internal — it is not shown
+     * in help. When a feature key is provided, the command is gated at run time:
+     * before it executes, the CLI checks whether that backend feature flag is
+     * enabled for the team, and stops with a clear message if it is not.
+     */
+    public earlyAccess(featureKey?: string): CommandConfig {
+        (this.cmd as any).isEarlyAccess = true;
+        if (featureKey) {
+            (this.cmd as any).earlyAccessFeatureKey = featureKey;
+        }
+        return this;
+    }
+ 
+    public action(handler: CommandHandler): void {
+        this.cmd.action(async (): Promise<void> => {
+            try {
+                this.printDeprecationNoticeIfDeprecated();
+                await this.checkEarlyAccessFeatureFlag();
+                await handler(this.ctx, this.cmd, this.cmd.optsWithGlobals());
+            } catch (error) {
+                if (error instanceof GracefulError) {
+                    logger.error(error.message);
+                    return;
+                }
+                logger.error(`An unexpected error occured executing a command: ${error}`);
+                process.exitCode = 1;
+            }
+        });
+    }
+ 
+    private printDeprecationNoticeIfDeprecated(): void {
+        if (this.deprecationMessage) {
+            logger.warn("⚠️  [DEPRECATION NOTICE] \n" + this.deprecationMessage);
+        }
+    }
+ 
+    /**
+     * For early-access commands that carry a feature key, verify the backend
+     * feature flag is enabled for the team before the command runs. Throws a
+     * GracefulError with a clear message when it is not enabled (or cannot be
+     * verified). Commands with no feature key are left untouched.
+     */
+    private async checkEarlyAccessFeatureFlag(): Promise<void> {
+        const featureKey = (this.cmd as any).earlyAccessFeatureKey;
+        if (!featureKey) {
+            return;
+        }
+ 
+        let enabled: boolean;
+        try {
+            enabled = await new FeatureFlagService(this.ctx).isEnabled(featureKey);
+        } catch (error) {
+            // With no profile, surface the standard "no profile provided" error
+            // rather than masking it with an early-access message.
+            if (!this.ctx.profile) {
+                throw error;
+            }
+            throw new GracefulError(
+                `Could not verify whether '${this.cmd.name()}' is enabled for your team. Please try again later or contact support.`
+            );
+        }
+ 
+        if (!enabled) {
+            throw new GracefulError(
+                `'${this.cmd.name()}' is not enabled for your team. Contact support to request access.`
+            );
+        }
+    }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/favicon.png b/coverage/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..c1525b811a167671e9de1fa78aab9f5c0b61cef7 GIT binary patch literal 445 zcmV;u0Yd(XP))rP{nL}Ln%S7`m{0DjX9TLF* zFCb$4Oi7vyLOydb!7n&^ItCzb-%BoB`=x@N2jll2Nj`kauio%aw_@fe&*}LqlFT43 z8doAAe))z_%=P%v^@JHp3Hjhj^6*Kr_h|g_Gr?ZAa&y>wxHE99Gk>A)2MplWz2xdG zy8VD2J|Uf#EAw*bo5O*PO_}X2Tob{%bUoO2G~T`@%S6qPyc}VkhV}UifBuRk>%5v( z)x7B{I~z*k<7dv#5tC+m{km(D087J4O%+<<;K|qwefb6@GSX45wCK}Sn*> + + + + Code coverage report for feature-flag/early-access-features.ts + + + + + + + + + +
+
+

All files / feature-flag early-access-features.ts

+
+ +
+ 100% + Statements + 13/13 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 13/13 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +141x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x + 
/**
+ * Backend feature-flag keys for early-access commands.
+ *
+ * These mirror the backend `FeatureToggle` keys and are the values passed to
+ * `CommandConfig.earlyAccess(...)`. Keeping them here gives a single place to
+ * see every early-access feature key even though the wiring lives on the
+ * individual commands.
+ */
+export const EarlyAccessFeature = {
+    BRANCHING: "pacman.branching",
+} as const;
+ 
+export type EarlyAccessFeatureKey = (typeof EarlyAccessFeature)[keyof typeof EarlyAccessFeature];
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/feature-flag/feature-flag.service.ts.html b/coverage/feature-flag/feature-flag.service.ts.html new file mode 100644 index 00000000..f51159d0 --- /dev/null +++ b/coverage/feature-flag/feature-flag.service.ts.html @@ -0,0 +1,187 @@ + + + + + + Code coverage report for feature-flag/feature-flag.service.ts + + + + + + + + + +
+
+

All files / feature-flag feature-flag.service.ts

+
+ +
+ 100% + Statements + 34/34 +
+ + +
+ 100% + Branches + 10/10 +
+ + +
+ 100% + Functions + 3/3 +
+ + +
+ 100% + Lines + 34/34 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +351x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +13x +13x +1x +1x +13x +13x +13x +1x + 
import { Context } from "../command/cli-context";
+import { HttpClient } from "../http/http-client";
+ 
+/**
+ * A backend ("paid") feature flag as returned by the team-features endpoint.
+ * Only the key is needed here — presence in the list means the flag is enabled
+ * for the calling team.
+ */
+interface TeamFeature {
+    key: string;
+}
+ 
+/**
+ * Queries whether a backend feature flag is enabled for the current team.
+ *
+ * Uses the same endpoint the web frontend relies on to resolve backend/per-team
+ * ("paid") feature flags: `GET /api/team/features` returns the list of flags
+ * enabled for the team behind the profile's token. A flag is considered enabled
+ * when an entry with a matching key is present in that list.
+ */
+export class FeatureFlagService {
+    private static readonly TEAM_FEATURES_URL = "/api/team/features";
+ 
+    private httpClient: () => HttpClient;
+ 
+    constructor(context: Context) {
+        this.httpClient = () => context.httpClient;
+    }
+ 
+    public async isEnabled(featureKey: string): Promise<boolean> {
+        const features: TeamFeature[] = await this.httpClient().get(FeatureFlagService.TEAM_FEATURES_URL);
+        return Array.isArray(features) && features.some(feature => feature?.key === featureKey);
+    }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/feature-flag/index.html b/coverage/feature-flag/index.html new file mode 100644 index 00000000..0aa13214 --- /dev/null +++ b/coverage/feature-flag/index.html @@ -0,0 +1,131 @@ + + + + + + Code coverage report for feature-flag + + + + + + + + + +
+
+

All files feature-flag

+
+ +
+ 100% + Statements + 47/47 +
+ + +
+ 100% + Branches + 10/10 +
+ + +
+ 100% + Functions + 3/3 +
+ + +
+ 100% + Lines + 47/47 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
early-access-features.ts +
+
100%13/13100%0/0100%0/0100%13/13
feature-flag.service.ts +
+
100%34/34100%10/10100%3/3100%34/34
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/index.html b/coverage/index.html new file mode 100644 index 00000000..b8610ee8 --- /dev/null +++ b/coverage/index.html @@ -0,0 +1,131 @@ + + + + + + Code coverage report for All files + + + + + + + + + +
+
+

All files

+
+ +
+ 71.74% + Statements + 226/315 +
+ + +
+ 100% + Branches + 47/47 +
+ + +
+ 89.47% + Functions + 17/19 +
+ + +
+ 71.74% + Lines + 226/315 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
command +
+
66.79%179/268100%37/3787.5%14/1666.79%179/268
feature-flag +
+
100%47/47100%10/10100%3/3100%47/47
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/base.css b/coverage/lcov-report/base.css new file mode 100644 index 00000000..f418035b --- /dev/null +++ b/coverage/lcov-report/base.css @@ -0,0 +1,224 @@ +body, html { + margin:0; padding: 0; + height: 100%; +} +body { + font-family: Helvetica Neue, Helvetica, Arial; + font-size: 14px; + color:#333; +} +.small { font-size: 12px; } +*, *:after, *:before { + -webkit-box-sizing:border-box; + -moz-box-sizing:border-box; + box-sizing:border-box; + } +h1 { font-size: 20px; margin: 0;} +h2 { font-size: 14px; } +pre { + font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; + margin: 0; + padding: 0; + -moz-tab-size: 2; + -o-tab-size: 2; + tab-size: 2; +} +a { color:#0074D9; text-decoration:none; } +a:hover { text-decoration:underline; } +.strong { font-weight: bold; } +.space-top1 { padding: 10px 0 0 0; } +.pad2y { padding: 20px 0; } +.pad1y { padding: 10px 0; } +.pad2x { padding: 0 20px; } +.pad2 { padding: 20px; } +.pad1 { padding: 10px; } +.space-left2 { padding-left:55px; } +.space-right2 { padding-right:20px; } +.center { text-align:center; } +.clearfix { display:block; } +.clearfix:after { + content:''; + display:block; + height:0; + clear:both; + visibility:hidden; + } +.fl { float: left; } +@media only screen and (max-width:640px) { + .col3 { width:100%; max-width:100%; } + .hide-mobile { display:none!important; } +} + +.quiet { + color: #7f7f7f; + color: rgba(0,0,0,0.5); +} +.quiet a { opacity: 0.7; } + +.fraction { + font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; + font-size: 10px; + color: #555; + background: #E8E8E8; + padding: 4px 5px; + border-radius: 3px; + vertical-align: middle; +} + +div.path a:link, div.path a:visited { color: #333; } +table.coverage { + border-collapse: collapse; + margin: 10px 0 0 0; + padding: 0; +} + +table.coverage td { + margin: 0; + padding: 0; + vertical-align: top; +} +table.coverage td.line-count { + text-align: right; + padding: 0 5px 0 20px; +} +table.coverage td.line-coverage { + text-align: right; + padding-right: 10px; + min-width:20px; +} + +table.coverage td span.cline-any { + display: inline-block; + padding: 0 5px; + width: 100%; +} +.missing-if-branch { + display: inline-block; + margin-right: 5px; + border-radius: 3px; + position: relative; + padding: 0 4px; + background: #333; + color: yellow; +} + +.skip-if-branch { + display: none; + margin-right: 10px; + position: relative; + padding: 0 4px; + background: #ccc; + color: white; +} +.missing-if-branch .typ, .skip-if-branch .typ { + color: inherit !important; +} +.coverage-summary { + border-collapse: collapse; + width: 100%; +} +.coverage-summary tr { border-bottom: 1px solid #bbb; } +.keyline-all { border: 1px solid #ddd; } +.coverage-summary td, .coverage-summary th { padding: 10px; } +.coverage-summary tbody { border: 1px solid #bbb; } +.coverage-summary td { border-right: 1px solid #bbb; } +.coverage-summary td:last-child { border-right: none; } +.coverage-summary th { + text-align: left; + font-weight: normal; + white-space: nowrap; +} +.coverage-summary th.file { border-right: none !important; } +.coverage-summary th.pct { } +.coverage-summary th.pic, +.coverage-summary th.abs, +.coverage-summary td.pct, +.coverage-summary td.abs { text-align: right; } +.coverage-summary td.file { white-space: nowrap; } +.coverage-summary td.pic { min-width: 120px !important; } +.coverage-summary tfoot td { } + +.coverage-summary .sorter { + height: 10px; + width: 7px; + display: inline-block; + margin-left: 0.5em; + background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; +} +.coverage-summary .sorted .sorter { + background-position: 0 -20px; +} +.coverage-summary .sorted-desc .sorter { + background-position: 0 -10px; +} +.status-line { height: 10px; } +/* yellow */ +.cbranch-no { background: yellow !important; color: #111; } +/* dark red */ +.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } +.low .chart { border:1px solid #C21F39 } +.highlighted, +.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ + background: #C21F39 !important; +} +/* medium red */ +.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } +/* light red */ +.low, .cline-no { background:#FCE1E5 } +/* light green */ +.high, .cline-yes { background:rgb(230,245,208) } +/* medium green */ +.cstat-yes { background:rgb(161,215,106) } +/* dark green */ +.status-line.high, .high .cover-fill { background:rgb(77,146,33) } +.high .chart { border:1px solid rgb(77,146,33) } +/* dark yellow (gold) */ +.status-line.medium, .medium .cover-fill { background: #f9cd0b; } +.medium .chart { border:1px solid #f9cd0b; } +/* light yellow */ +.medium { background: #fff4c2; } + +.cstat-skip { background: #ddd; color: #111; } +.fstat-skip { background: #ddd; color: #111 !important; } +.cbranch-skip { background: #ddd !important; color: #111; } + +span.cline-neutral { background: #eaeaea; } + +.coverage-summary td.empty { + opacity: .5; + padding-top: 4px; + padding-bottom: 4px; + line-height: 1; + color: #888; +} + +.cover-fill, .cover-empty { + display:inline-block; + height: 12px; +} +.chart { + line-height: 0; +} +.cover-empty { + background: white; +} +.cover-full { + border-right: none !important; +} +pre.prettyprint { + border: none !important; + padding: 0 !important; + margin: 0 !important; +} +.com { color: #999 !important; } +.ignore-none { color: #999; font-weight: normal; } + +.wrapper { + min-height: 100%; + height: auto !important; + height: 100%; + margin: 0 auto -48px; +} +.footer, .push { + height: 48px; +} diff --git a/coverage/lcov-report/block-navigation.js b/coverage/lcov-report/block-navigation.js new file mode 100644 index 00000000..cc121302 --- /dev/null +++ b/coverage/lcov-report/block-navigation.js @@ -0,0 +1,87 @@ +/* eslint-disable */ +var jumpToCode = (function init() { + // Classes of code we would like to highlight in the file view + var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; + + // Elements to highlight in the file listing view + var fileListingElements = ['td.pct.low']; + + // We don't want to select elements that are direct descendants of another match + var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` + + // Selecter that finds elements on the page to which we can jump + var selector = + fileListingElements.join(', ') + + ', ' + + notSelector + + missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` + + // The NodeList of matching elements + var missingCoverageElements = document.querySelectorAll(selector); + + var currentIndex; + + function toggleClass(index) { + missingCoverageElements + .item(currentIndex) + .classList.remove('highlighted'); + missingCoverageElements.item(index).classList.add('highlighted'); + } + + function makeCurrent(index) { + toggleClass(index); + currentIndex = index; + missingCoverageElements.item(index).scrollIntoView({ + behavior: 'smooth', + block: 'center', + inline: 'center' + }); + } + + function goToPrevious() { + var nextIndex = 0; + if (typeof currentIndex !== 'number' || currentIndex === 0) { + nextIndex = missingCoverageElements.length - 1; + } else if (missingCoverageElements.length > 1) { + nextIndex = currentIndex - 1; + } + + makeCurrent(nextIndex); + } + + function goToNext() { + var nextIndex = 0; + + if ( + typeof currentIndex === 'number' && + currentIndex < missingCoverageElements.length - 1 + ) { + nextIndex = currentIndex + 1; + } + + makeCurrent(nextIndex); + } + + return function jump(event) { + if ( + document.getElementById('fileSearch') === document.activeElement && + document.activeElement != null + ) { + // if we're currently focused on the search input, we don't want to navigate + return; + } + + switch (event.which) { + case 78: // n + case 74: // j + goToNext(); + break; + case 66: // b + case 75: // k + case 80: // p + goToPrevious(); + break; + } + }; +})(); +window.addEventListener('keydown', jumpToCode); diff --git a/coverage/lcov-report/command/index.html b/coverage/lcov-report/command/index.html new file mode 100644 index 00000000..6e3f5816 --- /dev/null +++ b/coverage/lcov-report/command/index.html @@ -0,0 +1,116 @@ + + + + + + Code coverage report for command + + + + + + + + + +
+
+

All files command

+
+ +
+ 66.79% + Statements + 179/268 +
+ + +
+ 100% + Branches + 37/37 +
+ + +
+ 87.5% + Functions + 14/16 +
+ + +
+ 66.79% + Lines + 179/268 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
module-handler.ts +
+
66.79%179/268100%37/3787.5%14/1666.79%179/268
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/command/module-handler.ts.html b/coverage/lcov-report/command/module-handler.ts.html new file mode 100644 index 00000000..633cd3a1 --- /dev/null +++ b/coverage/lcov-report/command/module-handler.ts.html @@ -0,0 +1,889 @@ + + + + + + Code coverage report for command/module-handler.ts + + + + + + + + + +
+
+

All files / command module-handler.ts

+
+ +
+ 66.79% + Statements + 179/268 +
+ + +
+ 100% + Branches + 37/37 +
+ + +
+ 87.5% + Functions + 14/16 +
+ + +
+ 66.79% + Lines + 179/268 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +2691x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +80x +80x +80x +80x +80x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +87x +87x +87x +1x +1x +1x +1x +1x +1x +1x +227x +60x +60x +167x +167x +167x +167x +167x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1923x +1923x +1923x +1x +1x +1756x +1756x +1756x +1x +1x +80x +80x +80x +1x +1x +1913x +1913x +1913x +1x +1x +  +  +  +1x +1x +6460x +6460x +6460x +1x +1x +1465x +1465x +1465x +1x +1x +300x +300x +300x +1x +1x +1x +1x +1x +1x +1x +1x +8x +8x +7x +7x +8x +8x +1x +1x +1389x +85x +85x +85x +80x +85x +30x +6x +6x +6x +24x +24x +24x +1389x +1389x +1x +1x +85x +31x +31x +85x +1x +1x +1x +1x +1x +1x +1x +1x +85x +85x +78x +78x +7x +7x +7x +7x +5x +3x +3x +3x +1x +1x +2x +2x +2x +2x +4x +10x +2x +2x +2x +2x +85x +1x + 
import path = require("path");
+import * as fs from "fs";
+import { Command, CommandOptions, OptionValues } from "commander";
+import { Context } from "./cli-context";
+import { GracefulError, logger } from "../utils/logger";
+import { FeatureFlagService } from "../feature-flag/feature-flag.service";
+ 
+export abstract class IModule {
+    public abstract register(context: Context, commandConfig: Configurator): void;
+}
+ 
+export type IModuleConstructor = new () => IModule;
+ 
+export class ModuleHandler {
+    public configurator: Configurator;
+ 
+    constructor(
+        public program: Command,
+        public context: Context
+    ) {
+        this.configurator = new Configurator(this.program, this.context);
+    }
+ 
+    // Store registered module instances if needed later
+    public registeredModules: IModule[] = [];
+ 
+    /**
+     * Discovers modules in the specified directory, imports them,
+     * instantiates the default exported class, and calls its register method.
+     *
+     * @param {any} rootPath - __dirname when invoked from the main entry file
+     * @param devMode        - Use uncompiled modules for development debug mode
+     */
+    public discoverAndRegisterModules(rootPath: string, devMode: boolean = false): void {
+        const modulesDirPath = path.resolve(rootPath, "commands");
+
+        try {
+            const moduleFolders = fs.readdirSync(modulesDirPath, { withFileTypes: true });
+
+            for (const dirent of moduleFolders) {
+                if (dirent.isDirectory()) {
+                    const moduleFolderName = dirent.name;
+
+                    const moduleFileName = devMode ? "module.ts" : "module.js";
+
+                    // Calculate path relative to *this file's location in dist*
+                    let potentialModuleJsPath: any;
+                    potentialModuleJsPath = path.resolve(
+                        rootPath,
+                        "commands",
+                        moduleFolderName,
+                        moduleFileName // Look for the compiled JS file
+                    );
+                    try {
+                        fs.accessSync(potentialModuleJsPath);
+                    } catch (err) {
+                        // apparently the file does not exist of is not accessible
+                        potentialModuleJsPath = null;
+                    }
+
+                    if (!potentialModuleJsPath) {
+                        logger.debug(
+                            `Module folder ${moduleFolderName} does not contain a valid entry point and is skipped.`
+                        );
+                    } else {
+                        // Check if the compiled JS file exists
+                        try {
+                            logger.debug(`Found potential module definition: ${potentialModuleJsPath}`);
+
+                            // Dynamically require the module
+                            const requiredModule = require(potentialModuleJsPath);
+
+                            // With 'export =' or 'module.exports =', the required value *is* the class
+                            const ModuleClass = requiredModule as IModuleConstructor; // Cast for TS check
+
+                            // Basic check: Is it a class (function)?
+                            if (typeof ModuleClass === "function" && ModuleClass.prototype) {
+                                const moduleInstance: IModule = new ModuleClass(); // Instantiate
+
+                                // Check if the instance has the register method
+                                if (typeof moduleInstance.register === "function") {
+                                    logger.debug(`Registering module: ${moduleFolderName}`);
+                                    // Call register - can still be async even if require() is sync
+                                    moduleInstance.register(this.context, this.configurator);
+                                    this.registeredModules.push(moduleInstance);
+                                } else {
+                                    logger.warn(`Module ${moduleFolderName} export does not have a 'register' method.`);
+                                }
+                            } else {
+                                logger.warn(`Module ${moduleFolderName} export is not a class/constructor function.`);
+                            }
+                        } catch (error: any) {
+                            if (error.code === "ENOENT") {
+                                // Compiled module.js not found, maybe folder doesn't contain a valid module
+                                logger.warn(
+                                    `Directory ${moduleFolderName} does not contain a compiled module.js file.`
+                                );
+                            } else if (error.code === "MODULE_NOT_FOUND") {
+                                logger.debug("Error details", error);
+                                logger.warn(
+                                    `Could not require module ${moduleFolderName}. Check dependencies or compilation. Path: ${potentialModuleJsPath}`
+                                );
+                            } else {
+                                logger.error(`Error processing module in ${moduleFolderName}:`, error);
+                            }
+                        }
+                    }
+                }
+            }
+        } catch (error: any) {
+            if (error.code === "ENOENT") {
+                logger.error(
+                    `Modules directory not found relative to JS output: ${path.resolve(path.dirname(__filename), "commands")}`
+                );
+            } else {
+                logger.error("Failed to read modules directory:", error);
+            }
+        }
+        logger.debug(`Module discovery complete. ${this.registeredModules.length} modules registered.`);
+    }
+}
+ 
+type CommandHandler = (context: Context, command: Command, options: OptionValues) => Promise<void>;
+ 
+/**
+ * Allows the creation of root level commands.
+ */
+export class Configurator {
+    public rootCommandMap = new Map<string, CommandConfig>();
+ 
+    constructor(
+        private program: Command,
+        private ctx: Context
+    ) {}
+ 
+    /**
+     * Get or create a root level command.
+     * @param name
+     * @returns
+     */
+    public command(name: string): CommandConfig {
+        if (this.rootCommandMap.has(name)) {
+            return this.rootCommandMap.get(name);
+        }
+        const cmd = this.program.command(name);
+        const cmdConfig = new CommandConfig(cmd, this.ctx);
+        this.rootCommandMap.set(name, cmdConfig);
+        return cmdConfig;
+    }
+}
+ 
+/**
+ * Delegate wrapper around the Command object, to simply change the way the program is
+ * executed.
+ */
+export class CommandConfig {
+    private deprecationMessage: string;
+ 
+    constructor(
+        private cmd: Command,
+        private ctx: Context
+    ) {}
+ 
+    public command(nameAndArgs: string, opts?: CommandOptions): CommandConfig {
+        return new CommandConfig(this.cmd.command(nameAndArgs, opts), this.ctx)
+            .option("-p, --profile <profile>", "Profile which you want to use");
+    }
+ 
+    public alias(alias: string): CommandConfig {
+        this.cmd.alias(alias);
+        return this;
+    }
+ 
+    public description(description: string): CommandConfig {
+        this.cmd.description(description);
+        return this;
+    }
+ 
+    public argument(name: string, description?: string, defaultValue?: unknown): CommandConfig {
+        this.cmd.argument(name, description, defaultValue);
+        return this;
+    }
+ 
+    public option(flags: string, description?: string, defaultValue?: string | boolean | string[]): CommandConfig {
+        this.cmd.option(flags, description, defaultValue);
+        return this;
+    }
+ 
+    public requiredOption(flags: string, description?: string, defaultValue?: string | boolean | string[]): CommandConfig {
+        this.cmd.requiredOption(flags, description, defaultValue);
+        return this;
+    }
+ 
+    public deprecationNotice(deprecationMessage: string): CommandConfig {
+        this.deprecationMessage = deprecationMessage;
+        return this;
+    }
+ 
+    /**
+     * Marks a command as early access (non-GA). Purely internal — it is not shown
+     * in help. When a feature key is provided, the command is gated at run time:
+     * before it executes, the CLI checks whether that backend feature flag is
+     * enabled for the team, and stops with a clear message if it is not.
+     */
+    public earlyAccess(featureKey?: string): CommandConfig {
+        (this.cmd as any).isEarlyAccess = true;
+        if (featureKey) {
+            (this.cmd as any).earlyAccessFeatureKey = featureKey;
+        }
+        return this;
+    }
+ 
+    public action(handler: CommandHandler): void {
+        this.cmd.action(async (): Promise<void> => {
+            try {
+                this.printDeprecationNoticeIfDeprecated();
+                await this.checkEarlyAccessFeatureFlag();
+                await handler(this.ctx, this.cmd, this.cmd.optsWithGlobals());
+            } catch (error) {
+                if (error instanceof GracefulError) {
+                    logger.error(error.message);
+                    return;
+                }
+                logger.error(`An unexpected error occured executing a command: ${error}`);
+                process.exitCode = 1;
+            }
+        });
+    }
+ 
+    private printDeprecationNoticeIfDeprecated(): void {
+        if (this.deprecationMessage) {
+            logger.warn("⚠️  [DEPRECATION NOTICE] \n" + this.deprecationMessage);
+        }
+    }
+ 
+    /**
+     * For early-access commands that carry a feature key, verify the backend
+     * feature flag is enabled for the team before the command runs. Throws a
+     * GracefulError with a clear message when it is not enabled (or cannot be
+     * verified). Commands with no feature key are left untouched.
+     */
+    private async checkEarlyAccessFeatureFlag(): Promise<void> {
+        const featureKey = (this.cmd as any).earlyAccessFeatureKey;
+        if (!featureKey) {
+            return;
+        }
+ 
+        let enabled: boolean;
+        try {
+            enabled = await new FeatureFlagService(this.ctx).isEnabled(featureKey);
+        } catch (error) {
+            // With no profile, surface the standard "no profile provided" error
+            // rather than masking it with an early-access message.
+            if (!this.ctx.profile) {
+                throw error;
+            }
+            throw new GracefulError(
+                `Could not verify whether '${this.cmd.name()}' is enabled for your team. Please try again later or contact support.`
+            );
+        }
+ 
+        if (!enabled) {
+            throw new GracefulError(
+                `'${this.cmd.name()}' is not enabled for your team. Contact support to request access.`
+            );
+        }
+    }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/favicon.png b/coverage/lcov-report/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..c1525b811a167671e9de1fa78aab9f5c0b61cef7 GIT binary patch literal 445 zcmV;u0Yd(XP))rP{nL}Ln%S7`m{0DjX9TLF* zFCb$4Oi7vyLOydb!7n&^ItCzb-%BoB`=x@N2jll2Nj`kauio%aw_@fe&*}LqlFT43 z8doAAe))z_%=P%v^@JHp3Hjhj^6*Kr_h|g_Gr?ZAa&y>wxHE99Gk>A)2MplWz2xdG zy8VD2J|Uf#EAw*bo5O*PO_}X2Tob{%bUoO2G~T`@%S6qPyc}VkhV}UifBuRk>%5v( z)x7B{I~z*k<7dv#5tC+m{km(D087J4O%+<<;K|qwefb6@GSX45wCK}Sn*> + + + + Code coverage report for feature-flag/early-access-features.ts + + + + + + + + + +
+
+

All files / feature-flag early-access-features.ts

+
+ +
+ 100% + Statements + 13/13 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 13/13 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +141x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x + 
/**
+ * Backend feature-flag keys for early-access commands.
+ *
+ * These mirror the backend `FeatureToggle` keys and are the values passed to
+ * `CommandConfig.earlyAccess(...)`. Keeping them here gives a single place to
+ * see every early-access feature key even though the wiring lives on the
+ * individual commands.
+ */
+export const EarlyAccessFeature = {
+    BRANCHING: "pacman.branching",
+} as const;
+ 
+export type EarlyAccessFeatureKey = (typeof EarlyAccessFeature)[keyof typeof EarlyAccessFeature];
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/feature-flag/feature-flag.service.ts.html b/coverage/lcov-report/feature-flag/feature-flag.service.ts.html new file mode 100644 index 00000000..c802b434 --- /dev/null +++ b/coverage/lcov-report/feature-flag/feature-flag.service.ts.html @@ -0,0 +1,187 @@ + + + + + + Code coverage report for feature-flag/feature-flag.service.ts + + + + + + + + + +
+
+

All files / feature-flag feature-flag.service.ts

+
+ +
+ 100% + Statements + 34/34 +
+ + +
+ 100% + Branches + 10/10 +
+ + +
+ 100% + Functions + 3/3 +
+ + +
+ 100% + Lines + 34/34 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +351x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +13x +13x +1x +1x +13x +13x +13x +1x + 
import { Context } from "../command/cli-context";
+import { HttpClient } from "../http/http-client";
+ 
+/**
+ * A backend ("paid") feature flag as returned by the team-features endpoint.
+ * Only the key is needed here — presence in the list means the flag is enabled
+ * for the calling team.
+ */
+interface TeamFeature {
+    key: string;
+}
+ 
+/**
+ * Queries whether a backend feature flag is enabled for the current team.
+ *
+ * Uses the same endpoint the web frontend relies on to resolve backend/per-team
+ * ("paid") feature flags: `GET /api/team/features` returns the list of flags
+ * enabled for the team behind the profile's token. A flag is considered enabled
+ * when an entry with a matching key is present in that list.
+ */
+export class FeatureFlagService {
+    private static readonly TEAM_FEATURES_URL = "/api/team/features";
+ 
+    private httpClient: () => HttpClient;
+ 
+    constructor(context: Context) {
+        this.httpClient = () => context.httpClient;
+    }
+ 
+    public async isEnabled(featureKey: string): Promise<boolean> {
+        const features: TeamFeature[] = await this.httpClient().get(FeatureFlagService.TEAM_FEATURES_URL);
+        return Array.isArray(features) && features.some(feature => feature?.key === featureKey);
+    }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/feature-flag/index.html b/coverage/lcov-report/feature-flag/index.html new file mode 100644 index 00000000..7409122d --- /dev/null +++ b/coverage/lcov-report/feature-flag/index.html @@ -0,0 +1,131 @@ + + + + + + Code coverage report for feature-flag + + + + + + + + + +
+
+

All files feature-flag

+
+ +
+ 100% + Statements + 47/47 +
+ + +
+ 100% + Branches + 10/10 +
+ + +
+ 100% + Functions + 3/3 +
+ + +
+ 100% + Lines + 47/47 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
early-access-features.ts +
+
100%13/13100%0/0100%0/0100%13/13
feature-flag.service.ts +
+
100%34/34100%10/10100%3/3100%34/34
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/index.html b/coverage/lcov-report/index.html new file mode 100644 index 00000000..6b4239b2 --- /dev/null +++ b/coverage/lcov-report/index.html @@ -0,0 +1,131 @@ + + + + + + Code coverage report for All files + + + + + + + + + +
+
+

All files

+
+ +
+ 71.74% + Statements + 226/315 +
+ + +
+ 100% + Branches + 47/47 +
+ + +
+ 89.47% + Functions + 17/19 +
+ + +
+ 71.74% + Lines + 226/315 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
command +
+
66.79%179/268100%37/3787.5%14/1666.79%179/268
feature-flag +
+
100%47/47100%10/10100%3/3100%47/47
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/prettify.css b/coverage/lcov-report/prettify.css new file mode 100644 index 00000000..b317a7cd --- /dev/null +++ b/coverage/lcov-report/prettify.css @@ -0,0 +1 @@ +.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} diff --git a/coverage/lcov-report/prettify.js b/coverage/lcov-report/prettify.js new file mode 100644 index 00000000..b3225238 --- /dev/null +++ b/coverage/lcov-report/prettify.js @@ -0,0 +1,2 @@ +/* eslint-disable */ +window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); diff --git a/coverage/lcov-report/sort-arrow-sprite.png b/coverage/lcov-report/sort-arrow-sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..6ed68316eb3f65dec9063332d2f69bf3093bbfab GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^>_9Bd!3HEZxJ@+%Qh}Z>jv*C{$p!i!8j}?a+@3A= zIAGwzjijN=FBi!|L1t?LM;Q;gkwn>2cAy-KV{dn nf0J1DIvEHQu*n~6U}x}qyky7vi4|9XhBJ7&`njxgN@xNA8m%nc literal 0 HcmV?d00001 diff --git a/coverage/lcov-report/sorter.js b/coverage/lcov-report/sorter.js new file mode 100644 index 00000000..2bb296a8 --- /dev/null +++ b/coverage/lcov-report/sorter.js @@ -0,0 +1,196 @@ +/* eslint-disable */ +var addSorting = (function() { + 'use strict'; + var cols, + currentSort = { + index: 0, + desc: false + }; + + // returns the summary table element + function getTable() { + return document.querySelector('.coverage-summary'); + } + // returns the thead element of the summary table + function getTableHeader() { + return getTable().querySelector('thead tr'); + } + // returns the tbody element of the summary table + function getTableBody() { + return getTable().querySelector('tbody'); + } + // returns the th element for nth column + function getNthColumn(n) { + return getTableHeader().querySelectorAll('th')[n]; + } + + function onFilterInput() { + const searchValue = document.getElementById('fileSearch').value; + const rows = document.getElementsByTagName('tbody')[0].children; + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + if ( + row.textContent + .toLowerCase() + .includes(searchValue.toLowerCase()) + ) { + row.style.display = ''; + } else { + row.style.display = 'none'; + } + } + } + + // loads the search box + function addSearchBox() { + var template = document.getElementById('filterTemplate'); + var templateClone = template.content.cloneNode(true); + templateClone.getElementById('fileSearch').oninput = onFilterInput; + template.parentElement.appendChild(templateClone); + } + + // loads all columns + function loadColumns() { + var colNodes = getTableHeader().querySelectorAll('th'), + colNode, + cols = [], + col, + i; + + for (i = 0; i < colNodes.length; i += 1) { + colNode = colNodes[i]; + col = { + key: colNode.getAttribute('data-col'), + sortable: !colNode.getAttribute('data-nosort'), + type: colNode.getAttribute('data-type') || 'string' + }; + cols.push(col); + if (col.sortable) { + col.defaultDescSort = col.type === 'number'; + colNode.innerHTML = + colNode.innerHTML + ''; + } + } + return cols; + } + // attaches a data attribute to every tr element with an object + // of data values keyed by column name + function loadRowData(tableRow) { + var tableCols = tableRow.querySelectorAll('td'), + colNode, + col, + data = {}, + i, + val; + for (i = 0; i < tableCols.length; i += 1) { + colNode = tableCols[i]; + col = cols[i]; + val = colNode.getAttribute('data-value'); + if (col.type === 'number') { + val = Number(val); + } + data[col.key] = val; + } + return data; + } + // loads all row data + function loadData() { + var rows = getTableBody().querySelectorAll('tr'), + i; + + for (i = 0; i < rows.length; i += 1) { + rows[i].data = loadRowData(rows[i]); + } + } + // sorts the table using the data for the ith column + function sortByIndex(index, desc) { + var key = cols[index].key, + sorter = function(a, b) { + a = a.data[key]; + b = b.data[key]; + return a < b ? -1 : a > b ? 1 : 0; + }, + finalSorter = sorter, + tableBody = document.querySelector('.coverage-summary tbody'), + rowNodes = tableBody.querySelectorAll('tr'), + rows = [], + i; + + if (desc) { + finalSorter = function(a, b) { + return -1 * sorter(a, b); + }; + } + + for (i = 0; i < rowNodes.length; i += 1) { + rows.push(rowNodes[i]); + tableBody.removeChild(rowNodes[i]); + } + + rows.sort(finalSorter); + + for (i = 0; i < rows.length; i += 1) { + tableBody.appendChild(rows[i]); + } + } + // removes sort indicators for current column being sorted + function removeSortIndicators() { + var col = getNthColumn(currentSort.index), + cls = col.className; + + cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); + col.className = cls; + } + // adds sort indicators for current column being sorted + function addSortIndicators() { + getNthColumn(currentSort.index).className += currentSort.desc + ? ' sorted-desc' + : ' sorted'; + } + // adds event listeners for all sorter widgets + function enableUI() { + var i, + el, + ithSorter = function ithSorter(i) { + var col = cols[i]; + + return function() { + var desc = col.defaultDescSort; + + if (currentSort.index === i) { + desc = !currentSort.desc; + } + sortByIndex(i, desc); + removeSortIndicators(); + currentSort.index = i; + currentSort.desc = desc; + addSortIndicators(); + }; + }; + for (i = 0; i < cols.length; i += 1) { + if (cols[i].sortable) { + // add the click event handler on the th so users + // dont have to click on those tiny arrows + el = getNthColumn(i).querySelector('.sorter').parentElement; + if (el.addEventListener) { + el.addEventListener('click', ithSorter(i)); + } else { + el.attachEvent('onclick', ithSorter(i)); + } + } + } + } + // adds sorting functionality to the UI + return function() { + if (!getTable()) { + return; + } + cols = loadColumns(); + loadData(); + addSearchBox(); + addSortIndicators(); + enableUI(); + }; +})(); + +window.addEventListener('load', addSorting); diff --git a/coverage/lcov.info b/coverage/lcov.info new file mode 100644 index 00000000..018ef678 --- /dev/null +++ b/coverage/lcov.info @@ -0,0 +1,427 @@ +TN: +SF:src/core/command/module-handler.ts +FN:17,ModuleHandler +FN:34,discoverAndRegisterModules +FN:131,Configurator +FN:141,command +FN:159,CommandConfig +FN:164,command +FN:169,alias +FN:174,description +FN:179,argument +FN:184,option +FN:189,requiredOption +FN:194,deprecationNotice +FN:205,earlyAccess +FN:213,action +FN:230,printDeprecationNoticeIfDeprecated +FN:242,checkEarlyAccessFeatureFlag +FNF:16 +FNH:14 +FNDA:80,ModuleHandler +FNDA:0,discoverAndRegisterModules +FNDA:87,Configurator +FNDA:227,command +FNDA:1923,CommandConfig +FNDA:1756,command +FNDA:80,alias +FNDA:1913,description +FNDA:0,argument +FNDA:6460,option +FNDA:1465,requiredOption +FNDA:300,deprecationNotice +FNDA:8,earlyAccess +FNDA:1389,action +FNDA:85,printDeprecationNoticeIfDeprecated +FNDA:85,checkEarlyAccessFeatureFlag +DA:1,1 +DA:2,1 +DA:3,1 +DA:4,1 +DA:5,1 +DA:6,1 +DA:7,1 +DA:8,1 +DA:9,1 +DA:10,1 +DA:11,1 +DA:12,1 +DA:13,1 +DA:14,1 +DA:15,1 +DA:16,1 +DA:17,1 +DA:18,80 +DA:19,80 +DA:20,80 +DA:21,80 +DA:22,80 +DA:23,1 +DA:24,1 +DA:25,1 +DA:26,1 +DA:27,1 +DA:28,1 +DA:29,1 +DA:30,1 +DA:31,1 +DA:32,1 +DA:33,1 +DA:34,1 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:43,0 +DA:44,0 +DA:45,0 +DA:46,0 +DA:47,0 +DA:48,0 +DA:49,0 +DA:50,0 +DA:51,0 +DA:52,0 +DA:53,0 +DA:54,0 +DA:55,0 +DA:56,0 +DA:57,0 +DA:58,0 +DA:59,0 +DA:60,0 +DA:61,0 +DA:62,0 +DA:63,0 +DA:64,0 +DA:65,0 +DA:66,0 +DA:67,0 +DA:68,0 +DA:69,0 +DA:70,0 +DA:71,0 +DA:72,0 +DA:73,0 +DA:74,0 +DA:75,0 +DA:76,0 +DA:77,0 +DA:78,0 +DA:79,0 +DA:80,0 +DA:81,0 +DA:82,0 +DA:83,0 +DA:84,0 +DA:85,0 +DA:86,0 +DA:87,0 +DA:88,0 +DA:89,0 +DA:90,0 +DA:91,0 +DA:92,0 +DA:93,0 +DA:94,0 +DA:95,0 +DA:96,0 +DA:97,0 +DA:98,0 +DA:99,0 +DA:100,0 +DA:101,0 +DA:102,0 +DA:103,0 +DA:104,0 +DA:105,0 +DA:106,0 +DA:107,0 +DA:108,0 +DA:109,0 +DA:110,0 +DA:111,0 +DA:112,0 +DA:113,0 +DA:114,0 +DA:115,0 +DA:116,0 +DA:117,0 +DA:118,0 +DA:119,0 +DA:120,0 +DA:121,1 +DA:122,1 +DA:123,1 +DA:124,1 +DA:125,1 +DA:126,1 +DA:127,1 +DA:128,1 +DA:129,1 +DA:130,1 +DA:131,1 +DA:132,87 +DA:133,87 +DA:134,87 +DA:135,1 +DA:136,1 +DA:137,1 +DA:138,1 +DA:139,1 +DA:140,1 +DA:141,1 +DA:142,227 +DA:143,60 +DA:144,60 +DA:145,167 +DA:146,167 +DA:147,167 +DA:148,167 +DA:149,167 +DA:150,1 +DA:151,1 +DA:152,1 +DA:153,1 +DA:154,1 +DA:155,1 +DA:156,1 +DA:157,1 +DA:158,1 +DA:159,1 +DA:160,1923 +DA:161,1923 +DA:162,1923 +DA:163,1 +DA:164,1 +DA:165,1756 +DA:166,1756 +DA:167,1756 +DA:168,1 +DA:169,1 +DA:170,80 +DA:171,80 +DA:172,80 +DA:173,1 +DA:174,1 +DA:175,1913 +DA:176,1913 +DA:177,1913 +DA:178,1 +DA:179,1 +DA:180,0 +DA:181,0 +DA:182,0 +DA:183,1 +DA:184,1 +DA:185,6460 +DA:186,6460 +DA:187,6460 +DA:188,1 +DA:189,1 +DA:190,1465 +DA:191,1465 +DA:192,1465 +DA:193,1 +DA:194,1 +DA:195,300 +DA:196,300 +DA:197,300 +DA:198,1 +DA:199,1 +DA:200,1 +DA:201,1 +DA:202,1 +DA:203,1 +DA:204,1 +DA:205,1 +DA:206,8 +DA:207,8 +DA:208,7 +DA:209,7 +DA:210,8 +DA:211,8 +DA:212,1 +DA:213,1 +DA:214,1389 +DA:215,85 +DA:216,85 +DA:217,85 +DA:218,80 +DA:219,85 +DA:220,30 +DA:221,6 +DA:222,6 +DA:223,6 +DA:224,24 +DA:225,24 +DA:226,24 +DA:227,1389 +DA:228,1389 +DA:229,1 +DA:230,1 +DA:231,85 +DA:232,31 +DA:233,31 +DA:234,85 +DA:235,1 +DA:236,1 +DA:237,1 +DA:238,1 +DA:239,1 +DA:240,1 +DA:241,1 +DA:242,1 +DA:243,85 +DA:244,85 +DA:245,78 +DA:246,78 +DA:247,7 +DA:248,7 +DA:249,7 +DA:250,7 +DA:251,5 +DA:252,3 +DA:253,3 +DA:254,3 +DA:255,1 +DA:256,1 +DA:257,2 +DA:258,2 +DA:259,2 +DA:260,2 +DA:261,4 +DA:262,10 +DA:263,2 +DA:264,2 +DA:265,2 +DA:266,2 +DA:267,85 +DA:268,1 +LF:268 +LH:179 +BRDA:17,0,0,80 +BRDA:131,1,0,87 +BRDA:141,2,0,227 +BRDA:142,3,0,60 +BRDA:145,4,0,167 +BRDA:159,5,0,1923 +BRDA:164,6,0,1756 +BRDA:169,7,0,80 +BRDA:174,8,0,1913 +BRDA:184,9,0,6460 +BRDA:189,10,0,1465 +BRDA:194,11,0,300 +BRDA:205,12,0,8 +BRDA:207,13,0,7 +BRDA:213,14,0,1389 +BRDA:214,15,0,85 +BRDA:214,16,0,85 +BRDA:218,17,0,83 +BRDA:218,18,0,80 +BRDA:219,19,0,55 +BRDA:219,20,0,30 +BRDA:220,21,0,29 +BRDA:220,22,0,6 +BRDA:224,23,0,24 +BRDA:230,24,0,85 +BRDA:231,25,0,31 +BRDA:242,26,0,85 +BRDA:244,27,0,78 +BRDA:247,28,0,10 +BRDA:247,29,0,7 +BRDA:251,30,0,5 +BRDA:251,31,0,4 +BRDA:251,32,0,3 +BRDA:254,33,0,2 +BRDA:254,34,0,1 +BRDA:261,35,0,4 +BRDA:262,36,0,2 +BRF:37 +BRH:37 +end_of_record +TN: +SF:src/core/feature-flag/early-access-features.ts +FNF:0 +FNH:0 +DA:1,1 +DA:2,1 +DA:3,1 +DA:4,1 +DA:5,1 +DA:6,1 +DA:7,1 +DA:8,1 +DA:9,1 +DA:10,1 +DA:11,1 +DA:12,1 +DA:13,1 +LF:13 +LH:13 +BRF:0 +BRH:0 +end_of_record +TN: +SF:src/core/feature-flag/feature-flag.service.ts +FN:26,FeatureFlagService +FN:27,FeatureFlagService.httpClient +FN:30,isEnabled +FNF:3 +FNH:3 +FNDA:13,FeatureFlagService +FNDA:13,FeatureFlagService.httpClient +FNDA:13,isEnabled +DA:1,1 +DA:2,1 +DA:3,1 +DA:4,1 +DA:5,1 +DA:6,1 +DA:7,1 +DA:8,1 +DA:9,1 +DA:10,1 +DA:11,1 +DA:12,1 +DA:13,1 +DA:14,1 +DA:15,1 +DA:16,1 +DA:17,1 +DA:18,1 +DA:19,1 +DA:20,1 +DA:21,1 +DA:22,1 +DA:23,1 +DA:24,1 +DA:25,1 +DA:26,1 +DA:27,13 +DA:28,13 +DA:29,1 +DA:30,1 +DA:31,13 +DA:32,13 +DA:33,13 +DA:34,1 +LF:34 +LH:34 +BRDA:26,0,0,13 +BRDA:27,1,0,13 +BRDA:30,2,0,13 +BRDA:32,3,0,10 +BRDA:32,4,0,9 +BRDA:32,5,0,8 +BRDA:32,6,0,6 +BRDA:32,7,0,5 +BRDA:32,8,0,1 +BRDA:32,9,0,5 +BRF:10 +BRH:10 +end_of_record diff --git a/coverage/prettify.css b/coverage/prettify.css new file mode 100644 index 00000000..b317a7cd --- /dev/null +++ b/coverage/prettify.css @@ -0,0 +1 @@ +.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} diff --git a/coverage/prettify.js b/coverage/prettify.js new file mode 100644 index 00000000..b3225238 --- /dev/null +++ b/coverage/prettify.js @@ -0,0 +1,2 @@ +/* eslint-disable */ +window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); diff --git a/coverage/sort-arrow-sprite.png b/coverage/sort-arrow-sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..6ed68316eb3f65dec9063332d2f69bf3093bbfab GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^>_9Bd!3HEZxJ@+%Qh}Z>jv*C{$p!i!8j}?a+@3A= zIAGwzjijN=FBi!|L1t?LM;Q;gkwn>2cAy-KV{dn nf0J1DIvEHQu*n~6U}x}qyky7vi4|9XhBJ7&`njxgN@xNA8m%nc literal 0 HcmV?d00001 diff --git a/coverage/sorter.js b/coverage/sorter.js new file mode 100644 index 00000000..2bb296a8 --- /dev/null +++ b/coverage/sorter.js @@ -0,0 +1,196 @@ +/* eslint-disable */ +var addSorting = (function() { + 'use strict'; + var cols, + currentSort = { + index: 0, + desc: false + }; + + // returns the summary table element + function getTable() { + return document.querySelector('.coverage-summary'); + } + // returns the thead element of the summary table + function getTableHeader() { + return getTable().querySelector('thead tr'); + } + // returns the tbody element of the summary table + function getTableBody() { + return getTable().querySelector('tbody'); + } + // returns the th element for nth column + function getNthColumn(n) { + return getTableHeader().querySelectorAll('th')[n]; + } + + function onFilterInput() { + const searchValue = document.getElementById('fileSearch').value; + const rows = document.getElementsByTagName('tbody')[0].children; + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + if ( + row.textContent + .toLowerCase() + .includes(searchValue.toLowerCase()) + ) { + row.style.display = ''; + } else { + row.style.display = 'none'; + } + } + } + + // loads the search box + function addSearchBox() { + var template = document.getElementById('filterTemplate'); + var templateClone = template.content.cloneNode(true); + templateClone.getElementById('fileSearch').oninput = onFilterInput; + template.parentElement.appendChild(templateClone); + } + + // loads all columns + function loadColumns() { + var colNodes = getTableHeader().querySelectorAll('th'), + colNode, + cols = [], + col, + i; + + for (i = 0; i < colNodes.length; i += 1) { + colNode = colNodes[i]; + col = { + key: colNode.getAttribute('data-col'), + sortable: !colNode.getAttribute('data-nosort'), + type: colNode.getAttribute('data-type') || 'string' + }; + cols.push(col); + if (col.sortable) { + col.defaultDescSort = col.type === 'number'; + colNode.innerHTML = + colNode.innerHTML + ''; + } + } + return cols; + } + // attaches a data attribute to every tr element with an object + // of data values keyed by column name + function loadRowData(tableRow) { + var tableCols = tableRow.querySelectorAll('td'), + colNode, + col, + data = {}, + i, + val; + for (i = 0; i < tableCols.length; i += 1) { + colNode = tableCols[i]; + col = cols[i]; + val = colNode.getAttribute('data-value'); + if (col.type === 'number') { + val = Number(val); + } + data[col.key] = val; + } + return data; + } + // loads all row data + function loadData() { + var rows = getTableBody().querySelectorAll('tr'), + i; + + for (i = 0; i < rows.length; i += 1) { + rows[i].data = loadRowData(rows[i]); + } + } + // sorts the table using the data for the ith column + function sortByIndex(index, desc) { + var key = cols[index].key, + sorter = function(a, b) { + a = a.data[key]; + b = b.data[key]; + return a < b ? -1 : a > b ? 1 : 0; + }, + finalSorter = sorter, + tableBody = document.querySelector('.coverage-summary tbody'), + rowNodes = tableBody.querySelectorAll('tr'), + rows = [], + i; + + if (desc) { + finalSorter = function(a, b) { + return -1 * sorter(a, b); + }; + } + + for (i = 0; i < rowNodes.length; i += 1) { + rows.push(rowNodes[i]); + tableBody.removeChild(rowNodes[i]); + } + + rows.sort(finalSorter); + + for (i = 0; i < rows.length; i += 1) { + tableBody.appendChild(rows[i]); + } + } + // removes sort indicators for current column being sorted + function removeSortIndicators() { + var col = getNthColumn(currentSort.index), + cls = col.className; + + cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); + col.className = cls; + } + // adds sort indicators for current column being sorted + function addSortIndicators() { + getNthColumn(currentSort.index).className += currentSort.desc + ? ' sorted-desc' + : ' sorted'; + } + // adds event listeners for all sorter widgets + function enableUI() { + var i, + el, + ithSorter = function ithSorter(i) { + var col = cols[i]; + + return function() { + var desc = col.defaultDescSort; + + if (currentSort.index === i) { + desc = !currentSort.desc; + } + sortByIndex(i, desc); + removeSortIndicators(); + currentSort.index = i; + currentSort.desc = desc; + addSortIndicators(); + }; + }; + for (i = 0; i < cols.length; i += 1) { + if (cols[i].sortable) { + // add the click event handler on the th so users + // dont have to click on those tiny arrows + el = getNthColumn(i).querySelector('.sorter').parentElement; + if (el.addEventListener) { + el.addEventListener('click', ithSorter(i)); + } else { + el.attachEvent('onclick', ithSorter(i)); + } + } + } + } + // adds sorting functionality to the UI + return function() { + if (!getTable()) { + return; + } + cols = loadColumns(); + loadData(); + addSearchBox(); + addSortIndicators(); + enableUI(); + }; +})(); + +window.addEventListener('load', addSorting); diff --git a/tests/core/feature-flag/feature-flag.service.spec.ts b/tests/core/feature-flag/feature-flag.service.spec.ts index 108cc449..8ee83a06 100644 --- a/tests/core/feature-flag/feature-flag.service.spec.ts +++ b/tests/core/feature-flag/feature-flag.service.spec.ts @@ -29,6 +29,22 @@ describe("FeatureFlagService", () => { expect(enabled).toBe(false); }); + it("returns false when the response is not an array", async () => { + mockAxiosGet(TEAM_FEATURES_URL, null); + + const enabled = await new FeatureFlagService(testContext).isEnabled("pacman.branching"); + + expect(enabled).toBe(false); + }); + + it("ignores null entries and still matches a present key", async () => { + mockAxiosGet(TEAM_FEATURES_URL, [null, { key: "pacman.branching" }]); + + const enabled = await new FeatureFlagService(testContext).isEnabled("pacman.branching"); + + expect(enabled).toBe(true); + }); + it("rejects when the team features endpoint fails", async () => { mockAxiosGetError(TEAM_FEATURES_URL, 500, { error: "boom" }); diff --git a/tests/integration/commands/early-access.spec.ts b/tests/integration/commands/early-access.spec.ts index 23605e14..35e143a8 100644 --- a/tests/integration/commands/early-access.spec.ts +++ b/tests/integration/commands/early-access.spec.ts @@ -1,5 +1,6 @@ import { IModule, Configurator } from "../../../src/core/command/module-handler"; import { Context } from "../../../src/core/command/cli-context"; +import { EarlyAccessFeature } from "../../../src/core/feature-flag/early-access-features"; import { CliRunResult, runCli as runCliProcess } from "../../utls/cli-runner"; import { mockAxiosGet, mockAxiosGetError } from "../../utls/http-requests-mock"; @@ -16,7 +17,7 @@ class EarlyAccessTestModule extends IModule { public register(_context: Context, configurator: Configurator): void { configurator .command("ea-test") - .earlyAccess("pacman.branching") + .earlyAccess(EarlyAccessFeature.BRANCHING) .action(handlerSpy); } } @@ -31,7 +32,7 @@ describe("early access command integration", () => { } it("runs the command when the feature flag is enabled for the team", async () => { - mockAxiosGet(TEAM_FEATURES_URL, [{ key: "pacman.branching" }]); + mockAxiosGet(TEAM_FEATURES_URL, [{ key: EarlyAccessFeature.BRANCHING }]); const result = await runCli(["ea-test"]); From 9cee3558f9ee7715784472fe72f7b3bc0cc4ce30 Mon Sep 17 00:00:00 2001 From: "a.jashari" Date: Thu, 9 Jul 2026 13:55:38 +0200 Subject: [PATCH 3/6] chore: ignore coverage output Co-Authored-By: Claude Opus 4.8 --- .gitignore | 3 + coverage/base.css | 224 ----- coverage/block-navigation.js | 87 -- coverage/command/index.html | 116 --- coverage/command/module-handler.ts.html | 889 ------------------ coverage/favicon.png | Bin 445 -> 0 bytes .../early-access-features.ts.html | 124 --- .../feature-flag/feature-flag.service.ts.html | 187 ---- coverage/feature-flag/index.html | 131 --- coverage/index.html | 131 --- coverage/lcov-report/base.css | 224 ----- coverage/lcov-report/block-navigation.js | 87 -- coverage/lcov-report/command/index.html | 116 --- .../command/module-handler.ts.html | 889 ------------------ coverage/lcov-report/favicon.png | Bin 445 -> 0 bytes .../early-access-features.ts.html | 124 --- .../feature-flag/feature-flag.service.ts.html | 187 ---- coverage/lcov-report/feature-flag/index.html | 131 --- coverage/lcov-report/index.html | 131 --- coverage/lcov-report/prettify.css | 1 - coverage/lcov-report/prettify.js | 2 - coverage/lcov-report/sort-arrow-sprite.png | Bin 138 -> 0 bytes coverage/lcov-report/sorter.js | 196 ---- coverage/lcov.info | 427 --------- coverage/prettify.css | 1 - coverage/prettify.js | 2 - coverage/sort-arrow-sprite.png | Bin 138 -> 0 bytes coverage/sorter.js | 196 ---- 28 files changed, 3 insertions(+), 4603 deletions(-) delete mode 100644 coverage/base.css delete mode 100644 coverage/block-navigation.js delete mode 100644 coverage/command/index.html delete mode 100644 coverage/command/module-handler.ts.html delete mode 100644 coverage/favicon.png delete mode 100644 coverage/feature-flag/early-access-features.ts.html delete mode 100644 coverage/feature-flag/feature-flag.service.ts.html delete mode 100644 coverage/feature-flag/index.html delete mode 100644 coverage/index.html delete mode 100644 coverage/lcov-report/base.css delete mode 100644 coverage/lcov-report/block-navigation.js delete mode 100644 coverage/lcov-report/command/index.html delete mode 100644 coverage/lcov-report/command/module-handler.ts.html delete mode 100644 coverage/lcov-report/favicon.png delete mode 100644 coverage/lcov-report/feature-flag/early-access-features.ts.html delete mode 100644 coverage/lcov-report/feature-flag/feature-flag.service.ts.html delete mode 100644 coverage/lcov-report/feature-flag/index.html delete mode 100644 coverage/lcov-report/index.html delete mode 100644 coverage/lcov-report/prettify.css delete mode 100644 coverage/lcov-report/prettify.js delete mode 100644 coverage/lcov-report/sort-arrow-sprite.png delete mode 100644 coverage/lcov-report/sorter.js delete mode 100644 coverage/lcov.info delete mode 100644 coverage/prettify.css delete mode 100644 coverage/prettify.js delete mode 100644 coverage/sort-arrow-sprite.png delete mode 100644 coverage/sorter.js diff --git a/.gitignore b/.gitignore index 7363130f..74284100 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,6 @@ npm-debug.log .idea *.iml .DS_Store + +# Test coverage output +coverage/ diff --git a/coverage/base.css b/coverage/base.css deleted file mode 100644 index f418035b..00000000 --- a/coverage/base.css +++ /dev/null @@ -1,224 +0,0 @@ -body, html { - margin:0; padding: 0; - height: 100%; -} -body { - font-family: Helvetica Neue, Helvetica, Arial; - font-size: 14px; - color:#333; -} -.small { font-size: 12px; } -*, *:after, *:before { - -webkit-box-sizing:border-box; - -moz-box-sizing:border-box; - box-sizing:border-box; - } -h1 { font-size: 20px; margin: 0;} -h2 { font-size: 14px; } -pre { - font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; - margin: 0; - padding: 0; - -moz-tab-size: 2; - -o-tab-size: 2; - tab-size: 2; -} -a { color:#0074D9; text-decoration:none; } -a:hover { text-decoration:underline; } -.strong { font-weight: bold; } -.space-top1 { padding: 10px 0 0 0; } -.pad2y { padding: 20px 0; } -.pad1y { padding: 10px 0; } -.pad2x { padding: 0 20px; } -.pad2 { padding: 20px; } -.pad1 { padding: 10px; } -.space-left2 { padding-left:55px; } -.space-right2 { padding-right:20px; } -.center { text-align:center; } -.clearfix { display:block; } -.clearfix:after { - content:''; - display:block; - height:0; - clear:both; - visibility:hidden; - } -.fl { float: left; } -@media only screen and (max-width:640px) { - .col3 { width:100%; max-width:100%; } - .hide-mobile { display:none!important; } -} - -.quiet { - color: #7f7f7f; - color: rgba(0,0,0,0.5); -} -.quiet a { opacity: 0.7; } - -.fraction { - font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; - font-size: 10px; - color: #555; - background: #E8E8E8; - padding: 4px 5px; - border-radius: 3px; - vertical-align: middle; -} - -div.path a:link, div.path a:visited { color: #333; } -table.coverage { - border-collapse: collapse; - margin: 10px 0 0 0; - padding: 0; -} - -table.coverage td { - margin: 0; - padding: 0; - vertical-align: top; -} -table.coverage td.line-count { - text-align: right; - padding: 0 5px 0 20px; -} -table.coverage td.line-coverage { - text-align: right; - padding-right: 10px; - min-width:20px; -} - -table.coverage td span.cline-any { - display: inline-block; - padding: 0 5px; - width: 100%; -} -.missing-if-branch { - display: inline-block; - margin-right: 5px; - border-radius: 3px; - position: relative; - padding: 0 4px; - background: #333; - color: yellow; -} - -.skip-if-branch { - display: none; - margin-right: 10px; - position: relative; - padding: 0 4px; - background: #ccc; - color: white; -} -.missing-if-branch .typ, .skip-if-branch .typ { - color: inherit !important; -} -.coverage-summary { - border-collapse: collapse; - width: 100%; -} -.coverage-summary tr { border-bottom: 1px solid #bbb; } -.keyline-all { border: 1px solid #ddd; } -.coverage-summary td, .coverage-summary th { padding: 10px; } -.coverage-summary tbody { border: 1px solid #bbb; } -.coverage-summary td { border-right: 1px solid #bbb; } -.coverage-summary td:last-child { border-right: none; } -.coverage-summary th { - text-align: left; - font-weight: normal; - white-space: nowrap; -} -.coverage-summary th.file { border-right: none !important; } -.coverage-summary th.pct { } -.coverage-summary th.pic, -.coverage-summary th.abs, -.coverage-summary td.pct, -.coverage-summary td.abs { text-align: right; } -.coverage-summary td.file { white-space: nowrap; } -.coverage-summary td.pic { min-width: 120px !important; } -.coverage-summary tfoot td { } - -.coverage-summary .sorter { - height: 10px; - width: 7px; - display: inline-block; - margin-left: 0.5em; - background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; -} -.coverage-summary .sorted .sorter { - background-position: 0 -20px; -} -.coverage-summary .sorted-desc .sorter { - background-position: 0 -10px; -} -.status-line { height: 10px; } -/* yellow */ -.cbranch-no { background: yellow !important; color: #111; } -/* dark red */ -.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } -.low .chart { border:1px solid #C21F39 } -.highlighted, -.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ - background: #C21F39 !important; -} -/* medium red */ -.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } -/* light red */ -.low, .cline-no { background:#FCE1E5 } -/* light green */ -.high, .cline-yes { background:rgb(230,245,208) } -/* medium green */ -.cstat-yes { background:rgb(161,215,106) } -/* dark green */ -.status-line.high, .high .cover-fill { background:rgb(77,146,33) } -.high .chart { border:1px solid rgb(77,146,33) } -/* dark yellow (gold) */ -.status-line.medium, .medium .cover-fill { background: #f9cd0b; } -.medium .chart { border:1px solid #f9cd0b; } -/* light yellow */ -.medium { background: #fff4c2; } - -.cstat-skip { background: #ddd; color: #111; } -.fstat-skip { background: #ddd; color: #111 !important; } -.cbranch-skip { background: #ddd !important; color: #111; } - -span.cline-neutral { background: #eaeaea; } - -.coverage-summary td.empty { - opacity: .5; - padding-top: 4px; - padding-bottom: 4px; - line-height: 1; - color: #888; -} - -.cover-fill, .cover-empty { - display:inline-block; - height: 12px; -} -.chart { - line-height: 0; -} -.cover-empty { - background: white; -} -.cover-full { - border-right: none !important; -} -pre.prettyprint { - border: none !important; - padding: 0 !important; - margin: 0 !important; -} -.com { color: #999 !important; } -.ignore-none { color: #999; font-weight: normal; } - -.wrapper { - min-height: 100%; - height: auto !important; - height: 100%; - margin: 0 auto -48px; -} -.footer, .push { - height: 48px; -} diff --git a/coverage/block-navigation.js b/coverage/block-navigation.js deleted file mode 100644 index cc121302..00000000 --- a/coverage/block-navigation.js +++ /dev/null @@ -1,87 +0,0 @@ -/* eslint-disable */ -var jumpToCode = (function init() { - // Classes of code we would like to highlight in the file view - var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; - - // Elements to highlight in the file listing view - var fileListingElements = ['td.pct.low']; - - // We don't want to select elements that are direct descendants of another match - var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` - - // Selecter that finds elements on the page to which we can jump - var selector = - fileListingElements.join(', ') + - ', ' + - notSelector + - missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` - - // The NodeList of matching elements - var missingCoverageElements = document.querySelectorAll(selector); - - var currentIndex; - - function toggleClass(index) { - missingCoverageElements - .item(currentIndex) - .classList.remove('highlighted'); - missingCoverageElements.item(index).classList.add('highlighted'); - } - - function makeCurrent(index) { - toggleClass(index); - currentIndex = index; - missingCoverageElements.item(index).scrollIntoView({ - behavior: 'smooth', - block: 'center', - inline: 'center' - }); - } - - function goToPrevious() { - var nextIndex = 0; - if (typeof currentIndex !== 'number' || currentIndex === 0) { - nextIndex = missingCoverageElements.length - 1; - } else if (missingCoverageElements.length > 1) { - nextIndex = currentIndex - 1; - } - - makeCurrent(nextIndex); - } - - function goToNext() { - var nextIndex = 0; - - if ( - typeof currentIndex === 'number' && - currentIndex < missingCoverageElements.length - 1 - ) { - nextIndex = currentIndex + 1; - } - - makeCurrent(nextIndex); - } - - return function jump(event) { - if ( - document.getElementById('fileSearch') === document.activeElement && - document.activeElement != null - ) { - // if we're currently focused on the search input, we don't want to navigate - return; - } - - switch (event.which) { - case 78: // n - case 74: // j - goToNext(); - break; - case 66: // b - case 75: // k - case 80: // p - goToPrevious(); - break; - } - }; -})(); -window.addEventListener('keydown', jumpToCode); diff --git a/coverage/command/index.html b/coverage/command/index.html deleted file mode 100644 index f07df22b..00000000 --- a/coverage/command/index.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - Code coverage report for command - - - - - - - - - -
-
-

All files command

-
- -
- 66.79% - Statements - 179/268 -
- - -
- 100% - Branches - 37/37 -
- - -
- 87.5% - Functions - 14/16 -
- - -
- 66.79% - Lines - 179/268 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
module-handler.ts -
-
66.79%179/268100%37/3787.5%14/1666.79%179/268
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/command/module-handler.ts.html b/coverage/command/module-handler.ts.html deleted file mode 100644 index d04f020a..00000000 --- a/coverage/command/module-handler.ts.html +++ /dev/null @@ -1,889 +0,0 @@ - - - - - - Code coverage report for command/module-handler.ts - - - - - - - - - -
-
-

All files / command module-handler.ts

-
- -
- 66.79% - Statements - 179/268 -
- - -
- 100% - Branches - 37/37 -
- - -
- 87.5% - Functions - 14/16 -
- - -
- 66.79% - Lines - 179/268 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -226 -227 -228 -229 -230 -231 -232 -233 -234 -235 -236 -237 -238 -239 -240 -241 -242 -243 -244 -245 -246 -247 -248 -249 -250 -251 -252 -253 -254 -255 -256 -257 -258 -259 -260 -261 -262 -263 -264 -265 -266 -267 -268 -2691x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -80x -80x -80x -80x -80x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -87x -87x -87x -1x -1x -1x -1x -1x -1x -1x -227x -60x -60x -167x -167x -167x -167x -167x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1923x -1923x -1923x -1x -1x -1756x -1756x -1756x -1x -1x -80x -80x -80x -1x -1x -1913x -1913x -1913x -1x -1x -  -  -  -1x -1x -6460x -6460x -6460x -1x -1x -1465x -1465x -1465x -1x -1x -300x -300x -300x -1x -1x -1x -1x -1x -1x -1x -1x -8x -8x -7x -7x -8x -8x -1x -1x -1389x -85x -85x -85x -80x -85x -30x -6x -6x -6x -24x -24x -24x -1389x -1389x -1x -1x -85x -31x -31x -85x -1x -1x -1x -1x -1x -1x -1x -1x -85x -85x -78x -78x -7x -7x -7x -7x -5x -3x -3x -3x -1x -1x -2x -2x -2x -2x -4x -10x -2x -2x -2x -2x -85x -1x - 
import path = require("path");
-import * as fs from "fs";
-import { Command, CommandOptions, OptionValues } from "commander";
-import { Context } from "./cli-context";
-import { GracefulError, logger } from "../utils/logger";
-import { FeatureFlagService } from "../feature-flag/feature-flag.service";
- 
-export abstract class IModule {
-    public abstract register(context: Context, commandConfig: Configurator): void;
-}
- 
-export type IModuleConstructor = new () => IModule;
- 
-export class ModuleHandler {
-    public configurator: Configurator;
- 
-    constructor(
-        public program: Command,
-        public context: Context
-    ) {
-        this.configurator = new Configurator(this.program, this.context);
-    }
- 
-    // Store registered module instances if needed later
-    public registeredModules: IModule[] = [];
- 
-    /**
-     * Discovers modules in the specified directory, imports them,
-     * instantiates the default exported class, and calls its register method.
-     *
-     * @param {any} rootPath - __dirname when invoked from the main entry file
-     * @param devMode        - Use uncompiled modules for development debug mode
-     */
-    public discoverAndRegisterModules(rootPath: string, devMode: boolean = false): void {
-        const modulesDirPath = path.resolve(rootPath, "commands");
-
-        try {
-            const moduleFolders = fs.readdirSync(modulesDirPath, { withFileTypes: true });
-
-            for (const dirent of moduleFolders) {
-                if (dirent.isDirectory()) {
-                    const moduleFolderName = dirent.name;
-
-                    const moduleFileName = devMode ? "module.ts" : "module.js";
-
-                    // Calculate path relative to *this file's location in dist*
-                    let potentialModuleJsPath: any;
-                    potentialModuleJsPath = path.resolve(
-                        rootPath,
-                        "commands",
-                        moduleFolderName,
-                        moduleFileName // Look for the compiled JS file
-                    );
-                    try {
-                        fs.accessSync(potentialModuleJsPath);
-                    } catch (err) {
-                        // apparently the file does not exist of is not accessible
-                        potentialModuleJsPath = null;
-                    }
-
-                    if (!potentialModuleJsPath) {
-                        logger.debug(
-                            `Module folder ${moduleFolderName} does not contain a valid entry point and is skipped.`
-                        );
-                    } else {
-                        // Check if the compiled JS file exists
-                        try {
-                            logger.debug(`Found potential module definition: ${potentialModuleJsPath}`);
-
-                            // Dynamically require the module
-                            const requiredModule = require(potentialModuleJsPath);
-
-                            // With 'export =' or 'module.exports =', the required value *is* the class
-                            const ModuleClass = requiredModule as IModuleConstructor; // Cast for TS check
-
-                            // Basic check: Is it a class (function)?
-                            if (typeof ModuleClass === "function" && ModuleClass.prototype) {
-                                const moduleInstance: IModule = new ModuleClass(); // Instantiate
-
-                                // Check if the instance has the register method
-                                if (typeof moduleInstance.register === "function") {
-                                    logger.debug(`Registering module: ${moduleFolderName}`);
-                                    // Call register - can still be async even if require() is sync
-                                    moduleInstance.register(this.context, this.configurator);
-                                    this.registeredModules.push(moduleInstance);
-                                } else {
-                                    logger.warn(`Module ${moduleFolderName} export does not have a 'register' method.`);
-                                }
-                            } else {
-                                logger.warn(`Module ${moduleFolderName} export is not a class/constructor function.`);
-                            }
-                        } catch (error: any) {
-                            if (error.code === "ENOENT") {
-                                // Compiled module.js not found, maybe folder doesn't contain a valid module
-                                logger.warn(
-                                    `Directory ${moduleFolderName} does not contain a compiled module.js file.`
-                                );
-                            } else if (error.code === "MODULE_NOT_FOUND") {
-                                logger.debug("Error details", error);
-                                logger.warn(
-                                    `Could not require module ${moduleFolderName}. Check dependencies or compilation. Path: ${potentialModuleJsPath}`
-                                );
-                            } else {
-                                logger.error(`Error processing module in ${moduleFolderName}:`, error);
-                            }
-                        }
-                    }
-                }
-            }
-        } catch (error: any) {
-            if (error.code === "ENOENT") {
-                logger.error(
-                    `Modules directory not found relative to JS output: ${path.resolve(path.dirname(__filename), "commands")}`
-                );
-            } else {
-                logger.error("Failed to read modules directory:", error);
-            }
-        }
-        logger.debug(`Module discovery complete. ${this.registeredModules.length} modules registered.`);
-    }
-}
- 
-type CommandHandler = (context: Context, command: Command, options: OptionValues) => Promise<void>;
- 
-/**
- * Allows the creation of root level commands.
- */
-export class Configurator {
-    public rootCommandMap = new Map<string, CommandConfig>();
- 
-    constructor(
-        private program: Command,
-        private ctx: Context
-    ) {}
- 
-    /**
-     * Get or create a root level command.
-     * @param name
-     * @returns
-     */
-    public command(name: string): CommandConfig {
-        if (this.rootCommandMap.has(name)) {
-            return this.rootCommandMap.get(name);
-        }
-        const cmd = this.program.command(name);
-        const cmdConfig = new CommandConfig(cmd, this.ctx);
-        this.rootCommandMap.set(name, cmdConfig);
-        return cmdConfig;
-    }
-}
- 
-/**
- * Delegate wrapper around the Command object, to simply change the way the program is
- * executed.
- */
-export class CommandConfig {
-    private deprecationMessage: string;
- 
-    constructor(
-        private cmd: Command,
-        private ctx: Context
-    ) {}
- 
-    public command(nameAndArgs: string, opts?: CommandOptions): CommandConfig {
-        return new CommandConfig(this.cmd.command(nameAndArgs, opts), this.ctx)
-            .option("-p, --profile <profile>", "Profile which you want to use");
-    }
- 
-    public alias(alias: string): CommandConfig {
-        this.cmd.alias(alias);
-        return this;
-    }
- 
-    public description(description: string): CommandConfig {
-        this.cmd.description(description);
-        return this;
-    }
- 
-    public argument(name: string, description?: string, defaultValue?: unknown): CommandConfig {
-        this.cmd.argument(name, description, defaultValue);
-        return this;
-    }
- 
-    public option(flags: string, description?: string, defaultValue?: string | boolean | string[]): CommandConfig {
-        this.cmd.option(flags, description, defaultValue);
-        return this;
-    }
- 
-    public requiredOption(flags: string, description?: string, defaultValue?: string | boolean | string[]): CommandConfig {
-        this.cmd.requiredOption(flags, description, defaultValue);
-        return this;
-    }
- 
-    public deprecationNotice(deprecationMessage: string): CommandConfig {
-        this.deprecationMessage = deprecationMessage;
-        return this;
-    }
- 
-    /**
-     * Marks a command as early access (non-GA). Purely internal — it is not shown
-     * in help. When a feature key is provided, the command is gated at run time:
-     * before it executes, the CLI checks whether that backend feature flag is
-     * enabled for the team, and stops with a clear message if it is not.
-     */
-    public earlyAccess(featureKey?: string): CommandConfig {
-        (this.cmd as any).isEarlyAccess = true;
-        if (featureKey) {
-            (this.cmd as any).earlyAccessFeatureKey = featureKey;
-        }
-        return this;
-    }
- 
-    public action(handler: CommandHandler): void {
-        this.cmd.action(async (): Promise<void> => {
-            try {
-                this.printDeprecationNoticeIfDeprecated();
-                await this.checkEarlyAccessFeatureFlag();
-                await handler(this.ctx, this.cmd, this.cmd.optsWithGlobals());
-            } catch (error) {
-                if (error instanceof GracefulError) {
-                    logger.error(error.message);
-                    return;
-                }
-                logger.error(`An unexpected error occured executing a command: ${error}`);
-                process.exitCode = 1;
-            }
-        });
-    }
- 
-    private printDeprecationNoticeIfDeprecated(): void {
-        if (this.deprecationMessage) {
-            logger.warn("⚠️  [DEPRECATION NOTICE] \n" + this.deprecationMessage);
-        }
-    }
- 
-    /**
-     * For early-access commands that carry a feature key, verify the backend
-     * feature flag is enabled for the team before the command runs. Throws a
-     * GracefulError with a clear message when it is not enabled (or cannot be
-     * verified). Commands with no feature key are left untouched.
-     */
-    private async checkEarlyAccessFeatureFlag(): Promise<void> {
-        const featureKey = (this.cmd as any).earlyAccessFeatureKey;
-        if (!featureKey) {
-            return;
-        }
- 
-        let enabled: boolean;
-        try {
-            enabled = await new FeatureFlagService(this.ctx).isEnabled(featureKey);
-        } catch (error) {
-            // With no profile, surface the standard "no profile provided" error
-            // rather than masking it with an early-access message.
-            if (!this.ctx.profile) {
-                throw error;
-            }
-            throw new GracefulError(
-                `Could not verify whether '${this.cmd.name()}' is enabled for your team. Please try again later or contact support.`
-            );
-        }
- 
-        if (!enabled) {
-            throw new GracefulError(
-                `'${this.cmd.name()}' is not enabled for your team. Contact support to request access.`
-            );
-        }
-    }
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/favicon.png b/coverage/favicon.png deleted file mode 100644 index c1525b811a167671e9de1fa78aab9f5c0b61cef7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 445 zcmV;u0Yd(XP))rP{nL}Ln%S7`m{0DjX9TLF* zFCb$4Oi7vyLOydb!7n&^ItCzb-%BoB`=x@N2jll2Nj`kauio%aw_@fe&*}LqlFT43 z8doAAe))z_%=P%v^@JHp3Hjhj^6*Kr_h|g_Gr?ZAa&y>wxHE99Gk>A)2MplWz2xdG zy8VD2J|Uf#EAw*bo5O*PO_}X2Tob{%bUoO2G~T`@%S6qPyc}VkhV}UifBuRk>%5v( z)x7B{I~z*k<7dv#5tC+m{km(D087J4O%+<<;K|qwefb6@GSX45wCK}Sn*> - - - - Code coverage report for feature-flag/early-access-features.ts - - - - - - - - - -
-
-

All files / feature-flag early-access-features.ts

-
- -
- 100% - Statements - 13/13 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 0/0 -
- - -
- 100% - Lines - 13/13 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -141x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x - 
/**
- * Backend feature-flag keys for early-access commands.
- *
- * These mirror the backend `FeatureToggle` keys and are the values passed to
- * `CommandConfig.earlyAccess(...)`. Keeping them here gives a single place to
- * see every early-access feature key even though the wiring lives on the
- * individual commands.
- */
-export const EarlyAccessFeature = {
-    BRANCHING: "pacman.branching",
-} as const;
- 
-export type EarlyAccessFeatureKey = (typeof EarlyAccessFeature)[keyof typeof EarlyAccessFeature];
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/feature-flag/feature-flag.service.ts.html b/coverage/feature-flag/feature-flag.service.ts.html deleted file mode 100644 index f51159d0..00000000 --- a/coverage/feature-flag/feature-flag.service.ts.html +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - Code coverage report for feature-flag/feature-flag.service.ts - - - - - - - - - -
-
-

All files / feature-flag feature-flag.service.ts

-
- -
- 100% - Statements - 34/34 -
- - -
- 100% - Branches - 10/10 -
- - -
- 100% - Functions - 3/3 -
- - -
- 100% - Lines - 34/34 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -351x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -13x -13x -1x -1x -13x -13x -13x -1x - 
import { Context } from "../command/cli-context";
-import { HttpClient } from "../http/http-client";
- 
-/**
- * A backend ("paid") feature flag as returned by the team-features endpoint.
- * Only the key is needed here — presence in the list means the flag is enabled
- * for the calling team.
- */
-interface TeamFeature {
-    key: string;
-}
- 
-/**
- * Queries whether a backend feature flag is enabled for the current team.
- *
- * Uses the same endpoint the web frontend relies on to resolve backend/per-team
- * ("paid") feature flags: `GET /api/team/features` returns the list of flags
- * enabled for the team behind the profile's token. A flag is considered enabled
- * when an entry with a matching key is present in that list.
- */
-export class FeatureFlagService {
-    private static readonly TEAM_FEATURES_URL = "/api/team/features";
- 
-    private httpClient: () => HttpClient;
- 
-    constructor(context: Context) {
-        this.httpClient = () => context.httpClient;
-    }
- 
-    public async isEnabled(featureKey: string): Promise<boolean> {
-        const features: TeamFeature[] = await this.httpClient().get(FeatureFlagService.TEAM_FEATURES_URL);
-        return Array.isArray(features) && features.some(feature => feature?.key === featureKey);
-    }
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/feature-flag/index.html b/coverage/feature-flag/index.html deleted file mode 100644 index 0aa13214..00000000 --- a/coverage/feature-flag/index.html +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - Code coverage report for feature-flag - - - - - - - - - -
-
-

All files feature-flag

-
- -
- 100% - Statements - 47/47 -
- - -
- 100% - Branches - 10/10 -
- - -
- 100% - Functions - 3/3 -
- - -
- 100% - Lines - 47/47 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
early-access-features.ts -
-
100%13/13100%0/0100%0/0100%13/13
feature-flag.service.ts -
-
100%34/34100%10/10100%3/3100%34/34
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/index.html b/coverage/index.html deleted file mode 100644 index b8610ee8..00000000 --- a/coverage/index.html +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - Code coverage report for All files - - - - - - - - - -
-
-

All files

-
- -
- 71.74% - Statements - 226/315 -
- - -
- 100% - Branches - 47/47 -
- - -
- 89.47% - Functions - 17/19 -
- - -
- 71.74% - Lines - 226/315 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
command -
-
66.79%179/268100%37/3787.5%14/1666.79%179/268
feature-flag -
-
100%47/47100%10/10100%3/3100%47/47
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/lcov-report/base.css b/coverage/lcov-report/base.css deleted file mode 100644 index f418035b..00000000 --- a/coverage/lcov-report/base.css +++ /dev/null @@ -1,224 +0,0 @@ -body, html { - margin:0; padding: 0; - height: 100%; -} -body { - font-family: Helvetica Neue, Helvetica, Arial; - font-size: 14px; - color:#333; -} -.small { font-size: 12px; } -*, *:after, *:before { - -webkit-box-sizing:border-box; - -moz-box-sizing:border-box; - box-sizing:border-box; - } -h1 { font-size: 20px; margin: 0;} -h2 { font-size: 14px; } -pre { - font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; - margin: 0; - padding: 0; - -moz-tab-size: 2; - -o-tab-size: 2; - tab-size: 2; -} -a { color:#0074D9; text-decoration:none; } -a:hover { text-decoration:underline; } -.strong { font-weight: bold; } -.space-top1 { padding: 10px 0 0 0; } -.pad2y { padding: 20px 0; } -.pad1y { padding: 10px 0; } -.pad2x { padding: 0 20px; } -.pad2 { padding: 20px; } -.pad1 { padding: 10px; } -.space-left2 { padding-left:55px; } -.space-right2 { padding-right:20px; } -.center { text-align:center; } -.clearfix { display:block; } -.clearfix:after { - content:''; - display:block; - height:0; - clear:both; - visibility:hidden; - } -.fl { float: left; } -@media only screen and (max-width:640px) { - .col3 { width:100%; max-width:100%; } - .hide-mobile { display:none!important; } -} - -.quiet { - color: #7f7f7f; - color: rgba(0,0,0,0.5); -} -.quiet a { opacity: 0.7; } - -.fraction { - font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; - font-size: 10px; - color: #555; - background: #E8E8E8; - padding: 4px 5px; - border-radius: 3px; - vertical-align: middle; -} - -div.path a:link, div.path a:visited { color: #333; } -table.coverage { - border-collapse: collapse; - margin: 10px 0 0 0; - padding: 0; -} - -table.coverage td { - margin: 0; - padding: 0; - vertical-align: top; -} -table.coverage td.line-count { - text-align: right; - padding: 0 5px 0 20px; -} -table.coverage td.line-coverage { - text-align: right; - padding-right: 10px; - min-width:20px; -} - -table.coverage td span.cline-any { - display: inline-block; - padding: 0 5px; - width: 100%; -} -.missing-if-branch { - display: inline-block; - margin-right: 5px; - border-radius: 3px; - position: relative; - padding: 0 4px; - background: #333; - color: yellow; -} - -.skip-if-branch { - display: none; - margin-right: 10px; - position: relative; - padding: 0 4px; - background: #ccc; - color: white; -} -.missing-if-branch .typ, .skip-if-branch .typ { - color: inherit !important; -} -.coverage-summary { - border-collapse: collapse; - width: 100%; -} -.coverage-summary tr { border-bottom: 1px solid #bbb; } -.keyline-all { border: 1px solid #ddd; } -.coverage-summary td, .coverage-summary th { padding: 10px; } -.coverage-summary tbody { border: 1px solid #bbb; } -.coverage-summary td { border-right: 1px solid #bbb; } -.coverage-summary td:last-child { border-right: none; } -.coverage-summary th { - text-align: left; - font-weight: normal; - white-space: nowrap; -} -.coverage-summary th.file { border-right: none !important; } -.coverage-summary th.pct { } -.coverage-summary th.pic, -.coverage-summary th.abs, -.coverage-summary td.pct, -.coverage-summary td.abs { text-align: right; } -.coverage-summary td.file { white-space: nowrap; } -.coverage-summary td.pic { min-width: 120px !important; } -.coverage-summary tfoot td { } - -.coverage-summary .sorter { - height: 10px; - width: 7px; - display: inline-block; - margin-left: 0.5em; - background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; -} -.coverage-summary .sorted .sorter { - background-position: 0 -20px; -} -.coverage-summary .sorted-desc .sorter { - background-position: 0 -10px; -} -.status-line { height: 10px; } -/* yellow */ -.cbranch-no { background: yellow !important; color: #111; } -/* dark red */ -.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } -.low .chart { border:1px solid #C21F39 } -.highlighted, -.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ - background: #C21F39 !important; -} -/* medium red */ -.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } -/* light red */ -.low, .cline-no { background:#FCE1E5 } -/* light green */ -.high, .cline-yes { background:rgb(230,245,208) } -/* medium green */ -.cstat-yes { background:rgb(161,215,106) } -/* dark green */ -.status-line.high, .high .cover-fill { background:rgb(77,146,33) } -.high .chart { border:1px solid rgb(77,146,33) } -/* dark yellow (gold) */ -.status-line.medium, .medium .cover-fill { background: #f9cd0b; } -.medium .chart { border:1px solid #f9cd0b; } -/* light yellow */ -.medium { background: #fff4c2; } - -.cstat-skip { background: #ddd; color: #111; } -.fstat-skip { background: #ddd; color: #111 !important; } -.cbranch-skip { background: #ddd !important; color: #111; } - -span.cline-neutral { background: #eaeaea; } - -.coverage-summary td.empty { - opacity: .5; - padding-top: 4px; - padding-bottom: 4px; - line-height: 1; - color: #888; -} - -.cover-fill, .cover-empty { - display:inline-block; - height: 12px; -} -.chart { - line-height: 0; -} -.cover-empty { - background: white; -} -.cover-full { - border-right: none !important; -} -pre.prettyprint { - border: none !important; - padding: 0 !important; - margin: 0 !important; -} -.com { color: #999 !important; } -.ignore-none { color: #999; font-weight: normal; } - -.wrapper { - min-height: 100%; - height: auto !important; - height: 100%; - margin: 0 auto -48px; -} -.footer, .push { - height: 48px; -} diff --git a/coverage/lcov-report/block-navigation.js b/coverage/lcov-report/block-navigation.js deleted file mode 100644 index cc121302..00000000 --- a/coverage/lcov-report/block-navigation.js +++ /dev/null @@ -1,87 +0,0 @@ -/* eslint-disable */ -var jumpToCode = (function init() { - // Classes of code we would like to highlight in the file view - var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; - - // Elements to highlight in the file listing view - var fileListingElements = ['td.pct.low']; - - // We don't want to select elements that are direct descendants of another match - var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` - - // Selecter that finds elements on the page to which we can jump - var selector = - fileListingElements.join(', ') + - ', ' + - notSelector + - missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` - - // The NodeList of matching elements - var missingCoverageElements = document.querySelectorAll(selector); - - var currentIndex; - - function toggleClass(index) { - missingCoverageElements - .item(currentIndex) - .classList.remove('highlighted'); - missingCoverageElements.item(index).classList.add('highlighted'); - } - - function makeCurrent(index) { - toggleClass(index); - currentIndex = index; - missingCoverageElements.item(index).scrollIntoView({ - behavior: 'smooth', - block: 'center', - inline: 'center' - }); - } - - function goToPrevious() { - var nextIndex = 0; - if (typeof currentIndex !== 'number' || currentIndex === 0) { - nextIndex = missingCoverageElements.length - 1; - } else if (missingCoverageElements.length > 1) { - nextIndex = currentIndex - 1; - } - - makeCurrent(nextIndex); - } - - function goToNext() { - var nextIndex = 0; - - if ( - typeof currentIndex === 'number' && - currentIndex < missingCoverageElements.length - 1 - ) { - nextIndex = currentIndex + 1; - } - - makeCurrent(nextIndex); - } - - return function jump(event) { - if ( - document.getElementById('fileSearch') === document.activeElement && - document.activeElement != null - ) { - // if we're currently focused on the search input, we don't want to navigate - return; - } - - switch (event.which) { - case 78: // n - case 74: // j - goToNext(); - break; - case 66: // b - case 75: // k - case 80: // p - goToPrevious(); - break; - } - }; -})(); -window.addEventListener('keydown', jumpToCode); diff --git a/coverage/lcov-report/command/index.html b/coverage/lcov-report/command/index.html deleted file mode 100644 index 6e3f5816..00000000 --- a/coverage/lcov-report/command/index.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - Code coverage report for command - - - - - - - - - -
-
-

All files command

-
- -
- 66.79% - Statements - 179/268 -
- - -
- 100% - Branches - 37/37 -
- - -
- 87.5% - Functions - 14/16 -
- - -
- 66.79% - Lines - 179/268 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
module-handler.ts -
-
66.79%179/268100%37/3787.5%14/1666.79%179/268
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/lcov-report/command/module-handler.ts.html b/coverage/lcov-report/command/module-handler.ts.html deleted file mode 100644 index 633cd3a1..00000000 --- a/coverage/lcov-report/command/module-handler.ts.html +++ /dev/null @@ -1,889 +0,0 @@ - - - - - - Code coverage report for command/module-handler.ts - - - - - - - - - -
-
-

All files / command module-handler.ts

-
- -
- 66.79% - Statements - 179/268 -
- - -
- 100% - Branches - 37/37 -
- - -
- 87.5% - Functions - 14/16 -
- - -
- 66.79% - Lines - 179/268 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -226 -227 -228 -229 -230 -231 -232 -233 -234 -235 -236 -237 -238 -239 -240 -241 -242 -243 -244 -245 -246 -247 -248 -249 -250 -251 -252 -253 -254 -255 -256 -257 -258 -259 -260 -261 -262 -263 -264 -265 -266 -267 -268 -2691x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -80x -80x -80x -80x -80x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -87x -87x -87x -1x -1x -1x -1x -1x -1x -1x -227x -60x -60x -167x -167x -167x -167x -167x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1923x -1923x -1923x -1x -1x -1756x -1756x -1756x -1x -1x -80x -80x -80x -1x -1x -1913x -1913x -1913x -1x -1x -  -  -  -1x -1x -6460x -6460x -6460x -1x -1x -1465x -1465x -1465x -1x -1x -300x -300x -300x -1x -1x -1x -1x -1x -1x -1x -1x -8x -8x -7x -7x -8x -8x -1x -1x -1389x -85x -85x -85x -80x -85x -30x -6x -6x -6x -24x -24x -24x -1389x -1389x -1x -1x -85x -31x -31x -85x -1x -1x -1x -1x -1x -1x -1x -1x -85x -85x -78x -78x -7x -7x -7x -7x -5x -3x -3x -3x -1x -1x -2x -2x -2x -2x -4x -10x -2x -2x -2x -2x -85x -1x - 
import path = require("path");
-import * as fs from "fs";
-import { Command, CommandOptions, OptionValues } from "commander";
-import { Context } from "./cli-context";
-import { GracefulError, logger } from "../utils/logger";
-import { FeatureFlagService } from "../feature-flag/feature-flag.service";
- 
-export abstract class IModule {
-    public abstract register(context: Context, commandConfig: Configurator): void;
-}
- 
-export type IModuleConstructor = new () => IModule;
- 
-export class ModuleHandler {
-    public configurator: Configurator;
- 
-    constructor(
-        public program: Command,
-        public context: Context
-    ) {
-        this.configurator = new Configurator(this.program, this.context);
-    }
- 
-    // Store registered module instances if needed later
-    public registeredModules: IModule[] = [];
- 
-    /**
-     * Discovers modules in the specified directory, imports them,
-     * instantiates the default exported class, and calls its register method.
-     *
-     * @param {any} rootPath - __dirname when invoked from the main entry file
-     * @param devMode        - Use uncompiled modules for development debug mode
-     */
-    public discoverAndRegisterModules(rootPath: string, devMode: boolean = false): void {
-        const modulesDirPath = path.resolve(rootPath, "commands");
-
-        try {
-            const moduleFolders = fs.readdirSync(modulesDirPath, { withFileTypes: true });
-
-            for (const dirent of moduleFolders) {
-                if (dirent.isDirectory()) {
-                    const moduleFolderName = dirent.name;
-
-                    const moduleFileName = devMode ? "module.ts" : "module.js";
-
-                    // Calculate path relative to *this file's location in dist*
-                    let potentialModuleJsPath: any;
-                    potentialModuleJsPath = path.resolve(
-                        rootPath,
-                        "commands",
-                        moduleFolderName,
-                        moduleFileName // Look for the compiled JS file
-                    );
-                    try {
-                        fs.accessSync(potentialModuleJsPath);
-                    } catch (err) {
-                        // apparently the file does not exist of is not accessible
-                        potentialModuleJsPath = null;
-                    }
-
-                    if (!potentialModuleJsPath) {
-                        logger.debug(
-                            `Module folder ${moduleFolderName} does not contain a valid entry point and is skipped.`
-                        );
-                    } else {
-                        // Check if the compiled JS file exists
-                        try {
-                            logger.debug(`Found potential module definition: ${potentialModuleJsPath}`);
-
-                            // Dynamically require the module
-                            const requiredModule = require(potentialModuleJsPath);
-
-                            // With 'export =' or 'module.exports =', the required value *is* the class
-                            const ModuleClass = requiredModule as IModuleConstructor; // Cast for TS check
-
-                            // Basic check: Is it a class (function)?
-                            if (typeof ModuleClass === "function" && ModuleClass.prototype) {
-                                const moduleInstance: IModule = new ModuleClass(); // Instantiate
-
-                                // Check if the instance has the register method
-                                if (typeof moduleInstance.register === "function") {
-                                    logger.debug(`Registering module: ${moduleFolderName}`);
-                                    // Call register - can still be async even if require() is sync
-                                    moduleInstance.register(this.context, this.configurator);
-                                    this.registeredModules.push(moduleInstance);
-                                } else {
-                                    logger.warn(`Module ${moduleFolderName} export does not have a 'register' method.`);
-                                }
-                            } else {
-                                logger.warn(`Module ${moduleFolderName} export is not a class/constructor function.`);
-                            }
-                        } catch (error: any) {
-                            if (error.code === "ENOENT") {
-                                // Compiled module.js not found, maybe folder doesn't contain a valid module
-                                logger.warn(
-                                    `Directory ${moduleFolderName} does not contain a compiled module.js file.`
-                                );
-                            } else if (error.code === "MODULE_NOT_FOUND") {
-                                logger.debug("Error details", error);
-                                logger.warn(
-                                    `Could not require module ${moduleFolderName}. Check dependencies or compilation. Path: ${potentialModuleJsPath}`
-                                );
-                            } else {
-                                logger.error(`Error processing module in ${moduleFolderName}:`, error);
-                            }
-                        }
-                    }
-                }
-            }
-        } catch (error: any) {
-            if (error.code === "ENOENT") {
-                logger.error(
-                    `Modules directory not found relative to JS output: ${path.resolve(path.dirname(__filename), "commands")}`
-                );
-            } else {
-                logger.error("Failed to read modules directory:", error);
-            }
-        }
-        logger.debug(`Module discovery complete. ${this.registeredModules.length} modules registered.`);
-    }
-}
- 
-type CommandHandler = (context: Context, command: Command, options: OptionValues) => Promise<void>;
- 
-/**
- * Allows the creation of root level commands.
- */
-export class Configurator {
-    public rootCommandMap = new Map<string, CommandConfig>();
- 
-    constructor(
-        private program: Command,
-        private ctx: Context
-    ) {}
- 
-    /**
-     * Get or create a root level command.
-     * @param name
-     * @returns
-     */
-    public command(name: string): CommandConfig {
-        if (this.rootCommandMap.has(name)) {
-            return this.rootCommandMap.get(name);
-        }
-        const cmd = this.program.command(name);
-        const cmdConfig = new CommandConfig(cmd, this.ctx);
-        this.rootCommandMap.set(name, cmdConfig);
-        return cmdConfig;
-    }
-}
- 
-/**
- * Delegate wrapper around the Command object, to simply change the way the program is
- * executed.
- */
-export class CommandConfig {
-    private deprecationMessage: string;
- 
-    constructor(
-        private cmd: Command,
-        private ctx: Context
-    ) {}
- 
-    public command(nameAndArgs: string, opts?: CommandOptions): CommandConfig {
-        return new CommandConfig(this.cmd.command(nameAndArgs, opts), this.ctx)
-            .option("-p, --profile <profile>", "Profile which you want to use");
-    }
- 
-    public alias(alias: string): CommandConfig {
-        this.cmd.alias(alias);
-        return this;
-    }
- 
-    public description(description: string): CommandConfig {
-        this.cmd.description(description);
-        return this;
-    }
- 
-    public argument(name: string, description?: string, defaultValue?: unknown): CommandConfig {
-        this.cmd.argument(name, description, defaultValue);
-        return this;
-    }
- 
-    public option(flags: string, description?: string, defaultValue?: string | boolean | string[]): CommandConfig {
-        this.cmd.option(flags, description, defaultValue);
-        return this;
-    }
- 
-    public requiredOption(flags: string, description?: string, defaultValue?: string | boolean | string[]): CommandConfig {
-        this.cmd.requiredOption(flags, description, defaultValue);
-        return this;
-    }
- 
-    public deprecationNotice(deprecationMessage: string): CommandConfig {
-        this.deprecationMessage = deprecationMessage;
-        return this;
-    }
- 
-    /**
-     * Marks a command as early access (non-GA). Purely internal — it is not shown
-     * in help. When a feature key is provided, the command is gated at run time:
-     * before it executes, the CLI checks whether that backend feature flag is
-     * enabled for the team, and stops with a clear message if it is not.
-     */
-    public earlyAccess(featureKey?: string): CommandConfig {
-        (this.cmd as any).isEarlyAccess = true;
-        if (featureKey) {
-            (this.cmd as any).earlyAccessFeatureKey = featureKey;
-        }
-        return this;
-    }
- 
-    public action(handler: CommandHandler): void {
-        this.cmd.action(async (): Promise<void> => {
-            try {
-                this.printDeprecationNoticeIfDeprecated();
-                await this.checkEarlyAccessFeatureFlag();
-                await handler(this.ctx, this.cmd, this.cmd.optsWithGlobals());
-            } catch (error) {
-                if (error instanceof GracefulError) {
-                    logger.error(error.message);
-                    return;
-                }
-                logger.error(`An unexpected error occured executing a command: ${error}`);
-                process.exitCode = 1;
-            }
-        });
-    }
- 
-    private printDeprecationNoticeIfDeprecated(): void {
-        if (this.deprecationMessage) {
-            logger.warn("⚠️  [DEPRECATION NOTICE] \n" + this.deprecationMessage);
-        }
-    }
- 
-    /**
-     * For early-access commands that carry a feature key, verify the backend
-     * feature flag is enabled for the team before the command runs. Throws a
-     * GracefulError with a clear message when it is not enabled (or cannot be
-     * verified). Commands with no feature key are left untouched.
-     */
-    private async checkEarlyAccessFeatureFlag(): Promise<void> {
-        const featureKey = (this.cmd as any).earlyAccessFeatureKey;
-        if (!featureKey) {
-            return;
-        }
- 
-        let enabled: boolean;
-        try {
-            enabled = await new FeatureFlagService(this.ctx).isEnabled(featureKey);
-        } catch (error) {
-            // With no profile, surface the standard "no profile provided" error
-            // rather than masking it with an early-access message.
-            if (!this.ctx.profile) {
-                throw error;
-            }
-            throw new GracefulError(
-                `Could not verify whether '${this.cmd.name()}' is enabled for your team. Please try again later or contact support.`
-            );
-        }
- 
-        if (!enabled) {
-            throw new GracefulError(
-                `'${this.cmd.name()}' is not enabled for your team. Contact support to request access.`
-            );
-        }
-    }
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/lcov-report/favicon.png b/coverage/lcov-report/favicon.png deleted file mode 100644 index c1525b811a167671e9de1fa78aab9f5c0b61cef7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 445 zcmV;u0Yd(XP))rP{nL}Ln%S7`m{0DjX9TLF* zFCb$4Oi7vyLOydb!7n&^ItCzb-%BoB`=x@N2jll2Nj`kauio%aw_@fe&*}LqlFT43 z8doAAe))z_%=P%v^@JHp3Hjhj^6*Kr_h|g_Gr?ZAa&y>wxHE99Gk>A)2MplWz2xdG zy8VD2J|Uf#EAw*bo5O*PO_}X2Tob{%bUoO2G~T`@%S6qPyc}VkhV}UifBuRk>%5v( z)x7B{I~z*k<7dv#5tC+m{km(D087J4O%+<<;K|qwefb6@GSX45wCK}Sn*> - - - - Code coverage report for feature-flag/early-access-features.ts - - - - - - - - - -
-
-

All files / feature-flag early-access-features.ts

-
- -
- 100% - Statements - 13/13 -
- - -
- 100% - Branches - 0/0 -
- - -
- 100% - Functions - 0/0 -
- - -
- 100% - Lines - 13/13 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -141x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x - 
/**
- * Backend feature-flag keys for early-access commands.
- *
- * These mirror the backend `FeatureToggle` keys and are the values passed to
- * `CommandConfig.earlyAccess(...)`. Keeping them here gives a single place to
- * see every early-access feature key even though the wiring lives on the
- * individual commands.
- */
-export const EarlyAccessFeature = {
-    BRANCHING: "pacman.branching",
-} as const;
- 
-export type EarlyAccessFeatureKey = (typeof EarlyAccessFeature)[keyof typeof EarlyAccessFeature];
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/lcov-report/feature-flag/feature-flag.service.ts.html b/coverage/lcov-report/feature-flag/feature-flag.service.ts.html deleted file mode 100644 index c802b434..00000000 --- a/coverage/lcov-report/feature-flag/feature-flag.service.ts.html +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - Code coverage report for feature-flag/feature-flag.service.ts - - - - - - - - - -
-
-

All files / feature-flag feature-flag.service.ts

-
- -
- 100% - Statements - 34/34 -
- - -
- 100% - Branches - 10/10 -
- - -
- 100% - Functions - 3/3 -
- - -
- 100% - Lines - 34/34 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -351x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -1x -13x -13x -1x -1x -13x -13x -13x -1x - 
import { Context } from "../command/cli-context";
-import { HttpClient } from "../http/http-client";
- 
-/**
- * A backend ("paid") feature flag as returned by the team-features endpoint.
- * Only the key is needed here — presence in the list means the flag is enabled
- * for the calling team.
- */
-interface TeamFeature {
-    key: string;
-}
- 
-/**
- * Queries whether a backend feature flag is enabled for the current team.
- *
- * Uses the same endpoint the web frontend relies on to resolve backend/per-team
- * ("paid") feature flags: `GET /api/team/features` returns the list of flags
- * enabled for the team behind the profile's token. A flag is considered enabled
- * when an entry with a matching key is present in that list.
- */
-export class FeatureFlagService {
-    private static readonly TEAM_FEATURES_URL = "/api/team/features";
- 
-    private httpClient: () => HttpClient;
- 
-    constructor(context: Context) {
-        this.httpClient = () => context.httpClient;
-    }
- 
-    public async isEnabled(featureKey: string): Promise<boolean> {
-        const features: TeamFeature[] = await this.httpClient().get(FeatureFlagService.TEAM_FEATURES_URL);
-        return Array.isArray(features) && features.some(feature => feature?.key === featureKey);
-    }
-}
- 
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/lcov-report/feature-flag/index.html b/coverage/lcov-report/feature-flag/index.html deleted file mode 100644 index 7409122d..00000000 --- a/coverage/lcov-report/feature-flag/index.html +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - Code coverage report for feature-flag - - - - - - - - - -
-
-

All files feature-flag

-
- -
- 100% - Statements - 47/47 -
- - -
- 100% - Branches - 10/10 -
- - -
- 100% - Functions - 3/3 -
- - -
- 100% - Lines - 47/47 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
early-access-features.ts -
-
100%13/13100%0/0100%0/0100%13/13
feature-flag.service.ts -
-
100%34/34100%10/10100%3/3100%34/34
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/lcov-report/index.html b/coverage/lcov-report/index.html deleted file mode 100644 index 6b4239b2..00000000 --- a/coverage/lcov-report/index.html +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - Code coverage report for All files - - - - - - - - - -
-
-

All files

-
- -
- 71.74% - Statements - 226/315 -
- - -
- 100% - Branches - 47/47 -
- - -
- 89.47% - Functions - 17/19 -
- - -
- 71.74% - Lines - 226/315 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
command -
-
66.79%179/268100%37/3787.5%14/1666.79%179/268
feature-flag -
-
100%47/47100%10/10100%3/3100%47/47
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/lcov-report/prettify.css b/coverage/lcov-report/prettify.css deleted file mode 100644 index b317a7cd..00000000 --- a/coverage/lcov-report/prettify.css +++ /dev/null @@ -1 +0,0 @@ -.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} diff --git a/coverage/lcov-report/prettify.js b/coverage/lcov-report/prettify.js deleted file mode 100644 index b3225238..00000000 --- a/coverage/lcov-report/prettify.js +++ /dev/null @@ -1,2 +0,0 @@ -/* eslint-disable */ -window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); diff --git a/coverage/lcov-report/sort-arrow-sprite.png b/coverage/lcov-report/sort-arrow-sprite.png deleted file mode 100644 index 6ed68316eb3f65dec9063332d2f69bf3093bbfab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^>_9Bd!3HEZxJ@+%Qh}Z>jv*C{$p!i!8j}?a+@3A= zIAGwzjijN=FBi!|L1t?LM;Q;gkwn>2cAy-KV{dn nf0J1DIvEHQu*n~6U}x}qyky7vi4|9XhBJ7&`njxgN@xNA8m%nc diff --git a/coverage/lcov-report/sorter.js b/coverage/lcov-report/sorter.js deleted file mode 100644 index 2bb296a8..00000000 --- a/coverage/lcov-report/sorter.js +++ /dev/null @@ -1,196 +0,0 @@ -/* eslint-disable */ -var addSorting = (function() { - 'use strict'; - var cols, - currentSort = { - index: 0, - desc: false - }; - - // returns the summary table element - function getTable() { - return document.querySelector('.coverage-summary'); - } - // returns the thead element of the summary table - function getTableHeader() { - return getTable().querySelector('thead tr'); - } - // returns the tbody element of the summary table - function getTableBody() { - return getTable().querySelector('tbody'); - } - // returns the th element for nth column - function getNthColumn(n) { - return getTableHeader().querySelectorAll('th')[n]; - } - - function onFilterInput() { - const searchValue = document.getElementById('fileSearch').value; - const rows = document.getElementsByTagName('tbody')[0].children; - for (let i = 0; i < rows.length; i++) { - const row = rows[i]; - if ( - row.textContent - .toLowerCase() - .includes(searchValue.toLowerCase()) - ) { - row.style.display = ''; - } else { - row.style.display = 'none'; - } - } - } - - // loads the search box - function addSearchBox() { - var template = document.getElementById('filterTemplate'); - var templateClone = template.content.cloneNode(true); - templateClone.getElementById('fileSearch').oninput = onFilterInput; - template.parentElement.appendChild(templateClone); - } - - // loads all columns - function loadColumns() { - var colNodes = getTableHeader().querySelectorAll('th'), - colNode, - cols = [], - col, - i; - - for (i = 0; i < colNodes.length; i += 1) { - colNode = colNodes[i]; - col = { - key: colNode.getAttribute('data-col'), - sortable: !colNode.getAttribute('data-nosort'), - type: colNode.getAttribute('data-type') || 'string' - }; - cols.push(col); - if (col.sortable) { - col.defaultDescSort = col.type === 'number'; - colNode.innerHTML = - colNode.innerHTML + ''; - } - } - return cols; - } - // attaches a data attribute to every tr element with an object - // of data values keyed by column name - function loadRowData(tableRow) { - var tableCols = tableRow.querySelectorAll('td'), - colNode, - col, - data = {}, - i, - val; - for (i = 0; i < tableCols.length; i += 1) { - colNode = tableCols[i]; - col = cols[i]; - val = colNode.getAttribute('data-value'); - if (col.type === 'number') { - val = Number(val); - } - data[col.key] = val; - } - return data; - } - // loads all row data - function loadData() { - var rows = getTableBody().querySelectorAll('tr'), - i; - - for (i = 0; i < rows.length; i += 1) { - rows[i].data = loadRowData(rows[i]); - } - } - // sorts the table using the data for the ith column - function sortByIndex(index, desc) { - var key = cols[index].key, - sorter = function(a, b) { - a = a.data[key]; - b = b.data[key]; - return a < b ? -1 : a > b ? 1 : 0; - }, - finalSorter = sorter, - tableBody = document.querySelector('.coverage-summary tbody'), - rowNodes = tableBody.querySelectorAll('tr'), - rows = [], - i; - - if (desc) { - finalSorter = function(a, b) { - return -1 * sorter(a, b); - }; - } - - for (i = 0; i < rowNodes.length; i += 1) { - rows.push(rowNodes[i]); - tableBody.removeChild(rowNodes[i]); - } - - rows.sort(finalSorter); - - for (i = 0; i < rows.length; i += 1) { - tableBody.appendChild(rows[i]); - } - } - // removes sort indicators for current column being sorted - function removeSortIndicators() { - var col = getNthColumn(currentSort.index), - cls = col.className; - - cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); - col.className = cls; - } - // adds sort indicators for current column being sorted - function addSortIndicators() { - getNthColumn(currentSort.index).className += currentSort.desc - ? ' sorted-desc' - : ' sorted'; - } - // adds event listeners for all sorter widgets - function enableUI() { - var i, - el, - ithSorter = function ithSorter(i) { - var col = cols[i]; - - return function() { - var desc = col.defaultDescSort; - - if (currentSort.index === i) { - desc = !currentSort.desc; - } - sortByIndex(i, desc); - removeSortIndicators(); - currentSort.index = i; - currentSort.desc = desc; - addSortIndicators(); - }; - }; - for (i = 0; i < cols.length; i += 1) { - if (cols[i].sortable) { - // add the click event handler on the th so users - // dont have to click on those tiny arrows - el = getNthColumn(i).querySelector('.sorter').parentElement; - if (el.addEventListener) { - el.addEventListener('click', ithSorter(i)); - } else { - el.attachEvent('onclick', ithSorter(i)); - } - } - } - } - // adds sorting functionality to the UI - return function() { - if (!getTable()) { - return; - } - cols = loadColumns(); - loadData(); - addSearchBox(); - addSortIndicators(); - enableUI(); - }; -})(); - -window.addEventListener('load', addSorting); diff --git a/coverage/lcov.info b/coverage/lcov.info deleted file mode 100644 index 018ef678..00000000 --- a/coverage/lcov.info +++ /dev/null @@ -1,427 +0,0 @@ -TN: -SF:src/core/command/module-handler.ts -FN:17,ModuleHandler -FN:34,discoverAndRegisterModules -FN:131,Configurator -FN:141,command -FN:159,CommandConfig -FN:164,command -FN:169,alias -FN:174,description -FN:179,argument -FN:184,option -FN:189,requiredOption -FN:194,deprecationNotice -FN:205,earlyAccess -FN:213,action -FN:230,printDeprecationNoticeIfDeprecated -FN:242,checkEarlyAccessFeatureFlag -FNF:16 -FNH:14 -FNDA:80,ModuleHandler -FNDA:0,discoverAndRegisterModules -FNDA:87,Configurator -FNDA:227,command -FNDA:1923,CommandConfig -FNDA:1756,command -FNDA:80,alias -FNDA:1913,description -FNDA:0,argument -FNDA:6460,option -FNDA:1465,requiredOption -FNDA:300,deprecationNotice -FNDA:8,earlyAccess -FNDA:1389,action -FNDA:85,printDeprecationNoticeIfDeprecated -FNDA:85,checkEarlyAccessFeatureFlag -DA:1,1 -DA:2,1 -DA:3,1 -DA:4,1 -DA:5,1 -DA:6,1 -DA:7,1 -DA:8,1 -DA:9,1 -DA:10,1 -DA:11,1 -DA:12,1 -DA:13,1 -DA:14,1 -DA:15,1 -DA:16,1 -DA:17,1 -DA:18,80 -DA:19,80 -DA:20,80 -DA:21,80 -DA:22,80 -DA:23,1 -DA:24,1 -DA:25,1 -DA:26,1 -DA:27,1 -DA:28,1 -DA:29,1 -DA:30,1 -DA:31,1 -DA:32,1 -DA:33,1 -DA:34,1 -DA:35,0 -DA:36,0 -DA:37,0 -DA:38,0 -DA:39,0 -DA:40,0 -DA:41,0 -DA:42,0 -DA:43,0 -DA:44,0 -DA:45,0 -DA:46,0 -DA:47,0 -DA:48,0 -DA:49,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:53,0 -DA:54,0 -DA:55,0 -DA:56,0 -DA:57,0 -DA:58,0 -DA:59,0 -DA:60,0 -DA:61,0 -DA:62,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:66,0 -DA:67,0 -DA:68,0 -DA:69,0 -DA:70,0 -DA:71,0 -DA:72,0 -DA:73,0 -DA:74,0 -DA:75,0 -DA:76,0 -DA:77,0 -DA:78,0 -DA:79,0 -DA:80,0 -DA:81,0 -DA:82,0 -DA:83,0 -DA:84,0 -DA:85,0 -DA:86,0 -DA:87,0 -DA:88,0 -DA:89,0 -DA:90,0 -DA:91,0 -DA:92,0 -DA:93,0 -DA:94,0 -DA:95,0 -DA:96,0 -DA:97,0 -DA:98,0 -DA:99,0 -DA:100,0 -DA:101,0 -DA:102,0 -DA:103,0 -DA:104,0 -DA:105,0 -DA:106,0 -DA:107,0 -DA:108,0 -DA:109,0 -DA:110,0 -DA:111,0 -DA:112,0 -DA:113,0 -DA:114,0 -DA:115,0 -DA:116,0 -DA:117,0 -DA:118,0 -DA:119,0 -DA:120,0 -DA:121,1 -DA:122,1 -DA:123,1 -DA:124,1 -DA:125,1 -DA:126,1 -DA:127,1 -DA:128,1 -DA:129,1 -DA:130,1 -DA:131,1 -DA:132,87 -DA:133,87 -DA:134,87 -DA:135,1 -DA:136,1 -DA:137,1 -DA:138,1 -DA:139,1 -DA:140,1 -DA:141,1 -DA:142,227 -DA:143,60 -DA:144,60 -DA:145,167 -DA:146,167 -DA:147,167 -DA:148,167 -DA:149,167 -DA:150,1 -DA:151,1 -DA:152,1 -DA:153,1 -DA:154,1 -DA:155,1 -DA:156,1 -DA:157,1 -DA:158,1 -DA:159,1 -DA:160,1923 -DA:161,1923 -DA:162,1923 -DA:163,1 -DA:164,1 -DA:165,1756 -DA:166,1756 -DA:167,1756 -DA:168,1 -DA:169,1 -DA:170,80 -DA:171,80 -DA:172,80 -DA:173,1 -DA:174,1 -DA:175,1913 -DA:176,1913 -DA:177,1913 -DA:178,1 -DA:179,1 -DA:180,0 -DA:181,0 -DA:182,0 -DA:183,1 -DA:184,1 -DA:185,6460 -DA:186,6460 -DA:187,6460 -DA:188,1 -DA:189,1 -DA:190,1465 -DA:191,1465 -DA:192,1465 -DA:193,1 -DA:194,1 -DA:195,300 -DA:196,300 -DA:197,300 -DA:198,1 -DA:199,1 -DA:200,1 -DA:201,1 -DA:202,1 -DA:203,1 -DA:204,1 -DA:205,1 -DA:206,8 -DA:207,8 -DA:208,7 -DA:209,7 -DA:210,8 -DA:211,8 -DA:212,1 -DA:213,1 -DA:214,1389 -DA:215,85 -DA:216,85 -DA:217,85 -DA:218,80 -DA:219,85 -DA:220,30 -DA:221,6 -DA:222,6 -DA:223,6 -DA:224,24 -DA:225,24 -DA:226,24 -DA:227,1389 -DA:228,1389 -DA:229,1 -DA:230,1 -DA:231,85 -DA:232,31 -DA:233,31 -DA:234,85 -DA:235,1 -DA:236,1 -DA:237,1 -DA:238,1 -DA:239,1 -DA:240,1 -DA:241,1 -DA:242,1 -DA:243,85 -DA:244,85 -DA:245,78 -DA:246,78 -DA:247,7 -DA:248,7 -DA:249,7 -DA:250,7 -DA:251,5 -DA:252,3 -DA:253,3 -DA:254,3 -DA:255,1 -DA:256,1 -DA:257,2 -DA:258,2 -DA:259,2 -DA:260,2 -DA:261,4 -DA:262,10 -DA:263,2 -DA:264,2 -DA:265,2 -DA:266,2 -DA:267,85 -DA:268,1 -LF:268 -LH:179 -BRDA:17,0,0,80 -BRDA:131,1,0,87 -BRDA:141,2,0,227 -BRDA:142,3,0,60 -BRDA:145,4,0,167 -BRDA:159,5,0,1923 -BRDA:164,6,0,1756 -BRDA:169,7,0,80 -BRDA:174,8,0,1913 -BRDA:184,9,0,6460 -BRDA:189,10,0,1465 -BRDA:194,11,0,300 -BRDA:205,12,0,8 -BRDA:207,13,0,7 -BRDA:213,14,0,1389 -BRDA:214,15,0,85 -BRDA:214,16,0,85 -BRDA:218,17,0,83 -BRDA:218,18,0,80 -BRDA:219,19,0,55 -BRDA:219,20,0,30 -BRDA:220,21,0,29 -BRDA:220,22,0,6 -BRDA:224,23,0,24 -BRDA:230,24,0,85 -BRDA:231,25,0,31 -BRDA:242,26,0,85 -BRDA:244,27,0,78 -BRDA:247,28,0,10 -BRDA:247,29,0,7 -BRDA:251,30,0,5 -BRDA:251,31,0,4 -BRDA:251,32,0,3 -BRDA:254,33,0,2 -BRDA:254,34,0,1 -BRDA:261,35,0,4 -BRDA:262,36,0,2 -BRF:37 -BRH:37 -end_of_record -TN: -SF:src/core/feature-flag/early-access-features.ts -FNF:0 -FNH:0 -DA:1,1 -DA:2,1 -DA:3,1 -DA:4,1 -DA:5,1 -DA:6,1 -DA:7,1 -DA:8,1 -DA:9,1 -DA:10,1 -DA:11,1 -DA:12,1 -DA:13,1 -LF:13 -LH:13 -BRF:0 -BRH:0 -end_of_record -TN: -SF:src/core/feature-flag/feature-flag.service.ts -FN:26,FeatureFlagService -FN:27,FeatureFlagService.httpClient -FN:30,isEnabled -FNF:3 -FNH:3 -FNDA:13,FeatureFlagService -FNDA:13,FeatureFlagService.httpClient -FNDA:13,isEnabled -DA:1,1 -DA:2,1 -DA:3,1 -DA:4,1 -DA:5,1 -DA:6,1 -DA:7,1 -DA:8,1 -DA:9,1 -DA:10,1 -DA:11,1 -DA:12,1 -DA:13,1 -DA:14,1 -DA:15,1 -DA:16,1 -DA:17,1 -DA:18,1 -DA:19,1 -DA:20,1 -DA:21,1 -DA:22,1 -DA:23,1 -DA:24,1 -DA:25,1 -DA:26,1 -DA:27,13 -DA:28,13 -DA:29,1 -DA:30,1 -DA:31,13 -DA:32,13 -DA:33,13 -DA:34,1 -LF:34 -LH:34 -BRDA:26,0,0,13 -BRDA:27,1,0,13 -BRDA:30,2,0,13 -BRDA:32,3,0,10 -BRDA:32,4,0,9 -BRDA:32,5,0,8 -BRDA:32,6,0,6 -BRDA:32,7,0,5 -BRDA:32,8,0,1 -BRDA:32,9,0,5 -BRF:10 -BRH:10 -end_of_record diff --git a/coverage/prettify.css b/coverage/prettify.css deleted file mode 100644 index b317a7cd..00000000 --- a/coverage/prettify.css +++ /dev/null @@ -1 +0,0 @@ -.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} diff --git a/coverage/prettify.js b/coverage/prettify.js deleted file mode 100644 index b3225238..00000000 --- a/coverage/prettify.js +++ /dev/null @@ -1,2 +0,0 @@ -/* eslint-disable */ -window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); diff --git a/coverage/sort-arrow-sprite.png b/coverage/sort-arrow-sprite.png deleted file mode 100644 index 6ed68316eb3f65dec9063332d2f69bf3093bbfab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^>_9Bd!3HEZxJ@+%Qh}Z>jv*C{$p!i!8j}?a+@3A= zIAGwzjijN=FBi!|L1t?LM;Q;gkwn>2cAy-KV{dn nf0J1DIvEHQu*n~6U}x}qyky7vi4|9XhBJ7&`njxgN@xNA8m%nc diff --git a/coverage/sorter.js b/coverage/sorter.js deleted file mode 100644 index 2bb296a8..00000000 --- a/coverage/sorter.js +++ /dev/null @@ -1,196 +0,0 @@ -/* eslint-disable */ -var addSorting = (function() { - 'use strict'; - var cols, - currentSort = { - index: 0, - desc: false - }; - - // returns the summary table element - function getTable() { - return document.querySelector('.coverage-summary'); - } - // returns the thead element of the summary table - function getTableHeader() { - return getTable().querySelector('thead tr'); - } - // returns the tbody element of the summary table - function getTableBody() { - return getTable().querySelector('tbody'); - } - // returns the th element for nth column - function getNthColumn(n) { - return getTableHeader().querySelectorAll('th')[n]; - } - - function onFilterInput() { - const searchValue = document.getElementById('fileSearch').value; - const rows = document.getElementsByTagName('tbody')[0].children; - for (let i = 0; i < rows.length; i++) { - const row = rows[i]; - if ( - row.textContent - .toLowerCase() - .includes(searchValue.toLowerCase()) - ) { - row.style.display = ''; - } else { - row.style.display = 'none'; - } - } - } - - // loads the search box - function addSearchBox() { - var template = document.getElementById('filterTemplate'); - var templateClone = template.content.cloneNode(true); - templateClone.getElementById('fileSearch').oninput = onFilterInput; - template.parentElement.appendChild(templateClone); - } - - // loads all columns - function loadColumns() { - var colNodes = getTableHeader().querySelectorAll('th'), - colNode, - cols = [], - col, - i; - - for (i = 0; i < colNodes.length; i += 1) { - colNode = colNodes[i]; - col = { - key: colNode.getAttribute('data-col'), - sortable: !colNode.getAttribute('data-nosort'), - type: colNode.getAttribute('data-type') || 'string' - }; - cols.push(col); - if (col.sortable) { - col.defaultDescSort = col.type === 'number'; - colNode.innerHTML = - colNode.innerHTML + ''; - } - } - return cols; - } - // attaches a data attribute to every tr element with an object - // of data values keyed by column name - function loadRowData(tableRow) { - var tableCols = tableRow.querySelectorAll('td'), - colNode, - col, - data = {}, - i, - val; - for (i = 0; i < tableCols.length; i += 1) { - colNode = tableCols[i]; - col = cols[i]; - val = colNode.getAttribute('data-value'); - if (col.type === 'number') { - val = Number(val); - } - data[col.key] = val; - } - return data; - } - // loads all row data - function loadData() { - var rows = getTableBody().querySelectorAll('tr'), - i; - - for (i = 0; i < rows.length; i += 1) { - rows[i].data = loadRowData(rows[i]); - } - } - // sorts the table using the data for the ith column - function sortByIndex(index, desc) { - var key = cols[index].key, - sorter = function(a, b) { - a = a.data[key]; - b = b.data[key]; - return a < b ? -1 : a > b ? 1 : 0; - }, - finalSorter = sorter, - tableBody = document.querySelector('.coverage-summary tbody'), - rowNodes = tableBody.querySelectorAll('tr'), - rows = [], - i; - - if (desc) { - finalSorter = function(a, b) { - return -1 * sorter(a, b); - }; - } - - for (i = 0; i < rowNodes.length; i += 1) { - rows.push(rowNodes[i]); - tableBody.removeChild(rowNodes[i]); - } - - rows.sort(finalSorter); - - for (i = 0; i < rows.length; i += 1) { - tableBody.appendChild(rows[i]); - } - } - // removes sort indicators for current column being sorted - function removeSortIndicators() { - var col = getNthColumn(currentSort.index), - cls = col.className; - - cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); - col.className = cls; - } - // adds sort indicators for current column being sorted - function addSortIndicators() { - getNthColumn(currentSort.index).className += currentSort.desc - ? ' sorted-desc' - : ' sorted'; - } - // adds event listeners for all sorter widgets - function enableUI() { - var i, - el, - ithSorter = function ithSorter(i) { - var col = cols[i]; - - return function() { - var desc = col.defaultDescSort; - - if (currentSort.index === i) { - desc = !currentSort.desc; - } - sortByIndex(i, desc); - removeSortIndicators(); - currentSort.index = i; - currentSort.desc = desc; - addSortIndicators(); - }; - }; - for (i = 0; i < cols.length; i += 1) { - if (cols[i].sortable) { - // add the click event handler on the th so users - // dont have to click on those tiny arrows - el = getNthColumn(i).querySelector('.sorter').parentElement; - if (el.addEventListener) { - el.addEventListener('click', ithSorter(i)); - } else { - el.attachEvent('onclick', ithSorter(i)); - } - } - } - } - // adds sorting functionality to the UI - return function() { - if (!getTable()) { - return; - } - cols = loadColumns(); - loadData(); - addSearchBox(); - addSortIndicators(); - enableUI(); - }; -})(); - -window.addEventListener('load', addSorting); From 3110e6509668fee7a762dc82e53f4d802c6ee5dd Mon Sep 17 00:00:00 2001 From: "A. Jashari" <63860906+admirjashari@users.noreply.github.com> Date: Thu, 9 Jul 2026 14:58:49 +0200 Subject: [PATCH 4/6] Apply suggestion from @tneum-celonis MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Thomas Neumüller --- src/core/command/module-handler.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/command/module-handler.ts b/src/core/command/module-handler.ts index 4575f898..0c0f2292 100644 --- a/src/core/command/module-handler.ts +++ b/src/core/command/module-handler.ts @@ -203,9 +203,10 @@ export class CommandConfig { * enabled for the team, and stops with a clear message if it is not. */ public earlyAccess(featureKey?: string): CommandConfig { - (this.cmd as any).isEarlyAccess = true; + const command = this.cmd as any + command.isEarlyAccess = true; if (featureKey) { - (this.cmd as any).earlyAccessFeatureKey = featureKey; + command.earlyAccessFeatureKey = featureKey; } return this; } From dccf046a157e0498a3613ae17b69f5b2dec574ee Mon Sep 17 00:00:00 2001 From: "a.jashari" Date: Thu, 9 Jul 2026 15:13:16 +0200 Subject: [PATCH 5/6] SP-1383: address SonarCloud findings (readonly field, this return type) Co-Authored-By: Claude Opus 4.8 --- src/core/command/module-handler.ts | 2 +- src/core/feature-flag/feature-flag.service.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/command/module-handler.ts b/src/core/command/module-handler.ts index 0c0f2292..31abe707 100644 --- a/src/core/command/module-handler.ts +++ b/src/core/command/module-handler.ts @@ -202,7 +202,7 @@ export class CommandConfig { * before it executes, the CLI checks whether that backend feature flag is * enabled for the team, and stops with a clear message if it is not. */ - public earlyAccess(featureKey?: string): CommandConfig { + public earlyAccess(featureKey?: string): this { const command = this.cmd as any command.isEarlyAccess = true; if (featureKey) { diff --git a/src/core/feature-flag/feature-flag.service.ts b/src/core/feature-flag/feature-flag.service.ts index 8ff26682..61ae4a7d 100644 --- a/src/core/feature-flag/feature-flag.service.ts +++ b/src/core/feature-flag/feature-flag.service.ts @@ -21,7 +21,7 @@ interface TeamFeature { export class FeatureFlagService { private static readonly TEAM_FEATURES_URL = "/api/team/features"; - private httpClient: () => HttpClient; + private readonly httpClient: () => HttpClient; constructor(context: Context) { this.httpClient = () => context.httpClient; From ae34eae98ccb46ee61ab23daa6e2cebe697cefd9 Mon Sep 17 00:00:00 2001 From: "a.jashari" Date: Thu, 9 Jul 2026 15:52:43 +0200 Subject: [PATCH 6/6] SP-1383: cover deployment module register() to fix new-code coverage Co-Authored-By: Claude Opus 4.8 --- tests/commands/deployment/module.spec.ts | 44 ++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 tests/commands/deployment/module.spec.ts diff --git a/tests/commands/deployment/module.spec.ts b/tests/commands/deployment/module.spec.ts new file mode 100644 index 00000000..7b370709 --- /dev/null +++ b/tests/commands/deployment/module.spec.ts @@ -0,0 +1,44 @@ +import Module = require("../../../src/commands/deployment/module"); +import { testContext } from "../../utls/test-context"; +import { createMockConfigurator } from "../../utls/configurator-mock"; + +describe("Deployment Module", () => { + describe("register", () => { + it("registers the deployment command groups without throwing", () => { + const mockConfigurator = createMockConfigurator(); + + expect(() => new Module().register(testContext, mockConfigurator)).not.toThrow(); + + expect(mockConfigurator.command).toHaveBeenCalledWith("deployment"); + expect(mockConfigurator.command).toHaveBeenCalledWith("create"); + expect(mockConfigurator.command).toHaveBeenCalledWith("list"); + expect(mockConfigurator.command).toHaveBeenCalledWith("history"); + expect(mockConfigurator.command).toHaveBeenCalledWith("active"); + expect(mockConfigurator.command).toHaveBeenCalledWith("deployables"); + expect(mockConfigurator.command).toHaveBeenCalledWith("targets"); + }); + + it("marks every deployment command as early access", () => { + const mockConfigurator = createMockConfigurator(); + + new Module().register(testContext, mockConfigurator); + + // deployment, create, list, history, active, deployables, targets + const expectedEarlyAccessCommands = 7; + expect(mockConfigurator.earlyAccess).toHaveBeenCalledTimes(expectedEarlyAccessCommands); + }); + + it("wires an action handler for every leaf subcommand", () => { + const mockConfigurator = createMockConfigurator(); + + new Module().register(testContext, mockConfigurator); + + // create, history, active, deployables, targets + const expectedLeafCommands = 5; + expect(mockConfigurator.action).toHaveBeenCalledTimes(expectedLeafCommands); + for (const call of mockConfigurator.action.mock.calls) { + expect(typeof call[0]).toBe("function"); + } + }); + }); +});