项目作者: cirbuk

项目描述 :
Resolve marked up JavaScript object/array/string against a data object.
高级语言: JavaScript
项目地址: git://github.com/cirbuk/resolver.git
创建时间: 2019-08-06T17:19:10Z
项目社区:https://github.com/cirbuk/resolver

开源协议:MIT License

下载


@kubric/resolver Featured on Openbase

Resolver is capable of resolving any marked up JavaScript object/array/string against a data object.

Installation

  1. npm install @kubric/resolver

or

  1. yarn add @kubric/resolver

Usage

  1. import Resolver from "@kubric/resolver"
  2. //Data JSON
  3. const data = {
  4. isFormData: false,
  5. appName: 'an_app',
  6. email: [{
  7. id: 'abc@gmail.com',
  8. }],
  9. mapValue: {
  10. data: {
  11. name: "tester",
  12. id: 1234
  13. }
  14. },
  15. };
  16. //Template JSON
  17. const template = {
  18. method: 'post',
  19. isFormData: '{{isFormData}}',
  20. userId: 'userid_{{mapValue.data.id}}',
  21. data: {
  22. userid: '{{email.0.id}}',
  23. app_name: '{{appName}}',
  24. },
  25. extraData: '{{mapValue.data}}'
  26. };
  27. const resolver = new Resolver();
  28. const resolvedData = resolver.resolve(template, data);
  29. // resolvedData will be
  30. // {
  31. // method: 'post',
  32. // isFormData: false,
  33. // userId: 'userid_1234',
  34. // data: {
  35. // userid: 'abc@gmail.com',
  36. // app_name: 'an_app'
  37. // },
  38. // extraData: {
  39. // name: "tester",
  40. // id: 1234
  41. // }
  42. // }

Default values

Default values can be provided in the markup, to support the case when the mapping path results in an undefined when resolved against the data

  1. import Resolver from "@kubric/resolver"
  2. //Data JSON
  3. const data = {};
  4. //Template JSON
  5. const template = {
  6. method: 'post',
  7. isFormData: '{{isFormData|false}}',
  8. userId: 'userid_{{mapValue.data.id|1234}}',
  9. data: {
  10. userid: '{{email.0.id|abc@gmail.com}}',
  11. app_name: '{{appName|an_app}}',
  12. }
  13. };
  14. const resolver = new Resolver();
  15. const resolvedData = resolver.resolve(template, data);
  16. // resolvedData will be
  17. // {
  18. // method: 'post',
  19. // isFormData: 'false',
  20. // userId: 'userid_1234',
  21. // data: {
  22. // userid: 'abc@gmail.com',
  23. // app_name: 'an_app'
  24. // }
  25. // }

Type conversion

