@neurodevs/ndx-cli 0.1.32 → 0.1.34

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.
Files changed (32) hide show
  1. package/build/__tests__/modules/CliCommandRunner.test.d.ts +10 -2
  2. package/build/__tests__/modules/CliCommandRunner.test.js +73 -6
  3. package/build/__tests__/modules/CliCommandRunner.test.js.map +1 -1
  4. package/build/modules/CliCommandRunner.d.ts +2 -52
  5. package/build/modules/CliCommandRunner.js +18 -278
  6. package/build/modules/CliCommandRunner.js.map +1 -1
  7. package/build/modules/commands/CreateImplCommand.d.ts +17 -0
  8. package/build/modules/commands/CreateImplCommand.js +68 -0
  9. package/build/modules/commands/CreateImplCommand.js.map +1 -0
  10. package/build/modules/commands/CreatePackageCommand.d.ts +15 -0
  11. package/build/modules/commands/CreatePackageCommand.js +73 -0
  12. package/build/modules/commands/CreatePackageCommand.js.map +1 -0
  13. package/build/modules/commands/CreateUiCommand.d.ts +34 -0
  14. package/build/modules/commands/CreateUiCommand.js +185 -0
  15. package/build/modules/commands/CreateUiCommand.js.map +1 -0
  16. package/build/modules/commands/UpgradePackageCommand.d.ts +11 -0
  17. package/build/modules/commands/UpgradePackageCommand.js +44 -0
  18. package/build/modules/commands/UpgradePackageCommand.js.map +1 -0
  19. package/build/modules/expandHomeDir.d.ts +1 -0
  20. package/build/modules/expandHomeDir.js +14 -0
  21. package/build/modules/expandHomeDir.js.map +1 -0
  22. package/build/scripts/runNeurodevsAutocloner.js +2 -1
  23. package/build/scripts/runNeurodevsAutocloner.js.map +1 -1
  24. package/package.json +2 -2
  25. package/src/__tests__/modules/CliCommandRunner.test.ts +111 -7
  26. package/src/modules/CliCommandRunner.ts +18 -381
  27. package/src/modules/commands/CreateImplCommand.ts +81 -0
  28. package/src/modules/commands/CreatePackageCommand.ts +87 -0
  29. package/src/modules/commands/CreateUiCommand.ts +243 -0
  30. package/src/modules/commands/UpgradePackageCommand.ts +51 -0
  31. package/src/modules/expandHomeDir.ts +8 -0
  32. package/src/scripts/runNeurodevsAutocloner.ts +2 -1
