@sprucelabs/spruce-cli 14.22.8 → 14.23.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 (192) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/build/.spruce/events/appointments/didBookAppointments.v2021_06_23.contract.d.ts +10 -0
  3. package/build/.spruce/events/appointments/didBookAppointments.v2021_06_23.contract.js +24 -0
  4. package/build/.spruce/events/appointments/didBookAppointments.v2021_06_23.contract.js.map +1 -0
  5. package/build/.spruce/events/events.contract.d.ts +346 -36
  6. package/build/.spruce/events/events.contract.js +9 -1
  7. package/build/.spruce/events/events.contract.js.map +1 -1
  8. package/build/.spruce/events/forms/convertPdfToForm.v2021_07_02.contract.d.ts +20 -2
  9. package/build/.spruce/events/forms/convertPdfToForm.v2021_07_02.contract.js +23 -5
  10. package/build/.spruce/events/forms/convertPdfToForm.v2021_07_02.contract.js.map +1 -1
  11. package/build/.spruce/events/forms/convertPdfToSchemas.v2021_07_02.contract.d.ts +20 -2
  12. package/build/.spruce/events/forms/convertPdfToSchemas.v2021_07_02.contract.js +23 -5
  13. package/build/.spruce/events/forms/convertPdfToSchemas.v2021_07_02.contract.js.map +1 -1
  14. package/build/.spruce/events/forms/createForm.v2021_07_02.contract.d.ts +20 -2
  15. package/build/.spruce/events/forms/createForm.v2021_07_02.contract.js +23 -5
  16. package/build/.spruce/events/forms/createForm.v2021_07_02.contract.js.map +1 -1
  17. package/build/.spruce/events/forms/deleteCompletedForm.v2021_07_02.contract.d.ts +20 -2
  18. package/build/.spruce/events/forms/deleteCompletedForm.v2021_07_02.contract.js +23 -5
  19. package/build/.spruce/events/forms/deleteCompletedForm.v2021_07_02.contract.js.map +1 -1
  20. package/build/.spruce/events/forms/getCompletedForm.v2021_07_02.contract.d.ts +15 -0
  21. package/build/.spruce/events/forms/getCompletedForm.v2021_07_02.contract.js +17 -2
  22. package/build/.spruce/events/forms/getCompletedForm.v2021_07_02.contract.js.map +1 -1
  23. package/build/.spruce/events/forms/listCompletedForms.v2021_07_02.contract.d.ts +20 -3
  24. package/build/.spruce/events/forms/listCompletedForms.v2021_07_02.contract.js +23 -6
  25. package/build/.spruce/events/forms/listCompletedForms.v2021_07_02.contract.js.map +1 -1
  26. package/build/.spruce/events/forms/listForms.v2021_07_02.contract.d.ts +38 -4
  27. package/build/.spruce/events/forms/listForms.v2021_07_02.contract.js +45 -11
  28. package/build/.spruce/events/forms/listForms.v2021_07_02.contract.js.map +1 -1
  29. package/build/.spruce/events/heartwood/didRegisterSkillViews.v2021_02_11.contract.d.ts +15 -0
  30. package/build/.spruce/events/heartwood/didRegisterSkillViews.v2021_02_11.contract.js +17 -2
  31. package/build/.spruce/events/heartwood/didRegisterSkillViews.v2021_02_11.contract.js.map +1 -1
  32. package/build/.spruce/events/heartwood/generateUrl.v2021_02_11.contract.d.ts +21 -4
  33. package/build/.spruce/events/heartwood/generateUrl.v2021_02_11.contract.js +24 -7
  34. package/build/.spruce/events/heartwood/generateUrl.v2021_02_11.contract.js.map +1 -1
  35. package/build/.spruce/events/heartwood/getSkillViews.v2021_02_11.contract.d.ts +21 -1
  36. package/build/.spruce/events/heartwood/getSkillViews.v2021_02_11.contract.js +26 -6
  37. package/build/.spruce/events/heartwood/getSkillViews.v2021_02_11.contract.js.map +1 -1
  38. package/build/.spruce/events/mySkill163459634973936127/myCoolEvent.v2021_01_22.contract.d.ts +38 -0
  39. package/build/.spruce/events/mySkill163459634973936127/myCoolEvent.v2021_01_22.contract.js +48 -0
  40. package/build/.spruce/events/mySkill163459634973936127/myCoolEvent.v2021_01_22.contract.js.map +1 -0
  41. package/build/.spruce/events/mySkill163493473102035607/myCoolEvent.v2021_01_22.contract.d.ts +38 -0
  42. package/build/.spruce/events/mySkill163493473102035607/myCoolEvent.v2021_01_22.contract.js +48 -0
  43. package/build/.spruce/events/mySkill163493473102035607/myCoolEvent.v2021_01_22.contract.js.map +1 -0
  44. package/build/.spruce/events/mySkill163493479880935941/myCoolEvent.v2021_01_22.contract.d.ts +38 -0
  45. package/build/.spruce/events/mySkill163493479880935941/myCoolEvent.v2021_01_22.contract.js +48 -0
  46. package/build/.spruce/events/mySkill163493479880935941/myCoolEvent.v2021_01_22.contract.js.map +1 -0
  47. package/build/.spruce/schemas/appointments/v2021_06_23/appointments.schema.d.ts +3 -0
  48. package/build/.spruce/schemas/appointments/v2021_06_23/appointments.schema.js +28 -0
  49. package/build/.spruce/schemas/appointments/v2021_06_23/appointments.schema.js.map +1 -0
  50. package/build/.spruce/schemas/appointments/v2021_06_23/didBookAppointmentsEmitPayload.schema.d.ts +3 -0
  51. package/build/.spruce/schemas/appointments/v2021_06_23/didBookAppointmentsEmitPayload.schema.js +36 -0
  52. package/build/.spruce/schemas/appointments/v2021_06_23/didBookAppointmentsEmitPayload.schema.js.map +1 -0
  53. package/build/.spruce/schemas/appointments/v2021_06_23/didBookAppointmentsEmitTarget.schema.d.ts +3 -0
  54. package/build/.spruce/schemas/appointments/v2021_06_23/didBookAppointmentsEmitTarget.schema.js +28 -0
  55. package/build/.spruce/schemas/appointments/v2021_06_23/didBookAppointmentsEmitTarget.schema.js.map +1 -0
  56. package/build/.spruce/schemas/appointments/v2021_06_23/didBookAppointmentsEmitTargetAndPayload.schema.d.ts +3 -0
  57. package/build/.spruce/schemas/appointments/v2021_06_23/didBookAppointmentsEmitTargetAndPayload.schema.js +56 -0
  58. package/build/.spruce/schemas/appointments/v2021_06_23/didBookAppointmentsEmitTargetAndPayload.schema.js.map +1 -0
  59. package/build/.spruce/schemas/heartwood/v2021_02_11/registerSkillViewsEmitTargetAndPayload.schema.js +0 -10
  60. package/build/.spruce/schemas/heartwood/v2021_02_11/registerSkillViewsEmitTargetAndPayload.schema.js.map +1 -1
  61. package/build/.spruce/schemas/schemas.types.d.ts +678 -604
  62. package/build/.spruce/schemas/schemas.types.js.map +1 -1
  63. package/build/__tests__/behavioral/AddingADependency.test.d.ts +9 -0
  64. package/build/__tests__/behavioral/AddingADependency.test.js +273 -0
  65. package/build/__tests__/behavioral/AddingADependency.test.js.map +1 -0
  66. package/build/__tests__/behavioral/CreatingADataStore.test.js.map +1 -1
  67. package/build/__tests__/behavioral/ManagingDependencies.test.d.ts +9 -0
  68. package/build/__tests__/behavioral/ManagingDependencies.test.js +279 -0
  69. package/build/__tests__/behavioral/ManagingDependencies.test.js.map +1 -0
  70. package/build/__tests__/behavioral/SyncingEventsOnlyFromDependencies.test.d.ts +8 -0
  71. package/build/__tests__/behavioral/SyncingEventsOnlyFromDependencies.test.js +209 -0
  72. package/build/__tests__/behavioral/SyncingEventsOnlyFromDependencies.test.js.map +1 -0
  73. package/build/__tests__/behavioral/events/CreatingAListener.test.js +9 -5
  74. package/build/__tests__/behavioral/events/CreatingAListener.test.js.map +1 -1
  75. package/build/__tests__/behavioral/events/KeepingEventsInSync.test.js +14 -7
  76. package/build/__tests__/behavioral/events/KeepingEventsInSync.test.js.map +1 -1
  77. package/build/__tests__/behavioral/events/KeepingEventsInSync2.test.js +43 -12
  78. package/build/__tests__/behavioral/events/KeepingEventsInSync2.test.js.map +1 -1
  79. package/build/__tests__/behavioral/views/CreatingATheme.test.js +8 -2
  80. package/build/__tests__/behavioral/views/CreatingATheme.test.js.map +1 -1
  81. package/build/__tests__/behavioral/views/SettingUpViews.test.d.ts +1 -0
  82. package/build/__tests__/behavioral/views/SettingUpViews.test.js +48 -3
  83. package/build/__tests__/behavioral/views/SettingUpViews.test.js.map +1 -1
  84. package/build/__tests__/implementation/EventStore.test.js +4 -3
  85. package/build/__tests__/implementation/EventStore.test.js.map +1 -1
  86. package/build/__tests__/implementation/EventTemplateItemBuilder.test.d.ts +1 -0
  87. package/build/__tests__/implementation/EventTemplateItemBuilder.test.js +21 -3
  88. package/build/__tests__/implementation/EventTemplateItemBuilder.test.js.map +1 -1
  89. package/build/errors/SpruceError.js +2 -2
  90. package/build/errors/SpruceError.js.map +1 -1
  91. package/build/features/FeatureInstaller.d.ts +1 -1
  92. package/build/features/FeatureInstallerFactory.js +4 -2
  93. package/build/features/FeatureInstallerFactory.js.map +1 -1
  94. package/build/features/dependencies/DependencyFeature.d.ts +16 -0
  95. package/build/features/dependencies/DependencyFeature.js +92 -0
  96. package/build/features/dependencies/DependencyFeature.js.map +1 -0
  97. package/build/features/dependencies/actions/AddAction.d.ts +33 -0
  98. package/build/features/dependencies/actions/AddAction.js +154 -0
  99. package/build/features/dependencies/actions/AddAction.js.map +1 -0
  100. package/build/features/dependencies/actions/ManageAction.d.ts +19 -0
  101. package/build/features/dependencies/actions/ManageAction.js +161 -0
  102. package/build/features/dependencies/actions/ManageAction.js.map +1 -0
  103. package/build/features/event/EventFeature.js +2 -1
  104. package/build/features/event/EventFeature.js.map +1 -1
  105. package/build/features/event/builders/EventContractBuilder.d.ts +3 -0
  106. package/build/features/event/builders/EventContractBuilder.js +12 -8
  107. package/build/features/event/builders/EventContractBuilder.js.map +1 -1
  108. package/build/features/event/stores/EventStore.d.ts +2 -1
  109. package/build/features/event/stores/EventStore.js +33 -25
  110. package/build/features/event/stores/EventStore.js.map +1 -1
  111. package/build/features/schema/actions/SyncAction.js +4 -2
  112. package/build/features/schema/actions/SyncAction.js.map +1 -1
  113. package/build/features/skill/actions/RebuildAction.js.map +1 -1
  114. package/build/features/skill/stores/SkillStore.d.ts +4 -0
  115. package/build/features/skill/stores/SkillStore.js +39 -15
  116. package/build/features/skill/stores/SkillStore.js.map +1 -1
  117. package/build/features/view/ViewFeature.js +5 -1
  118. package/build/features/view/ViewFeature.js.map +1 -1
  119. package/build/interfaces/SpyInterface.d.ts +2 -1
  120. package/build/interfaces/SpyInterface.js +67 -7
  121. package/build/interfaces/SpyInterface.js.map +1 -1
  122. package/build/services/DependencyService.d.ts +13 -0
  123. package/build/services/DependencyService.js +49 -0
  124. package/build/services/DependencyService.js.map +1 -0
  125. package/build/services/ServiceFactory.d.ts +2 -0
  126. package/build/services/ServiceFactory.js +5 -0
  127. package/build/services/ServiceFactory.js.map +1 -1
  128. package/build/templateItemBuilders/EventTemplateItemBuilder.js +9 -0
  129. package/build/templateItemBuilders/EventTemplateItemBuilder.js.map +1 -1
  130. package/build/tests/AbstractCliTest.js +2 -36
  131. package/build/tests/AbstractCliTest.js.map +1 -1
  132. package/build/tests/fixtures/SkillFixture.d.ts +2 -0
  133. package/build/tests/fixtures/SkillFixture.js +8 -8
  134. package/build/tests/fixtures/SkillFixture.js.map +1 -1
  135. package/build/utilities/action.utility.js +1 -5
  136. package/build/utilities/action.utility.js.map +1 -1
  137. package/package.json +27 -27
  138. package/src/.spruce/events/appointments/didBookAppointments.v2021_06_23.contract.ts +15 -0
  139. package/src/.spruce/events/events.contract.ts +32 -8
  140. package/src/.spruce/events/forms/convertPdfToForm.v2021_07_02.contract.ts +20 -2
  141. package/src/.spruce/events/forms/convertPdfToSchemas.v2021_07_02.contract.ts +20 -2
  142. package/src/.spruce/events/forms/createForm.v2021_07_02.contract.ts +20 -2
  143. package/src/.spruce/events/forms/deleteCompletedForm.v2021_07_02.contract.ts +20 -2
  144. package/src/.spruce/events/forms/getCompletedForm.v2021_07_02.contract.ts +15 -0
  145. package/src/.spruce/events/forms/listCompletedForms.v2021_07_02.contract.ts +20 -3
  146. package/src/.spruce/events/forms/listForms.v2021_07_02.contract.ts +38 -4
  147. package/src/.spruce/events/heartwood/didRegisterSkillViews.v2021_02_11.contract.ts +15 -0
  148. package/src/.spruce/events/heartwood/generateUrl.v2021_02_11.contract.ts +21 -4
  149. package/src/.spruce/events/heartwood/getSkillViews.v2021_02_11.contract.ts +21 -1
  150. package/src/.spruce/events/mySkill163459634973936127/myCoolEvent.v2021_01_22.contract.ts +45 -0
  151. package/src/.spruce/events/mySkill163493473102035607/myCoolEvent.v2021_01_22.contract.ts +45 -0
  152. package/src/.spruce/events/mySkill163493479880935941/myCoolEvent.v2021_01_22.contract.ts +45 -0
  153. package/src/.spruce/schemas/appointments/v2021_06_23/appointments.schema.ts +22 -0
  154. package/src/.spruce/schemas/appointments/v2021_06_23/didBookAppointmentsEmitPayload.schema.ts +24 -0
  155. package/src/.spruce/schemas/appointments/v2021_06_23/didBookAppointmentsEmitTarget.schema.ts +22 -0
  156. package/src/.spruce/schemas/appointments/v2021_06_23/didBookAppointmentsEmitTargetAndPayload.schema.ts +36 -0
  157. package/src/.spruce/schemas/heartwood/v2021_02_11/registerSkillViewsEmitTargetAndPayload.schema.ts +0 -6
  158. package/src/.spruce/schemas/schemas.types.ts +815 -720
  159. package/src/__tests__/behavioral/AddingADependency.test.ts +98 -0
  160. package/src/__tests__/behavioral/CreatingADataStore.test.ts +2 -0
  161. package/src/__tests__/behavioral/ManagingDependencies.test.ts +115 -0
  162. package/src/__tests__/behavioral/SyncingEventsOnlyFromDependencies.test.ts +70 -0
  163. package/src/__tests__/behavioral/events/CreatingAListener.test.ts +5 -0
  164. package/src/__tests__/behavioral/events/KeepingEventsInSync.test.ts +6 -0
  165. package/src/__tests__/behavioral/events/KeepingEventsInSync2.test.ts +27 -0
  166. package/src/__tests__/behavioral/views/CreatingATheme.test.ts +4 -0
  167. package/src/__tests__/behavioral/views/SettingUpViews.test.ts +23 -0
  168. package/src/__tests__/implementation/EventStore.test.ts +5 -2
  169. package/src/__tests__/implementation/EventTemplateItemBuilder.test.ts +20 -1
  170. package/src/errors/SpruceError.ts +1 -1
  171. package/src/features/FeatureInstallerFactory.ts +3 -0
  172. package/src/features/dependencies/DependencyFeature.ts +27 -0
  173. package/src/features/dependencies/actions/AddAction.ts +63 -0
  174. package/src/features/dependencies/actions/ManageAction.ts +84 -0
  175. package/src/features/event/EventFeature.ts +1 -0
  176. package/src/features/event/builders/EventContractBuilder.ts +9 -2
  177. package/src/features/event/stores/EventStore.ts +20 -11
  178. package/src/features/schema/actions/SyncAction.ts +6 -3
  179. package/src/features/skill/actions/RebuildAction.ts +2 -0
  180. package/src/features/skill/stores/SkillStore.ts +8 -1
  181. package/src/features/view/ViewFeature.ts +5 -0
  182. package/src/interfaces/SpyInterface.ts +29 -2
  183. package/src/services/DependencyService.ts +27 -0
  184. package/src/services/ServiceFactory.ts +6 -0
  185. package/src/templateItemBuilders/EventTemplateItemBuilder.ts +10 -0
  186. package/src/tests/AbstractCliTest.ts +1 -21
  187. package/src/tests/fixtures/SkillFixture.ts +6 -2
  188. package/src/utilities/action.utility.ts +1 -6
  189. package/build/.spruce/schemas/heartwood/v2021_02_11/registerSkillViewsEmitTarget.schema.d.ts +0 -3
  190. package/build/.spruce/schemas/heartwood/v2021_02_11/registerSkillViewsEmitTarget.schema.js +0 -28
  191. package/build/.spruce/schemas/heartwood/v2021_02_11/registerSkillViewsEmitTarget.schema.js.map +0 -1
  192. package/src/.spruce/schemas/heartwood/v2021_02_11/registerSkillViewsEmitTarget.schema.ts +0 -22
