Skip to content

Commit 77f402f

Browse files
committed
[revert] move NestedWizard logic to Wizard class
1 parent 83cc0ff commit 77f402f

File tree

4 files changed

+80
-58
lines changed

4 files changed

+80
-58
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*!
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import { Wizard, WizardOptions } from '../wizards/wizard'
7+
import { Prompter } from './prompter'
8+
import { WizardPrompter } from './wizardPrompter'
9+
import { createHash } from 'crypto'
10+
11+
/**
12+
* An abstract class that extends the base Wizard class plus the ability to
13+
* use other wizard classes as prompters
14+
*/
15+
export abstract class NestedWizard<T> extends Wizard<T> {
16+
/**
17+
* Map to store memoized wizard instances using SHA-256 hashed keys
18+
*/
19+
private wizardInstances: Map<string, any> = new Map()
20+
21+
public constructor(options?: WizardOptions<T>) {
22+
super(options)
23+
}
24+
25+
/**
26+
* Creates a prompter for a wizard instance with memoization.
27+
*
28+
* @template TWizard - The type of wizard, must extend Wizard<TState>
29+
* @template TState - The type of state managed by the wizard
30+
*
31+
* @param wizardClass - The wizard class constructor
32+
* @param args - Constructor arguments for the wizard instance
33+
*
34+
* @returns A wizard prompter to be used as prompter
35+
*
36+
* @example
37+
* // Create a prompter for SyncWizard
38+
* const prompter = this.createWizardPrompter<SyncWizard, SyncParams>(
39+
* SyncWizard,
40+
* template.uri,
41+
* syncUrl
42+
* )
43+
*
44+
* @remarks
45+
* - Instances are memoized using a SHA-256 hash of the wizard class name and arguments
46+
* - The same wizard instance is reused for identical constructor parameters for restoring wizard prompter
47+
* states during back button click event
48+
*/
49+
protected createWizardPrompter<TWizard extends Wizard<TState>, TState>(
50+
wizardClass: new (...args: any[]) => TWizard,
51+
...args: ConstructorParameters<new (...args: any[]) => TWizard>
52+
): Prompter<TState> {
53+
const memoizeKey = createHash('sha256')
54+
.update(wizardClass.name + JSON.stringify(args))
55+
.digest('hex')
56+
57+
if (!this.wizardInstances.get(memoizeKey)) {
58+
this.wizardInstances.set(memoizeKey, new wizardClass(...args))
59+
}
60+
61+
return new WizardPrompter(this.wizardInstances.get(memoizeKey)) as Prompter<TState>
62+
}
63+
}

packages/core/src/shared/ui/wizardPrompter.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,14 @@ import { Prompter, PromptResult } from './prompter'
99

