File tree Expand file tree Collapse file tree 6 files changed +152
-0
lines changed Expand file tree Collapse file tree 6 files changed +152
-0
lines changed Original file line number Diff line number Diff line change @@ -133,6 +133,21 @@ const user = db
133133 .all ();
134134` ` `
135135
136+ ### parameter-prefix
137+
138+ Enforce that all queries use the same prefix for named parameters.
139+ Can be configured to one of ` : ` (default), ` @` , or ` $` .
140+
141+ ` ` ` ts
142+ // Bad
143+ /* eslint "sqlite/parameter-prefix": ["error", ":"] */
144+ db .prepare (" SELECT * FROM users WHERE id = @id" );
145+
146+ // Good
147+ /* eslint "sqlite/parameter-prefix": ["error", ":"] */
148+ db .prepare (" SELECT * FROM users WHERE id = :id" );
149+ ` ` `
150+
136151## License
137152
138153eslint-plugin-sqlite is licensed under the [MIT License](LICENSE) and
Original file line number Diff line number Diff line change 11pub mod nullable;
22pub mod parameters;
3+ pub mod prefix;
34pub mod query;
Original file line number Diff line number Diff line change 1+ use fallible_iterator:: FallibleIterator ;
2+ use sqlite3_parser:: {
3+ ast:: { fmt:: ToTokens , ParameterInfo } ,
4+ lexer:: sql:: Parser ,
5+ } ;
6+ use wasm_bindgen:: prelude:: * ;
7+
8+ #[ wasm_bindgen]
9+ pub fn does_all_named_parameters_start_with_prefix ( query : & str , prefix : char ) -> Option < bool > {
10+ let mut parser = Parser :: new ( query. as_bytes ( ) ) ;
11+ let cmd = parser. next ( ) . ok ( ) ??;
12+
13+ let mut parameters = ParameterInfo :: default ( ) ;
14+
15+ cmd. to_tokens ( & mut parameters) . ok ( ) ?;
16+
17+ Some ( parameters. names . iter ( ) . all ( |n| n. starts_with ( prefix) ) )
18+ }
Original file line number Diff line number Diff line change @@ -4,6 +4,7 @@ import type { TSESLint } from "@typescript-eslint/utils";
44import SQLite from "better-sqlite3" ;
55
66import { GetDatabaseOptions , RuleOptions } from "./ruleOptions.js" ;
7+ import { parameterPrefixRule } from "./rules/parameter-prefix.js" ;
78import { typedInputRule } from "./rules/typed-input.js" ;
89import { createTypedResultRule } from "./rules/typed-result.js" ;
910import { createValidQueryRule } from "./rules/valid-query.js" ;
@@ -67,6 +68,7 @@ export function createSqlitePlugin(options: CreatePluginOptions) {
6768 "valid-query" : createValidQueryRule ( ruleOptions ) ,
6869 "typed-result" : createTypedResultRule ( ruleOptions ) ,
6970 "typed-input" : typedInputRule ,
71+ "parameter-prefix" : parameterPrefixRule ,
7072 } ,
7173 } satisfies TSESLint . FlatConfig . Plugin ;
7274
Original file line number Diff line number Diff line change 1+ import { ESLintUtils , TSESTree } from "@typescript-eslint/utils" ;
2+
3+ import { does_all_named_parameters_start_with_prefix } from "../parser/parser.js" ;
4+ import { getQueryValue } from "../utils.js" ;
5+
6+ export const parameterPrefixRule = ESLintUtils . RuleCreator . withoutDocs ( {
7+ create ( context , options ) {
8+ const expectedPrefix = options [ 0 ] ;
9+
10+ return {
11+ 'CallExpression[callee.type=MemberExpression][callee.property.name="prepare"][arguments.length=1]' (
12+ node : Omit < TSESTree . CallExpression , "arguments" | "callee" > & {
13+ arguments : [ TSESTree . CallExpression [ "arguments" ] [ 0 ] ] ;
14+ callee : TSESTree . MemberExpression ;
15+ } ,
16+ ) {
17+ const arg = node . arguments [ 0 ] ;
18+
19+ const val = getQueryValue ( arg , context . sourceCode . getScope ( arg ) ) ;
20+
21+ if ( typeof val ?. value !== "string" ) {
22+ return ;
23+ }
24+
25+ const result = does_all_named_parameters_start_with_prefix (
26+ val . value ,
27+ expectedPrefix ,
28+ ) ;
29+
30+ if ( result === false ) {
31+ context . report ( {
32+ node : arg ,
33+ messageId : "incorrectPrefixUsed" ,
34+ data : {
35+ prefix : expectedPrefix ,
36+ } ,
37+ } ) ;
38+ }
39+ } ,
40+ } ;
41+ } ,
42+ meta : {
43+ messages : {
44+ incorrectPrefixUsed :
45+ "Query uses a named parameter prefix that isn't permitted, use '{{prefix}}' instead." ,
46+ } ,
47+ schema : [
48+ {
49+ type : "string" ,
50+ enum : [ ":" , "@" , "$" ] ,
51+ } ,
52+ ] ,
53+ type : "problem" ,
54+ } ,
55+ defaultOptions : [ ":" ] ,
56+ } ) ;
Original file line number Diff line number Diff line change 1+ import { parameterPrefixRule } from "../../src/rules/parameter-prefix.js" ;
2+ import { ruleTester } from "./rule-tester.js" ;
3+
4+ ruleTester . run ( "parameter-prefix" , parameterPrefixRule , {
5+ valid : [
6+ {
7+ code : "db.prepare('SELECT * FROM foo WHERE id = :id')" ,
8+ } ,
9+ {
10+ code : "db.prepare('SELECT * FROM foo WHERE id = :id')" ,
11+ options : [ ":" ] ,
12+ } ,
13+ {
14+ code : "db.prepare('SELECT * FROM foo WHERE id = @id')" ,
15+ options : [ "@" ] ,
16+ } ,
17+ {
18+ code : "db.prepare('SELECT * FROM foo WHERE id = $id')" ,
19+ options : [ "$" ] ,
20+ } ,
21+ ] ,
22+ invalid : [
23+ {
24+ code : 'db.prepare("SELECT * FROM foo WHERE id = :id")' ,
25+ options : [ "@" ] ,
26+ errors : [
27+ {
28+ messageId : "incorrectPrefixUsed" ,
29+ data : {
30+ prefix : "@" ,
31+ } ,
32+ } ,
33+ ] ,
34+ } ,
35+ {
36+ code : 'db.prepare("SELECT * FROM foo WHERE id = @id")' ,
37+ options : [ "$" ] ,
38+ errors : [
39+ {
40+ messageId : "incorrectPrefixUsed" ,
41+ data : {
42+ prefix : "$" ,
43+ } ,
44+ } ,
45+ ] ,
46+ } ,
47+ {
48+ code : 'db.prepare("SELECT * FROM foo WHERE id = $id")' ,
49+ options : [ ":" ] ,
50+ errors : [
51+ {
52+ messageId : "incorrectPrefixUsed" ,
53+ data : {
54+ prefix : ":" ,
55+ } ,
56+ } ,
57+ ] ,
58+ } ,
59+ ] ,
60+ } ) ;
You can’t perform that action at this time.
0 commit comments