Generates type validator functions for Firestore Security Rules (version 2) and injects them into the specified file.

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 below.

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.

Usage

typesync generate-rules --definition <filePathOrPattern> --outFile <filePath> --startMarker <startMarker> --endMarker <endMarker> --validatorNamePattern <validatorNamePattern> --validatorParamName <validatorParamName> --indentation <indentation> --debug <debug>

Options

definition
string
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'
outFile
string
required

The path to the output file.

startMarker
string
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).

endMarker
string
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).

validatorNamePattern
string
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.
validatorParamName
string
default: "data"

The name of the parameter taken by each type validator.

indentation
int
default: 2

Indentation or tab width for the generated code.

debug
boolean
default: false

Whether to enable debug logs.

Example

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

# yaml-language-server: $schema=https://schema.typesync.org/v0.8.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
  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

To generate type validators for the defined models and inject them between the typesync-start and typesync-end markers (these are the default values for --startMarker and --endMarker options) in the firestore.rules file, you can run the following command:

typesync generate-rules --definition definition.yml --outFile firestore.rules

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

firestore.rules
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);
    }
  }
}