Skip to content

Commit

Permalink
feat: handle backticks surrounding IDs (#622)
Browse files Browse the repository at this point in the history
Closes #579

### Summary of Changes

Backticks allow using keywords as IDs. This now removes them properly
from IDs.

---------

Co-authored-by: megalinter-bot <129584137+megalinter-bot@users.noreply.github.com>
  • Loading branch information
lars-reimann and megalinter-bot committed Oct 9, 2023
1 parent a51a644 commit 608e470
Show file tree
Hide file tree
Showing 20 changed files with 137 additions and 4 deletions.
2 changes: 2 additions & 0 deletions src/language/grammar/safe-ds-value-converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { convertString, CstNode, DefaultValueConverter, GrammarAST, ValueType }
export class SafeDsValueConverter extends DefaultValueConverter {
protected override runConverter(rule: GrammarAST.AbstractRule, input: string, cstNode: CstNode): ValueType {
switch (rule.name.toUpperCase()) {
case 'ID':
return input.replaceAll('`', '');
case 'TEMPLATE_STRING_START':
return convertString(input.substring(0, input.length - 1));
case 'TEMPLATE_STRING_INNER':
Expand Down
4 changes: 3 additions & 1 deletion tests/helpers/nodeFinder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,12 @@ describe('getNodeOfType', () => {

it('should return the nth matching node if an index is set', async () => {
const code = `
package p
class C
enum D
`;
const node = await getNodeOfType(services, code, isSdsDeclaration, 1);
const node = await getNodeOfType(services, code, isSdsDeclaration, 2);
expect(node).to.satisfy(isSdsEnum);
});
});
4 changes: 2 additions & 2 deletions tests/helpers/nodeFinder.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Location, Range } from 'vscode-languageserver';
import { isRangeEqual, parseHelper } from 'langium/test';
import { SafeDsServices } from '../../src/language/safe-ds-module.js';
import { AstNode, streamAllContents, URI } from 'langium';
import { AstNode, streamAllContents, streamAst, URI } from 'langium';
import { SdsModule } from '../../src/language/generated/ast.js';
import { AssertionError } from 'assert';
import { locationToString } from './location.js';
Expand Down Expand Up @@ -67,7 +67,7 @@ export const getNodeOfType = async <T extends AstNode>(
): Promise<T> => {
const document = await parseHelper(services)(code);
const module = document.parseResult.value as SdsModule;
const candidates = streamAllContents(module).filter(predicate).toArray();
const candidates = streamAst(module).filter(predicate).toArray();

if (candidates.length === 0) {
throw new AssertionError({ message: `Expected to find a matching node but found none.` });
Expand Down
99 changes: 99 additions & 0 deletions tests/language/grammar/safe-ds-value-converter.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { describe, expect, it } from 'vitest';
import { createSafeDsServices } from '../../../src/language/safe-ds-module.js';
import { EmptyFileSystem } from 'langium';
import { getNodeOfType } from '../../helpers/nodeFinder.js';
import {
isSdsClass,
isSdsModule,
isSdsTemplateStringEnd,
isSdsTemplateStringInner,
isSdsTemplateStringStart,
} from '../../../src/language/generated/ast.js';

const services = createSafeDsServices(EmptyFileSystem).SafeDs;

describe('runConverter', () => {
it('should remove backticks from IDs (package)', async () => {
const code = `
package \`foo\`.bar
`;

const module = await getNodeOfType(services, code, isSdsModule);
expect(module.name).toBe('foo.bar');
});

it('should remove backticks from IDs (declaration)', async () => {
const code = `
class \`MyClass\`
`;

const firstClass = await getNodeOfType(services, code, isSdsClass);
expect(firstClass.name).toBe('MyClass');
});

it('should remove delimiters from TEMPLATE_STRING_STARTs', async () => {
const code = `
pipeline myPipeline {
"start{{ 1 }}inner{{ 2 }}end";
}
`;

const firstTemplateStringStart = await getNodeOfType(services, code, isSdsTemplateStringStart);
expect(firstTemplateStringStart.value).toBe('start');
});

it('should handle escape sequences in TEMPLATE_STRING_STARTs', async () => {
const code = `
pipeline myPipeline {
"\\tstart{{ 1 }}inner{{ 2 }}end";
}
`;

const firstTemplateStringStart = await getNodeOfType(services, code, isSdsTemplateStringStart);
expect(firstTemplateStringStart.value).toBe('\tstart');
});

it('should remove delimiters from TEMPLATE_STRING_INNERs', async () => {
const code = `
pipeline myPipeline {
"start{{ 1 }}inner{{ 2 }}end";
}
`;

const firstTemplateStringInner = await getNodeOfType(services, code, isSdsTemplateStringInner);
expect(firstTemplateStringInner.value).toBe('inner');
});

it('should handle escape sequences in TEMPLATE_STRING_INNERs', async () => {
const code = `
pipeline myPipeline {
"start{{ 1 }}\\tinner{{ 2 }}end";
}
`;

const firstTemplateStringInner = await getNodeOfType(services, code, isSdsTemplateStringInner);
expect(firstTemplateStringInner.value).toBe('\tinner');
});

it('should remove delimiters from TEMPLATE_STRING_ENDs', async () => {
const code = `
pipeline myPipeline {
"start{{ 1 }}inner{{ 2 }}end";
}
`;

const firstTemplateStringEnd = await getNodeOfType(services, code, isSdsTemplateStringEnd);
expect(firstTemplateStringEnd.value).toBe('end');
});

it('should handle escape sequences in TEMPLATE_STRING_ENDs', async () => {
const code = `
pipeline myPipeline {
"start{{ 1 }}inner{{ 2 }}\\tend";
}
`;

const firstTemplateStringEnd = await getNodeOfType(services, code, isSdsTemplateStringEnd);
expect(firstTemplateStringEnd.value).toBe('\tend');
});
});
2 changes: 2 additions & 0 deletions tests/resources/validation/names/casing/annotations.sdstest
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package tests.validation.names.casing

// $TEST$ no warning "Names of annotations should be UpperCamelCase."
annotation »AnnotationUppercase1«
// $TEST$ no warning "Names of annotations should be UpperCamelCase."
annotation »`AnnotationUppercase2`«
// $TEST$ warning "Names of annotations should be UpperCamelCase."
annotation »annotationLowercase«
// $TEST$ warning "Names of annotations should be UpperCamelCase."
Expand Down
2 changes: 2 additions & 0 deletions tests/resources/validation/names/casing/attributes.sdstest
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ class MyClass {
attr »AttributeUppercase«: Int
// $TEST$ no warning "Names of attributes should be lowerCamelCase."
attr »attributeLowercase1«: Int
// $TEST$ no warning "Names of attributes should be lowerCamelCase."
attr »`attributeLowercase2`«: Int
// $TEST$ warning "Names of attributes should be lowerCamelCase."
attr »_attributeUnderscore«: Int
// $TEST$ warning "Names of attributes should be lowerCamelCase."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ pipeline myPipeline1 {
yield »LambdaResultUppercase« = 1;
// $TEST$ no warning "Names of block lambda results should be lowerCamelCase."
yield »lambdaResultLowercase1« = 1;
// $TEST$ no warning "Names of block lambda results should be lowerCamelCase."
yield »`lambdaResultLowercase2`« = 1;
// $TEST$ warning "Names of block lambda results should be lowerCamelCase."
yield »_lambdaResultUnderscore« = 1;
// $TEST$ warning "Names of block lambda results should be lowerCamelCase."
Expand Down
2 changes: 2 additions & 0 deletions tests/resources/validation/names/casing/classes.sdstest
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package tests.validation.names.casing

// $TEST$ no warning "Names of classes should be UpperCamelCase."
class »ClassUppercase1«
// $TEST$ no warning "Names of classes should be UpperCamelCase."
class »`ClassUppercase2`«
// $TEST$ warning "Names of classes should be UpperCamelCase."
class »classLowercase«
// $TEST$ warning "Names of classes should be UpperCamelCase."
Expand Down
2 changes: 2 additions & 0 deletions tests/resources/validation/names/casing/enum variants.sdstest
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package tests.validation.names.casing
enum MyEnum {
// $TEST$ no warning "Names of enum variants should be UpperCamelCase."
»EnumVariantUppercase1«
// $TEST$ no warning "Names of enum variants should be UpperCamelCase."
»`EnumVariantUppercase2`«
// $TEST$ warning "Names of enum variants should be UpperCamelCase."
»enumVariantLowercase«
// $TEST$ warning "Names of enum variants should be UpperCamelCase."
Expand Down
2 changes: 2 additions & 0 deletions tests/resources/validation/names/casing/enums.sdstest
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package tests.validation.names.casing

// $TEST$ no warning "Names of enums should be UpperCamelCase."
enum »EnumUppercase1«
// $TEST$ no warning "Names of enums should be UpperCamelCase."
enum »`EnumUppercase2`«
// $TEST$ warning "Names of enums should be UpperCamelCase."
enum »enumLowercase«
// $TEST$ warning "Names of enums should be UpperCamelCase."
Expand Down
2 changes: 2 additions & 0 deletions tests/resources/validation/names/casing/functions.sdstest
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ package tests.validation.names.casing
fun »FunctionUppercase«()
// $TEST$ no warning "Names of functions should be lowerCamelCase."
fun »functionLowercase1«()
// $TEST$ no warning "Names of functions should be lowerCamelCase."
fun »`functionLowercase2`«()
// $TEST$ warning "Names of functions should be lowerCamelCase."
fun »_functionUnderscore«()
// $TEST$ warning "Names of functions should be lowerCamelCase."
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// $TEST$ no warning "All segments of the qualified name of a package should be lowerCamelCase."
package »tests.validation.declarations.`lowercase1`«
2 changes: 2 additions & 0 deletions tests/resources/validation/names/casing/parameters.sdstest
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ fun myFunction1(
»ParameterUppercase«: Int,
// $TEST$ no warning "Names of parameters should be lowerCamelCase."
»parameterLowercase1«: Int,
// $TEST$ no warning "Names of parameters should be lowerCamelCase."
»`parameterLowercase2`«: Int,
// $TEST$ warning "Names of parameters should be lowerCamelCase."
»_parameterUnderscore«: Int,
// $TEST$ warning "Names of parameters should be lowerCamelCase."
Expand Down
2 changes: 2 additions & 0 deletions tests/resources/validation/names/casing/pipelines.sdstest
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ package tests.validation.names.casing
pipeline »PipelineUppercase« {}
// $TEST$ no warning "Names of pipelines should be lowerCamelCase."
pipeline »pipelineLowercase1« {}
// $TEST$ no warning "Names of pipelines should be lowerCamelCase."
pipeline »`pipelineLowercase2`« {}
// $TEST$ warning "Names of pipelines should be lowerCamelCase."
pipeline »_pipelineUnderscore« {}
// $TEST$ warning "Names of pipelines should be lowerCamelCase."
Expand Down
2 changes: 2 additions & 0 deletions tests/resources/validation/names/casing/placeholders.sdstest
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ pipeline myPipeline2 {
val »PlaceholderUppercase« = 1;
// $TEST$ no warning "Names of placeholders should be lowerCamelCase."
val »placeholderLowercase1« = 1;
// $TEST$ no warning "Names of placeholders should be lowerCamelCase."
val »`placeholderLowercase2`« = 1;
// $TEST$ warning "Names of placeholders should be lowerCamelCase."
val »_placeholderUnderscore« = 1;
// $TEST$ warning "Names of placeholders should be lowerCamelCase."
Expand Down
2 changes: 2 additions & 0 deletions tests/resources/validation/names/casing/results.sdstest
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ fun myFunction2() -> (
»ResultUppercase«: Int,
// $TEST$ no warning "Names of results should be lowerCamelCase."
»resultLowercase1«: Int,
// $TEST$ no warning "Names of results should be lowerCamelCase."
»`resultLowercase2`«: Int,
// $TEST$ warning "Names of results should be lowerCamelCase."
»_resultUnderscore«: Int,
// $TEST$ warning "Names of results should be lowerCamelCase."
Expand Down
2 changes: 2 additions & 0 deletions tests/resources/validation/names/casing/schemas.sdstest
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package tests.validation.names.casing

// $TEST$ no warning "Names of schemas should be UpperCamelCase."
schema »SchemaUppercase1« {}
// $TEST$ no warning "Names of schemas should be UpperCamelCase."
schema »`SchemaUppercase2`« {}
// $TEST$ warning "Names of schemas should be UpperCamelCase."
schema »schemaLowercase« {}
// $TEST$ warning "Names of schemas should be UpperCamelCase."
Expand Down
2 changes: 2 additions & 0 deletions tests/resources/validation/names/casing/segments.sdstest
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ package tests.validation.names.casing
segment »SegmentUppercase«() {}
// $TEST$ no warning "Names of segments should be lowerCamelCase."
segment »segmentLowercase1«() {}
// $TEST$ no warning "Names of segments should be lowerCamelCase."
segment »`segmentLowercase2`«() {}
// $TEST$ warning "Names of segments should be lowerCamelCase."
segment »_segmentUnderscore«() {}
// $TEST$ warning "Names of segments should be lowerCamelCase."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package tests.validation.names.casing
fun myFunction3<
// $TEST$ no warning "Names of type parameters should be UpperCamelCase."
»TypeParameterUppercase1«,
// $TEST$ no warning "Names of type parameters should be UpperCamelCase."
»`TypeParameterUppercase2`«,
// $TEST$ warning "Names of type parameters should be UpperCamelCase."
»typeParameterLowercase«,
// $TEST$ warning "Names of type parameters should be UpperCamelCase."
Expand Down
2 changes: 1 addition & 1 deletion vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
chaiConfig: {
truncateThreshold: 0,
truncateThreshold: 200,
},
coverage: {
provider: 'v8',
Expand Down

0 comments on commit 608e470

Please sign in to comment.