@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.
- package/README.md +15 -0
- package/dist/TypeReferenceSymbol.d.ts +8 -0
- package/dist/TypeReferenceSymbol.d.ts.map +1 -0
- package/dist/bundles/chunk-GJX4NJYC.js +4836 -0
- package/dist/bundles/chunk-GJX4NJYC.js.map +7 -0
- package/dist/bundles/index.js +1417 -0
- package/dist/bundles/index.js.map +7 -0
- package/dist/bundles/sub-languages/capture/index.js +677 -0
- package/dist/bundles/sub-languages/capture/index.js.map +7 -0
- package/dist/bundles/sub-languages/projection/index.js +1647 -0
- package/dist/bundles/sub-languages/projection/index.js.map +7 -0
- package/dist/code-actions.d.ts +3 -0
- package/dist/code-actions.d.ts.map +1 -0
- package/dist/completion-items.d.ts +1 -0
- package/dist/completion-items.d.ts.map +1 -1
- package/dist/completion-planner.d.ts.map +1 -1
- package/dist/completions.d.ts.map +1 -1
- package/dist/diagnostic-codes.d.ts +3 -0
- package/dist/diagnostic-codes.d.ts.map +1 -1
- package/dist/diagnostics.d.ts.map +1 -1
- package/dist/hover-content.d.ts.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/keyword-docs.d.ts.map +1 -1
- package/dist/language.d.ts +1 -0
- package/dist/language.d.ts.map +1 -1
- package/dist/production-destinations.d.ts.map +1 -1
- package/dist/symbols.d.ts +4 -0
- package/dist/symbols.d.ts.map +1 -1
- package/dist/tokens.d.ts.map +1 -1
- package/dist/validation.d.ts +1 -0
- package/dist/validation.d.ts.map +1 -1
- package/package.json +13 -9
- package/DestinationHint.ts +0 -8
- package/ProductionSymbol.ts +0 -11
- package/completion-items.ts +0 -261
- package/completion-planner.ts +0 -167
- package/completions.ts +0 -156
- package/diagnostic-codes.ts +0 -43
- package/diagnostics.ts +0 -55
- package/dist/DestinationHint.js +0 -4
- package/dist/DestinationHint.js.map +0 -1
- package/dist/ProductionSymbol.js +0 -4
- package/dist/ProductionSymbol.js.map +0 -1
- package/dist/completion-items.js +0 -228
- package/dist/completion-items.js.map +0 -1
- package/dist/completion-planner.js +0 -143
- package/dist/completion-planner.js.map +0 -1
- package/dist/completions.js +0 -101
- package/dist/completions.js.map +0 -1
- package/dist/diagnostic-codes.js +0 -41
- package/dist/diagnostic-codes.js.map +0 -1
- package/dist/diagnostics.js +0 -50
- package/dist/diagnostics.js.map +0 -1
- package/dist/document-context.js +0 -85
- package/dist/document-context.js.map +0 -1
- package/dist/event-analysis-source.js +0 -19
- package/dist/event-analysis-source.js.map +0 -1
- package/dist/event-context-catalog.js +0 -116
- package/dist/event-context-catalog.js.map +0 -1
- package/dist/event-context.js +0 -88
- package/dist/event-context.js.map +0 -1
- package/dist/file-imports.js +0 -58
- package/dist/file-imports.js.map +0 -1
- package/dist/file-references.js +0 -70
- package/dist/file-references.js.map +0 -1
- package/dist/hover-content.js +0 -98
- package/dist/hover-content.js.map +0 -1
- package/dist/hover.js +0 -15
- package/dist/hover.js.map +0 -1
- package/dist/index.js +0 -61
- package/dist/index.js.map +0 -1
- package/dist/inlay-hints.js +0 -15
- package/dist/inlay-hints.js.map +0 -1
- package/dist/inline-event-validation.js +0 -131
- package/dist/inline-event-validation.js.map +0 -1
- package/dist/keyword-docs.js +0 -148
- package/dist/keyword-docs.js.map +0 -1
- package/dist/language.js +0 -196
- package/dist/language.js.map +0 -1
- package/dist/production-destinations.js +0 -32
- package/dist/production-destinations.js.map +0 -1
- package/dist/sub-language-registry.js +0 -18
- package/dist/sub-language-registry.js.map +0 -1
- package/dist/sub-languages/capture/CompletionProvider.js +0 -332
- package/dist/sub-languages/capture/CompletionProvider.js.map +0 -1
- package/dist/sub-languages/capture/HoverProvider.js +0 -87
- package/dist/sub-languages/capture/HoverProvider.js.map +0 -1
- package/dist/sub-languages/capture/Validator.js +0 -72
- package/dist/sub-languages/capture/Validator.js.map +0 -1
- package/dist/sub-languages/capture/index.js +0 -58
- package/dist/sub-languages/capture/index.js.map +0 -1
- package/dist/sub-languages/capture/language.js +0 -160
- package/dist/sub-languages/capture/language.js.map +0 -1
- package/dist/sub-languages/cdl.js +0 -74
- package/dist/sub-languages/cdl.js.map +0 -1
- package/dist/sub-languages/pdl.js +0 -73
- package/dist/sub-languages/pdl.js.map +0 -1
- package/dist/sub-languages/projection/CodeActionProvider.js +0 -93
- package/dist/sub-languages/projection/CodeActionProvider.js.map +0 -1
- package/dist/sub-languages/projection/CompletionProvider.js +0 -595
- package/dist/sub-languages/projection/CompletionProvider.js.map +0 -1
- package/dist/sub-languages/projection/HoverProvider.js +0 -333
- package/dist/sub-languages/projection/HoverProvider.js.map +0 -1
- package/dist/sub-languages/projection/Validator.js +0 -388
- package/dist/sub-languages/projection/Validator.js.map +0 -1
- package/dist/sub-languages/projection/index.js +0 -160
- package/dist/sub-languages/projection/index.js.map +0 -1
- package/dist/sub-languages/projection/language.js +0 -171
- package/dist/sub-languages/projection/language.js.map +0 -1
- package/dist/symbols.js +0 -275
- package/dist/symbols.js.map +0 -1
- package/dist/themes/screenplay-dark.js +0 -30
- package/dist/themes/screenplay-dark.js.map +0 -1
- package/dist/themes/screenplay-light.js +0 -30
- package/dist/themes/screenplay-light.js.map +0 -1
- package/dist/tokens.js +0 -147
- package/dist/tokens.js.map +0 -1
- package/dist/validation.js +0 -248
- package/dist/validation.js.map +0 -1
- package/document-context.ts +0 -93
- package/event-analysis-source.ts +0 -18
- package/event-context-catalog.ts +0 -135
- package/event-context.ts +0 -119
- package/file-imports.ts +0 -70
- package/file-references.ts +0 -87
- package/for_documentContext/when_stripping_comments.ts +0 -32
- package/for_eventContext/when_resolving_generated_catalog_vectors.ts +0 -15
- package/for_eventGenerations/when_editing_event_generations.ts +0 -57
- package/for_fileImports/when_finding_file_imports.ts +0 -38
- package/for_fileReferences/when_recognizing_an_absolute_path/with_paths_of_every_shape.ts +0 -26
- package/for_fileReferences/when_scanning_a_document/inside_a_code_fence.ts +0 -26
- package/for_fileReferences/when_scanning_a_document/with_a_bare_file_keyword.ts +0 -19
- package/for_fileReferences/when_scanning_a_document/with_a_file_directive.ts +0 -30
- package/for_fileReferences/when_scanning_a_document/with_a_property_named_file.ts +0 -25
- package/for_fileReferences/when_scanning_a_document/with_a_trailing_comment.ts +0 -25
- package/for_fileReferences/when_scanning_a_document/with_directives_on_several_constructs.ts +0 -41
- package/for_importablePaths/when_listing_what_a_document_can_import.ts +0 -34
- package/for_inlineEvents/when_analyzing_many_inline_events.ts +0 -59
- package/for_inlineEvents/when_authoring_inline_events.ts +0 -149
- package/for_inlineEvents/when_completing_many_events.ts +0 -49
- package/for_inlineEvents/when_indexing_command_production_ownership.ts +0 -79
- package/for_planCompletions/when_completing_a_file_import.ts +0 -26
- package/for_planCompletions/when_completing_a_specification_query.ts +0 -24
- package/for_planCompletions/when_completing_a_specification_step.ts +0 -42
- package/for_planCompletions/when_completing_an_absent_read_model.ts +0 -14
- package/for_planCompletions/when_completing_reaction_reads.ts +0 -36
- package/for_projectionCompletionProvider/when_completing_an_event_context_path.ts +0 -102
- package/for_projectionHoverProvider/when_hovering_an_event_context_path.ts +0 -44
- package/for_projectionValidator/when_validating_a_projection_with_variants.ts +0 -128
- package/for_projectionValidator/when_validating_event_context_paths.ts +0 -31
- package/for_scanDocument/when_scanning_a_query/with_a_dotted_return_type.ts +0 -34
- package/for_scanDocument/when_scanning_aliased_reads.ts +0 -33
- package/for_scanDocument/when_scanning_many_commands.ts +0 -47
- package/for_tokens/when_highlighting_a_file_import.ts +0 -18
- package/for_tokens/when_highlighting_event_metadata.ts +0 -63
- package/for_tokens/when_highlighting_specification_steps.ts +0 -28
- package/for_validateLines/when_validating_a_document/with_a_problem_of_every_coded_kind.ts +0 -77
- package/for_validateLines/when_validating_a_document/with_an_unknown_policy.ts +0 -33
- package/for_validateLines/when_validating_a_file_placed_by_an_import/with_names_declared_in_other_files.ts +0 -43
- package/for_validateLines/when_validating_event_context_paths/in_a_projection.ts +0 -97
- package/for_validateLines/when_validating_file_imports/at_every_level.ts +0 -36
- package/for_validateLines/when_validating_production_destinations/with_an_available_identifier.ts +0 -120
- package/hover-content.ts +0 -117
- package/hover.ts +0 -23
- package/index.ts +0 -125
- package/inlay-hints.ts +0 -17
- package/inline-event-validation.ts +0 -115
- package/keyword-docs.ts +0 -152
- package/language.ts +0 -212
- package/production-destinations.ts +0 -32
- package/sub-language-registry.ts +0 -42
- package/sub-languages/capture/CompletionProvider.ts +0 -365
- package/sub-languages/capture/HoverProvider.ts +0 -99
- package/sub-languages/capture/Validator.ts +0 -97
- package/sub-languages/capture/index.ts +0 -72
- package/sub-languages/capture/language.ts +0 -176
- package/sub-languages/cdl.ts +0 -76
- package/sub-languages/pdl.ts +0 -75
- package/sub-languages/projection/CodeActionProvider.ts +0 -123
- package/sub-languages/projection/CompletionProvider.ts +0 -660
- package/sub-languages/projection/HoverProvider.ts +0 -377
- package/sub-languages/projection/Validator.ts +0 -441
- package/sub-languages/projection/index.ts +0 -223
- package/sub-languages/projection/language.ts +0 -193
- package/symbols.ts +0 -374
- package/themes/screenplay-dark.ts +0 -33
- package/themes/screenplay-light.ts +0 -33
- package/tokens.ts +0 -174
- package/validation.ts +0 -443
- package/vitest.setup.ts +0 -5
|
@@ -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, it } from 'vitest';
|
|
5
|
-
import { completionEntriesFor, planCompletions } from '../completion-planner';
|
|
6
|
-
import { hoverContent } from '../hover-content';
|
|
7
|
-
import { clauseKeywords } from '../language';
|
|
8
|
-
|
|
9
|
-
// Monaco's tokenizer uses clauseKeywords for directives at every indentation depth.
|
|
10
|
-
describe('when editing reaction trigger reads', () => {
|
|
11
|
-
it('highlights reads as a clause keyword under a trigger', () => {
|
|
12
|
-
clauseKeywords.includes('reads').should.be.true;
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it('offers a reads clause under a reaction trigger', () => {
|
|
16
|
-
// Context chains are innermost first: ['when', 'reaction'], not ['reaction', 'when'].
|
|
17
|
-
completionEntriesFor(['when', 'reaction']).some(entry => entry.label === 'reads').should.be.true;
|
|
18
|
-
const plan = planCompletions(['reaction Handle', ' when Placed', ' '], 2, ' ');
|
|
19
|
-
(plan.kind === 'entries' && plan.entries.some(entry => entry.label === 'reads')).should.be.true;
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
for (const source of ['every 15 minutes', 'at 08:00']) {
|
|
23
|
-
it(`offers a whole-view read with no by clause under ${source}`, () => {
|
|
24
|
-
const plan = planCompletions(['reaction Handle', ` ${source}`, ' '], 2, ' ');
|
|
25
|
-
(plan.kind === 'entries' && plan.entries.some(entry => entry.label === 'reads' &&
|
|
26
|
-
entry.insertText === 'reads ${1:View}')).should.be.true;
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it(`shows no by syntax in reads hover under ${source}`, () => {
|
|
30
|
-
const lines = ['reaction Handle', ` ${source}`, ' reads Status'];
|
|
31
|
-
const content = hoverContent(lines, 2, 'reads', 5, 10);
|
|
32
|
-
content!.should.contain('reads <View>');
|
|
33
|
-
content!.should.not.contain('by <');
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
});
|
|
@@ -1,102 +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 type { editor, languages, Position } from 'monaco-editor';
|
|
6
|
-
import { CompletionProvider } from '../sub-languages/projection/CompletionProvider';
|
|
7
|
-
import { eventContextMembers } from '../event-context';
|
|
8
|
-
|
|
9
|
-
function complete(line: string): string[] {
|
|
10
|
-
const lines = ['projection Statistics => StatisticsReadModel', ' all', line];
|
|
11
|
-
const model = {
|
|
12
|
-
getLineContent: (lineNumber: number) => lines[lineNumber - 1],
|
|
13
|
-
getWordAtPosition: () => null,
|
|
14
|
-
} as unknown as editor.ITextModel;
|
|
15
|
-
const position = { lineNumber: 3, column: line.length + 1 } as Position;
|
|
16
|
-
const result = new CompletionProvider().provideCompletionItems(model, position) as languages.CompletionList;
|
|
17
|
-
return result.suggestions.map((suggestion) => suggestion.label as string);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
describe('when completing the first segment of an event context path', () => {
|
|
21
|
-
let labels: string[];
|
|
22
|
-
|
|
23
|
-
beforeEach(() => {
|
|
24
|
-
labels = complete(' lastSeen = $eventContext.');
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('should offer every member of the catalog', () => {
|
|
28
|
-
labels.should.have.members(eventContextMembers.map((member) => member.name));
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('should offer the event store', () => {
|
|
32
|
-
labels.should.include('eventStore');
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('should offer the namespace', () => {
|
|
36
|
-
labels.should.include('namespace');
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('should not offer a causation identifier', () => {
|
|
40
|
-
labels.should.not.include('causationId');
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
describe('when completing below a composite member of an event context path', () => {
|
|
45
|
-
let labels: string[];
|
|
46
|
-
|
|
47
|
-
beforeEach(() => {
|
|
48
|
-
labels = complete(' by = $eventContext.causedBy.');
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('should offer the members of the identity', () => {
|
|
52
|
-
labels.should.have.members(['subject', 'name', 'userName', 'onBehalfOf']);
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
describe('when completing a dynamic dictionary key', () => {
|
|
57
|
-
let labels: string[];
|
|
58
|
-
|
|
59
|
-
beforeEach(() => {
|
|
60
|
-
labels = complete(' count eventCountByType.$eventContext.eventType.');
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('should offer the members of the event type', () => {
|
|
64
|
-
labels.should.have.members(['id', 'generation', 'tombstone']);
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
describe('when completing below a collection of the event context', () => {
|
|
69
|
-
let labels: string[];
|
|
70
|
-
|
|
71
|
-
beforeEach(() => {
|
|
72
|
-
labels = complete(' x = $eventContext.causation.');
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it('should offer nothing', () => {
|
|
76
|
-
labels.should.be.empty;
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
describe('when completing the week of when the event occurred', () => {
|
|
81
|
-
let labels: string[];
|
|
82
|
-
|
|
83
|
-
beforeEach(() => {
|
|
84
|
-
labels = complete(' week = $eventContext.occurred.');
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it('should offer the derived week', () => {
|
|
88
|
-
labels.should.have.members(['Week']);
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
describe('when completing below the caused by short form', () => {
|
|
93
|
-
let labels: string[];
|
|
94
|
-
|
|
95
|
-
beforeEach(() => {
|
|
96
|
-
labels = complete(' by = $causedBy.onBehalfOf.');
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
it('should offer the members of the identity it acted for', () => {
|
|
100
|
-
labels.should.have.members(['subject', 'name', 'userName', 'onBehalfOf']);
|
|
101
|
-
});
|
|
102
|
-
});
|
|
@@ -1,44 +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 type { editor, languages, Position } from 'monaco-editor';
|
|
6
|
-
import { HoverProvider } from '../sub-languages/projection/HoverProvider';
|
|
7
|
-
import { eventContextMembers } from '../event-context';
|
|
8
|
-
|
|
9
|
-
const line = ' type = $eventContext.eventType.id';
|
|
10
|
-
|
|
11
|
-
function hover(word: string): string {
|
|
12
|
-
const startColumn = line.lastIndexOf(word) + 1;
|
|
13
|
-
const lines = ['projection Statistics => StatisticsReadModel', ' all', line];
|
|
14
|
-
const model = {
|
|
15
|
-
getLineContent: (lineNumber: number) => lines[lineNumber - 1],
|
|
16
|
-
getWordAtPosition: () => ({ word, startColumn, endColumn: startColumn + word.length }),
|
|
17
|
-
} as unknown as editor.ITextModel;
|
|
18
|
-
const result = new HoverProvider().provideHover(model, { lineNumber: 3, column: startColumn } as Position) as languages.Hover;
|
|
19
|
-
return (result.contents[0] as { value: string }).value;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
describe('when hovering the event context', () => {
|
|
23
|
-
let content: string;
|
|
24
|
-
|
|
25
|
-
beforeEach(() => {
|
|
26
|
-
content = hover('$eventContext');
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('should list every member of the catalog', () => {
|
|
30
|
-
eventContextMembers.every((member) => content.includes(`\`${member.name}\``)).should.be.true;
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
describe('when hovering a member of an event context path that is also a keyword', () => {
|
|
35
|
-
let content: string;
|
|
36
|
-
|
|
37
|
-
beforeEach(() => {
|
|
38
|
-
content = hover('id');
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('should describe the member rather than the keyword', () => {
|
|
42
|
-
content.should.include('$eventContext.eventType.id');
|
|
43
|
-
});
|
|
44
|
-
});
|
|
@@ -1,128 +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 type { editor } from 'monaco-editor';
|
|
6
|
-
import { Validator } from '../sub-languages/projection/Validator';
|
|
7
|
-
import type { JsonSchema, ReadModelInfo } from '../sub-languages/projection/index';
|
|
8
|
-
|
|
9
|
-
function modelFor(content: string): editor.ITextModel {
|
|
10
|
-
return { getValue: () => content } as unknown as editor.ITextModel;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const backlogItemSchema: JsonSchema = {
|
|
14
|
-
name: 'BacklogItem',
|
|
15
|
-
properties: { title: { type: 'string' } },
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const pullRequestItemSchema: JsonSchema = {
|
|
19
|
-
name: 'PullRequestItem',
|
|
20
|
-
properties: { pullRequestUrl: { type: 'string' } },
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
const readModels: ReadModelInfo[] = [
|
|
24
|
-
{ identifier: 'BacklogItem', displayName: 'BacklogItem', schema: backlogItemSchema },
|
|
25
|
-
{ identifier: 'PullRequestItem', displayName: 'PullRequestItem', schema: pullRequestItemSchema },
|
|
26
|
-
];
|
|
27
|
-
|
|
28
|
-
describe('when validating a projection with a variant naming a known read model', () => {
|
|
29
|
-
let validator: Validator;
|
|
30
|
-
let markers: editor.IMarkerData[];
|
|
31
|
-
|
|
32
|
-
beforeEach(() => {
|
|
33
|
-
validator = new Validator();
|
|
34
|
-
validator.setReadModels(readModels);
|
|
35
|
-
markers = validator.validate(modelFor([
|
|
36
|
-
'projection WorkItem',
|
|
37
|
-
' variant BacklogItem',
|
|
38
|
-
' title = title',
|
|
39
|
-
].join('\n')));
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('should not report the variant as an unknown read model', () => {
|
|
43
|
-
markers.some(marker => marker.message.includes('not found')).should.be.false;
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('should not warn about a property the variant actually has', () => {
|
|
47
|
-
markers.some(marker => marker.message.includes("Property 'title'")).should.be.false;
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
describe('when validating a projection with a variant naming an unknown read model', () => {
|
|
52
|
-
let validator: Validator;
|
|
53
|
-
let markers: editor.IMarkerData[];
|
|
54
|
-
|
|
55
|
-
beforeEach(() => {
|
|
56
|
-
validator = new Validator();
|
|
57
|
-
validator.setReadModels(readModels);
|
|
58
|
-
markers = validator.validate(modelFor([
|
|
59
|
-
'projection WorkItem',
|
|
60
|
-
' variant SomethingElse',
|
|
61
|
-
' enters on SomethingHappened',
|
|
62
|
-
].join('\n')));
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('should report the variant read model as not found', () => {
|
|
66
|
-
markers.some(marker => marker.message === "Read model 'SomethingElse' not found").should.be.true;
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
describe('when validating a variant that maps a property it does not have', () => {
|
|
71
|
-
let validator: Validator;
|
|
72
|
-
let markers: editor.IMarkerData[];
|
|
73
|
-
|
|
74
|
-
beforeEach(() => {
|
|
75
|
-
validator = new Validator();
|
|
76
|
-
validator.setReadModels(readModels);
|
|
77
|
-
markers = validator.validate(modelFor([
|
|
78
|
-
'projection WorkItem',
|
|
79
|
-
' variant BacklogItem',
|
|
80
|
-
' pullRequestUrl = url',
|
|
81
|
-
].join('\n')));
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it('should warn about the property missing from the variant', () => {
|
|
85
|
-
markers.some(marker => marker.message.includes("Property 'pullRequestUrl' not found")).should.be.true;
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
describe('when validating an enters on line', () => {
|
|
90
|
-
let validator: Validator;
|
|
91
|
-
let markers: editor.IMarkerData[];
|
|
92
|
-
|
|
93
|
-
beforeEach(() => {
|
|
94
|
-
validator = new Validator();
|
|
95
|
-
validator.setReadModels(readModels);
|
|
96
|
-
validator.setEventSchemas({ IssueCreated: { name: 'IssueCreated', properties: {} } });
|
|
97
|
-
markers = validator.validate(modelFor([
|
|
98
|
-
'projection WorkItem',
|
|
99
|
-
' variant BacklogItem',
|
|
100
|
-
' enters on SomethingUnknown',
|
|
101
|
-
].join('\n')));
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it('should report the unknown event type', () => {
|
|
105
|
-
markers.some(marker => marker.message === "Event type 'SomethingUnknown' not found").should.be.true;
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
describe('when two variants each declare their own property scope', () => {
|
|
110
|
-
let validator: Validator;
|
|
111
|
-
let markers: editor.IMarkerData[];
|
|
112
|
-
|
|
113
|
-
beforeEach(() => {
|
|
114
|
-
validator = new Validator();
|
|
115
|
-
validator.setReadModels(readModels);
|
|
116
|
-
markers = validator.validate(modelFor([
|
|
117
|
-
'projection WorkItem',
|
|
118
|
-
' variant BacklogItem',
|
|
119
|
-
' title = title',
|
|
120
|
-
' variant PullRequestItem',
|
|
121
|
-
' pullRequestUrl = url',
|
|
122
|
-
].join('\n')));
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it('should not cross-check a property against the wrong variant', () => {
|
|
126
|
-
markers.should.be.empty;
|
|
127
|
-
});
|
|
128
|
-
});
|
|
@@ -1,31 +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, it, expect } from 'vitest';
|
|
5
|
-
import type { editor } from 'monaco-editor';
|
|
6
|
-
import { Validator } from '../sub-languages/projection/Validator';
|
|
7
|
-
|
|
8
|
-
const modelFor = (content: string): editor.ITextModel => ({ getValue: () => content }) as editor.ITextModel;
|
|
9
|
-
|
|
10
|
-
describe('when validating event context paths in the standalone projection editor', () => {
|
|
11
|
-
const markers = new Validator().validate(modelFor([
|
|
12
|
-
'projection Orders',
|
|
13
|
-
' from OrderPlaced',
|
|
14
|
-
' bad = $eventContext.unknown',
|
|
15
|
-
' badPath = $eventContext.eventType.unknown',
|
|
16
|
-
' badCollection = $eventContext.tags.value',
|
|
17
|
-
' missing = $eventContext.',
|
|
18
|
-
' totals.$causedBy.subject = quantity',
|
|
19
|
-
' good = $eventContext.occurred.Week()',
|
|
20
|
-
].join('\n')));
|
|
21
|
-
|
|
22
|
-
it('reports each catalog diagnostic with its source line and severity', () => {
|
|
23
|
-
expect(markers.filter(marker => typeof marker.code === 'string').map(marker => [marker.code, marker.startLineNumber, marker.severity])).toEqual([
|
|
24
|
-
['PLAY0295', 3, 4],
|
|
25
|
-
['PLAY0296', 4, 4],
|
|
26
|
-
['PLAY0297', 5, 8],
|
|
27
|
-
['PLAY0298', 6, 8],
|
|
28
|
-
['PLAY0299', 7, 4],
|
|
29
|
-
]);
|
|
30
|
-
});
|
|
31
|
-
});
|
|
@@ -1,34 +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 { DocumentSymbols, scanDocument } from '../../symbols';
|
|
6
|
-
|
|
7
|
-
// The compiler takes a dotted return type - QueryParser's ([\w.]+(?:\[\])?\??) - so the editor has to
|
|
8
|
-
// as well. When it did not, the query never made it into the symbol table and every check and
|
|
9
|
-
// completion reading from it went silently missing.
|
|
10
|
-
describe('when scanning a query with a dotted return type', () => {
|
|
11
|
-
let symbols: DocumentSymbols;
|
|
12
|
-
|
|
13
|
-
beforeEach(() => {
|
|
14
|
-
symbols = scanDocument([
|
|
15
|
-
'module Invoicing',
|
|
16
|
-
' feature Invoices',
|
|
17
|
-
' slice StateView Overdue',
|
|
18
|
-
' query Overdue => Invoicing.OverdueReadModel[]',
|
|
19
|
-
' by invoiceId InvoiceId',
|
|
20
|
-
]);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('should register the query', () => {
|
|
24
|
-
symbols.queries.should.have.lengthOf(1);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('should carry the return type as written', () => {
|
|
28
|
-
symbols.queries[0].returnType.should.equal('Invoicing.OverdueReadModel[]');
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('should collect the parameters it declares', () => {
|
|
32
|
-
symbols.queries[0].parameters.should.have.lengthOf(1);
|
|
33
|
-
});
|
|
34
|
-
});
|
|
@@ -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 { DocumentSymbols, scanDocument } from '../symbols';
|
|
6
|
-
|
|
7
|
-
describe('when scanning aliased command reads', () => {
|
|
8
|
-
let symbols: DocumentSymbols;
|
|
9
|
-
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
symbols = scanDocument([
|
|
12
|
-
'module Banking',
|
|
13
|
-
' feature Transfers',
|
|
14
|
-
' slice StateChange Transfer',
|
|
15
|
-
' command Transfer',
|
|
16
|
-
' sourceId Uuid',
|
|
17
|
-
' destinationId Uuid',
|
|
18
|
-
' reads Account as source by sourceId',
|
|
19
|
-
' reads Account as destination by destinationId',
|
|
20
|
-
]);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('should preserve both read instances and their aliases', () => {
|
|
24
|
-
symbols.commands[0].reads!.should.deep.equal([
|
|
25
|
-
{ view: 'Account', alias: 'source', by: 'sourceId', line: 6 },
|
|
26
|
-
{ view: 'Account', alias: 'destination', by: 'destinationId', line: 7 },
|
|
27
|
-
]);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('should not treat reads lines as properties', () => {
|
|
31
|
-
symbols.commands[0].properties.map((property) => property.name).should.deep.equal(['sourceId', 'destinationId']);
|
|
32
|
-
});
|
|
33
|
-
});
|
|
@@ -1,47 +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, it, vi } from 'vitest';
|
|
5
|
-
import * as context from '../document-context';
|
|
6
|
-
import { scanDocument } from '../symbols';
|
|
7
|
-
import { validateLines } from '../validation';
|
|
8
|
-
|
|
9
|
-
function commands(count: number): string[] {
|
|
10
|
-
return ['module Projects', ' feature Registration', ...Array.from({ length: count }, (_, index) => [
|
|
11
|
-
` slice StateChange Register${index}`,
|
|
12
|
-
` command Register${index} // command`,
|
|
13
|
-
' description Uuid identifier // keyword-named property',
|
|
14
|
-
' details String',
|
|
15
|
-
' produces Registered',
|
|
16
|
-
' nested Uuid identifier',
|
|
17
|
-
' // a comment is not an ancestor',
|
|
18
|
-
' handler',
|
|
19
|
-
' ```csharp',
|
|
20
|
-
' ghost Uuid identifier',
|
|
21
|
-
' ```',
|
|
22
|
-
' name String',
|
|
23
|
-
]).flat()];
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
describe('when scanning many commands', () => {
|
|
27
|
-
it('should visit structural indentation a linear number of times', () => {
|
|
28
|
-
const visits = vi.spyOn(context, 'indentOf');
|
|
29
|
-
try {
|
|
30
|
-
const small = commands(150);
|
|
31
|
-
validateLines(small);
|
|
32
|
-
const smallCount = visits.mock.calls.length;
|
|
33
|
-
visits.mockClear();
|
|
34
|
-
const large = commands(300);
|
|
35
|
-
validateLines(large);
|
|
36
|
-
const largeCount = visits.mock.calls.length;
|
|
37
|
-
const symbols = scanDocument(large);
|
|
38
|
-
smallCount.should.be.greaterThan(0);
|
|
39
|
-
largeCount.should.be.lessThan(large.length * 10);
|
|
40
|
-
largeCount.should.be.lessThan(smallCount * 2.1);
|
|
41
|
-
symbols.commands.length.should.equal(300);
|
|
42
|
-
symbols.commands.every(command => command.properties.map(property => property.name).join(',') === 'description,details,name').should.equal(true);
|
|
43
|
-
} finally {
|
|
44
|
-
visits.mockRestore();
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
});
|
|
@@ -1,18 +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, it } from 'vitest';
|
|
5
|
-
import { createTokensProvider } from '../tokens';
|
|
6
|
-
|
|
7
|
-
const rules = createTokensProvider([]).tokenizer.root as unknown as [RegExp, unknown][];
|
|
8
|
-
const fileImportRule = rules.find((rule) => Array.isArray(rule[1]) && (rule[1] as string[]).includes('string.link'));
|
|
9
|
-
|
|
10
|
-
describe('when highlighting a file import', () => {
|
|
11
|
-
it('should read the quoted path as a link', () => {
|
|
12
|
-
fileImportRule![0].test(' import "Orders/**/*.play"').should.be.true;
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it('should leave a qualified import to the keyword rules', () => {
|
|
16
|
-
fileImportRule![0].test('import Customers.CustomerRegistered').should.be.false;
|
|
17
|
-
});
|
|
18
|
-
});
|
|
@@ -1,63 +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, expect, it } from 'vitest';
|
|
5
|
-
import type { Token } from 'monaco-editor';
|
|
6
|
-
import { clauseKeywords } from '../language';
|
|
7
|
-
import { createTokensProvider } from '../tokens';
|
|
8
|
-
|
|
9
|
-
const provider = createTokensProvider([]);
|
|
10
|
-
const rules = provider.tokenizer.eventBody as unknown as [RegExp, unknown][];
|
|
11
|
-
|
|
12
|
-
describe('when highlighting event metadata', () => {
|
|
13
|
-
it.each(['id', 'documentation'])('should leave %s available as an ordinary name', word => {
|
|
14
|
-
expect(clauseKeywords).not.toContain(word);
|
|
15
|
-
});
|
|
16
|
-
it('should recognize only directive-shaped metadata inside the event state', () => {
|
|
17
|
-
expect(rules[1][0].test(' id "Old"')).toBe(true);
|
|
18
|
-
expect(rules[1][0].test(' id String')).toBe(false);
|
|
19
|
-
expect(rules[1][0].test(' name String = id')).toBe(false);
|
|
20
|
-
expect(rules[2][0].test(' documentation // details')).toBe(true);
|
|
21
|
-
expect(rules[2][0].test(' documentation String')).toBe(false);
|
|
22
|
-
});
|
|
23
|
-
it('should tokenize event directives without claiming property names or later blocks', async () => {
|
|
24
|
-
const compilerPath = 'monaco-editor/esm/vs/editor/standalone/common/monarch/monarchCompile.js';
|
|
25
|
-
const lexerPath = 'monaco-editor/esm/vs/editor/standalone/common/monarch/monarchLexer.js';
|
|
26
|
-
const { compile } = await import(compilerPath);
|
|
27
|
-
const { MonarchTokenizer } = await import(lexerPath);
|
|
28
|
-
const tokenizer = new MonarchTokenizer({}, {}, 'screenplay', compile('screenplay', provider), {
|
|
29
|
-
getValue: () => 20000,
|
|
30
|
-
onDidChangeConfiguration: () => ({ dispose() {} }),
|
|
31
|
-
});
|
|
32
|
-
let state = tokenizer.getInitialState();
|
|
33
|
-
const tokenize = (line: string): Token[] => {
|
|
34
|
-
const result = tokenizer.tokenize(line, true, state);
|
|
35
|
-
state = result.endState;
|
|
36
|
-
return result.tokens;
|
|
37
|
-
};
|
|
38
|
-
try {
|
|
39
|
-
for (const header of [' event Done', ' produces event Done']) {
|
|
40
|
-
tokenize(header);
|
|
41
|
-
expect(tokenize(' id "Old"').find(token => token.offset === 4)?.type).toBe('keyword.play');
|
|
42
|
-
expect(tokenize(' id String').find(token => token.offset === 4)?.type).toBe('identifier.play');
|
|
43
|
-
expect(tokenize(' documentation String').find(token => token.offset === 4)?.type).toBe('identifier.play');
|
|
44
|
-
const documentation = tokenize(' documentation // details');
|
|
45
|
-
expect(documentation.find(token => token.offset === 4)?.type).toBe('keyword.play');
|
|
46
|
-
expect(documentation.find(token => token.offset === 18)?.type).toBe('comment.play');
|
|
47
|
-
expect(tokenize(' ```markdown').find(token => token.type === 'string.quote.play')).toBeDefined();
|
|
48
|
-
expect(tokenize(' event Prose')[0].type).toBe('string.play');
|
|
49
|
-
tokenize(' ```');
|
|
50
|
-
tokenize(' command Other');
|
|
51
|
-
expect(tokenize(' id "NotMetadata"').find(token => token.offset === 4)?.type).toBe('identifier.play');
|
|
52
|
-
}
|
|
53
|
-
} finally {
|
|
54
|
-
tokenizer.dispose();
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
it('should leave the event state when a line is not nested under its header', () => {
|
|
58
|
-
const exit = new RegExp(rules[0][0].source.replace('$S2', ' '));
|
|
59
|
-
expect(exit.test(' command Other')).toBe(true);
|
|
60
|
-
expect(exit.test(' id "Old"')).toBe(false);
|
|
61
|
-
expect(exit.test('')).toBe(false);
|
|
62
|
-
});
|
|
63
|
-
});
|
|
@@ -1,28 +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, it } from 'vitest';
|
|
5
|
-
import { ensureBuiltInSubLanguages } from '../index';
|
|
6
|
-
import { getSubLanguages } from '../sub-language-registry';
|
|
7
|
-
import { createTokensProvider } from '../tokens';
|
|
8
|
-
|
|
9
|
-
ensureBuiltInSubLanguages();
|
|
10
|
-
const rules = createTokensProvider(getSubLanguages()).tokenizer.root as unknown as [RegExp, unknown][];
|
|
11
|
-
const stepRules = rules.filter((rule) => Array.isArray(rule[1]) && (rule[1] as string[]).join() === 'white,keyword,white,keyword');
|
|
12
|
-
const captureLanguage = rules.findIndex((rule) => rule[0].source === '\\bcapture\\b');
|
|
13
|
-
|
|
14
|
-
describe('when highlighting specification steps', () => {
|
|
15
|
-
it('should come before the capture sub-language can claim a step', () => {
|
|
16
|
-
rules.indexOf(stepRules[stepRules.length - 1]).should.be.below(captureLanguage);
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
for (const line of [' given clock "2026-10-05T08:00:00Z"', ' given capture LegacyLoans', ' when trigger NightlySync', ' when query OpeningHoursFor', ' then result exactly', ' then no result']) {
|
|
20
|
-
it(`should read the step words of '${line.trim()}' as keywords`, () => {
|
|
21
|
-
stepRules.some((rule) => rule[0].test(line)).should.be.true;
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
it('should leave a capture declaration to the sub-language', () => {
|
|
26
|
-
stepRules.some((rule) => rule[0].test(' capture LegacyLoans')).should.be.false;
|
|
27
|
-
});
|
|
28
|
-
});
|
|
@@ -1,77 +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
|
-
// One document holding every condition the editor and the compiler both check, so a condition added
|
|
9
|
-
// later without a code fails here rather than reaching a user as a codeless squiggle.
|
|
10
|
-
const document = [
|
|
11
|
-
'concept InvoiceId : Guid',
|
|
12
|
-
'concept InvoiceId : String',
|
|
13
|
-
'concept Amount : Wat',
|
|
14
|
-
'',
|
|
15
|
-
'module Invoicing',
|
|
16
|
-
' import Customers.CustomerRegistered',
|
|
17
|
-
' feature Invoices',
|
|
18
|
-
' slice Wat Register',
|
|
19
|
-
' event InvoiceRegistered',
|
|
20
|
-
' invoiceId InvoiceId',
|
|
21
|
-
'\t amount Amount',
|
|
22
|
-
' command RegisterInvoice',
|
|
23
|
-
' invoiceId InvoiceId identifier',
|
|
24
|
-
' amount Amount identifier',
|
|
25
|
-
' reference Unknown',
|
|
26
|
-
' authorize CanRegister',
|
|
27
|
-
' produces InvoiceArchived',
|
|
28
|
-
' registeredBy = $context.wat',
|
|
29
|
-
' causedBy = $context.causedBy.wat',
|
|
30
|
-
' department = $context.identity.wat',
|
|
31
|
-
' command ArchiveInvoice',
|
|
32
|
-
' invoiceId InvoiceId identifier',
|
|
33
|
-
' produces InvoiceArchived',
|
|
34
|
-
' projection Statistics => StatisticsReadModel',
|
|
35
|
-
' from InvoiceRegistered',
|
|
36
|
-
' cause = $eventContext.causationId',
|
|
37
|
-
' typeName = $eventContext.eventType.name',
|
|
38
|
-
' firstCause = $eventContext.causation.occurred',
|
|
39
|
-
' nothing = $eventContext.',
|
|
40
|
-
' count byUser.$causedBy.subject',
|
|
41
|
-
' command Rename',
|
|
42
|
-
' invoiceId InvoiceId identifier',
|
|
43
|
-
' otherId InvoiceId',
|
|
44
|
-
' produces event Renamed generation 2',
|
|
45
|
-
' invoiceId InvoiceId = invoiceId',
|
|
46
|
-
' id "Renamed"',
|
|
47
|
-
' id "Older"',
|
|
48
|
-
' documentation "not fenced"',
|
|
49
|
-
' produces Other',
|
|
50
|
-
' for otherId',
|
|
51
|
-
' event Renamed',
|
|
52
|
-
' reaction React',
|
|
53
|
-
' every 1 day',
|
|
54
|
-
' produces event Unsupported',
|
|
55
|
-
' query Overdue => OverdueReadModel[]',
|
|
56
|
-
' performer',
|
|
57
|
-
' csharp',
|
|
58
|
-
' ```',
|
|
59
|
-
' return readModels;',
|
|
60
|
-
];
|
|
61
|
-
|
|
62
|
-
describe('when validating a document with a problem of every coded kind', () => {
|
|
63
|
-
let issues: ValidationIssue[];
|
|
64
|
-
|
|
65
|
-
beforeEach(() => {
|
|
66
|
-
issues = validateLines(document);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('should give every issue it reports a code', () => {
|
|
70
|
-
issues.filter((issue) => !issue.code).should.be.empty;
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it('should report each condition with the code the compiler reports it with', () => {
|
|
74
|
-
const reported = new Set(issues.map((issue) => issue.code));
|
|
75
|
-
[...Object.values(diagnosticCodes)].forEach((code) => reported.has(code).should.be.true);
|
|
76
|
-
});
|
|
77
|
-
});
|