ymlr
TypeScript icon, indicating that this package has built-in type declarations

1.2.6-alpha.34 • Public • Published

ymlr

A platform helps to run everythings base on a yaml script file

Installation

Install via npm

  npm install -g ymlr

Install via yarn

  yarn global add ymlr

Supported tags

  1. ymlr-mqtt Pub/sub messages to channels in mqtt
  2. ymlr-redis Handle redis into ymlr platform
  3. ymlr-telegram Send telegram text, photo..., support "listen", "command", "hears"... in telegram bot
  4. ymlr-sql Execute query to mysql, postgresql, orable, sqlite...
  5. ymlr-cron Schedule jobs to do something base on cron pattern

Run a scene

Run a scene file

  ymlr $PATH_TO_SCENE_FILE

Run a encrypted scene file with a password

  ymlr $PATH_TO_SCENE_FILE $PASSWORD

Override env variables then run

  ymlr -e "port=80" -e "log=error" -- $PATH_TO_SCENE_FILE

CLI

Show helps

  ymlr -h

Show all tags version

  ymlr

Add new external tags, libraries which is used in the scene

  ymlr add ymlr-telegram@latest

Upgrade external tags, libraries which is used in the scene

  ymlr up ymlr-telegram@latest

Remove external tags, libraries which is used in the scene

  ymlr rm ymlr-telegram@latest

Customize source paths which are registed tags in your application

  ymlr --tag-dirs /myapp1 --tag-dirs /myapp2 -- myapp.yaml     # "/myapp1", "/myapp2" are includes source code

Override show debug log for all of tags

  ymlr --debug=all -- myapp.yaml

Docker

Docker image file: circle2jt/ymlr

Run a scene file.
Default is /script/index.yaml, you can override it in commands
$PASSWORD is optional when run a encrypted scene file

  docker run -v $PATH_TO_SCENE_FILE:/scripts/index.yaml --rm -it circle2jt/ymlr /scripts/index.yaml $PASSWORD

Run a specific file

  docker run -v $PATH_TO_SCENE_DIR:/scripts --rm -it circle2jt/ymlr /scripts/$PATH_TO_SCENE_FILE

Example

  1. Create a scene file at test.yaml
name: Test scene
runs:
  - echo: Hello world

  - name: Get post data
    http'get:
      url: http://localhost:3000/posts
    vars: postData

  - echo: ${ $vars.postData }
  1. Run
  ymlr test.yaml

Common tags which is used in the program

