url-templates 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Validate a template.
3
- * Returns true or throws a detailed error.
3
+ * @returns true or throws a detailed error.
4
4
  *
5
5
  * @throws {TypeError | Error}
6
6
  */
@@ -8,29 +8,47 @@ declare function isUrlTemplate(template: string): boolean;
8
8
 
9
9
  /**
10
10
  * Inspect a template.
11
- * Returns the parsed AST.
11
+ * @returns the parsed AST.
12
12
  */
13
13
  declare function inspect(template: string): any[];
14
14
 
15
+ /**
16
+ * Expand the compiled template by given vars.
17
+ * @param vars - the object containing expansion variables.
18
+ * @param callback - optional function that receives the current key and should return a replacement for current value.
19
+ * @returns the expanded template.
20
+ */
21
+ declare function expand(vars: any, callback?: { key: string }): string
22
+
15
23
  /**
16
24
  * Parse and validate a template.
17
- * Returns an object with an expand() method.
25
+ * @returns an object with an expand() method.
18
26
  *
19
27
  * @throws {TypeError | Error}
20
28
  */
21
- declare function parseTemplate(template: string): { expand(vars?: any): string };
29
+ declare function parseTemplate(template: string): { expand: typeof expand };
22
30
 
23
31
  /**
24
32
  * Compile a template without validation.
25
- * Returns an object with an expand() method.
33
+ * @returns an object with an expand() method.
34
+ */
35
+ declare function compile(template: string): { expand: typeof expand };
36
+
37
+ /**
38
+ * Recursively compile a template without validation.
39
+ * @param vars - the object containing expansion variables.
40
+ * @param templateKey - starter template key, must be a vars[key].
41
+ * @param callback - optional function that receives the current key and should return a replacement for current value.
42
+ * @returns the recursively compiled and expanded template.
26
43
  */
27
- declare function compile(template: string): { expand(vars?: any): string };
44
+ declare function recursiveCompile(vars: object, templateKey: string, callback?: { key: string } ): string;
28
45
 
29
46
  declare const urlTemplates: {
30
47
  isUrlTemplate: typeof isUrlTemplate;
31
48
  inspect: typeof inspect;
32
49
  parseTemplate: typeof parseTemplate;
33
50
  compile: typeof compile;
51
+ recursiveCompile: typeof recursiveCompile;
34
52
  };
35
53
 
36
54
  export = urlTemplates;
