Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP feat(onboarding): dont throw error for unknown presets #140

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 65 additions & 38 deletions src/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ import type {
PresetField,
ProgressState,
ReachElementParams,
CommonPreset,
EventsMap,
EventTypes,
PresetStatus,
ResolvedOptions,
UserPreset,
} from './types';
import {CommonPreset, EventsMap, EventTypes, PresetStatus, ResolvedOptions} from './types';
import {HintStore} from './hints/hintStore';
import {createLogger, Logger} from './logger';
import {createDebounceHandler} from './debounce';
Expand Down Expand Up @@ -362,27 +367,32 @@ export class Controller<HintParams, Presets extends string, Steps extends string

const userExistedPresetSlugs = allUserPresetSlugs.filter(this.isVisiblePreset) as Presets[];

return userExistedPresetSlugs.map((presetSlug) => {
let status: PresetStatus = 'unPassed';
return userExistedPresetSlugs
.map((presetSlug) => {
let status: PresetStatus = 'unPassed';

const slug = this.resolvePresetSlug(presetSlug);
const slug = this.resolvePresetSlug(presetSlug);

if (this.state.base.activePresets.includes(slug)) {
status = 'inProgress';
} else if (this.state.progress?.finishedPresets.includes(slug)) {
status = 'finished';
}
if (!slug) {
status = 'unPassed';
} else if (this.state.base.activePresets.includes(slug)) {
status = 'inProgress';
} else if (this.state.progress?.finishedPresets.includes(slug)) {
status = 'finished';
}

return {
slug: presetSlug,
name: (this.options.config.presets[presetSlug] as CommonPreset<HintParams, Steps>)
.name,
description: (
this.options.config.presets[presetSlug] as CommonPreset<HintParams, Steps>
).description,
status,
};
});
return {
slug: presetSlug,
name: (
this.options.config.presets[presetSlug] as CommonPreset<HintParams, Steps>
).name,
description: (
this.options.config.presets[presetSlug] as CommonPreset<HintParams, Steps>
).description,
status,
};
})
.filter((userPreset) => Boolean(userPreset)) as UserPreset<Presets>[];
}

addPreset = async (presetArg: string | string[]) => {
Expand Down Expand Up @@ -410,21 +420,23 @@ export class Controller<HintParams, Presets extends string, Steps extends string

if (this.state.base.suggestedPresets.includes(preset)) {
this.logger.debug('Preset has already been suggested', preset);
return;
return false;
}

const allowRun = await this.events.emit('beforeSuggestPreset', {preset});

if (!allowRun) {
this.logger.debug('Preset suggestion cancelled', preset);
return;
return false;
}

await this.runPreset(preset);
return this.runPreset(preset);
};

runPreset = async (presetToRunSlug: string) => {
this.ensurePresetExists(presetToRunSlug);
if (!this.ensurePresetExists(presetToRunSlug)) {
return false;
}

const presetToRun = this.options.config.presets[presetToRunSlug];
const presetSlug = (
Expand All @@ -433,7 +445,7 @@ export class Controller<HintParams, Presets extends string, Steps extends string

this.logger.debug('Running preset', presetSlug);

await this.options.config.presets[presetToRunSlug].hooks?.onBeforeStart?.();
await presetToRun.hooks?.onBeforeStart?.();
if (presetSlug !== presetToRunSlug) {
await this.options.config.presets[presetSlug].hooks?.onBeforeStart?.();
}
Expand All @@ -445,7 +457,7 @@ export class Controller<HintParams, Presets extends string, Steps extends string
}

if (this.state.base.activePresets.includes(presetSlug)) {
return;
return false;
}

this.state.base.activePresets.push(presetSlug);
Expand All @@ -465,7 +477,7 @@ export class Controller<HintParams, Presets extends string, Steps extends string
});

this.events.emit('runPreset', {preset: presetSlug});
this.options.config.presets[presetToRunSlug].hooks?.onStart?.();
presetToRun.hooks?.onStart?.();
if (presetSlug !== presetToRunSlug) {
this.options.config.presets[presetSlug].hooks?.onStart?.();
}
Expand All @@ -474,11 +486,18 @@ export class Controller<HintParams, Presets extends string, Steps extends string

await this.updateBaseState();
this.logger.debug('Preset ran', presetSlug);

return true;
};

finishPreset = async (presetToFinish: Presets, shouldSave = true) => {
// take normal or find internal
const presetSlug = this.resolvePresetSlug(presetToFinish);
if (!presetSlug) {
return false;
}
this.ensurePresetExists(presetToFinish);

this.logger.debug('Preset finished', presetToFinish);

this.events.emit('finishPreset', {preset: presetSlug});
Expand All @@ -504,6 +523,8 @@ export class Controller<HintParams, Presets extends string, Steps extends string
await this.updateBaseState();
await this.updateProgress();
}

return true;
};

