1
1
import {
2
+ isSdsQualifiedImport ,
2
3
SdsAnnotation ,
3
4
SdsBlockLambda ,
4
5
SdsCallableType ,
@@ -8,21 +9,32 @@ import {
8
9
SdsEnumVariant ,
9
10
SdsExpressionLambda ,
10
11
SdsFunction ,
12
+ SdsImportedDeclaration ,
13
+ SdsModule ,
11
14
SdsPipeline ,
15
+ SdsSchema ,
12
16
SdsSegment ,
13
17
} from '../generated/ast.js' ;
14
- import { ValidationAcceptor } from 'langium' ;
18
+ import { getDocument , ValidationAcceptor } from 'langium' ;
15
19
import {
16
20
blockLambdaResultsOrEmpty ,
17
21
classMembersOrEmpty ,
22
+ columnsOrEmpty ,
18
23
enumVariantsOrEmpty ,
24
+ importedDeclarationsOrEmpty ,
25
+ importsOrEmpty ,
19
26
isStatic ,
27
+ moduleMembersOrEmpty ,
28
+ packageNameOrUndefined ,
20
29
parametersOrEmpty ,
21
30
placeholdersOrEmpty ,
22
31
resultsOrEmpty ,
23
32
typeParametersOrEmpty ,
24
33
} from '../helpers/nodeProperties.js' ;
25
34
import { duplicatesBy } from '../helpers/collectionUtils.js' ;
35
+ import { isInPipelineFile , isInStubFile , isInTestFile } from '../helpers/fileExtensions.js' ;
36
+ import { declarationIsAllowedInPipelineFile , declarationIsAllowedInStubFile } from './other/modules.js' ;
37
+ import { SafeDsServices } from '../safe-ds-module.js' ;
26
38
27
39
export const CODE_NAME_BLOCK_LAMBDA_PREFIX = 'name/block-lambda-prefix' ;
28
40
export const CODE_NAME_CASING = 'name/casing' ;
@@ -211,6 +223,75 @@ export const functionMustContainUniqueNames = (node: SdsFunction, accept: Valida
211
223
) ;
212
224
} ;
213
225
226
+ export const moduleMemberMustHaveNameThatIsUniqueInPackage = ( services : SafeDsServices ) => {
227
+ const packageManager = services . workspace . PackageManager ;
228
+
229
+ return ( node : SdsModule , accept : ValidationAcceptor ) : void => {
230
+ for ( const member of moduleMembersOrEmpty ( node ) ) {
231
+ const packageName = packageNameOrUndefined ( member ) ?? '' ;
232
+ const declarationsInPackage = packageManager . getDeclarationsInPackage ( packageName ) ;
233
+ const memberUri = getDocument ( member ) . uri ?. toString ( ) ;
234
+
235
+ if (
236
+ declarationsInPackage . some ( ( it ) => it . name === member . name && it . documentUri . toString ( ) !== memberUri )
237
+ ) {
238
+ accept ( 'error' , `Multiple declarations in this package have the name '${ member . name } '.` , {
239
+ node : member ,
240
+ property : 'name' ,
241
+ code : CODE_NAME_DUPLICATE ,
242
+ } ) ;
243
+ }
244
+ }
245
+ } ;
246
+ } ;
247
+
248
+ export const moduleMustContainUniqueNames = ( node : SdsModule , accept : ValidationAcceptor ) : void => {
249
+ // Names of imported declarations must be unique
250
+ const importedDeclarations = importsOrEmpty ( node ) . filter ( isSdsQualifiedImport ) . flatMap ( importedDeclarationsOrEmpty ) ;
251
+ for ( const duplicate of duplicatesBy ( importedDeclarations , importedDeclarationName ) ) {
252
+ if ( duplicate . alias ) {
253
+ accept ( 'error' , `A declaration with name '${ importedDeclarationName ( duplicate ) } ' was imported already.` , {
254
+ node : duplicate . alias ,
255
+ property : 'alias' ,
256
+ code : CODE_NAME_DUPLICATE ,
257
+ } ) ;
258
+ } else {
259
+ accept ( 'error' , `A declaration with name '${ importedDeclarationName ( duplicate ) } ' was imported already.` , {
260
+ node : duplicate ,
261
+ property : 'declaration' ,
262
+ code : CODE_NAME_DUPLICATE ,
263
+ } ) ;
264
+ }
265
+ }
266
+
267
+ // Names of module members must be unique
268
+ if ( isInPipelineFile ( node ) ) {
269
+ namesMustBeUnique (
270
+ moduleMembersOrEmpty ( node ) ,
271
+ ( name ) => `A declaration with name '${ name } ' exists already in this file.` ,
272
+ accept ,
273
+ declarationIsAllowedInPipelineFile ,
274
+ ) ;
275
+ } else if ( isInStubFile ( node ) ) {
276
+ namesMustBeUnique (
277
+ moduleMembersOrEmpty ( node ) ,
278
+ ( name ) => `A declaration with name '${ name } ' exists already in this file.` ,
279
+ accept ,
280
+ declarationIsAllowedInStubFile ,
281
+ ) ;
282
+ } else if ( isInTestFile ( node ) ) {
283
+ namesMustBeUnique (
284
+ moduleMembersOrEmpty ( node ) ,
285
+ ( name ) => `A declaration with name '${ name } ' exists already in this file.` ,
286
+ accept ,
287
+ ) ;
288
+ }
289
+ } ;
290
+
291
+ const importedDeclarationName = ( node : SdsImportedDeclaration | undefined ) : string | undefined => {
292
+ return node ?. alias ?. alias ?? node ?. declaration . ref ?. name ;
293
+ } ;
294
+
214
295
export const pipelineMustContainUniqueNames = ( node : SdsPipeline , accept : ValidationAcceptor ) : void => {
215
296
namesMustBeUnique (
216
297
placeholdersOrEmpty ( node . body ) ,
@@ -219,6 +300,17 @@ export const pipelineMustContainUniqueNames = (node: SdsPipeline, accept: Valida
219
300
) ;
220
301
} ;
221
302
303
+ export const schemaMustContainUniqueNames = ( node : SdsSchema , accept : ValidationAcceptor ) : void => {
304
+ const duplicates = duplicatesBy ( columnsOrEmpty ( node ) , ( it ) => it . columnName . value ) ;
305
+ for ( const duplicate of duplicates ) {
306
+ accept ( 'error' , `A column with name '${ duplicate . columnName . value } ' exists already.` , {
307
+ node : duplicate ,
308
+ property : 'columnName' ,
309
+ code : CODE_NAME_DUPLICATE ,
310
+ } ) ;
311
+ }
312
+ } ;
313
+
222
314
export const segmentMustContainUniqueNames = ( node : SdsSegment , accept : ValidationAcceptor ) : void => {
223
315
const parametersAndPlaceholder = [ ...parametersOrEmpty ( node ) , ...placeholdersOrEmpty ( node . body ) ] ;
224
316
namesMustBeUnique (
@@ -238,12 +330,15 @@ const namesMustBeUnique = (
238
330
nodes : Iterable < SdsDeclaration > ,
239
331
createMessage : ( name : string ) => string ,
240
332
accept : ValidationAcceptor ,
333
+ shouldReportErrorOn : ( node : SdsDeclaration ) => boolean = ( ) => true ,
241
334
) : void => {
242
335
for ( const node of duplicatesBy ( nodes , ( it ) => it . name ) ) {
243
- accept ( 'error' , createMessage ( node . name ) , {
244
- node,
245
- property : 'name' ,
246
- code : CODE_NAME_DUPLICATE ,
247
- } ) ;
336
+ if ( shouldReportErrorOn ( node ) ) {
337
+ accept ( 'error' , createMessage ( node . name ) , {
338
+ node,
339
+ property : 'name' ,
340
+ code : CODE_NAME_DUPLICATE ,
341
+ } ) ;
342
+ }
248
343
}
249
344
} ;
0 commit comments