Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow wildcard properties in type statement #235

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ![Bolt Icon](docs/images/flash.png) Bolt Compiler

[![Build Status](https://travis-ci.org/firebase/bolt.svg?branch=master)](https://travis-ci.org/firebase/bolt)
[![Build Status](https://travis-ci.org/FirebaseExtended/bolt.svg?branch=master)](https://travis-ci.org/FirebaseExtended/bolt)
[![NPM Version](https://badge.fury.io/js/firebase-bolt.svg)](https://npmjs.org/package/firebase-bolt)
[![NPM Downloads](http://img.shields.io/npm/dm/firebase-bolt.svg)](https://npmjs.org/package/firebase-bolt)

Expand All @@ -11,7 +11,7 @@ using with production applications.

Otherwise, we'd love to have feedback from early adopters. You can email questions
to [email protected] using "Bolt" in the subject line, or post bugs
on our [Issue Tracker](https://github.com/firebase/bolt/issues).
on our [Issue Tracker](https://github.com/FirebaseExtended/bolt/issues).

# Language Definition

Expand Down
7 changes: 7 additions & 0 deletions docs/language.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ A (user-defined) type statement describes a value that can be stored in the Fire
type MyType [extends BaseType] {
property1: Type,
property2: Type,
$wildcardProp: Type
...

validate() { <validation expression> }
Expand All @@ -55,6 +56,12 @@ to use any other character in a property name, you can enclose them in quotes (n
that Firebase allows any character in a path *except* for `.`, `$`, `#`, `[`, `[`, `/`,
or control characters).

When a type statement contains a wildcard property, i.e. a property starting with the
`$`-character, the value is allowed to have an arbitrary number of extra properties. When
there is no wildcard property, the value can only have the properties defined in the
type statement. A type can have at most one wildcard property.


Built-in base types are also similar to JavaScript types:

String - Character strings
Expand Down
40 changes: 40 additions & 0 deletions samples/issue-212.bolt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
type MyType {
num: Number;
str: String;
any: Any;
$extras: String;
}

type AnyMap {
$extras: Any;
}

type OtherType extends AnyMap {
name: String;
}

type WithExtras<T> extends T {
$extras: Any;
}

type AnotherType {
name: String;
}


path /path is MyType {
read() { true }
write() { true }
}

path /other is OtherType {
read() { true }
}

path /another is AnotherType {
read() { true }
}

path /anotherWithExtras is WithExtras<AnotherType> {
read() { true }
}
45 changes: 45 additions & 0 deletions samples/issue-212.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"rules": {
"path": {
".validate": "newData.hasChildren(['num', 'str', 'any'])",
"num": {
".validate": "newData.isNumber()"
},
"str": {
".validate": "newData.isString()"
},
"any": {
".validate": "true"
},
"$extras": {
".validate": "newData.isString()"
},
".read": "true",
".write": "true"
},
"other": {
".validate": "newData.hasChildren(['name'])",
"name": {
".validate": "newData.isString()"
},
".read": "true"
},
"another": {
".validate": "newData.hasChildren(['name'])",
"name": {
".validate": "newData.isString()"
},
"$other": {
".validate": "false"
},
".read": "true"
},
"anotherWithExtras": {
".validate": "newData.hasChildren(['name'])",
"name": {
".validate": "newData.isString()"
},
".read": "true"
}
}
}
9 changes: 7 additions & 2 deletions src/rules-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ export class Generator {
let wildProperties = 0;
Object.keys(schema.properties).forEach((propName) => {
if (propName[0] === '$') {
delete validator.$other;
wildProperties += 1;
if (INVALID_KEY_REGEX.test(propName.slice(1))) {
this.fatal(errors.invalidPropertyName + propName);
Expand All @@ -467,7 +468,7 @@ export class Generator {
extendValidator(<Validator> validator[propName], this.ensureValidator(propType));
});

if (wildProperties > 1 || wildProperties === 1 && requiredProperties.length > 0) {
if (wildProperties > 1) {
this.fatal(errors.invalidWildChildren);
}

Expand All @@ -478,7 +479,11 @@ export class Generator {
}

// Disallow $other properties by default
if (hasProps) {
let hasWildProps = Object.keys(validator).some((v) => {
return v[0] === '$';
});

if (hasProps && !hasWildProps) {
validator['$other'] = {};
extendValidator(<Validator> validator['$other'],
<Validator> {'.validate': ast.boolean(false)});
Expand Down
1 change: 1 addition & 0 deletions src/test/sample-files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export let samples = [
"issue-169",
"issue-232",
"issue-97",
"issue-212",
"mail",
"map-scalar",
"multi-update",
Expand Down