@cratis/screenplay-language 4.52.0 → 4.54.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 (191) hide show
  1. package/README.md +15 -0
  2. package/dist/TypeReferenceSymbol.d.ts +8 -0
  3. package/dist/TypeReferenceSymbol.d.ts.map +1 -0
  4. package/dist/bundles/chunk-GJX4NJYC.js +4836 -0
  5. package/dist/bundles/chunk-GJX4NJYC.js.map +7 -0
  6. package/dist/bundles/index.js +1417 -0
  7. package/dist/bundles/index.js.map +7 -0
  8. package/dist/bundles/sub-languages/capture/index.js +677 -0
  9. package/dist/bundles/sub-languages/capture/index.js.map +7 -0
  10. package/dist/bundles/sub-languages/projection/index.js +1647 -0
  11. package/dist/bundles/sub-languages/projection/index.js.map +7 -0
  12. package/dist/code-actions.d.ts +3 -0
  13. package/dist/code-actions.d.ts.map +1 -0
  14. package/dist/completion-items.d.ts +1 -0
  15. package/dist/completion-items.d.ts.map +1 -1
  16. package/dist/completion-planner.d.ts.map +1 -1
  17. package/dist/completions.d.ts.map +1 -1
  18. package/dist/diagnostic-codes.d.ts +3 -0
  19. package/dist/diagnostic-codes.d.ts.map +1 -1
  20. package/dist/diagnostics.d.ts.map +1 -1
  21. package/dist/hover-content.d.ts.map +1 -1
  22. package/dist/index.d.ts +3 -0
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/keyword-docs.d.ts.map +1 -1
  25. package/dist/language.d.ts +1 -0
  26. package/dist/language.d.ts.map +1 -1
  27. package/dist/production-destinations.d.ts.map +1 -1
  28. package/dist/symbols.d.ts +4 -0
  29. package/dist/symbols.d.ts.map +1 -1
  30. package/dist/tokens.d.ts.map +1 -1
  31. package/dist/validation.d.ts +1 -0
  32. package/dist/validation.d.ts.map +1 -1
  33. package/package.json +13 -9
  34. package/DestinationHint.ts +0 -8
  35. package/ProductionSymbol.ts +0 -11
  36. package/completion-items.ts +0 -261
  37. package/completion-planner.ts +0 -167
  38. package/completions.ts +0 -156
  39. package/diagnostic-codes.ts +0 -43
  40. package/diagnostics.ts +0 -55
  41. package/dist/DestinationHint.js +0 -4
  42. package/dist/DestinationHint.js.map +0 -1
  43. package/dist/ProductionSymbol.js +0 -4
  44. package/dist/ProductionSymbol.js.map +0 -1
  45. package/dist/completion-items.js +0 -228
  46. package/dist/completion-items.js.map +0 -1
  47. package/dist/completion-planner.js +0 -143
  48. package/dist/completion-planner.js.map +0 -1
  49. package/dist/completions.js +0 -101
  50. package/dist/completions.js.map +0 -1
  51. package/dist/diagnostic-codes.js +0 -41
  52. package/dist/diagnostic-codes.js.map +0 -1
  53. package/dist/diagnostics.js +0 -50
  54. package/dist/diagnostics.js.map +0 -1
  55. package/dist/document-context.js +0 -85
  56. package/dist/document-context.js.map +0 -1
  57. package/dist/event-analysis-source.js +0 -19
  58. package/dist/event-analysis-source.js.map +0 -1
  59. package/dist/event-context-catalog.js +0 -116
  60. package/dist/event-context-catalog.js.map +0 -1
  61. package/dist/event-context.js +0 -88
  62. package/dist/event-context.js.map +0 -1
  63. package/dist/file-imports.js +0 -58
  64. package/dist/file-imports.js.map +0 -1
  65. package/dist/file-references.js +0 -70
  66. package/dist/file-references.js.map +0 -1
  67. package/dist/hover-content.js +0 -98
  68. package/dist/hover-content.js.map +0 -1
  69. package/dist/hover.js +0 -15
  70. package/dist/hover.js.map +0 -1
  71. package/dist/index.js +0 -61
  72. package/dist/index.js.map +0 -1
  73. package/dist/inlay-hints.js +0 -15
  74. package/dist/inlay-hints.js.map +0 -1
  75. package/dist/inline-event-validation.js +0 -131
  76. package/dist/inline-event-validation.js.map +0 -1
  77. package/dist/keyword-docs.js +0 -148
  78. package/dist/keyword-docs.js.map +0 -1
  79. package/dist/language.js +0 -196
  80. package/dist/language.js.map +0 -1
  81. package/dist/production-destinations.js +0 -32
  82. package/dist/production-destinations.js.map +0 -1
  83. package/dist/sub-language-registry.js +0 -18
  84. package/dist/sub-language-registry.js.map +0 -1
  85. package/dist/sub-languages/capture/CompletionProvider.js +0 -332
  86. package/dist/sub-languages/capture/CompletionProvider.js.map +0 -1
  87. package/dist/sub-languages/capture/HoverProvider.js +0 -87
  88. package/dist/sub-languages/capture/HoverProvider.js.map +0 -1
  89. package/dist/sub-languages/capture/Validator.js +0 -72
  90. package/dist/sub-languages/capture/Validator.js.map +0 -1
  91. package/dist/sub-languages/capture/index.js +0 -58
  92. package/dist/sub-languages/capture/index.js.map +0 -1
  93. package/dist/sub-languages/capture/language.js +0 -160
  94. package/dist/sub-languages/capture/language.js.map +0 -1
  95. package/dist/sub-languages/cdl.js +0 -74
  96. package/dist/sub-languages/cdl.js.map +0 -1
  97. package/dist/sub-languages/pdl.js +0 -73
  98. package/dist/sub-languages/pdl.js.map +0 -1
  99. package/dist/sub-languages/projection/CodeActionProvider.js +0 -93
  100. package/dist/sub-languages/projection/CodeActionProvider.js.map +0 -1
  101. package/dist/sub-languages/projection/CompletionProvider.js +0 -595
  102. package/dist/sub-languages/projection/CompletionProvider.js.map +0 -1
  103. package/dist/sub-languages/projection/HoverProvider.js +0 -333
  104. package/dist/sub-languages/projection/HoverProvider.js.map +0 -1
  105. package/dist/sub-languages/projection/Validator.js +0 -388
  106. package/dist/sub-languages/projection/Validator.js.map +0 -1
  107. package/dist/sub-languages/projection/index.js +0 -160
  108. package/dist/sub-languages/projection/index.js.map +0 -1
  109. package/dist/sub-languages/projection/language.js +0 -171
  110. package/dist/sub-languages/projection/language.js.map +0 -1
  111. package/dist/symbols.js +0 -275
  112. package/dist/symbols.js.map +0 -1
  113. package/dist/themes/screenplay-dark.js +0 -30
  114. package/dist/themes/screenplay-dark.js.map +0 -1
  115. package/dist/themes/screenplay-light.js +0 -30
  116. package/dist/themes/screenplay-light.js.map +0 -1
  117. package/dist/tokens.js +0 -147
  118. package/dist/tokens.js.map +0 -1
  119. package/dist/validation.js +0 -248
  120. package/dist/validation.js.map +0 -1
  121. package/document-context.ts +0 -93
  122. package/event-analysis-source.ts +0 -18
  123. package/event-context-catalog.ts +0 -135
  124. package/event-context.ts +0 -119
  125. package/file-imports.ts +0 -70
  126. package/file-references.ts +0 -87
  127. package/for_documentContext/when_stripping_comments.ts +0 -32
  128. package/for_eventContext/when_resolving_generated_catalog_vectors.ts +0 -15
  129. package/for_eventGenerations/when_editing_event_generations.ts +0 -57
  130. package/for_fileImports/when_finding_file_imports.ts +0 -38
  131. package/for_fileReferences/when_recognizing_an_absolute_path/with_paths_of_every_shape.ts +0 -26
  132. package/for_fileReferences/when_scanning_a_document/inside_a_code_fence.ts +0 -26
  133. package/for_fileReferences/when_scanning_a_document/with_a_bare_file_keyword.ts +0 -19
  134. package/for_fileReferences/when_scanning_a_document/with_a_file_directive.ts +0 -30
  135. package/for_fileReferences/when_scanning_a_document/with_a_property_named_file.ts +0 -25
  136. package/for_fileReferences/when_scanning_a_document/with_a_trailing_comment.ts +0 -25
  137. package/for_fileReferences/when_scanning_a_document/with_directives_on_several_constructs.ts +0 -41
  138. package/for_importablePaths/when_listing_what_a_document_can_import.ts +0 -34
  139. package/for_inlineEvents/when_analyzing_many_inline_events.ts +0 -59
  140. package/for_inlineEvents/when_authoring_inline_events.ts +0 -149
  141. package/for_inlineEvents/when_completing_many_events.ts +0 -49
  142. package/for_inlineEvents/when_indexing_command_production_ownership.ts +0 -79
  143. package/for_planCompletions/when_completing_a_file_import.ts +0 -26
  144. package/for_planCompletions/when_completing_a_specification_query.ts +0 -24
  145. package/for_planCompletions/when_completing_a_specification_step.ts +0 -42
  146. package/for_planCompletions/when_completing_an_absent_read_model.ts +0 -14
  147. package/for_planCompletions/when_completing_reaction_reads.ts +0 -36
  148. package/for_projectionCompletionProvider/when_completing_an_event_context_path.ts +0 -102
  149. package/for_projectionHoverProvider/when_hovering_an_event_context_path.ts +0 -44
  150. package/for_projectionValidator/when_validating_a_projection_with_variants.ts +0 -128
  151. package/for_projectionValidator/when_validating_event_context_paths.ts +0 -31
  152. package/for_scanDocument/when_scanning_a_query/with_a_dotted_return_type.ts +0 -34
  153. package/for_scanDocument/when_scanning_aliased_reads.ts +0 -33
  154. package/for_scanDocument/when_scanning_many_commands.ts +0 -47
  155. package/for_tokens/when_highlighting_a_file_import.ts +0 -18
  156. package/for_tokens/when_highlighting_event_metadata.ts +0 -63
  157. package/for_tokens/when_highlighting_specification_steps.ts +0 -28
  158. package/for_validateLines/when_validating_a_document/with_a_problem_of_every_coded_kind.ts +0 -77
  159. package/for_validateLines/when_validating_a_document/with_an_unknown_policy.ts +0 -33
  160. package/for_validateLines/when_validating_a_file_placed_by_an_import/with_names_declared_in_other_files.ts +0 -43
  161. package/for_validateLines/when_validating_event_context_paths/in_a_projection.ts +0 -97
  162. package/for_validateLines/when_validating_file_imports/at_every_level.ts +0 -36
  163. package/for_validateLines/when_validating_production_destinations/with_an_available_identifier.ts +0 -120
  164. package/hover-content.ts +0 -117
  165. package/hover.ts +0 -23
  166. package/index.ts +0 -125
  167. package/inlay-hints.ts +0 -17
  168. package/inline-event-validation.ts +0 -115
  169. package/keyword-docs.ts +0 -152
  170. package/language.ts +0 -212
  171. package/production-destinations.ts +0 -32
  172. package/sub-language-registry.ts +0 -42
  173. package/sub-languages/capture/CompletionProvider.ts +0 -365
  174. package/sub-languages/capture/HoverProvider.ts +0 -99
  175. package/sub-languages/capture/Validator.ts +0 -97
  176. package/sub-languages/capture/index.ts +0 -72
  177. package/sub-languages/capture/language.ts +0 -176
  178. package/sub-languages/cdl.ts +0 -76
  179. package/sub-languages/pdl.ts +0 -75
  180. package/sub-languages/projection/CodeActionProvider.ts +0 -123
  181. package/sub-languages/projection/CompletionProvider.ts +0 -660
  182. package/sub-languages/projection/HoverProvider.ts +0 -377
  183. package/sub-languages/projection/Validator.ts +0 -441
  184. package/sub-languages/projection/index.ts +0 -223
  185. package/sub-languages/projection/language.ts +0 -193
  186. package/symbols.ts +0 -374
  187. package/themes/screenplay-dark.ts +0 -33
  188. package/themes/screenplay-light.ts +0 -33
  189. package/tokens.ts +0 -174
  190. package/validation.ts +0 -443
  191. package/vitest.setup.ts +0 -5