Tags Description
md'doc Generate comment in a file to document
echo Print to console screen
echo'debug Add more information when print to console screen
clear Clear console screen
event'emit Send data via global event
event'on Handle global events in app
fn-debounce Debounce function (#Ref: lodash.debounce)
fn-debounce'cancel Cancel debounce function (#Ref: lodash.debounce)
fn-debounce'del Cancel & remove debounce function (#Ref: lodash.debounce)
fn-debounce'flush Force to call debounce function ASAP if it's called before that (#Ref: lodash.debounce)
fn-debounce'touch touch debounce function. Reused last agruments(#Ref: lodash.debounce)
fn-queue Register a queue job
fn-queue'add Add a job to an exsited queue
fn-queue'del Stop and remove a queue
fn-singleton This is locked before run and unlock after done. When it's called many time, this is only run after unlock
fn-singleton'del Remove singleton function
fn-throttle Throttle function (#Ref: lodash.throttle)
fn-throttle'cancel Cancel throttle function (#Ref: lodash.throttle)
fn-throttle'del Cancel & remove throttle function (#Ref: lodash.throttle)
fn-throttle'flush Force to call throttle function ASAP if it's called before that (#Ref: lodash.throttle)
fn-throttle'touch touch throttle function. Reused last agruments (#Ref: lodash.throttle)
exec Execute a program
exec'js Execute a nodejs code
exec'sh Execute a shell script
exit Stop then quit the program
fetch'del Send a http request with DELETE method
fetch'get Send a http request with GET method
fetch'head Send a http request with HEAD method
fetch'patch Send a http request with PATCH method
fetch'post Send a http request with POST method
fetch'put Send a http request with PUT method
file'read Read a file then load data into a variable
file'store Store data to file
file'write Write data to file
http'del Send a http request with DELETE method
http'get Send a http request with GET method
http'head Send a http request with HEAD method
http'patch Send a http request with PATCH method
http'post Send a http request with POST method
http'put Send a http request with PUT method
http'server Create a http server to serve content via http
include Include a scene file or list scene files in a folder
input'confirm Get user confirm (yes/no)
input'multiselect Suggest a list of choices for user then allow pick multiple choices
input'number Get user input from keyboard then convert to number
input'password Get user input from keyboard but hide them then convert to text
input'select Suggest a list of choices for user then allow pick a choice
input'suggest Suggest a list of choices for user then allow pick a choice or create a new one
input'text Get user input from keyboard then convert to text
js Execute a nodejs code
npm'install Install librarries to use in the scene.
npm'uninstall Uninstall librarries to use in the scene.
pause Pause the program then wait to user enter to continue
runs Group elements
scene Load another scene into the running program
scene'returns Return value to parent scene
scene'thread Same "scene" but it run in a new thread
sh Execute a shell script
sleep Sleep the program then wait to user enter to continue
tag'register Register custom tags from code or npm module, github....
test Check conditions in the program

Root scene

It's a scene file
Root scene file includes all of steps to run

Example:

  name: Scene name                  # Scene name
  description: Scene description    # Scene description
  log: info                         # Show log when run. Default is info. [silent, error, warn, info, debug, trace, all]
  password:                         # Encrypted this file with the password. To run this file, need to provides a password in the command line
  vars:                             # Declare global variables which are used in the program.
    env: production                 # |- Only the variables which are declared in the top of root scene just can be overrided by environment variables
  env:                              # Set value to environment variable (process.env)
    DEBUG: all
    DEBUG_CONTEXTS: test=debug
    NODE_ENV: production
    env: dev                        # It overrides to $vars.env
    # - NODE_ENV=production
  envFiles:                         # Load env variable from files (string | string[])
    - .env
    - .env.dev
  varsFiles:                        # Load vars from json or yaml files (string | string[])
    - ./var1.json
    - ./var2.yaml
  runs:                             # Defined all of steps which will be run in the scene
    - echo: Hello world
    - test: test props

->

It's a property in a tag
Expose item properties for others extends

Example:

Use skip

  - ->: helloTemplate
    skip: true
    echo: Hello               # Not run

  - <-: helloTemplate         # => Hello

Use template

  - ->: hiTemplate
    template: Hi              # Not run

  - <-: hiTemplate            # => Hi
    echo:

# @include

It's a yaml comment type
Include the content file to current position. This is will be read a file then copy file content into current position If you want to use expresion ${}, you can use tag "include". Useful for import var file ....

Example:

  - vars:
      # @include ./.env

.env file is

ENV: production
APP: test

<-

It's a property in a tag
Copy properties from others (a item, or list items)

Example:

  - ->: baseRequest
    template:
      baseURL: http://localhost
  - <-: baseRequest
    ->: user1Request
    template:
      headers:
        authorization: Bearer user1_token
  - ->: user2RequestWithoutBaseURL
    template:
      headers:
        authorization: Bearer user2_token

  - <-: user1Request
    http'get:                      # Send a get request with baseURL is "http://localhost" and headers.authorization is "Bearer user1_token"
      url: /posts
    vars: user1Posts

  - <-: [baseRequest, user2RequestWithoutBaseURL]
    http'get:                      # Send a get request with baseURL is "http://localhost" and headers.authorization is "Bearer user2_token"
      url: /posts
    vars: user2Posts

async

It's a property in a tag
Execute parallel tasks

Example:

  - async: true
    http'get:
      url: /categories
    vars: categories
  - ~http'get:            # Can use shortcut by add "~"" before tag name
      url: /product/1
    vars: product

  - name: The product ${$vars.product.name} is in the categories ${$vars.categories.map(c => c.name)}

context

It's a property in a tag
Context logger name which is allow filter log by cli "ymlr --debug-context context_name=level --"

Example:

  - name: Get list user
    context: userapi
    debug: warn
    http'get: ...

  - name: Get user details
    context: userapi
    debug: warn
    http'get: ...

  - name: Get product details
    context: productapi
    debug: warn
    http'get: ...

Now, we have 2 choices to debug all of user APIs and product APIs

  1. Replace all "debug: warn" to "debug: debug"
  2. Only run cli as below
  ymlr --debug-context userapi=debug --debug-context productapi=trace -- $SCENE_FILE.yaml

debug

It's a property in a tag
How to print log details for each of item. Default is info Value must be in:

  • true: is debug
  • all: Print all of debug message
  • trace: Print all of debug message
  • debug: Print short of debug
  • info: Print name, description without log details
  • warn: Only show warning debug
  • error: Only show error debug

Example:

  - name: Get data from a API
    debug: debug
    http'get:
      url: http://...../data.json

detach

It's a property in a tag
Push the tag execution to background jobs to run async, the next steps will be run ASAP. Before the program is exited, it will be released

Example:

  - name: job1
    detach: true
    loop: ${[1,2,3]}
    runs:
      - echo: Hello ${this.parentProxy.loopValue}
      - sleep: 1s
  - name: job2
    echo: first
  - name: job3
    echo: second

In above example, job2, job3 will run step by step, but job1 run in background, the program will wait job1 done then finish the program

else

It's a property in a tag
Check condition before run the item and skip the next cases when it passed

Example:

  - vars:
      number: 11

  - if: ${$vars.number === 11}
    echo: Value is 11                   # => Value is 11

  - elseif: ${$vars.number > 10}
    echo: Value is greater than 10      # =>

  - else:
    echo: Value is lessthan than 10     # =>

  - echo: Done                          # => Done

elseif

It's a property in a tag
Check condition before run the item and skip the next cases when it passed

Example:

  - vars:
      number: 11

  - if: ${$vars.number === 11}
    echo: Value is 11                   # => Value is 11

  - elseif: ${$vars.number > 10}
    echo: Value is greater than 10      # =>

  - elseif: ${$vars.number < 10}
    echo: Value is lessthan than 10     # =>

  - echo: Done                          # => Done

failure

It's a property in a tag
Handle error when do something wrong. Default it will exit app when something error.

  • ignore: Ignore error then keep playing the next
  • restart: max: 3 When got something error, it will be restarted automatically ASAP (-1/0 is same) sleep: 3000

Example:

  - failure:
      restart:                     # Try to restart 3 time before exit app. Each of retry, it will be sleep 3s before restart
        max: 3
        sleep: 3s
    js: |
      const a = 1/0
  - failure:
      ignore: true                 # Ignore error then play the next
    js: |
      const a = 1/0

id

It's a property in a tag
ID Reference to element object in the $vars

Example:

  - id: echo1
    echo: Hello

  - exec'js: |
      this.logger.debug($vars.echo1.content)

if

It's a property in a tag
Check condition before run the item

Example:

  - vars:
      number: 11

  - if: ${$vars.number === 11}
    echo: Value is 11                   # => Value is 11

  - if: ${$vars.number > 10}
    echo: Value is greater than 10      # => Value is greater than 10

  - if: ${$vars.number < 10}
    echo: Value is lessthan than 10     # =>

  - echo: Done                          # => Done

loop

It's a property in a tag
Loop to run items with a condition

Example:

Loop in array

  - vars:
      arrs: [1,2,3,4]
  - loop: ${$vars.arrs}
    echo: Index is ${$loopKey}, value is ${$loopValue}    # $loopKey ~ this.loopKey AND $loopValue ~ this.loopValue
  # =>
  # Index is 0, value is 1
  # Index is 1, value is 2
  # Index is 2, value is 3
  # Index is 3, value is 4

Loop in object

  - vars:
      obj: {
        "name": "thanh",
        "sex": "male"
      }
  - loop: ${$vars.obj}
    echo: Key is ${$loopKey}, value is ${$loopValue}
  # =>
  # Key is name, value is thanh
  # Key is sex, value is male

Dynamic loop in a condition

  - vars:
      i: 0
  - loop: ${$vars.i < 3}
    echo: value is ${$vars.i++}
  # =>
  # value is 0
  # value is 1
  # value is 2

Loop in nested items

  - vars:
      arrs: [1,2,3]
  - loop: ${$vars.arrs}
    name: group ${$loopValue}
    runs:
      - echo: item value is ${this.parent.loopValue}
  # =>
  # group 1
  # item value is 1

name

It's a property in a tag
Step name

Example:

  - name: Sleep in 1s
    sleep: 1000

only

It's a property in a tag
Only run this

Example:

  - echo: Hi                   # No print "hi"

  - only: true
    echo: Hello                # Only print "Hello"

  - echo: world                # No print "world"

  - only: true
    echo: Bye                  # Only print "Bye"

runs

It's a property in a tag
Steps will be run in the running element

Example:

  - http'server:
      address: 0.0.0.0:1234
    runs:
      - echo: Do something when a request comes
      - echo: Do something when a request comes...
      ...

skip

It's a property in a tag
No run this

Example:

  - echo: Hi                   # Print "hi"

  - skip: true
    echo: Hello                # No print "Hello"

  - echo: world                # Print "world"

skipNext

It's a property in a tag
Skip the next steps in the same parent group when done this

Example:

  - loop: ${ [1,2,3] }
    runs:
      - echo: begin                                          # Always print begin

      - echo: ${ this.parentProxy.loopValue }
        skipNext: ${ this.parentProxy.loopValue === 2 }      # When $loopValue is 2, skip the next step

      - echo: end                                            # Only print end when $loopValue is not equals 2

template

It's a property in a tag
Declare a template to extends later

Example:

  - ->: localhost           # Auto skip, not run it
    template:
      baseURL: http://localhost:3000

  - <-: localhost           # => Auto inherits "baseURL" from localhost
    http'get:
      url: /items

vars

It's a property in a tag

  • Set value in the item to global vars to reused later
  • Declare and set value to variables to reused in the scene/global scope
  • If the first character is uppercase, it's auto assigned to global which is used in the program (all of scenes)
  • If the first character is NOT uppercase, it will be assigned to scene scope which is only used in the scene

Example:

A main scene file

  - echo: Hello world
    vars: helloText             # Save output from echo to global variable "helloText"
  - echo: ${$vars.helloText}    # => Hello world

  - vars:
      MainName: global var      # Is used in all of scenes
      mainName: local var       # Only used in this scene

  - scene:
      path: ./child.scene.yaml

  - echo: ${$vars.MainName}      # => global var
  - echo: ${$vars.mainName}      # => local var
  - echo: ${$vars.name}          # => undefined
  - echo: ${$vars.Name}          # => global name here

A scene file child.scene.yaml is:

  - vars:
      Name: global name here
      name: scene name here     # Only used in this scene

  - echo: ${$vars.MainName}      # => global var
  - echo: ${$vars.mainName}      # => undefined
  - echo: ${$vars.name}          # => scene name here
  - echo: ${$vars.Name}          # => global name here

md'doc

doc
Generate comment in a file to document

Example:

  - doc'md:
      includeDirs:
        - /workspaces/ymlr/src/components/doc/md.ts
      includePattern: "^(?!.*\\.spec\\.ts$)"
      excludeDirs:
        - node_modules
      prependMDs:                                     # Prepend content in the document (Optional)
        - path: ../INSTALLATION.md                    # |- {path}: Read file content then copy it into document
        - ---                                         # |- string: Markdown content
      appendMDs:                                      # Append content in the document
        - ---
        - "### Have fun :)"
      saveTo: /workspaces/ymlr/test/thanh.doc.md

Declare doc in file Example

echo

Print to console screen

Example:

Print a message

  - echo: Hello world

  - echo:
      if: ${true}
      content: Hello

Print a variable

  - vars:
      name: thanh
  - echo: ${ $vars.name }

Print text with custom type. (Follow "chalk")

  - echo: Color is white

  - echo:
      styles: [red]
      content: Color is red
  - echo:
      styles: [red, bold]
      content: Content is red and bold

echo'debug

Add more information when print to console screen

Example:

Print a message

                                            # Default prepend execution time into log
  - echo'debug: Hello world                 # => 01:01:01.101    Hello world

  - echo'debug:
      formatTime: YYYY/MM/DD hh:mm:ss.ms    # Default format is "hh:mm:ss.ms"
      content: Hello                        # => 2023/01/01 01:01:01.101    Hello

clear

Clear console screen

Example:

  - clear:

event'emit

Send data via global event

Example:

  - event'emit:
      name: test-event
      data:
        name: Test event
        data: Hello
      opts:
        - params 1
        - params 2

event'on

Handle global events in app

Example:

  - event'on:
      name: test-event
    runs:
      - echo: ${ $parentState.eventData }   # => { name: Test event, data: Hello }
      - echo: ${ $parentState.eventOpts }   # => [ params 1, params 2 ]
  - event'emit:
      name: test-event
      data:
        name: Test event
        data: Hello
      opts:
        - params 1
        - params 2

fn-debounce

Debounce function (#Ref: lodash.debounce)

  • Without "wait" and "runs" then it's only touch with last agruments
  • Specific "wait" and "runs" then it's run with new agruments

Example:

  - fn-debounce:
      name: Delay to do something
      wait: 1s                # The number of milliseconds to delay.
      trailing: true          # Specify invoking on the trailing edge of the timeout. Default is true
      leading: false          # Specify invoking on the leading edge of the timeout. Default is false
      maxWait: 2s             # The maximum time func is allowed to be delayed before it's invoked.
    runs:
      - echo: Do this when it's free for 1s

  # touch if debounce is existed
  - fn-debounce:                          # Touch the existed throttle with last agruments
      name: Delay to do something
  # OR
  - fn-debounce: Delay to do something    # Touch the existed throttle with last agruments

fn-debounce'cancel

Cancel debounce function (#Ref: lodash.debounce)

Example:

  - fn-debounce'cancel:
      name: Delay to do something               # Debounce name to cancel
  # OR
  - fn-debounce'cancel: Delay to do something   # Debounce name to cancel
  # OR
  - fn-debounce'cancel:
      - delay1
      - delay2

fn-debounce'del

Cancel & remove debounce function (#Ref: lodash.debounce)

Example:

  - fn-debounce'del:
      name: Delay to do something               # Debounce name to delete
  # OR
  - fn-debounce'del: Delay to do something      # Debounce name to delete
  # OR
  - fn-debounce'del:
      - delay1
      - delay2

fn-debounce'flush

Force to call debounce function ASAP if it's called before that (#Ref: lodash.debounce)

Example:

  - fn-debounce'flush:
      name: Delay to do something                 # Debounce name to delete
  # OR
  - fn-debounce'flush: Delay to do something      # Debounce name to delete
  # OR
  - fn-debounce'flush:
      - delay1
      - delay2

fn-debounce'touch

touch debounce function. Reused last agruments(#Ref: lodash.debounce)

Example:

  - fn-debounce'touch:
      name: Delay to do something               # Debounce name to touch
  # OR
  - fn-debounce'touch: Delay to do something    # Debounce name to touch
  # OR
  - fn-debounce'touch:
      - delay1
      - delay2

fn-queue

Register a queue job

Example:

  - fn-queue:
      name: My Queue 1        # Use stateless queue, not reload after startup
      concurrent: 2
    runs:
      - echo: ${ $parentState.queueData.key1 } is ${ $parentState.queueData.value1 }

  - fn-queue'add:
      name: My Queue 1
      data:
        key1: value1
        key2: value 2
  - fn-queue:
      name: My Queue 1
      concurrent: 2
      skipError: false       # Not throw error when a job failed
      db:                    # Optional: Statefull queue, it's will reload after startup
        path: /tmp/db        #  - Optional: Default is "tempdir/queuename"
        password: abc        #  - Optional: Default is no encrypted by password
    runs:
      - echo: ${ $parentState.queueData.key1 } is ${ $parentState.queueData.value1 }

  - fn-queue'add:
      name: My Queue 1
      data:
        key1: value1
        key2: value 2

fn-queue'add

Add a job to an exsited queue

Example:

  - fn-queue'add:
      name: My Queue 1                 # Queue name to add
      data:                            # Job data
        key1: value1

fn-queue'del

Stop and remove a queue

Example:

  - fn-queue'del:
      name: My Queue 1                 # Queue name to delete
  # OR
  - fn-queue'del: My Queue 1           # Queue name to delete

fn-singleton

This is locked before run and unlock after done. When it's called many time, this is only run after unlock

Example:

  - fn-singleton:
      name: Only run 1 time
      trailing: true              # When someone call in the running but it's not finished yet, then it will run 1 time again after is unlocked
    runs:
      - echo: Do this when it's free for 1s

fn-singleton'del

Remove singleton function

Example:

  - fn-singleton'del:
      name: Delay to do something                 # Singleton name to delete
  # OR
  - fn-singleton'del: Delay to do something       # Singleton name to delete

fn-throttle

Throttle function (#Ref: lodash.throttle)

  • Without "wait" and "runs" then it's only touch with last agruments
  • Specific "wait" and "runs" then it's run with new agruments

Example:

  - fn-throttle:
      name: Delay to do something
      wait: 1s            # The number of milliseconds to throttle invocations to.
      trailing: true      # Specify invoking on the trailing edge of the timeout. Default is true
      leading: true      # Specify invoking on the leading edge of the timeout. Default is true
    runs:
      - echo: Do this when it's free for 1s

  # Call if throttle is existed
  - fn-throttle:                         # Touch the existed throttle with last agruments
      name: Delay to do something
  # OR
  - fn-throttle: Delay to do something   # Touch the existed throttle with last agruments

fn-throttle'cancel

Cancel throttle function (#Ref: lodash.throttle)

Example:

  - fn-throttle'cancel:
      name: Delay to do something               # Throttle name to cancel
  # OR
  - fn-throttle'cancel: Delay to do something   # Throttle name to cancel
  # OR
  - fn-throttle'cancel:
      - delay1
      - delay2

fn-throttle'del

Cancel & remove throttle function (#Ref: lodash.throttle)

Example:

  - fn-throttle'del:
      name: Delay to do something               # Throttle name to delete
  # OR
  - fn-throttle'del: Delay to do something      # Throttle name to delete
  # OR
  - fn-throttle'del:
      - delay1
      - delay2

fn-throttle'flush

Force to call throttle function ASAP if it's called before that (#Ref: lodash.throttle)

Example:

  - fn-throttle'flush:
      name: Delay to do something                 # Throttle name to delete
  # OR
  - fn-throttle'flush: Delay to do something      # Throttle name to delete
  # OR
  - fn-throttle'flush:
      - delay1
      - delay2

fn-throttle'touch

touch throttle function. Reused last agruments (#Ref: lodash.throttle)

Example:

  - fn-throttle'touch:
      name: Delay to do something               # Throttle name to touch
  # OR
  - fn-throttle'touch: Delay to do something   # Throttle name to touch
  # OR
  - fn-throttle'touch:
      - delay1
      - delay2

exec

Execute a program

Example:

Execute a bash script

  - name: Run a bash script
    exec:
      - /bin/sh
      - /startup.sh

Execute a python app

  - exec:
      - python
      - app.py

exec'js

Execute a nodejs code

Example:

Refers to "js" tag document

exec'sh

Execute a shell script

Example:

Refers to "sh" tag document

exit

Stop then quit the program

Example:

  - exit: 0

  - name: Throw error
    exit: 1

fetch'del

Send a http request with DELETE method

Example:

  # DELETE http://localhost:3000/posts/1?method=check_existed
  - name: Delete a post
    fetch'del:
      url: /posts/1
      baseURL: http://localhost:3000  # !optional - Request base url
      query:                          # !optional - Request query string
        method: check_existed
      headers:                        # !optional - Request headers
        authorization: Bearer TOKEN
      timeout: 5000                   # !optional - Request timeout. Default is no timeout
    vars:                             # !optional - Global variable which store value after executed
      status: ${this.response.status}

fetch'get

Send a http request with GET method

Example:

Get data from API then store value in vars.posts

  # GET http://localhost:3000/posts?category=users
  - name: Get list posts
    fetch'get:
      url: /posts
      timeout: 5000                   # !optional - Request timeout. Default is no timeout
      baseURL: http://localhost:3000  # !optional - Request base url
      query:                          # !optional - Request query string
        category: users
      headers:                        # !optional - Request headers
        authorization: Bearer TOKEN
      responseType: json              # !optional - Default is json ['json' | 'blob' | 'text' | 'buffer' | 'none']
    vars: posts                       # !optional - Global variable which store value after executed

Download file from a API

  # GET http://localhost:3000/posts?category=users
  - name: Download a file
    fetch'get:
      baseURL: http://localhost:3000
      url: /posts
      query:
        category: users
      headers:
        authorization: Bearer TOKEN
      saveTo: /tmp/post.json

fetch'head

Send a http request with HEAD method

Example:

  # HEAD http://localhost:3000/posts/1?method=check_existed
  - name: Check post is existed or not
    fetch'head:
      baseURL: http://localhost:
      timeout: 5000                   # !optional - Request timeout. Default is no timeout
                                      # supported: d h m s ~ day, hour, minute, seconds
                                      # example: 1h2m3s ~ 1 hour, 2 minutes, 3 seconds
      url: /posts/1
      query:
        method: check_existed
      headers:
        authorization: Bearer TOKEN
    vars:
      status: ${this.response?.status}

fetch'patch

Send a http request with PATCH method

Example:

Update apart of data to API then store value in vars.posts

  # PATCH http://localhost:3000/posts/ID?category=users
  - name: Update a post
    fetch'patch:
      baseURL: http://localhost:3000
      url: /posts/ID
      query:
        category: users
      headers:
        authorization: Bearer TOKEN
      type: json                      # 'json' | 'form' | 'raw' | 'multipart' | 'text'
      timeout: 5000                   # !optional - Request timeout. Default is no timeout
      body: {
        "title": "My title",
        "description": "My description"
      }
      responseType: json              # 'json' | 'blob' | 'text' | 'buffer' | 'none'
    vars: newPost

Upload file to server

  # PATCH http://localhost:3000/upload/ID_UPLOADER_TO_REPLACE
  - name: Upload and update data
    fetch'patch:
      baseURL: http://localhost:3000
      url: /upload/ID_UPLOADER_TO_REPLACE
      headers:
        authorization: Bearer TOKEN
      type: multipart
      body: {
        "file": { # File upload must includes path of file, name is optional
          "path": "/tmp/new_my_avatar.jpg",
          "name": "thanh_avatar"
        }
      }
    vars:
      status: ${this.response.status}

fetch'post

Send a http request with POST method

Example:

Post data to API then store value in vars.posts

  # POST http://localhost:3000/posts?category=users
  - name: Create a new post
    fetch'post:
      baseURL: http://localhost:3000
      url: /posts
      query:
        category: users
      headers:
        authorization: Bearer TOKEN
      type: json                      # 'json' | 'form' | 'raw' | 'multipart' | 'text'
      timeout: 5000                   # !optional - Request timeout. Default is no timeout
      body: {
        "title": "My title",
        "description": "My description"
      }
      responseType: json              # 'json' | 'blob' | 'text' | 'buffer' | 'none'
    vars: newPost

Upload file to server

  # POST http://localhost:3000/upload
  - name: Upload a new avatar
    fetch'post:
      baseURL: http://localhost:3000
      url: /upload
      headers:
        authorization: Bearer TOKEN
      type: multipart
      body: {
        "category": "avatar",
        "file": { # File upload must includes path of file, name is optional
          "path": "/tmp/my_avatar.jpg",
          "name": "thanh_avatar"
        }
      }
    vars:
      status: ${this.response.status}

fetch'put

Send a http request with PUT method

Example:

Update data to API then store value in vars.posts

  # PUT http://localhost:3000/posts/ID?category=users
  - name: Update a post
    fetch'put:
      baseURL: http://localhost:3000
      url: /posts/ID
      query:
        category: users
      headers:
        authorization: Bearer TOKEN
      type: json                      # 'json' | 'form' | 'raw' | 'multipart' | 'text'
      timeout: 5000                   # !optional - Request timeout. Default is no timeout
      body: {
        "title": "My title",
        "description": "My description"
      }
      responseType: json              # 'json' | 'blob' | 'text' | 'buffer' | 'none'
    vars: newPost

Upload file to server

  # PUT http://localhost:3000/upload/ID_UPLOADER_TO_REPLACE
  - name: Upload and update data
    fetch'put:
      baseURL: http://localhost:3000
      url: /upload/ID_UPLOADER_TO_REPLACE
      headers:
        authorization: Bearer TOKEN
      type: multipart
      body: {
        "category": "avatar updated",
        "file": { # File upload must includes path of file, name is optional
          "path": "/tmp/new_my_avatar.jpg",
          "name": "thanh_avatar"
        }
      }
    vars:
      status: ${this.response.status}

file'read

Read a file then load data into a variable

Example:

Read a json file

  - file'read:
      path: /tmp/data.json
      format: json  # !optional
    vars: fileData

Read a yaml file

  - file'read:
      path: /tmp/data.yaml
      format: yaml  # !optional
    vars: fileData

Read a text file

  - file'read:
      path: /tmp/data.txt
    vars: fileContent

file'store

Store data to file

Example:

  - file'store:
      path: /tmp/data.json      # Path to store data
      password:                 # Password to encrypt/decrypt data content
      initData: []              # Default data will be stored when file not found

Use in global by reference

  - file'store:
      path: /tmp/data.yaml
      initData: []
    vars:
      fileDB: ${this}         # Store this element to "fileDB" in vars

  - exec'js: |
      const { fileDB } = vars
      fileDB.data.push('item 1')
      fileDB.data.push('item 2')
      // Save data to file
      fileDB.save()

  - echo: ${$vars.fileDB.data}   # => ['item 1', 'item 2']

file'write

Write data to file

Example:

Write a json file

  - file'write:
      path: /tmp/data.json
      content: {
        "say": "hello"
      }
      format: json  # !optional
      pretty: true  # !optional

Write a yaml file

  - file'write:
      path: /tmp/data.yaml
      content: ${$vars.fileData}
      format: yaml  # !optional

Write a text file

  - file'write:
      path: /tmp/data.txt
      content: Hello world

http'del

Send a http request with DELETE method

Example:

  # DELETE http://localhost:3000/posts/1?method=check_existed
  - name: Delete a post
    http'del:
      url: /posts/1
      baseURL: http://localhost:3000  # !optional - Request base url
      query:                          # !optional - Request query string
        method: check_existed
      headers:                        # !optional - Request headers
        authorization: Bearer TOKEN
      timeout: 5000                   # !optional - Request timeout. Default is no timeout
    vars:                             # !optional - Global variable which store value after executed
      status: ${this.response.status}

http'get

Send a http request with GET method

Example:

Get data from API then store value in vars.posts

  # GET http://localhost:3000/posts?category=users
  - name: Get list posts
    http'get:
      url: /posts
      timeout: 5000                   # !optional - Request timeout. Default is no timeout
      baseURL: http://localhost:3000  # !optional - Request base url
      query:                          # !optional - Request query string
        category: users
      headers:                        # !optional - Request headers
        authorization: Bearer TOKEN
      responseType: json              # !optional - Default is json ['json' | 'blob' | 'text' | 'buffer' | 'none']
    vars: posts                       # !optional - Global variable which store value after executed

Download file from a API

  # GET http://localhost:3000/posts?category=users
  - name: Download a file
    http'get:
      baseURL: http://localhost:3000
      url: /posts
      query:
        category: users
      headers:
        authorization: Bearer TOKEN
      saveTo: /tmp/post.json

http'head

Send a http request with HEAD method

Example:

  # HEAD http://localhost:3000/posts/1?method=check_existed
  - name: Check post is existed or not
    http'head:
      baseURL: http://localhost:
      timeout: 5000                   # !optional - Request timeout. Default is no timeout
                                      # supported: d h m s ~ day, hour, minute, seconds
                                      # example: 1h2m3s ~ 1 hour, 2 minutes, 3 seconds
      url: /posts/1
      query:
        method: check_existed
      headers:
        authorization: Bearer TOKEN
    vars:
      status: ${this.response?.status}

http'patch

Send a http request with PATCH method

Example:

Update apart of data to API then store value in vars.posts

  # PATCH http://localhost:3000/posts/ID?category=users
  - name: Update a post
    http'patch:
      baseURL: http://localhost:3000
      url: /posts/ID
      query:
        category: users
      headers:
        authorization: Bearer TOKEN
      type: json                      # 'json' | 'form' | 'raw' | 'multipart' | 'text'
      timeout: 5000                   # !optional - Request timeout. Default is no timeout
      body: {
        "title": "My title",
        "description": "My description"
      }
      responseType: json              # 'json' | 'blob' | 'text' | 'buffer' | 'none'
    vars: newPost

Upload file to server

  # PATCH http://localhost:3000/upload/ID_UPLOADER_TO_REPLACE
  - name: Upload and update data
    http'patch:
      baseURL: http://localhost:3000
      url: /upload/ID_UPLOADER_TO_REPLACE
      headers:
        authorization: Bearer TOKEN
      type: multipart
      body: {
        "file": { # File upload must includes path of file, name is optional
          "path": "/tmp/new_my_avatar.jpg",
          "name": "thanh_avatar"
        }
      }
    vars:
      status: ${this.response.status}

http'post

Send a http request with POST method

Example:

Post data to API then store value in vars.posts

  # POST http://localhost:3000/posts?category=users
  - name: Create a new post
    http'post:
      baseURL: http://localhost:3000
      url: /posts
      query:
        category: users
      headers:
        authorization: Bearer TOKEN
      type: json                      # 'json' | 'form' | 'raw' | 'multipart' | 'text'
      timeout: 5000                   # !optional - Request timeout. Default is no timeout
      body: {
        "title": "My title",
        "description": "My description"
      }
      responseType: json              # 'json' | 'blob' | 'text' | 'buffer' | 'none'
    vars: newPost

Upload file to server

  # POST http://localhost:3000/upload
  - name: Upload a new avatar
    http'post:
      baseURL: http://localhost:3000
      url: /upload
      headers:
        authorization: Bearer TOKEN
      type: multipart
      body: {
        "category": "avatar",
        "file": { # File upload must includes path of file, name is optional
          "path": "/tmp/my_avatar.jpg",
          "name": "thanh_avatar"
        }
      }
    vars:
      status: ${this.response.status}

http'put

Send a http request with PUT method

Example:

Update data to API then store value in vars.posts

  # PUT http://localhost:3000/posts/ID?category=users
  - name: Update a post
    http'put:
      baseURL: http://localhost:3000
      url: /posts/ID
      query:
        category: users
      headers:
        authorization: Bearer TOKEN
      type: json                      # 'json' | 'form' | 'raw' | 'multipart' | 'text'
      timeout: 5000                   # !optional - Request timeout. Default is no timeout
      body: {
        "title": "My title",
        "description": "My description"
      }
      responseType: json              # 'json' | 'blob' | 'text' | 'buffer' | 'none'
    vars: newPost

Upload file to server

  # PUT http://localhost:3000/upload/ID_UPLOADER_TO_REPLACE
  - name: Upload and update data
    http'put:
      baseURL: http://localhost:3000
      url: /upload/ID_UPLOADER_TO_REPLACE
      headers:
        authorization: Bearer TOKEN
      type: multipart
      body: {
        "category": "avatar updated",
        "file": { # File upload must includes path of file, name is optional
          "path": "/tmp/new_my_avatar.jpg",
          "name": "thanh_avatar"
        }
      }
    vars:
      status: ${this.response.status}

http'server

Create a http server to serve content via http

Example:

  - http'server:
      address: 0.0.0.0:8811                   # Address to listen
      auth:                                   # Check authentication
        basic:                                # 'Basic ' + base64(`${username}:${password}`)
          username: username
          password: password
        custom:
          secret: 'SERVER_SECRET_TOKEN'
          secretKey: SECRET_HEADER_KEY
          verify(): |
            return $parentState.headers[this.secretKey] === this.secret
    runs:                                   # Execute when a request comes
      - echo: ${ $parentState.path }        # Get request path
      - echo: ${ $parentState.method }      # Get request method
      - echo: ${ $parentState.headers }     # Get request headers
      - echo: ${ $parentState.query }       # Get request query string
      - echo: ${ $parentState.body }        # Get request body
      - echo: ${ $parentState.response }    # Set response data
                                            # - status: 200       - http response status
                                            # - statusMessage: OK - http response status message
                                            # - headers: {}       - Set response headers
                                            # - data: {}          - Set response data
      - echo: ${ $parentState.req }         # Ref to req in http.IncomingMessage in nodejs
      - echo: ${ $parentState.res }         # Ref to res in http.ServerResponse in nodejs
      - js: |                               # Handle response by yourself (When $parentState.response is undefined)
          $parentState.res.status = 200
          $parentState.res.statusMessage = 'OK'
          $parentState.res.write('OK')
          $parentState.res.end()

include

Include a scene file or list scene files in a folder

Example:

  - include: ./my-scenes/scene1.yaml  # Includes a only file "scene1.yaml"

  - include:
      file: ./my-scenes               # Includes all of files (.yaml, .yml) which in the directory (./my-scenes)
      cached: true                    # Load file for the first time, the next will get from caches

input'confirm

Get user confirm (yes/no)

Example:

# - input'conf:
  - input'confirm:
      title: Are you sure to delete it ?
      default: false  # !optional
      required: true  # !optional
    vars: userWantToDelete

input'multiselect

Suggest a list of choices for user then allow pick multiple choices

Example:

# - input'msel:
  - input'multiselect:
      title: Please select your hobbies ?
      choices:
        - title: Tennis
          value: tn
        - title: Football
          value: fb
        - title: Basket ball
          value: bb
      default: [tn, fb]   # !optional
      required: true      # !optional
    vars: hobbies

input'number

Get user input from keyboard then convert to number

Example:

# - input'num:
  - input'number:
      title: Enter your age ?
      default: 18     # !optional
      required: true  # !optional
    vars: age

input'password

Get user input from keyboard but hide them then convert to text

Example:

# - input'pwd:
  - input'password:
      title: Enter your password ?
      required: true  # !optional
    vars: password

input'select

Suggest a list of choices for user then allow pick a choice

Example:

# - input'sel:
  - input'select:
      title: Your sex ?
      choices:
        - title: male
          value: m
        - title: female
          value: f
      default: m      # !optional
      required: true  # !optional
    vars: sex

input'suggest

Suggest a list of choices for user then allow pick a choice or create a new one

Example:

# - input'sug:
  - input'suggest:
      title: Your hobby
      choices:
        - title: Football
          value: football
        - title: Basket Ball
          value: backetball
      default: football                         # !optional
      required: true                            # !optional
      suggestType: INCLUDE_AND_ALLOW_NEW        # Must be in [STARTSWITH_AND_ALLOW_NEW, INCLUDE_AND_ALLOW_NEW, STARTSWITH, INCLUDE]
                                                # - "INCLUDE": Only find in the text in the list suggestions
                                                # - "INCLUDE_AND_ALLOW_NEW": Same "INCLUDE" and allow to create a new one if not in the list suggestions
                                                # - "STARTSWITH": Only find in the start of text
                                                # - "STARTSWITH_AND_ALLOW_NEW": Same "STARTSWITH" and allow to create a new one if not in the list suggestions
    vars: hobby

input'text

Get user input from keyboard then convert to text

Example:

# - input:
  - input'text:
      title: Enter your name
      default: Noname # !optional
      required: true  # !optional
    vars: name

js

Execute a nodejs code

Example:

Set value to a variable

  - name: Set value to a variable
    js: |
      vars.name = 'thanh'
      logger.info(vars.name)

Write a file

  - name: Write a file
    js:
      path: /sayHello.sh              # Path of js file (Use only "path" OR "script")
      script: |                       # NodeJS content
        const { writeFileSync } = require('fs')
        writeFileSync('/tmp/hello.txt', 'Hello world')
        return "OK"
    vars: result                      # !optional

npm'install

Install librarries to use in the scene.

Example:

  - npm'install: module1, module2

  - npm'install:
      - module1
      - myapp: git+ssh:git@github.com:...

  - Always get latest ymlr-telegram librarry
    npm'install: [lodash, ymlr-telegram@latest]

  # How to used
  - exec'js: |
      vars.newObject = require('lodash').merge({a: 2, b: 2}, {a: 1})
      require('myapp')

  - echo: ${$vars.newObject}

Install from github

  - name: Install from github
    if: ${$vars.useExternalPackage}
    npm'install:
      - myapp: git+ssh:git@github.com:...
      - ymlr...

  # How to used
  - myapp:
      name: This is my first application

npm'uninstall

Uninstall librarries to use in the scene.

Example:

  - npm'uninstall: module1, module2

  - npm'uninstall:
      - module1
      - myapp

  - name: Uninstall librarry
    npm'uninstall: [ymlr-telegram, ymlr...]

pause

Pause the program then wait to user enter to continue

Example:

  - pause:

  - name: Pause here
    pause:

runs

Group elements

Example:

  - name: Print all of message
    runs:
      - echo: hello
      - echo: world
      - name: Stop
        runs:
          - exit:

scene

Load another scene into the running program

Example:

  - name: A scene from remote server
    # scene: ./another.yaml             # path can be URL or local path
    scene:
      name: Scene name
      path: https://.../another.yaml    # path can be URL or local path
      cached: false                     # caches yaml content to ram to prevent reload content from a file
      password:                         # password to decode when the file is encrypted
      env:                              # Set to env variable. Support an array or object (- key=value) (key: value)
        NODE_ENV: production
        # Or
        - NODE_ENV=production
      vars:                             # They will only overrides vars in the parents to this scene
                                        # - Global variables is always passed into this scene
        foo: scene bar                  # First is lowercase is vars which is used in scenes
        Foo: Global bar                 # First is uppercase is global vars which is used in the program
        localVars: ${ $vars.parentVar } # This will get value of "$vars.parentVar" in the parent then pass it into "$vars.localVars" which is used in this scene
      envFiles:                         # Load env variable from files (string | string[])
        - .env
        - .env.dev
      varsFiles:                        # Load vars from json or yaml files (string | string[])
        - ./var1.json
        - ./var2.yaml

scene'returns

Return value to parent scene

Example:

Scene sum.yaml

  vars:
    x: 0
    y: 0
  runs:
    - vars:
        result: ${ $vars.x + $vars.y }

    - scene'returns: ${ $vars.result }

Main scene index.yaml

  - name: Load a scene to sum 2 digits
    scene:
      path: .../sum.yaml
      vars:
        x: 10
        y: 20
    vars: sumOfXY

  - echo: ${ $vars.sumOfXY }    # => 30

scene'thread

Same "scene" but it run in a new thread

Example:

  - name: A scene run in a new thread
    # scene'thread: ./another.yaml     # path can be URL or local path
    scene'thread:
      id: #newID                        # thread id (optional)
      name: Scene name
      path: https://.../another.yaml    # path can be URL or local path
      password:                         # password to decode when the file is encrypted
      vars:                             # They will only overrides vars in the parents to this scene
                                        # - Global variables is always passed into this scene
        foo: scene bar                  # First is lowercase is vars which is used in scenes
        Foo: Global bar                 # First is uppercase is global vars which is used in the program
        localVars: ${ $vars.parentVar } # This will get value of "$vars.parentVar" in the parent then pass it into "$vars.localVars" which is used in this scene

Send data via global event between threads and each others. (Includes main thread) main.yaml

  name: This is main thread
  runs:
    - name: Run in a new thread 1
      detach: true
      scene'thread:
        id: thread1
        path: ./new_thread.yaml
        vars:
          name: thread 1
    - name: Run in a new thread 2
      detach: true
      scene'thread:
        id: thread2
        path: ./new_thread.yaml
        vars:
          name: thread 2

    - sleep: 1s

    - name: Listen data from childs thread
      ~event'on:
        name: ${ $const.FROM_GLOBAL_EVENT }
      runs:
        - name: Received data from thread ID ${ $parentState.eventOpt.fromID }
          echo: ${ $parentState.eventData }

    - name: Emit data to childs threads
      ~event'emit:
        name: ${ $const.TO_GLOBAL_EVENT }
        data:
          name: this is data from main thread

new_thread.yaml

  vars:
    name: Thread name will be overried by parent scene
  runs:
    - event'on:
        name: ${ $const.FROM_GLOBAL_EVENT }
      runs:
        - name: Thread ${ $vars.name } is received data from thread ID ${ $parentState.eventOpt.fromID }
          echo: ${ $parentState.eventData }

        - name: Thead ${ $vars.name } sent data to global event
          event'emit:
            name: ${ $const.TO_GLOBAL_EVENT }
            data:
              name: this is data from thread ${ $vars.name }
            # opts:
            #  toIDs: ['thread1']             # Specific the thread ID to send. Default it send to all
        - sleep: 2s
        - stop:

sh

Execute a shell script

Example:

Execute a sh file

  - name: Write a hello file
    sh:
      path: /sayHello.sh              # Path of sh file (Use only "path" OR "script")
    vars: log       # !optional

Execute a bash script

  - name: Write a hello file
    sh:
      script: |                       # Shell script content
        touch hello.txt
        echo "Hello world" > /tmp/hello.txt
      bin: /bin/sh                    # !optional. Default use /bin/sh to run sh script
      timeout: 10m                    # Time to run before force quit
      process: true                   # Create a new child process to execute it. Default is false
      opts:                           # Ref: "SpawnOptionsWithoutStdio", "ExecFileOptions" in nodeJS
        detached: true
        ...
    vars: log                         # !optional

sleep

Sleep the program then wait to user enter to continue

Example:

Sleep for a time

  • 1d = 1 day
  • 1h = 1 hour
  • 1m = 1 minute
  • 1s = 1 second
  • 1ms = 1 milisecond
  - sleep: 10000            # Sleep 10s then keep continue
  - sleep: 10s              # Sleep 10s then keep continue
  - sleep: 1h1m20s          # Sleep in 1 hour, 1 minute and 20 seconds then keep continue

Full props

  - name: Sleep 10s
    sleep: 10000          # Sleep 10s then keep continue

tag'register

Register custom tags from code or npm module, github....

Example:

Register custom tags from a file

  - tag'register:
      test1: /workspaces/ymlr/test/resources/test.js       # { tagName: pathOfModule }

  - test1:
      foo: bar

Register custom tags from an object

  - tag'register:
      newOne: |
        {
          constructor(props) {
            Object.assign(this, props)
          },
          async asyncConstructor(props) {
            // Do async job to init data
          },
          exec() {
            this.logger.info('ok ' + this.name, this.tag)
          },
          dispose() {
            // Dispose after finished this
          }
        }

  - newOne:
      name: foo

Register custom tags from a class

  - tag'register:
      newOne: |
        class {
          constructor(props) {
            Object.assign(this, props)
          }
          async asyncConstructor(props) {
            // Do async job to init data
          }
          exec() {
            this.logger.info('ok ' + this.name, this.tag)
          }
          dispose() {
            // Dispose after finished this
          }
        }

  - newOne:
      name: foo

test

Check conditions in the program

Example:

Quick test

  - test:
      title: Number must be greater than 10
      check: ${$vars.age > 10}

  - test: ${$vars.age < 10}

Test with nodejs script

  - test:
      title: Number must be greater than 10
      script: |
        if (vars.age > 10) this.$.failed('Age is not valid')

$utils.base64

Utility function
Base64 encrypt/decrypt a string

Example:

  - echo: ${ $utils.base64.encrypt('hello world') }

  - echo: ${ $utils.base64.decrypt('$ENCRYPTED_STRING') }

$utils.base64

Utility function
AES encrypt/decrypt a string

Example:

  - echo: ${ $utils.aes.encrypt('hello world') }

  - echo: ${ $utils.aes.decrypt('$ENCRYPTED_STRING') }

$utils.format

Utility function
Formater

Example:

- echo: ${ $utils.format.fileName('a@(*&#à.jpg', ' ') }                             # => a a.jpg

- echo: ${ $utils.format.number(1000000) }                                          # => 1,000,000

- echo: ${ $utils.format.number(1000000) }                                          # => 1,000,000

- echo: ${ $utils.format.fixLengthNumber(1, 2) }                                    # => 001
- echo: ${ $utils.format.fixLengthNumber(10, 2) }                                   # => 010

- echo: ${ $utils.format.formatTextToMs('1d 1h 1m 1s 100') }                        # => 90061100

- echo: ${ $utils.format.formatTextToMs(new Date(), 'DD/MM/YYYY hh:mm:ss.ms') }     # => 01/12/2023 23:59:59.0

- echo: ${ $utils.format.yaml({name: 'yaml title'})}                                # => name: yaml title

$utils.globalEvent

Utility function
Reference global event in application

Example:

  - js: |
      $utils.globalEvent.on('say', (name) => {
        this.logger.info('Hello', name)
      })

  - js: |
      $utils.globalEvent.emit('say', 'Thanh 01')

$utils.md5

Utility function
Encrypt a string to md5

Example:

  - echo: ${ $utils.md5.encrypt('hello world') }

$utils.parse

Utility function
Parser

Example:

- echo: ${ $utils.parse.yaml('title: "yaml title"') }       # => { "title": "yaml title" }  

<br/>

### Have fun :)

Readme

Keywords

Package Sidebar

Install

npm i ymlr

Weekly Downloads

24

Version

1.2.6-alpha.34

License

ISC

Unpacked Size

615 kB

Total Files

716

Last publish

Collaborators

  • circle2jt