This commit applies `strictNullChecks` to the entire codebase to improve maintainability and type safety. Key changes include: - Remove some explicit null-checks where unnecessary. - Add necessary null-checks. - Refactor static factory functions for a more functional approach. - Improve some test names and contexts for better debugging. - Add unit tests for any additional logic introduced. - Refactor `createPositionFromRegexFullMatch` to its own function as the logic is reused. - Prefer `find` prefix on functions that may return `undefined` and `get` prefix for those that always return a value.
46 lines
1.7 KiB
TypeScript
46 lines
1.7 KiB
TypeScript
import { ILanguageSyntax } from '@/application/Parser/Script/Validation/Syntax/ILanguageSyntax';
|
|
import { ICodeLine } from '../ICodeLine';
|
|
import { ICodeValidationRule, IInvalidCodeLine } from '../ICodeValidationRule';
|
|
|
|
export class NoDuplicatedLines implements ICodeValidationRule {
|
|
constructor(private readonly syntax: ILanguageSyntax) { }
|
|
|
|
public analyze(lines: readonly ICodeLine[]): IInvalidCodeLine[] {
|
|
return lines
|
|
.map((line): IDuplicateAnalyzedLine => ({
|
|
index: line.index,
|
|
isIgnored: shouldIgnoreLine(line.text, this.syntax),
|
|
occurrenceIndices: lines
|
|
.filter((other) => other.text === line.text)
|
|
.map((duplicatedLine) => duplicatedLine.index),
|
|
}))
|
|
.filter((line) => hasInvalidDuplicates(line))
|
|
.map((line): IInvalidCodeLine => ({
|
|
index: line.index,
|
|
error: `Line is duplicated at line numbers ${line.occurrenceIndices.join(',')}.`,
|
|
}));
|
|
}
|
|
}
|
|
|
|
interface IDuplicateAnalyzedLine {
|
|
readonly index: number;
|
|
readonly occurrenceIndices: readonly number[];
|
|
readonly isIgnored: boolean;
|
|
}
|
|
|
|
function hasInvalidDuplicates(line: IDuplicateAnalyzedLine): boolean {
|
|
return !line.isIgnored && line.occurrenceIndices.length > 1;
|
|
}
|
|
|
|
function shouldIgnoreLine(codeLine: string, syntax: ILanguageSyntax): boolean {
|
|
const lowerCaseCodeLine = codeLine.toLowerCase();
|
|
const isCommentLine = () => syntax.commentDelimiters.some(
|
|
(delimiter) => lowerCaseCodeLine.startsWith(delimiter),
|
|
);
|
|
const consistsOfFrequentCommands = () => {
|
|
const trimmed = lowerCaseCodeLine.trim().split(' ');
|
|
return trimmed.every((part) => syntax.commonCodeParts.includes(part));
|
|
};
|
|
return isCommentLine() || consistsOfFrequentCommands();
|
|
}
|