package/index.js CHANGED
@@ -55,7 +55,7 @@ function isUrlTemplate(template, inspect) {
55
55
  function parseTemplate(template, validate) {
56
56
  if (validate) isUrlTemplate(template);
57
57
  return {
58
- expand: (vars = {}) =>
58
+ expand: (vars = {}, callback) =>
59
59
  template.replace(/([^\{\}]+)|\{([^\{\}])([^\{\}]*)\}/g, (match, literal, first, expression) => {
60
60
  if (first + expression) {
61
61
  const values = [];
@@ -64,7 +64,7 @@ function parseTemplate(template, validate) {
64
64
  expression.split(/,/g).forEach((variable) => {
65
65
  const match = /(?<key>[^:\*]*)(?::(?<length>\d+)|(?<explode>\*))?/.exec(variable).groups;
66
66
  const key = match.key;
67
- const value = vars[key];
67
+ const value = typeof callback === 'function' ? callback(key) : vars[key];
68
68
  if (!isDefined(value)) defined--;
69
69
  if (isDefined(value) && value !== '') {
70
70
  if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
@@ -114,10 +114,21 @@ function parseTemplate(template, validate) {
114
114
  }),
115
115
  };
116
116
  }
117
+ // recursive compile
118
+ function recursiveCompile(vars, key, callback) {
119
+ let prev;
120
+ let result = vars[key];
121
+ do {
122
+ prev = result;
123
+ result = decodeURIComponent(parseTemplate(result).expand(vars, callback));
124
+ } while (result !== prev);
125
+ return result;
126
+ }
117
127
  // export
118
128
  module.exports = {
119
129
  parseTemplate: (template) => parseTemplate(template, true),
120
130
  isUrlTemplate: (template) => isUrlTemplate(template),
121
131
  inspect: (template) => isUrlTemplate(template, true),
122
132
  compile: (template) => parseTemplate(template),
133
+ recursiveCompile,
123
134
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "url-templates",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "A url-template validator, expander and inspector as defined by RFC 6570",
5
5
  "keywords": [
6
6
  "url",
package/readme.md CHANGED
@@ -48,7 +48,7 @@ try {
48
48
  ```
49
49
 
50
50
  **Note:**
51
- Same as with `isUrlTemplate`, but if valid returns the parsed `AST` instead of `true`.
51
+ - Same as with `isUrlTemplate`, but if valid returns the parsed `AST` instead of `true`.
52
52
 
53
53
  ### Expansion with validation
54
54
 
@@ -62,7 +62,7 @@ try {
62
62
  ```
63
63
 
64
64
  **Note:**
65
- If valid returns the `expand(vars)` function which returns the expanded `url-template`. Otherwise, it throws an `error`. The `expand` function also throws `error` if `limit` is defined on `objects` (`isUrlTemplate` function cannot know that without runtime vars).
65
+ - If valid returns the `expand(vars)` function which returns the expanded `url-template`. Otherwise, it throws an `error`. The `expand` function also throws `error` if `limit` is defined on `objects` (`isUrlTemplate` function cannot know that without runtime vars).
66
66
 
67
67
  ### Expansion without validation
68
68
 
@@ -74,7 +74,7 @@ console.log(compile('/undefined{id}').expand({ id: undefined })); // returns '/u
74
74
  ```
75
75
 
76
76
  **Note:**
77
- Returns a usable expander without validation for cases where validation is done elsewhere, or for the cases where some sort of postprocessing will follow. A good example of postprocessing is described next:
77
+ - Returns a usable expander without validation for cases where validation is done elsewhere, or for the cases where some sort of postprocessing will follow. A good example of postprocessing is described next:
78
78
 
79
79
  ### Multi pass expansion without validation
80
80
 
@@ -101,4 +101,46 @@ console.log(compile(firstPass).expand(vars2)); // returns '[1,2,3]';
101
101
  ```
102
102
 
103
103
  **Important Note:**
104
- The first pass will preserve the `{bar,baz}` expression only if the supplied variable has **none** of its members. This method can also be used to preserve quantifiers like `{1,4}` in regular expresions.
104
+ - The first pass will preserve the `{bar,baz}` expression only if the supplied variable has **none** of its members. This method can also be used to preserve quantifiers like `{1,4}` in regular expressions.
105
+
106
+ **Example 3 (transform with callback)**
107
+
108
+ ```js title="js"
109
+ const { compile } = require('url-templates');
110
+ const vars1 = { foo: 1 };
111
+ const vars2 = { bar: 2, baz: 3 };
112
+ const firstPass = decodeURIComponent(compile('[{foo},{bar,baz}]').expand(vars1));
113
+ console.log(firstPass); // returns '[1,{bar,baz}]';
114
+ console.log(compile(firstPass).expand(vars2, (key) => key === 'baz' ? vars2[key] * 10 : vars2[key])); // returns '[1,2,30]';
115
+ ```
116
+
117
+ **Note:**
118
+ - The optional `callback` function argument is present on each `expand` function.
119
+
120
+ ### Recursively compile and expand without validation
121
+
122
+ If all the required template members are present in a single `object`, then the above multi-pass compilation and expansion can be done recursively as follows:
123
+
124
+ **Example 1**
125
+
126
+ ```js title="js"
127
+ const { recursiveCompile } = require('url-templates');
128
+ const vars = { start: '[{foo},{bar,baz}]', foo: 1, bar: 2, baz: 3 };
129
+ console.log(recursiveCompile(vars, 'start')); // returns '[1,2,3]';
130
+ ```
131
+
132
+ **Example 2**
133
+
134
+ ```js title="js"
135
+ const { recursiveCompile } = require('url-templates');
136
+ const vars = { start: '[{foo},{boo}]', boo: '{bar,baz}', foo: 1, bar: 2, baz: 3 };
137
+ console.log(recursiveCompile(vars, 'start')); // returns '[1,2,3]';
138
+ ```
139
+
140
+ **Example 3 (transform with callback)**
141
+
142
+ ```js title="js"
143
+ const { recursiveCompile } = require('url-templates');
144
+ const vars = { start: '[{foo},{bar,baz}]', foo: 1, bar: 2, baz: 3 };
145
+ console.log(recursiveCompile(vars, 'start', (key) => vars[key] * 2)); // returns '[2,4,6]';
146
+ ```