From 85d19251d4f95049530261e2cacb01839c52748f Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Thu, 6 Sep 2018 12:22:33 +0100 Subject: [PATCH] update docs --- docs/extending.md | 213 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 213 insertions(+) diff --git a/docs/extending.md b/docs/extending.md index 8b9b212dc..d91d72938 100644 --- a/docs/extending.md +++ b/docs/extending.md @@ -91,6 +91,219 @@ Always keep in mind that all extension files are merged together at runtime. That allows plugins overwriting the code from the main application or altering other plugins.

+### Startup behaviour + +First, the root `app.extensions.json` is loaded by means of the special `Loader` service. +The file can contain all the necessary declarations for an application to function, +and having extra plugin files is fully optional. + +Next, the `Loader` traverses the `$references` metadata and loads additional files if provided. +For the sake of speed the files are loaded in parallel, +however, once everything is loaded, they are applied in the order of declaration. + +After all the external files are fetched, the `Loader` sorts them, removes the metadata properties +and stacks the resulting JSON objects on top of each other. + +

+Any top-level property name that starts with the `$` symbol is considered a metadata and does not participate in merge process. +That allows a plugin to carry extra information for maintenance and visualisation purposes, +for example: `$name`, `$version`, `$description`, `$license`, etc. +

+ +#### Merging properties + +There are no limits in the JSON structure and level of nesting. +All objects are merged into a single set based on property keys and object IDs (for arrays). + +Before: Plugin 1 + +```json +{ + "$name": "plugin1", + "plugin1.key": "value", + "plugin1.text": "string" +} +``` + +Before: Plugin 2 + +```json +{ + "$name": "plugin2", + "plugin2.key": "value", + "plugin1.text": "custom string" +} +``` + +Final result: + +```json +{ + "plugin1.key": "value", + "plugin1.text": "custom string", + "plugin2.key": "value" +} +``` + +Note that as a result we have two unique properties `plugin1.key` and `plugin2.key`, +and also a `plugin1.text` that was first defined in the `Plugin 1`, but then overwritten by the `Plugin 2`. + +

+JSON merging is very powerful concept as it gives you abilities to alter any base application settings, +or toggle features in other plugins without rebuilding the application or corresponding plugin libraries. +

+ +#### Merging objects + +The complex objects are merged by properties. This process is recursive and has no limits for nesting levels. + +Before: Plugin 1 + +```json +{ + "$name": "plugin1", + "features": { + "title": "some title", + "page1": { + "title": "page 1" + } + } +} +``` + +Before: Plugin 2 + +```json +{ + "$name": "plugin2", + "features": { + "page1": { + "title": "custom title" + }, + "page2": { + "title": "page 2" + } + } +} +``` + +Final result: + +```json +{ + "features": { + "title": "some title", + "page1": { + "title": "custom title" + }, + "page2": { + "title": "page 2" + } + } +} +``` + +As you can see, the unique properties get merged together in a single object. +However the last non-unique property always wins and overwrites the previous value. + +As per current design it is not possible to delete any application property from the plugin. +The loader engine supports only overwriting values on purpose. +Many components however support the `disabled` property you can change from external definition: + +Before: Plugin 1 + +```json +{ + "$name": "plugin1", + "feature1": { + "disabled": false, + "text": "some-feature", + "icon": "some-icon" + } +} +``` + +Before: Plugin 2 + +```json +{ + "$name": "plugin2", + "feature1": { + "disabled": true + } +} +``` + +Final result: + +```json +{ + "feature1": { + "disabled": true, + "text": "some-feature", + "icon": "some-icon" + } +} +``` + +You can find more details in the [Disabling Content](#disabling-content) section + +#### Merging arrays + +The extension `Loader` provides a special support for merging Arrays. +By default, two collections will be merged into a single array unless objects have `id` properties. + +

+If array contains two objects with the same `id` property, the objects will be merged rather than appended. +

+ +Before: Plugin 1 + +```json +{ + "$name": "plugin1", + "features": [ + { "text": "common 1" }, + { + "id": "page1", + "text": "page 1" + } + ] +} +``` + +Before: Plugin 2 + +```json +{ + "$name": "plugin2", + "features": [ + { "text": "common 2" }, + { + "id": "page1", + "text": "custom page" + } + ] +} +``` + +Final result: + +```json +{ + "features": [ + { "text": "common 1" }, + { "text": "common 2" }, + { + "id": "page1", + "text": "custom page" + } + ] +} +``` + +Note that objects with the same `page1` identifiers were merged while other unique entries were appended to the resulting array. + ### Disabling content Most of the schema elements can be switched off by using the `disabled` property: