Firebase Rules Parser
The `firebase-rules-parser` library provides a parser and emulator for Firebase security rules, allowing developers to programmatically load and test Firebase rule files. Its primary use case is facilitating unit testing for Firebase projects, particularly as a companion to `ts-mock-firebase`. The current stable version is 2.0.1, released in May 2019. While it aims to support nearly all Firebase rules language functionality, it explicitly notes limitations with duration, latlong, and timestamp functions. The project's release cadence appears to be slow or inactive since 2019, and it differentiates itself by offering an off-platform rule emulation capability without requiring a live Firebase instance, making it suitable for local development and CI/CD pipelines. It ships with TypeScript types, enhancing developer experience for TypeScript users.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'init')
cause Attempting to call `init` on an undefined interpreter instance, likely due to incorrect default import syntax for `createFirebaseRulesIntepreter` with CommonJS.fixUse `const createFirebaseRulesIntepreter = require('firebase-rules-parser').default;` for CommonJS, or preferably use ES module imports `import createFirebaseRulesIntepreter from 'firebase-rules-parser';`. -
Error: Cannot find module 'antlr4'
cause The `antlr4` library, a peer dependency, is not installed in the project.fixInstall `antlr4` as a direct dependency: `npm install antlr4` or `yarn add antlr4`. -
Property 'FirebaseRulesIntepreterFacade' does not exist on type 'typeof import("firebase-rules-parser")'.cause Attempting to reference the old class name `FirebaseRulesIntepreterFacade` after upgrading to v2.0.0 or later.fixRename `FirebaseRulesIntepreterFacade` to `FirebaseRulesIntepreter` in your code.
Warnings
- breaking The `FirebaseRulesIntepreterFacade` class was renamed to `FirebaseRulesIntepreter`.
- gotcha The `antlr4` dependency was moved from a direct dependency to a peer dependency. Consumers of the library are now responsible for installing `antlr4` themselves.
- gotcha This library is based on reverse-engineering Firebase rules behavior. There might be subtle differences between its emulation and the actual Firebase rules engine, especially with less common functions (e.g., duration, latlong, timestamp) or newer Firebase features.
- gotcha The project appears to be minimally maintained since its last release in 2019. It may not support newer Firebase rules features or address recent security updates to the Firebase platform itself.
Install
-
npm install firebase-rules-parser -
yarn add firebase-rules-parser -
pnpm add firebase-rules-parser
Imports
- createFirebaseRulesIntepreter
const createFirebaseRulesIntepreter = require('firebase-rules-parser').createFirebaseRulesIntepreter;import createFirebaseRulesIntepreter from 'firebase-rules-parser';
- createFirebaseRulesContext
import createFirebaseRulesContext from 'firebase-rules-parser/createFirebaseRulesContext';
import { createFirebaseRulesContext } from 'firebase-rules-parser'; - FirebaseRulesIntepreter
import { FirebaseRulesIntepreter } from 'firebase-rules-parser';import type { FirebaseRulesIntepreter } from 'firebase-rules-parser';
Quickstart
import createFirebaseRulesIntepreter, { createFirebaseRulesContext } from 'firebase-rules-parser';
const rulesSource = `
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read: if request.auth.uid == userId;
allow write: if request.auth.uid == userId && resource.data.name is string;
}
match /public/{documentId} {
allow read: if true;
}
}
}
`;
// Create an instance of the interpreter
const rules = createFirebaseRulesIntepreter();
// Load your rules source string
rules.init(rulesSource);
// Create a context object for the access check
const context = createFirebaseRulesContext({
auth: {
uid: 'testUserId123',
email: 'test@example.com'
},
resource: {
id: 'testUserId123',
data: {
name: 'John Doe',
value: 123
}
},
// Define triggers for `exists()` and `get()` calls within rules
onExistsCall: (path) => {
return path === '/databases/DEFAULT/documents/users/testUserId123';
},
onGetCall: (path) => {
if (path === '/databases/DEFAULT/documents/users/testUserId123') {
return {
uid: 'testUserId123',
name: 'Test User'
};
}
return null;
}
});
// Check access for a specific path and operation
const hasReadAccess = rules.hasAccess('/databases/DEFAULT/documents/users/testUserId123', context);
console.log('Read access:', hasReadAccess.read); // Should be true
const hasWriteAccess = rules.hasAccess('/databases/DEFAULT/documents/users/testUserId123', context);
console.log('Write access:', hasWriteAccess.write); // Should be true
const noAccessContext = createFirebaseRulesContext({
auth: { uid: 'anotherUser' },
resource: { id: 'testUserId123', data: { name: 'Another Name' } }
});
const noReadAccess = rules.hasAccess('/databases/DEFAULT/documents/users/testUserId123', noAccessContext);
console.log('No read access:', noReadAccess.read); // Should be false or undefined
const publicReadAccess = rules.hasAccess('/databases/DEFAULT/documents/public/someDoc', noAccessContext);
console.log('Public read access:', publicReadAccess.read); // Should be true