Skip to content

Commit

Permalink
feat: support any string value in map and join
Browse files Browse the repository at this point in the history
  • Loading branch information
merceyz committed Sep 29, 2024
1 parent bff855a commit ec596ca
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 22 deletions.
57 changes: 36 additions & 21 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,27 @@ export function getQueryValue(
}

if (arg.type === TSESTree.AST_NODE_TYPES.TemplateLiteral) {
if (arg.expressions.every((expr) => isVariableParameterExpression(expr))) {
return {
value: arg.quasis.map((quasi) => quasi.value.cooked).join("?"),
};
let query = "";

for (let i = 0; i < arg.quasis.length; i++) {
const quasi = arg.quasis[i];
if (quasi) {
query += quasi.value.cooked;

const expr = arg.expressions[i];
if (expr) {
const value = getParameterExpressionValue(expr);
if (value == null) {
return null;
}
query += value;
}
}
}

return null;
return {
value: query,
};
}

if (arg.type === TSESTree.AST_NODE_TYPES.Identifier) {
Expand All @@ -63,61 +77,62 @@ export function getQueryValue(
}

/**
* Checks if the expression looks like `foo.map(() => '?').join(',')`
* If the expression looks like `foo.map(() => '<value>').join('<separator>')`
* then the value of the map callback is returned.
*/
function isVariableParameterExpression(expr: TSESTree.Expression) {
function getParameterExpressionValue(expr: TSESTree.Expression) {
if (expr.type !== TSESTree.AST_NODE_TYPES.CallExpression || expr.optional) {
return false;
return null;
}

if (expr.callee.type !== TSESTree.AST_NODE_TYPES.MemberExpression) {
return false;
return null;
}

if (!expr.arguments[0]) {
return false;
return null;
}

if (ASTUtils.getPropertyName(expr.callee) !== "join") {
return false;
return null;
}

const joinValue = ASTUtils.getStaticValue(expr.arguments[0]);
if (typeof joinValue?.value !== "string" || joinValue.value.trim() !== ",") {
return false;
if (typeof joinValue?.value !== "string") {
return null;
}

if (
expr.callee.object.type !== TSESTree.AST_NODE_TYPES.CallExpression ||
expr.callee.object.optional
) {
return false;
return null;
}

const maybeMapExpr = expr.callee.object;

if (maybeMapExpr.callee.type !== TSESTree.AST_NODE_TYPES.MemberExpression) {
return false;
return null;
}

if (ASTUtils.getPropertyName(maybeMapExpr.callee) !== "map") {
return false;
return null;
}

if (!maybeMapExpr.arguments[0]) {
return false;
return null;
}

const maybeCallback = maybeMapExpr.arguments[0];

if (maybeCallback.type !== TSESTree.AST_NODE_TYPES.ArrowFunctionExpression) {
return false;
return null;
}

const mapValue = ASTUtils.getStaticValue(maybeCallback.body);
if (typeof mapValue?.value !== "string" || mapValue.value.trim() !== "?") {
return false;
if (typeof mapValue?.value !== "string") {
return null;
}

return true;
return mapValue.value;
}
12 changes: 11 additions & 1 deletion tests/rules/valid-query.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ db.exec(`

const db_users = new SQLite(":memory:");
db_users.exec(`
CREATE TABLE users (id int);
CREATE TABLE users (id int, name text);
`);

const rule = createValidQueryRule({
Expand All @@ -36,6 +36,8 @@ ruleTester.run("valid-query", rule, {
"db.prepare('DELETE FROM foo')",
"db_users.prepare(`SELECT * FROM users WHERE id IN (${ids.map(() => '?').join(',')})`);",
"const query = `SELECT * FROM users WHERE id IN (${ids.map(() => '?').join(',')})`;db_users.prepare(query);",
"db_users.prepare(`SELECT * FROM users WHERE ${ids.map(() => 'NAME LIKE ? || \\'%\\'').join(' OR ')}`);",
"const query = `SELECT * FROM users WHERE ${ids.map(() => 'NAME LIKE ? || \\'%\\'').join(' OR ')}`;db_users.prepare(query);",
],
invalid: [
{
Expand All @@ -46,6 +48,14 @@ ruleTester.run("valid-query", rule, {
},
],
},
{
code: "db_users.prepare(`SELECT * FROM users WHERE ${ids.map(() => unknownValue).join(' OR ')}`);",
errors: [
{
messageId: "nonStaticQuery",
},
],
},
{
code: "db.prepare(42)",
errors: [
Expand Down

0 comments on commit ec596ca

Please sign in to comment.