> ## Documentation Index
> Fetch the complete documentation index at: https://docs.typesync.org/llms.txt
> Use this file to discover all available pages before exploring further.

# generate-rules

Generates validator functions for Firestore Security Rules (version 2) and injects them into the specified file. These validators ensure that request data adheres to defined model interfaces and detect any modifications to read-only fields during write operations.

Since Security Rules are centralized in a single file (typically `firestore.rules`), and developers often implement custom rules alongside type validations, Typesync inserts only the necessary validator functions, without overriding your custom rules. You can specify where these validators are added within the file using the `--startMarker` and `--endMarker` options. For a detailed guide, see the full [example](#example) below.

<Info>
  Note that these validators must adhere to the intrinsic limitations of Security Rules. For example, while it's
  feasible to verify if `x` is a list with the `x is list` predicate, determining whether it's a list of strings is not
  possible since loop constructs are not available in Security Rules. Typesync will provide the most stringent
  validation possible within these constraints.
</Info>

## Usage

```bash theme={null}
typesync generate-rules --definition <filePathOrPattern> --outFile <filePath> --startMarker <startMarker> --endMarker <endMarker> --typeValidatorNamePattern <typeValidatorNamePattern> --typeValidatorParamName <typeValidatorParamName> --indentation <indentation> --debug <debug>
```

## Options

<ParamField type="string" path="definition" required>
  The exact path or a Glob pattern to the definition file or files. Each definition file must be a YAML or JSON file containing model definitions.

  * Example single file path: `definition/models.json`
  * Example Glob pattern: `'definition/**/*.yml'`
</ParamField>

<ParamField type="string" path="outFile" required>
  The path to the output file.
</ParamField>

<ParamField type="string" path="startMarker" default="typesync-start">
  A marker that indicates the line after which the generated code should be
  inserted. Make sure to use a string that is unique within the file. The line
  containing the marker must be commented i.e. the marker needs to appear after
  the `//` (see [example](#example)).
</ParamField>

<ParamField type="string" path="endMarker" default="typesync-end">
  A marker that indicates the line before which the generated code should be inserted. Make sure to use a string that is
  unique within the file. The line containing the marker must be commented i.e. the marker needs to appear after the
  `//` (see [example](#example)).
</ParamField>

<ParamField type="string" path="typeValidatorNamePattern" default="isValid{modelName}">
  The pattern that specifies how the generated type validators are named. The pattern must be a string that contains the `"{modelName}"` substring (this is a literal value).

  Example values:

  * `"isValid{modelName}"` -> produces validators like `isValidUser`, `isValidProject`, `isValidAccount` etc.
  * `"is{modelName}"` -> produces validators like `isUser`, `isProject`, `isAccount` etc.
</ParamField>

<ParamField type="string" path="typeValidatorParamName" default="data">
  The name of the parameter taken by each type validator.
</ParamField>

<ParamField type="int" path="indentation" default={2}>
  Indentation or tab width for the generated code.
</ParamField>

<ParamField type="boolean" path="debug" default={false}>
  Whether to enable debug logs.
</ParamField>

## Example

Suppose you have a schema definition file named `models.yml` and a Security Rules file named `firestore.rules`.

<CodeGroup>
  ```yaml models.yml theme={null}
  # yaml-language-server: $schema=https://schema.typesync.org/v0.18.json

  UserRole:
    model: alias
    docs: Represents a user's role within a project.
    type:
      type: enum
      members:
        - label: Owner
          value: owner
        - label: Admin
          value: admin
        - label: Member
          value: member

  User:
    model: document
    path: users/{userId}
    docs: Represents a user that belongs to a project.
    type:
      type: object
      fields:
        username:
          type: string
          docs: A string that uniquely identifies the user within a project.
        role:
          type: UserRole
        website_url:
          type: string
          optional: true
        created_at:
          type: timestamp
  ```

  ```javascript firestore.rules (initial) theme={null}
  rules_version = '2';
  service cloud.firestore {
    // typesync-start
    // typesync-end

    // Here you define your custom rules
    match /databases/{database}/documents {
      match /users/{uid} {
        allow read;
        allow write: if isValidUser(request.resource.data);
      }
    }
  }
  ```
</CodeGroup>

To generate validators for the defined models and inject them between the `typesync-start` and `typesync-end` markers in the `firestore.rules` file, you can run the following command:

```bash theme={null}
typesync generate-rules --definition definition.yml --outFile firestore.rules --startMarker typesync-start --endMarker typesync-end
```

Typesync will insert the `isValidUserRole()` and `isValidUser()` validators into the file. You can then use these validators as needed in your custom rules.

```javascript firestore.rules theme={null}
rules_version = '2';
service cloud.firestore {
  // typesync-start
  function isValidUserRole(data) {
    return ((data == 'owner') || (data == 'admin') || (data == 'member'));
  }

  function isValidUser(data) {
    return (
      (data is map) &&
      (data.keys().hasOnly(['username', 'role', 'website_url', 'created_at'])) &&
      (data.username is string) &&
      isValidUserRole(data.role) &&
      ((data.website_url is string) || !('website_url' in data)) &&
      (data.created_at is timestamp)
    );
  }
  // typesync-end

  // Here you define your custom rules
  match /databases/{database}/documents {
    match /users/{uid} {
      allow read;
      allow write: if isValidUser(request.resource.data);
    }
  }
}
```