resetPresetProgress = async (
Expand All @@ -516,7 +537,9 @@ export class Controller<HintParams, Presets extends string, Steps extends string

const presets = this.filterExistedPresets(
Array.isArray(presetArg) ? presetArg : [presetArg],
).map((preset) => this.resolvePresetSlug(preset));
)
.map((preset) => this.resolvePresetSlug(preset))
.filter((preset) => Boolean(preset)) as Presets[];

this.state.progress.finishedPresets = this.state.progress.finishedPresets.filter(
(preset) => !presets.includes(preset as Presets),
Expand Down Expand Up @@ -613,7 +636,10 @@ export class Controller<HintParams, Presets extends string, Steps extends string
}
}

private resolvePresetSlug = (presetSlug: Presets) => {
private resolvePresetSlug = (presetSlug: string) => {
if (!this.ensurePresetExists(presetSlug)) {
return undefined;
}
const preset = this.options.config.presets[presetSlug];

return preset.type === 'combined' ? this.findInternalPreset(presetSlug) : presetSlug;
Expand All @@ -623,16 +649,16 @@ export class Controller<HintParams, Presets extends string, Steps extends string
const preset = this.options.config.presets[presetSlug];

if (preset.type !== 'combined') {
throw new Error('not internal preset');
return undefined;
}

const activeInternalPreset = this.state.base.activePresets.find((activePreset) =>
preset.internalPresets.includes(activePreset),
) as Presets;
) as Presets | undefined;

const finishedInternalPreset = this.state.progress?.finishedPresets.find((finishedPreset) =>
preset.internalPresets.includes(finishedPreset),
) as Presets;
) as Presets | undefined;

return activeInternalPreset || finishedInternalPreset;
};
Expand All @@ -643,12 +669,12 @@ export class Controller<HintParams, Presets extends string, Steps extends string
};

private isVisiblePreset = (presetSlug: string) => {
const preset = this.options.config.presets[presetSlug as Presets];

if (!preset) {
if (!this.ensurePresetExists(presetSlug)) {
return false;
}

const preset = this.options.config.presets[presetSlug];

const isInternal = preset.type === 'internal';
if (isInternal) {
return false;
Expand Down Expand Up @@ -786,13 +812,14 @@ export class Controller<HintParams, Presets extends string, Steps extends string
await this.saveBaseState();
}

private ensurePresetExists(preset: string): asserts preset is Presets {
// @ts-ignore
if (!this.options.config.presets[preset]) {
private ensurePresetExists(preset: string): preset is Presets {
if (!(preset in this.options.config.presets)) {
this.logger.error('No preset in config', preset);

throw new Error('No preset in config');
return false;
}

return true;
}

private assertProgressLoaded(): asserts this is this & {
Expand Down
4 changes: 3 additions & 1 deletion src/tests/commonPresets.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ describe('preset management', function () {
it('preset not from config -> nothing', async function () {
const controller = new Controller(options);

expect(controller.runPreset('createQueue123')).rejects.toThrow();
const result = await controller.runPreset('createQueue123');

expect(result).toBe(false);
expect(options.onSave.state).not.toHaveBeenCalled();
expect(options.onSave.progress).not.toHaveBeenCalled();
});
Expand Down
27 changes: 9 additions & 18 deletions src/tests/controller.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,33 +215,24 @@ describe('wrong data', function () {
expect(options.logger.logger.error).not.toHaveBeenCalled();
});

it('suggest not existed preset -> error', async function () {
expect.assertions(2);

it('suggest not existed preset -> афдыу', async function () {
const options = getOptions();
const controller = new Controller(options);

try {
await controller.suggestPresetOnce('unknownPreset');
} catch (e: unknown) {
// @ts-ignore
expect(e.message).toBe('No preset in config');
const result = await controller.suggestPresetOnce('unknownPreset');

expect(options.logger.logger.error).toHaveBeenCalled();
}
expect(result).toBe(false);
expect(options.logger.logger.error).toHaveBeenCalled();
});

it('run not existed preset -> throw error', async function () {
expect.assertions(1);

it('run not existed preset -> return false', async function () {
const options = getOptions();
const controller = new Controller(options);

try {
await controller.runPreset('unknownPreset');
} catch (e) {
expect(options.logger.logger.error).toHaveBeenCalled();
}
const result = await controller.runPreset('unknownPreset');

expect(result).toBe(false);
expect(options.logger.logger.error).toHaveBeenCalled();
});

it('reach not existed step', async function () {
Expand Down
7 changes: 7 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@ export type CombinedPreset<InternalPresets extends string> = {
pickPreset: () => InternalPresets | Promise<InternalPresets>;
};

export type UserPreset<Presets extends string> = {
slug: Presets;
name: string;
description: string;
status: PresetStatus;
};

export type PresetFunctions = {
goNextStep: VoidFn;
goPrevStep: VoidFn;
Expand Down
Loading