@sprucelabs/spruce-cli 22.2.0 → 23.0.0

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 (145) hide show
  1. package/.eslintcache +1 -1
  2. package/build/.spruce/errors/errors.types.d.ts +4 -4
  3. package/build/.spruce/errors/options.types.d.ts +3 -3
  4. package/build/.spruce/errors/spruceCli/appControllerAlreadyExists.schema.d.ts +3 -0
  5. package/build/.spruce/errors/spruceCli/appControllerAlreadyExists.schema.js +12 -0
  6. package/build/.spruce/errors/spruceCli/appControllerAlreadyExists.schema.js.map +1 -0
  7. package/build/.spruce/schemas/schemas.types.d.ts +2 -4
  8. package/build/__tests__/behavioral/features/InstallingFeaturesDirectly.test.d.ts +17 -0
  9. package/build/__tests__/behavioral/features/InstallingFeaturesDirectly.test.js +142 -0
  10. package/build/__tests__/behavioral/features/InstallingFeaturesDirectly.test.js.map +1 -0
  11. package/build/__tests__/behavioral/onboard/StartingOnboarding.test.js +17 -7
  12. package/build/__tests__/behavioral/onboard/StartingOnboarding.test.js.map +1 -1
  13. package/build/__tests__/behavioral/schemas/HandlesRelatedSchemas.test.js +1 -1
  14. package/build/__tests__/behavioral/schemas/HandlesRelatedSchemas.test.js.map +1 -1
  15. package/build/__tests__/behavioral/schemas/UsingSchemasInCli.test.js +17 -7
  16. package/build/__tests__/behavioral/schemas/UsingSchemasInCli.test.js.map +1 -1
  17. package/build/__tests__/behavioral/tests/SelectingAnAbstractTestClass.test.js +1 -1
  18. package/build/__tests__/behavioral/tests/SelectingAnAbstractTestClass.test.js.map +1 -1
  19. package/build/__tests__/behavioral/views/{CreatingAnAppViewController.test.d.ts → CreatingAnAppController.test.d.ts} +9 -5
  20. package/build/__tests__/behavioral/views/{CreatingAnAppViewController.test.js → CreatingAnAppController.test.js} +63 -34
  21. package/build/__tests__/behavioral/views/CreatingAnAppController.test.js.map +1 -0
  22. package/build/__tests__/behavioral/views/CreatingViewControllers.test.d.ts +5 -0
  23. package/build/__tests__/behavioral/views/CreatingViewControllers.test.js +37 -0
  24. package/build/__tests__/behavioral/views/CreatingViewControllers.test.js.map +1 -0
  25. package/build/__tests__/behavioral/views/KeepingViewsInSync.test.d.ts +1 -0
  26. package/build/__tests__/behavioral/views/KeepingViewsInSync.test.js +14 -0
  27. package/build/__tests__/behavioral/views/KeepingViewsInSync.test.js.map +1 -1
  28. package/build/__tests__/behavioral/watchers/WatchingForChanges.test.js +5 -10
  29. package/build/__tests__/behavioral/watchers/WatchingForChanges.test.js.map +1 -1
  30. package/build/__tests__/implementation/ArgParser.test.js +17 -7
  31. package/build/__tests__/implementation/ArgParser.test.js.map +1 -1
  32. package/build/__tests__/implementation/BulkImporting.test.js +17 -7
  33. package/build/__tests__/implementation/BulkImporting.test.js.map +1 -1
  34. package/build/__tests__/implementation/CommanderCommandResultMapper.test.js +17 -7
  35. package/build/__tests__/implementation/CommanderCommandResultMapper.test.js.map +1 -1
  36. package/build/__tests__/implementation/EventContractCleanerUtil.test.js +17 -7
  37. package/build/__tests__/implementation/EventContractCleanerUtil.test.js.map +1 -1
  38. package/build/__tests__/implementation/FeaturesUtil.test.js +17 -7
  39. package/build/__tests__/implementation/FeaturesUtil.test.js.map +1 -1
  40. package/build/__tests__/implementation/JestJsonParser.test.js +17 -7
  41. package/build/__tests__/implementation/JestJsonParser.test.js.map +1 -1
  42. package/build/__tests__/implementation/SchemaValueTypeWriter.test.js +1 -1
  43. package/build/__tests__/implementation/SchemaValueTypeWriter.test.js.map +1 -1
  44. package/build/__tests__/implementation/TerminalInterface.test.js +17 -7
  45. package/build/__tests__/implementation/TerminalInterface.test.js.map +1 -1
  46. package/build/errors/SpruceError.js +2 -2
  47. package/build/errors/SpruceError.js.map +1 -1
  48. package/build/errors/{appViewControllerAlreadyExists.builder.js → appControllerAlreadyExists.builder.js} +2 -2
  49. package/build/errors/appControllerAlreadyExists.builder.js.map +1 -0
  50. package/build/features/cache/CacheFeature.d.ts +8 -5
  51. package/build/features/cache/CacheFeature.js.map +1 -1
  52. package/build/features/conversation/ConversationFeature.d.ts +8 -5
  53. package/build/features/conversation/ConversationFeature.js.map +1 -1
  54. package/build/features/dependencies/DependencyFeature.d.ts +8 -5
  55. package/build/features/dependencies/DependencyFeature.js.map +1 -1
  56. package/build/features/deploy/DeployFeature.d.ts +8 -5
  57. package/build/features/deploy/DeployFeature.js.map +1 -1
  58. package/build/features/error/ErrorFeature.d.ts +8 -8
  59. package/build/features/error/ErrorFeature.js.map +1 -1
  60. package/build/features/eventContract/EventContractFeature.d.ts +8 -5
  61. package/build/features/eventContract/EventContractFeature.js.map +1 -1
  62. package/build/features/onboard/OnboardFeature.d.ts +8 -5
  63. package/build/features/onboard/OnboardFeature.js.map +1 -1
  64. package/build/features/organization/OrganizationFeature.d.ts +3 -0
  65. package/build/features/permission/PermissionFeature.d.ts +3 -0
  66. package/build/features/person/PersonFeature.d.ts +3 -0
  67. package/build/features/polish/PolishFeature.d.ts +3 -0
  68. package/build/features/sandbox/SandboxFeature.d.ts +8 -5
  69. package/build/features/sandbox/SandboxFeature.js.map +1 -1
  70. package/build/features/skill/actions/BootAction.d.ts +9 -9
  71. package/build/features/skill/actions/BootAction.js.map +1 -1
  72. package/build/features/skill/actions/InstallFeatureAction.d.ts +37 -0
  73. package/build/features/skill/actions/InstallFeatureAction.js +80 -0
  74. package/build/features/skill/actions/InstallFeatureAction.js.map +1 -0
  75. package/build/features/store/StoreFeature.d.ts +8 -5
  76. package/build/features/store/StoreFeature.js.map +1 -1
  77. package/build/features/test/TestFeature.d.ts +8 -5
  78. package/build/features/test/TestFeature.js.map +1 -1
  79. package/build/features/validateAndNormalize.utility.js.map +1 -1
  80. package/build/features/view/ViewFeature.d.ts +8 -8
  81. package/build/features/view/ViewFeature.js.map +1 -1
  82. package/build/features/view/actions/CreateAppAction.d.ts +1 -0
  83. package/build/features/view/actions/CreateAppAction.js +4 -3
  84. package/build/features/view/actions/CreateAppAction.js.map +1 -1
  85. package/build/features/view/actions/SyncAction.js +6 -6
  86. package/build/features/view/actions/SyncAction.js.map +1 -1
  87. package/build/features/view/writers/ViewWriter.d.ts +2 -1
  88. package/build/features/view/writers/ViewWriter.js +15 -8
  89. package/build/features/view/writers/ViewWriter.js.map +1 -1
  90. package/build/features/vscode/VsCodeFeature.d.ts +8 -5
  91. package/build/features/vscode/VsCodeFeature.js.map +1 -1
  92. package/build/features/watch/WatchFeature.js +1 -2
  93. package/build/features/watch/WatchFeature.js.map +1 -1
  94. package/build/tests/AbstractCliTest.js +17 -7
  95. package/build/tests/AbstractCliTest.js.map +1 -1
  96. package/build/tests/cleanTestData.js +17 -7
  97. package/build/tests/cleanTestData.js.map +1 -1
  98. package/build/utilities/introspection.utility.js +17 -7
  99. package/build/utilities/introspection.utility.js.map +1 -1
  100. package/junit.xml +8 -1773
  101. package/package.json +30 -30
  102. package/src/.spruce/errors/errors.types.ts +4 -4
  103. package/src/.spruce/errors/options.types.ts +3 -3
  104. package/src/.spruce/errors/spruceCli/appControllerAlreadyExists.schema.ts +16 -0
  105. package/src/.spruce/schemas/schemas.types.ts +1 -1
  106. package/src/__tests__/behavioral/features/InstallingFeaturesDirectly.test.ts +149 -0
  107. package/src/__tests__/behavioral/schemas/HandlesRelatedSchemas.test.ts +1 -1
  108. package/src/__tests__/behavioral/tests/SelectingAnAbstractTestClass.test.ts +1 -1
  109. package/src/__tests__/behavioral/views/{CreatingAnAppViewController.test.ts → CreatingAnAppController.test.ts} +57 -25
  110. package/src/__tests__/behavioral/views/CreatingViewControllers.test.ts +28 -0
  111. package/src/__tests__/behavioral/views/KeepingViewsInSync.test.ts +16 -0
  112. package/src/__tests__/behavioral/watchers/WatchingForChanges.test.ts +6 -11
  113. package/src/__tests__/implementation/SchemaValueTypeWriter.test.ts +1 -1
  114. package/src/errors/SpruceError.ts +2 -2
  115. package/src/errors/{appViewControllerAlreadyExists.builder.ts → appControllerAlreadyExists.builder.ts} +1 -1
  116. package/src/features/cache/CacheFeature.ts +10 -6
  117. package/src/features/conversation/ConversationFeature.ts +10 -6
  118. package/src/features/dependencies/DependencyFeature.ts +10 -6
  119. package/src/features/deploy/DeployFeature.ts +10 -6
  120. package/src/features/error/ErrorFeature.ts +10 -10
  121. package/src/features/eventContract/EventContractFeature.ts +10 -6
  122. package/src/features/onboard/OnboardFeature.ts +10 -6
  123. package/src/features/organization/OrganizationFeature.ts +4 -0
  124. package/src/features/permission/PermissionFeature.ts +4 -0
  125. package/src/features/person/PersonFeature.ts +4 -0
  126. package/src/features/polish/PolishFeature.ts +4 -0
  127. package/src/features/sandbox/SandboxFeature.ts +10 -6
  128. package/src/features/skill/actions/BootAction.ts +11 -11
  129. package/src/features/skill/actions/InstallFeatureAction.ts +96 -0
  130. package/src/features/store/StoreFeature.ts +10 -6
  131. package/src/features/test/TestFeature.ts +10 -6
  132. package/src/features/validateAndNormalize.utility.ts +2 -1
  133. package/src/features/view/ViewFeature.ts +10 -10
  134. package/src/features/view/actions/CreateAppAction.ts +8 -4
  135. package/src/features/view/actions/SyncAction.ts +12 -8
  136. package/src/features/view/writers/ViewWriter.ts +34 -9
  137. package/src/features/vscode/VsCodeFeature.ts +9 -6
  138. package/src/features/watch/WatchFeature.ts +2 -3
  139. package/build/.spruce/errors/spruceCli/appViewControllerAlreadyExists.schema.d.ts +0 -3
  140. package/build/.spruce/errors/spruceCli/appViewControllerAlreadyExists.schema.js +0 -12
  141. package/build/.spruce/errors/spruceCli/appViewControllerAlreadyExists.schema.js.map +0 -1
  142. package/build/__tests__/behavioral/views/CreatingAnAppViewController.test.js.map +0 -1
  143. package/build/errors/appViewControllerAlreadyExists.builder.js.map +0 -1
  144. package/src/.spruce/errors/spruceCli/appViewControllerAlreadyExists.schema.ts +0 -16
  145. /package/build/errors/{appViewControllerAlreadyExists.builder.d.ts → appControllerAlreadyExists.builder.d.ts} +0 -0
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  ]
18
18
  },