By default, the resolver always resolve to whatever type is returned from the data. This behavior can be altered by forcing a type conversion. The following 7 types are supported - number, object, array, string, boolean and null.

  1. import Resolver from "@kubric/resolver"
  2. //Data JSON
  3. const data = {
  4. once: 1,
  5. numberstring: "3",
  6. number: 4,
  7. stringnumber: 10,
  8. booleanstring: "test",
  9. boolean: true,
  10. array: [1],
  11. object: {
  12. one: 1
  13. },
  14. objectstring: '{"four":4}',
  15. null: 5
  16. };
  17. //Template JSON
  18. const template = {
  19. //{{data.once|5}} = 1 resolved from data. Default value "5" is ignored
  20. //{{data.twice|2}} = "2" resolved from default value.
  21. withinstring: "replacing within string once {{data.once|5}} and twice {{data.twice|2}}",
  22. //{{data.notypedefault|5}} = "5" resolved from default value
  23. notypedefault: "{{data.notypedefault|5}}",
  24. //{{data.numberstring||number}} = 3 resolved from data.numberstring("3") and
  25. //converted to number(3)
  26. numberstring: "{{data.numberstring||number}}",
  27. //{{data.number||number}} = 4 resolved from data.number(4) and converted to
  28. //number(4)
  29. number: "{{data.number||number}}",
  30. //{{data.numberdefault|5|number}} = 5 resolved from defaultValue("5") and
  31. //converted to number(5)
  32. numberdefault: "{{data.numberdefault|5|number}}",
  33. //{{data.stringnumber||string}} = "10" resolved from data.stringnumber(10) and
  34. //converted to string("10")
  35. stringnumber: "{{data.stringnumber||string}}",
  36. //{{data.stringdefault|test|string}} = "test" resolved from default value("test")
  37. stringdefault: "{{data.stringdefault|test|string}}",
  38. //boolean type resolves to true for boolean true and string "true". It resolve
  39. //to false for everything else
  40. //{{data.booldefault|test|boolean}} = false resolved from default value("test").
  41. booldefault: "{{data.booldefault|test|boolean}}",
  42. //{{data.boolfalsedefault|true|boolean}} = true resolved from default value
  43. //("true").
  44. booltruedefault: "{{data.boolfalsedefault|true|boolean}}",
  45. //{{data.booleanstring||boolean}} = false resolved from data.booleanstring
  46. //("test").
  47. booleanstring: "{{data.booleanstring||boolean}}",
  48. //{{data.boolean||boolean}} = true resolved from data.boolean(true).
  49. boolean: "{{data.boolean||boolean}}",
  50. //{{data.array|[2,3]|array}} = [1] resolved from data.array([1])
  51. array: "{{data.array|[2,3]|array}}",
  52. //{{data.defaultarray|[2,3]|array}} = [2,3] resolved from default value("[2,3]")
  53. //and converted to array([2,3])
  54. defaultarray: "{{data.defaultarray|[2,3]|array}}",
  55. //{{data.defaultarray|[2,3]}} = "[2,3]" resolved from default value("[2,3]")
  56. arraystring: "{{data.defaultarray|[2,3]}}",
  57. //{{data.object|{"two": 2, "three": 3}|object}} = {"one":1} resolved from
  58. //data.object({"one":1})
  59. object: '{{data.object|{"two": 2, "three": 3}|object}}',
  60. //{{data.defaultobject|{"two": 2, "three": 3}|object}} = {"two":2,"three":3}
  61. //resolved from default value('{"two": 2, "three": 3}') and converted to object
  62. //({"two": 2, "three": 3})
  63. defaultobject: '{{data.defaultobject|{"two": 2, "three": 3}|object}}',
  64. //{{data.defaultobject|{"two": 2, "three": 3}}} = '{"two": 2, "three": 3}'
  65. //resolved from default value('{"two": 2, "three": 3}')
  66. defaultobjectstring: '{{data.defaultobject|{"two": 2, "three": 3}}}',
  67. //{{data.objectstring||object}} = {"four": 4} resolved from data.objectstring
  68. //('{"four": 4}') and converted to object({"four": 4})
  69. objectstring: '{{data.objectstring||object}}',
  70. //null is a special type. If the type is null and the mapping results in an
  71. //undefined value, the mapping resolved to null
  72. //{{data.nulldefault||null}} = null as data.nulldefault returns undefined
  73. nulldefault: '{{data.nulldefault||null}}',
  74. //{{data.null||null}} = 5 resolved from data.null(5)
  75. null: '{{data.null||null}}',
  76. };
  77. const resolver = new Resolver();
  78. const resolvedData = resolver.resolve(template, data);
  79. // resolvedData will be
  80. // {
  81. // withinstring: "replacing within string once 1 and twice 2",
  82. // notypedefault: "5",
  83. // numberstring: 3,
  84. // number: 4,
  85. // numberdefault: 5,
  86. // stringnumber: "10",
  87. // stringdefault: "test",
  88. // booldefault: false,
  89. // booltruedefault: true,
  90. // booleanstring: false,
  91. // boolean: true,
  92. // array: [1],
  93. // defaultarray: [2, 3],
  94. // arraystring: "[2,3]",
  95. // defaultobjectstring: '{"two": 2, "three": 3}',
  96. // defaultobject: {
  97. // two: 2,
  98. // three: 3
  99. // },
  100. // object: {
  101. // one: 1
  102. // },
  103. // objectstring: {
  104. // four: 4
  105. // },
  106. // nulldefault: null,
  107. // null: 5
  108. // }

Transformers

Transformers can be defined in the template when extracted data need to be transformed before being applied.

In the template if any of the properties have as its value, an object with just the 2 properties _mapping and _transformer where _transformer is a function, then the resolver will resolve the mapping string from the data object and get the value resolved by passing it to the transformer function.

  1. import Resolver from "@kubric/resolver"
  2. const data = {
  3. isFormData: false,
  4. };
  5. const template = {
  6. method: 'post',
  7. isFormData: {
  8. //resolves to false
  9. _mapping: "{{isFormData}}",
  10. //The value false resolved using the _mapping is passed to the function. The
  11. //value that the function returns will become the value of isFormData
  12. _transformer(value) {
  13. return value === false ? "This is a false value" : "This is a true value";
  14. }
  15. }
  16. };
  17. const resolver = new Resolver();
  18. const resolvedData = resolver.resolve(template, data);
  19. // resolvedData will be
  20. // {
  21. // isFormData: 'This is a false value',
  22. // }

Transformers can be defined in 3 places

  1. mapping: This transformer affects only the mapping for which it is defined. eg. The transformer defined in the above code. A mapping transformer, if defined will always be called.
  2. resolve() function call: When resolve() is called, a transformer function can be passed in the options(see resolve())). This transformer will be called for every mapping in the template, other than the mappings that have a transformer already defined.
  3. new Resolver(): When a resolver instance is created, a transformer can b e passed in the options(see options). This transformer will be called for all mappings for all calls to the resolve() function.

