@sprucelabs/spruce-cli 24.0.0 → 24.1.1

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 (182) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/build/InFlightEntertainment.d.ts +2 -2
  3. package/build/__tests__/behavioral/DeployingASkill.test.js.map +1 -1
  4. package/build/__tests__/behavioral/EnablingAndDisablingCache.test.js.map +1 -1
  5. package/build/__tests__/behavioral/conversations/CreatingAConversationTopic.test.js +2 -2
  6. package/build/__tests__/behavioral/conversations/CreatingAConversationTopic.test.js.map +1 -1
  7. package/build/__tests__/behavioral/conversations/RegisteringConversationsOnBoot.test.js +1 -1
  8. package/build/__tests__/behavioral/conversations/RegisteringConversationsOnBoot.test.js.map +1 -1
  9. package/build/__tests__/behavioral/conversations/TestingAConversation.test.js +5 -5
  10. package/build/__tests__/behavioral/conversations/TestingAConversation.test.js.map +1 -1
  11. package/build/__tests__/behavioral/lint/LintService.test.js.map +1 -1
  12. package/build/__tests__/behavioral/node/CreatingANodeModule.test.js.map +1 -1
  13. package/build/__tests__/behavioral/onboard/StartingOnboarding.test.js.map +1 -1
  14. package/build/__tests__/behavioral/organization/CreatingAnOrg.test.js.map +1 -1
  15. package/build/__tests__/behavioral/skill/CreatingASkill.test.js.map +1 -1
  16. package/build/__tests__/behavioral/skill/RebuildingASkill.test.js.map +1 -1
  17. package/build/__tests__/behavioral/stores/CreatingADataStore.test.js.map +1 -1
  18. package/build/__tests__/behavioral/tests/migrationToInstance/AbstractInstanceTest.d.ts +11 -0
  19. package/build/__tests__/behavioral/tests/migrationToInstance/AbstractInstanceTest.js +49 -0
  20. package/build/__tests__/behavioral/tests/migrationToInstance/AbstractInstanceTest.js.map +1 -0
  21. package/build/__tests__/behavioral/tests/migrationToInstance/InstanceBasedTesting.test.d.ts +5 -0
  22. package/build/__tests__/behavioral/tests/migrationToInstance/InstanceBasedTesting.test.js +34 -0
  23. package/build/__tests__/behavioral/tests/migrationToInstance/InstanceBasedTesting.test.js.map +1 -0
  24. package/build/__tests__/behavioral/tests/migrationToInstance/MigratingTests.test.d.ts +12 -0
  25. package/build/__tests__/behavioral/tests/migrationToInstance/MigratingTests.test.js +88 -0
  26. package/build/__tests__/behavioral/tests/migrationToInstance/MigratingTests.test.js.map +1 -0
  27. package/build/__tests__/behavioral/tests/migrationToInstance/StaticTestFinder.test.d.ts +13 -0
  28. package/build/__tests__/behavioral/tests/migrationToInstance/StaticTestFinder.test.js +109 -0
  29. package/build/__tests__/behavioral/tests/migrationToInstance/StaticTestFinder.test.js.map +1 -0
  30. package/build/__tests__/behavioral/tests/migrationToInstance/StaticTestsWhenAlreadyExists.test.d.ts +4 -0
  31. package/build/__tests__/behavioral/tests/migrationToInstance/StaticTestsWhenAlreadyExists.test.js +29 -0
  32. package/build/__tests__/behavioral/tests/migrationToInstance/StaticTestsWhenAlreadyExists.test.js.map +1 -0
  33. package/build/__tests__/behavioral/tests/migrationToInstance/StaticToInstanceMigrator.test.d.ts +29 -0
  34. package/build/__tests__/behavioral/tests/migrationToInstance/StaticToInstanceMigrator.test.js +300 -0
  35. package/build/__tests__/behavioral/tests/migrationToInstance/StaticToInstanceMigrator.test.js.map +1 -0
  36. package/build/__tests__/behavioral/tests/migrationToInstance/StaticToInstanceTestFileMigrator.test.d.ts +26 -0
  37. package/build/__tests__/behavioral/tests/migrationToInstance/StaticToInstanceTestFileMigrator.test.js +202 -0
  38. package/build/__tests__/behavioral/tests/migrationToInstance/StaticToInstanceTestFileMigrator.test.js.map +1 -0
  39. package/build/__tests__/behavioral/tests/migrationToInstance/support/AbstractInstanceTest.txt +24 -0
  40. package/build/__tests__/behavioral/tests/migrationToInstance/support/AbstractStaticTest.txt +24 -0
  41. package/build/__tests__/behavioral/tests/migrationToInstance/support/InstanceTest.txt +36 -0
  42. package/build/__tests__/behavioral/tests/migrationToInstance/support/InstanceTest2.txt +63 -0
  43. package/build/__tests__/behavioral/tests/migrationToInstance/support/InstanceTest3.txt +222 -0
  44. package/build/__tests__/behavioral/tests/migrationToInstance/support/StaticTest.txt +34 -0
  45. package/build/__tests__/behavioral/tests/migrationToInstance/support/StaticTest2.txt +62 -0
  46. package/build/__tests__/behavioral/tests/migrationToInstance/support/StaticTest3.txt +221 -0
  47. package/build/__tests__/behavioral/tests/migrationToInstance/testFileContentsGenerators.d.ts +2 -0
  48. package/build/__tests__/behavioral/tests/migrationToInstance/testFileContentsGenerators.js +51 -0
  49. package/build/__tests__/behavioral/tests/migrationToInstance/testFileContentsGenerators.js.map +1 -0
  50. package/build/__tests__/behavioral/upgrading/UpdatingDependencies2.test.js.map +1 -1
  51. package/build/__tests__/behavioral/upgrading/UpgradingANodeModule.test.js.map +1 -1
  52. package/build/__tests__/behavioral/upgrading/UpgradingANonSpruceNodeModule.test.js.map +1 -1
  53. package/build/__tests__/behavioral/upgrading/UpgradingASkill3.test.js.map +1 -1
  54. package/build/__tests__/behavioral/upgrading/UpgradingASkill4.test.js.map +1 -1
  55. package/build/__tests__/behavioral/upgrading/UpgradingASkill5.test.js.map +1 -1
  56. package/build/__tests__/behavioral/versions/ResolvingVersions.test.js +0 -3
  57. package/build/__tests__/behavioral/versions/ResolvingVersions.test.js.map +1 -1
  58. package/build/__tests__/behavioral/views/WatchingSkillViews.test.js.map +1 -1
  59. package/build/__tests__/implementation/ActionExecuter2.test.js.map +1 -1
  60. package/build/__tests__/implementation/ActionExecuter4.test.js.map +1 -1
  61. package/build/__tests__/implementation/FeatureInstaller.test.js.map +1 -1
  62. package/build/__tests__/implementation/OrganizationStore.test.js +2 -2
  63. package/build/__tests__/implementation/OrganizationStore.test.js.map +1 -1
  64. package/build/__tests__/implementation/PkgService.test.js.map +1 -1
  65. package/build/__tests__/implementation/StoreFeature.test.js.map +1 -1
  66. package/build/__tests__/testDirsAndFiles/static_test_migration_1/src/__tests__/AnotherStaticTest.test.ts +33 -0
  67. package/build/__tests__/testDirsAndFiles/static_test_migration_1/src/__tests__/ShouldBeIgnored.ts +0 -0
  68. package/build/__tests__/testDirsAndFiles/static_test_migration_1/src/__tests__/StaticTest1.test.ts +33 -0
  69. package/build/__tests__/testDirsAndFiles/static_test_migration_2/src/DoNotInclude.ts +0 -0
  70. package/build/__tests__/testDirsAndFiles/static_test_migration_2/src/__tests__/AStaticTest.test.ts +33 -0
  71. package/build/__tests__/testDirsAndFiles/static_test_migration_2/src/__tests__/AnotherStaticTest1.test.ts +33 -0
  72. package/build/__tests__/testDirsAndFiles/static_test_migration_3/NotAFileThatShouldBeMigrated.ts +0 -0
  73. package/build/__tests__/testDirsAndFiles/static_test_migration_3/src/__tests__/AStaticTest2.test.ts +17 -0
  74. package/build/__tests__/testDirsAndFiles/static_test_migration_3/src/__tests__/AbstractWhateverTest.ts +3 -0
  75. package/build/boot.js.map +1 -1
  76. package/build/features/skill/actions/BootAction.js.map +1 -1
  77. package/build/features/test/TestRunner.d.ts +2 -2
  78. package/build/features/test/TestRunner.js.map +1 -1
  79. package/build/features/test/actions/CreateAction.d.ts +1 -0
  80. package/build/features/test/actions/CreateAction.js +13 -0
  81. package/build/features/test/actions/CreateAction.js.map +1 -1
  82. package/build/features/test/actions/MigrateAction.d.ts +17 -0
  83. package/build/features/test/actions/MigrateAction.js +42 -0
  84. package/build/features/test/actions/MigrateAction.js.map +1 -0
  85. package/build/features/vscode/services/VsCodeService.d.ts +2 -2
  86. package/build/features/vscode/services/VsCodeService.js.map +1 -1
  87. package/build/services/BuildService.d.ts +2 -2
  88. package/build/services/BuildService.js.map +1 -1
  89. package/build/services/CommandService.d.ts +20 -12
  90. package/build/services/CommandService.js +4 -4
  91. package/build/services/CommandService.js.map +1 -1
  92. package/build/services/GameService.d.ts +2 -2
  93. package/build/services/GameService.js.map +1 -1
  94. package/build/services/ImportService.d.ts +2 -2
  95. package/build/services/ImportService.js.map +1 -1
  96. package/build/services/LintService.d.ts +1 -1
  97. package/build/services/PkgService.d.ts +2 -2
  98. package/build/services/PkgService.js.map +1 -1
  99. package/build/services/ServiceFactory.d.ts +2 -2
  100. package/build/services/ServiceFactory.js.map +1 -1
  101. package/build/tests/AbstractCliTest.js.map +1 -1
  102. package/build/tests/CommandFaker.js.map +1 -1
  103. package/build/tests/staticToInstanceMigration/StaticTestFinder.d.ts +8 -0
  104. package/build/tests/staticToInstanceMigration/StaticTestFinder.js +23 -0
  105. package/build/tests/staticToInstanceMigration/StaticTestFinder.js.map +1 -0
  106. package/build/tests/staticToInstanceMigration/StaticToInstanceMigrator.d.ts +61 -0
  107. package/build/tests/staticToInstanceMigration/StaticToInstanceMigrator.js +55 -0
  108. package/build/tests/staticToInstanceMigration/StaticToInstanceMigrator.js.map +1 -0
  109. package/build/tests/staticToInstanceMigration/StaticToInstanceTestFileMigrator.d.ts +12 -0
  110. package/build/tests/staticToInstanceMigration/StaticToInstanceTestFileMigrator.js +138 -0
  111. package/build/tests/staticToInstanceMigration/StaticToInstanceTestFileMigrator.js.map +1 -0
  112. package/package.json +27 -27
  113. package/src/InFlightEntertainment.ts +2 -2
  114. package/src/__tests__/behavioral/DeployingASkill.test.ts +26 -23
  115. package/src/__tests__/behavioral/EnablingAndDisablingCache.test.ts +13 -13
  116. package/src/__tests__/behavioral/conversations/CreatingAConversationTopic.test.ts +2 -2
  117. package/src/__tests__/behavioral/conversations/RegisteringConversationsOnBoot.test.ts +1 -1
  118. package/src/__tests__/behavioral/conversations/TestingAConversation.test.ts +5 -5
  119. package/src/__tests__/behavioral/lint/LintService.test.ts +3 -3
  120. package/src/__tests__/behavioral/node/CreatingANodeModule.test.ts +2 -2
  121. package/src/__tests__/behavioral/onboard/StartingOnboarding.test.ts +2 -2
  122. package/src/__tests__/behavioral/organization/CreatingAnOrg.test.ts +0 -1
  123. package/src/__tests__/behavioral/skill/CreatingASkill.test.ts +2 -2
  124. package/src/__tests__/behavioral/skill/RebuildingASkill.test.ts +3 -3
  125. package/src/__tests__/behavioral/stores/CreatingADataStore.test.ts +3 -3
  126. package/src/__tests__/behavioral/tests/migrationToInstance/AbstractInstanceTest.ts +77 -0
  127. package/src/__tests__/behavioral/tests/migrationToInstance/InstanceBasedTesting.test.ts +19 -0
  128. package/src/__tests__/behavioral/tests/migrationToInstance/MigratingTests.test.ts +99 -0
  129. package/src/__tests__/behavioral/tests/migrationToInstance/StaticTestFinder.test.ts +72 -0
  130. package/src/__tests__/behavioral/tests/migrationToInstance/StaticTestsWhenAlreadyExists.test.ts +31 -0
  131. package/src/__tests__/behavioral/tests/migrationToInstance/StaticToInstanceMigrator.test.ts +310 -0
  132. package/src/__tests__/behavioral/tests/migrationToInstance/StaticToInstanceTestFileMigrator.test.ts +193 -0
  133. package/src/__tests__/behavioral/tests/migrationToInstance/support/AbstractInstanceTest.txt +24 -0
  134. package/src/__tests__/behavioral/tests/migrationToInstance/support/AbstractStaticTest.txt +24 -0
  135. package/src/__tests__/behavioral/tests/migrationToInstance/support/InstanceTest.txt +36 -0
  136. package/src/__tests__/behavioral/tests/migrationToInstance/support/InstanceTest2.txt +63 -0
  137. package/src/__tests__/behavioral/tests/migrationToInstance/support/InstanceTest3.txt +222 -0
  138. package/src/__tests__/behavioral/tests/migrationToInstance/support/StaticTest.txt +34 -0
  139. package/src/__tests__/behavioral/tests/migrationToInstance/support/StaticTest2.txt +62 -0
  140. package/src/__tests__/behavioral/tests/migrationToInstance/support/StaticTest3.txt +221 -0
  141. package/src/__tests__/behavioral/tests/migrationToInstance/testFileContentsGenerators.ts +50 -0
  142. package/src/__tests__/behavioral/upgrading/UpdatingDependencies2.test.ts +3 -3
  143. package/src/__tests__/behavioral/upgrading/UpgradingANodeModule.test.ts +6 -6
  144. package/src/__tests__/behavioral/upgrading/UpgradingANonSpruceNodeModule.test.ts +4 -4
  145. package/src/__tests__/behavioral/upgrading/UpgradingASkill3.test.ts +9 -9
  146. package/src/__tests__/behavioral/upgrading/UpgradingASkill4.test.ts +4 -4
  147. package/src/__tests__/behavioral/upgrading/UpgradingASkill5.test.ts +4 -4
  148. package/src/__tests__/behavioral/versions/ResolvingVersions.test.ts +1 -3
  149. package/src/__tests__/behavioral/views/WatchingSkillViews.test.ts +2 -2
  150. package/src/__tests__/implementation/ActionExecuter2.test.ts +2 -2
  151. package/src/__tests__/implementation/ActionExecuter4.test.ts +3 -3
  152. package/src/__tests__/implementation/FeatureInstaller.test.ts +2 -2
  153. package/src/__tests__/implementation/OrganizationStore.test.ts +6 -2
  154. package/src/__tests__/implementation/PkgService.test.ts +3 -3
  155. package/src/__tests__/implementation/StoreFeature.test.ts +2 -2
  156. package/src/__tests__/testDirsAndFiles/static_test_migration_1/src/__tests__/AnotherStaticTest.test.ts +33 -0
  157. package/src/__tests__/testDirsAndFiles/static_test_migration_1/src/__tests__/ShouldBeIgnored.ts +0 -0
  158. package/src/__tests__/testDirsAndFiles/static_test_migration_1/src/__tests__/StaticTest1.test.ts +33 -0
  159. package/src/__tests__/testDirsAndFiles/static_test_migration_2/src/DoNotInclude.ts +0 -0
  160. package/src/__tests__/testDirsAndFiles/static_test_migration_2/src/__tests__/AStaticTest.test.ts +33 -0
  161. package/src/__tests__/testDirsAndFiles/static_test_migration_2/src/__tests__/AnotherStaticTest1.test.ts +33 -0
  162. package/src/__tests__/testDirsAndFiles/static_test_migration_3/NotAFileThatShouldBeMigrated.ts +0 -0
  163. package/src/__tests__/testDirsAndFiles/static_test_migration_3/src/__tests__/AStaticTest2.test.ts +17 -0
  164. package/src/__tests__/testDirsAndFiles/static_test_migration_3/src/__tests__/AbstractWhateverTest.ts +3 -0
  165. package/src/boot.ts +2 -2
  166. package/src/features/skill/actions/BootAction.ts +2 -2
  167. package/src/features/test/TestRunner.ts +3 -3
  168. package/src/features/test/actions/CreateAction.ts +17 -0
  169. package/src/features/test/actions/MigrateAction.ts +44 -0
  170. package/src/features/vscode/services/VsCodeService.ts +2 -2
  171. package/src/services/BuildService.ts +3 -3
  172. package/src/services/CommandService.ts +27 -14
  173. package/src/services/GameService.ts +3 -3
  174. package/src/services/ImportService.ts +3 -3
  175. package/src/services/LintService.ts +1 -1
  176. package/src/services/PkgService.ts +3 -3
  177. package/src/services/ServiceFactory.ts +6 -6
  178. package/src/tests/AbstractCliTest.ts +2 -2
  179. package/src/tests/CommandFaker.ts +4 -4
  180. package/src/tests/staticToInstanceMigration/StaticTestFinder.ts +25 -0
  181. package/src/tests/staticToInstanceMigration/StaticToInstanceMigrator.ts +83 -0
  182. package/src/tests/staticToInstanceMigration/StaticToInstanceTestFileMigrator.ts +197 -0