19
19
  "license": "MIT",
20
- "version": "22.2.0",
20
+ "version": "23.0.0",
21
21
  "bin": {
22
22
  "spruce": "./build/index.js"
23
23
  },
@@ -73,23 +73,23 @@
73
73
  },
74
74
  "dependencies": {
75
75
  "@jest/reporters": "^29.7.0",
76
- "@sprucelabs/error": "^6.0.537",
77
- "@sprucelabs/globby": "^2.0.498",
78
- "@sprucelabs/heartwood-view-controllers": "^111.1.0",
79
- "@sprucelabs/jest-json-reporter": "^8.0.538",
80
- "@sprucelabs/mercury-client": "^42.0.590",
81
- "@sprucelabs/mercury-event-emitter": "^42.0.590",
82
- "@sprucelabs/mercury-types": "^47.0.594",
83
- "@sprucelabs/schema": "^30.0.553",
84
- "@sprucelabs/spruce-core-schemas": "^40.1.540",
85
- "@sprucelabs/spruce-event-utils": "^40.1.314",
86
- "@sprucelabs/spruce-skill-utils": "^31.0.614",
87
- "@sprucelabs/spruce-templates": "^22.2.0",
76
+ "@sprucelabs/error": "^6.0.556",
77
+ "@sprucelabs/globby": "^2.0.501",
78
+ "@sprucelabs/heartwood-view-controllers": "^113.0.1",
79
+ "@sprucelabs/jest-json-reporter": "^8.0.558",
80
+ "@sprucelabs/mercury-client": "^42.0.658",
81
+ "@sprucelabs/mercury-event-emitter": "^42.0.658",
82
+ "@sprucelabs/mercury-types": "^47.0.640",
83
+ "@sprucelabs/schema": "^31.0.3",
84
+ "@sprucelabs/spruce-core-schemas": "^40.1.585",
85
+ "@sprucelabs/spruce-event-utils": "^40.1.369",
86
+ "@sprucelabs/spruce-skill-utils": "^31.1.8",
87
+ "@sprucelabs/spruce-templates": "^23.0.0",
88
88
  "@typescript-eslint/eslint-plugin": "^7.7.1",
89
89
  "@typescript-eslint/parser": "^7.7.1",
90
90
  "cfonts": "^3.3.0",
91
91
  "chalk": "4.1.2",
92
- "chokidar": "^4.0.1",
92
+ "chokidar": "^4.0.3",
93
93
  "cli-table3": "^0.6.5",
94
94
  "commander": "7.2.0",
95
95
  "emphasize": "4.2.0",
@@ -106,27 +106,27 @@
106
106
  "terminal-kit": "sprucelabsai/terminal-kit",
107
107
  "tree-kill": "^1.2.2",
108
108
  "tsutils": "^3.21.0",
109
- "typescript": "^5.6.3",
110
- "uuid": "^11.0.2"
109
+ "typescript": "^5.7.2",
110
+ "uuid": "^11.0.3"
111
111
  },
