-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #548 from player-ui/docs/dsl
Add Missing DSL Docs
- Loading branch information
Showing
6 changed files
with
677 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
--- | ||
title: Overview | ||
--- | ||
|
||
# TSX/JSX Content Authoring (Player DSL) | ||
|
||
While Player content _can_ be written directly in JSON, it's definitely not the preferable authoring format. To take advantage of existing developer tool-chains, Player provides a mechanism for authoring content in (J/T)SX as React components and simple TypeScript objects. The Player CLI can then be used to transpile the React tree into a JSON content. | ||
|
||
## DSL Benefits | ||
|
||
At a high level, the benefits to writing Player content in the DSL can be summarized by three key factors: | ||
|
||
#### Easier maintainability | ||
Simply put, DSL code more concise than its JSON equivalent. That means there is less code for you to have to maintain. Also, as its easier to read than JSON, when you do need to make updates to it, its much more wieldy to work with. | ||
|
||
#### Better development experience | ||
Since the DSL leverages a lot of standard TypeScript language features, most editors will offer quality of life features like typechecking, suggestions, and code generation. All of this is in service of shortening the feedback loop of writing content and ensuring it is what you intended for it. | ||
|
||
#### Easier to extend | ||
The DSL now offers a easily accessible programatic hook into Player content. This allows custom tooling to be created around your DSL integration much easier that before. Common patterns can be extracted into higher level compoennts, functions can be created to generate code, and code generation can be integrated into almost any process where relevant data is present. | ||
|
||
For a further explination on the benefits, see the DSL Benefits section in the [DSL Views](./views.mdx#dsl-benefits-in-views) and the [DSL Schema](./schema.mdx#dsl-benefit-in-schema) | ||
|
||
## Writing DSL Content | ||
|
||
In order to use the DSL to write content, your plugin library should ship a DSL component package. These will define the primitive _components_ to use to build up the tree. Authorship of these components is covered in the [Writing DSL Components](../assets/dsl) secton. The Player Reference Assets ship their own DSL Components via the `@player-ui/reference-assets-components` pacakge. | ||
|
||
In the examples below, we will use the Player Reference Assets Components. | ||
|
||
### Basic Setup | ||
|
||
To get started, you'll need the following dependencies in your `package.json`: | ||
|
||
```json | ||
{ | ||
"dependencies": { | ||
"@player-tools/dsl": "0.4.1", | ||
"@player-tools/cli": "0.4.1", | ||
"@player-ui/reference-assets-components": "0.6.0", | ||
"@types/react": "17.0.39", | ||
"react": "17.0.2" | ||
} | ||
} | ||
``` | ||
|
||
Next, you'll need to configure your environment for DSL Compilation and JSON validation. Below is a basic configuration that can be added in your `package.json`. For a more detailed explination and examples on further customization please refer to the [CLI](../tools/cli) section. | ||
|
||
```json | ||
{ | ||
"player": { | ||
"dsl": { | ||
"src": "./src/main/tsx", | ||
"outDir": "./out" | ||
}, | ||
"json": { | ||
"src": "./out/*.json" | ||
}, | ||
} | ||
} | ||
``` | ||
|
||
### Basic Format and File Layout | ||
|
||
By default, all files that contain a Player Flow should be exported as a `.tsx` file and the schema should be in a `.ts` file. For how to change this behavior, please refer to the [DSL Plugins](./plugins) section of the docs. Each of these files should contain a default export of their appropriate object. For example a file that exports a flow should look like the following: | ||
|
||
```tsx | ||
export default { | ||
id: 'my-flow', | ||
views: [....], | ||
navigation: {....} | ||
} | ||
``` | ||
|
||
and a file that exports the schema should look like: | ||
|
||
```typescript | ||
const mySchema = {...} | ||
|
||
export default mySchema | ||
|
||
``` | ||
|
||
### Navigation | ||
|
||
At this time the `navigation` section is a basic JS object. The `@player-ui/types` package provides typescript typings for this. | ||
|
||
```tsx | ||
import { Navigation } from '@player-ui/types'; | ||
|
||
const navigation: Navigation = { | ||
BEGIN: 'Start', | ||
Start: { | ||
startState: 'VIEW_1', | ||
VIEW_1: { | ||
state_type: 'VIEW', | ||
ref: 'view-1', | ||
transitions: { | ||
'*': 'END_Done', | ||
}, | ||
}, | ||
END_Done: { | ||
state_type: 'END', | ||
outcome: 'done', | ||
}, | ||
}, | ||
}; | ||
``` | ||
|
||
One convenience feature is the auto injection of the the `ref` property for a `VIEW` type state if the corresponding view is a React tree. | ||
|
||
```tsx | ||
import { Navigation } from '@player-ui/types'; | ||
|
||
const view = ( | ||
<Collection id="my-view"> | ||
<Text>Some value</Text> | ||
<Input> | ||
<Input.Label>Some label</Input.Label> | ||
</Input> | ||
</Collection> | ||
); | ||
|
||
const navigation: Navigation = { | ||
BEGIN: 'Start', | ||
Start: { | ||
startState: 'VIEW_1', | ||
VIEW_1: { | ||
state_type: 'VIEW', | ||
ref: view, | ||
transitions: { | ||
'*': 'END_Done', | ||
}, | ||
}, | ||
END_Done: { | ||
state_type: 'END', | ||
outcome: 'done', | ||
}, | ||
}, | ||
}; | ||
``` | ||
|
||
_Note: The `Navigation` type we're importing here from the `@player-ui/types` package is different than the `Navigation` type from the `@player-tools/dsl` package. The former is the core definition for what the Navigation section of Player content is. The latter has specific replacements to take DSL constructs where normal objects would be defined._ | ||
|
||
### Bindings and Expressions | ||
|
||
Both `binding` and `expression` in the JSX authoring leverages a tagged template, typically abbreviated as `b` and `e` respectively. In a similar fashion to using `css` or `graphql` in a JS file, this enables syntax-highlighting and validation of bindings and expressions within a JS file. | ||
|
||
```tsx | ||
import { binding as b, expression as e } from '@player-tools/dsl'; | ||
|
||
const myBinding = b`foo.bar`; | ||
const myExpression = e`foo()`; | ||
``` | ||
|
||
The binding and expression instances can also automatically dereference themselves when used inside of another string: | ||
|
||
```tsx | ||
const stringWithBinding = `Some text: ${myBinding}`; // 'Some text: {{foo.bar}}' | ||
const stringWithExp = `Some expr: ${myExpression}`; // 'Some expr: @[foo()]@' | ||
``` | ||
|
||
### View | ||
|
||
Please refer to the [Views](../dsl/views) section for a detailed overview of how to write DSL Views | ||
|
||
### Schema | ||
|
||
Please refer to the [Schema](../dsl/schema) section for a detailed overview of how to write DSL Schemas | ||
|
||
## Compiling DSL Content | ||
|
||
Once your DSL content is authored, you can use the Player CLI to compile and validate your content. For documentation on this functionality, please refer to the [Player CLI](../tools/cli) section |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
--- | ||
title: Plugins | ||
--- | ||
|
||
# DSl Plugins | ||
|
||
Much like the rest of Player, DSL compilation supports plugins that can influce how content gets compiled and generated. DSL Plugins are a subset of CLI Plugins that use either the hooks available on the CLI itself or on the DSL compiler instance created by the CLI. This section will cover the hooks that are available for use and why you might want to tap them. | ||
|
||
## CLI Hooks | ||
|
||
The `createCompilerContext` function available to plugins that extend the `PlayerCLIPlugin` class gives access to the `CompilationContext` instance. This class manages the context around DSL compilation and exposes two related hooks. | ||
|
||
### `identifyContentType` | ||
|
||
The `identifyContentType` hooks's purpose is to allow plugins to inject custom behavior around detecting what kind of file is being compiled. By default there are three types of content the CLI is aware of (`view`, `flow`, and `schema`). Its methods for detecting which kind of content is contained within a file is very rudimentary (the logic can be found [here](https://github.com/player-ui/tools/blob/main/language/dsl/src/compiler/utils.ts#L5)). In order to allow desired convention or orchestrate the compilation of custom file types, this hook provides a mechanism for allowing that custom logic to be injected. The result of this hook is used in the next hook | ||
|
||
### `compileContent` | ||
|
||
The `compileContent` hook's purpose is to allow the custom compilation logic for any identified file type. As it is an `AsyncSeriesBailHook` it will take the first result returned from a tap who was able to return a result for the compilation for the given file of the identified type. In the case where no external logic is added, the hook will attempt to compile any of its known content types with the built in compiler instance. | ||
|
||
## Compilation Hooks | ||
|
||
The CLI will initialize an instance of the `DSLCompiler` and provide a reference to it via the `onCreateDSLCompiler` function available to plugins that extend the `PlayerCLIPlugin` class. On the compiler itself, the following hook are available to modify the behavior of how DSL content is compiled. | ||
|
||
### `preProcessFlow` | ||
_Note: Only called for `view` or `flow` content_ | ||
|
||
This hook allows transformations on the content before it is compiled. This enables the injection of additonal data or resolving any integration specific convention into something that may be understood by the compiler. This hook can also be used to collate information on what is being compiled for use later. | ||
|
||
### `postProcessFlow` | ||
_Note: Only called for `view` or `flow` content_ | ||
|
||
This hook allows transformations on the content after it is compiled. This allows modifications to the compiled content which in some cases may be preferable as manipulating JSON may be easier than a React Tree. | ||
|
||
### `schemaGenerator` | ||
|
||
This hook gives access to the internal `SchemaGenerator` object which is responsible for compiling the schema. On this generator there are the following hooks. | ||
|
||
#### `createSchemaNode` | ||
|
||
This hook allows custom logic for processing schema nodes as they are generated. This enables arbitrary properties to be statically or dynamically added based on the authored schema node. One potential usecase of this is to allow integration specific semantic conventions to be defined and injected into the final schema. For example, the presence of a specific `Symbol` might mean that a property needs to be injected or even that the schema tree from this point on needs to be modified. | ||
|
||
|
||
### `onEnd` | ||
|
||
This hook is called to signal that the compilation of all files has been completed. This allows any post processing on the output as a whole to take place as a part of the build process. This may include actions like moving or bundling the compilation results or writing new files based on information collected via other hooks on the files that were processed. |
Oops, something went wrong.