@sprucelabs/spruce-cli 14.28.5 → 14.29.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 (142) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/build/__tests__/behavioral/BootingWithBadFiles.test.js +26 -13
  3. package/build/__tests__/behavioral/BootingWithBadFiles.test.js.map +1 -1
  4. package/build/__tests__/behavioral/SettingLogTransportsInASkill.test.js +13 -9
  5. package/build/__tests__/behavioral/SettingLogTransportsInASkill.test.js.map +1 -1
  6. package/build/__tests__/behavioral/SyncingEventsOnlyFromDependencies.test.d.ts +1 -1
  7. package/build/__tests__/behavioral/SyncingEventsOnlyFromDependencies.test.js +24 -14
  8. package/build/__tests__/behavioral/SyncingEventsOnlyFromDependencies.test.js.map +1 -1
  9. package/build/__tests__/behavioral/TestingDataStores.test.js +15 -11
  10. package/build/__tests__/behavioral/TestingDataStores.test.js.map +1 -1
  11. package/build/__tests__/behavioral/eventContract/PullingMercuryEventContract.test.js +3 -1
  12. package/build/__tests__/behavioral/eventContract/PullingMercuryEventContract.test.js.map +1 -1
  13. package/build/__tests__/behavioral/events/CreatingAListener.test.d.ts +2 -0
  14. package/build/__tests__/behavioral/events/CreatingAListener.test.js +157 -81
  15. package/build/__tests__/behavioral/events/CreatingAListener.test.js.map +1 -1
  16. package/build/__tests__/behavioral/events/KeepingEventsInSync2.test.js +1 -1
  17. package/build/__tests__/behavioral/events/KeepingEventsInSync2.test.js.map +1 -1
  18. package/build/__tests__/behavioral/events/KeepingListenersInSync.test.d.ts +7 -0
  19. package/build/__tests__/behavioral/events/KeepingListenersInSync.test.js +171 -0
  20. package/build/__tests__/behavioral/events/KeepingListenersInSync.test.js.map +1 -0
  21. package/build/__tests__/behavioral/events/SkillEmitsBootEvents.test.d.ts +1 -0
  22. package/build/__tests__/behavioral/events/SkillEmitsBootEvents.test.js +53 -21
  23. package/build/__tests__/behavioral/events/SkillEmitsBootEvents.test.js.map +1 -1
  24. package/build/__tests__/behavioral/skill/UpgradingASkill2.test.d.ts +1 -1
  25. package/build/__tests__/behavioral/skill/UpgradingASkill2.test.js +10 -20
  26. package/build/__tests__/behavioral/skill/UpgradingASkill2.test.js.map +1 -1
  27. package/build/__tests__/behavioral/skill/UpgradingWithListeners.test.d.ts +5 -0
  28. package/build/__tests__/behavioral/skill/UpgradingWithListeners.test.js +137 -0
  29. package/build/__tests__/behavioral/skill/UpgradingWithListeners.test.js.map +1 -0
  30. package/build/__tests__/behavioral/{CreatingADataStore.test.d.ts → stores/CreatingADataStore.test.d.ts} +2 -1
  31. package/build/__tests__/behavioral/{CreatingADataStore.test.js → stores/CreatingADataStore.test.js} +87 -57
  32. package/build/__tests__/behavioral/stores/CreatingADataStore.test.js.map +1 -0
  33. package/build/__tests__/behavioral/{KeepingDataStoresInSync.test.d.ts → stores/KeepingDataStoresInSync.test.d.ts} +5 -2
  34. package/build/__tests__/behavioral/{KeepingDataStoresInSync.test.js → stores/KeepingDataStoresInSync.test.js} +138 -49
  35. package/build/__tests__/behavioral/stores/KeepingDataStoresInSync.test.js.map +1 -0
  36. package/build/__tests__/behavioral/tests/CreatingATest.test.js +14 -10
  37. package/build/__tests__/behavioral/tests/CreatingATest.test.js.map +1 -1
  38. package/build/__tests__/behavioral/views/TestingViewControllers.test.d.ts +1 -0
  39. package/build/__tests__/behavioral/views/TestingViewControllers.test.js +67 -35
  40. package/build/__tests__/behavioral/views/TestingViewControllers.test.js.map +1 -1
  41. package/build/__tests__/implementation/AuthService.test.d.ts +1 -0
  42. package/build/__tests__/implementation/AuthService.test.js +8 -0
  43. package/build/__tests__/implementation/AuthService.test.js.map +1 -1
  44. package/build/__tests__/implementation/EventStore.test.js +3 -1
  45. package/build/__tests__/implementation/EventStore.test.js.map +1 -1
  46. package/build/__tests__/implementation/StoreFeature.test.d.ts +4 -0
  47. package/build/__tests__/implementation/StoreFeature.test.js +132 -0
  48. package/build/__tests__/implementation/StoreFeature.test.js.map +1 -0
  49. package/build/cli.d.ts +1 -1
  50. package/build/cli.js +1 -1
  51. package/build/cli.js.map +1 -1
  52. package/build/features/event/EventFeature.d.ts +2 -2
  53. package/build/features/event/EventFeature.js +53 -13
  54. package/build/features/event/EventFeature.js.map +1 -1
  55. package/build/features/event/actions/ListenAction.d.ts +1 -0
  56. package/build/features/event/actions/ListenAction.js +60 -31
  57. package/build/features/event/actions/ListenAction.js.map +1 -1
  58. package/build/features/event/actions/SyncListenersAction.d.ts +15 -0
  59. package/build/features/event/actions/SyncListenersAction.js +115 -0
  60. package/build/features/event/actions/SyncListenersAction.js.map +1 -0
  61. package/build/features/event/builders/ListenerTemplateItemBuilder.d.ts +8 -0
  62. package/build/features/event/builders/ListenerTemplateItemBuilder.js +65 -0
  63. package/build/features/event/builders/ListenerTemplateItemBuilder.js.map +1 -0
  64. package/build/features/event/stores/EventStore.js +2 -2
  65. package/build/features/event/stores/EventStore.js.map +1 -1
  66. package/build/features/event/stores/ListenerStore.d.ts +9 -0
  67. package/build/features/event/stores/ListenerStore.js +122 -0
  68. package/build/features/event/stores/ListenerStore.js.map +1 -0
  69. package/build/features/event/writers/EventWriter.d.ts +4 -1
  70. package/build/features/event/writers/EventWriter.js +42 -8
  71. package/build/features/event/writers/EventWriter.js.map +1 -1
  72. package/build/features/node/NodeFeature.js +6 -11
  73. package/build/features/node/NodeFeature.js.map +1 -1
  74. package/build/features/skill/SkillFeature.js +1 -1
  75. package/build/features/skill/SkillFeature.js.map +1 -1
  76. package/build/features/skill/stores/SkillStore.js +4 -8
  77. package/build/features/skill/stores/SkillStore.js.map +1 -1
  78. package/build/features/store/StoreFeature.d.ts +1 -1
  79. package/build/features/store/StoreFeature.js +6 -6
  80. package/build/features/store/StoreFeature.js.map +1 -1
  81. package/build/features/store/actions/SyncAction.js +11 -10
  82. package/build/features/store/actions/SyncAction.js.map +1 -1
  83. package/build/features/store/writers/StoreWriter.d.ts +6 -0
  84. package/build/features/store/writers/StoreWriter.js +78 -8
  85. package/build/features/store/writers/StoreWriter.js.map +1 -1
  86. package/build/services/AuthService.d.ts +4 -1
  87. package/build/services/AuthService.js +15 -4
  88. package/build/services/AuthService.js.map +1 -1
  89. package/build/services/LintService.d.ts +4 -1
  90. package/build/services/LintService.js +123 -94
  91. package/build/services/LintService.js.map +1 -1
  92. package/build/services/ServiceFactory.js +3 -3
  93. package/build/services/ServiceFactory.js.map +1 -1
  94. package/build/stores/StoreFactory.d.ts +2 -0
  95. package/build/stores/StoreFactory.js +4 -1
  96. package/build/stores/StoreFactory.js.map +1 -1
  97. package/build/tests/AbstractCliTest.js +3 -3
  98. package/build/tests/AbstractCliTest.js.map +1 -1
  99. package/build/writers/AbstractWriter.d.ts +0 -3
  100. package/build/writers/AbstractWriter.js +2 -18
  101. package/build/writers/AbstractWriter.js.map +1 -1
  102. package/package.json +30 -28
  103. package/src/__tests__/behavioral/BootingWithBadFiles.test.ts +8 -3
  104. package/src/__tests__/behavioral/SettingLogTransportsInASkill.test.ts +2 -0
  105. package/src/__tests__/behavioral/SyncingEventsOnlyFromDependencies.test.ts +10 -5
  106. package/src/__tests__/behavioral/TestingDataStores.test.ts +2 -0
  107. package/src/__tests__/behavioral/eventContract/PullingMercuryEventContract.test.ts +1 -0
  108. package/src/__tests__/behavioral/events/CreatingAListener.test.ts +28 -9
  109. package/src/__tests__/behavioral/events/KeepingEventsInSync2.test.ts +1 -1
  110. package/src/__tests__/behavioral/events/KeepingListenersInSync.test.ts +47 -0
  111. package/src/__tests__/behavioral/events/SkillEmitsBootEvents.test.ts +6 -0
  112. package/src/__tests__/behavioral/skill/UpgradingASkill2.test.ts +1 -10
  113. package/src/__tests__/behavioral/skill/UpgradingWithListeners.test.ts +59 -0
  114. package/src/__tests__/behavioral/{CreatingADataStore.test.ts → stores/CreatingADataStore.test.ts} +13 -6
  115. package/src/__tests__/behavioral/{KeepingDataStoresInSync.test.ts → stores/KeepingDataStoresInSync.test.ts} +37 -8
  116. package/src/__tests__/behavioral/tests/CreatingATest.test.ts +2 -0
  117. package/src/__tests__/behavioral/views/TestingViewControllers.test.ts +6 -0
  118. package/src/__tests__/implementation/AuthService.test.ts +6 -0
  119. package/src/__tests__/implementation/EventStore.test.ts +1 -0
  120. package/src/__tests__/implementation/StoreFeature.test.ts +40 -0
  121. package/src/cli.ts +2 -2
  122. package/src/features/event/EventFeature.ts +21 -4
  123. package/src/features/event/actions/ListenAction.ts +9 -3
  124. package/src/features/event/actions/SyncListenersAction.ts +38 -0
  125. package/src/features/event/builders/ListenerTemplateItemBuilder.ts +27 -0
  126. package/src/features/event/stores/EventStore.ts +1 -1
  127. package/src/features/event/stores/ListenerStore.ts +32 -0
  128. package/src/features/event/writers/EventWriter.ts +19 -0
  129. package/src/features/node/NodeFeature.ts +0 -3
  130. package/src/features/skill/SkillFeature.ts +1 -1
  131. package/src/features/skill/stores/SkillStore.ts +4 -3
  132. package/src/features/store/StoreFeature.ts +3 -3
  133. package/src/features/store/actions/SyncAction.ts +2 -1
  134. package/src/features/store/writers/StoreWriter.ts +30 -0
  135. package/src/services/AuthService.ts +15 -5
  136. package/src/services/LintService.ts +19 -2
  137. package/src/services/ServiceFactory.ts +9 -3
  138. package/src/stores/StoreFactory.ts +3 -0
  139. package/src/tests/AbstractCliTest.ts +2 -2
  140. package/src/writers/AbstractWriter.ts +2 -13
  141. package/build/__tests__/behavioral/CreatingADataStore.test.js.map +0 -1
  142. package/build/__tests__/behavioral/KeepingDataStoresInSync.test.js.map +0 -1