@@ -0,0 +1,98 @@
1
+ import { test, assert } from '@sprucelabs/test'
2
+ import { errorAssertUtil } from '@sprucelabs/test-utils'
3
+ import AbstractSkillTest from '../../tests/AbstractSkillTest'
4
+
5
+ export default class ConfiguringDependenciesTest extends AbstractSkillTest {
6
+ protected static skillCacheKey = 'skills'
7
+
8
+ @test()
9
+ protected static async hasAddDependencyAction() {
10
+ assert.isFunction(this.Action('dependency', 'add').execute)
11
+ }
12
+
13
+ @test()
14
+ protected static async errorsWhenPassedBadSlug() {
15
+ await this.getSkillFixture().registerCurrentSkill({
16
+ name: 'current skill in adding deps',
17
+ })
18
+
19
+ const results = await this.Action('dependency', 'add').execute({
20
+ namespace: 'waka-waka',
21
+ })
22
+
23
+ assert.isTruthy(results.errors)
24
+
25
+ errorAssertUtil.assertError(results.errors[0], 'SKILL_NOT_FOUND')
26
+ }
27
+
28
+ @test()
29
+ protected static async succeedsWhenPassedGoodSlug() {
30
+ const otherSkill = await this.getSkillFixture().seedDemoSkill({
31
+ name: 'dependent skill',
32
+ })
33
+
34
+ const results = await this.Action('dependency', 'add').execute({
35
+ namespace: otherSkill.slug,
36
+ })
37
+
38
+ assert.isFalsy(results.errors)
39
+
40
+ const settings = this.Service('settings')
41
+ const dependencies = settings.get('dependencies')
42
+
43
+ assert.isEqualDeep(dependencies, [
44
+ {
45
+ id: otherSkill.id,
46
+ namespace: otherSkill.slug,
47
+ },
48
+ ])
49
+ }
50
+
51
+ @test()
52
+ protected static async asksToSelectSkillWhenNoSlugPassed() {
53
+ const otherSkill = await this.getSkillFixture().seedDemoSkill({
54
+ name: 'dependent skill',
55
+ })
56
+
57
+ const promise = this.Action('dependency', 'add').execute({})
58
+
59
+ await this.waitForInput()
60
+
61
+ const last = this.ui.lastInvocation()
62
+
63
+ assert.doesInclude(last.options.options.choices, {
64
+ value: otherSkill.slug,
65
+ label: otherSkill.name,
66
+ })
67
+
68
+ await this.ui.sendInput(otherSkill.slug)
69
+
70
+ const results = await promise
71
+ assert.isFalsy(results.errors)
72
+
73
+ const settings = this.Service('settings')
74
+ const dependencies = settings.get('dependencies')
75
+
76
+ assert.isEqualDeep(dependencies[1], {
77
+ id: otherSkill.id,
78
+ namespace: otherSkill.slug,
79
+ })
80
+ }
81
+
82
+ @test()
83
+ protected static async canAddSkillThatWasCreatedBySomeoneElse() {
84
+ const skill = await this.getSkillFixture().seedDemoSkill({
85
+ name: 'global dependency skill',
86
+ })
87
+
88
+ await this.getPersonFixture().loginAsDemoPerson(
89
+ process.env.DEMO_NUMBER_GLOBAL_EVENTS
90
+ )
91
+
92
+ const results = await this.Action('dependency', 'add').execute({
93
+ namespace: skill.slug,
94
+ })
95
+
96
+ assert.isFalsy(results.errors)
97
+ }
98
+ }
@@ -8,6 +8,7 @@ import testUtil from '../../tests/utilities/test.utility'
8
8
 
