Skip to content

Commit

Permalink
Implement disable/enable comments
Browse files Browse the repository at this point in the history
Fixes #703
  • Loading branch information
nene committed Jan 21, 2024
1 parent b8455d7 commit c3ea743
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 4 deletions.
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,34 @@ format('SELECT * FROM tbl', {
});
```

### Disabling the formatter

You can disable the formatter for a section of SQL by surrounding it with disable/enable comments:

```sql
/* sql-formatter-disable */
SELECT * FROM tbl1;
/* sql-formatter-enable */
SELECT * FROM tbl2;
```

which produces:

```sql
/* sql-formatter-disable */
SELECT * FROM tbl1;
/* sql-formatter-enable */
SELECT
*
FROM
tbl2;
```

The formatter doesn't even parse the code between these comments.
So in case there's some SQL that happens to crash SQL Formatter,
you can at comment the culprit out (at least until the issue gets
fixed in SQL Formatter).

### Placeholders replacement

In addition to formatting, this library can also perform placeholder replacement in prepared SQL statements:
Expand Down
7 changes: 5 additions & 2 deletions src/formatter/ExpressionFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
CaseElseNode,
DataTypeNode,
ParameterizedDataTypeNode,
DisableCommentNode,
} from '../parser/ast.js';

import Layout, { WS } from './Layout.js';
Expand Down Expand Up @@ -134,6 +135,8 @@ export default class ExpressionFormatter {
return this.formatLineComment(node);
case NodeType.block_comment:
return this.formatBlockComment(node);
case NodeType.disable_comment:
return this.formatBlockComment(node);
case NodeType.data_type:
return this.formatDataType(node);
case NodeType.keyword:
Expand Down Expand Up @@ -367,8 +370,8 @@ export default class ExpressionFormatter {
}
}

private formatBlockComment(node: BlockCommentNode) {
if (this.isMultilineBlockComment(node)) {
private formatBlockComment(node: BlockCommentNode | DisableCommentNode) {
if (node.type === NodeType.block_comment && this.isMultilineBlockComment(node)) {
this.splitBlockComment(node.text).forEach(line => {
this.layout.add(WS.NEWLINE, WS.INDENT, line);
});
Expand Down
5 changes: 5 additions & 0 deletions src/lexer/Tokenizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ export default class Tokenizer {
// the Tokenizer config options specified for each SQL dialect
private buildRulesBeforeParams(cfg: TokenizerOptions): TokenRule[] {
return this.validRules([
{
type: TokenType.BLOCK_COMMENT,
regex:
/(\/\* *sql-formatter-disable *\*\/[\s\S]*?(?:\/\* *sql-formatter-enable *\*\/|$))/uy,
},
{
type: TokenType.BLOCK_COMMENT,
regex: cfg.nestedBlockComments ? new NestedComment() : /(\/\*[^]*?\*\/)/uy,
Expand Down
2 changes: 2 additions & 0 deletions src/lexer/token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ export enum TokenType {
CLOSE_PAREN = 'CLOSE_PAREN',
LINE_COMMENT = 'LINE_COMMENT',
BLOCK_COMMENT = 'BLOCK_COMMENT',
// Text between /* sql-formatter-disable */ and /* sql-formatter-enable */
DISABLE_COMMENT = 'DISABLE_COMMENT',
NUMBER = 'NUMBER',
NAMED_PARAMETER = 'NAMED_PARAMETER',
QUOTED_PARAMETER = 'QUOTED_PARAMETER',
Expand Down
12 changes: 10 additions & 2 deletions src/parser/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export enum NodeType {
comma = 'comma',
line_comment = 'line_comment',
block_comment = 'block_comment',
disable_comment = 'disable_comment',
}

interface BaseNode {
Expand Down Expand Up @@ -178,7 +179,13 @@ export interface BlockCommentNode extends BaseNode {
precedingWhitespace: string;
}

export type CommentNode = LineCommentNode | BlockCommentNode;
export interface DisableCommentNode extends BaseNode {
type: NodeType.disable_comment;
text: string;
precedingWhitespace: string;
}

export type CommentNode = LineCommentNode | BlockCommentNode | DisableCommentNode;

export type AstNode =
| ClauseNode
Expand All @@ -202,4 +209,5 @@ export type AstNode =
| OperatorNode
| CommaNode
| LineCommentNode
| BlockCommentNode;
| BlockCommentNode
| DisableCommentNode;
7 changes: 7 additions & 0 deletions src/parser/grammar.ne
Original file line number Diff line number Diff line change
Expand Up @@ -380,3 +380,10 @@ comment -> %BLOCK_COMMENT {%
precedingWhitespace: token.precedingWhitespace,
})
%}
comment -> %DISABLE_COMMENT {%
([token]) => ({
type: NodeType.disable_comment,
text: token.text,
precedingWhitespace: token.precedingWhitespace,
})
%}
2 changes: 2 additions & 0 deletions test/behavesLikeSqlFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ import supportsLogicalOperatorNewline from './options/logicalOperatorNewline.js'
import supportsParamTypes from './options/paramTypes.js';
import supportsWindowFunctions from './features/windowFunctions.js';
import supportsFunctionCase from './options/functionCase.js';
import supportsDisableComment from './features/disableComment.js';

/**
* Core tests for all SQL formatters
*/
export default function behavesLikeSqlFormatter(format: FormatFn) {
supportsDisableComment(format);
supportsCase(format);
supportsNumbers(format);
supportsWith(format);
Expand Down
65 changes: 65 additions & 0 deletions test/features/disableComment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import dedent from 'dedent-js';

import { FormatFn } from '../../src/sqlFormatter.js';

export default function supportsDisableComment(format: FormatFn) {
it('does not format text between /* sql-formatter-disable */ and /* sql-formatter-enable */', () => {
const result = format(dedent`
SELECT foo FROM bar;
/* sql-formatter-disable */
SELECT foo FROM bar;
/* sql-formatter-enable */
SELECT foo FROM bar;
`);

expect(result).toBe(dedent`
SELECT
foo
FROM
bar;
/* sql-formatter-disable */
SELECT foo FROM bar;
/* sql-formatter-enable */
SELECT
foo
FROM
bar;
`);
});

it('does not format text after /* sql-formatter-disable */ until end of file', () => {
const result = format(dedent`
SELECT foo FROM bar;
/* sql-formatter-disable */
SELECT foo FROM bar;
SELECT foo FROM bar;
`);

expect(result).toBe(dedent`
SELECT
foo
FROM
bar;
/* sql-formatter-disable */
SELECT foo FROM bar;
SELECT foo FROM bar;
`);
});

it('does not parse code between disable/enable comments', () => {
const result = format(dedent`
SELECT /*sql-formatter-disable*/ ?!{}[] /*sql-formatter-enable*/ FROM bar;
`);

expect(result).toBe(dedent`
SELECT
/*sql-formatter-disable*/ ?!{}[] /*sql-formatter-enable*/
FROM
bar;
`);
});
}

0 comments on commit c3ea743

Please sign in to comment.