prisma-lint
Advanced tools
Comparing version 0.5.0 to 0.6.0
import { PrismaPropertyType } from '#src/common/prisma.js'; | ||
const IGNORE_MODEL = '/// prisma-lint-ignore-model'; | ||
const IGNORE_ENUM = '/// prisma-lint-ignore-enum'; | ||
export function listIgnoreModelComments(node) { | ||
@@ -9,11 +10,23 @@ const commentFields = node.properties.filter((p) => p.type === PrismaPropertyType.COMMENT); | ||
} | ||
export function isModelEntirelyIgnored(ignoreModelComments) { | ||
return ignoreModelComments.includes(IGNORE_MODEL); | ||
export function listIgnoreEnumComments(node) { | ||
const commentFields = node.enumerators.filter((enumerator) => enumerator.type === 'comment'); | ||
return commentFields | ||
.map((f) => f.text.trim()) | ||
.filter((t) => t.startsWith(IGNORE_ENUM)); | ||
} | ||
export function isModelEntirelyIgnored(ignoreComments) { | ||
return ignoreComments.includes(IGNORE_MODEL); | ||
} | ||
export function isEnumEntirelyIgnored(ignoreComments) { | ||
return ignoreComments.includes(IGNORE_ENUM); | ||
} | ||
export function isRuleEntirelyIgnored(ruleName, ignoreModelComments) { | ||
return ignoreModelComments.includes(`${IGNORE_MODEL} ${ruleName}`); | ||
return (ignoreModelComments.includes(`${IGNORE_MODEL} ${ruleName}`) || | ||
ignoreModelComments.includes(`${IGNORE_ENUM} ${ruleName}`)); | ||
} | ||
export function getRuleIgnoreParams(model, ruleName) { | ||
const ignoreModelComments = listIgnoreModelComments(model); | ||
const ruleIgnoreComment = ignoreModelComments.find((c) => c.startsWith(`${IGNORE_MODEL} ${ruleName} `)); | ||
export function getRuleIgnoreParams(node, ruleName) { | ||
const ignoreComments = node.type === 'model' | ||
? listIgnoreModelComments(node) | ||
: listIgnoreEnumComments(node); | ||
const ruleIgnoreComment = ignoreComments.find((c) => c.startsWith(`${node.type === 'model' ? IGNORE_MODEL : IGNORE_ENUM} ${ruleName} `)); | ||
if (ruleIgnoreComment == null) { | ||
@@ -20,0 +33,0 @@ return []; |
import { getPrismaSchema } from '#src/common/get-prisma-schema.js'; | ||
import { isModelEntirelyIgnored, isRuleEntirelyIgnored, listIgnoreModelComments, } from '#src/common/ignore.js'; | ||
import { isModelEntirelyIgnored, isRuleEntirelyIgnored, listIgnoreModelComments, listIgnoreEnumComments, isEnumEntirelyIgnored, } from '#src/common/ignore.js'; | ||
import { listModelBlocks, listFields, listEnumBlocks, listCustomTypeBlocks, } from '#src/common/prisma.js'; | ||
@@ -48,3 +48,16 @@ export function lintPrismaSourceCode({ rules, fileName, sourceCode, }) { | ||
}); | ||
enums.forEach((enumObj) => { | ||
const comments = listIgnoreEnumComments(enumObj); | ||
if (isEnumEntirelyIgnored(comments)) { | ||
return; | ||
} | ||
namedRuleInstances | ||
.filter(({ ruleName }) => !isRuleEntirelyIgnored(ruleName, comments)) | ||
.forEach(({ ruleInstance }) => { | ||
if ('Enum' in ruleInstance) { | ||
ruleInstance.Enum(enumObj); | ||
} | ||
}); | ||
}); | ||
return violations; | ||
} |
@@ -8,3 +8,3 @@ import chalk from 'chalk'; | ||
const { fileName } = first; | ||
const rawLocation = first.field?.location ?? first.model.location; | ||
const rawLocation = first.field?.location ?? first.model?.location ?? first.enum?.location; | ||
if (!rawLocation) { | ||
@@ -11,0 +11,0 @@ throw new Error('No location'); |
@@ -11,3 +11,3 @@ import { keyViolationListPairs } from '#src/output/render/render-util.js'; | ||
const { fileName } = first; | ||
const rawLocation = first.field?.location ?? first.model.location; | ||
const rawLocation = first.field?.location ?? first.model?.location ?? first.enum?.location; | ||
if (!rawLocation) { | ||
@@ -14,0 +14,0 @@ throw new Error('No location'); |
@@ -7,3 +7,3 @@ import chalk from 'chalk'; | ||
const first = violations[0]; | ||
const location = first.field?.location ?? first.model.location; | ||
const location = first.field?.location ?? first.model?.location ?? first.enum?.location; | ||
if (!location) { | ||
@@ -10,0 +10,0 @@ throw new Error('No location'); |
export const keyViolationListPairs = (violations) => { | ||
const groupedByKey = violations.reduce((acc, violation) => { | ||
const { model, field } = violation; | ||
const key = field ? `${model.name}.${field.name}` : model.name; | ||
const { model, field, enum: enumObj } = violation; | ||
const key = field | ||
? `${model.name}.${field.name}` | ||
: enumObj | ||
? enumObj.name | ||
: model.name; | ||
const violations = acc[key] ?? []; | ||
@@ -6,0 +10,0 @@ return { ...acc, [key]: [...violations, violation] }; |
@@ -0,1 +1,5 @@ | ||
import banUnboundedStringType from '#src/rules/ban-unbounded-string-type.js'; | ||
import enumNamePascalCase from '#src/rules/enum-name-pascal-case.js'; | ||
import enumValueSnakeCase from '#src/rules/enum-value-snake-case.js'; | ||
import fieldNameCamelCase from '#src/rules/field-name-camel-case.js'; | ||
import fieldNameMappingSnakeCase from '#src/rules/field-name-mapping-snake-case.js'; | ||
@@ -7,2 +11,3 @@ import fieldOrder from '#src/rules/field-order.js'; | ||
import modelNameMappingSnakeCase from '#src/rules/model-name-mapping-snake-case.js'; | ||
import modelNamePascalCase from '#src/rules/model-name-pascal-case.js'; | ||
import modelNamePrefix from '#src/rules/model-name-prefix.js'; | ||
@@ -14,2 +19,6 @@ import requireDefaultEmptyArrays from '#src/rules/require-default-empty-arrays.js'; | ||
export default [ | ||
banUnboundedStringType, | ||
enumNamePascalCase, | ||
enumValueSnakeCase, | ||
fieldNameCamelCase, | ||
fieldNameMappingSnakeCase, | ||
@@ -21,2 +30,3 @@ fieldOrder, | ||
modelNameMappingSnakeCase, | ||
modelNamePascalCase, | ||
modelNamePrefix, | ||
@@ -23,0 +33,0 @@ requireDefaultEmptyArrays, |
@@ -16,7 +16,4 @@ import { z } from 'zod'; | ||
* | ||
* This rule support selectively ignoring fields via the | ||
* `prisma-lint-ignore-model` comment, like so: | ||
* This rule support selectively ignoring fields with parameterized comments. | ||
* | ||
* /// prisma-lint-ignore-model field-name-mapping-snake-case tenantId | ||
* | ||
* That will ignore only `tenantId` field violations for the model. Other | ||
@@ -103,2 +100,17 @@ * fields will still be enforced. A comma-separated list of fields can be | ||
* | ||
* @example parameterized | ||
* // good | ||
* type Post { | ||
* /// prisma-lint-ignore-model field-name-mapping-snake-case tenantId | ||
* tenantId String | ||
* userId String @map(name: "user_id") | ||
* } | ||
* | ||
* // bad | ||
* type Post { | ||
* /// prisma-lint-ignore-model field-name-mapping-snake-case tenantId | ||
* tenantId String | ||
* userId String | ||
* } | ||
* | ||
*/ | ||
@@ -105,0 +117,0 @@ export default { |
{ | ||
"name": "prisma-lint", | ||
"version": "0.5.0", | ||
"version": "0.6.0", | ||
"description": "A linter for Prisma schema files.", | ||
@@ -48,6 +48,6 @@ "repository": { | ||
"@types/jest": "^29.2.5", | ||
"@types/node": "^20.2.5", | ||
"@types/node": "^22.2.0", | ||
"@types/pluralize": "^0.0.33", | ||
"@typescript-eslint/eslint-plugin": "^7.0.2", | ||
"@typescript-eslint/parser": "^7.0.2", | ||
"@typescript-eslint/eslint-plugin": "^8.1.0", | ||
"@typescript-eslint/parser": "^8.1.0", | ||
"eslint": "^8.41.0", | ||
@@ -62,3 +62,3 @@ "eslint-config-prettier": "^9.0.0", | ||
"lint-staged": "^15.0.1", | ||
"prettier": "3.2.5", | ||
"prettier": "3.3.3", | ||
"ts-jest": "^29.1.0", | ||
@@ -65,0 +65,0 @@ "typescript": "^5.0.4" |
76896
42
2248