Node.jsnpmprismaprisma-lint

prisma-lint の ルール一覧

はじめに

prisma-lint に設定できる Rule は RULES.md に記載。 RULES.md の内容を日本語で説明したく訳を作成しました。

:::note warn 2024/11時点の情報です。最新の情報は下記URLを確認してください。

:::

ルール

ban-unbounded-string-type

文字列フィールドが長さを制限するために、データベースネイティブの型で定義されていることを確認する(例: @db.VarChar(x))。 意図せず無制限の長さをサポートするAPIを構築しないようにすることを目的としている。 このルールは https://brandur.org/text に影響を受け作成された。

設定

z.object({
  allowNativeTextType: z.boolean().optional(),
}).strict();

// OK
model User {
  id String @db.VarChar(36)
}

// NG
model User {
  id String
}

// NG
model User {
 id String @db.Text
}
// OK
model User {
  id String @db.Text
}

enum-name-pascal-case

Enum 型の名前が PascalCase であることを確認する。

設定

z.object({
  allowList: z.array(z.union([z.string(), z.instanceof(RegExp)])).optional(),
  trimPrefix: z
    .union([
      z.string(),
      z.instanceof(RegExp),
      z.array(z.union([z.string(), z.instanceof(RegExp)])),
    ])
    .optional(),
}).strict();

// OK
enum ExampleOptions {
  value1
}

// NG
enum exampleOptions {
  value1
}

// NG
enum example_options {
 value1
}

enum-value-snake-case

列挙型の値が snake_case であることを確認する。 このルールは、特定の列挙型の値を無視するためにprisma-lint-ignore-enumコメントが使用可能。

/// prisma-lint-ignore-enum enum-value-snake-case SCREAMING_SNAKE

上記記述によって SCREAMING_SNAKE が許可される。それ以外の値はsnake_caseである必要がある。

設定

z.object({
  allowList: z.array(z.union([z.string(), z.instanceof(RegExp)])).optional(),
  trimPrefix: z
    .union([
      z.string(),
      z.instanceof(RegExp),
      z.array(z.union([z.string(), z.instanceof(RegExp)])),
    ])
    .optional(),
}).strict();

// OK
enum Example {
  value
}

// OK
enum Example {
  value_1
}

// NG
enum Example {
  Value
}

// NG
enum Example {
  VALUE
}

// NG
enum Example {
  camelCase
}

field-name-camel-case

フィールド名がキャメルケースで記述されていることを確認する。

設定

z.object({
  allowList: z.array(z.union([z.string(), z.instanceof(RegExp)])).optional(),
  trimPrefix: z
    .union([
      z.string(),
      z.instanceof(RegExp),
      z.array(z.union([z.string(), z.instanceof(RegExp)])),
    ])
    .optional(),
}).strict();

// OK
model User {
  rowId String @id
}

// NG
model User {
  RowId String @id
}

// NG
model User {
 row_id String @id
}

field-name-mapping-snake-case

フィールドのマッピング名がスネークケースであることを確認する。

設定

z.object({
  compoundWords: z.array(z.string()).optional(),
  requireUnderscorePrefixForIds: z.boolean().optional(),
})
  .strict()
  .optional();

// OK
model UserRole {
  userId String @map(name: "user_id")
}

model UserRole {
  // 単語のみで構成されるフィールド名はマッピング不要
  id String
  // 関連フィールドはマッピング不要
  grantedByUser User
}

// NG
model UserRole {
  userId String
}

model UserRole {
  userId String @map(name: "user_i_d")
}
// OK
model PersistedQuery {
  graphQLId String @map(name: "graphql_id")
}

// NG
model PersistedQuery {
  graphQLId String @map(name: "graph_q_l_id")
}
// OK
model PersistedQuery {
  id String @id @map(name: "_id")
  otherField String @map(name: "other_field")
}

// NG
model PersistedQuery {
  id String @id @map(name: "id")
  otherField String @map(name: "other_field")
}
// OK
enum RoleType {
  ADMIN
  MEMBER
}