@@ -0,0 +1,44 @@
1
+ import { buildSchema } from '@sprucelabs/schema'
2
+ import { diskUtil } from '@sprucelabs/spruce-skill-utils'
3
+ import StaticTestFinderImpl from '../../../tests/staticToInstanceMigration/StaticTestFinder'
4
+ import StaticToInstanceMigratorImpl from '../../../tests/staticToInstanceMigration/StaticToInstanceMigrator'
5
+ import StaticToInstanceTestFileMigratorImpl from '../../../tests/staticToInstanceMigration/StaticToInstanceTestFileMigrator'
6
+ import AbstractAction from '../../AbstractAction'
7
+ import { FeatureActionResponse } from '../../features.types'
8
+
9
+ export default class MigrationAction extends AbstractAction<OptionsSchema> {
10
+ public optionsSchema = optionsSchema
11
+ public commandAliases = ['migrate.tests']
12
+ public invocationMessage = 'Migrating tests from static to instance... 🌲'
13
+
14
+ public async execute(): Promise<FeatureActionResponse> {
15
+ const testFinder = StaticTestFinderImpl.Finder()
16
+ const testFileMigrator = StaticToInstanceTestFileMigratorImpl.Migrator()
17
+ const lintService = this.Service('lint')
18
+ const migrator = StaticToInstanceMigratorImpl.Migrator({
19
+ testFinder,
20
+ testFileMigrator,
21
+ lintService,
22
+ })
23
+
24
+ this.ui.startLoading('Migrating tests...')
25
+ const path = diskUtil.resolvePath(this.cwd, 'src', '__tests__')
26
+ const { totalTestsSkipped, totalTestsUpdated } =
27
+ await migrator.run(path)
28
+
29
+ return {
30
+ headline: 'Migrated tests from static to instance based.',
31
+ summaryLines: [
32
+ `${totalTestsUpdated} test${totalTestsUpdated === 1 ? '' : 's'} updated`,
33
+ `${totalTestsSkipped} test${totalTestsSkipped === 1 ? '' : 's'} skipped`,
34
+ ],
35
+ }
36
+ }
37
+ }
38
+
39
+ const optionsSchema = buildSchema({
40
+ id: 'migrateTests',
41
+ fields: {},
42
+ })
43
+
44
+ type OptionsSchema = typeof optionsSchema
@@ -1,7 +1,7 @@
1
1
  import semver from 'semver'