Rules for transformer invocation are as follows

  1. Only one transformer will be called for a mapping
  2. Order of precedence of if transformers have been defined in multiple levels - mapping > resolve() > new Resolver()

Mappers

The resolver’s default behavior is to try and replace everything between {{ and }} with values from the data json. mappers can be used to define other markup operators.

  1. import Resolver from "@kubric/resolver"
  2. import math from "math-expression-evaluator";
  3. const data = {
  4. val1: "1",
  5. val2: "2",
  6. val3: "3",
  7. val4: "4",
  8. };
  9. const evaluators = {
  10. // "data" is the data that has been passed for resolution to the resolve()
  11. // call
  12. math: (match, formula, data) => {
  13. try {
  14. return +math.eval(formula);
  15. } catch (ex) {
  16. return match;
  17. }
  18. }
  19. };
  20. const template = {
  21. //Multiple mappings are used inside a string here. So the values returned by
  22. //the evaluator will be replaced into the string. The final value here will
  23. //be the string "3 and 7"
  24. calculatedStringValue: "[[{{val1}} + {{val2}}]] and [[{{val3}} + {{val4}}]]",
  25. //The entire string is one mapping. So value returned by the evaluator will be
  26. //assigned as such. The final value here will be the number 5
  27. calculatedNumberValue: "[[{{val1}} + {{val4}}]]"
  28. };
  29. //Anything that is enclosed within [[ and ]] will be passed to the math evaluator
  30. const resolver = new Resolver({
  31. //Anything enclosed between [[ and ]] will be sent to the math evaluator
  32. mappers: [
  33. [/\[\[(.+?)]]/g, evaluators.math]
  34. ]
  35. });
  36. const resolvedData = resolver.resolve(template, data);
  37. // resolvedData will be
  38. // {
  39. // calculatedStringValue: '3 and 7',
  40. // calculatedNumberValue: 5
  41. // }

mappers take effect only after standard mappings(mappings between {{ and }}) are resolved and the transformer pipeline has been executed. The standard mapping operator cannot be overridden using custom mappers.

Nested mapping

  1. import Resolver from "@kubric/resolver"
  2. //Data JSON
  3. const data = {
  4. property: "value",
  5. index: {
  6. value: "2",
  7. value1: 0
  8. },
  9. array: ["one", "two", ["3"]]
  10. };
  11. //Template JSON
  12. const template = {
  13. string: "This is a string that has been resolved from a " +
  14. "{{array.{{index.{{property}}||number}}.{{index.value1}}||number}} level nested mapping"
  15. };
  16. const resolver = new Resolver();
  17. const resolvedData = resolver.resolve(template, data);
  18. // resolvedData will be
  19. // {
  20. // string: "This is a string that has been resolved from a 3 level nested mapping"
  21. // }
  22. // {{property}} - Resolves to "value" and the mapping becomes {{array.{{index.value||number}}.{{index.value1}}||number}}
  23. // {{index.value||number}} - Resolves to 2 and the mapping becomes {{array.2.{{index.value1}}||number}}
  24. // {{index.value1}} - Resolves to 0 and the mapping becomes {{array.2.0||number}}
  25. // {{array.2.0||number}} - Resolves to 3

API

new Resolver(options)

Creates a new Resolver instance

options

options should be an object with the following properties

Property Description Remarks
replaceUndefinedWith If a mapping path does not exist or is marked as undefined in the data json, the value of that mapping is taken to be undefined. replaceUndefinedWith can be used to replace such missing mappings with a custom value. optional
ignoreUndefined If true, mappings that do not exist or returns undefined from the data json will be ignored and left as is without resolving them. optional

Default value: false.
transformer Resolver instance level transformer can be defined here optional

See Transformers
mappers Used to define custom markup operators and their behavior optional

Refer mappers
delimiter Sets the delimiter pattern that is used to delimit between mapping, default value and type in a mapping string. optional

Default value: `
`
fields It accepts an object with string properties mapping and transformer whose values will replace _mapping and _transformer as the keywords while defining a transformer for a single mapping. optional

Defaults to { mapping: "_mapping", tranformer: "_transformer" }
overrideDefault If true, will override the default resolver behavior i.e. it will avoid resolving content between {{}} and will rely entirely on the mappers for resolution. optional

Default value: false

resolver.resolve(template, data, options)

Property Description Remarks
template JS object/string/array that needs to be resolved against data required
data JSON object against which the template will be resolved optional
options.transformer If defined, this function will be called to transform the value of every mapping defined in template except if there is an exclusive transformer defined for a mapping optional

See Transformers
options.mappers If defined, will override the mappers defined at an instance level for that invocation of the resolve() function optional

Refer mappers
options.overrideDefault If defined, will override the overrideDefault defined at an instance level for that invocation of the resolve() function optional

Refer options