model UserRole {
  roleType RoleType @map(name: "role_type")
}

// NG
model UserRole {
  roleType RoleType
}
// OK
type UserInfo {
  institution String
}

model User {
  userInfo UserInfo @map(name: "user_info")
}

// NG
model User {
  userInfo UserInfo
}
// OK
type Post {
  /// prisma-lint-ignore-model field-name-mapping-snake-case tenantId
  tenantId String
  userId String @map(name: "user_id")
}

// NG
type Post {
  /// prisma-lint-ignore-model field-name-mapping-snake-case tenantId
  tenantId String
  userId String
}

field-order

モデル内のフィールドが指定された順序で並んでいることを確認する。

order リストに含まれないフィールドは無視。 フィールドを必須にする場合は、require-field ルールを使用する。

order リストの最初のフィールドはモデルの先頭に、最後のフィールドはモデルの末尾に配置されることが要求される。特別なフィールド名 ... は、その位置に任意の数のフィールドが配置可能であることを示す。

設定

z.object({
  order: z.array(z.string()),
}).strict();

// OK
model User {
  tenantId String
  id String @id
  email String
}

model User {
  tenantId String
  id String @id
  createdAt DateTime
  email String
}

// NG
model User {
  id String @id
  email String
  tenantId String
}
// OK
model User {
  tenantId String
  id String
  email String
  createdAt DateTime
  updatedAt DateTime
}

model User {
  tenantId String
  id String
  email String
  createdAt DateTime
}

// NG
model User {
  id String @id
  createdAt DateTime
  email String
}

forbid-field

特定の名前のフィールドを禁止する。

設定

z.object({
  forbid: z.array(z.union([z.string(), z.instanceof(RegExp)])),
}).strict();

// OK
type Product {
  uuid String
}

// NG
type Product {
  id String
}
// OK
type Product {
  id String
  priceAmountD6 Int
}

// NG
type Product {
  id Int
  priceD6 Int
}

forbid-required-ignored-field

デフォルト値のない必須の無視されたフィールドを禁止する。

このルールは、フィールドがクライアントに生成されない一方で、データベースが対応する非NULL列を要求することを防ぐ。

さらなる保護を検討する場合は、Prisma Safety の使用を推奨。

// OK
type Product {
  uuid String
  toBeRemoved String? @ignore
}

// OK
type Product {
  uuid String
  toBeRemoved Boolean @default(false) @ignore
}

// NG
type Product {
  uuid String
  toBeRemoved String @ignore
}

model-name-grammatical-number

モデル名が単数形または複数形のスタイルに準拠しているかをチェックする。

文法的数 (Grammatical number) に基づき、モデル名を制約する。

設定

z.object({
  style: z.enum(['singular', 'plural']),
  allowlist: z.array(z.union([z.string(), z.instanceof(RegExp)])).optional(),
}).strict();

// OK
model User {
  id String @id
}

// NG
model Users {
  id String @id
}
// OK
model Users {
  id String @id
}

// NG
model User {
  id String @id
}
// OK
model UserData {
  id String @id
}

model User {
  id String @id
}

// NG ("Data" はデフォルトで複数形と見なされる)
model TenantData {
  id String @id
}

model Users {
  id String @id
}
// OK
model UserData {
  id String @id
}

model TenantData {
  id String @id
}

// NG
model DataRecords {
  id String @id
}

model Users {
  id String @id
}

model-name-mapping-snake-case

モデルのマッピング名がスネークケース (snake_case) に準拠しているかをチェックする。

設定

z.object({
  compoundWords: z.array(z.string()).optional(),
  irregularPlurals: z.record(z.string()).optional(),
  pluralize: z.boolean().optional(),
  trimPrefix: z.string().optional(),
})
  .strict()
  .optional();

// OK
model UserRole {
  id String @id
  @@map(name: "user_role")
}

// NG
model UserRole {
  id String @id
}

model UserRole {
  id String @id
  @@map(name: "user_roles")
}
// OK
model DbUserRole {
  id String @id
  @@map(name: "user_role")
}

