openapi-explorer 2.1.656 → 2.1.659

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 (80) hide show
  1. package/dist/browser/openapi-explorer.min.js +2 -2
  2. package/dist/es/components/api-request.js +58 -140
  3. package/dist/es/components/api-response.js +9 -34
  4. package/dist/es/components/json-tree.js +4 -18
  5. package/dist/es/components/request-form-table.js +13 -36
  6. package/dist/es/components/schema-table.js +28 -42
  7. package/dist/es/components/schema-tree.js +31 -61
  8. package/dist/es/components/syntax-highlighter.js +7 -26
  9. package/dist/es/components/tag-input.js +2 -14
  10. package/dist/es/openapi-explorer-oauth-handler.js +0 -2
  11. package/dist/es/openapi-explorer.js +62 -174
  12. package/dist/es/react.js +4 -4
  13. package/dist/es/styles/input-styles.js +1 -1
  14. package/dist/es/styles/schema-styles.js +1 -1
  15. package/dist/es/templates/advance-search-template.js +1 -5
  16. package/dist/es/templates/callback-template.js +2 -2
  17. package/dist/es/templates/code-samples-template.js +1 -3
  18. package/dist/es/templates/components-template.js +41 -4
  19. package/dist/es/templates/endpoint-template.js +6 -17
  20. package/dist/es/templates/expanded-endpoint-template.js +4 -7
  21. package/dist/es/templates/focused-endpoint-template.js +0 -10
  22. package/dist/es/templates/mainBodyTemplate.js +3 -2
  23. package/dist/es/templates/navbar-template.js +9 -12
  24. package/dist/es/templates/overview-template.js +1 -1
  25. package/dist/es/templates/security-scheme-template.js +12 -73
  26. package/dist/es/templates/server-template.js +1 -8
  27. package/dist/es/utils/color-utils.js +2 -21
  28. package/dist/es/utils/common-utils.js +3 -20
  29. package/dist/es/utils/schema-utils.js +35 -132
  30. package/dist/es/utils/spec-parser.js +35 -120
  31. package/dist/es/utils/theme.js +3 -6
  32. package/dist/es/utils/xml/xml.js +1 -40
  33. package/dist/lib/components/api-request.js +58 -157
  34. package/dist/lib/components/api-response.js +9 -54
  35. package/dist/lib/components/json-tree.js +4 -27
  36. package/dist/lib/components/request-form-table.js +14 -42
  37. package/dist/lib/components/schema-table.js +28 -52
  38. package/dist/lib/components/schema-tree.js +31 -72
  39. package/dist/lib/components/syntax-highlighter.js +6 -49
  40. package/dist/lib/components/tag-input.js +2 -18
  41. package/dist/lib/languages/en.js +2 -3
  42. package/dist/lib/languages/fr.js +2 -3
  43. package/dist/lib/languages/index.js +0 -6
  44. package/dist/lib/openapi-explorer-oauth-handler.js +0 -6
  45. package/dist/lib/openapi-explorer.js +61 -197
  46. package/dist/lib/react.js +4 -5
  47. package/dist/lib/styles/advanced-search-styles.js +1 -5
  48. package/dist/lib/styles/api-request-styles.js +1 -5
  49. package/dist/lib/styles/border-styles.js +1 -5
  50. package/dist/lib/styles/endpoint-styles.js +1 -5
  51. package/dist/lib/styles/flex-styles.js +1 -5
  52. package/dist/lib/styles/font-styles.js +1 -5
  53. package/dist/lib/styles/info-styles.js +1 -5
  54. package/dist/lib/styles/input-styles.js +1 -5
  55. package/dist/lib/styles/key-frame-styles.js +1 -5
  56. package/dist/lib/styles/nav-styles.js +1 -5
  57. package/dist/lib/styles/prism-styles.js +1 -5
  58. package/dist/lib/styles/schema-styles.js +1 -5
  59. package/dist/lib/styles/tab-styles.js +1 -5
  60. package/dist/lib/styles/table-styles.js +1 -5
  61. package/dist/lib/styles/tag-input-styles.js +1 -5
  62. package/dist/lib/templates/advance-search-template.js +0 -6
  63. package/dist/lib/templates/callback-template.js +1 -3
  64. package/dist/lib/templates/code-samples-template.js +0 -4
  65. package/dist/lib/templates/components-template.js +43 -9
  66. package/dist/lib/templates/endpoint-template.js +6 -29
  67. package/dist/lib/templates/expanded-endpoint-template.js +3 -17
  68. package/dist/lib/templates/focused-endpoint-template.js +0 -19
  69. package/dist/lib/templates/mainBodyTemplate.js +2 -13
  70. package/dist/lib/templates/navbar-template.js +9 -20
  71. package/dist/lib/templates/overview-template.js +0 -5
  72. package/dist/lib/templates/security-scheme-template.js +12 -79
  73. package/dist/lib/templates/server-template.js +1 -12
  74. package/dist/lib/utils/color-utils.js +4 -25
  75. package/dist/lib/utils/common-utils.js +3 -33
  76. package/dist/lib/utils/schema-utils.js +33 -141
  77. package/dist/lib/utils/spec-parser.js +35 -128
  78. package/dist/lib/utils/theme.js +3 -16
  79. package/dist/lib/utils/xml/xml.js +1 -42
  80. package/package.json +2 -2
