jtlt 0.1.0

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.
Files changed (43) hide show
  1. package/.editorconfig +16 -0
  2. package/CHANGES.md +5 -0
  3. package/LICENSE-MIT.txt +21 -0
  4. package/README.md +534 -0
  5. package/dist/AbstractJoiningTransformer.d.ts +42 -0
  6. package/dist/AbstractJoiningTransformer.d.ts.map +1 -0
  7. package/dist/DOMJoiningTransformer.d.ts +113 -0
  8. package/dist/DOMJoiningTransformer.d.ts.map +1 -0
  9. package/dist/JSONJoiningTransformer.d.ts +160 -0
  10. package/dist/JSONJoiningTransformer.d.ts.map +1 -0
  11. package/dist/JSONPathTransformer.d.ts +95 -0
  12. package/dist/JSONPathTransformer.d.ts.map +1 -0
  13. package/dist/JSONPathTransformerContext.d.ts +263 -0
  14. package/dist/JSONPathTransformerContext.d.ts.map +1 -0
  15. package/dist/StringJoiningTransformer.d.ts +168 -0
  16. package/dist/StringJoiningTransformer.d.ts.map +1 -0
  17. package/dist/XPathTransformer.d.ts +51 -0
  18. package/dist/XPathTransformer.d.ts.map +1 -0
  19. package/dist/XPathTransformerContext.d.ts +260 -0
  20. package/dist/XPathTransformerContext.d.ts.map +1 -0
  21. package/dist/XSLTStyleJSONPathResolver.d.ts +16 -0
  22. package/dist/XSLTStyleJSONPathResolver.d.ts.map +1 -0
  23. package/dist/index.d.ts +168 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/docs/API.expanded.md +263 -0
  26. package/docs/API.md +69 -0
  27. package/eslint.config.js +30 -0
  28. package/package.json +53 -0
  29. package/pnpm-workspace.yaml +3 -0
  30. package/src/AbstractJoiningTransformer.js +73 -0
  31. package/src/DOMJoiningTransformer.js +237 -0
  32. package/src/JSONJoiningTransformer.js +472 -0
  33. package/src/JSONPathTransformer.js +159 -0
  34. package/src/JSONPathTransformerContext.js +807 -0
  35. package/src/StringJoiningTransformer.js +589 -0
  36. package/src/XPathTransformer.js +94 -0
  37. package/src/XPathTransformerContext.js +496 -0
  38. package/src/XSLTStyleJSONPathResolver.js +39 -0
  39. package/src/index.js +299 -0
  40. package/src/types/xpath2-js.d.ts +2 -0
  41. package/tsconfig-prod.json +19 -0
  42. package/tsconfig.json +14 -0
  43. package/typings/xpath2-js.d.ts +2 -0
