@cratis/screenplay-language 4.47.0 → 4.48.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/completion-items.ts +37 -1
- package/completion-planner.ts +15 -0
- package/completions.ts +26 -3
- package/diagnostic-codes.ts +1 -0
- package/dist/completion-items.d.ts +1 -0
- package/dist/completion-items.d.ts.map +1 -1
- package/dist/completion-items.js +36 -1
- package/dist/completion-items.js.map +1 -1
- package/dist/completion-planner.d.ts +3 -0
- package/dist/completion-planner.d.ts.map +1 -1
- package/dist/completion-planner.js +15 -0
- package/dist/completion-planner.js.map +1 -1
- package/dist/completions.d.ts +5 -2
- package/dist/completions.d.ts.map +1 -1
- package/dist/completions.js +13 -2
- package/dist/completions.js.map +1 -1
- package/dist/diagnostic-codes.d.ts +1 -0
- package/dist/diagnostic-codes.d.ts.map +1 -1
- package/dist/diagnostic-codes.js +1 -0
- package/dist/diagnostic-codes.js.map +1 -1
- package/dist/file-imports.d.ts +11 -0
- package/dist/file-imports.d.ts.map +1 -0
- package/dist/file-imports.js +58 -0
- package/dist/file-imports.js.map +1 -0
- package/dist/hover-content.d.ts.map +1 -1
- package/dist/hover-content.js +5 -1
- package/dist/hover-content.js.map +1 -1
- package/dist/index.d.ts +10 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -5
- package/dist/index.js.map +1 -1
- package/dist/keyword-docs.d.ts +1 -0
- package/dist/keyword-docs.d.ts.map +1 -1
- package/dist/keyword-docs.js +13 -2
- package/dist/keyword-docs.js.map +1 -1
- package/dist/language.d.ts.map +1 -1
- package/dist/language.js +2 -0
- package/dist/language.js.map +1 -1
- package/dist/symbols.d.ts +1 -0
- package/dist/symbols.d.ts.map +1 -1
- package/dist/symbols.js +15 -0
- package/dist/symbols.js.map +1 -1
- package/dist/themes/screenplay-dark.d.ts.map +1 -1
- package/dist/themes/screenplay-dark.js +1 -0
- package/dist/themes/screenplay-dark.js.map +1 -1
- package/dist/themes/screenplay-light.d.ts.map +1 -1
- package/dist/themes/screenplay-light.js +1 -0
- package/dist/themes/screenplay-light.js.map +1 -1
- package/dist/tokens.d.ts.map +1 -1
- package/dist/tokens.js +6 -0
- package/dist/tokens.js.map +1 -1
- package/dist/validation.d.ts +5 -1
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +29 -8
- package/dist/validation.js.map +1 -1
- package/file-imports.ts +70 -0
- package/for_fileImports/when_finding_file_imports.ts +38 -0
- package/for_importablePaths/when_listing_what_a_document_can_import.ts +34 -0
- package/for_planCompletions/when_completing_a_file_import.ts +26 -0
- package/for_planCompletions/when_completing_a_specification_step.ts +42 -0
- package/for_tokens/when_highlighting_a_file_import.ts +18 -0
- package/for_tokens/when_highlighting_specification_steps.ts +28 -0
- package/for_validateLines/when_validating_a_document/with_a_problem_of_every_coded_kind.ts +1 -0
- package/for_validateLines/when_validating_a_file_placed_by_an_import/with_names_declared_in_other_files.ts +43 -0
- package/for_validateLines/when_validating_file_imports/at_every_level.ts +36 -0
- package/hover-content.ts +6 -1
- package/index.ts +13 -7
- package/keyword-docs.ts +14 -2
- package/language.ts +2 -0
- package/package.json +1 -1
- package/symbols.ts +16 -0
- package/themes/screenplay-dark.ts +1 -0
- package/themes/screenplay-light.ts +1 -0
- package/tokens.ts +6 -0
- package/validation.ts +43 -7
package/validation.ts
CHANGED
|
@@ -3,15 +3,17 @@
|
|
|
3
3
|
|
|
4
4
|
import { causedByProperties, contextRoots, identityProperties, primitiveTypes, sliceTypes } from './language';
|
|
5
5
|
import { DiagnosticCode, diagnosticCodes } from './diagnostic-codes';
|
|
6
|
-
import { fenceMap, indentOf } from './document-context';
|
|
6
|
+
import { enclosingChain, fenceMap, indentOf } from './document-context';
|
|
7
7
|
import { resolveEventContextPath } from './event-context';
|
|
8
8
|
import {
|
|
9
9
|
DocumentSymbols,
|
|
10
10
|
PropertySymbol,
|
|
11
11
|
knownEventNames,
|
|
12
12
|
knownTypeNames,
|
|
13
|
+
mergeSymbols,
|
|
13
14
|
scanDocument,
|
|
14
15
|
} from './symbols';
|
|
16
|
+
import { fileImportOn, isFileImportLine } from './file-imports';
|
|
15
17
|
|
|
16
18
|
export type ValidationSeverity = 'error' | 'warning';
|
|
17
19
|
|
|
@@ -27,6 +29,14 @@ export interface ValidationIssue {
|
|
|
27
29
|
code?: DiagnosticCode;
|
|
28
30
|
}
|
|
29
31
|
|
|
32
|
+
// What a document is validated against beyond itself.
|
|
33
|
+
export interface ValidationContext {
|
|
34
|
+
// What the rest of the application declares - the other .play files of a folder, or the files an import
|
|
35
|
+
// brings in - so a name declared in another file is not reported unknown. Merge the scanned symbols of
|
|
36
|
+
// those files with mergeSymbols. The document's own declarations are always known.
|
|
37
|
+
application?: DocumentSymbols;
|
|
38
|
+
}
|
|
39
|
+
|
|
30
40
|
function issue(
|
|
31
41
|
severity: ValidationSeverity,
|
|
32
42
|
line: number,
|
|
@@ -52,9 +62,9 @@ function tokenIssue(
|
|
|
52
62
|
|
|
53
63
|
// Reports every property whose type reference names nothing the document declares, and
|
|
54
64
|
// every command that marks more than one property as its identifier.
|
|
55
|
-
function validateDeclarations(lines: string[], symbols: DocumentSymbols): ValidationIssue[] {
|
|
65
|
+
function validateDeclarations(lines: string[], symbols: DocumentSymbols, application: DocumentSymbols): ValidationIssue[] {
|
|
56
66
|
const issues: ValidationIssue[] = [];
|
|
57
|
-
const types = new Set(knownTypeNames(symbols, primitiveTypes));
|
|
67
|
+
const types = new Set([...knownTypeNames(symbols, primitiveTypes), ...knownTypeNames(application, [])]);
|
|
58
68
|
|
|
59
69
|
const checkProperties = (properties: PropertySymbol[], owner: string) => {
|
|
60
70
|
for (const property of properties.filter(
|
|
@@ -118,12 +128,17 @@ function validateDeclarations(lines: string[], symbols: DocumentSymbols): Valida
|
|
|
118
128
|
|
|
119
129
|
// Validates a Screenplay document without any editor dependency — both the Monaco
|
|
120
130
|
// service and the VSCode extension adapt these issues to their marker/diagnostic APIs.
|
|
121
|
-
|
|
131
|
+
//
|
|
132
|
+
// The checks read the document line by line, never as a whole document's top level, so a file an import
|
|
133
|
+
// places in a module or feature - holding slices or features at its top level - validates as it is written.
|
|
134
|
+
// Where it is placed, and whether its imports resolve, is the compiler's to say.
|
|
135
|
+
export function validateLines(lines: string[], context: ValidationContext = {}): ValidationIssue[] {
|
|
122
136
|
const fences = fenceMap(lines);
|
|
123
137
|
const symbols = scanDocument(lines);
|
|
124
|
-
const
|
|
125
|
-
const
|
|
126
|
-
const
|
|
138
|
+
const application = context.application ?? mergeSymbols();
|
|
139
|
+
const events = new Set([...knownEventNames(symbols), ...knownEventNames(application)]);
|
|
140
|
+
const policies = new Set([...symbols.policies, ...application.policies].map((policy) => policy.name));
|
|
141
|
+
const issues: ValidationIssue[] = validateDeclarations(lines, symbols, application);
|
|
127
142
|
|
|
128
143
|
const checkEvent = (line: number, text: string, name: string) => {
|
|
129
144
|
if (!events.has(name)) {
|
|
@@ -187,6 +202,9 @@ export function validateLines(lines: string[]): ValidationIssue[] {
|
|
|
187
202
|
authorizeIndent = -1;
|
|
188
203
|
}
|
|
189
204
|
|
|
205
|
+
const fileImportIssue = validateImport(lines, fences, index);
|
|
206
|
+
if (fileImportIssue) issues.push(fileImportIssue);
|
|
207
|
+
|
|
190
208
|
const slice = trimmed.match(/^slice\s+(\w+)/);
|
|
191
209
|
if (slice && !sliceTypes.includes(slice[1])) {
|
|
192
210
|
issues.push(
|
|
@@ -328,6 +346,24 @@ export function validateLines(lines: string[]): ValidationIssue[] {
|
|
|
328
346
|
return issues;
|
|
329
347
|
}
|
|
330
348
|
|
|
349
|
+
// Inside a module or feature an import names files, and a quoted import anywhere has the compiler's shape.
|
|
350
|
+
function validateImport(lines: string[], fences: boolean[], index: number): ValidationIssue | undefined {
|
|
351
|
+
const line = lines[index];
|
|
352
|
+
const trimmed = line.trim().replace(/\s*\/\/.*$/, '');
|
|
353
|
+
if (!/^import\b/.test(trimmed) || fileImportOn(line, index)) return undefined;
|
|
354
|
+
const indent = indentOf(line);
|
|
355
|
+
const inBody = indent > 0 && ['module', 'feature'].includes(enclosingChain(lines, fences, index, indent)[0]);
|
|
356
|
+
if (!inBody && !isFileImportLine(line)) return undefined;
|
|
357
|
+
return issue(
|
|
358
|
+
'error',
|
|
359
|
+
index,
|
|
360
|
+
indent + 1,
|
|
361
|
+
trimmed.length,
|
|
362
|
+
`Invalid import '${trimmed}' — inside a module or feature, import names files: 'import "<path or glob>"'.`,
|
|
363
|
+
diagnosticCodes.invalidFileImport,
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
|
|
331
367
|
// A mapping target: the first word of a mapping line, after the keyword that opens it if there is one.
|
|
332
368
|
const mappingTarget = /^(?:(?:increment|decrement|count|clear|add|subtract|set)\s+)?@?([$\w.]+)(?=\s|=|$)/;
|
|
333
369
|
|