@@ -1,11 +1,17 @@
1
1
  import { diskUtil } from '@sprucelabs/spruce-skill-utils'
2
2
  import { test, assert } from '@sprucelabs/test'
3
+ import LintService from '../../../services/LintService'
3
4
  import AbstractSkillTest from '../../../tests/AbstractSkillTest'
4
5
  import testUtil from '../../../tests/utilities/test.utility'
5
6
 
6
7
  export default class TestingViewControllersTest extends AbstractSkillTest {
7
8
  protected static skillCacheKey = 'viewsWithTests'
8
9
 
10
+ protected static async beforeEach() {
11
+ await super.beforeEach()
12
+ LintService.enableLinting()
13
+ }
14
+
9
15
  @test()
10
16
  protected static async showsNotInstalled() {
11
17
  const viewFeature = this.cli.getFeature('view')
@@ -70,11 +70,13 @@ export default class AuthServiceTest extends AbstractCliTest {
70
70
 
71
71
  @test()
72
72
  protected static getCurrentSkillReturnsNull() {
73
+ this.writePackageJson()
73
74
  assert.isNull(this.auth.getCurrentSkill())
74
75
  }
75
76
 
76
77
  @test()
77
78
  protected static canSetCurrentSkill() {
79
+ this.writePackageJson()
78
80
  const skill = {
79
81
  id: '123467aaoeuaoeu',
80
82
  apiKey: 'taco',
@@ -86,4 +88,8 @@ export default class AuthServiceTest extends AbstractCliTest {
86
88
 
87
89
  assert.isEqualDeep(this.auth.getCurrentSkill(), skill)
88
90
  }
91
+
92
+ private static writePackageJson() {
93
+ diskUtil.writeFile(this.resolvePath('package.json'), '{}')
94
+ }
89
95
  }
@@ -29,6 +29,7 @@ export default class EventStoreTest extends AbstractEventTest {
29
29
  public static async beforeEach() {
30
30
  await super.beforeEach()
31
31
  this.createAction = this.Action<CreateAction>('event', 'create')
32
+ diskUtil.writeFile(this.resolvePath('package.json'), '{}')
32
33
  }
33
34
 
34
35
  @test()
@@ -0,0 +1,40 @@
1
+ import { test, assert } from '@sprucelabs/test'
2
+ import CommandService from '../../services/CommandService'
3
+ import AbstractCliTest from '../../tests/AbstractCliTest'
4
+
5
+ export default class StoreFeatureTest extends AbstractCliTest {
6
+ @test()
7
+ protected static async syncsOnWillExecute() {
8
+ await this.FeatureFixture().installCachedFeatures('stores')
9
+
10
+ CommandService.setMockResponse(/yarn/, {
11
+ code: 0,
12
+ })
13
+
14
+ let hitCount = 0
15
+ const emitter = this.getEmitter()
16
+ await emitter.on(
17
+ 'feature.will-execute',
18
+ async ({ featureCode, actionCode }) => {
19
+ if (featureCode === 'store' && actionCode === 'sync') {
20
+ hitCount++
21
+ }
22
+ }
23
+ )
24
+
25
+ await emitter.emit('feature.will-execute', {
26
+ featureCode: 'node',
27
+ actionCode: 'upgrade',
28
+ })
29
+
30
+ assert.isEqual(hitCount, 1)
31
+
32
+ await emitter.emit('feature.did-execute', {
33
+ featureCode: 'node',
34
+ actionCode: 'upgrade',
35
+ results: {},
36
+ })
37
+
38
+ assert.isEqual(hitCount, 1)
39
+ }
40
+ }
package/src/cli.ts CHANGED
@@ -45,7 +45,7 @@ import { argParserUtil } from './utilities/argParser.utility'
45
45
  import WriterFactory from './writers/WriterFactory'
46
46
 
47
47
  interface HealthOptions {
48
- isRunningLocally?: boolean
48
+ shouldRunOnSourceFiles?: boolean
49
49
  }
50
50
 
51
51
  export interface CliInterface extends MercuryEventEmitter<GlobalEventContract> {
@@ -153,7 +153,7 @@ export default class Cli implements CliInterface {
153
153
  try {
154
154
  const commandService = this.serviceFactory.Service(this.cwd, 'command')
155
155
  const command =
156
- options?.isRunningLocally === false
156
+ options?.shouldRunOnSourceFiles === false
157
157
  ? 'yarn health'
158
158
  : 'yarn health.local'
159
159
  const results = await commandService.execute(command)
@@ -3,6 +3,7 @@ import { diskUtil } from '@sprucelabs/spruce-skill-utils'
3
3
  import syncEventActionSchema from '#spruce/schemas/spruceCli/v2020_07_22/syncEventOptions.schema'
4
4
  import TerminalInterface from '../../interfaces/TerminalInterface'
5
5
  import { FileDescription } from '../../types/cli.types'
6
+ import actionUtil from '../../utilities/action.utility'
6
7
  import AbstractFeature, {
7
8
  FeatureDependency,
8
9
  FeatureOptions,
@@ -73,6 +74,11 @@ export default class EventFeature extends AbstractFeature {
73
74
 
74
75
  public async afterPackageInstall() {
75
76
  diskUtil.createDir(diskUtil.resolvePath(this.cwd, 'src', 'events'))
77
+ const isSkillInstalled = await this.featureInstaller.isInstalled('skill')
78
+ if (isSkillInstalled) {
79
+ return await this.Action('event', 'sync.listeners').execute({})
80
+ }
81
+
76
82
  return {}
77
83
  }
78
84
 
@@ -82,19 +88,21 @@ export default class EventFeature extends AbstractFeature {
82
88
  }): Promise<FeatureActionResponse> {
83
89
  const { featureCode, actionCode } = payload
84
90
 
91
+ let results: FeatureActionResponse = {}
92
+
85
93
  if (!this.initiatingAction) {
86
94
  EventStore.clearCache()
87
95
  const combined = this.combineCodes(featureCode, actionCode)
88
96
  this.initiatingAction = combined
89
97
  }
90
98
 
91
- const isInstalled = await this.featureInstaller.isInstalled('event')
92
-
93
99
  if (featureCode === 'node' || featureCode === 'upgrade') {
94
100
  const settings = this.Service('eventSettings')
95
101
  settings.clearListenerCache()
96
102
  }
97
103
 
104
+ const isInstalled = await this.featureInstaller.isInstalled('event')
105
+
98
106
  if (
99
107
  isInstalled &&
100
108
  (featureCode === 'event' ||
@@ -102,10 +110,19 @@ export default class EventFeature extends AbstractFeature {
102
110
  actionCode === 'login') &&
103
111
  actionCode !== 'setRemote'
104
112
  ) {
105
- return this.appendRemoteToResultsOrPrompt()
113
+ const remoteResults = await this.appendRemoteToResultsOrPrompt()
114
+
115
+ results = actionUtil.mergeActionResults(results, remoteResults)
106
116
  }
107
117
 
108
- return {}
118
+ if (featureCode === 'node' && actionCode === 'upgrade' && isInstalled) {
119
+ const syncResults = await this.Action('event', 'sync.listeners').execute(
120
+ {}
121
+ )
122
+ results = actionUtil.mergeActionResults(results, syncResults)
123
+ }
124
+
125
+ return results
109
126
  }
110
127
 
111
128
  private async handleDidExecute(payload: {
@@ -151,8 +151,8 @@ export default class ListenAction extends AbstractAction<OptionsSchema> {
151
151
  templateItems.responsePayloadSchemaTemplateItem
152
152
  }
153
153
 
154
- const generator = this.Writer('event')
155
- const results = await generator.writeListener(resolvedDestination, {
154
+ const writer = this.Writer('event')
155
+ response.files = await writer.writeListener(resolvedDestination, {
156
156
  ...normalizedOptions,
157
157
  version: resolvedVersion,
158
158
  eventName,
@@ -168,7 +168,9 @@ export default class ListenAction extends AbstractAction<OptionsSchema> {
168
168
  schemaTypesLookupDir: resolvedSchemaTypesLookupDir,
169
169
  })
170
170
 
171
- response.files = results
171
+ const syncResults = await this.syncListeners()
172
+
173
+ response = actionUtil.mergeActionResults(syncResults, response)
172
174
 
173
175
  if (isSkillEvent) {
174
176
  const syncOptions = normalizeSchemaValues(
@@ -191,6 +193,10 @@ export default class ListenAction extends AbstractAction<OptionsSchema> {
191
193
  }
192
194
  }
193
195
 
196
+ private async syncListeners() {
197
+ return this.Action('event', 'sync.listeners').execute({})
198
+ }
199
+
194
200
  private async collectEvent(
195
201
  contracts: EventContract[],
196
202
  namespace: string
@@ -0,0 +1,38 @@
1
+ import { buildSchema } from '@sprucelabs/schema'
2
+ import { diskUtil } from '@sprucelabs/spruce-skill-utils'
3
+ import AbstractAction from '../../AbstractAction'
4
+ import ListenerTemplateItemBuilder from '../builders/ListenerTemplateItemBuilder'
5
+
6
+ const syncListenersOptionScheam = buildSchema({
7
+ id: 'syncListenersOptions',
8
+ fields: {},
9
+ })
10
+
11
+ type OptionsSchema = typeof syncListenersOptionScheam
12
+
13
+ export default class SyncListenerAction extends AbstractAction<OptionsSchema> {
14
+ public optionsSchema: OptionsSchema = syncListenersOptionScheam
15
+ public invocationMessage = 'Syncing listeners... 🎧'
16
+ public commandAliases = ['sync.listeners']
17
+
18
+ public async execute() {
19
+ const listeners = await this.Store('listener').loadListeners()
20
+ const builder = new ListenerTemplateItemBuilder()
21
+
22
+ const templateItems = builder.buildTemplateItems({
23
+ listeners,
24
+ cwd: this.cwd,
25
+ })
26
+
27
+ const files = await this.Writer('event').writeListenerMap(
28
+ diskUtil.resolveHashSprucePath(this.cwd, 'events'),
29
+ {
30
+ listeners: templateItems,
31
+ }
32
+ )
33
+
34
+ return {
35
+ files,
36
+ }
37
+ }
38
+ }
@@ -0,0 +1,27 @@
1
+ import pathUtil from 'path'
2
+ import { diskUtil } from '@sprucelabs/spruce-skill-utils'
3
+ import { ListenerTemplateItem } from '@sprucelabs/spruce-templates'
4
+ import { Listener } from '../stores/ListenerStore'
5
+
6
+ export default class ListenerTemplateItemBuilder {
7
+ public buildTemplateItems(options: { listeners: Listener[]; cwd: string }) {
8
+ const destination = diskUtil.resolveHashSprucePath(
9
+ options.cwd,
10
+ 'events',
11
+ 'listeners.ts'
12
+ )
13
+
14
+ const listeners: ListenerTemplateItem[] = []
15
+
16
+ for (const match of options.listeners) {
17
+ listeners.push({
18
+ ...match,
19
+ path: pathUtil
20
+ .relative(pathUtil.dirname(destination), match.path)
21
+ .replace('.ts', ''),
22
+ })
23
+ }
24
+
25
+ return listeners
26
+ }
27
+ }
@@ -76,7 +76,7 @@ export default class EventStore extends AbstractStore {
76
76
  try {
77
77
  contracts = await this.fetchRemoteContracts(namespaces)
78
78
  } catch (err: any) {
79
- const error = err.options.responseErrors[0]
79
+ const error = err.options.responseErrors?.[0] ?? err
80
80
  throw error
81
81
  }
82
82
 
@@ -0,0 +1,32 @@
1
+ import { eventDiskUtil } from '@sprucelabs/spruce-event-utils'
2
+ import { diskUtil } from '@sprucelabs/spruce-skill-utils'
3
+ import { ListenerTemplateItem } from '@sprucelabs/spruce-templates'
4
+ import globby from 'globby'
5
+ import AbstractStore from '../../../stores/AbstractStore'
6
+
7
+ export type Listener = ListenerTemplateItem & {
8
+ path: string
9
+ }
10
+
11
+ export default class ListenerStore extends AbstractStore {
12
+ public name = 'listener'
13
+
14
+ public async loadListeners() {
15
+ const matches = await globby(
16
+ diskUtil.resolvePath(this.cwd, 'src', 'listeners', '**/*.listener.ts')
17
+ )
18
+
19
+ const listeners: Listener[] = []
20
+
21
+ for (const match of matches) {
22
+ const listener = eventDiskUtil.splitPathToListener(match)
23
+
24
+ listeners.push({
25
+ ...listener,
26
+ path: match,
27
+ })
28
+ }
29
+
30
+ return listeners
31
+ }
32
+ }
@@ -9,6 +9,7 @@ import {
9
9
  import {
10
10
  EventContractTemplateItem,
11
11
  EventListenerOptions,
12
+ ListenerTemplateItem,
12
13
  } from '@sprucelabs/spruce-templates'
13
14
  import { GeneratedFile } from '../../../types/cli.types'
14
15
  import AbstractWriter from '../../../writers/AbstractWriter'
@@ -182,6 +183,24 @@ export default class EventWriter extends AbstractWriter {
182
183
  return results
183
184
  }
184
185
 
186
+ public async writeListenerMap(
187
+ destinationDir: string,
188
+ options: {
189
+ listeners: ListenerTemplateItem[]
190
+ }
191
+ ) {
192
+ const destination = diskUtil.resolvePath(destinationDir, 'listeners.ts')
193
+ const contents = this.templates.listeners({ listeners: options.listeners })
194
+
195
+ const results = await this.writeFileIfChangedMixinResults(
196
+ destination,
197
+ contents,
198
+ 'An object holding all your data stores for easy import!'
199
+ )
200
+
201
+ return results
202
+ }
203
+
185
204
  public async writeEvent(
186
205
  destinationDir: string,
187
206
  options: {
@@ -64,9 +64,6 @@ export default class NodeFeature<
64
64
  this.ui.startLoading('Cleaning build...')
65
65
  await this.Service('command').execute('yarn clean.build')
66
66
 
67
- this.ui.startLoading('Applying lint rules to all files...')
68
- await this.Service('command').execute('yarn fix.lint')
69
-
70
67
  this.ui.startLoading('Rebuilding...')
71
68
  await this.Service('command').execute('yarn build.dev')
72
69
 
@@ -196,7 +196,7 @@ export default class SkillFeature<
196
196
 
197
197
  if (isInstalled && featureCode === 'node' && actionCode === 'upgrade') {
198
198
  const updater = new Updater(this, this.emitter)
199
- const files = await updater.updateFiles(upgradeOptions as any)
199
+ const files = await updater.updateFiles(upgradeOptions ?? {})
200
200
  return {
201
201
  files,
202
202
  }
@@ -71,6 +71,7 @@ export default class SkillStore extends AbstractStore {
71
71
 
72
72
  if (currentSkill) {
73
73
  const client = await this.connectToApi({ shouldAuthAsCurrentSkill: true })
74
+
74
75
  const response = await client.emit('get-skill::v2020_12_25', {
75
76
  target: {
76
77
  skillId: currentSkill.id,
@@ -85,6 +86,7 @@ export default class SkillStore extends AbstractStore {
85
86
  isRegistered: true,
86
87
  apiKey: currentSkill.apiKey,
87
88
  }
89
+
88
90
  return SkillStore.currentSkill as CurrentSkill
89
91
  }
90
92
 
@@ -133,12 +135,11 @@ export default class SkillStore extends AbstractStore {
133
135
  if (isRegistered) {
134
136
  throw new SpruceError({
135
137
  code: 'GENERIC',
136
- friendlyMessage: `You can't change the namespace of a skill that is registered.`,
138
+ friendlyMessage: `You can't set the namespace of a skill that is registered.`,
137
139
  })
138
140
  }
139
141
 
140
- const pkg = this.Service('pkg')
141
- pkg.set({ path: 'skill.namespace', value: namesUtil.toKebab(namespace) })
142
+ this.Service('auth').updateCurrentSkillNamespace(namespace)
142
143
  }
143
144
 
144
145
  private getEventNamespaceForNotRegistered() {
@@ -37,8 +37,8 @@ export default class StoreFeature extends AbstractFeature {
37
37
  this.registerAbstractTestClassHandler.bind(this)
38
38
  )
39
39
  void this.emitter.on(
40
- 'feature.did-execute',
41
- this.didExecuterHandler.bind(this)
40
+ 'feature.will-execute',
41
+ this.handleWillExecute.bind(this)
42
42
  )
43
43
  }
44
44
 
@@ -55,7 +55,7 @@ export default class StoreFeature extends AbstractFeature {
55
55
  }
56
56
  }
57
57
 
58
- private async didExecuterHandler(payload: {
58
+ private async handleWillExecute(payload: {
59
59
  featureCode: string
60
60
  actionCode: string
61
61
  }) {
@@ -31,7 +31,8 @@ export default class SyncAction extends AbstractAction<OptionsSchema> {
31
31
  const builder = new StoreTemplateItemBuilder()
32
32
  const templateItems = builder.buildTemplateItems(stores, destination)
33
33
 
34
- files = await this.Writer('store').writeTypes(destination, {
34
+ const writer = this.Writer('store')
35
+ files = await writer.writeTypesAndMap(destination, {
35
36
  stores: templateItems,
36
37
  })
37
38
  }
@@ -59,6 +59,18 @@ export default class StoreWriter extends AbstractWriter {
59
59
  return results
60
60
  }
61
61
 
62
+ public async writeTypesAndMap(
63
+ destination: string,
64
+ options: { stores: StoreTemplateItem[] }
65
+ ) {
66
+ const [types, map] = await Promise.all([
67
+ this.writeTypes(destination, options),
68
+ this.writeMap(destination, options),
69
+ ])
70
+
71
+ return [...types, ...map]
72
+ }
73
+
62
74
  public async writeTypes(
63
75
  destination: string,
64
76
  options: { stores: StoreTemplateItem[] }
@@ -77,4 +89,22 @@ export default class StoreWriter extends AbstractWriter {
77
89
 
78
90
  return files
79
91
  }
92
+
93
+ public async writeMap(
94
+ destination: string,
95
+ options: { stores: StoreTemplateItem[] }
96
+ ) {
97
+ const file = diskUtil.resolvePath(destination, 'stores.ts')
98
+ const mapContent = this.templates.stores(options)
99
+
100
+ const files = this.writeFileIfChangedMixinResults(
101
+ file,
102
+ mapContent,
103
+ 'A reference to all your data stores for easy inclusion.'
104
+ )
105
+
106
+ await this.lint(file)
107
+
108
+ return files
109
+ }
80
110
  }
@@ -1,7 +1,8 @@
1
1
  import { SpruceSchemas } from '@sprucelabs/mercury-types'
2
2
  import { normalizeSchemaValues, validateSchemaValues } from '@sprucelabs/schema'
3
- import { EnvService } from '@sprucelabs/spruce-skill-utils'
3
+ import { EnvService, namesUtil } from '@sprucelabs/spruce-skill-utils'
4
4
  import personWithTokenSchema from '#spruce/schemas/spruceCli/v2020_07_22/personWithToken.schema'
5
+ import PkgService from './PkgService'
5
6
 
6
7
  type PersonWithToken = SpruceSchemas.SpruceCli.v2020_07_22.PersonWithToken
7
8
 
@@ -16,9 +17,11 @@ const LOGGED_IN_PERSON_KEY = 'LOGGED_IN_PERSON'
16
17
 
17
18
  export default class AuthService {
18
19
  private env: EnvService
20
+ private pkg: PkgService
19
21
 
20
- public constructor(envService: EnvService) {
22
+ public constructor(envService: EnvService, pkgService: PkgService) {
21
23
  this.env = envService
24
+ this.pkg = pkgService
22
25
  }
23
26
 
24
27
  public getLoggedInPerson(): PersonWithToken | null {
@@ -51,7 +54,7 @@ export default class AuthService {
51
54
  const id = this.env.get('SKILL_ID') as string
52
55
  const apiKey = this.env.get('SKILL_API_KEY') as string
53
56
  const name = this.env.get('SKILL_NAME') as string
54
- const slug = this.env.get('SKILL_SLUG') as string
57
+ const slug = this.pkg.get('skill.namespace') as string
55
58
 
56
59
  if (id && apiKey) {
57
60
  return {
@@ -69,13 +72,20 @@ export default class AuthService {
69
72
  this.env.unset('SKILL_ID')
70
73
  this.env.unset('SKILL_API_KEY')
71
74
  this.env.unset('SKILL_NAME')
72
- this.env.unset('SKILL_SLUG')
73
75
  }
74
76
 
75
77
  public updateCurrentSkill(skill: SkillAuth) {
76
78
  this.env.set('SKILL_ID', skill.id)
77
79
  this.env.set('SKILL_API_KEY', skill.apiKey)
78
80
  this.env.set('SKILL_NAME', skill.name)
79
- this.env.set('SKILL_SLUG', skill.slug)
81
+
82
+ this.updateCurrentSkillNamespace(skill.slug)
83
+ }
84
+
85
+ public updateCurrentSkillNamespace(namespace: string) {
86
+ this.pkg.set({
87
+ path: 'skill.namespace',
88
+ value: namesUtil.toKebab(namespace),
89
+ })
80
90
  }
81
91
  }
@@ -1,4 +1,5 @@
1
1
  import { SchemaError } from '@sprucelabs/schema'
2
+ // import { ESLint } from 'eslint'
2
3
  import fs from 'fs-extra'
3
4
  import SpruceError from '../errors/SpruceError'
4
5
  import CommandService from './CommandService'
@@ -7,9 +8,19 @@ export default class LintService {
7
8
  public cwd: string
8
9
  private command: CommandService
9
10
 
10
- public constructor(cwd: string, command: CommandService) {
11
+ private static isLintingEnabled = true
12
+
13
+ public static disableLinting() {
14
+ this.isLintingEnabled = false
15
+ }
16
+
17
+ public static enableLinting() {
18
+ this.isLintingEnabled = true
19
+ }
20
+
21
+ public constructor(cwd: string, commandService: CommandService) {
11
22
  this.cwd = cwd
12
- this.command = command
23
+ this.command = commandService
13
24
  }
14
25
 
15
26
  public fix = async (pattern: string): Promise<string[]> => {
@@ -20,9 +31,15 @@ export default class LintService {
20
31
  })
21
32
  }
22
33
 
34
+ if (!LintService.isLintingEnabled) {
35
+ return []
36
+ }
37
+
23
38
  let fixedFiles: any = {}
24
39
  const fixedPaths: string[] = []
25
40
  try {
41
+ // const cli = new ESLint({ fix: true, cwd: this.cwd, cache: true })
42
+ // fixedFiles = await cli.lintFiles([pattern])
26
43
  const script = `"(async function lint() { try { const { ESLint } = require('eslint'); const cli = new ESLint({ fix: true, cwd: '${this.cwd}', }); const result = await cli.lintFiles(['${pattern}']); console.log(JSON.stringify(result)); } catch (err) { console.log(err.toString()); }})()"`
27
44
 
28
45
  const { stdout } = await this.command.execute('node', {
@@ -39,7 +39,10 @@ export default class ServiceFactory {
39
39
  public Service<S extends Service>(cwd: string, type: S): ServiceMap[S] {
40
40
  switch (type) {
41
41
  case 'auth':
42
- return new AuthService(new EnvService(cwd)) as ServiceMap[S]
42
+ return new AuthService(
43
+ new EnvService(cwd),
44
+ new PkgService(cwd)
45
+ ) as ServiceMap[S]
43
46
  case 'pkg':
44
47
  return new PkgService(cwd) as ServiceMap[S]
45
48
  case 'env':
@@ -52,7 +55,10 @@ export default class ServiceFactory {
52
55
  command: new CommandService(cwd),
53
56
  }) as ServiceMap[S]
54
57
  case 'lint':
55
- return new LintService(cwd, new CommandService(cwd)) as ServiceMap[S]
58
+ return new LintService(
59
+ cwd,
60
+ this.Service(cwd, 'command')
61
+ ) as ServiceMap[S]
56
62
  case 'command': {
57
63
  return new CommandService(cwd) as ServiceMap[S]
58
64
  }
@@ -74,7 +80,7 @@ export default class ServiceFactory {
74
80
  const commandService = new CommandService(cwd)
75
81
  return new BuildService(
76
82
  commandService,
77
- new LintService(cwd, commandService)
83
+ new LintService(cwd, this.Service(cwd, 'command'))
78
84
  ) as ServiceMap[S]
79
85
  }
80
86
  case 'eventSettings':
@@ -1,5 +1,6 @@
1
1
  import ConversationStore from '../features/conversation/stores/ConversationStore'
2
2
  import EventStore from '../features/event/stores/EventStore'
3
+ import ListenerStore from '../features/event/stores/ListenerStore'
3
4
  import OnboardingStore from '../features/onboard/stores/OnboardingStore'
4
5
  import OrganizationStore from '../features/organization/stores/OrganizationStore'
5
6
  import SchemaStore from '../features/schema/stores/SchemaStore'
@@ -20,6 +21,7 @@ export interface StoreMap {
20
21
  conversation: ConversationStore
21
22
  store: StoreStore
22
23
  view: ViewStore
24
+ listener: ListenerStore
23
25
  }
24
26
 
25
27
  export type StoreCode = keyof StoreMap
@@ -33,6 +35,7 @@ const storeMap = {
33
35
  conversation: ConversationStore,
34
36
  store: StoreStore,
35
37
  view: ViewStore,
38
+ listener: ListenerStore,
36
39
  }
37
40
 
38
41
  export interface StoreFactoryMethodOptions {
@@ -23,6 +23,7 @@ import CliGlobalEmitter, { GlobalEmitter } from '../GlobalEmitter'
23
23
  import SpyInterface from '../interfaces/SpyInterface'
24
24
  import CommandService from '../services/CommandService'
25
25
  import ImportService from '../services/ImportService'
26
+ import LintService from '../services/LintService'
26
27
  import ServiceFactory, { Service, ServiceMap } from '../services/ServiceFactory'
27
28
  import StoreFactory, {
28
29
  StoreCode,
@@ -32,7 +33,6 @@ import StoreFactory, {
32
33
  } from '../stores/StoreFactory'
33
34
  import { ApiClientFactoryOptions } from '../types/apiClient.types'
34
35
  import { OptionOverrides } from '../types/cli.types'
35
- import AbstractWriter from '../writers/AbstractWriter'
36
36
  import WriterFactory from '../writers/WriterFactory'
37
37
  import FeatureFixture, {
38
38
  FeatureFixtureOptions,
@@ -66,7 +66,7 @@ export default abstract class AbstractCliTest extends AbstractSpruceTest {
66
66
  await super.beforeAll()
67
67
  await this.cleanTestDirsAndFiles()
68
68
 
69
- AbstractWriter.disableLinting()
69
+ LintService.disableLinting()
70
70
 
71
71
  ImportService.setCacheDir(diskUtil.createRandomTempDir())
72
72
  ImportService.enableCaching()