firebase-manifest-compiler v1.0.3
Firebase manifest compiler WIP
Aims to take care of redundant firebase tasks that could be skipped by providing data schemes
Only for firestore atm, realtime database & security rules will follow, might implement links to other gcp services later, it all depends on what I need on my own project but PRs are welcomed
Experimental
Features
Write a schema once and never hardcode string paths to your document references ever again,
firestore.doc('chatrooms/{roomId}/messages/{messageId}')
simply becomesdb.room(id).message(msg_id)
for documents anddb.room(id).messages
for the collection itself.Save on bandwidth & storage without compromising on code readability. The compiler automatically adds in functions to map collection, document and property names to single characters of your choosing such that you get the full
{ name, username, picture_url }
object client and server side ( with VSCode autocompletion WIP ) while the database only stores{ n, u, p }
. The library comes with wrappers that allow this kind of thing to happen even with deeply nested document data objects.Hardcoded documents within nested collections are collapsed in the compiled manifest, such that
users/{uid}/private/profile
simply becomesdb.user(uid).profile
when there aren't conflicts with other subcollections or wildcard documents within/private
Adding the
@preprocess
property on a wildcard document allows you to change arguments before they are converted to paths, so that if you need to enforce username uniqueness for example, you'd set'@preprocess' : 'username.toLowerCase()'
once under the username document in the manifest and that'd get it lowercased anytime you access documents atusernames/{username}
, be it server or client side.Document properties can have defaults, and any property can be converted using an inline function
Install
npm install --savedev firebase-manifest-compiler
Usage
import { compile_firestore_manifest } from 'firebase-manifest-compiler'
compile_firestore_manifest( myManifest, { path : './client.manifest.js' }, { path : './server.manifest.js' } )
Example
Simple one level deep manifest :
Compiles down to :
calling myManifest.user(uid)
will get you a wrapped DocumentReference
, it's just like the one you'd get from firestore but this one converts the data from and to the database without you having to think about it ever again.
If user
had subcollections, they'd get passed as another argument to the function and assigned to the returned DocumentReference
.
Manifest syntax
Type | syntax | prerequisites | example | result |
---|---|---|---|---|
collection [] | [min:name] : { [ hardset \| wildcard documents ] } | Must be property of root or property of a document | [u:users] | manifest.users will give you a reference to the users collection |
wildcard document () | (name:argumentName?) : { [properties &\| collections ] } | Must be property of collection | (user:uid) | manifest.user will be a function callable with an argument named uid that returns a wrapped instance of a firestore DocumentReference |
hardset document {} | {min:name} : { [properties &\| collections ] } | Must be property of collection | {p:profile} | manifest.user will be a function callable with an argument named uid that returns a wrapped instance of a firestore DocumentReference |
document property '' | 'min:name' : 'type [= {default}]' | Must be property of a document or property of a property of defined type 'object' | 'n:name' : 'string = "unknown"' | The name property will be renamed to and from n when needed and set to "unknown" anytime it's undefined ( except when updating the document ) |
modifier @ | '@modifier:arg1' : 'arg2' | Must be property of a document or property of a property | (user:uid): { '@preprocess' : 'uid.toLowerCase()', 'n:name': { type : 'string', '@from': my_function, '@to' : my_other_function } } | uid will be lower cased before firestore.doc(path) is called. name = my_function(name) will be called when name is retrieved from the server and name = my_other_function(name) will be called when it goes the other way around |
Exports
function | arguments |
---|---|
compile_firestore_manifest | manifest, clientOpts, serverOpts, commonOpts? |
Options
Property | Description | default |
---|---|---|
path : string | output file path ( ex ./manifest.js ) | undefined |
name : string | name of the compiled manifest variable | 'toFirestore' |
imports : string | optional imports in the output file ( e.g. firebase itself ) | '' |
firestore : string | defines firestore in the output file | client : typeof window !== 'undefined' ? firebase.firestore : noop server : admin.firestore |
prettier : object | string | prettier config object for the output file, can also be a path to .prettierrc | { parser : 'babel' } |
Todo
- Get non generic VSCode autocompletion working on
.data()
& alike - Implement the
@link
modifier ( i.e. assign references to documents in other collections whose ID are one of the current document data properties to each of itsDocumentReference
s &DocumentSnapshot
s ) - Implement the
@bind
modifier ( ) //todo - Implement wraps for collection refs & queries
- Include types in the output
- Security rules compiler
- Realtime database manifest compiler
- Write tests
.md written with StackEdit.