@@ -1,33 +0,0 @@
1
- // Copyright (c) Cratis. All rights reserved.
2
- // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
-
4
- import { describe, beforeEach, it } from 'vitest';
5
- import { diagnosticCodes } from '../../diagnostic-codes';
6
- import { ValidationIssue, validateLines } from '../../validation';
7
-
8
- describe('when validating a document with an unknown policy', () => {
9
- let issues: ValidationIssue[];
10
-
11
- beforeEach(() => {
12
- issues = validateLines([
13
- 'module Invoicing',
14
- ' feature Invoices',
15
- ' slice StateView Overdue',
16
- ' query Overdue => OverdueReadModel[]',
17
- ' authorize CanRead',
18
- ' or CanAlsoRead',
19
- ]);
20
- });
21
-
22
- it('should report the policy named on the authorize line', () => {
23
- issues[0].should.include({ line: 4, code: diagnosticCodes.unknownPolicy });
24
- });
25
-
26
- it('should report the policy continued on the line below it', () => {
27
- issues[1].should.include({ line: 5, code: diagnosticCodes.unknownPolicy });
28
- });
29
-
30
- it('should report nothing else', () => {
31
- issues.should.have.lengthOf(2);
32
- });
33
- });
@@ -1,43 +0,0 @@
1
- // Copyright (c) Cratis. All rights reserved.
2
- // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
-
4
- import { describe, beforeEach, it } from 'vitest';
5
- import { mergeSymbols, scanDocument } from '../../symbols';
6
- import { ValidationIssue, validateLines } from '../../validation';
7
-
8
- // A file an import places in a feature holds slices at its top level, and the names it uses are declared in
9
- // the other files of the application.
10
- describe('when validating a file placed by an import with names declared in other files', () => {
11
- let issues: ValidationIssue[];
12
- let alone: ValidationIssue[];
13
- const fragment = [
14
- 'slice StateChange PlaceOrder',
15
- ' command PlaceOrder',
16
- ' orderId OrderId identifier',
17
- ' customer Customer',
18
- ' authorize Staff',
19
- ' produces OrderPlaced',
20
- ' for orderId',
21
- ' reaction Notify',
22
- ' when OrderPlaced',
23
- ' produces CustomerNotified',
24
- ];
25
-
26
- beforeEach(() => {
27
- const application = mergeSymbols(
28
- scanDocument(['concept OrderId : Uuid', 'policy Staff', ' require authenticated']),
29
- scanDocument(['type Customer', ' name String', 'module Ordering', ' feature Orders', ' slice StateChange PlaceOrder', ' event OrderPlaced', ' note String']),
30
- scanDocument(['import Customers.CustomerNotified']),
31
- );
32
- issues = validateLines(fragment, { application });
33
- alone = validateLines(fragment);
34
- });
35
-
36
- it('should report nothing', () => {
37
- issues.should.be.empty;
38
- });
39
-
40
- it('should report the names as unknown without the application', () => {
41
- alone.map((issue) => issue.code).should.deep.equal(['PLAY0165', 'PLAY0165', 'PLAY0167', 'PLAY0166', 'PLAY0166']);
42
- });
43
- });
@@ -1,97 +0,0 @@
1
- // Copyright (c) Cratis. All rights reserved.
2
- // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
-
4
- import { describe, beforeEach, it } from 'vitest';
5
- import { diagnosticCodes } from '../../diagnostic-codes';
6
- import { eventContextPaths } from '../../event-context';
7
- import { ValidationIssue, validateLines } from '../../validation';
8
-
9
- function validate(...mappings: string[]): ValidationIssue[] {
10
- return validateLines([
11
- 'projection Statistics => StatisticsReadModel',
12
- ' from Happened',
13
- ...mappings.map((mapping) => ` ${mapping}`),
14
- ]);
15
- }
16
-
17
- describe('when validating every event context path the catalog lists', () => {
18
- let issues: ValidationIssue[];
19
-
20
- beforeEach(() => {
21
- issues = validate(
22
- ...eventContextPaths.map((path, index) => `value${index} = $eventContext.${path.path}`),
23
- ...eventContextPaths.map((path) => `count countBy.$eventContext.${path.path}`),
24
- 'week = $eventContext.occurred.Week()',
25
- 'type = $eventContext.EventType.Id',
26
- );
27
- });
28
-
29
- it('should report nothing', () => {
30
- issues.should.be.empty;
31
- });
32
- });
33
-
34
- describe('when validating an unknown event context member', () => {
35
- let issues: ValidationIssue[];
36
-
37
- beforeEach(() => {
38
- issues = validate('cause = $eventContext.causationId');
39
- });
40
-
41
- it('should warn with the compiler code', () => {
42
- issues.map((issue) => [issue.code, issue.severity]).should.deep.equal([[diagnosticCodes.unknownEventContextMember, 'warning']]);
43
- });
44
-
45
- it('should squiggle the whole path', () => {
46
- const [issue] = issues;
47
- [issue.startColumn, issue.endColumn].should.deep.equal([13, 13 + '$eventContext.causationId'.length]);
48
- });
49
- });
50
-
51
- describe('when validating an unknown event context sub-path', () => {
52
- let issues: ValidationIssue[];
53
-
54
- beforeEach(() => {
55
- issues = validate('week = $eventContext.occurred.week');
56
- });
57
-
58
- it('should warn with the compiler code', () => {
59
- issues.map((issue) => [issue.code, issue.severity]).should.deep.equal([[diagnosticCodes.unknownEventContextPath, 'warning']]);
60
- });
61
- });
62
-
63
- describe('when validating a path below an event context collection', () => {
64
- let issues: ValidationIssue[];
65
-
66
- beforeEach(() => {
67
- issues = validate('count byTag.$eventContext.tags.value');
68
- });
69
-
70
- it('should report an error with the compiler code', () => {
71
- issues.map((issue) => [issue.code, issue.severity]).should.deep.equal([[diagnosticCodes.eventContextPathBelowCollection, 'error']]);
72
- });
73
- });
74
-
75
- describe('when validating a dynamic key naming no event context member', () => {
76
- let issues: ValidationIssue[];
77
-
78
- beforeEach(() => {
79
- issues = validate('count byNothing.$eventContext');
80
- });
81
-
82
- it('should report an error with the compiler code', () => {
83
- issues.map((issue) => [issue.code, issue.severity]).should.deep.equal([[diagnosticCodes.missingEventContextPath, 'error']]);
84
- });
85
- });
86
-
87
- describe('when validating a dynamic key naming another source', () => {
88
- let issues: ValidationIssue[];
89
-
90
- beforeEach(() => {
91
- issues = validate('count byUser.$causedBy.subject');
92
- });
93
-
94
- it('should warn with the compiler code', () => {
95
- issues.map((issue) => [issue.code, issue.severity]).should.deep.equal([[diagnosticCodes.unresolvedDynamicKeySource, 'warning']]);
96
- });
97
- });
@@ -1,36 +0,0 @@
1
- // Copyright (c) Cratis. All rights reserved.
2
- // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
-
4
- import { describe, beforeEach, it } from 'vitest';
5
- import { diagnosticCodes } from '../../diagnostic-codes';
6
- import { ValidationIssue, validateLines } from '../../validation';
7
-
8
- describe('when validating file imports at every level', () => {
9
- let issues: ValidationIssue[];
10
-
11
- beforeEach(() => {
12
- issues = validateLines([
13
- 'import Customers.CustomerRegistered',
14
- 'import "**/*.play" // every document',
15
- 'import "Bad\\Path.play"',
16
- 'module Ordering',
17
- ' import "Orders/*.play"',
18
- ' import Customers.CustomerRegistered',
19
- ' feature Orders',
20
- ' import "Slices/**/*.play"',
21
- ' import "Unclosed',
22
- ]);
23
- });
24
-
25
- it('should report the malformed and the qualified imports inside a body', () => {
26
- issues.map((issue) => `${issue.code}@${issue.line}`).should.deep.equal([
27
- `${diagnosticCodes.invalidFileImport}@2`,
28
- `${diagnosticCodes.invalidFileImport}@5`,
29
- `${diagnosticCodes.invalidFileImport}@8`,
30
- ]);
31
- });
32
-
33
- it('should span the whole import', () => {
34
- issues[1].should.include({ startColumn: 3, endColumn: 3 + 'import Customers.CustomerRegistered'.length });
35
- });
36
- });
@@ -1,120 +0,0 @@
1
- // Copyright (c) Cratis. All rights reserved.
2
- // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
-
4
- import { beforeEach, describe, it } from 'vitest';
5
- import { diagnosticCodes } from '../../diagnostic-codes';
6
- import { ValidationIssue, validateLines } from '../../validation';
7
-
8
- const source = [
9
- 'module Projects',
10
- ' feature Registration',
11
- ' slice StateChange Register',
12
- ' command Register',
13
- ' projectId Uuid identifier',
14
- ' produces ProjectRegistered // omitted destination',
15
- ' name = name',
16
- ' produces ProjectUpdated',
17
- ' for projectId // explicit destination',
18
- ' produces when true == true',
19
- ' ProjectConditional',
20
- ' event ProjectRegistered',
21
- ' event ProjectUpdated',
22
- ' event ProjectConditional',
23
- ];
24
-
25
- const destinations = (lines: string[]) => validateLines(lines).filter(issue => issue.code === diagnosticCodes.omittedProductionDestination);
26
-
27
- describe('when validating production destinations with an available identifier', () => {
28
- let issues: ValidationIssue[];
29
-
30
- beforeEach(() => {
31
- issues = destinations(source);
32
- });
33
-
34
- it('should advise only on the plain omitted destination', () => {
35
- issues.map(issue => issue.line).should.deep.equal([5]);
36
- });
37
-
38
- it('should keep the advice informational', () => {
39
- issues[0].severity.should.equal('information');
40
- issues[0].message.should.contain('for projectId');
41
- });
42
-
43
- it('should not advise without an identifier', () => {
44
- destinations(source.map(line => line.replace(' identifier', ''))).should.have.lengthOf(0);
45
- });
46
-
47
- it.each(['Uuid?', 'Uuid[]', 'Uuid[]?'])('should not advise for a %s identifier', (type) => {
48
- destinations(source.map(line => line.replace('projectId Uuid identifier', `projectId ${type} identifier`))).should.have.lengthOf(0);
49
- });
50
-
51
- it.each([
52
- ['command Register // explanation', 'projectId Uuid identifier'],
53
- ['command Register', 'projectId Uuid identifier // explanation'],
54
- ['command Register // explanation', 'projectId Uuid identifier // explanation'],
55
- ])('should discover identifiers despite trailing comments: %s; %s', (command, property) => {
56
- destinations(source.map(line => line.replace('command Register', command).replace('projectId Uuid identifier', property)))
57
- .map(issue => issue.line).should.deep.equal([5]);
58
- });
59
-
60
- it.each(['// outside', ' // beside the command', ' // beside the production'])(
61
- 'should skip comment-only ancestry lines: %s', (comment) => {
62
- destinations([...source.slice(0, 5), comment, ...source.slice(5)])
63
- .map(issue => issue.line).should.deep.equal([6]);
64
- });
65
-
66
- it.each(['description', 'handler', 'concurrency', 'validate', 'template', 'profile', 'when', 'identifier', 'sourceType', 'streamType'])(
67
- 'should follow command property rules for %s', (name) => {
68
- const issues = destinations(source.map(line => line.replaceAll('projectId', name)));
69
- issues.map(issue => issue.line).should.deep.equal([5]);
70
- issues[0].message.should.contain(`for ${name}`);
71
- });
72
-
73
- it('should not treat a nested concurrency dimension as a command identifier', () => {
74
- destinations([
75
- ...source.slice(0, 4),
76
- ' concurrency',
77
- ' sourceType Uuid identifier',
78
- ' produces ProjectRegistered',
79
- ' event ProjectRegistered',
80
- ]).should.have.lengthOf(0);
81
- });
82
-
83
- it('should not discover an identifier inside a fence', () => {
84
- destinations([
85
- ...source.slice(0, 4),
86
- ' produces ProjectRegistered',
87
- ' validate',
88
- ' ```csharp',
89
- ' ghostId Uuid identifier',
90
- ' ```',
91
- ' event ProjectRegistered',
92
- ]).should.have.lengthOf(0);
93
- });
94
-
95
- it('should not count fenced identifiers beside a real identifier', () => {
96
- destinations([
97
- ...source.slice(0, 5),
98
- ' produces ProjectRegistered',
99
- ' validate',
100
- ' ```csharp',
101
- ' ghostId Uuid identifier',
102
- ' ```',
103
- ' event ProjectRegistered',
104
- ]).map(issue => issue.line).should.deep.equal([5]);
105
- });
106
-
107
- it('should not advise on reaction productions', () => {
108
- destinations(source.map(line => line.replace('command Register', 'reaction Register'))).should.have.lengthOf(0);
109
- });
110
-
111
- it('should ignore fenced code that looks like a production', () => {
112
- destinations([
113
- ...source.slice(0, 5),
114
- ' handler',
115
- ' ```csharp',
116
- ' produces NotScreenplay',
117
- ' ```',
118
- ]).should.have.lengthOf(0);
119
- });
120
- });
package/hover-content.ts DELETED
@@ -1,117 +0,0 @@
1
- // Copyright (c) Cratis. All rights reserved.
2
- // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
-
4
- import { enclosingChain, fenceMap, indentOf } from './document-context';
5
- import { directBody, scanDocument } from './symbols';
6
- import { eventAnalysisSource } from './event-analysis-source';
7
- import { getSubLanguage } from './sub-language-registry';
8
- import { attributeDocs, contextVariableDocs, keywordDocs, specificationKeywordDocs } from './keyword-docs';
9
-
10
- // Produces the hover markdown for a word at a position, without any editor
11
- // dependency — the Monaco service and the VSCode extension share this content.
12
- // Columns are 1-based, matching both editors' word-at-position APIs.
13
- export function hoverContent(
14
- lines: string[],
15
- lineIndex: number,
16
- word: string,
17
- startColumn: number,
18
- endColumn: number,
19
- ): string | null {
20
- const fences = fenceMap(lines);
21
- if (fences[lineIndex]) return null;
22
-
23
- const line = lines[lineIndex] ?? '';
24
- const before = line.charAt(startColumn - 2);
25
-
26
- if (before === '@') {
27
- const doc = attributeDocs[word];
28
- if (doc) return doc;
29
- }
30
- if (before === '$' || before === '.') {
31
- const variable = line.substring(0, endColumn - 1).match(/\$[\w.]*$/)?.[0];
32
- if (variable) {
33
- const doc =
34
- contextVariableDocs[variable] ??
35
- (variable.startsWith('$env') ? contextVariableDocs['$env'] : undefined);
36
- if (doc) return doc;
37
- }
38
- }
39
-
40
- const symbols = scanDocument(lines);
41
-
42
- const concept = symbols.concepts.find((candidate) => candidate.name === word);
43
- if (concept) {
44
- const attributes = concept.attributes.length ? ` ${concept.attributes.join(' ')}` : '';
45
- const values = concept.enumValues.length
46
- ? `\n\nValues: ${concept.enumValues.join(', ')}`
47
- : '';
48
- const reasons = Object.entries(concept.attributeReasons)
49
- .map(([attribute, reason]) => `\n\n**@${attribute}** — ${reason}`)
50
- .join('');
51
- return `\`\`\`screenplay\nconcept ${concept.name} : ${concept.primitive}${attributes}\n\`\`\`${reasons}${values}`;
52
- }
53
-
54
- const type = symbols.types.find((candidate) => candidate.name === word);
55
- if (type) {
56
- const properties = type.properties
57
- .map((property) => `${property.name} ${property.type}`)
58
- .join('\n');
59
- return `\`\`\`screenplay\ntype ${type.name}\n${properties}\n\`\`\``;
60
- }
61
-
62
- const policy = symbols.policies.find((candidate) => candidate.name === word);
63
- if (policy) {
64
- const body = policy.requires.length ? policy.requires.join('\n') : '(custom C#)';
65
- return `\`\`\`screenplay\npolicy ${policy.name}\n${body}\n\`\`\``;
66
- }
67
-
68
- const event = symbols.events.find((candidate) => candidate.name === word && candidate.line === lineIndex) ??
69
- symbols.events.filter((candidate) => candidate.name === word)
70
- .sort((left, right) => (right.generation ?? 1) - (left.generation ?? 1))[0];
71
- if (event) {
72
- const properties = event.properties
73
- .map((property) => `${property.name} ${property.type}`)
74
- .join('\n');
75
- return `\`\`\`screenplay\nevent ${event.name}${event.generation !== undefined ? ` generation ${event.generation}` : ''}\n${properties}\n\`\`\``;
76
- }
77
-
78
- const command = symbols.commands.find((candidate) => candidate.name === word);
79
- if (command && command.properties.length > 0) {
80
- const properties = command.properties
81
- .map(
82
- (property) =>
83
- `${property.name} ${property.type}${property.isIdentifier ? ' identifier' : ''}`,
84
- )
85
- .join('\n');
86
- return `\`\`\`screenplay\ncommand ${command.name}\n${properties}\n\`\`\``;
87
- }
88
-
89
- // Sub-language keywords take precedence inside their construct.
90
- const chain = enclosingChain(lines, fences, lineIndex, indentOf(line));
91
- for (const construct of [line.trim().split(/\s+/)[0], ...chain]) {
92
- const subLanguage = getSubLanguage(construct ?? '');
93
- const doc = subLanguage?.hovers?.[word];
94
- if (doc) return doc;
95
- }
96
-
97
- if (word === 'reads' && (chain[0] === 'every' || chain[0] === 'at') && chain.includes('reaction')) {
98
- return '**reads** — Declares a whole view this clock trigger consults: `reads <View>`. Clock triggers take no values, so `by` is unavailable.';
99
- }
100
-
101
- const step = line.trim().match(/^(given|when|then)\s+(?:no\s+)?(\w+)/);
102
- if (step && step[2] === word && chain[0] === 'specification' && specificationKeywordDocs[word]) {
103
- return `**${word}** — ${specificationKeywordDocs[word]}`;
104
- }
105
-
106
- if (word === 'id' || word === 'documentation') {
107
- const source = eventAnalysisSource(lines);
108
- const inEvent = symbols.events.some(event => directBody(source, fences, event.line, indentOf(source[event.line])).includes(lineIndex));
109
- const directive = word === 'id' ? /^\s*id\s+"/.test(source[lineIndex]) : /^\s*documentation\s*$/.test(source[lineIndex]);
110
- if (!inEvent || !directive || startColumn !== indentOf(line) + 1) return null;
111
- }
112
-
113
- const keywordDoc = keywordDocs[word];
114
- if (keywordDoc) return `**${word}** — ${keywordDoc}`;
115
-
116
- return null;
117
- }
package/hover.ts DELETED
@@ -1,23 +0,0 @@
1
- // Copyright (c) Cratis. All rights reserved.
2
- // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
-
4
- import type { languages } from 'monaco-editor';
5
- import { hoverContent } from './hover-content';
6
-
7
- export function createHoverProvider(): languages.HoverProvider {
8
- return {
9
- provideHover(model, position) {
10
- const word = model.getWordAtPosition(position);
11
- if (!word) return null;
12
-
13
- const content = hoverContent(
14
- model.getLinesContent(),
15
- position.lineNumber - 1,
16
- word.word,
17
- word.startColumn,
18
- word.endColumn,
19
- );
20
- return content ? { contents: [{ value: content }] } : null;
21
- },
22
- };
23
- }
package/index.ts DELETED
@@ -1,125 +0,0 @@
1
- // Copyright (c) Cratis. All rights reserved.
2
- // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
-
4
- import {
5
- Monaco,
6
- languageConfiguration,
7
- languageExtensionPoint,
8
- languageId,
9
- } from './language';
10
- import { createTokensProvider } from './tokens';
11
- import { CompletionOptions, createCompletionProvider } from './completions';
12
- import { createHoverProvider } from './hover';
13
- import { createInlayHintsProvider } from './inlay-hints';
14
- import { attachDiagnostics } from './diagnostics';
15
- import {
16
- getSubLanguage,
17
- getSubLanguages,
18
- onSubLanguagesChanged,
19
- registerSubLanguage,
20
- } from './sub-language-registry';
21
- import { pdl } from './sub-languages/pdl';
22
- import { cdl } from './sub-languages/cdl';
23
- import { screenplayDark, screenplayDarkThemeName } from './themes/screenplay-dark';
24
- import { screenplayLight, screenplayLightThemeName } from './themes/screenplay-light';
25
-
26
- const registeredInstances = new Set<Monaco>();
27
-
28
- function applyTokensProvider(monaco: Monaco): void {
29
- monaco.languages.setMonarchTokensProvider(languageId, createTokensProvider(getSubLanguages()));
30
- }
31
-
32
- // Sub-languages registered after register() recompose the tokenizer on the fly.
33
- onSubLanguagesChanged(() => registeredInstances.forEach(applyTokensProvider));
34
-
35
- // Registers the built-in PDL and CDL sub-languages. Hosts that do not go through
36
- // register() — such as the VSCode extension — call this before using the registry.
37
- export function ensureBuiltInSubLanguages(): void {
38
- if (!getSubLanguage('projection')) registerSubLanguage('projection', pdl);
39
- if (!getSubLanguage('capture')) registerSubLanguage('capture', cdl);
40
- }
41
-
42
- // What a host can tell the language service beyond the models it holds.
43
- export type LanguageServiceOptions = CompletionOptions;
44
-
45
- export function register(monaco: Monaco, options: LanguageServiceOptions = {}): void {
46
- if (registeredInstances.has(monaco)) return;
47
-
48
- ensureBuiltInSubLanguages();
49
-
50
- registeredInstances.add(monaco);
51
-
52
- monaco.languages.register(languageExtensionPoint);
53
- monaco.languages.setLanguageConfiguration(languageId, languageConfiguration);
54
- applyTokensProvider(monaco);
55
- monaco.languages.registerCompletionItemProvider(languageId, createCompletionProvider(monaco, options));
56
- monaco.languages.registerHoverProvider(languageId, createHoverProvider());
57
- monaco.languages.registerInlayHintsProvider(languageId, createInlayHintsProvider());
58
- monaco.editor.defineTheme(screenplayDarkThemeName, screenplayDark);
59
- monaco.editor.defineTheme(screenplayLightThemeName, screenplayLight);
60
- attachDiagnostics(monaco);
61
- }
62
-
63
- export {
64
- causedByProperties,
65
- clauseKeywords,
66
- codeBlockTags,
67
- conceptAttributes,
68
- constructKeywords,
69
- contextRoots,
70
- languageId,
71
- primitiveTypes,
72
- sliceTypes,
73
- } from './language';
74
- export type { Monaco } from './language';
75
- export { getSubLanguage, getSubLanguages, registerSubLanguage } from './sub-language-registry';
76
- export type {
77
- MonarchTokenRules,
78
- SubLanguage,
79
- SubLanguageCompletion,
80
- SubLanguageDefinition,
81
- } from './sub-language-registry';
82
- export { pdl } from './sub-languages/pdl';
83
- export { cdl } from './sub-languages/cdl';
84
- export { screenplayDarkThemeName } from './themes/screenplay-dark';
85
- export { screenplayLightThemeName } from './themes/screenplay-light';
86
- export { enclosingChain, fenceMap, firstWord, indentOf } from './document-context';
87
- export {
88
- fileReferenceKeyword,
89
- fileReferenceOn,
90
- fileReferences,
91
- isAbsoluteFileReferencePath,
92
- } from './file-references';
93
- export type { FileReference } from './file-references';
94
- export { fileImportOn, fileImports, importablePaths, isFileImportLine } from './file-imports';
95
- export type { FileImport } from './file-imports';
96
- export type { CompletionOptions } from './completions';
97
- export { builtInTriggerNames, knownEventNames, knownTriggerNames, knownTypeNames, mergeSymbols, scanDocument } from './symbols';
98
- export type {
99
- CommandSymbol,
100
- ConceptSymbol,
101
- DocumentSymbols,
102
- EventSymbol,
103
- ImportSymbol,
104
- NamedSymbol,
105
- PolicySymbol,
106
- PropertySymbol,
107
- ReadSymbol,
108
- QuerySymbol,
109
- TypeSymbol,
110
- } from './symbols';
111
- export { attributeDocs, contextVariableDocs, keywordDocs, specificationKeywordDocs } from './keyword-docs';
112
- export { eventContextMemberAt, eventContextMembers, eventContextMembersAfter, eventContextPaths, namesEventContextMember } from './event-context';
113
- export type { EventContextMember, EventContextPath } from './event-context';
114
- export { contextVariableItems, producesItems, specificationStepItems } from './completion-items';
115
- export type { CompletionEntry } from './completion-items';
116
- export { completionEntriesFor, planCompletions } from './completion-planner';
117
- export type { CompletionPlan } from './completion-planner';
118
- export { hoverContent } from './hover-content';
119
- export { validateLines } from './validation';
120
- export { destinationHints, productionDestinations } from './production-destinations';
121
- export type { DestinationHint } from './DestinationHint';
122
- export type { ProductionSymbol } from './ProductionSymbol';
123
- export type { ValidationContext, ValidationIssue, ValidationSeverity } from './validation';
124
- export { diagnosticCodes } from './diagnostic-codes';
125
- export type { DiagnosticCode } from './diagnostic-codes';
package/inlay-hints.ts DELETED
@@ -1,17 +0,0 @@
1
- // Copyright (c) Cratis. All rights reserved.
2
- // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
-
4
- import type { languages } from 'monaco-editor';
5
- import { destinationHints } from './production-destinations';
6
-
7
- export function createInlayHintsProvider(): languages.InlayHintsProvider {
8
- return {
9
- provideInlayHints(model, range) {
10
- const hints = destinationHints(model.getLinesContent()).filter(hint => hint.line + 1 >= range.startLineNumber && hint.line + 1 <= range.endLineNumber);
11
- return {
12
- hints: hints.map(hint => ({ position: { lineNumber: hint.line + 1, column: hint.column }, label: hint.label, paddingLeft: true })),
13
- dispose() {},
14
- };
15
- },
16
- };
17
- }