2
- import CommandService from '../../../services/CommandService'
2
+ import CommandServiceImpl from '../../../services/CommandService'
3
3
 
4
- export default class VsCodeService extends CommandService {
4
+ export default class VsCodeService extends CommandServiceImpl {
5
5
  /** Returns whether or not vscode is installed */
6
6
  public async isInstalled(): Promise<boolean> {
7
7
  const isInstalled = false
@@ -1,4 +1,4 @@
1
- import CommandService from './CommandService'
1
+ import CommandServiceImpl from './CommandService'
2
2
  import LintService from './LintService'
3
3
 
4
4
  export default class BuildService {
@@ -10,11 +10,11 @@ export default class BuildService {
10
10
  return this.commandService.cwd
11
11
  }
12
12
 
13
- private commandService: CommandService
13
+ private commandService: CommandServiceImpl
14
14
  private lintService: LintService
15
15
 
16
16
  public constructor(
17
- commandService: CommandService,
17
+ commandService: CommandServiceImpl,
18
18
  lintService: LintService
19
19
  ) {
20
20
  this.commandService = commandService
@@ -9,7 +9,7 @@ import SpruceError from '../errors/SpruceError'
9
9
 
10
10
  process.setMaxListeners(100)
11
11
 
12
- export default class CommandService {
12
+ export default class CommandServiceImpl implements CommandService {
13
13
  public cwd: string
14
14
  private activeChildProcess: ChildProcess | undefined
15
15
  private ignoreCloseErrors = false
@@ -25,17 +25,7 @@ export default class CommandService {
25
25
 
26
26
  public async execute(
27
27
  cmd: string,
28
- options?: {
29
- ignoreErrors?: boolean
30
- args?: string[]
31
- shouldStream?: boolean
32
- outStream?: Writable
33
- onError?: (error: string) => void
34
- onData?: (data: string) => void
35
- spawnOptions?: SpawnOptions
36
- forceColor?: boolean
37
- env?: Record<string, any>
38
- }
28
+ options?: ExecuteCommandOptions
39
29
  ): Promise<{
40
30
  stdout: string
41
31
  }> {
@@ -51,7 +41,7 @@ export default class CommandService {
51
41
  const { mockResponse, mockKey } = this.getMockResponse(executable, args)
52
42
 
53
43
  if (mockResponse) {
54
- CommandService.commandsRunCapturedByMockResponses.push(mockKey)
44
+ CommandServiceImpl.commandsRunCapturedByMockResponses.push(mockKey)
55
45
  mockResponse.callback?.(executable, args)
56
46
 
57
47
  if (mockResponse.code !== 0) {
@@ -174,7 +164,7 @@ export default class CommandService {
174
164
 
175
165
  private getMockResponse(executable: string, args: string[]) {
176
166
  const mockKey = `${executable} ${args.join(' ')}`.trim()
177
- const commands = CommandService.fakeResponses
167
+ const commands = CommandServiceImpl.fakeResponses
178
168
  const match = commands.find((r) =>
179
169
  r.command instanceof RegExp
180
170
  ? mockKey.search(r.command) > -1
@@ -208,3 +198,26 @@ interface FakedCommandResponse {
208
198
  stderr?: string
209
199
  callback?: FakedCommandCallback
210
200
  }
201
+
202
+ export interface CommandService {
203
+ execute(
204
+ cmd: string,
205
+ options?: ExecuteCommandOptions
206
+ ): Promise<{
207
+ stdout: string
208
+ }>
209
+ kill(): void
210
+ pid(): number | undefined
211
+ }
212
+
213
+ export interface ExecuteCommandOptions {
214
+ ignoreErrors?: boolean
215
+ args?: string[]
216
+ shouldStream?: boolean
217
+ outStream?: Writable
218
+ onError?: (error: string) => void
219
+ onData?: (data: string) => void
220
+ spawnOptions?: SpawnOptions
221
+ forceColor?: boolean
222
+ env?: Record<string, any>
223
+ }
@@ -1,14 +1,14 @@
1
1
  import { diskUtil } from '@sprucelabs/spruce-skill-utils'
2
2
  import TerminalInterface from '../interfaces/TerminalInterface'
3
- import CommandService from './CommandService'
3
+ import CommandServiceImpl from './CommandService'
4
4
 
5
5
  export default class GameService {
6
- private command: CommandService
6
+ private command: CommandServiceImpl
7
7
  private ui: TerminalInterface
8
8
  private statusMessage?: string
9
9
  private killed = false
10
10
 
11
- public constructor(command: CommandService, ui: TerminalInterface) {
11
+ public constructor(command: CommandServiceImpl, ui: TerminalInterface) {
12
12
  this.command = command
13
13
  this.ui = ui
14
14
  this.command.cwd = diskUtil.resolvePath(__dirname, '../../')
@@ -3,7 +3,7 @@ import { diskUtil } from '@sprucelabs/spruce-skill-utils'
3
3
  import fs from 'fs-extra'
4
4
  import md5 from 'md5'
5
5
  import SpruceError from '../errors/SpruceError'
6
- import CommandService from './CommandService'
6
+ import CommandServiceImpl from './CommandService'
7
7
 
8
8
  export default class ImportService {
9
9
  public cwd: string
@@ -14,10 +14,10 @@ export default class ImportService {
14
14
  private static cachedImports: Record<string, Record<string, any>> = {}
15
15
  private static importCacheDir: string =
16
16
  diskUtil.createTempDir('import-service')
17
- private command: CommandService
17
+ private command: CommandServiceImpl
18
18
  private static isCachingEnabled: boolean
19
19
 
20
- public constructor(options: { cwd: string; command: CommandService }) {
20
+ public constructor(options: { cwd: string; command: CommandServiceImpl }) {
21
21
  this.cwd = options.cwd
22
22
  this.command = options.command
23
23
  }
@@ -2,7 +2,7 @@ import { SchemaError } from '@sprucelabs/schema'
2
2
  // import { ESLint } from 'eslint'
3
3
  // import fs from 'fs-extra'
4
4
  import SpruceError from '../errors/SpruceError'
5
- import CommandService from './CommandService'
5
+ import { CommandService } from './CommandService'
6
6
 
7
7
  export default class LintService {
8
8
  public cwd: string
@@ -4,12 +4,12 @@ import {
4
4
  PkgService as BasePkgService,
5
5
  } from '@sprucelabs/spruce-skill-utils'
6
6
  import isCi from '../utilities/isCi'
7
- import CommandService from './CommandService'
7
+ import CommandServiceImpl from './CommandService'
8
8
 
9
9
  export default class PkgService extends BasePkgService {
10
- private commandService: CommandService
10
+ private commandService: CommandServiceImpl
11
11
 
12
- public constructor(cwd: string, commandService: CommandService) {
12
+ public constructor(cwd: string, commandService: CommandServiceImpl) {
13
13
  super(cwd)
14
14
  this.commandService = commandService
15
15
  }
@@ -9,7 +9,7 @@ import { FeatureCode } from '../features/features.types'
9
9
  import SchemaService from '../features/schema/services/SchemaService'
10
10
  import VsCodeService from '../features/vscode/services/VsCodeService'
11
11
  import BuildService from './BuildService'
12
- import CommandService from './CommandService'
12
+ import CommandServiceImpl from './CommandService'
13
13
  import DependencyService from './DependencyService'
14
14
  import ImportService from './ImportService'
15
15
  import LintService from './LintService'
@@ -41,14 +41,14 @@ export default class ServiceFactory {
41
41
  case 'schema':
42
42
  return new SchemaService({
43
43
  cwd,
44
- command: new CommandService(cwd),
44
+ command: new CommandServiceImpl(cwd),
45
45
  }) as ServiceMap[S]
46
46
  case 'lint':
47
47
  return new (Class ?? LintService)(cwd, () =>
48
48
  this.Service(cwd, 'command')
49
49
  ) as ServiceMap[S]
50
50
  case 'command': {
51
- return new CommandService(cwd) as ServiceMap[S]
51
+ return new CommandServiceImpl(cwd) as ServiceMap[S]
52
52
  }
53
53
  case 'remote':
54
54
  return new RemoteService(new EnvService(cwd)) as ServiceMap[S]
@@ -68,7 +68,7 @@ export default class ServiceFactory {
68
68
  case 'import':
69
69
  return this.buildImportService(cwd) as ServiceMap[S]
70
70
  case 'build': {
71
- const commandService = new CommandService(cwd)
71
+ const commandService = new CommandServiceImpl(cwd)
72
72
  return new BuildService(
73
73
  commandService,
74
74
  this.Service(cwd, 'lint')
@@ -86,7 +86,7 @@ export default class ServiceFactory {
86
86
  private buildImportService(cwd: string): ImportService {
87
87
  return new ImportService({
88
88
  cwd,
89
- command: new CommandService(cwd),
89
+ command: new CommandServiceImpl(cwd),
90
90
  })
91
91
  }
92
92
 
@@ -104,7 +104,7 @@ export interface ServiceMap {
104
104
  vsCode: VsCodeService
105
105
  schema: SchemaService
106
106
  lint: LintService
107
- command: CommandService
107
+ command: CommandServiceImpl
108
108
  typeChecker: TypeCheckerService
109
109
  import: ImportService
110
110
  build: BuildService
@@ -22,7 +22,7 @@ import OnboardingStore from '../features/onboard/stores/OnboardingStore'
22
22
  import SkillStore from '../features/skill/stores/SkillStore'
23
23
  import CliGlobalEmitter, { GlobalEmitter } from '../GlobalEmitter'
24
24
  import SpyInterface from '../interfaces/SpyInterface'
25
- import CommandService from '../services/CommandService'
25
+ import CommandServiceImpl from '../services/CommandService'
26
26
  import ImportService from '../services/ImportService'
27
27
  import LintService from '../services/LintService'
28
28
  import ServiceFactory, { Service, ServiceMap } from '../services/ServiceFactory'
@@ -114,7 +114,7 @@ export default abstract class AbstractCliTest extends AbstractSpruceTest {
114
114
  ImportService.clearCache()
115
115
  SkillStore.clearCurrentSkill()
116
116
  EventStore.clearCache()
117
- CommandService.clearFakedResponses()
117
+ CommandServiceImpl.clearFakedResponses()
118
118
  MercuryClientFactory.reset()
119
119
  MercuryClientFactory.setIsTestMode(false)
120
120
 
@@ -1,24 +1,24 @@
1
1
  import { assert } from '@sprucelabs/test-utils'
2
- import CommandService from '../services/CommandService'
2
+ import CommandServiceImpl from '../services/CommandService'
3
3
 
4
4
  type Command = RegExp | string
5
5
 
6
6
  export default class CommandFaker {
7
7
  public fakeCommand(command: Command, code = 0) {
8
- CommandService.fakeCommand(command, {
8
+ CommandServiceImpl.fakeCommand(command, {
9
9
  code,
10
10
  })
11
11
  }
12
12
 
13
13
  public on(command: Command, cb: () => void) {
14
- CommandService.fakeCommand(command, {
14
+ CommandServiceImpl.fakeCommand(command, {
15
15
  code: 0,
16
16
  callback: cb,
17
17
  })
18
18
  }
19
19
 
20
20
  public makeCommandThrow(command: Command) {
21
- CommandService.fakeCommand(command, {
21
+ CommandServiceImpl.fakeCommand(command, {
22
22
  code: 1,
23
23
  callback: () =>
24
24
  assert.fail(`${command} should not have been called`),
@@ -0,0 +1,25 @@
1
+ import globby from '@sprucelabs/globby'
2
+ import { assertOptions } from '@sprucelabs/schema'
3
+
4
+ export default class StaticTestFinderImpl implements StaticTestFinder {
5
+ public static Class?: new () => StaticTestFinder
6
+
7
+ public static Finder(): StaticTestFinder {
8
+ return new (this.Class ?? this)()
9
+ }
10
+
11
+ public async find(lookupDir: string) {
12
+ assertOptions({ lookupDir }, ['lookupDir'])
13
+
14
+ const matches = await globby([
15
+ `${lookupDir}/**/Abstract*Test.ts`,
16
+ `${lookupDir}/**/*.test.ts`,
17
+ ])
18
+
19
+ return matches
20
+ }
21
+ }
22
+
23
+ export interface StaticTestFinder {
24
+ find(lookupDir: string): Promise<string[]>
25
+ }
@@ -0,0 +1,83 @@
1
+ import { assertOptions } from '@sprucelabs/schema'
2
+ import { diskUtil } from '@sprucelabs/spruce-skill-utils'
3
+ import LintService from '../../services/LintService'
4
+ import StaticTestFinder from './StaticTestFinder'
5
+ import { StaticToInstanceTestFileMigrator } from './StaticToInstanceTestFileMigrator'
6
+
7
+ export default class StaticToInstanceMigratorImpl
8
+ implements StaticToInstanceMigrator
9
+ {
10
+ public static diskUtil = diskUtil
11
+ public static Class?: new (
12
+ options: StaticToInstanceMigratorOptions
13
+ ) => StaticToInstanceMigrator
14
+
15
+ private testFinder: StaticTestFinder
16
+ private testFileMigrator: StaticToInstanceTestFileMigrator
17
+ private lintService: LintService
18
+
19
+ protected constructor(options: StaticToInstanceMigratorOptions) {
20
+ const { testFinder, testFileMigrator, lintService } = options
21
+ this.testFinder = testFinder
22
+ this.testFileMigrator = testFileMigrator
23
+ this.lintService = lintService
24
+ }
25
+
26
+ public static Migrator(options: StaticToInstanceMigratorOptions) {
27
+ assertOptions(options, [
28
+ 'testFinder',
29
+ 'testFileMigrator',
30
+ 'lintService',
31
+ ])
32
+ return new (this.Class ?? this)(options)
33
+ }
34
+
35
+ public async run(lookupDir: string) {
36
+ assertOptions({ lookupDir }, ['lookupDir'])
37
+ const matches = await this.testFinder.find(lookupDir)
38
+
39
+ let totalTestsUpdated = 0
40
+ let totalTestsSkipped = 0
41
+
42
+ for (const match of matches) {
43
+ const contents = this.readFile(match)
44
+ const updated = this.testFileMigrator.migrate(contents)
45
+ if (contents === updated) {
46
+ totalTestsSkipped++
47
+ } else {
48
+ totalTestsUpdated++
49
+ this.writeFile(match, updated)
50
+ }
51
+ }
52
+
53
+ await this.lintService.fix('**/*.ts')
54
+
55
+ return {
56
+ totalTestsUpdated,
57
+ totalTestsSkipped,
58
+ }
59
+ }
60
+
61
+ private readFile(match: string) {
62
+ return StaticToInstanceMigratorImpl.diskUtil.readFile(match)
63
+ }
64
+
65
+ private writeFile(match: string, updated: string) {
66
+ StaticToInstanceMigratorImpl.diskUtil.writeFile(match, updated)
67
+ }
68
+ }
69
+
70
+ export interface StaticToInstanceMigratorOptions {
71
+ testFinder: StaticTestFinder
72
+ testFileMigrator: StaticToInstanceTestFileMigrator
73
+ lintService: LintService
74
+ }
75
+
76
+ export interface StaticToInstanceMigratorResults {
77
+ totalTestsUpdated: number
78
+ totalTestsSkipped: number
79
+ }
80
+
81
+ export interface StaticToInstanceMigrator {
82
+ run(lookupDir: string): Promise<StaticToInstanceMigratorResults>
83
+ }
@@ -0,0 +1,197 @@
1
+ import { assertOptions } from '@sprucelabs/schema'
2
+
3
+ export default class StaticToInstanceTestFileMigratorImpl
4
+ implements StaticToInstanceTestFileMigrator
5
+ {
6
+ public static Class?: new () => StaticToInstanceTestFileMigrator
7
+
8
+ public static Migrator() {
9
+ return new (this.Class ?? this)()
10
+ }
11
+
12
+ public migrate(contents: string) {
13
+ assertOptions({ contents }, ['contents'])
14
+
15
+ // 1a. Remove `static ` only when it appears immediately before a method
16
+ // that has the `@test()` decorator
17
+ // 1b. If the contents include `export default abstract class`,
18
+ // remove `static` from all methods
19
+ const includesAbstractExport = contents.includes(
20
+ 'export default abstract class'
21
+ )
22
+ let cleanedUp = includesAbstractExport
23
+ ? contents.replaceAll(' static ', ' ')
24
+ : contents.replace(
25
+ // Matches @test() or @seed(...) followed (on next line) by optional visibility and `static`.
26
+ /(@(?:test\(\)|seed\([^)]*\))\s*\n\s*(?:public|protected)\s+)static\s+/g,
27
+ '$1'
28
+ )
29
+
30
+ // 2. Add `@suite()` above `export default class` if it's not already present
31
+ if (!cleanedUp.includes('@suite')) {
32
+ cleanedUp = cleanedUp.replace(
33
+ /export default class/,
34
+ '@suite()\nexport default class'
35
+ )
36
+ }
37
+
38
+ // 3. Ensure `suite` is imported from `@sprucelabs/test-utils`
39
+ if (!this.hasSuiteImport(cleanedUp)) {
40
+ if (cleanedUp.includes('{ test')) {
41
+ cleanedUp = cleanedUp.replace('{ test', '{ test, suite')
42
+ } else if (cleanedUp.includes('test }')) {
43
+ cleanedUp = cleanedUp.replace('test }', 'test, suite }')
44
+ } else {
45
+ cleanedUp = cleanedUp.replace('test,', 'test,\n suite,')
46
+ }
47
+ }
48
+
49
+ const thisCallNames = this.findThisCalls(cleanedUp)
50
+ for (const name of thisCallNames) {
51
+ cleanedUp = this.removeStaticFromDeclaration(cleanedUp, name)
52
+ }
53
+
54
+ // 4. lifecicle methods
55
+ const methods = ['beforeEach', 'afterEach']
56
+ for (const method of methods) {
57
+ cleanedUp = cleanedUp.replace(
58
+ `protected static async ${method}()`,
59
+ `protected async ${method}()`
60
+ )
61
+ }
62
+
63
+ cleanedUp = this.fixNonNullAssertions(cleanedUp)
64
+
65
+ return cleanedUp
66
+ }
67
+
68
+ private hasSuiteImport(text: string): boolean {
69
+ const pattern = new RegExp(
70
+ `import\\s+(?:[\\s\\S]*?\\bsuite\\b[\\s\\S]*?)\\s+from\\s+['"]@sprucelabs/test-utils['"]`
71
+ )
72
+ return pattern.test(text)
73
+ }
74
+
75
+ private findThisCalls(contents: string): string[] {
76
+ // Matches `this.myProp` if followed by space, punctuation, parentheses, or end of string
77
+ const thisPropertyRegex = /this\.(\w+)(?=[\s.(),;]|$)/g
78
+ const names: string[] = []
79
+ let match: RegExpExecArray | null
80
+
81
+ while ((match = thisPropertyRegex.exec(contents)) !== null) {
82
+ const propName = match[1]
83
+ if (!names.includes(propName)) {
84
+ names.push(propName)
85
+ }
86
+ }
87
+
88
+ return names
89
+ }
90
+
91
+ private removeStaticFromDeclaration(
92
+ contents: string,
93
+ name: string
94
+ ): string {
95
+ /**
96
+ * 1) Remove `static` for methods/getters/setters, e.g.:
97
+ * private static async doSomething() => private async doSomething()
98
+ * private static get value() => private get value()
99
+ * private static set value(v) => private set value(v)
100
+ */
101
+ const methodPattern = new RegExp(
102
+ `((?:public|protected|private)?\\s+)?` + // group 1
103
+ `static\\s+` + // literal "static "
104
+ `(?:(async)\\s+)?` + // group 2: "async"?
105
+ `(?:(get|set)\\s+)?` + // group 3: "get" or "set"?
106
+ `(${name})\\s*\\(`, // group 4: the identifier + '('
107
+ 'g'
108
+ )
109
+ let updated = contents.replace(
110
+ methodPattern,
111
+ (match, g1, g2, g3, g4) => {
112
+ const asyncPart = g2 ? g2 + ' ' : ''
113
+ const accessorPart = g3 ? g3 + ' ' : ''
114
+ // Rebuild the declaration without "static"
115
+ return `${g1 ?? ''}${asyncPart}${accessorPart}${g4}(`
116
+ }
117
+ )
118
+
119
+ /**
120
+ * 2) Remove `static` from property declarations and add a non-null assertion.
121
+ * e.g.
122
+ * private static myProp: Type => private myProp!: Type
123
+ */
124
+ const propertyPattern = new RegExp(
125
+ `((?:public|protected|private)?\\s+)?` + // group 1: optional visibility
126
+ `static\\s+` + // literal "static "
127
+ `(${name})` + // group 2: the property name
128
+ `(?=[\\s=:\\[;]|$)`, // lookahead: space, '=', ':', '[', ';', or end-of-string
129
+ 'g'
130
+ )
131
+ updated = updated.replace(propertyPattern, (match, g1, g2) => {
132
+ // g1 = "private " / "public " / "protected " or empty
133
+ // g2 = property name
134
+ return `${g1 ?? ''}${g2}!`
135
+ })
136
+
137
+ return updated
138
+ }
139
+
140
+ private fixNonNullAssertions(contents: string): string {
141
+ const lines = contents.split('\n')
142
+
143
+ const propertyRegex =
144
+ /^(\s*)(public|protected|private)(\s+readonly)?\s+(\w+)\s*(!)?\s*:\s*([^=;]+)(=.*)?;?$/
145
+
146
+ const updatedLines = lines.map((originalLine) => {
147
+ // Skip lines containing "static"
148
+ if (originalLine.includes('static')) {
149
+ return originalLine
150
+ }
151
+
152
+ const match = originalLine.match(propertyRegex)
153
+ if (!match) {
154
+ return originalLine
155
+ }
156
+
157
+ let [
158
+ ,
159
+ leadingWhitespace,
160
+ visibility,
161
+ readonlyPart = '',
162
+ propName,
163
+ exclamation,
164
+ typeDecl,
165
+ assignment,
166
+ ] = match
167
+
168
+ // Trim trailing whitespace from the type
169
+ typeDecl = typeDecl.trim()
170
+
171
+ if (assignment) {
172
+ // Remove the bang if there's an assignment
173
+ exclamation = ''
174
+
175
+ // Remove trailing semicolon
176
+ assignment = assignment.replace(/;$/, '')
177
+
178
+ // Ensure we always have " = " at the start
179
+ // E.g. "=something" => " = something"
180
+ assignment = assignment.replace(/^=\s*/, ' = ')
181
+ } else {
182
+ // No assignment? Add bang
183
+ exclamation = '!'
184
+ }
185
+
186
+ // Rebuild line, preserving leading indentation
187
+ const rebuilt = `${leadingWhitespace}${visibility}${readonlyPart} ${propName}${exclamation}: ${typeDecl}${assignment ?? ''}`
188
+ return rebuilt
189
+ })
190
+
191
+ return updatedLines.join('\n')
192
+ }
193
+ }
194
+
195
+ export interface StaticToInstanceTestFileMigrator {
196
+ migrate(contents: string): string
197
+ }