1010
/**
1111
* Wraps {@link Wizard} object into its own {@link Prompter}, allowing wizards to use other wizards in their flows.
12-
* This is meant to be used exclusively in createWizardPrompter() method of {@link Wizard} class.
12+
* This is meant to be used exclusively in createWizardPrompter() method of {@link NestedWizard} class.
13+
*
1314
* @remarks
14-
* - Use createWizardPrompter() method of {@link Wizard} when creating a nested wizard prompter for proper state management.
1515
* - The WizardPrompter class should never be instantiated with directly.
16+
* - Use createWizardPrompter() method of {@link NestedWizard} when creating a nested wizard prompter for proper state management.
17+
* - See examples:
18+
* - {@link SingleNestedWizard}
19+
* - {@link DoubleNestedWizard}
1620
*/
1721
export class WizardPrompter<T> extends Prompter<T> {
1822
public get recentItem(): any {
@@ -57,7 +61,7 @@ export class WizardPrompter<T> extends Prompter<T> {
5761

5862
if (this.response === undefined) {
5963
return WIZARD_BACK as PromptResult<T>
60-
} else if (JSON.stringify(this.response) === '{}') {
64+
} else if (_.isEmpty(this.response)) {
6165
return WIZARD_SKIP as PromptResult<T>
6266
}
6367

packages/core/src/shared/wizards/wizard.ts

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ import { Branch, ControlSignal, StateMachineController, StepFunction } from './s
77
import * as _ from 'lodash'
88
import { Prompter, PromptResult } from '../../shared/ui/prompter'
99
import { PrompterProvider, WizardForm } from './wizardForm'
10-
import { createHash } from 'crypto'
11-
import { WizardPrompter } from '../ui/wizardPrompter'
1210

1311
/** Checks if the user response is valid (i.e. not undefined and not a control signal) */
1412
export function isValidResponse<T>(response: PromptResult<T>): response is T {
@@ -91,10 +89,6 @@ export class Wizard<TState extends Partial<Record<keyof TState, unknown>>> {
9189
private _exitStep?: StepFunction<TState>
9290
/** Guards against accidental use of the Wizard before `init()`. */
9391
private _ready: boolean
94-
/**
95-
* Map to store memoized wizard instances using SHA-256 hashed keys
96-
*/
97-
private childWizards: Map<string, any> = new Map()
9892

9993
/** Checks that `init()` was performed (if it was defined). */
10094
private assertReady() {
@@ -105,45 +99,6 @@ export class Wizard<TState extends Partial<Record<keyof TState, unknown>>> {
10599
}
106100
}
107101

108-
/**
109-
* Creates a prompter for a wizard instance with memoization.
110-
*
111-
* @template TWizard - The type of wizard, must extend Wizard<TState>
112-
* @template TState - The type of state managed by the wizard
113-
*
114-
* @param wizardClass - The wizard class constructor
115-
* @param args - Constructor arguments for the wizard instance
116-
*
117-
* @returns A wizard prompter to be used as prompter
118-
*
119-
* @example
120-
* // Create a prompter for SyncWizard
121-
* const prompter = this.createWizardPrompter<SyncWizard, SyncParams>(
122-
* SyncWizard,
123-
* template.uri,
124-
* syncUrl
125-
* )
126-
*
127-
* @remarks
128-
* - Instances are memoized using a SHA-256 hash of the wizard class name and arguments
129-
* - The same wizard instance is reused for identical constructor parameters for restoring wizard prompter
130-
* states during back button click event
131-
*/
132-
protected createWizardPrompter<TWizard extends Wizard<TState>, TState>(
133-
wizardClass: new (...args: any[]) => TWizard,
134-
...args: ConstructorParameters<new (...args: any[]) => TWizard>
135-
): Prompter<TState> {
136-
const memoizeKey = createHash('sha256')
137-
.update(wizardClass.name + JSON.stringify(args))
138-
.digest('hex')
139-
140-
if (!this.childWizards.get(memoizeKey)) {
141-
this.childWizards.set(memoizeKey, new wizardClass(...args))
142-
}
143-
144-
return new WizardPrompter(this.childWizards.get(memoizeKey)) as Prompter<TState>
145-
}
146-
147102
/**
148103
* The offset is applied to both the current step and total number of steps. Useful if the wizard is
149104
* apart of some overarching flow.

packages/core/src/test/shared/wizards/nestedWizard.test.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
*/
55
import * as vscode from 'vscode'
66
import { createCommonButtons } from '../../../shared/ui/buttons'
7+
import { NestedWizard } from '../../../shared/ui/nestedWizardPrompter'
78
import { createQuickPick, DataQuickPickItem } from '../../../shared/ui/pickerPrompter'
8-
import { Wizard } from '../../../shared/wizards/wizard'
99
import * as assert from 'assert'
1010
import { PrompterTester } from './prompterTester'
1111
import { TestQuickPick } from '../vscode/quickInput'
@@ -40,7 +40,7 @@ export function createTestPrompter(title: string, itemsString: string[]) {
4040
return createQuickPick(items, { title: title, buttons: createCommonButtons() })
4141
}
4242

43-
class ChildWizard extends Wizard<ChildWizardForm> {
43+
class ChildWizard extends NestedWizard<ChildWizardForm> {
4444
constructor() {
4545
super()
4646
this.form.childWizardProp1.bindPrompter(() =>
@@ -55,7 +55,7 @@ class ChildWizard extends Wizard<ChildWizardForm> {
5555
}
5656
}
5757

58-
class SingleNestedWizard extends Wizard<SingleNestedWizardForm> {
58+
class SingleNestedWizard extends NestedWizard<SingleNestedWizardForm> {
5959
constructor() {
6060
super()
6161

@@ -74,7 +74,7 @@ class SingleNestedWizard extends Wizard<SingleNestedWizardForm> {
7474
}
7575
}
7676

77-
class DoubleNestedWizard extends Wizard<DoubleNestedWizardForm> {
77+
class DoubleNestedWizard extends NestedWizard<DoubleNestedWizardForm> {
7878
constructor() {
7979
super()
8080

@@ -105,12 +105,12 @@ describe('NestedWizard', () => {
105105
+-- ChildWizard
106106
| |
107107
| +-- Prompter 1
108-
| |
109-
| +-- Prompter 2
110-
| |
111-
| +-- Prompter 3
112-
|
113-
+-- Prompter 3
108+
| |
109+
| +-- Prompter 2
110+
| |
111+
| +-- Prompter 3
112+
|
113+
+-- Prompter 3
114114
*/
115115
const expectedCallOrders = [
116116
'SingleNestedWizard Prompter 1',

0 commit comments

Comments
 (0)