Skip to content

Commit

Permalink
Support custom key funcion in custom param types
Browse files Browse the repository at this point in the history
  • Loading branch information
nene committed Mar 22, 2023
1 parent 59a6237 commit e8b8f7b
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 17 deletions.
14 changes: 8 additions & 6 deletions src/lexer/Tokenizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Token, TokenType } from './token.js';
import * as regex from './regexFactory.js';
import { ParamTypes, TokenizerOptions } from './TokenizerOptions.js';
import TokenizerEngine, { TokenRule } from './TokenizerEngine.js';
import { escapeRegExp } from './regexUtil.js';
import { escapeRegExp, patternToRegex } from './regexUtil.js';
import { equalizeWhitespace, Optional } from '../utils.js';
import { NestedComment } from './NestedComment.js';

Expand Down Expand Up @@ -227,11 +227,13 @@ export default class Tokenizer {
type: TokenType.POSITIONAL_PARAMETER,
regex: paramTypes.positional ? /[?]/y : undefined,
},
{
type: TokenType.CUSTOM_PARAMETER,
regex: regex.customParameter(paramTypes.custom),
key: v => v,
},
...paramTypes.custom.map(
(customParam): TokenRule => ({
type: TokenType.CUSTOM_PARAMETER,
regex: patternToRegex(customParam.regex),
key: customParam.key ?? (v => v),
})
),
]);
}

Expand Down
12 changes: 10 additions & 2 deletions src/lexer/TokenizerOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,16 @@ export interface ParamTypes {
// Prefixes for quoted parameter placeholders to support, e.g. :"name"
// The type of quotes will depend on `identifierTypes` option.
quoted?: (':' | '@' | '$')[];
// Array of regular expressions
custom?: RegexPattern[];
// Custom parameter type definitions
custom?: CustomParameter[];
}

export interface CustomParameter {
// Regex pattern for matching the parameter
regex: string;
// Takes the matched parameter string and returns the name of the parameter
// For example we might match "{foo}" and the name would be "foo".
key?: (text: string) => string;
}

export interface TokenizerOptions {
Expand Down
9 changes: 1 addition & 8 deletions src/lexer/regexFactory.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { sortByLengthDesc } from '../utils.js';

import { IdentChars, QuoteType, RegexPattern, VariableType } from './TokenizerOptions.js';
import { IdentChars, QuoteType, VariableType } from './TokenizerOptions.js';
import { escapeRegExp, patternToRegex, prefixesPattern, withDashes } from './regexUtil.js';

/**
Expand Down Expand Up @@ -66,13 +66,6 @@ export const parameter = (paramTypes: string[], pattern: string): RegExp | undef
return patternToRegex(`(?:${typesRegex})(?:${pattern})`);
};

export const customParameter = (patterns: RegexPattern[]): RegExp | undefined => {
if (!patterns.length) {
return undefined;
}
return patternToRegex(patterns.map(p => p.regex).join('|'));
};

const buildQStringPatterns = () => {
const specialDelimiterMap = {
'<': '>',
Expand Down
27 changes: 26 additions & 1 deletion test/options/paramTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export default function supportsParamTypes(format: FormatFn) {
// - it likely works when the other paramTypes tests work
// - it's the config that's least likely to be actually used in practice.

describe('when paramTypes.custom=[regex]', () => {
describe('when paramTypes.custom=[...]', () => {
it('replaces %blah% numbered placeholders with param values', () => {
const result = format('SELECT %1%, %2%, %3%;', {
paramTypes: { custom: [{ regex: '%[0-9]+%' }] },
Expand All @@ -70,5 +70,30 @@ export default function supportsParamTypes(format: FormatFn) {
third;
`);
});

it('supports custom function for extracting parameter name', () => {
const result = format('SELECT %1%, %2%, %3%;', {
paramTypes: { custom: [{ regex: '%[0-9]+%', key: v => v.slice(1, -1) }] },
params: { '1': 'first', '2': 'second', '3': 'third' },
});
expect(result).toBe(dedent`
SELECT
first,
second,
third;
`);
});

it('supports multiple custom param types', () => {
const result = format('SELECT %1%, {2};', {
paramTypes: { custom: [{ regex: '%[0-9]+%' }, { regex: String.raw`\{[0-9]\}` }] },
params: { '%1%': 'first', '{2}': 'second' },
});
expect(result).toBe(dedent`
SELECT
first,
second;
`);
});
});
}

0 comments on commit e8b8f7b

Please sign in to comment.