eslint-plugin-slonik 1.9.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -1
- package/dist/index.cjs +32 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +32 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -81,8 +81,8 @@ export default [
|
|
|
81
81
|
| `sql.jsonb(value)` | ✅ Full | Extracts type → `$1::jsonb` |
|
|
82
82
|
| `sql.literalValue(value)` | ✅ Full | Extracts type → `$1` |
|
|
83
83
|
| `sql.uuid(str)` | ✅ Full | Extracts type → `$1::uuid` |
|
|
84
|
+
| `sql.binary(buffer)` | ✅ Full | Extracts type → `$1::bytea` |
|
|
84
85
|
| `sql.join([...], glue)` | ✅ Skip | Skipped (runtime content) |
|
|
85
|
-
| `sql.binary(buffer)` | ✅ Skip | Skipped |
|
|
86
86
|
|
|
87
87
|
### How It Works
|
|
88
88
|
|
|
@@ -143,6 +143,12 @@ sql.type(z.object({ id: z.number() }))`
|
|
|
143
143
|
SELECT id FROM users WHERE external_id = ${sql.uuid(externalId)}
|
|
144
144
|
`;
|
|
145
145
|
// → Validates: SELECT id FROM users WHERE external_id = $1::uuid
|
|
146
|
+
|
|
147
|
+
// sql.binary for binary data
|
|
148
|
+
sql.type(z.object({ id: z.number() }))`
|
|
149
|
+
UPDATE files SET content = ${sql.binary(buffer)} WHERE id = ${id}
|
|
150
|
+
`;
|
|
151
|
+
// → Validates: UPDATE files SET content = $1::bytea WHERE id = $2
|
|
146
152
|
```
|
|
147
153
|
|
|
148
154
|
**Graceful Skip** means the plugin recognizes Slonik tokens and skips validation for those expressions, preventing false positives:
|
package/dist/index.cjs
CHANGED
|
@@ -477,6 +477,20 @@ function isSlonikUuidCall(expression) {
|
|
|
477
477
|
const objectName = getMemberExpressionObjectName(callee.object);
|
|
478
478
|
return objectName === "sql";
|
|
479
479
|
}
|
|
480
|
+
function isSlonikBinaryCall(expression) {
|
|
481
|
+
if (expression.type !== "CallExpression") {
|
|
482
|
+
return false;
|
|
483
|
+
}
|
|
484
|
+
const callee = expression.callee;
|
|
485
|
+
if (callee.type !== "MemberExpression") {
|
|
486
|
+
return false;
|
|
487
|
+
}
|
|
488
|
+
if (callee.property.type !== "Identifier" || callee.property.name !== "binary") {
|
|
489
|
+
return false;
|
|
490
|
+
}
|
|
491
|
+
const objectName = getMemberExpressionObjectName(callee.object);
|
|
492
|
+
return objectName === "sql";
|
|
493
|
+
}
|
|
480
494
|
function extractSlonikFragment(expression) {
|
|
481
495
|
if (expression.type !== "TaggedTemplateExpression") {
|
|
482
496
|
return null;
|
|
@@ -724,6 +738,24 @@ function mapTemplateLiteralToQueryText(quasi, parser, checker, options, sourceCo
|
|
|
724
738
|
});
|
|
725
739
|
continue;
|
|
726
740
|
}
|
|
741
|
+
if (isSlonikBinaryCall(expression)) {
|
|
742
|
+
const placeholder2 = `$${++$idx}::bytea`;
|
|
743
|
+
$queryText += placeholder2;
|
|
744
|
+
sourcemaps.push({
|
|
745
|
+
original: {
|
|
746
|
+
start: expression.range[0] - quasi.range[0] - 2,
|
|
747
|
+
end: expression.range[1] - quasi.range[0],
|
|
748
|
+
text: sourceCode.text.slice(expression.range[0] - 2, expression.range[1] + 1)
|
|
749
|
+
},
|
|
750
|
+
generated: {
|
|
751
|
+
start: position,
|
|
752
|
+
end: position + placeholder2.length,
|
|
753
|
+
text: placeholder2
|
|
754
|
+
},
|
|
755
|
+
offset: 0
|
|
756
|
+
});
|
|
757
|
+
continue;
|
|
758
|
+
}
|
|
727
759
|
const slonikUnnestTypes = extractSlonikUnnestTypes(expression);
|
|
728
760
|
if (slonikUnnestTypes !== null) {
|
|
729
761
|
const placeholders = slonikUnnestTypes.map((type) => `$${++$idx}::${type}`);
|