From c4535bdf1ae83b36b35f0f72a3c6ff787010e454 Mon Sep 17 00:00:00 2001 From: Kristian Dupont Date: Wed, 22 Mar 2017 12:54:35 +0100 Subject: [PATCH] Improve api docs (#920) * Set docs title in configuration * Add markdown plugin to jsdoc * Add query language tutorial to docs * jsdoc template submodule updated * Add query docs * Document placeholders and composition operators * Add logo * Add note about boolean checks * Fixes as per PR comments --- docs/collection.js | 2 + docs/conf.json | 6 ++- docs/jsdoc-template | 2 +- docs/plugins/markdown.js | 89 ++++++++++++++++++++++++++++++++ docs/static/logo.svg | 0 docs/tutorials/query-language.md | 58 +++++++++++++++++++++ docs/tutorials/tutorials.json | 5 ++ package.json | 2 +- 8 files changed, 161 insertions(+), 3 deletions(-) create mode 100644 docs/plugins/markdown.js create mode 100644 docs/static/logo.svg create mode 100644 docs/tutorials/query-language.md create mode 100644 docs/tutorials/tutorials.json diff --git a/docs/collection.js b/docs/collection.js index 98824151..d81fa882 100644 --- a/docs/collection.js +++ b/docs/collection.js @@ -43,6 +43,8 @@ class Collection { * (e.g. `$0`, `$1`, `$2`, …) in the query. * @throws {Error} If the query or any other argument passed into this method is invalid. * @returns {Realm.Results} filtered according to the provided query. + * + * See {@tutorial query-language} for details about the query language. * @example * let merlots = wines.filtered('variety == "Merlot" && vintage <= $0', maxYear); */ diff --git a/docs/conf.json b/docs/conf.json index 5551074d..397a94f5 100644 --- a/docs/conf.json +++ b/docs/conf.json @@ -14,9 +14,13 @@ }, "plugins": ["plugins/markdown"], "templates": { + "applicationName": "Realm JavaScript", "cleverLinks": true, "default": { - "outputSourceFiles": false + "outputSourceFiles": false, + "staticFiles": { + "paths": ["docs/static"] + } } } } diff --git a/docs/jsdoc-template b/docs/jsdoc-template index ab495962..4e014653 160000 --- a/docs/jsdoc-template +++ b/docs/jsdoc-template @@ -1 +1 @@ -Subproject commit ab495962a2cf92718374d53f9b7c2f7b7d164068 +Subproject commit 4e014653f07066eb8652b1920a75969c5bc6e3f8 diff --git a/docs/plugins/markdown.js b/docs/plugins/markdown.js new file mode 100644 index 00000000..989f4e7a --- /dev/null +++ b/docs/plugins/markdown.js @@ -0,0 +1,89 @@ +/** + * @overview Translate doclet descriptions from MarkDown into HTML. + * @module plugins/markdown + * @author Michael Mathews + * @author Ben Blank + */ +'use strict'; + +var env = require('jsdoc/env'); + +var config = env.conf.markdown || {}; +var defaultTags = [ + 'author', + 'classdesc', + 'description', + 'exceptions', + 'params', + 'properties', + 'returns', + 'see' +]; +var hasOwnProp = Object.prototype.hasOwnProperty; +var parse = require('jsdoc/util/markdown').getParser(); +var tags = []; +var excludeTags = []; + +function shouldProcessString(tagName, text) { + var shouldProcess = true; + + // we only want to process `@author` and `@see` tags that contain Markdown links + if ( (tagName === 'author' || tagName === 'see') && text.indexOf('[') === -1 ) { + shouldProcess = false; + } + + return shouldProcess; +} + +/** + * Process the markdown source in a doclet. The properties that should be + * processed are configurable, but always include "classdesc", "description", + * "params", "properties", and "returns". Handled properties can be bare + * strings, objects, or arrays of objects. + */ +function process(doclet) { + tags.forEach(function(tag) { + if ( !hasOwnProp.call(doclet, tag) ) { + return; + } + + if (typeof doclet[tag] === 'string' && shouldProcessString(tag, doclet[tag]) ) { + doclet[tag] = parse(doclet[tag]); + } + else if ( Array.isArray(doclet[tag]) ) { + doclet[tag].forEach(function(value, index, original) { + var inner = {}; + inner[tag] = value; + process(inner); + original[index] = inner[tag]; + }); + } + else if (doclet[tag]) { + process(doclet[tag]); + } + }); +} + +// set up the list of "tags" (properties) to process +if (config.tags) { + tags = config.tags.slice(); +} +// set up the list of default tags to exclude from processing +if (config.excludeTags) { + excludeTags = config.excludeTags.slice(); +} +defaultTags.forEach(function(tag) { + if (excludeTags.indexOf(tag) === -1 && tags.indexOf(tag) === -1) { + tags.push(tag); + } +}); + +exports.handlers = { + /** + * Translate markdown syntax in a new doclet's description into HTML. Is run + * by JSDoc 3 whenever a "newDoclet" event fires. + */ + newDoclet: function(e) { + process(e.doclet); + } +}; diff --git a/docs/static/logo.svg b/docs/static/logo.svg new file mode 100644 index 00000000..e69de29b diff --git a/docs/tutorials/query-language.md b/docs/tutorials/query-language.md new file mode 100644 index 00000000..a7a093e8 --- /dev/null +++ b/docs/tutorials/query-language.md @@ -0,0 +1,58 @@ +The Realm JavaScript SDK supports querying based on a language inspired by [NSPredicate](https://realm.io/news/nspredicate-cheatsheet/). + +The {@link Realm.Collection#filtered Collection.filtered()} method is used to query a Realm: + +```JS +let contacts = realm.objects('Contact'); +let friendsPage2 = contacts.filtered('type == "friend" AND name BEGINSWITH "B"'); +``` + +It's possible to filter by linked or child objects with a keypath. + +Example: +```JS +let johnsChildren = realm.Object('Contact').filtered('father.name == "John"'); +``` + +Query strings can use numbered (`$0`, `$1`, ...) placeholders. The succeeding parameters contain the values. +Named placeholders are **not** yet supported. + +Example: +```JS +let merlots = wines.filtered('variety == $0 && vintage <= $1', 'Merlot', maxYear); +``` + + +### Relational operators +You can use equality comparison on all property types: +`==` and `!=` + +Furthermore, the following can be used on numerical types: +`<`, `<=`, `>`, `>=` + +Example: +```JS +let oldContacts = realm.objects('Contact').filtered('age > 2'); +``` + +Note that for boolean properties, you should test against the expected keyword. + +Example: +```JS +let women = realm.objects('Contact').filtered('isMale == false'); +``` + +### String operators +For string properties, prefix, suffix, and substring queries are supported by using the `BEGINSWITH`, `ENDSWITH`, and `CONTAINS` operators. + +For any string operation you can append `[c]` to the operator to make it case insensitive. + +Example: +```JS +let peopleWhoseNameContainsA = realm.objects('Contact').filtered('name CONTAINS[c] "a"'); +let Johns = realm.objects('Contact').filtered('name ==[c] "john"'); +``` + +### Composition +Use parentheses and the `&&`/`AND` and `||`/`OR` operators to compose queries. You can negate a predicate with `!`/`NOT`. + diff --git a/docs/tutorials/tutorials.json b/docs/tutorials/tutorials.json new file mode 100644 index 00000000..ca691891 --- /dev/null +++ b/docs/tutorials/tutorials.json @@ -0,0 +1,5 @@ + { + "query-language": { + "title": "Query language" + } + } \ No newline at end of file diff --git a/package.json b/package.json index 80c2fe7a..e3f140f9 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "set-version": "scripts/set-version.sh", "get-core-version": "scripts/download-core.sh --version", "get-sync-version": "scripts/download-core.sh --versionSync", - "jsdoc": "rm -rf docs/output && jsdoc -c docs/conf.json", + "jsdoc": "rm -rf docs/output && jsdoc -u docs/tutorials -p package.json -c docs/conf.json", "lint": "eslint", "test": "scripts/test.sh", "install": "node-pre-gyp install --fallback-to-build",