// NG
model DbUserRole {
  id String @id
  @@map(name: "db_user_role")
}
// OK
model GraphQLPersistedQuery {
  id String @id
  @@map(name: "graphql_persisted_query")
}

// NG
model GraphQLPersistedQuery {
  id String @id
  @@map(name: "graph_q_l_persisted_query")
}
// OK
model UserRole {
  id String @id
  @@map(name: "user_roles")
}

// NG
model UserRole {
  id String @id
}

model UserRole {
  id String @id
  @@map(name: "user_role")
}

model-name-pascal-case

モデル名がパスカルケース (PascalCase) に準拠しているかをチェックする。

設定

z.object({
  allowList: z.array(z.union([z.string(), z.instanceof(RegExp)])).optional(),
  trimPrefix: z
    .union([
      z.string(),
      z.instanceof(RegExp),
      z.array(z.union([z.string(), z.instanceof(RegExp)])),
    ])
    .optional(),
}).strict();

// OK
model DbUser {
  id String @id
}

// NG
model dbUser {
  id String @id
}

// NG
model db_user {
  id String @id
}

model-name-prefix

モデル名が指定されたプレフィックスを含んでいるかをチェックする。

設定

z.object({
  prefix: z.string(),
}).strict();

// OK
model DbUser {
  id String @id
}

// NG
model User {
  id String @id
}

require-default-empty-arrays

配列フィールドにデフォルト値として空配列を設定することを要求する。

動機

空配列をデフォルト値として明示的に設定することで、予期しないエラーを防ぐ。詳細な動機は Prisma lint issue #275 を参照。

// OK
model Post {
  tags String[] @default([])
}

// NG
model Post {
  tags String[]
}

require-field-index

特定のフィールドにインデックスが設定されていることを確認する。

設定

z.object({
  forAllRelations: z.boolean().optional(),
  forNames: z
    .union([z.string(), z.array(z.union([z.string(), z.instanceof(RegExp)]))])
    .optional(),
}).strict();

// OK
model User {
  createdAt DateTime @unique
}

model User {
  createdAt DateTime
  @@index([createdAt])
}

model User {
  createdAt DateTime
  id String
  @@index([createdAt, id])
}

// NG
model User {
  createdAt string
}

model User {
  createdAt DateTime
  id String
  @@index([id, createdAt])
}
// OK
model User {
  tenantId String
  @@index([tenantId])
}

// NG
model User {
  tenantId String
}
// OK
type Bar {
  fooId String
  foo Foo @relation(fields: [fooId], references: [id])
  @@index([fooId])
}

// NG
type Bar {
  fooId String
  foo Foo @relation(fields: [fooId], references: [id])
}

require-field-type

特定のフィールドが特定の型を持っていることを確認する。

設定

z.object({
  require: z.array(
    z.object({
      ifName: z.union([z.string(), z.instanceof(RegExp)]),
      type: z.string(),
    }),
  ),
}).strict();

// OK
model User {
  id String
}

// NG
model User {
  id Int
}
// OK
model User {
  createdAt DateTime
  updatedAt DateTime
}

// NG
model User {
  createdAt String
  updatedAt String
}

require-field

モデルが特定のフィールドを持つことを確認する。

このルールは prisma-lint-ignore-model コメントを使用して特定のフィールドを無視することができる。例えば:

/// prisma-lint-ignore-model require-field tenantId

これは、モデル内の tenantId フィールド違反のみを無視する。他の必須フィールドは引き続き適用される。複数のフィールドを無視する場合は、カンマで区切って指定する。

設定

z.object({
  require: z.array(
    z.union([
      z.string(),
      z.object({
        name: z.string(),
        ifSibling: z.union([z.string(), z.instanceof(RegExp)]),
      }),
    ]),
  ),
}).strict();

// OK
model User {
  id Int @id
}

// NG
model User {
  name String
}
// OK
model Product {
  currencyCode String
  priceAmountD6 Int
}

// NG
model Product {
  priceAmountD6 Int
}

Ref