@@ -1,14 +1,11 @@
1
1
  import OpenApiResolver from 'openapi-resolver/dist/openapi-resolver.browser.js';
2
2
  import { marked } from 'marked';
3
3
  import { invalidCharsRegEx } from './common-utils.js';
4
- import { getI18nText } from '../languages/index.js';
5
4
  import cloneDeep from 'lodash.clonedeep';
6
5
  export default async function ProcessSpec(specUrlOrObject, serverUrl = '') {
7
6
  var _jsonParsedSpec$info, _jsonParsedSpec$compo;
8
-
9
7
  const inputSpecIsAUrl = typeof specUrlOrObject === 'string' && specUrlOrObject.match(/^http/) || typeof specUrlOrObject === 'object' && typeof specUrlOrObject.href === 'string';
10
8
  let jsonParsedSpec;
11
-
12
9
  try {
13
10
  jsonParsedSpec = await OpenApiResolver(specUrlOrObject);
14
11
  } catch (error) {
@@ -16,20 +13,21 @@ export default async function ProcessSpec(specUrlOrObject, serverUrl = '') {
16
13
  console.error('Error parsing specification', error);
17
14
  throw Error('SpecificationNotFound');
18
15
  }
19
-
20
16
  if (!jsonParsedSpec) {
21
17
  throw Error('SpecificationNotFound');
22
- } // Tags with Paths and WebHooks
23
-
18
+ }
24
19
 
25
- const tags = groupByTags(jsonParsedSpec); // Components
20
+ // Tags with Paths and WebHooks
21
+ const tags = groupByTags(jsonParsedSpec);
26
22
 
27
- const components = getComponents(jsonParsedSpec); // Info Description Headers
23
+ // Components
24
+ const components = getComponents(jsonParsedSpec);
28
25
 
29
- const infoDescriptionHeaders = (_jsonParsedSpec$info = jsonParsedSpec.info) !== null && _jsonParsedSpec$info !== void 0 && _jsonParsedSpec$info.description ? getHeadersFromMarkdown(jsonParsedSpec.info.description) : []; // Security Scheme
26
+ // Info Description Headers
27
+ const infoDescriptionHeaders = (_jsonParsedSpec$info = jsonParsedSpec.info) !== null && _jsonParsedSpec$info !== void 0 && _jsonParsedSpec$info.description ? getHeadersFromMarkdown(jsonParsedSpec.info.description) : [];
30
28
 
29
+ // Security Scheme
31
30
  const securitySchemes = [];
32
-
33
31
  if ((_jsonParsedSpec$compo = jsonParsedSpec.components) !== null && _jsonParsedSpec$compo !== void 0 && _jsonParsedSpec$compo.securitySchemes) {
34
32
  Object.entries(jsonParsedSpec.components.securitySchemes).forEach(kv => {
35
33
  const securityObj = {
@@ -38,7 +36,6 @@ export default async function ProcessSpec(specUrlOrObject, serverUrl = '') {
38
36
  };
39
37
  securityObj.value = '';
40
38
  securityObj.finalKeyValue = '';
41
-
42
39
  if (kv[1].type === 'apiKey' || kv[1].type === 'http') {
43
40
  securityObj.name = kv[1].name || 'Authorization';
44
41
  securityObj.user = '';
@@ -48,26 +45,22 @@ export default async function ProcessSpec(specUrlOrObject, serverUrl = '') {
48
45
  securityObj.clientId = '';
49
46
  securityObj.clientSecret = '';
50
47
  }
51
-
52
48
  securitySchemes.push(securityObj);
53
49
  });
54
- } // Servers
55
-
50
+ }
56
51
 
52
+ // Servers
57
53
  let servers = [];
58
-
59
54
  if (Array.isArray(jsonParsedSpec.servers) && jsonParsedSpec.servers.length) {
60
55
  jsonParsedSpec.servers.filter(s => s).forEach(v => {
61
56
  let computedUrl = v.url.trim();
62
-
63
57
  if (!(computedUrl.startsWith('http') || computedUrl.startsWith('//') || computedUrl.startsWith('{'))) {
64
58
  if (window.location.origin.startsWith('http')) {
65
59
  v.url = window.location.origin + v.url;
66
60
  computedUrl = v.url;
67
61
  }
68
- } // Apply server-variables to generate final computed-url
69
-
70
-
62
+ }
63
+ // Apply server-variables to generate final computed-url
71
64
  if (v.variables) {
72
65
  Object.entries(v.variables).forEach(kv => {
73
66
  const regex = new RegExp(`{${kv[0]}}`, 'g');
@@ -75,7 +68,6 @@ export default async function ProcessSpec(specUrlOrObject, serverUrl = '') {
75
68
  kv[1].value = kv[1].default || '';
76
69
  });
77
70
  }
78
-
79
71
  v.computedUrl = computedUrl;
80
72
  });
81
73
  const explicitServers = serverUrl && !jsonParsedSpec.servers.some(s => s.url === serverUrl || s.computedUrl === serverUrl) ? [{
@@ -104,7 +96,6 @@ export default async function ProcessSpec(specUrlOrObject, serverUrl = '') {
104
96
  computedUrl: 'http://localhost'
105
97
  }];
106
98
  }
107
-
108
99
  const parsedSpec = {
109
100
  info: jsonParsedSpec.info,
110
101
  infoDescriptionHeaders,
@@ -117,96 +108,36 @@ export default async function ProcessSpec(specUrlOrObject, serverUrl = '') {
117
108
  };
118
109
  return parsedSpec;
119
110
  }
120
-
121
111
  function getHeadersFromMarkdown(markdownContent) {
122
112
  const tokens = marked.lexer(markdownContent);
123
113
  const headers = tokens.filter(v => v.type === 'heading' && v.depth <= 2);
124
114
  return headers || [];
125
115
  }
126
-
127
116
  function getComponents(openApiSpec) {
128
117
  if (!openApiSpec.components) {
129
118
  return [];
130
119
  }
131
-
132
120
  const components = [];
133
-
134
- for (const component in openApiSpec.components) {
135
- const subComponents = Object.keys(openApiSpec.components[component]).map(sComponent => ({
121
+ for (const componentKeyId in openApiSpec.components) {
122
+ const subComponents = Object.keys(openApiSpec.components[componentKeyId]).map(sComponent => ({
136
123
  expanded: true,
137
- id: `${component.toLowerCase()}-${sComponent.toLowerCase()}`.replace(invalidCharsRegEx, '-'),
124
+ id: `${componentKeyId.toLowerCase()}-${sComponent.toLowerCase()}`.replace(invalidCharsRegEx, '-'),
138
125
  name: sComponent,
139
- component: openApiSpec.components[component][sComponent]
126
+ component: openApiSpec.components[componentKeyId][sComponent]
140
127
  })).sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()));
141
- let cmpDescription;
142
- let cmpName;
143
-
144
- switch (component) {
145
- case 'schemas':
146
- cmpName = getI18nText('menu.schemas');
147
- cmpDescription = '';
148
- break;
149
-
150
- case 'responses':
151
- cmpName = 'Responses';
152
- cmpDescription = 'Describes responses from an API Operation, including design-time, static links to operations based on the response.';
153
- break;
154
-
155
- case 'parameters':
156
- cmpName = 'Parameters';
157
- cmpDescription = 'Describes operation parameters. A unique parameter is defined by a combination of a name and location.';
158
- break;
159
-
160
- case 'examples':
161
- cmpName = 'Examples';
162
- cmpDescription = 'List of Examples for operations, can be requests, responses and objects examples.';
163
- break;
164
-
165
- case 'requestBodies':
166
- break;
167
-
168
- case 'headers':
169
- cmpName = 'Headers';
170
- cmpDescription = 'Headers follows the structure of the Parameters but they are explicitly in "header"';
171
- break;
172
-
173
- case 'securitySchemes':
174
- case 'securitySchemas':
175
- break;
176
-
177
- case 'links':
178
- cmpName = 'Links';
179
- cmpDescription = 'Links represent a possible design-time link for a response. The presence of a link does not guarantee the caller\'s ability to successfully invoke it, rather it provides a known relationship and traversal mechanism between responses and other operations.';
180
- break;
181
-
182
- case 'callbacks':
183
- cmpName = 'Callbacks'; // eslint-disable-next-line max-len
184
-
185
- cmpDescription = 'A map of possible out-of band callbacks related to the parent operation. Each value in the map is a Path Item Object that describes a set of requests that may be initiated by the API provider and the expected responses. The key value used to identify the path item object is an expression, evaluated at runtime, that identifies a URL to use for the callback operation.';
186
- break;
187
-
188
- default:
189
- cmpName = component;
190
- cmpDescription = component;
191
- break;
192
- }
193
-
194
- if (cmpName) {
195
- components.push({
196
- expanded: true,
197
- name: cmpName,
198
- description: cmpDescription,
199
- subComponents
200
- });
128
+ if (componentKeyId === 'requestBodies' || componentKeyId === 'securitySchemes' || componentKeyId === 'securitySchemas') {
129
+ continue;
201
130
  }
131
+ components.push({
132
+ expanded: true,
133
+ componentKeyId,
134
+ subComponents
135
+ });
202
136
  }
203
-
204
137
  return components;
205
138
  }
206
-
207
139
  function groupByTags(openApiSpec) {
208
140
  const supportedMethods = ['get', 'query', 'put', 'post', 'patch', 'delete', 'head', 'options']; // this is also used for ordering endpoints by methods
209
-
210
141
  const tags = openApiSpec.tags && Array.isArray(openApiSpec.tags) ? openApiSpec.tags.map(t => {
211
142
  const name = typeof t === 'string' ? t : t.name;
212
143
  return {
@@ -219,42 +150,32 @@ function groupByTags(openApiSpec) {
219
150
  };
220
151
  }) : [];
221
152
  const pathsAndWebhooks = openApiSpec.paths || {};
222
-
223
153
  if (openApiSpec.webhooks) {
224
154
  for (const [key, value] of Object.entries(openApiSpec.webhooks)) {
225
155
  value._type = 'webhook'; // eslint-disable-line no-underscore-dangle
226
-
227
156
  pathsAndWebhooks[key] = value;
228
157
  }
229
- } // For each path find the tag and push it into the corresponding tag
230
-
231
-
158
+ }
159
+ // For each path find the tag and push it into the corresponding tag
232
160
  for (const pathOrHookName in pathsAndWebhooks) {
233
161
  const commonPathPropServers = pathsAndWebhooks[pathOrHookName].servers || [];
234
162
  const isWebhook = pathsAndWebhooks[pathOrHookName]._type === 'webhook'; // eslint-disable-line no-underscore-dangle
235
-
236
163
  supportedMethods.forEach(methodName => {
237
164
  const commonParams = cloneDeep(pathsAndWebhooks[pathOrHookName].parameters);
238
-
239
165
  if (pathsAndWebhooks[pathOrHookName][methodName]) {
240
- const pathOrHookObj = openApiSpec.paths[pathOrHookName][methodName]; // If path.methods are tagged, else generate it from path
241
-
166
+ const pathOrHookObj = openApiSpec.paths[pathOrHookName][methodName];
167
+ // If path.methods are tagged, else generate it from path
242
168
  const pathTags = Array.isArray(pathOrHookObj.tags) ? pathOrHookObj.tags : pathOrHookObj.tags && [pathOrHookObj.tags] || [];
243
-
244
169
  if (pathTags.length === 0) {
245
170
  pathTags.push('General ⦂');
246
171
  }
247
-
248
172
  pathTags.forEach(tag => {
249
173
  let tagObj;
250
174
  let specTagsItem;
251
-
252
175
  if (openApiSpec.tags) {
253
176
  specTagsItem = tags.find(v => v.name.toLowerCase() === tag.toLowerCase());
254
177
  }
255
-
256
178
  tagObj = tags.find(v => v.name === tag);
257
-
258
179
  if (!tagObj) {
259
180
  tagObj = {
260
181
  elementId: `tag--${tag.replace(invalidCharsRegEx, '-')}`,
@@ -265,25 +186,21 @@ function groupByTags(openApiSpec) {
265
186
  expanded: true
266
187
  };
267
188
  tags.push(tagObj);
268
- } // Generate a short summary which is broken
269
-
189
+ }
270
190
 
191
+ // Generate a short summary which is broken
271
192
  let shortSummary = (pathOrHookObj.summary || pathOrHookObj.description || `${methodName.toUpperCase()} ${pathOrHookName}`).trim();
272
-
273
193
  if (shortSummary.length > 100) {
274
194
  shortSummary = shortSummary.split(/[.|!|?]\s|[\r?\n]/)[0]; // take the first line (period or carriage return)
275
- } // Merge Common Parameters with This methods parameters
276
-
277
-
195
+ }
196
+ // Merge Common Parameters with This methods parameters
278
197
  let finalParameters = [];
279
-
280
198
  if (commonParams) {
281
199
  if (pathOrHookObj.parameters) {
282
200
  finalParameters = commonParams.filter(commonParam => {
283
201
  if (!pathOrHookObj.parameters.some(param => commonParam.name === param.name && commonParam.in === param.in)) {
284
202
  return commonParam;
285
203
  }
286
-
287
204
  return undefined;
288
205
  }).concat(pathOrHookObj.parameters);
289
206
  } else {
@@ -291,22 +208,21 @@ function groupByTags(openApiSpec) {
291
208
  }
292
209
  } else {
293
210
  finalParameters = pathOrHookObj.parameters ? pathOrHookObj.parameters.slice(0) : [];
294
- } // Remove bad callbacks
295
-
211
+ }
296
212
 
213
+ // Remove bad callbacks
297
214
  if (pathOrHookObj.callbacks) {
298
215
  for (const [callbackName, callbackConfig] of Object.entries(pathOrHookObj.callbacks)) {
299
216
  const originalCallbackEntries = Object.entries(callbackConfig);
300
217
  const filteredCallbacks = originalCallbackEntries.filter(entry => typeof entry[1] === 'object') || [];
301
218
  pathOrHookObj.callbacks[callbackName] = Object.fromEntries(filteredCallbacks);
302
-
303
219
  if (filteredCallbacks.length !== originalCallbackEntries.length) {
304
220
  console.warn(`OpenAPI Explorer: Invalid Callback found in ${callbackName}`); // eslint-disable-line no-console
305
221
  }
306
222
  }
307
- } // Update Responses
308
-
223
+ }
309
224
 
225
+ // Update Responses
310
226
  const pathObject = {
311
227
  expanded: false,
312
228
  isWebhook,
@@ -338,6 +254,5 @@ function groupByTags(openApiSpec) {
338
254
  }
339
255
  }); // End of Methods
340
256
  }
341
-
342
257
  return tags;
343
258
  }
@@ -1,9 +1,10 @@
1
1
  import { html } from 'lit';
2
2
  import color from 'color';
3
3
  import ColorUtils from './color-utils.js';
4
+
4
5
  /* Generates an schema object containing type and constraint info */
5
- // TODO: possible drive theme from:
6
6
 
7
+ // TODO: possible drive theme from:
7
8
  /*
8
9
  if (!this.theme || !'light, dark,'.includes(`${this.theme},`)) {
9
10
  this.theme = (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) ? 'light' : 'dark';
@@ -14,16 +15,11 @@ export default function setTheme(theme = {}) {
14
15
  const bg1 = theme.bg1 ? theme.bg1 : '#ffffff';
15
16
  const fg1 = theme.fg1 ? theme.fg1 : '#444444';
16
17
  const bg2 = theme.bg2 ? theme.bg2 : ColorUtils.color.brightness(bg1, -5); // or '#fafafa'
17
-
18
18
  const bg3 = theme.bg3 ? theme.bg3 : ColorUtils.color.brightness(bg1, -15); // or '#f6f6f6'
19
-
20
19
  const lightBg = theme.bg3 ? theme.bg3 : ColorUtils.color.brightness(bg1, -45);
21
20
  const fg2 = theme.fg2 ? theme.fg2 : ColorUtils.color.brightness(fg1, 17); // or '#555'
22
-
23
21
  const fg3 = theme.fg3 ? theme.fg3 : ColorUtils.color.brightness(fg1, 30); // or #666
24
-
25
22
  const lightFg = theme.fg3 ? theme.fg3 : ColorUtils.color.brightness(fg1, 70); // or #999
26
-
27
23
  const inlineCodeFg = theme.inlineCodeFg ? theme.inlineCodeFg : 'brown';
28
24
  const selectionBg = '#444';
29
25
  const selectionFg = '#eee';
@@ -66,6 +62,7 @@ export default function setTheme(theme = {}) {
66
62
  // #dedede
67
63
  hoverColor: theme.hoverColor || ColorUtils.color.brightness(bg1, -5),
68
64
  // # f1f1f1
65
+
69
66
  codeFg: theme.codeFg || '#666',
70
67
  codePropertyColor: theme.codePropertyColor || '#905',
71
68
  codeKeywordColor: theme.codeKeywordColor || '#07a',
@@ -1,4 +1,5 @@
1
1
  /* eslint-disable no-underscore-dangle */
2
+
2
3
  const XML_CHARACTER_MAP = {
3
4
  '&': '&amp;',
4
5
  '"': '&quot;',
@@ -6,47 +7,38 @@ const XML_CHARACTER_MAP = {
6
7
  '<': '&lt;',
7
8
  '>': '&gt;'
8
9
  };
9
-
10
10
  function escapeForXML(string) {
11
11
  return string && string.replace ? string.replace(/([&"<>'])/g, function (str, item) {
12
12
  return XML_CHARACTER_MAP[item];
13
13
  }) : string;
14
14
  }
15
-
16
15
  const DEFAULT_INDENT = ' ';
17
16
  export default function xml(input, rawOptions) {
18
17
  let options = rawOptions;
19
-
20
18
  if (typeof options !== 'object') {
21
19
  options = {
22
20
  indent: options
23
21
  };
24
22
  }
25
-
26
23
  let output = '';
27
24
  const indent = !options.indent ? '' : options.indent === true ? DEFAULT_INDENT : options.indent;
28
-
29
25
  function append(_, out) {
30
26
  if (out !== undefined) {
31
27
  output += out;
32
28
  }
33
29
  }
34
-
35
30
  function add(value, last) {
36
31
  format(append, resolve(value, indent, indent ? 1 : 0), last);
37
32
  }
38
-
39
33
  function addXmlDeclaration(declaration) {
40
34
  const encoding = declaration.encoding || 'UTF-8';
41
35
  const attr = {
42
36
  version: '1.0',
43
37
  encoding: encoding
44
38
  };
45
-
46
39
  if (declaration.standalone) {
47
40
  attr.standalone = declaration.standalone;
48
41
  }
49
-
50
42
  add({
51
43
  '?xml': {
52
44
  _attr: attr
@@ -54,11 +46,9 @@ export default function xml(input, rawOptions) {
54
46
  });
55
47
  output = output.replace('/>', '?>');
56
48
  }
57
-
58
49
  if (options.declaration) {
59
50
  addXmlDeclaration(options.declaration);
60
51
  }
61
-
62
52
  if (input && input.forEach) {
63
53
  input.forEach(function (value, i) {
64
54
  add(value, i + 1 === input.length);
@@ -66,26 +56,21 @@ export default function xml(input, rawOptions) {
66
56
  } else {
67
57
  add(input, true);
68
58
  }
69
-
70
59
  return output;
71
60
  }
72
-
73
61
  function create_indent(character, count) {
74
62
  return new Array(count || 0).join(character || '');
75
63
  }
76
-
77
64
  function resolve(data, indent, indent_count_raw) {
78
65
  const indent_count = indent_count_raw || 0;
79
66
  const indent_spaces = create_indent(indent, indent_count);
80
67
  let name;
81
68
  let values = data;
82
69
  const interrupt = false;
83
-
84
70
  if (typeof data === 'object') {
85
71
  const keys = Object.keys(data);
86
72
  name = keys[0];
87
73
  values = data[name];
88
-
89
74
  if (values && values._elem) {
90
75
  values._elem.name = name;
91
76
  values._elem.icount = indent_count;
@@ -95,39 +80,32 @@ function resolve(data, indent, indent_count_raw) {
95
80
  return values._elem;
96
81
  }
97
82
  }
98
-
99
83
  const attributes = [];
100
84
  const content = [];
101
85
  let isStringContent;
102
-
103
86
  function get_attributes(obj) {
104
87
  const keys = Object.keys(obj);
105
88
  keys.forEach(function (key) {
106
89
  attributes.push(attribute(key, obj[key]));
107
90
  });
108
91
  }
109
-
110
92
  switch (typeof values) {
111
93
  case 'object':
112
94
  if (values === null) {
113
95
  break;
114
96
  }
115
-
116
97
  if (values._attr) {
117
98
  get_attributes(values._attr);
118
99
  }
119
-
120
100
  if (values._cdata) {
121
101
  content.push(`${`<![CDATA[${values._cdata}`.replace(/\]\]>/g, ']]]]><![CDATA[>')}]]>`);
122
102
  }
123
-
124
103
  if (values.forEach) {
125
104
  isStringContent = false;
126
105
  content.push('');
127
106
  values.forEach(function (value) {
128
107
  if (typeof value === 'object') {
129
108
  const _name = Object.keys(value)[0];
130
-
131
109
  if (_name === '_attr') {
132
110
  get_attributes(value._attr);
133
111
  } else {
@@ -140,19 +118,15 @@ function resolve(data, indent, indent_count_raw) {
140
118
  content.push(escapeForXML(value));
141
119
  }
142
120
  });
143
-
144
121
  if (!isStringContent) {
145
122
  content.push('');
146
123
  }
147
124
  }
148
-
149
125
  break;
150
-
151
126
  default:
152
127
  // string
153
128
  content.push(escapeForXML(values));
154
129
  }
155
-
156
130
  return {
157
131
  name: name,
158
132
  interrupt: interrupt,
@@ -163,33 +137,25 @@ function resolve(data, indent, indent_count_raw) {
163
137
  indent: indent
164
138
  };
165
139
  }
166
-
167
140
  function format(append, elem, end) {
168
141
  if (typeof elem !== 'object') {
169
142
  append(false, elem);
170
143
  return;
171
144
  }
172
-
173
145
  const len = elem.interrupt ? 1 : elem.content.length;
174
-
175
146
  function proceed() {
176
147
  while (elem.content.length) {
177
148
  const value = elem.content.shift();
178
-
179
149
  if (value === undefined) {
180
150
  continue;
181
151
  }
182
-
183
152
  if (interrupt(value)) {
184
153
  return;
185
154
  }
186
-
187
155
  format(append, value);
188
156
  }
189
-
190
157
  append(false, (len > 1 ? elem.indents : '') + (elem.name ? `</${elem.name}>` : '') + (elem.indent && !end ? '\n' : ''));
191
158
  }
192
-
193
159
  function interrupt(value) {
194
160
  if (value.interrupt) {
195
161
  value.interrupt.append = append;
@@ -198,22 +164,17 @@ function format(append, elem, end) {
198
164
  append(true);
199
165
  return true;
200
166
  }
201
-
202
167
  return false;
203
168
  }
204
-
205
169
  append(false, elem.indents + (elem.name ? `<${elem.name}` : '') + (elem.attributes.length ? ` ${elem.attributes.join(' ')}` : '') + (len ? elem.name ? '>' : '' : elem.name ? '/>' : '') + (elem.indent && len > 1 ? '\n' : ''));
206
-
207
170
  if (!len) {
208
171
  append(false, elem.indent ? '\n' : '');
209
172
  return;
210
173
  }
211
-
212
174
  if (!interrupt(elem)) {
213
175
  proceed();
214
176
  }
215
177
  }
216
-
217
178
  function attribute(key, value) {
218
179
  return `${key}=` + `"${escapeForXML(value)}"`;
219
180
  }