Skip to content

Commit

Permalink
feat: show info if unnecessary syntax is used (#566)
Browse files Browse the repository at this point in the history
Closes partially #543

### Summary of Changes

Show an info if one of the following can be removed:
* assignment (only wildcards as assignees)
* body of class/enum
* parameter list of annotation/enum variant
* result list of function/segment
* type parameter list of class/enum variant/function
* union type (singular type argument)

---------

Co-authored-by: megalinter-bot <129584137+megalinter-bot@users.noreply.github.com>
  • Loading branch information
lars-reimann and megalinter-bot committed Sep 20, 2023
1 parent a877f4c commit c26d33a
Show file tree
Hide file tree
Showing 52 changed files with 439 additions and 158 deletions.
126 changes: 0 additions & 126 deletions src/language/validation/nameConvention.ts

This file was deleted.

100 changes: 100 additions & 0 deletions src/language/validation/names.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { SdsDeclaration } from '../generated/ast.js';
import { ValidationAcceptor } from 'langium';

export const CODE_NAMES_BLOCK_LAMBDA_PREFIX = 'names/block-lambda-prefix';
export const CODE_NAMES_CASING = 'names/casing';

export const nameMustNotStartWithBlockLambdaPrefix = (node: SdsDeclaration, accept: ValidationAcceptor) => {
const name = node.name ?? '';
const blockLambdaPrefix = '__block_lambda_';
if (name.startsWith(blockLambdaPrefix)) {
accept(
'error',
"Names of declarations must not start with '__block_lambda_'. This is reserved for code generation of block lambdas.",
{
node,
property: 'name',
code: CODE_NAMES_BLOCK_LAMBDA_PREFIX,
},
);
}
};

export const nameShouldHaveCorrectCasing = (node: SdsDeclaration, accept: ValidationAcceptor): void => {
switch (node.$type) {
case 'SdsAnnotation':
return nameShouldBeUpperCamelCase(node, 'annotations', accept);
case 'SdsAttribute':
return nameShouldBeLowerCamelCase(node, 'attributes', accept);
case 'SdsBlockLambdaResult':
return nameShouldBeLowerCamelCase(node, 'block lambda results', accept);
case 'SdsClass':
return nameShouldBeUpperCamelCase(node, 'classes', accept);
case 'SdsEnum':
return nameShouldBeUpperCamelCase(node, 'enums', accept);
case 'SdsEnumVariant':
return nameShouldBeUpperCamelCase(node, 'enum variants', accept);
case 'SdsFunction':
return nameShouldBeLowerCamelCase(node, 'functions', accept);
case 'SdsModule':
const name = node.name ?? '';
const segments = name.split('.');
if (name !== '' && !segments.every(isLowerCamelCase)) {
accept('warning', 'All segments of the qualified name of a package should be lowerCamelCase.', {
node,
property: 'name',
code: CODE_NAMES_CASING,
});
}
return;
case 'SdsParameter':
return nameShouldBeLowerCamelCase(node, 'parameters', accept);
case 'SdsPipeline':
return nameShouldBeLowerCamelCase(node, 'pipelines', accept);
case 'SdsPlaceholder':
return nameShouldBeLowerCamelCase(node, 'placeholders', accept);
case 'SdsResult':
return nameShouldBeLowerCamelCase(node, 'results', accept);
case 'SdsSchema':
return nameShouldBeUpperCamelCase(node, 'schemas', accept);
case 'SdsSegment':
return nameShouldBeLowerCamelCase(node, 'segments', accept);
case 'SdsTypeParameter':
return nameShouldBeUpperCamelCase(node, 'type parameters', accept);
}
};

const nameShouldBeLowerCamelCase = (node: SdsDeclaration, nodeName: string, accept: ValidationAcceptor): void => {
const name = node.name ?? '';
if (!isLowerCamelCase(name)) {
acceptCasingWarning(node, nodeName, 'lowerCamelCase', accept);
}
};

const isLowerCamelCase = (name: string): boolean => {
return /^[a-z][a-zA-Z0-9]*$/gu.test(name);
};

const nameShouldBeUpperCamelCase = (node: SdsDeclaration, nodeName: string, accept: ValidationAcceptor): void => {
const name = node.name ?? '';
if (!isUpperCamelCase(name)) {
acceptCasingWarning(node, nodeName, 'UpperCamelCase', accept);
}
};

const isUpperCamelCase = (name: string): boolean => {
return /^[A-Z][a-zA-Z0-9]*$/gu.test(name);
};

const acceptCasingWarning = (
node: SdsDeclaration,
nodeName: string,
expectedCasing: string,
accept: ValidationAcceptor,
) => {
accept('warning', `Names of ${nodeName} should be ${expectedCasing}.`, {
node,
property: 'name',
code: CODE_NAMES_CASING,
});
};
23 changes: 22 additions & 1 deletion src/language/validation/safe-ds-validator.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
import { ValidationChecks } from 'langium';
import { SafeDsAstType } from '../generated/ast.js';
import type { SafeDsServices } from '../safe-ds-module.js';
import { nameMustNotStartWithBlockLambdaPrefix, nameShouldHaveCorrectCasing } from './nameConvention.js';
import { nameMustNotStartWithBlockLambdaPrefix, nameShouldHaveCorrectCasing } from './names.js';
import {
annotationParameterListShouldNotBeEmpty,
assignmentShouldHaveMoreThanWildcardsAsAssignees,
classBodyShouldNotBeEmpty,
classTypeParameterListShouldNotBeEmpty,
enumBodyShouldNotBeEmpty,
enumVariantParameterListShouldNotBeEmpty,
enumVariantTypeParameterListShouldNotBeEmpty,
functionResultListShouldNotBeEmpty,
functionTypeParameterListShouldNotBeEmpty,
segmentResultListShouldNotBeEmpty,
unionTypeShouldNotHaveASingularTypeArgument,
} from './unnecessarySyntax.js';

/**
* Register custom validation checks.
Expand All @@ -10,7 +23,15 @@ export const registerValidationChecks = function (services: SafeDsServices) {
const registry = services.validation.ValidationRegistry;
const validator = services.validation.SafeDsValidator;
const checks: ValidationChecks<SafeDsAstType> = {
SdsAssignment: [assignmentShouldHaveMoreThanWildcardsAsAssignees],
SdsAnnotation: [annotationParameterListShouldNotBeEmpty],
SdsClass: [classBodyShouldNotBeEmpty, classTypeParameterListShouldNotBeEmpty],
SdsDeclaration: [nameMustNotStartWithBlockLambdaPrefix, nameShouldHaveCorrectCasing],
SdsEnum: [enumBodyShouldNotBeEmpty],
SdsEnumVariant: [enumVariantParameterListShouldNotBeEmpty, enumVariantTypeParameterListShouldNotBeEmpty],
SdsFunction: [functionResultListShouldNotBeEmpty, functionTypeParameterListShouldNotBeEmpty],
SdsSegment: [segmentResultListShouldNotBeEmpty],
SdsUnionType: [unionTypeShouldNotHaveASingularTypeArgument],
};
registry.register(checks, validator);
};
Expand Down
Loading

0 comments on commit c26d33a

Please sign in to comment.