Skip to content

Commit c16eddf

Browse files
committed
Move parser rules to RuleError
1 parent 96fda16 commit c16eddf

28 files changed

+226
-459
lines changed

src/parser/errors.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { SourceLocation } from 'estree'
1+
import type { SourceLocation } from 'estree'
22

33
import { UNKNOWN_LOCATION } from '../constants'
4-
import { ErrorSeverity, ErrorType, Node, SourceError } from '../types'
4+
import { ErrorSeverity, ErrorType, type Node, type SourceError } from '../types'
55
import { stripIndent } from '../utils/formatters'
66

77
export class MissingSemicolonError implements SourceError {
@@ -93,3 +93,17 @@ export class DisallowedConstructError implements SourceError {
9393
}
9494
}
9595
}
96+
97+
export abstract class RuleError<T extends Node> implements SourceError {
98+
public type = ErrorType.SYNTAX
99+
public severity = ErrorSeverity.ERROR
100+
101+
constructor(public readonly node: T) {}
102+
103+
get location() {
104+
return this.node.loc ?? UNKNOWN_LOCATION
105+
}
106+
107+
public abstract explain(): string
108+
public abstract elaborate(): string
109+
}

src/parser/source/rules/bracesAroundFor.ts

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,9 @@
11
import { generate } from 'astring'
2-
import * as es from 'estree'
3-
4-
import { UNKNOWN_LOCATION } from '../../../constants'
5-
import { ErrorSeverity, ErrorType, Node, SourceError } from '../../../types'
6-
import { Rule } from '../../types'
7-
8-
export class BracesAroundForError implements SourceError {
9-
public type = ErrorType.SYNTAX
10-
public severity = ErrorSeverity.ERROR
11-
12-
constructor(public node: es.ForStatement) {}
13-
14-
get location() {
15-
return this.node.loc ?? UNKNOWN_LOCATION
16-
}
2+
import type { ForStatement } from 'estree'
3+
import type { Rule } from '../../types'
4+
import { RuleError } from '../../errors'
175

6+
export class BracesAroundForError extends RuleError<ForStatement> {
187
public explain() {
198
return 'Missing curly braces around "for" block.'
209
}
@@ -30,11 +19,11 @@ export class BracesAroundForError implements SourceError {
3019
}
3120
}
3221

33-
const bracesAroundFor: Rule<es.ForStatement> = {
22+
const bracesAroundFor: Rule<ForStatement> = {
3423
name: 'braces-around-for',
3524

3625
checkers: {
37-
ForStatement(node: es.ForStatement, _ancestors: [Node]) {
26+
ForStatement(node) {
3827
if (node.body.type !== 'BlockStatement') {
3928
return [new BracesAroundForError(node)]
4029
} else {

src/parser/source/rules/bracesAroundIfElse.ts

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,15 @@
11
import { generate } from 'astring'
2-
import * as es from 'estree'
3-
4-
import { UNKNOWN_LOCATION } from '../../../constants'
5-
import { ErrorSeverity, ErrorType, Node, SourceError } from '../../../types'
6-
import { Rule } from '../../types'
2+
import type { IfStatement } from 'estree'
3+
import type { Rule } from '../../types'
74
import { stripIndent } from '../../../utils/formatters'
5+
import { RuleError } from '../../errors'
86

9-
export class BracesAroundIfElseError implements SourceError {
10-
public type = ErrorType.SYNTAX
11-
public severity = ErrorSeverity.ERROR
12-
7+
export class BracesAroundIfElseError extends RuleError<IfStatement> {
138
constructor(
14-
public node: es.IfStatement,
9+
node: IfStatement,
1510
private branch: 'consequent' | 'alternate'
16-
) {}
17-
18-
get location() {
19-
return this.node.loc ?? UNKNOWN_LOCATION
11+
) {
12+
super(node)
2013
}
2114

2215
public explain() {
@@ -73,12 +66,12 @@ export class BracesAroundIfElseError implements SourceError {
7366
}
7467
}
7568

76-
const bracesAroundIfElse: Rule<es.IfStatement> = {
69+
const bracesAroundIfElse: Rule<IfStatement> = {
7770
name: 'braces-around-if-else',
7871

7972
checkers: {
80-
IfStatement(node: es.IfStatement, _ancestors: [Node]) {
81-
const errors: SourceError[] = []
73+
IfStatement(node) {
74+
const errors: BracesAroundIfElseError[] = []
8275
if (node.consequent && node.consequent.type !== 'BlockStatement') {
8376
errors.push(new BracesAroundIfElseError(node, 'consequent'))
8477
}

src/parser/source/rules/bracesAroundWhile.ts

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,9 @@
11
import { generate } from 'astring'
2-
import * as es from 'estree'
3-
4-
import { UNKNOWN_LOCATION } from '../../../constants'
5-
import { ErrorSeverity, ErrorType, Node, SourceError } from '../../../types'
6-
import { Rule } from '../../types'
7-
8-
export class BracesAroundWhileError implements SourceError {
9-
public type = ErrorType.SYNTAX
10-
public severity = ErrorSeverity.ERROR
11-
12-
constructor(public node: es.WhileStatement) {}
13-
14-
get location() {
15-
return this.node.loc ?? UNKNOWN_LOCATION
16-
}
2+
import type { WhileStatement } from 'estree'
3+
import type { Rule } from '../../types'
4+
import { RuleError } from '../../errors'
175

6+
export class BracesAroundWhileError extends RuleError<WhileStatement> {
187
public explain() {
198
return 'Missing curly braces around "while" block.'
209
}
@@ -27,11 +16,11 @@ export class BracesAroundWhileError implements SourceError {
2716
}
2817
}
2918

30-
const bracesAroundWhile: Rule<es.WhileStatement> = {
19+
const bracesAroundWhile: Rule<WhileStatement> = {
3120
name: 'braces-around-while',
3221

3322
checkers: {
34-
WhileStatement(node: es.WhileStatement, _ancestors: [Node]) {
23+
WhileStatement(node) {
3524
if (node.body.type !== 'BlockStatement') {
3625
return [new BracesAroundWhileError(node)]
3726
} else {

src/parser/source/rules/forStatementMustHaveAllParts.ts

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,17 @@
1-
import * as es from 'estree'
2-
3-
import { UNKNOWN_LOCATION } from '../../../constants'
4-
import { ErrorSeverity, ErrorType, SourceError } from '../../../types'
5-
import { Rule } from '../../types'
1+
import type { ForStatement } from 'estree'
2+
import type { Rule } from '../../types'
63
import { stripIndent } from '../../../utils/formatters'
4+
import { RuleError } from '../../errors'
75

8-
export class ForStatmentMustHaveAllParts implements SourceError {
9-
public type = ErrorType.SYNTAX
10-
public severity = ErrorSeverity.ERROR
6+
type ForStatementParts = keyof ForStatement
7+
const forStatementParts: ForStatementParts[] = ['init', 'test', 'update']
118

9+
export class ForStatmentMustHaveAllParts extends RuleError<ForStatement> {
1210
constructor(
13-
public node: es.ForStatement,
14-
private missingParts: string[]
15-
) {}
16-
17-
get location() {
18-
return this.node.loc ?? UNKNOWN_LOCATION
11+
node: ForStatement,
12+
private readonly missingParts: ForStatementParts[]
13+
) {
14+
super(node)
1915
}
2016

2117
public explain() {
@@ -31,12 +27,12 @@ export class ForStatmentMustHaveAllParts implements SourceError {
3127
}
3228
}
3329

34-
const forStatementMustHaveAllParts: Rule<es.ForStatement> = {
30+
const forStatementMustHaveAllParts: Rule<ForStatement> = {
3531
name: 'for-statement-must-have-all-parts',
3632

3733
checkers: {
38-
ForStatement(node: es.ForStatement) {
39-
const missingParts = ['init', 'test', 'update'].filter(part => node[part] === null)
34+
ForStatement(node) {
35+
const missingParts = forStatementParts.filter(part => node[part] === null)
4036
if (missingParts.length > 0) {
4137
return [new ForStatmentMustHaveAllParts(node, missingParts)]
4238
} else {

src/parser/source/rules/noDeclareMutable.ts

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,33 @@
11
import { generate } from 'astring'
2-
import * as es from 'estree'
3-
4-
import { UNKNOWN_LOCATION } from '../../../constants'
5-
import { Chapter, ErrorSeverity, ErrorType, Node, SourceError } from '../../../types'
6-
import { Rule } from '../../types'
2+
import type { VariableDeclaration } from 'estree'
3+
import type { Rule } from '../../types'
4+
import { getVariableDeclarationName } from '../../../utils/ast/astCreator'
5+
import { RuleError } from '../../errors'
6+
import { Chapter } from '../../../types'
77

88
const mutableDeclarators = ['let', 'var']
99

10-
export class NoDeclareMutableError implements SourceError {
11-
public type = ErrorType.SYNTAX
12-
public severity = ErrorSeverity.ERROR
13-
14-
constructor(public node: es.VariableDeclaration) {}
15-
16-
get location() {
17-
return this.node.loc ?? UNKNOWN_LOCATION
18-
}
19-
10+
export class NoDeclareMutableError extends RuleError<VariableDeclaration> {
2011
public explain() {
2112
return (
2213
'Mutable variable declaration using keyword ' + `'${this.node.kind}'` + ' is not allowed.'
2314
)
2415
}
2516

2617
public elaborate() {
27-
const name = (this.node.declarations[0].id as es.Identifier).name
18+
const name = getVariableDeclarationName(this.node)
2819
const value = generate(this.node.declarations[0].init)
2920

3021
return `Use keyword "const" instead, to declare a constant:\n\n\tconst ${name} = ${value};`
3122
}
3223
}
3324

34-
const noDeclareMutable: Rule<es.VariableDeclaration> = {
25+
const noDeclareMutable: Rule<VariableDeclaration> = {
3526
name: 'no-declare-mutable',
3627
disableFromChapter: Chapter.SOURCE_3,
3728

3829
checkers: {
39-
VariableDeclaration(node: es.VariableDeclaration, _ancestors: [Node]) {
30+
VariableDeclaration(node) {
4031
if (mutableDeclarators.includes(node.kind)) {
4132
return [new NoDeclareMutableError(node)]
4233
} else {

src/parser/source/rules/noDotAbbreviation.ts

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,9 @@
1-
import * as es from 'estree'
2-
3-
import { UNKNOWN_LOCATION } from '../../../constants'
4-
import { Chapter, ErrorSeverity, ErrorType, Node, SourceError } from '../../../types'
5-
import { Rule } from '../../types'
6-
7-
export class NoDotAbbreviationError implements SourceError {
8-
public type = ErrorType.SYNTAX
9-
public severity = ErrorSeverity.ERROR
10-
11-
constructor(public node: es.MemberExpression) {}
12-
13-
get location() {
14-
return this.node.loc ?? UNKNOWN_LOCATION
15-
}
1+
import type { MemberExpression } from 'estree'
2+
import type { Rule } from '../../types'
3+
import { RuleError } from '../../errors'
4+
import { Chapter } from '../../../types'
165

6+
export class NoDotAbbreviationError extends RuleError<MemberExpression> {
177
public explain() {
188
return 'Dot abbreviations are not allowed.'
199
}
@@ -24,13 +14,13 @@ export class NoDotAbbreviationError implements SourceError {
2414
}
2515
}
2616

27-
const noDotAbbreviation: Rule<es.MemberExpression> = {
17+
const noDotAbbreviation: Rule<MemberExpression> = {
2818
name: 'no-dot-abbreviation',
2919

3020
disableFromChapter: Chapter.LIBRARY_PARSER,
3121

3222
checkers: {
33-
MemberExpression(node: es.MemberExpression, _ancestors: [Node]) {
23+
MemberExpression(node) {
3424
if (!node.computed) {
3525
return [new NoDotAbbreviationError(node)]
3626
} else {

src/parser/source/rules/noEval.ts

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,8 @@
1-
import * as es from 'estree'
2-
3-
import { UNKNOWN_LOCATION } from '../../../constants'
4-
import { ErrorSeverity, ErrorType, Node, SourceError } from '../../../types'
5-
import { Rule } from '../../types'
6-
7-
export class NoEval implements SourceError {
8-
public type = ErrorType.SYNTAX
9-
public severity = ErrorSeverity.ERROR
10-
11-
constructor(public node: es.Identifier) {}
12-
13-
get location() {
14-
return this.node.loc ?? UNKNOWN_LOCATION
15-
}
1+
import type { Identifier } from 'estree'
2+
import { RuleError } from '../../errors'
3+
import type { Rule } from '../../types'
164

5+
export class NoEval extends RuleError<Identifier> {
176
public explain() {
187
return `eval is not allowed.`
198
}
@@ -23,11 +12,11 @@ export class NoEval implements SourceError {
2312
}
2413
}
2514

26-
const noEval: Rule<es.Identifier> = {
15+
const noEval: Rule<Identifier> = {
2716
name: 'no-eval',
2817

2918
checkers: {
30-
Identifier(node: es.Identifier, _ancestors: [Node]) {
19+
Identifier(node) {
3120
if (node.name === 'eval') {
3221
return [new NoEval(node)]
3322
} else {

src/parser/source/rules/noExportNamedDeclarationWithDefault.ts

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,10 @@
1-
import * as es from 'estree'
2-
3-
import { UNKNOWN_LOCATION } from '../../../constants'
1+
import type { ExportNamedDeclaration } from 'estree'
42
import { defaultExportLookupName } from '../../../stdlib/localImport.prelude'
5-
import { ErrorSeverity, ErrorType, Node, SourceError } from '../../../types'
6-
import { Rule } from '../../types'
3+
import type { Rule } from '../../types'
74
import syntaxBlacklist from '../syntax'
5+
import { RuleError } from '../../errors'
86

9-
export class NoExportNamedDeclarationWithDefaultError implements SourceError {
10-
public type = ErrorType.SYNTAX
11-
public severity = ErrorSeverity.ERROR
12-
13-
constructor(public node: es.ExportNamedDeclaration) {}
14-
15-
get location() {
16-
return this.node.loc ?? UNKNOWN_LOCATION
17-
}
18-
7+
export class NoExportNamedDeclarationWithDefaultError extends RuleError<ExportNamedDeclaration> {
198
public explain() {
209
return 'Export default declarations are not allowed'
2110
}
@@ -25,14 +14,14 @@ export class NoExportNamedDeclarationWithDefaultError implements SourceError {
2514
}
2615
}
2716

28-
const noExportNamedDeclarationWithDefault: Rule<es.ExportNamedDeclaration> = {
17+
const noExportNamedDeclarationWithDefault: Rule<ExportNamedDeclaration> = {
2918
name: 'no-declare-mutable',
3019
disableFromChapter: syntaxBlacklist['ExportDefaultDeclaration'],
3120

3221
checkers: {
33-
ExportNamedDeclaration(node: es.ExportNamedDeclaration, _ancestors: [Node]) {
22+
ExportNamedDeclaration(node) {
3423
const errors: NoExportNamedDeclarationWithDefaultError[] = []
35-
node.specifiers.forEach((specifier: es.ExportSpecifier) => {
24+
node.specifiers.forEach(specifier => {
3625
if (specifier.exported.name === defaultExportLookupName) {
3726
errors.push(new NoExportNamedDeclarationWithDefaultError(node))
3827
}

0 commit comments

Comments
 (0)