9
9
  export default class CreatingDataStoresTest extends AbstractSkillTest {
10
10
  protected static skillCacheKey = 'stores'
11
+
11
12
  @test()
12
13
  protected static async hasCreateStoreAction() {
13
14
  assert.isFunction(this.Action('store', 'create').execute)
@@ -72,6 +73,7 @@ export default class CreatingDataStoresTest extends AbstractSkillTest {
72
73
  @test()
73
74
  protected static async getsSecondStoresBackFromHealthCheck() {
74
75
  const health = await this.cli.checkHealth({ isRunningLocally: true })
76
+
75
77
  assert.isTruthy(health.store)
76
78
  assert.isFalsy(health.store.errors)
77
79
  assert.isLength(health.store.stores, 2)
@@ -0,0 +1,115 @@
1
+ import { test, assert } from '@sprucelabs/test'
2
+ import AbstractSkillTest from '../../tests/AbstractSkillTest'
3
+
4
+ export default class ManagingDependenciesTest extends AbstractSkillTest {
5
+ protected static skillCacheKey = 'skills'
6
+
7
+ @test()
8
+ protected static async hasAddDependencyAction() {
9
+ assert.isFunction(this.Action('dependency', 'manage').execute)
10
+ }
11
+
12
+ @test()
13
+ protected static async showsSkillsAsCheckboxes() {
14
+ const skill1 = await this.getSkillFixture().seedDemoSkill({
15
+ name: 'dependency manage 1',
16
+ })
17
+
18
+ const skill2 = await this.getSkillFixture().seedDemoSkill({
19
+ name: 'dependency manage 2',
20
+ })
21
+
22
+ void this.Action('dependency', 'manage').execute({})
23
+
24
+ await this.waitForInput()
25
+
26
+ const last = this.ui.lastInvocation()
27
+
28
+ assert.isEqual(last.options.type, 'select')
29
+
30
+ assert.doesInclude(last.options.options.choices, {
31
+ value: skill1.id,
32
+ })
33
+
34
+ assert.doesInclude(last.options.options.choices, {
35
+ value: skill2.id,
36
+ })
37
+
38
+ this.ui.reset()
39
+ }
40
+
41
+ @test()
42
+ protected static async selectsExistingDependencies() {
43
+ const skill1 = await this.getSkillFixture().seedDemoSkill({
44
+ name: 'dependency manage 3',
45
+ })
46
+
47
+ this.Service('dependency').set([
48
+ {
49
+ namespace: skill1.slug,
50
+ id: skill1.id,
51
+ },
52
+ ])
53
+
54
+ void this.Action('dependency', 'manage').execute({})
55
+
56
+ await this.waitForInput()
57
+
58
+ const last = this.ui.lastInvocation()
59
+
60
+ assert.isEqualDeep(last.options.value, [skill1.id])
61
+
62
+ this.ui.reset()
63
+ }
64
+
65
+ @test()
66
+ protected static async canSelectANewDependencies() {
67
+ const skill1 = await this.getSkillFixture().seedDemoSkill({
68
+ name: 'dependency manage 4',
69
+ })
70
+
71
+ const skill2 = await this.getSkillFixture().seedDemoSkill({
72
+ name: 'dependency manage 5',
73
+ })
74
+
75
+ const promise = this.Action('dependency', 'manage').execute({})
76
+
77
+ await this.waitForInput()
78
+
79
+ await this.ui.sendInput([skill1.id, skill2.id])
80
+
81
+ const dependencies = this.Service('settings').get('dependencies')
82
+
83
+ assert.isEqualDeep(dependencies, [
84
+ {
85
+ id: skill1.id,
86
+ namespace: skill1.slug,
87
+ },
88
+ {
89
+ id: skill2.id,
90
+ namespace: skill2.slug,
91
+ },
92
+ ])
93
+
94
+ await promise
95
+ }
96
+
97
+ @test()
98
+ protected static async doesNotShowCurrentSkill() {
99
+ const skill = await this.getSkillFixture().registerCurrentSkill({
100
+ name: 'current skill in managing deps',
101
+ })
102
+
103
+ void this.Action('dependency', 'manage').execute({})
104
+
105
+ await this.waitForInput()
106
+
107
+ const last = this.ui.lastInvocation()
108
+
109
+ assert.doesNotInclude(last.options.options.choices, {
110
+ value: skill.id,
111
+ })
112
+
113
+ this.ui.reset()
114
+ }
115
+ }
@@ -0,0 +1,70 @@
1
+ import { diskUtil, namesUtil } from '@sprucelabs/spruce-skill-utils'
2
+ import { test, assert } from '@sprucelabs/test'
3
+ import fsUtil from 'fs-extra'
4
+ import AbstractSkillTest from '../../tests/AbstractSkillTest'
5
+ import { RegisteredSkill } from '../../types/cli.types'
6
+
7
+ export default class SyncingEventsOnlyFromDependenciesTest extends AbstractSkillTest {
8
+ protected static skillCacheKey = 'events'
9
+
10
+ @test()
11
+ protected static async doesntSyncAnythingToStart() {
12
+ const skills = this.getSkillFixture()
13
+ await skills.registerCurrentSkill({
14
+ name: 'events in sync skill',
15
+ })
16
+ const { skill } = await this.registerGlobalEvent()
17
+
18
+ const results = await this.Action('event', 'sync', {}).execute({})
19
+ assert.isFalsy(results.errors)
20
+
21
+ const eventFolder = this.resolveEventFolder(skill)
22
+
23
+ assert.isFalse(diskUtil.doesDirExist(eventFolder))
24
+
25
+ const contents = fsUtil.readdirSync(this.resolveHashSprucePath('events'))
26
+
27
+ assert.isLength(contents, 1)
28
+ }
29
+
30
+ @test()
31
+ protected static async syncsEventsForSkillsWeveAddedAsDependencies() {
32
+ const { skill } = await this.registerGlobalEvent()
33
+
34
+ this.Service('dependency').add({
35
+ id: skill.id,
36
+ namespace: skill.slug,
37
+ })
38
+
39
+ const results = await this.Action('event', 'sync', {}).execute({})
40
+ assert.isFalsy(results.errors)
41
+
42
+ const eventFolder = this.resolveEventFolder(skill)
43
+
44
+ assert.isTrue(diskUtil.doesDirExist(eventFolder))
45
+
46
+ const contents = fsUtil.readdirSync(this.resolveHashSprucePath('events'))
47
+
48
+ assert.isLength(contents, 2)
49
+ }
50
+
51
+ private static async registerGlobalEvent() {
52
+ const skills = this.getSkillFixture()
53
+
54
+ const skill = await skills.seedDemoSkill({ name: 'a temp skill' })
55
+
56
+ await skills.registerEventContract(skill, {
57
+ eventSignatures: {
58
+ 'test-sync::v2021_01_01': {
59
+ isGlobal: true,
60
+ },
61
+ },
62
+ })
63
+
64
+ return { skill }
65
+ }
66
+
67
+ private static resolveEventFolder(skill: RegisteredSkill) {
68
+ return this.resolveHashSprucePath('events', namesUtil.toCamel(skill.slug))
69
+ }
70
+ }
@@ -277,6 +277,11 @@ export default class CreatingAListenerTest extends AbstractEventTest {
277
277
 
278
278
  await skillFixture.registerEventContract(skill2, eventContract)
279
279
 
280
+ this.Service('dependency').add({
281
+ id: skill2.id,
282
+ namespace: skill2.slug,
283
+ })
284
+
280
285
  const results = await this.Action('event', 'listen').execute({
281
286
  eventNamespace: skill2.slug,
282
287
  eventName: `my-new-event`,
@@ -56,6 +56,11 @@ export default class KeepingEventsInSyncTest extends AbstractEventTest {
56
56
 
57
57
  const skill2 = await skills.seedDemoSkill({ name: 'a temp skill' })
58
58
 
59
+ await this.Service('dependency').add({
60
+ id: skill2.id,
61
+ namespace: skill2.slug,
62
+ })
63
+
59
64
  await skills.registerEventContract(skill2, {
60
65
  eventSignatures: {
61
66
  'test-sync::v2021_01_01': {
@@ -154,6 +159,7 @@ export default class KeepingEventsInSyncTest extends AbstractEventTest {
154
159
  await this.syncCoreEventsPretendingToBeMercuryTypes()
155
160
 
156
161
  const results = await this.Action('schema', 'sync').execute({})
162
+
157
163
  await this.assertValidSyncSchemasResults(results, true)
158
164
  }
159
165
 
@@ -52,6 +52,7 @@ export default class KeepingEventsInSyncTest extends AbstractEventTest {
52
52
  const client = await this.getMercuryFixture().connectToApi({
53
53
  shouldAuthAsCurrentSkill: true,
54
54
  })
55
+
55
56
  await client.disconnect()
56
57
 
57
58
  EventStore.clearCache()
@@ -149,6 +150,11 @@ export default class KeepingEventsInSyncTest extends AbstractEventTest {
149
150
  },
150
151
  })
151
152
 
153
+ await this.Service('dependency').add({
154
+ id: skill2.id,
155
+ namespace: skill2.slug,
156
+ })
157
+
152
158
  const results = await this.Action('event', 'sync').execute({})
153
159
 
154
160
  const match = testUtil.assertFileByNameInGeneratedFiles(
@@ -224,6 +230,17 @@ export default class KeepingEventsInSyncTest extends AbstractEventTest {
224
230
  },
225
231
  })
226
232
 
233
+ await this.Service('dependency').set([
234
+ {
235
+ id: skill2.id,
236
+ namespace: skill2.slug,
237
+ },
238
+ {
239
+ id: skill3.id,
240
+ namespace: skill3.slug,
241
+ },
242
+ ])
243
+
227
244
  const results = await this.Action('event', 'sync').execute({})
228
245
 
229
246
  const contract = testUtil.assertFileByNameInGeneratedFiles(
@@ -259,6 +276,11 @@ export default class KeepingEventsInSyncTest extends AbstractEventTest {
259
276
  },
260
277
  })
261
278
 
279
+ await this.Service('dependency').add({
280
+ id: skill2.id,
281
+ namespace: skill2.slug,
282
+ })
283
+
262
284
  const results = await this.Action('event', 'sync').execute({})
263
285
 
264
286
  const contract = testUtil.assertFileByNameInGeneratedFiles(
@@ -414,6 +436,11 @@ export function buildPermissionContract(..._: any[]):any { return _[0] }
414
436
  },
415
437
  })
416
438
 
439
+ await this.Service('dependency').add({
440
+ id: skill.id,
441
+ namespace: skill.slug,
442
+ })
443
+
417
444
  const results = await this.Action('event', 'sync').execute({})
418
445
 
419
446
  return { results, filename }
@@ -13,6 +13,10 @@ export default class CreatingAThemeTest extends AbstractSkillTest {
13
13
 
14
14
  @test()
15
15
  protected static async syncsEventsFirst() {
16
+ await this.getSkillFixture().registerCurrentSkill({
17
+ name: 'current skill in creating a theme',
18
+ })
19
+
16
20
  const results = await this.Action('view', 'createTheme').execute({})
17
21
  assert.isFalsy(results.errors)
18
22
 
@@ -8,4 +8,27 @@ export default class SettingUpViewsTest extends AbstractCliTest {
8
8
  const feature = cli.getFeature('view')
9
9
  assert.isTruthy(feature)
10
10
  }
11
+
12
+ @test()
13
+ protected static async installingViewsAddsHeartwoodAsDependency() {
14
+ await this.FeatureFixture().installFeatures([
15
+ {
16
+ code: 'skill',
17
+ options: {
18
+ name: 'testing views',
19
+ description: 'this too, is a great test!',
20
+ },
21
+ },
22
+ {
23
+ code: 'view',
24
+ },
25
+ ])
26
+
27
+ await this.getPersonFixture().loginAsDemoPerson()
28
+
29
+ const dependencies = this.Service('dependency').get()
30
+ assert.isLength(dependencies, 1)
31
+
32
+ assert.isEqual(dependencies[0].namespace, 'heartwood')
33
+ }
11
34
  }
@@ -102,7 +102,8 @@ export default class EventStoreTest extends AbstractEventTest {
102
102
  localNamespace: 'my-skill',
103
103
  })
104
104
 
105
- assert.isTrue(contracts.length >= 2)
105
+ assert.isTrue(contracts.length > 2)
106
+
106
107
  const skillContract = contracts[1]
107
108
 
108
109
  const sig = eventContractUtil.getSignatureByName(
@@ -206,9 +207,11 @@ export default class EventStoreTest extends AbstractEventTest {
206
207
 
207
208
  const { contracts } = await this.Store('event').fetchEventContracts({
208
209
  localNamespace: skill.slug,
210
+ namespaces: ['core'],
209
211
  })
210
212
 
211
- assert.isTrue(contracts.length >= 2)
213
+ assert.isLength(contracts, 2)
214
+
212
215
  const name = eventNameUtil.join({
213
216
  eventName: EVENT_NAME,
214
217
  eventNamespace: skill.slug,
@@ -314,9 +314,9 @@ export default class EventTemplateItemBuilderTest extends AbstractCliTest {
314
314
  [contractWith2Signatures, contractWith2Signatures],
315
315
  [
316
316
  didBookTemplateItem,
317
- willBookTemplateItem,
318
317
  didBookTemplateItem,
319
318
  willBookTemplateItem,
319
+ willBookTemplateItem,
320
320
  ]
321
321
  )
322
322
  @test(
@@ -360,4 +360,23 @@ export default class EventTemplateItemBuilderTest extends AbstractCliTest {
360
360
  const match = schemaTemplateItems.find((item) => item.id === 'eventSource')
361
361
  assert.isTruthy(match)
362
362
  }
363
+
364
+ @test()
365
+ protected static sortsEventsAlphabetically() {
366
+ const { eventContractTemplateItems } = this.itemBuilder.buildTemplateItems({
367
+ contracts: [
368
+ {
369
+ eventSignatures: {
370
+ 'zebra-cheeta': {},
371
+ 'register-events':
372
+ coreEventContracts[0].eventSignatures['can-listen::v2020_12_25'],
373
+ },
374
+ },
375
+ ],
376
+ localNamespace: 'testing',
377
+ })
378
+
379
+ assert.isEqual(eventContractTemplateItems[0].nameCamel, 'registerEvents')
380
+ assert.isEqual(eventContractTemplateItems[1].nameCamel, 'zebraCheeta')
381
+ }
363
382
  }
@@ -207,7 +207,7 @@ export default class SpruceError extends AbstractSpruceError<ErrorOptions> {
207
207
  break
208
208
 
209
209
  case 'SKILL_NOT_FOUND':
210
- message = `I couldn't find that skill!`
210
+ message = options.friendlyMessage ?? `I couldn't find that skill!`
211
211
  break
212
212
 
213
213
  case 'NO_SKILLS_REGISTERED':
@@ -8,6 +8,7 @@ import { FeatureOptions } from './AbstractFeature'
8
8
  import ActionExecuter from './ActionExecuter'
9
9
  import CacheFeature from './cache/CacheFeature'
10
10
  import ConversationFeature from './conversation/ConversationFeature'
11
+ import DependencyFeature from './dependencies/DependencyFeature'
11
12
  import DeployFeature from './deploy/DeployFeature'
12
13
  import ErrorFeature from './error/ErrorFeature'
13
14
  import EventFeature from './event/EventFeature'
@@ -48,6 +49,7 @@ export default class FeatureInstallerFactory {
48
49
  ViewFeature,
49
50
  CacheFeature,
50
51
  LogFeature,
52
+ DependencyFeature,
51
53
  ]
52
54
 
53
55
  public static readonly featureCodes: FeatureCode[] = [
@@ -70,6 +72,7 @@ export default class FeatureInstallerFactory {
70
72
  'view',
71
73
  'cache',
72
74
  'log',
75
+ 'dependency',
73
76
  ]
74
77
 
75
78
  public static WithAllFeatures(options: {
@@ -0,0 +1,27 @@
1
+ import { diskUtil } from '@sprucelabs/spruce-skill-utils'
2
+ import AbstractFeature, { FeatureDependency } from '../AbstractFeature'
3
+ import { FeatureCode } from '../features.types'
4
+
5
+ declare module '../../features/features.types' {
6
+ interface FeatureMap {
7
+ dependency: DependencyFeature
8
+ }
9
+ }
10
+
11
+ export default class DependencyFeature extends AbstractFeature {
12
+ public description = 'Tell me which skills you depend on.'
13
+ public code: FeatureCode = 'dependency'
14
+ public nameReadable = 'Dependencies'
15
+ public actionsDir = diskUtil.resolvePath(__dirname, 'actions')
16
+ public dependencies: FeatureDependency[] = [
17
+ {
18
+ code: 'skill',
19
+ isRequired: true,
20
+ },
21
+ ]
22
+ public packageDependencies = []
23
+
24
+ public async isInstalled() {
25
+ return this.featureInstaller.isInstalled('skill')
26
+ }
27
+ }
@@ -0,0 +1,63 @@
1
+ import { buildSchema, SchemaValues } from '@sprucelabs/schema'
2
+ import SpruceError from '../../../errors/SpruceError'
3
+ import AbstractAction from '../../AbstractAction'
4
+ import { FeatureActionResponse } from '../../features.types'
5
+
6
+ const optionsSchema = buildSchema({
7
+ id: 'addDepnedency',
8
+ description: 'Add a skill as a dependency.',
9
+ fields: {
10
+ namespace: {
11
+ type: 'id',
12
+ label: 'Namespace',
13
+ hint: 'The namespace of the skill you want to add as a dependency.',
14
+ },
15
+ },
16
+ })
17
+
18
+ type OptionsSchema = typeof optionsSchema
19
+ type Options = SchemaValues<OptionsSchema>
20
+
21
+ export default class DeployAction extends AbstractAction<OptionsSchema> {
22
+ public optionsSchema = optionsSchema
23
+ public commandAliases = ['add.dependency']
24
+ public invocationMessage = 'Adding a dependency... 🔗'
25
+
26
+ public async execute(options: Options): Promise<FeatureActionResponse> {
27
+ let { namespace } = this.validateAndNormalizeOptions(options)
28
+
29
+ const skills = await this.Store('skill').fetchAllSkills()
30
+
31
+ if (!namespace) {
32
+ namespace = await this.ui.prompt({
33
+ type: 'select',
34
+ label: 'Which skill would you like to add as a dependency?',
35
+ isRequired: true,
36
+ options: {
37
+ choices: skills.map((s) => ({
38
+ value: s.slug,
39
+ label: s.name,
40
+ })),
41
+ },
42
+ })
43
+ }
44
+
45
+ const skill = skills.find((s) => s.slug === namespace)
46
+
47
+ if (!skill) {
48
+ throw new SpruceError({
49
+ code: 'SKILL_NOT_FOUND',
50
+ friendlyMessage: `I could not find a skill with the slug of ${namespace}.`,
51
+ })
52
+ }
53
+
54
+ this.Service('dependency').add({
55
+ id: skill.id,
56
+ namespace: skill.slug,
57
+ })
58
+
59
+ return {
60
+ summaryLines: [`Added "${skill.name}" as a dependency!`],
61
+ }
62
+ }
63
+ }