112
112
  "devDependencies": {
113
- "@sprucelabs/data-stores": "^28.3.207",
114
- "@sprucelabs/jest-sheets-reporter": "^3.0.182",
115
- "@sprucelabs/mercury-core-events": "^25.0.35",
116
- "@sprucelabs/resolve-path-aliases": "^2.0.513",
117
- "@sprucelabs/spruce-conversation-plugin": "^62.4.2",
118
- "@sprucelabs/spruce-deploy-plugin": "^62.4.2",
119
- "@sprucelabs/spruce-store-plugin": "^62.4.2",
120
- "@sprucelabs/spruce-test-fixtures": "^62.4.2",
121
- "@sprucelabs/test": "^9.0.57",
122
- "@sprucelabs/test-utils": "^5.1.496",
113
+ "@sprucelabs/data-stores": "^28.3.281",
114
+ "@sprucelabs/jest-sheets-reporter": "^3.0.197",
115
+ "@sprucelabs/mercury-core-events": "^25.0.104",
116
+ "@sprucelabs/resolve-path-aliases": "^2.0.523",
117
+ "@sprucelabs/spruce-conversation-plugin": "^62.6.12",
118
+ "@sprucelabs/spruce-deploy-plugin": "^62.6.12",
119
+ "@sprucelabs/spruce-store-plugin": "^62.6.12",
120
+ "@sprucelabs/spruce-test-fixtures": "^62.6.12",
121
+ "@sprucelabs/test": "^9.0.64",
122
+ "@sprucelabs/test-utils": "^5.1.529",
123
123
  "@types/blessed": "^0.1.25",
124
124
  "@types/eslint": "^9.6.1",
125
125
  "@types/fs-extra": "^11.0.4",
126
126
  "@types/inquirer": "^9.0.7",
127
127
  "@types/lodash": "^4.17.13",
128
128
  "@types/md5": "^2.3.5",
129
- "@types/node": "^22.8.7",
129
+ "@types/node": "^22.10.2",
130
130
  "@types/promise.allsettled": "^1.0.6",
131
131
  "@types/ps-node": "^0.1.3",
132
132
  "@types/semver": "^7.5.8",
@@ -138,8 +138,8 @@
138
138
  "chokidar-cli": "^3.0.0",
139
139
  "concurrently": "^9.1.0",
140
140
  "conventional-changelog-sprucelabs": "2.0.1",
141
- "dotenv": "^16.4.5",
142
- "eslint": "^9.14.0",
141
+ "dotenv": "^16.4.7",
142
+ "eslint": "^9.17.0",
143
143
  "eslint-config-spruce": "^11.2.26",
144
144
  "find-process": "^1.4.7",
145
145
  "jest": "^29.7.0",
@@ -150,7 +150,7 @@
150
150
  "ps-node": "^0.1.6",
151
151
  "ts-jest": "^29.2.5",
152
152
  "ts-node": "^10.9.2",
153
- "tsc-watch": "^6.2.0",
153
+ "tsc-watch": "^6.2.1",
154
154
  "tsconfig-paths": "^4.2.0"
155
155
  },
