@neurodevs/ndx-cli 0.1.32 → 0.1.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/__tests__/modules/CliCommandRunner.test.d.ts +10 -2
- package/build/__tests__/modules/CliCommandRunner.test.js +73 -6
- package/build/__tests__/modules/CliCommandRunner.test.js.map +1 -1
- package/build/modules/CliCommandRunner.d.ts +2 -52
- package/build/modules/CliCommandRunner.js +18 -278
- package/build/modules/CliCommandRunner.js.map +1 -1
- package/build/modules/commands/CreateImplCommand.d.ts +17 -0
- package/build/modules/commands/CreateImplCommand.js +68 -0
- package/build/modules/commands/CreateImplCommand.js.map +1 -0
- package/build/modules/commands/CreatePackageCommand.d.ts +16 -0
- package/build/modules/commands/CreatePackageCommand.js +79 -0
- package/build/modules/commands/CreatePackageCommand.js.map +1 -0
- package/build/modules/commands/CreateUiCommand.d.ts +34 -0
- package/build/modules/commands/CreateUiCommand.js +185 -0
- package/build/modules/commands/CreateUiCommand.js.map +1 -0
- package/build/modules/commands/UpgradePackageCommand.d.ts +12 -0
- package/build/modules/commands/UpgradePackageCommand.js +50 -0
- package/build/modules/commands/UpgradePackageCommand.js.map +1 -0
- package/package.json +1 -1
- package/src/__tests__/modules/CliCommandRunner.test.ts +111 -7
- package/src/modules/CliCommandRunner.ts +18 -381
- package/src/modules/commands/CreateImplCommand.ts +81 -0
- package/src/modules/commands/CreatePackageCommand.ts +94 -0
- package/src/modules/commands/CreateUiCommand.ts +243 -0
- package/src/modules/commands/UpgradePackageCommand.ts +58 -0
|
@@ -45,11 +45,18 @@ export default class CliCommandRunnerTest extends AbstractPackageTest {
|
|
|
45
45
|
private static readonly packageName = generateId()
|
|
46
46
|
private static readonly description = generateId()
|
|
47
47
|
private static readonly keywords = [generateId(), generateId()]
|
|
48
|
+
private static readonly githubToken = generateId()
|
|
49
|
+
|
|
50
|
+
private static readonly defaultKeywords = ['nodejs', 'typescript', 'tdd']
|
|
51
|
+
|
|
52
|
+
private static get keywordsWithDefaults() {
|
|
53
|
+
return [...this.defaultKeywords, ...this.keywords]
|
|
54
|
+
}
|
|
48
55
|
|
|
49
56
|
private static readonly createUiCommand = 'create.ui'
|
|
50
57
|
private static readonly componentName = generateId()
|
|
51
58
|
|
|
52
|
-
private static readonly
|
|
59
|
+
private static readonly upgradePackageCommand = 'upgrade.package'
|
|
53
60
|
|
|
54
61
|
protected static async beforeEach() {
|
|
55
62
|
await super.beforeEach()
|
|
@@ -257,7 +264,7 @@ export default class CliCommandRunnerTest extends AbstractPackageTest {
|
|
|
257
264
|
{
|
|
258
265
|
name: this.packageName,
|
|
259
266
|
description: this.description,
|
|
260
|
-
keywords: this.keywordsWithDefaults
|
|
267
|
+
keywords: this.keywordsWithDefaults,
|
|
261
268
|
gitNamespace: 'neurodevs',
|
|
262
269
|
npmNamespace: 'neurodevs',
|
|
263
270
|
installDir: this.expandHomeDir('~/dev'),
|
|
@@ -268,10 +275,6 @@ export default class CliCommandRunnerTest extends AbstractPackageTest {
|
|
|
268
275
|
)
|
|
269
276
|
}
|
|
270
277
|
|
|
271
|
-
private static keywordsWithDefaults() {
|
|
272
|
-
return ['nodejs', 'typescript', 'tdd', ...this.keywords]
|
|
273
|
-
}
|
|
274
|
-
|
|
275
278
|
@test()
|
|
276
279
|
protected static async createPackageRunsNpmAutopackage() {
|
|
277
280
|
await this.runCreatePackage()
|
|
@@ -279,7 +282,7 @@ export default class CliCommandRunnerTest extends AbstractPackageTest {
|
|
|
279
282
|
assert.isEqual(
|
|
280
283
|
FakeAutopackage.numCallsToRun,
|
|
281
284
|
1,
|
|
282
|
-
'Did not call run on
|
|
285
|
+
'Did not call run on NpmAutopackage!'
|
|
283
286
|
)
|
|
284
287
|
}
|
|
285
288
|
|
|
@@ -549,6 +552,100 @@ export default class CliCommandRunnerTest extends AbstractPackageTest {
|
|
|
549
552
|
)
|
|
550
553
|
}
|
|
551
554
|
|
|
555
|
+
@test()
|
|
556
|
+
protected static async upgradePackageCreatesInstance() {
|
|
557
|
+
const instance = await this.runUpgradePackage()
|
|
558
|
+
|
|
559
|
+
assert.isTruthy(
|
|
560
|
+
instance,
|
|
561
|
+
`Failed to create instance for ${this.upgradePackageCommand}!`
|
|
562
|
+
)
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
@test()
|
|
566
|
+
protected static async upgradePackageCreatesNpmAutopackage() {
|
|
567
|
+
const infoFromPackageJson = {
|
|
568
|
+
name: this.packageName,
|
|
569
|
+
description: this.description,
|
|
570
|
+
keywords: this.keywordsWithDefaults,
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
setFakeReadFileResult(
|
|
574
|
+
'package.json',
|
|
575
|
+
JSON.stringify(infoFromPackageJson)
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
await this.runUpgradePackage()
|
|
579
|
+
|
|
580
|
+
assert.isEqualDeep(
|
|
581
|
+
FakeAutopackage.callsToConstructor[0],
|
|
582
|
+
{
|
|
583
|
+
...infoFromPackageJson,
|
|
584
|
+
gitNamespace: 'neurodevs',
|
|
585
|
+
npmNamespace: 'neurodevs',
|
|
586
|
+
installDir: this.expandHomeDir('~/dev'),
|
|
587
|
+
license: 'MIT',
|
|
588
|
+
author: 'Eric Yates <hello@ericthecurious.com>',
|
|
589
|
+
},
|
|
590
|
+
'Did not create NpmAutopackage with expected options!'
|
|
591
|
+
)
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
@test()
|
|
595
|
+
protected static async upgradePackageRunsNpmAutopackage() {
|
|
596
|
+
await this.runUpgradePackage()
|
|
597
|
+
|
|
598
|
+
assert.isEqual(
|
|
599
|
+
FakeAutopackage.numCallsToRun,
|
|
600
|
+
1,
|
|
601
|
+
'Did not call run on NpmAutopackage!'
|
|
602
|
+
)
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
@test()
|
|
606
|
+
protected static async upgradePackageAddsDefaultKeywordsIfMissing() {
|
|
607
|
+
const infoFromPackageJson = {
|
|
608
|
+
name: this.packageName,
|
|
609
|
+
description: this.description,
|
|
610
|
+
keywords: [],
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
setFakeReadFileResult(
|
|
614
|
+
'package.json',
|
|
615
|
+
JSON.stringify(infoFromPackageJson)
|
|
616
|
+
)
|
|
617
|
+
|
|
618
|
+
await this.runUpgradePackage()
|
|
619
|
+
|
|
620
|
+
assert.isEqualDeep(
|
|
621
|
+
FakeAutopackage.callsToConstructor[0]?.keywords,
|
|
622
|
+
this.defaultKeywords,
|
|
623
|
+
'Did not add default keywords!'
|
|
624
|
+
)
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
@test()
|
|
628
|
+
protected static async upgradePackageDoesNotOverwriteKeywordsEvenIfDefaultsAreMissing() {
|
|
629
|
+
const infoFromPackageJson = {
|
|
630
|
+
name: this.packageName,
|
|
631
|
+
description: this.description,
|
|
632
|
+
keywords: [generateId(), generateId()],
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
setFakeReadFileResult(
|
|
636
|
+
'package.json',
|
|
637
|
+
JSON.stringify(infoFromPackageJson)
|
|
638
|
+
)
|
|
639
|
+
|
|
640
|
+
await this.runUpgradePackage()
|
|
641
|
+
|
|
642
|
+
assert.isEqualDeep(
|
|
643
|
+
FakeAutopackage.callsToConstructor[0]?.keywords,
|
|
644
|
+
[...this.defaultKeywords, ...infoFromPackageJson.keywords],
|
|
645
|
+
'Should not have overwritten keywords!'
|
|
646
|
+
)
|
|
647
|
+
}
|
|
648
|
+
|
|
552
649
|
private static async runCreateUi(
|
|
553
650
|
responses?: Record<string, string | boolean>
|
|
554
651
|
) {
|
|
@@ -645,6 +742,13 @@ export default class CliCommandRunnerTest extends AbstractPackageTest {
|
|
|
645
742
|
return instance
|
|
646
743
|
}
|
|
647
744
|
|
|
745
|
+
private static async runUpgradePackage() {
|
|
746
|
+
const instance = this.CliCommandRunner([this.upgradePackageCommand])
|
|
747
|
+
await instance.run()
|
|
748
|
+
|
|
749
|
+
return instance
|
|
750
|
+
}
|
|
751
|
+
|
|
648
752
|
private static expandHomeDir(inputPath: string): string {
|
|
649
753
|
return inputPath.startsWith('~')
|
|
650
754
|
? path.join(os.homedir(), inputPath.slice(1))
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import { exec as execSync } from 'child_process'
|
|
2
2
|
import { mkdir, readFile, writeFile } from 'fs/promises'
|
|
3
|
-
import os from 'os'
|
|
4
|
-
import path from 'path'
|
|
5
3
|
import { promisify } from 'util'
|
|
6
|
-
import {
|
|
7
|
-
ImplAutomodule,
|
|
8
|
-
NpmAutopackage,
|
|
9
|
-
UiAutomodule,
|
|
10
|
-
} from '@neurodevs/meta-node'
|
|
11
4
|
import prompts from 'prompts'
|
|
5
|
+
import CreateImplCommand from './commands/CreateImplCommand'
|
|
6
|
+
import CreatePackageCommand from './commands/CreatePackageCommand'
|
|
7
|
+
import CreateUiCommand from './commands/CreateUiCommand'
|
|
8
|
+
import UpgradePackageCommand from './commands/UpgradePackageCommand'
|
|
12
9
|
|
|
13
10
|
export default class CliCommandRunner implements CommandRunner {
|
|
14
11
|
public static Class?: CommandRunnerConstructor
|
|
@@ -21,21 +18,15 @@ export default class CliCommandRunner implements CommandRunner {
|
|
|
21
18
|
private args: string[]
|
|
22
19
|
|
|
23
20
|
private readonly createImplCommand = 'create.impl'
|
|
24
|
-
private interfaceName!: string
|
|
25
|
-
private implName!: string
|
|
26
|
-
|
|
27
21
|
private readonly createPackageCommand = 'create.package'
|
|
28
|
-
private packageName!: string
|
|
29
|
-
private description!: string
|
|
30
|
-
private keywords!: string[]
|
|
31
|
-
|
|
32
22
|
private readonly createUiCommand = 'create.ui'
|
|
33
|
-
private
|
|
23
|
+
private readonly upgradePackageCommand = 'upgrade.package'
|
|
34
24
|
|
|
35
25
|
private readonly supportedCommands = [
|
|
36
26
|
this.createImplCommand,
|
|
37
27
|
this.createPackageCommand,
|
|
38
28
|
this.createUiCommand,
|
|
29
|
+
this.upgradePackageCommand,
|
|
39
30
|
]
|
|
40
31
|
|
|
41
32
|
protected constructor(args: string[]) {
|
|
@@ -76,384 +67,30 @@ export default class CliCommandRunner implements CommandRunner {
|
|
|
76
67
|
case this.createUiCommand:
|
|
77
68
|
await this.createUiModule()
|
|
78
69
|
break
|
|
70
|
+
case this.upgradePackageCommand:
|
|
71
|
+
await this.upgradePackage()
|
|
72
|
+
break
|
|
79
73
|
}
|
|
80
74
|
}
|
|
81
75
|
|
|
82
76
|
private async createImplModule() {
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
this.interfaceName = interfaceName
|
|
86
|
-
this.implName = implName
|
|
87
|
-
|
|
88
|
-
if (!this.userInputExistsForCreateImpl) {
|
|
89
|
-
return
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
await this.makeRequiredImplDirectories()
|
|
93
|
-
|
|
94
|
-
const automodule = this.ImplAutomodule()
|
|
95
|
-
await automodule.run()
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
private async promptForAutomodule() {
|
|
99
|
-
return await this.prompts([
|
|
100
|
-
{
|
|
101
|
-
type: 'text',
|
|
102
|
-
name: 'interfaceName',
|
|
103
|
-
message: this.interfaceNameMessage,
|
|
104
|
-
},
|
|
105
|
-
{
|
|
106
|
-
type: 'text',
|
|
107
|
-
name: 'implName',
|
|
108
|
-
message: this.implNameMessage,
|
|
109
|
-
},
|
|
110
|
-
])
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
private readonly interfaceNameMessage =
|
|
114
|
-
'What should the interface be called? Example: YourInterface'
|
|
115
|
-
|
|
116
|
-
private readonly implNameMessage =
|
|
117
|
-
'What should the implementation class be called? Example: YourInterfaceImpl'
|
|
118
|
-
|
|
119
|
-
private get userInputExistsForCreateImpl() {
|
|
120
|
-
return this.interfaceName && this.implName
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
private async makeRequiredImplDirectories() {
|
|
124
|
-
await this.mkdir(this.implTestSaveDir, { recursive: true })
|
|
125
|
-
await this.mkdir(this.implModuleSaveDir, { recursive: true })
|
|
126
|
-
await this.mkdir(this.implFakeSaveDir, { recursive: true })
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
private readonly implTestSaveDir = 'src/__tests__/modules'
|
|
130
|
-
private readonly implModuleSaveDir = 'src/modules'
|
|
131
|
-
|
|
132
|
-
private get implFakeSaveDir() {
|
|
133
|
-
return `src/testDoubles/${this.interfaceName}`
|
|
77
|
+
const command = new CreateImplCommand()
|
|
78
|
+
await command.run()
|
|
134
79
|
}
|
|
135
80
|
|
|
136
81
|
private async createPackage() {
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
this.packageName = packageName
|
|
141
|
-
this.description = description
|
|
142
|
-
this.keywords = keywords
|
|
143
|
-
|
|
144
|
-
if (!this.userInputExistsForCreatePackage) {
|
|
145
|
-
return
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const autopackage = this.NpmAutopackage()
|
|
149
|
-
await autopackage.run()
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
private async promptForAutopackage() {
|
|
153
|
-
return await this.prompts([
|
|
154
|
-
{
|
|
155
|
-
type: 'text',
|
|
156
|
-
name: 'packageName',
|
|
157
|
-
message: this.packageNameMessage,
|
|
158
|
-
},
|
|
159
|
-
{
|
|
160
|
-
type: 'text',
|
|
161
|
-
name: 'description',
|
|
162
|
-
message: this.descriptionMessage,
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
type: 'text',
|
|
166
|
-
name: 'keywords',
|
|
167
|
-
message: this.keywordsMessage,
|
|
168
|
-
initial: '',
|
|
169
|
-
format: (value) =>
|
|
170
|
-
value ? this.splitOnCommaOrWhitespace(value) : [],
|
|
171
|
-
},
|
|
172
|
-
])
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
private readonly packageNameMessage =
|
|
176
|
-
'What should the package be called? Example: useful-package'
|
|
177
|
-
|
|
178
|
-
private readonly descriptionMessage =
|
|
179
|
-
'What should the package description be? Example: A useful package.'
|
|
180
|
-
|
|
181
|
-
private readonly keywordsMessage =
|
|
182
|
-
'Enter keywords (comma or space separated, lowercase, optional):'
|
|
183
|
-
|
|
184
|
-
private splitOnCommaOrWhitespace(value: string) {
|
|
185
|
-
return value
|
|
186
|
-
.split(/[\s,]+/)
|
|
187
|
-
.map((v: string) => v.trim())
|
|
188
|
-
.filter(Boolean)
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
private get userInputExistsForCreatePackage() {
|
|
192
|
-
return this.packageName && this.description
|
|
82
|
+
const command = new CreatePackageCommand()
|
|
83
|
+
await command.run()
|
|
193
84
|
}
|
|
194
85
|
|
|
195
86
|
private async createUiModule() {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const { componentName } = await this.promptForUimodule()
|
|
199
|
-
|
|
200
|
-
this.componentName = componentName
|
|
201
|
-
|
|
202
|
-
if (!this.componentName) {
|
|
203
|
-
return
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
await this.makeRequiredUiDirectories()
|
|
207
|
-
|
|
208
|
-
const instance = this.UiAutomodule()
|
|
209
|
-
await instance.run()
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
private async installDependenciesIfNeeded() {
|
|
213
|
-
const isInstalled = await this.checkIfDependenciesAreInstalled()
|
|
214
|
-
|
|
215
|
-
if (!isInstalled) {
|
|
216
|
-
const { shouldInstall } = await this.promptForInstallDependencies()
|
|
217
|
-
|
|
218
|
-
if (shouldInstall) {
|
|
219
|
-
await this.installReactDependencies()
|
|
220
|
-
await this.updateTsconfigForReact()
|
|
221
|
-
await this.createSetupTestsFile()
|
|
222
|
-
await this.addSetupTestsToPackageJson()
|
|
223
|
-
await this.recompileForTsxFiles()
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
private async checkIfDependenciesAreInstalled() {
|
|
229
|
-
const original = await this.loadPackageJson()
|
|
230
|
-
const parsed = JSON.parse(original)
|
|
231
|
-
|
|
232
|
-
const dependencies = Object.keys(parsed.dependencies ?? {})
|
|
233
|
-
|
|
234
|
-
const areDepsInstalled = this.requiredDependencies.every((dep) =>
|
|
235
|
-
dependencies.includes(dep)
|
|
236
|
-
)
|
|
237
|
-
|
|
238
|
-
const devDependencies = Object.keys(parsed.devDependencies ?? {})
|
|
239
|
-
|
|
240
|
-
const areDevDepsInstalled = this.requiredDevDependencies.every((dep) =>
|
|
241
|
-
devDependencies.includes(dep)
|
|
242
|
-
)
|
|
243
|
-
|
|
244
|
-
return areDepsInstalled && areDevDepsInstalled
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
private async loadPackageJson() {
|
|
248
|
-
return await this.readFile(this.packageJsonPath, 'utf-8')
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
private readonly packageJsonPath = 'package.json'
|
|
252
|
-
|
|
253
|
-
private readonly requiredDependencies = ['react', 'react-dom']
|
|
254
|
-
|
|
255
|
-
private readonly requiredDevDependencies = [
|
|
256
|
-
'@types/react',
|
|
257
|
-
'@types/react-dom',
|
|
258
|
-
'@types/jsdom',
|
|
259
|
-
'@testing-library/react',
|
|
260
|
-
'@testing-library/dom',
|
|
261
|
-
'@testing-library/jest-dom',
|
|
262
|
-
'jsdom',
|
|
263
|
-
]
|
|
264
|
-
|
|
265
|
-
private async promptForInstallDependencies() {
|
|
266
|
-
return await this.prompts([
|
|
267
|
-
{
|
|
268
|
-
type: 'confirm',
|
|
269
|
-
name: 'shouldInstall',
|
|
270
|
-
message:
|
|
271
|
-
'Some required dependencies are missing! Press Enter to install, or any other key to abort.',
|
|
272
|
-
initial: true,
|
|
273
|
-
},
|
|
274
|
-
])
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
private async installReactDependencies() {
|
|
278
|
-
await this.installDependencies()
|
|
279
|
-
await this.installDevDependencies()
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
private async installDependencies() {
|
|
283
|
-
console.log('Installing required dependencies...')
|
|
284
|
-
await this.exec('yarn add react react-dom')
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
private async installDevDependencies() {
|
|
288
|
-
console.log('Installing required dev dependencies...')
|
|
289
|
-
await this.exec(
|
|
290
|
-
'yarn add -D @types/react @types/react-dom @types/jsdom @testing-library/react @testing-library/dom @testing-library/jest-dom jsdom'
|
|
291
|
-
)
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
private async updateTsconfigForReact() {
|
|
295
|
-
console.log('Updating tsconfig.json for React...')
|
|
296
|
-
|
|
297
|
-
const original = await this.loadTsconfig()
|
|
298
|
-
const parsed = JSON.parse(original)
|
|
299
|
-
|
|
300
|
-
const updated = JSON.stringify(
|
|
301
|
-
{
|
|
302
|
-
...parsed,
|
|
303
|
-
compilerOptions: {
|
|
304
|
-
jsx: 'react-jsx',
|
|
305
|
-
...parsed.compilerOptions,
|
|
306
|
-
},
|
|
307
|
-
include: ['src'],
|
|
308
|
-
},
|
|
309
|
-
null,
|
|
310
|
-
4
|
|
311
|
-
)
|
|
312
|
-
|
|
313
|
-
await this.writeFile(this.tsconfigPath, updated)
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
private async loadTsconfig() {
|
|
317
|
-
return await this.readFile(this.tsconfigPath, 'utf-8')
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
private readonly tsconfigPath = 'tsconfig.json'
|
|
321
|
-
|
|
322
|
-
private async createSetupTestsFile() {
|
|
323
|
-
console.log('Creating src/setupTests.ts...')
|
|
324
|
-
await this.writeFile('src/__tests__/setupTests.ts', this.setupTestsFile)
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
private async addSetupTestsToPackageJson() {
|
|
328
|
-
console.log('Adding setupTests.ts to package.json...')
|
|
329
|
-
|
|
330
|
-
const original = await this.loadPackageJson()
|
|
331
|
-
const parsed = JSON.parse(original)
|
|
332
|
-
|
|
333
|
-
const updated = JSON.stringify(
|
|
334
|
-
{
|
|
335
|
-
...parsed,
|
|
336
|
-
jest: {
|
|
337
|
-
...parsed.jest,
|
|
338
|
-
setupFiles: ['<rootDir>/build/__tests__/setupTests.js'],
|
|
339
|
-
},
|
|
340
|
-
},
|
|
341
|
-
null,
|
|
342
|
-
4
|
|
343
|
-
)
|
|
344
|
-
|
|
345
|
-
await this.writeFile(this.packageJsonPath, updated)
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
private async recompileForTsxFiles() {
|
|
349
|
-
console.log('Recompiling project for .tsx files...')
|
|
350
|
-
await this.exec('npx tsc')
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
private async promptForUimodule() {
|
|
354
|
-
return await this.prompts([
|
|
355
|
-
{
|
|
356
|
-
type: 'text',
|
|
357
|
-
name: 'componentName',
|
|
358
|
-
message: this.componentNameMessage,
|
|
359
|
-
},
|
|
360
|
-
])
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
private readonly componentNameMessage =
|
|
364
|
-
'What should the component be called? Example: YourComponent'
|
|
365
|
-
|
|
366
|
-
private async makeRequiredUiDirectories() {
|
|
367
|
-
await this.mkdir(this.uiTestSaveDir, { recursive: true })
|
|
368
|
-
await this.mkdir(this.uiModuleSaveDir, { recursive: true })
|
|
369
|
-
await this.mkdir(this.uiFakeSaveDir, { recursive: true })
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
private expandHomeDir(inputPath: string): string {
|
|
373
|
-
return inputPath.startsWith('~')
|
|
374
|
-
? path.join(os.homedir(), inputPath.slice(1))
|
|
375
|
-
: inputPath
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
private readonly uiTestSaveDir = 'src/__tests__/ui'
|
|
379
|
-
private readonly uiModuleSaveDir = 'src/ui'
|
|
380
|
-
|
|
381
|
-
private get uiFakeSaveDir() {
|
|
382
|
-
return `src/testDoubles/${this.componentName}`
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
private get exec() {
|
|
386
|
-
return CliCommandRunner.exec
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
private get mkdir() {
|
|
390
|
-
return CliCommandRunner.mkdir
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
private get prompts() {
|
|
394
|
-
return CliCommandRunner.prompts
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
private get readFile() {
|
|
398
|
-
return CliCommandRunner.readFile
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
private get writeFile() {
|
|
402
|
-
return CliCommandRunner.writeFile
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
private readonly setupTestsFile = `
|
|
406
|
-
import { JSDOM } from 'jsdom'
|
|
407
|
-
|
|
408
|
-
const jsdom = new JSDOM('<!doctype html><html><body></body></html>', {
|
|
409
|
-
url: 'http://localhost',
|
|
410
|
-
})
|
|
411
|
-
|
|
412
|
-
global.window = jsdom.window as unknown as Window & typeof globalThis
|
|
413
|
-
global.document = jsdom.window.document
|
|
414
|
-
global.navigator = jsdom.window.navigator
|
|
415
|
-
global.HTMLElement = jsdom.window.HTMLElement
|
|
416
|
-
global.getComputedStyle = jsdom.window.getComputedStyle
|
|
417
|
-
|
|
418
|
-
global.ResizeObserver = class {
|
|
419
|
-
public observe() {}
|
|
420
|
-
public unobserve() {}
|
|
421
|
-
public disconnect() {}
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
global.SVGElement = jsdom.window.SVGElement
|
|
425
|
-
`
|
|
426
|
-
|
|
427
|
-
private ImplAutomodule() {
|
|
428
|
-
return ImplAutomodule.Create({
|
|
429
|
-
testSaveDir: this.implTestSaveDir,
|
|
430
|
-
moduleSaveDir: this.implModuleSaveDir,
|
|
431
|
-
fakeSaveDir: this.implFakeSaveDir,
|
|
432
|
-
interfaceName: this.interfaceName,
|
|
433
|
-
implName: this.implName,
|
|
434
|
-
})
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
private UiAutomodule() {
|
|
438
|
-
return UiAutomodule.Create({
|
|
439
|
-
testSaveDir: this.uiTestSaveDir,
|
|
440
|
-
moduleSaveDir: this.uiModuleSaveDir,
|
|
441
|
-
fakeSaveDir: this.uiFakeSaveDir,
|
|
442
|
-
componentName: this.componentName,
|
|
443
|
-
})
|
|
87
|
+
const command = new CreateUiCommand()
|
|
88
|
+
await command.run()
|
|
444
89
|
}
|
|
445
90
|
|
|
446
|
-
private
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
description: this.description,
|
|
450
|
-
keywords: ['nodejs', 'typescript', 'tdd', ...this.keywords],
|
|
451
|
-
gitNamespace: 'neurodevs',
|
|
452
|
-
npmNamespace: 'neurodevs',
|
|
453
|
-
installDir: this.expandHomeDir('~/dev'),
|
|
454
|
-
license: 'MIT',
|
|
455
|
-
author: 'Eric Yates <hello@ericthecurious.com>',
|
|
456
|
-
})
|
|
91
|
+
private async upgradePackage() {
|
|
92
|
+
const command = new UpgradePackageCommand()
|
|
93
|
+
await command.run()
|
|
457
94
|
}
|
|
458
95
|
}
|
|
459
96
|
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { ImplAutomodule } from '@neurodevs/meta-node'
|
|
2
|
+
import CliCommandRunner from '../CliCommandRunner'
|
|
3
|
+
|
|
4
|
+
export default class CreateImplCommand {
|
|
5
|
+
private interfaceName!: string
|
|
6
|
+
private implName!: string
|
|
7
|
+
|
|
8
|
+
public constructor() {}
|
|
9
|
+
|
|
10
|
+
public async run() {
|
|
11
|
+
const { interfaceName, implName } = await this.promptForAutomodule()
|
|
12
|
+
|
|
13
|
+
this.interfaceName = interfaceName
|
|
14
|
+
this.implName = implName
|
|
15
|
+
|
|
16
|
+
if (!this.userInputExistsForCreateImpl) {
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
await this.makeRequiredImplDirectories()
|
|
21
|
+
|
|
22
|
+
const automodule = this.ImplAutomodule()
|
|
23
|
+
await automodule.run()
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private async promptForAutomodule() {
|
|
27
|
+
return await this.prompts([
|
|
28
|
+
{
|
|
29
|
+
type: 'text',
|
|
30
|
+
name: 'interfaceName',
|
|
31
|
+
message: this.interfaceNameMessage,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
type: 'text',
|
|
35
|
+
name: 'implName',
|
|
36
|
+
message: this.implNameMessage,
|
|
37
|
+
},
|
|
38
|
+
])
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private readonly interfaceNameMessage =
|
|
42
|
+
'What should the interface be called? Example: YourInterface'
|
|
43
|
+
|
|
44
|
+
private readonly implNameMessage =
|
|
45
|
+
'What should the implementation class be called? Example: YourInterfaceImpl'
|
|
46
|
+
|
|
47
|
+
private get userInputExistsForCreateImpl() {
|
|
48
|
+
return this.interfaceName && this.implName
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private async makeRequiredImplDirectories() {
|
|
52
|
+
await this.mkdir(this.implTestSaveDir, { recursive: true })
|
|
53
|
+
await this.mkdir(this.implModuleSaveDir, { recursive: true })
|
|
54
|
+
await this.mkdir(this.implFakeSaveDir, { recursive: true })
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
private readonly implTestSaveDir = 'src/__tests__/modules'
|
|
58
|
+
private readonly implModuleSaveDir = 'src/modules'
|
|
59
|
+
|
|
60
|
+
private get implFakeSaveDir() {
|
|
61
|
+
return `src/testDoubles/${this.interfaceName}`
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private get mkdir() {
|
|
65
|
+
return CliCommandRunner.mkdir
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private get prompts() {
|
|
69
|
+
return CliCommandRunner.prompts
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private ImplAutomodule() {
|
|
73
|
+
return ImplAutomodule.Create({
|
|
74
|
+
testSaveDir: this.implTestSaveDir,
|
|
75
|
+
moduleSaveDir: this.implModuleSaveDir,
|
|
76
|
+
fakeSaveDir: this.implFakeSaveDir,
|
|
77
|
+
interfaceName: this.interfaceName,
|
|
78
|
+
implName: this.implName,
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
}
|