@@ -0,0 +1,87 @@
1
+ import { NpmAutopackage } from '@neurodevs/meta-node'
2
+ import CliCommandRunner from '../CliCommandRunner'
3
+ import expandHomeDir from '../expandHomeDir'
4
+
5
+ export default class CreatePackageCommand {
6
+ private packageName!: string
7
+ private description!: string
8
+ private keywords!: string[]
9
+
10
+ public constructor() {}
11
+
12
+ public async run() {
13
+ const { packageName, description, keywords } =
14
+ await this.promptForAutopackage()
15
+
16
+ this.packageName = packageName
17
+ this.description = description
18
+ this.keywords = keywords
19
+
20
+ if (!this.userInputExistsForCreatePackage) {
21
+ return
22
+ }
23
+
24
+ const autopackage = this.NpmAutopackage()
25
+ await autopackage.run()
26
+ }
27
+
28
+ private async promptForAutopackage() {
29
+ return await this.prompts([
30
+ {
31
+ type: 'text',
32
+ name: 'packageName',
33
+ message: this.packageNameMessage,
34
+ },
35
+ {
36
+ type: 'text',
37
+ name: 'description',
38
+ message: this.descriptionMessage,
39
+ },
40
+ {
41
+ type: 'text',
42
+ name: 'keywords',
43
+ message: this.keywordsMessage,
44
+ initial: '',
45
+ format: (value) =>
46
+ value ? this.splitOnCommaOrWhitespace(value) : [],
47
+ },
48
+ ])
49
+ }
50
+
51
+ private readonly packageNameMessage =
52
+ 'What should the package be called? Example: useful-package'
53
+
54
+ private readonly descriptionMessage =
55
+ 'What should the package description be? Example: A useful package.'
56
+
57
+ private readonly keywordsMessage =
58
+ 'Enter keywords (comma or space separated, lowercase, optional):'
59
+
60
+ private splitOnCommaOrWhitespace(value: string) {
61
+ return value
62
+ .split(/[\s,]+/)
63
+ .map((v: string) => v.trim())
64
+ .filter(Boolean)
65
+ }
66
+
67
+ private get userInputExistsForCreatePackage() {
68
+ return this.packageName && this.description
69
+ }
70
+
71
+ private get prompts() {
72
+ return CliCommandRunner.prompts
73
+ }
74
+
75
+ private NpmAutopackage() {
76
+ return NpmAutopackage.Create({
77
+ name: this.packageName,
78
+ description: this.description,
79
+ keywords: ['nodejs', 'typescript', 'tdd', ...this.keywords],
80
+ gitNamespace: 'neurodevs',
81
+ npmNamespace: 'neurodevs',
82
+ installDir: expandHomeDir('~/dev'),
83
+ license: 'MIT',
84
+ author: 'Eric Yates <hello@ericthecurious.com>',
85
+ })
86
+ }
87
+ }
@@ -0,0 +1,243 @@
1
+ import { UiAutomodule } from '@neurodevs/meta-node'
2
+ import CliCommandRunner from '../CliCommandRunner'
3
+
4
+ export default class CreateUiCommand {
5
+ private componentName!: string
6
+
7
+ public constructor() {}
8
+
9
+ public async run() {
10
+ await this.installDependenciesIfNeeded()
11
+
12
+ const { componentName } = await this.promptForUimodule()
13
+
14
+ this.componentName = componentName
15
+
16
+ if (!this.componentName) {
17
+ return
18
+ }
19
+
20
+ await this.makeRequiredUiDirectories()
21
+
22
+ const instance = this.UiAutomodule()
23
+ await instance.run()
24
+ }
25
+
26
+ private async installDependenciesIfNeeded() {
27
+ const isInstalled = await this.checkIfDependenciesAreInstalled()
28
+
29
+ if (!isInstalled) {
30
+ const { shouldInstall } = await this.promptForInstallDependencies()
31
+
32
+ if (shouldInstall) {
33
+ await this.installReactDependencies()
34
+ await this.updateTsconfigForReact()
35
+ await this.createSetupTestsFile()
36
+ await this.addSetupTestsToPackageJson()
37
+ await this.recompileForTsxFiles()
38
+ }
39
+ }
40
+ }
41
+
42
+ private async checkIfDependenciesAreInstalled() {
43
+ const original = await this.loadPackageJson()
44
+ const parsed = JSON.parse(original)
45
+
46
+ const dependencies = Object.keys(parsed.dependencies ?? {})
47
+
48
+ const areDepsInstalled = this.requiredDependencies.every((dep) =>
49
+ dependencies.includes(dep)
50
+ )
51
+
52
+ const devDependencies = Object.keys(parsed.devDependencies ?? {})
53
+
54
+ const areDevDepsInstalled = this.requiredDevDependencies.every((dep) =>
55
+ devDependencies.includes(dep)
56
+ )
57
+
58
+ return areDepsInstalled && areDevDepsInstalled
59
+ }
60
+
61
+ private async loadPackageJson() {
62
+ return await this.readFile(this.packageJsonPath, 'utf-8')
63
+ }
64
+
65
+ private readonly packageJsonPath = 'package.json'
66
+
67
+ private readonly requiredDependencies = ['react', 'react-dom']
68
+
69
+ private readonly requiredDevDependencies = [
70
+ '@types/react',
71
+ '@types/react-dom',
72
+ '@types/jsdom',
73
+ '@testing-library/react',
74
+ '@testing-library/dom',
75
+ '@testing-library/jest-dom',
76
+ 'jsdom',
77
+ ]
78
+
79
+ private async promptForInstallDependencies() {
80
+ return await this.prompts([
81
+ {
82
+ type: 'confirm',
83
+ name: 'shouldInstall',
84
+ message:
85
+ 'Some required dependencies are missing! Press Enter to install, or any other key to abort.',
86
+ initial: true,
87
+ },
88
+ ])
89
+ }
90
+
91
+ private async installReactDependencies() {
92
+ await this.installDependencies()
93
+ await this.installDevDependencies()
94
+ }
95
+
96
+ private async installDependencies() {
97
+ console.log('Installing required dependencies...')
98
+ await this.exec('yarn add react react-dom')
99
+ }
100
+
101
+ private async installDevDependencies() {
102
+ console.log('Installing required dev dependencies...')
103
+ await this.exec(
104
+ 'yarn add -D @types/react @types/react-dom @types/jsdom @testing-library/react @testing-library/dom @testing-library/jest-dom jsdom'
105
+ )
106
+ }
107
+
108
+ private async updateTsconfigForReact() {
109
+ console.log('Updating tsconfig.json for React...')
110
+
111
+ const original = await this.loadTsconfig()
112
+ const parsed = JSON.parse(original)
113
+
114
+ const updated = JSON.stringify(
115
+ {
116
+ ...parsed,
117
+ compilerOptions: {
118
+ jsx: 'react-jsx',
119
+ ...parsed.compilerOptions,
120
+ },
121
+ include: ['src'],
122
+ },
123
+ null,
124
+ 4
125
+ )
126
+
127
+ await this.writeFile(this.tsconfigPath, updated)
128
+ }
129
+
130
+ private async loadTsconfig() {
131
+ return await this.readFile(this.tsconfigPath, 'utf-8')
132
+ }
133
+
134
+ private readonly tsconfigPath = 'tsconfig.json'
135
+
136
+ private async createSetupTestsFile() {
137
+ console.log('Creating src/setupTests.ts...')
138
+ await this.writeFile('src/__tests__/setupTests.ts', this.setupTestsFile)
139
+ }
140
+
141
+ private async addSetupTestsToPackageJson() {
142
+ console.log('Adding setupTests.ts to package.json...')
143
+
144
+ const original = await this.loadPackageJson()
145
+ const parsed = JSON.parse(original)
146
+
147
+ const updated = JSON.stringify(
148
+ {
149
+ ...parsed,
150
+ jest: {
151
+ ...parsed.jest,
152
+ setupFiles: ['<rootDir>/build/__tests__/setupTests.js'],
153
+ },
154
+ },
155
+ null,
156
+ 4
157
+ )
158
+
159
+ await this.writeFile(this.packageJsonPath, updated)
160
+ }
161
+
162
+ private async recompileForTsxFiles() {
163
+ console.log('Recompiling project for .tsx files...')
164
+ await this.exec('npx tsc')
165
+ }
166
+
167
+ private async promptForUimodule() {
168
+ return await this.prompts([
169
+ {
170
+ type: 'text',
171
+ name: 'componentName',
172
+ message: this.componentNameMessage,
173
+ },
174
+ ])
175
+ }
176
+
177
+ private readonly componentNameMessage =
178
+ 'What should the component be called? Example: YourComponent'
179
+
180
+ private async makeRequiredUiDirectories() {
181
+ await this.mkdir(this.uiTestSaveDir, { recursive: true })
182
+ await this.mkdir(this.uiModuleSaveDir, { recursive: true })
183
+ await this.mkdir(this.uiFakeSaveDir, { recursive: true })
184
+ }
185
+
186
+ private readonly uiTestSaveDir = 'src/__tests__/ui'
187
+ private readonly uiModuleSaveDir = 'src/ui'
188
+
189
+ private get uiFakeSaveDir() {
190
+ return `src/testDoubles/${this.componentName}`
191
+ }
192
+
193
+ private get exec() {
194
+ return CliCommandRunner.exec
195
+ }
196
+
197
+ private get mkdir() {
198
+ return CliCommandRunner.mkdir
199
+ }
200
+
201
+ private get prompts() {
202
+ return CliCommandRunner.prompts
203
+ }
204
+
205
+ private get readFile() {
206
+ return CliCommandRunner.readFile
207
+ }
208
+
209
+ private get writeFile() {
210
+ return CliCommandRunner.writeFile
211
+ }
212
+
213
+ private readonly setupTestsFile = `
214
+ import { JSDOM } from 'jsdom'
215
+
216
+ const jsdom = new JSDOM('<!doctype html><html><body></body></html>', {
217
+ url: 'http://localhost',
218
+ })
219
+
220
+ global.window = jsdom.window as unknown as Window & typeof globalThis
221
+ global.document = jsdom.window.document
222
+ global.navigator = jsdom.window.navigator
223
+ global.HTMLElement = jsdom.window.HTMLElement
224
+ global.getComputedStyle = jsdom.window.getComputedStyle
225
+
226
+ global.ResizeObserver = class {
227
+ public observe() {}
228
+ public unobserve() {}
229
+ public disconnect() {}
230
+ }
231
+
232
+ global.SVGElement = jsdom.window.SVGElement
233
+ `
234
+
235
+ private UiAutomodule() {
236
+ return UiAutomodule.Create({
237
+ testSaveDir: this.uiTestSaveDir,
238
+ moduleSaveDir: this.uiModuleSaveDir,
239
+ fakeSaveDir: this.uiFakeSaveDir,
240
+ componentName: this.componentName,
241
+ })
242
+ }
243
+ }
@@ -0,0 +1,51 @@
1
+ import { NpmAutopackage } from '@neurodevs/meta-node'
2
+ import CliCommandRunner from '../CliCommandRunner'
3
+ import expandHomeDir from '../expandHomeDir'
4
+
5
+ export default class UpgradePackageCommand {
6
+ private packageName!: string
7
+ private description!: string
8
+ private keywords!: string[]
9
+
10
+ public constructor() {}
11
+
12
+ public async run() {
13
+ await this.loadInfoFromPackageJson()
14
+
15
+ const autopackage = this.NpmAutopackage()
16
+ await autopackage.run()
17
+ }
18
+
19
+ private async loadInfoFromPackageJson() {
20
+ const raw = await this.readFile('package.json', 'utf-8')
21
+ const { name, description, keywords } = JSON.parse(raw)
22
+
23
+ this.packageName = name
24
+ this.description = description
25
+
26
+ this.keywords = this.defaultKeywords.every((keyword) =>
27
+ keywords?.includes(keyword)
28
+ )
29
+ ? keywords
30
+ : [...this.defaultKeywords, ...(keywords || [])]
31
+ }
32
+
33
+ private readonly defaultKeywords = ['nodejs', 'typescript', 'tdd']
34
+
35
+ private get readFile() {
36
+ return CliCommandRunner.readFile
37
+ }
38
+
39
+ private NpmAutopackage() {
40
+ return NpmAutopackage.Create({
41
+ name: this.packageName,
42
+ description: this.description,
43
+ keywords: this.keywords,
44
+ gitNamespace: 'neurodevs',
45
+ npmNamespace: 'neurodevs',
46
+ installDir: expandHomeDir('~/dev'),
47
+ license: 'MIT',
48
+ author: 'Eric Yates <hello@ericthecurious.com>',
49
+ })
50
+ }
51
+ }
@@ -0,0 +1,8 @@
1
+ import os from 'os'
2
+ import path from 'path'
3
+
4
+ export default function expandHomeDir(inputPath: string): string {
5
+ return inputPath.startsWith('~')
6
+ ? path.join(os.homedir(), inputPath.slice(1))
7
+ : inputPath
8
+ }
@@ -1,8 +1,9 @@
1
+ import expandHomeDir from '../modules/expandHomeDir'
1
2
  import NeurodevsAutocloner from '../modules/NeurodevsAutocloner'
2
3
 
3
4
  async function main() {
4
5
  const cloner = NeurodevsAutocloner.Create()
5
- await cloner.run('/Users/ericthecurious/dev')
6
+ await cloner.run(expandHomeDir('~/dev'))
6
7
  }
7
8
 
8
9
  main().catch((err) => {