156
156
  "testSkillCache": {
@@ -1293,19 +1293,19 @@ export declare namespace SpruceErrors.SpruceCli {
1293
1293
  export declare namespace SpruceErrors.SpruceCli {
1294
1294
 
1295
1295
 
1296
- export interface AppViewControllerAlreadyExists {
1296
+ export interface AppControllerAlreadyExists {
1297
1297
 
1298
1298
  }
1299
1299
 
1300
- export interface AppViewControllerAlreadyExistsSchema extends SpruceSchema.Schema {
1301
- id: 'appViewControllerAlreadyExists',
1300
+ export interface AppControllerAlreadyExistsSchema extends SpruceSchema.Schema {
1301
+ id: 'appControllerAlreadyExists',
1302
1302
  namespace: 'SpruceCli',
1303
1303
  name: 'App view controller already exists',
1304
1304
  fields: {
1305
1305
  }
1306
1306
  }
1307
1307
 
1308
- export type AppViewControllerAlreadyExistsEntity = SchemaEntity<SpruceErrors.SpruceCli.AppViewControllerAlreadyExistsSchema>
1308
+ export type AppControllerAlreadyExistsEntity = SchemaEntity<SpruceErrors.SpruceCli.AppControllerAlreadyExistsSchema>
1309
1309
 
1310
1310
  }
1311
1311
 
@@ -124,13 +124,13 @@ export interface BuildFailedErrorOptions extends SpruceErrors.SpruceCli.BuildFai
124
124
  export interface BootErrorErrorOptions extends SpruceErrors.SpruceCli.BootError, ISpruceErrorOptions {
125
125
  code: 'BOOT_ERROR'
126
126
  }
127
- export interface AppViewControllerAlreadyExistsErrorOptions extends SpruceErrors.SpruceCli.AppViewControllerAlreadyExists, ISpruceErrorOptions {
128
- code: 'APP_VIEW_CONTROLLER_ALREADY_EXISTS'
127
+ export interface AppControllerAlreadyExistsErrorOptions extends SpruceErrors.SpruceCli.AppControllerAlreadyExists, ISpruceErrorOptions {
128
+ code: 'APP_CONTROLLER_ALREADY_EXISTS'
129
129
  }
130
130
  export interface ActionCancelledErrorOptions extends SpruceErrors.SpruceCli.ActionCancelled, ISpruceErrorOptions {
131
131
  code: 'ACTION_CANCELLED'
132
132
  }
133
133
 
134
- type ErrorOptions = | VscodeNotInstalledErrorOptions | ViewPluginAlreadyExistsErrorOptions | TransportAlreadyExistsErrorOptions | ThemeExistsErrorOptions | TestFailedErrorOptions | StoreExistsErrorOptions | SkillViewExistsErrorOptions | SkillNotRegisteredErrorOptions | SkillNotFoundErrorOptions | SchemaTemplateItemBuildingFailedErrorOptions | SchemaFailedToImportErrorOptions | SchemaExistsErrorOptions | NotLoggedInErrorOptions | NotImplementedErrorOptions | NoSkillsRegisteredErrorOptions | NoOrganizationsFoundErrorOptions | MissingDependenciesErrorOptions | MercuryResponseErrorErrorOptions | LintFailedErrorOptions | InvalidTestDirectoryErrorOptions | InvalidFeatureCodeErrorOptions | InvalidEventContractErrorOptions | InvalidCommandErrorOptions | GenericErrorOptions | FileExistsErrorOptions | FeatureNotInstalledErrorOptions | FailedToImportErrorOptions | ExecutingCommandFailedErrorOptions | DockerNotStartedErrorOptions | DirectoryNotSkillErrorOptions | DirectoryEmptyErrorOptions | DeployFailedErrorOptions | DependencyExistsErrorOptions | CreateAutoloaderFailedErrorOptions | CommandNotImplementedErrorOptions | CommandBlockedErrorOptions | CommandAbortedErrorOptions | CannotPromptInCiErrorOptions | CacheNotEnabledErrorOptions | BuildFailedErrorOptions | BootErrorErrorOptions | AppViewControllerAlreadyExistsErrorOptions | ActionCancelledErrorOptions
134
+ type ErrorOptions = | VscodeNotInstalledErrorOptions | ViewPluginAlreadyExistsErrorOptions | TransportAlreadyExistsErrorOptions | ThemeExistsErrorOptions | TestFailedErrorOptions | StoreExistsErrorOptions | SkillViewExistsErrorOptions | SkillNotRegisteredErrorOptions | SkillNotFoundErrorOptions | SchemaTemplateItemBuildingFailedErrorOptions | SchemaFailedToImportErrorOptions | SchemaExistsErrorOptions | NotLoggedInErrorOptions | NotImplementedErrorOptions | NoSkillsRegisteredErrorOptions | NoOrganizationsFoundErrorOptions | MissingDependenciesErrorOptions | MercuryResponseErrorErrorOptions | LintFailedErrorOptions | InvalidTestDirectoryErrorOptions | InvalidFeatureCodeErrorOptions | InvalidEventContractErrorOptions | InvalidCommandErrorOptions | GenericErrorOptions | FileExistsErrorOptions | FeatureNotInstalledErrorOptions | FailedToImportErrorOptions | ExecutingCommandFailedErrorOptions | DockerNotStartedErrorOptions | DirectoryNotSkillErrorOptions | DirectoryEmptyErrorOptions | DeployFailedErrorOptions | DependencyExistsErrorOptions | CreateAutoloaderFailedErrorOptions | CommandNotImplementedErrorOptions | CommandBlockedErrorOptions | CommandAbortedErrorOptions | CannotPromptInCiErrorOptions | CacheNotEnabledErrorOptions | BuildFailedErrorOptions | BootErrorErrorOptions | AppControllerAlreadyExistsErrorOptions | ActionCancelledErrorOptions
135
135
 
136
136
  export default ErrorOptions
@@ -0,0 +1,16 @@
1
+ import { SchemaRegistry } from '@sprucelabs/schema'
2
+ import { SpruceErrors } from '../errors.types'
3
+
4
+
5
+
6
+ const appControllerAlreadyExistsSchema: SpruceErrors.SpruceCli.AppControllerAlreadyExistsSchema = {
7
+ id: 'appControllerAlreadyExists',
8
+ namespace: 'SpruceCli',
9
+ name: 'App view controller already exists',
10
+ fields: {
11
+ }
12
+ }
13
+
14
+ SchemaRegistry.getInstance().trackSchema(appControllerAlreadyExistsSchema)
15
+
16
+ export default appControllerAlreadyExistsSchema
@@ -75,7 +75,7 @@ declare module '@sprucelabs/spruce-core-schemas/build/.spruce/schemas/core.schem
75
75
  interface WatcherDidDetectChangesEmitPayload {
76
76
 
77
77
 
78
- 'changes': ({ schemaId: 'generatedFile', version: 'v2020_07_22', values: SpruceSchemas.SpruceCli.v2020_07_22.GeneratedFile } | { schemaId: 'generatedDir', version: 'v2020_07_22', values: SpruceSchemas.SpruceCli.v2020_07_22.GeneratedDir })[]
78
+ 'changes': ({ id: 'generatedFile', values: SpruceSchemas.SpruceCli.v2020_07_22.GeneratedFile } | { id: 'generatedDir', values: SpruceSchemas.SpruceCli.v2020_07_22.GeneratedDir })[]
79
79
  }
80
80
 
81
81
  interface WatcherDidDetectChangesEmitPayloadSchema extends SpruceSchema.Schema {
@@ -0,0 +1,149 @@
1
+ import { SelectChoice } from '@sprucelabs/spruce-core-schemas'
2
+ import { test, assert, generateId } from '@sprucelabs/test-utils'
3
+ import { InstallFeatureOptions } from '../../../features/features.types'
4
+ import InstallFeatureAction, {
5
+ InstallFeatureActionOptions,
6
+ } from '../../../features/skill/actions/InstallFeatureAction'
7
+ import AbstractSkillTest from '../../../tests/AbstractSkillTest'
8
+
9
+ export default class InstallingFeaturesDirectlyTest extends AbstractSkillTest {
10
+ private static action: InstallFeatureAction
11
+ protected static skillCacheKey = 'skills'
12
+
13
+ protected static async beforeEach() {
14
+ await super.beforeEach()
15
+ this.action = this.Action('skill', 'installFeature')
16
+ }
17
+
18
+ protected static async afterEach() {
19
+ this.ui.reset()
20
+ await super.afterEach()
21
+ }
22
+
23
+ @test()
24
+ protected static async hasExpectedAliases() {
25
+ assert.isEqualDeep(this.action.commandAliases, ['install.feature'])
26
+ }
27
+
28
+ @test()
29
+ protected static async promptsForWhichFeatureToInstall() {
30
+ await this.executeAndWaitForPrompt()
31
+
32
+ const features = {
33
+ error: 'Errors',
34
+ event: 'Events',
35
+ schema: 'Schemas',
36
+ store: 'Stores (including database support)',
37
+ test: 'Tests',
38
+ view: 'Views',
39
+ }
40
+
41
+ const choices: SelectChoice[] = Object.keys(features).map((key) => ({
42
+ label: features[key as keyof typeof features],
43
+ value: key,
44
+ }))
45
+
46
+ const last = this.ui.getLastInvocation()
47
+ assert.isEqual(last.command, 'prompt')
48
+ assert.isEqualDeep(last.options, {
49
+ type: 'select',
50
+ label: 'Which feature do you want to install?',
51
+ isRequired: true,
52
+ options: {
53
+ choices,
54
+ },
55
+ })
56
+ }
57
+
58
+ @test('can install store feature', 'store')
59
+ @test('can install view feature', 'view')
60
+ @test('can install test feature', 'test')
61
+ protected static async selectingAFeatureTriesToInstallIt(featureCode: any) {
62
+ let passedOption: InstallFeatureOptions | undefined
63
+
64
+ this.featureInstaller.install = async (options) => {
65
+ passedOption = options
66
+ return {}
67
+ }
68
+ await this.executeAndWaitForPrompt()
69
+ await this.sendInput(featureCode)
70
+
71
+ assert.isEqualDeep(passedOption, { features: [{ code: featureCode }] })
72
+ }
73
+
74
+ @test()
75
+ protected static async returnsResultsFromFeatureInstall() {
76
+ const results = {
77
+ [generateId()]: generateId(),
78
+ [generateId()]: generateId(),
79
+ }
80
+
81
+ this.featureInstaller.install = async () => results
82
+
83
+ const { promise } = await this.executeAndWaitForPrompt()
84
+
85
+ await this.sendInput('store')
86
+
87
+ const actual = await promise
88
+
89
+ assert.isEqualDeep(actual, results)
90
+ }
91
+
92
+ @test('skips view feature if already installed', 'view')
93
+ @test('skips store feature if already installed', 'store')
94
+ @test('skips test feature if already installed', 'test')
95
+ protected static async doesNotShowOptionForInstalledFeature(code: string) {
96
+ this.featureInstaller.install = async () => ({})
97
+ const installed = ['skill', code]
98
+ this.featureInstaller.isInstalled = async (code) =>
99
+ installed.includes(code)
100
+ await this.executeAndWaitForPrompt()
101
+ const { options } = this.ui.getLastInvocation()
102
+ const choices = options.options.choices as SelectChoice[]
103
+ assert.doesNotInclude(
104
+ choices.map((c) => c.value),
105
+ code
106
+ )
107
+ }
108
+
109
+ @test()
110
+ protected static async ifThereAreNoFeaturesToInstallDonNotPrompt() {
111
+ this.featureInstaller.isInstalled = async () => true
112
+ const results = await this.execute()
113
+ assert.isEqualDeep(results, {
114
+ summaryLines: [
115
+ 'Nothing to install, you have already installed everything!',
116
+ ],
117
+ })
118
+ }
119
+
120
+ @test('should install directly view', 'view')
121
+ @test('should install directly store', 'store')
122
+ @test('should install directly test', 'test')
123
+ protected static async passingFeatureCodeToActionSkipsPrompt(code: any) {
124
+ let passedOption: InstallFeatureOptions | undefined
125
+ this.featureInstaller.install = async (options) => {
126
+ passedOption = options
127
+ return {}
128
+ }
129
+
130
+ this.ui.prompt = async () => assert.fail('Should not prompt')
131
+
132
+ await this.execute({ code })
133
+ assert.isEqualDeep(passedOption, { features: [{ code }] })
134
+ }
135
+
136
+ private static async sendInput(featureCode: string) {
137
+ await this.ui.sendInput(featureCode)
138
+ }
139
+
140
+ private static async executeAndWaitForPrompt() {
141
+ const promise = this.execute()
142
+ await this.ui.waitForInput()
143
+ return { promise }
144
+ }
145
+
146
+ private static execute(options?: InstallFeatureActionOptions) {
147
+ return this.action.execute(options ?? {})
148
+ }
149
+ }
@@ -48,7 +48,7 @@ export default class HandlesRelatedSchemasTest extends AbstractSchemaTest {
48
48
 
49
49
  assert.doesInclude(
50
50
  typesContent,
51
- "[fullyQualifiedEventName:string]: { schemaId: 'eventSignature', version: 'v2020_07_22', values: SpruceSchemas.TestingSchemas.v2020_07_22.EventSignature } | { schemaId: 'eventSignature2', version: 'v2020_07_22', values: SpruceSchemas.TestingSchemas.v2020_07_22.EventSignature2 }"
51
+ "[fullyQualifiedEventName:string]: { id: 'eventSignature', values: SpruceSchemas.TestingSchemas.v2020_07_22.EventSignature } | { id: 'eventSignature2', values: SpruceSchemas.TestingSchemas.v2020_07_22.EventSignature2 }"
52
52
  )
53
53
 
54
54
  await this.Service('typeChecker').check(typesPath)
@@ -131,8 +131,8 @@ export default class SelectingAnAbstractTestClassTest extends AbstractTestTest {
131
131
  for (const feat of featuresWithRegisteredTests) {
132
132
  await this.featureInstaller.install({
133
133
  features: [
134
+ //@ts-ignore
134
135
  {
135
- //@ts-ignore
136
136
  code: feat.featureCode,
137
137
  },
138
138
  ],
@@ -1,12 +1,13 @@
1
- import { diskUtil } from '@sprucelabs/spruce-skill-utils'
1
+ import { diskUtil, namesUtil } from '@sprucelabs/spruce-skill-utils'
2
2
  import { test, assert, errorAssert, generateId } from '@sprucelabs/test-utils'
3
3
  import CreateAppAction from '../../../features/view/actions/CreateAppAction'
4
4
  import AbstractSkillTest from '../../../tests/AbstractSkillTest'
5
5
  import testUtil from '../../../tests/utilities/test.utility'
6
6
 
7
- export default class CreatingAnAppViewControllerTest extends AbstractSkillTest {
7
+ export default class CreatingAnAppControllerTest extends AbstractSkillTest {
8
8
  protected static skillCacheKey = 'views'
9
- private static avcPath: string
9
+ private static acPath: string
10
+ private static skillNamespace = generateId().replace(/\d/g, '')
10
11
 
11
12
  private static action: CreateAppAction
12
13
  private static lastExecution: {
@@ -16,7 +17,9 @@ export default class CreatingAnAppViewControllerTest extends AbstractSkillTest {
16
17
 
17
18
  protected static async beforeAll(): Promise<void> {
18
19
  await super.beforeAll()
19
- this.avcPath = this.resolvePath('src/App.avc.ts')
20
+ this.acPath = this.resolvePath('src/App.ac.ts')
21
+ const pgk = this.Service('pkg')
22
+ pgk.set({ path: 'skill.namespace', value: this.skillNamespace })
20
23
  }
21
24
 
22
25
  protected static async beforeEach(): Promise<void> {
@@ -33,12 +36,12 @@ export default class CreatingAnAppViewControllerTest extends AbstractSkillTest {
33
36
  const results = await this.execute()
34
37
  assert.isFalsy(results.errors)
35
38
 
36
- testUtil.assertFileByPathInGeneratedFiles(this.avcPath, results.files)
39
+ testUtil.assertFileByPathInGeneratedFiles(this.acPath, results.files)
37
40
 
38
41
  assert.doesInclude(results.files, {
39
42
  action: 'generated',
40
- name: 'App.avc.ts',
41
- path: this.avcPath,
43
+ name: 'App.ac.ts',
44
+ path: this.acPath,
42
45
  })
43
46
 
44
47
  assert.doesInclude(results.files, {
@@ -50,7 +53,6 @@ export default class CreatingAnAppViewControllerTest extends AbstractSkillTest {
50
53
 
51
54
  @test()
52
55
  protected static async syncsViewsOnCreation() {
53
- debugger
54
56
  assert.doesInclude(this.lastExecution, {
55
57
  actionCode: 'sync',
56
58
  featureCode: 'view',
@@ -68,22 +70,22 @@ export default class CreatingAnAppViewControllerTest extends AbstractSkillTest {
68
70
  }
69
71
 
70
72
  @test()
71
- protected static async avcIncludesExpectedContents() {
72
- const contents = diskUtil.readFile(this.avcPath)
73
+ protected static async acIncludesExpectedContents() {
74
+ const contents = diskUtil.readFile(this.acPath)
73
75
  assert.doesInclude(
74
76
  contents,
75
- 'export default class AppViewControllerImpl extends AbstractAppViewController'
77
+ `export default class ${this.className} extends AbstractAppController`
76
78
  )
77
79
 
78
80
  assert.doesInclude(
79
81
  contents,
80
- 'public async (_options: AppViewControllerLoadOptions)'
82
+ 'public async load(_options: AppControllerLoadOptions)'
81
83
  )
82
84
  }
83
85
 
84
86
  @test()
85
87
  protected static async generatedFilesAreValid() {
86
- await this.Service('typeChecker').check(this.avcPath)
88
+ await this.Service('typeChecker').check(this.acPath)
87
89
  await this.assertCombinedViewsFileIsValid()
88
90
  }
89
91
 
@@ -96,36 +98,62 @@ export default class CreatingAnAppViewControllerTest extends AbstractSkillTest {
96
98
  @test()
97
99
  protected static async callsHeartwoodImportFunctionAsExpected() {
98
100
  this.assertCombinedViewsContains(
99
- 'heartwood({ vcs, pluginsByName, App: AppViewControllerImpl })'
101
+ `heartwood({ vcs, pluginsByName, App: ${this.className} })`
100
102
  )
101
103
  }
102
104
 
103
105
  @test()
104
- protected static async throwsEvenIfAppAvcMoves() {
105
- const destination = this.resolvePath(`src/${generateId()}/App.avc.ts`)
106
- diskUtil.moveFile(this.avcPath, destination)
106
+ protected static async combineViewsTypesAsExpected() {
107
+ const expected = `interface AppControllerMap {
108
+ '${this.skillNamespace}' : ${this.className}
109
+ }`
110
+
111
+ this.assertCombinedViewsContains(expected)
112
+ }
113
+
114
+ @test()
115
+ protected static async throwsEvenIfAppMoves() {
116
+ const destination = this.resolvePath(`src/${generateId()}/App.ac.ts`)
117
+ diskUtil.moveFile(this.acPath, destination)
107
118
 
108
119
  await this.executeAndAssertThrowsAvcExists()
109
- this.avcPath = destination
120
+ this.acPath = destination
110
121
  }
111
122
 
112
123
  @test()
113
- protected static async canRenameAppAvcAndItUpdatesCombinedViews() {
114
- const contents = diskUtil.readFile(this.avcPath)
124
+ protected static async canRenameAppAndItUpdatesCombinedViews() {
125
+ const contents = diskUtil.readFile(this.acPath)
115
126
  const updatedContents = contents.replace(
116
- 'AppViewControllerImpl',
117
- 'NewAppViewControllerImpl'
127
+ this.className,
128
+ 'NewAppControllerImpl'
118
129
  )
119
- diskUtil.writeFile(this.avcPath, updatedContents)
130
+ diskUtil.writeFile(this.acPath, updatedContents)
120
131
  await this.Action('view', 'sync').execute({})
121
132
 
122
133
  this.assertCombinedViewsContains(
123
- 'heartwood({ vcs, pluginsByName, App: NewAppViewControllerImpl })'
134
+ 'heartwood({ vcs, pluginsByName, App: NewAppControllerImpl })'
124
135
  )
125
136
 
126
137
  await this.assertCombinedViewsFileIsValid()
127
138
  }
128
139
 
140
+ @test()
141
+ protected static async importsAppFromCombinedViews() {
142
+ const testScript =
143
+ `import { App } from '#` +
144
+ `spruce/views/views'
145
+ const app = new App({} as any)
146
+ console.log(app)
147
+ if (App.id !== '${this.skillNamespace}') {
148
+ throw new Error('App.id is not correct')
149
+ }`
150
+
151
+ const testScriptPath = this.resolvePath('src/test.ts')
152
+ diskUtil.writeFile(testScriptPath, testScript)
153
+
154
+ await this.Service('typeChecker').check(testScriptPath)
155
+ }
156
+
129
157
  private static async assertCombinedViewsFileIsValid() {
130
158
  await this.Service('typeChecker').check(this.combinedViewsPath)
131
159
  }
@@ -143,12 +171,16 @@ export default class CreatingAnAppViewControllerTest extends AbstractSkillTest {
143
171
  return this.resolveHashSprucePath('views', 'views.ts')
144
172
  }
145
173
 
174
+ private static get className() {
175
+ return `${namesUtil.toPascal(this.skillNamespace)}AppController`
176
+ }
177
+
146
178
  private static async executeAndAssertThrowsAvcExists() {
147
179
  const results = await this.execute()
148
180
  assert.isTruthy(results.errors)
149
181
  errorAssert.assertError(
150
182
  results.errors[0],
151
- 'APP_VIEW_CONTROLLER_ALREADY_EXISTS'
183
+ 'APP_CONTROLLER_ALREADY_EXISTS'
152
184
  )
153
185
  }
154
186
 
@@ -0,0 +1,28 @@
1
+ import { diskUtil } from '@sprucelabs/spruce-skill-utils'
2
+ import { test, assert } from '@sprucelabs/test-utils'
3
+ import CreateAction from '../../../features/view/actions/CreateAction'
4
+ import AbstractSkillTest from '../../../tests/AbstractSkillTest'
5
+
6
+ export default class CreatingViewControllersTest extends AbstractSkillTest {
7
+ protected static skillCacheKey = 'views'
8
+
9
+ @test()
10
+ protected static async canCreateListViewController() {
11
+ const action = this.Action('view', 'create') as CreateAction
12
+ const results = await action.execute({
13
+ viewType: 'view',
14
+ isRoot: false,
15
+ viewModel: 'List',
16
+ nameReadable: 'My List',
17
+ namePascal: 'MyList',
18
+ })
19
+
20
+ assert.isFalsy(results.errors)
21
+
22
+ const file = results.files?.[0]
23
+ assert.isTruthy(file?.path)
24
+ const contents = diskUtil.readFile(file.path)
25
+
26
+ assert.doesInclude(contents, 'extends AbstractViewController<List>')
27
+ }
28
+ }
@@ -1,3 +1,4 @@
1
+ import { diskUtil } from '@sprucelabs/spruce-skill-utils'
1
2
  import { test, assert } from '@sprucelabs/test-utils'
2
3
  import { FeatureActionResponse } from '../../../features/features.types'
3
4
  import SyncAction from '../../../features/view/actions/SyncAction'
@@ -46,6 +47,21 @@ export default class KeepingViewsInSyncTest extends AbstractSkillTest {
46
47
  await this.assertValuedViewsFile(results)
47
48
  }
48
49
 
50
+ @test()
51
+ protected static async exportUndefinedApp() {
52
+ const testScript =
53
+ `import { App } from '#` +
54
+ `spruce/views/views'
55
+ if (App !== undefined) {
56
+ throw new Error('App should be undefined')
57
+ }`
58
+
59
+ const testScriptPath = this.resolvePath('src/test.ts')
60
+ diskUtil.writeFile(testScriptPath, testScript)
61
+
62
+ await this.Service('typeChecker').check(testScriptPath)
63
+ }
64
+
49
65
  private static async assertValuedViewsFile(results: FeatureActionResponse) {
50
66
  const match = testUtil.assertFileByPathInGeneratedFiles(
51
67
  `views/views.ts`,
@@ -1,4 +1,4 @@
1
- import { CORE_SCHEMA_VERSION, diskUtil } from '@sprucelabs/spruce-skill-utils'
1
+ import { diskUtil } from '@sprucelabs/spruce-skill-utils'
2
2
  import { test, assert } from '@sprucelabs/test-utils'
3
3
  import WatchFeature from '../../../features/watch/WatchFeature'
4
4
  import AbstractCliTest from '../../../tests/AbstractCliTest'
@@ -98,8 +98,7 @@ export default class WatchingForChangesTest extends AbstractCliTest {
98
98
  'console.log("hello world")'
99
99
  )
100
100
  expectedChanges.push({
101
- schemaId: 'generatedFile',
102
- version: CORE_SCHEMA_VERSION.constValue,
101
+ id: 'generatedFile',
103
102
  values: {
104
103
  action: 'generated',
105
104
  path: this.resolvePath('build', filename),
@@ -126,8 +125,7 @@ export default class WatchingForChangesTest extends AbstractCliTest {
126
125
 
127
126
  const expected: GeneratedFileOrDir[] = [
128
127
  {
129
- schemaId: 'generatedDir',
130
- version: 'v2020_07_22',
128
+ id: 'generatedDir',
131
129
  values: {
132
130
  action: 'generated',
133
131
  name: 'new_dir',
@@ -149,8 +147,7 @@ export default class WatchingForChangesTest extends AbstractCliTest {
149
147
 
150
148
  const expected: GeneratedFileOrDir[] = [
151
149
  {
152
- schemaId: 'generatedDir',
153
- version: 'v2020_07_22',
150
+ id: 'generatedDir',
154
151
  values: {
155
152
  action: 'deleted',
156
153
  name: 'new_dir',
@@ -173,8 +170,7 @@ export default class WatchingForChangesTest extends AbstractCliTest {
173
170
 
174
171
  const expected: GeneratedFileOrDir[] = [
175
172
  {
176
- schemaId: 'generatedFile',
177
- version: 'v2020_07_22',
173
+ id: 'generatedFile',
178
174
  values: {
179
175
  action: 'deleted',
180
176
  name: 'test.js',
@@ -199,8 +195,7 @@ export default class WatchingForChangesTest extends AbstractCliTest {
199
195
 
200
196
  const expected: GeneratedFileOrDir[] = [
201
197
  {
202
- schemaId: 'generatedFile',
203
- version: 'v2020_07_22',
198
+ id: 'generatedFile',
204
199
  values: {
205
200
  action: 'deleted',
206
201
  name: 'test.js',
@@ -95,7 +95,7 @@ export default class SchemaValueTypeGenerationTest extends AbstractSchemaTest {
95
95
  'generates dynamic field with nested schemas',
96
96
  `${LOCAL_NAMESPACE}.mercuryContract.${CORE_SCHEMA_VERSION.constValue}.__dynamicFieldSignature.valueTypes`,
97
97
  {
98
- type: `{ schemaId: 'eventSignature', version: 'v2020_07_22', values: SpruceSchemas.${LOCAL_NAMESPACE}.v2020_07_22.EventSignature } | { schemaId: 'eventSignature2', version: 'v2020_07_22', values: SpruceSchemas.${LOCAL_NAMESPACE}.v2020_07_22.EventSignature2 }`,
98
+ type: `{ id: 'eventSignature', values: SpruceSchemas.${LOCAL_NAMESPACE}.v2020_07_22.EventSignature } | { id: 'eventSignature2', values: SpruceSchemas.${LOCAL_NAMESPACE}.v2020_07_22.EventSignature2 }`,
99
99
  value: '[eventSignatureSchema_v2020_07_22, eventSignature2Schema_v2020_07_22]',
100
100
  schemaType: `(SpruceSchemas.${LOCAL_NAMESPACE}.v2020_07_22.EventSignatureSchema | SpruceSchemas.${LOCAL_NAMESPACE}.v2020_07_22.EventSignature2Schema)[]`,
101
101
  }
@@ -273,8 +273,8 @@ export default class SpruceError extends AbstractSpruceError<ErrorOptions> {
273
273
  message = 'A cannot prompt in ci just happened!'
274
274
  break
275
275
 
276
- case 'APP_VIEW_CONTROLLER_ALREADY_EXISTS':
277
- message = `You already have an AppViewController! Run \`spruce sync.views\` if you are having issues.`
276
+ case 'APP_CONTROLLER_ALREADY_EXISTS':
277
+ message = `You already have an AppController! Run \`spruce sync.views\` if you are having issues.`
278
278
  break
279
279
 
280
280
  default: