@firestore-rules/cli
v0.1.16
Published
> TODO: description
Downloads
2
Readme
@firestore-rules/cli
CLI library for automatic generation of Firestore rules.
Install
yarn add -D @firestore-rules/cli
# or npm add @firestore-rules/cli --save-dev
Usage
Create Firestore Rules Model
create ./src/firestore-rules.ts
// ./src/firestore-rules.ts
import { FirestoreRulesModel, type, op } from '@firestore-rules/cli'
export default class extends FirestoreRulesModel {
get path() {
return '/databases/{database}/documents'
}
get isAuthenticated() {
return this.defineFunc(op.ne(this.ctx.request.auth, new type.Null()))
}
get isMe() {
const uid = this.args('uid')
return this.defineFunc(
op.and(
this.isAuthenticated.call([]),
op.eq(uid, this.ctx.request.auth.uid)
)
)
}
get userCollection() {
const self = this
return this.defineModel(
class extends FirestoreRulesModel {
get path() {
return '/users/{uid}'
}
get() {
return self.isMe.call([this.variables.uid])
}
create() {
return self.isAuthenticated.call([])
}
update() {
return self.isMe.call([this.variables.uid])
}
}
)
}
}
Then run the following command
yarn firestore-rules
# or ./node_modules/.bin/firestore-rules
Then you will get the following firestore.rules
// !!! DO NOT EDIT !!!
// This file is generated by @firestore-rules/cli
rules_version = "2";
service cloud.firestore {
match /databases/{database}/documents {
function isAuthenticated() {
return (request.auth != null);
}
function isMe(uid) {
return (isAuthenticated() && (uid == request.auth.uid));
}
match /users/{uid} {
allow get: if isMe(uid);
allow create: if isAuthenticated();
allow update: if isMe(uid);
}
}
}
Options
There are several ways to specify the options
"firestore-rules"
inpackage.json
.firestore-rulesrc
(bothjson
oryaml
format is ok).firestore-rulesrc.{json,yaml,yml,js,cjs}
firestore-rules.config.{js,cjs}
See cosmiconfig for other specification methods.
Option Properties
rulesPath: string # path to firestore-rules file. (default is './src/firestore-rules.ts')
typescript: boolean # if you do not use typescript, turn off. (default is true)
tsconfigPath: string # path to your tsconfig file. (default is './tsconfig.json')
outputPath: string # path to generate file. (default is 'firestore.rules')
backupFile: boolean # if you don't want to create backup file, turn off. (default is true)
formatOption: # options for formatter
indent: tab or space # indent type. (default is space)
indentSize: number # indent size. (default is 2)
lineLength: number # Maximum length of a line. (* Currently under development)
rulesPath
Specify the path of the entry file to be read by cli.
Default is ./src/firestore-rules.ts
.
typescript
Set to true if you want to use Typescript.
Default is true.
tsconfigPath
If you use TypeScript, you should provide valid tscondif file.
Default is ./tsconfig.json
outputPath
Specify the path of the file to output.
Default is firestore.rules
.
backupFile
Set to true if you want the original rule to be backed up when generating the file.
Default is true.
The name of the file to be backed up will be outputPath + '.backup'
.
formatOption
Options to be passed to @firestore-rules/formatter.
Check @firestore-rules/formatter for details
Writing Style
1. Export default class that extends FirestoreRulesModel
import { FirestoreRulesModel } from '@firestore-rules/cli'
export default class extends FirestoreRulesModel {
// ...
}
Define a getter named path
The returned value will be the value to apply to the match statement in firestore.rules.
// ...
export default class extends FirestoreRulesModel {
get path() {
return '/databases/{database}/documents'
}
}
Define a function with no arguments
You can use a method called defineFunc
.
You can use this.ctx
to refer to a global value such as request
.
The literal
and op
that can be imported from @firestore-rules/cli
contain all types and operators except for the Bytes
type
import { FirestoreRulesModel, literal, op } from '@firestore-rules/cli'
export default class extends FirestoreRulesModel {
/*
* function isAuthenticated() {
* return (request.auth != null);
* }
*/
get isAuthenticated() {
return this.defineFunc(
op.ne(this.ctx.request.auth, new literal.FirestoreRulesLiteralNull())
)
}
}
Define a function with arguments
You can use a method called defineFunc
, too.
Arguments can be defined by using the arg
method.
Also, if you want to use a predefined function, you can use this.<funcName>.call()
.
The first argument of the call
should be the argument to be passed to the function. isAuthenticated
does not require any argument, so it will pass an empty array
import { FirestoreRulesModel, literal, op } from '@firestore-rules/cli'
export default class extends FirestoreRulesModel {
/*
* function isMe(uid) {
* return (isAuthenticated() && (uid == request.auth.uid));
* }
*/
get isMe() {
const uid = this.args('uid') // create argument
return this.defineFunc(
op.and(
this.isAuthenticated.call([]), // call defined function
op.eq(uid, this.ctx.request.auth.uid)
)
)
}
}
Nesting match statements
You can use the defineModel
method to nest match expressions.
The argument should be clsass
as well as the class
you are default export
.
It is also a good idea to replace the this
reference with a variable such as self
so that it can be used again.
import { FirestoreRulesModel, literal, op } from '@firestore-rules/cli'
export default class extends FirestoreRulesModel {
get userCollection() {
const self = this
return this.defineModel(
class extends FirestoreRulesModel {
// ...
}
)
}
}
Similarly, define the path
Define the path in the same way as you did for /databases/{database}/documents
.
import { FirestoreRulesModel, literal, op } from '@firestore-rules/cli'
export default class extends FirestoreRulesModel {
get userCollection() {
const self = this
return this.defineModel(
class extends FirestoreRulesModel {
get path() {
return '/users/{uid}'
}
}
)
}
}
Declare the permit conditions
Permission conditions can be specified by overriding the get
, list
, create
, update
, and delete
methods.
Also, the document ID (uid in this example) will be automatically associated with this.variables.uid
.
Since we just used self
, we can also call functions in the parent hierarchy from self
.
The isMe
function needs an argument, so let's give it one.
import { FirestoreRulesModel, literal, op } from '@firestore-rules/cli'
export default class extends FirestoreRulesModel {
/*
* match /users/{uid} {
* allow get: if isMe(uid);
* allow create: if isAuthenticated();
* allow update: if isMe(uid);
* }
*/
get userCollection() {
const self = this
return this.defineModel(
class extends FirestoreRulesModel {
get path() {
return '/users/{uid}'
}
get() {
return self.isMe.call([this.variables.uid])
}
create() {
return self.isAuthenticated.call([])
}
update() {
return self.isMe.call([this.variables.uid])
}
}
)
}
}
Others
If you have any questions, please open an Issue!