@@ -0,0 +1,159 @@
1
+ import JSONPathTransformerContext from './JSONPathTransformerContext.js';
2
+
3
+ /**
4
+ * Applies named JSONPath-driven templates to JSON data.
5
+ *
6
+ * This engine finds templates whose `path` match the current node (plus an
7
+ * optional `mode`), sorts by priority, and invokes the winning template.
8
+ * If no template matches, built-in default rules emulate XSLT-like behavior
9
+ * for objects, arrays, scalars, etc.
10
+ */
11
+ class JSONPathTransformer {
12
+ /**
13
+ * @param {object} config - Configuration object
14
+ * @param {boolean} [config.errorOnEqualPriority] - Whether to error on
15
+ * equal priority templates
16
+ * @param {any[]} config.templates - Array of template objects
17
+ */
18
+ constructor (config) {
19
+ let map = /** @type {Record<string, boolean>} */ ({});
20
+ this._config = config;
21
+ /** @type {any[]} */
22
+ this.rootTemplates = [];
23
+ this.templates = config.templates;
24
+ this.templates = this.templates.map(function (template) {
25
+ if (Array.isArray(template)) {
26
+ // Todo: We could allow a third argument (at beginning or
27
+ // end?) to represent template name
28
+ return {path: template[0], template: template[1]};
29
+ }
30
+ return template;
31
+ });
32
+ this.templates.forEach((template, i, templates) => {
33
+ if (template.name && map[template.name]) {
34
+ throw new Error('Templates must all have different names.');
35
+ }
36
+ map[template.name] = true;
37
+ if (template.path === '$') {
38
+ // eslint-disable-next-line unicorn/prefer-spread -- Refactor
39
+ this.rootTemplates = this.rootTemplates.concat(templates.splice(i, 1));
40
+ }
41
+ });
42
+ map = /** @type {any} */ (null);
43
+ }
44
+
45
+ /**
46
+ * @returns {void}
47
+ */
48
+ _triggerEqualPriorityError () {
49
+ if (this._config.errorOnEqualPriority) {
50
+ throw new Error(
51
+ 'You have configured JSONPathTransformer to throw errors on finding ' +
52
+ 'templates of equal priority and these have been found.'
53
+ );
54
+ }
55
+ }
56
+
57
+ /**
58
+ * @param {string} mode - Transformation mode
59
+ * @returns {*} The transformation result
60
+ */
61
+ transform (mode) {
62
+ const jte = new JSONPathTransformerContext(
63
+ /** @type {any} */ (this._config), this.templates
64
+ );
65
+ const len = this.rootTemplates.length;
66
+ const templateObj = len
67
+ ? this.rootTemplates.pop()
68
+ : JSONPathTransformer.DefaultTemplateRules.transformRoot;
69
+ if (len > 1) {
70
+ this._triggerEqualPriorityError();
71
+ }
72
+ const ret = templateObj.template.call(jte, undefined, {mode});
73
+ if (typeof ret !== 'undefined') {
74
+ // Will vary by jte._config.outputType
75
+ /** @type {any} */ (jte)._getJoiningTransformer().append(ret);
76
+ }
77
+ const result = jte.getOutput();
78
+ return result;
79
+ }
80
+
81
+ /**
82
+ * @param {string} select - JSONPath selector
83
+ * @returns {string} Absolute JSONPath
84
+ */
85
+ static makeJSONPathAbsolute (select) {
86
+ // See todo in JSONPath to avoid need for '$' (but may still need
87
+ // to add ".")
88
+ return select[0] !== '$'
89
+ ? ((select[0] === '[' ? '$' : '$.') + select)
90
+ : select;
91
+ }
92
+
93
+ // To-do: Express as JSONPath expressions?
94
+ static DefaultTemplateRules = {
95
+ transformRoot: {
96
+ /**
97
+ * @param {*} value - Value
98
+ * @param {{mode: string}} cfg - Configuration
99
+ * @returns {void}
100
+ */
101
+ template (value, cfg) {
102
+ /** @type {any} */ (this).applyTemplates(null, cfg.mode);
103
+ }
104
+ },
105
+ transformPropertyNames: {
106
+ /**
107
+ * @param {*} value - Current context value
108
+ * @returns {*}
109
+ */
110
+ template (value) {
111
+ // Emit property names for the current object context
112
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
113
+ return Object.keys(value).join('');
114
+ }
115
+ return '';
116
+ }
117
+ },
118
+ transformObjects: {
119
+ /**
120
+ * @param {*} value - Value
121
+ * @param {{mode: string}} cfg - Configuration
122
+ * @returns {void}
123
+ */
124
+ template (value, cfg) {
125
+ /** @type {any} */ (this).applyTemplates(null, cfg.mode);
126
+ }
127
+ },
128
+ transformArrays: {
129
+ /**
130
+ * @param {*} value - Value
131
+ * @param {{mode: string}} cfg - Configuration
132
+ * @returns {void}
133
+ */
134
+ template (value, cfg) {
135
+ /** @type {any} */ (this).applyTemplates(null, cfg.mode);
136
+ }
137
+ },
138
+ transformScalars: {
139
+ /**
140
+ * @returns {*}
141
+ */
142
+ template () {
143
+ return /** @type {any} */ (this).valueOf({select: '.'});
144
+ }
145
+ },
146
+ transformFunctions: {
147
+ /**
148
+ * @param {Function} value - Function at current context
149
+ * @returns {*}
150
+ */
151
+ template (value) {
152
+ // Call the function and return its result
153
+ return value();
154
+ }
155
+ }
156
+ };
157
+ }
158
+
159
+ export default JSONPathTransformer;