canada-api 5.1.3 → 5.1.5
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/README.md +62 -8
- package/dist/ca.js +1 -1
- package/package.json +44 -47
- package/src/children.js +49 -52
- package/src/config.js +1 -1
- package/src/content.js +21 -21
- package/src/index.js +24 -24
- package/src/meta.js +103 -103
- package/src/normalize.js +37 -38
- package/src/request.js +57 -40
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ Cross platform API for fetching public data from [canada.ca](https://www.canada.
|
|
|
9
9
|
## Browser
|
|
10
10
|
|
|
11
11
|
```html
|
|
12
|
-
<script src="https://cdn.jsdelivr.net/npm/canada-api@5.1.
|
|
12
|
+
<script src="https://cdn.jsdelivr.net/npm/canada-api@5.1.5"></script>
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## Node 18+
|
|
@@ -61,7 +61,11 @@ Fetches and parses the sitemap for the given page, returning its child pages. En
|
|
|
61
61
|
"lastmod": "2022-09-20T00:00:00.000Z"
|
|
62
62
|
}
|
|
63
63
|
],
|
|
64
|
-
"status": 200
|
|
64
|
+
"status": 200,
|
|
65
|
+
"statusText": "OK",
|
|
66
|
+
"headers": {
|
|
67
|
+
"content-type": "text/xml"
|
|
68
|
+
}
|
|
65
69
|
}
|
|
66
70
|
```
|
|
67
71
|
|
|
@@ -74,8 +78,12 @@ Retrieves the HTML content of the page.
|
|
|
74
78
|
|
|
75
79
|
```json
|
|
76
80
|
{
|
|
77
|
-
"data": "<!DOCTYPE html
|
|
78
|
-
"status": 200
|
|
81
|
+
"data": "<!DOCTYPE html>...",
|
|
82
|
+
"status": 200,
|
|
83
|
+
"statusText": "OK",
|
|
84
|
+
"headers": {
|
|
85
|
+
"content-type": "text/html"
|
|
86
|
+
}
|
|
79
87
|
}
|
|
80
88
|
```
|
|
81
89
|
|
|
@@ -100,7 +108,11 @@ Fetches JCR metadata for the given page. The following transformations are appli
|
|
|
100
108
|
"fluidWidth": false,
|
|
101
109
|
"peer": "/fr/ministere-defense-nationale/feuille-erable"
|
|
102
110
|
},
|
|
103
|
-
"status": 200
|
|
111
|
+
"status": 200,
|
|
112
|
+
"statusText": "OK",
|
|
113
|
+
"headers": {
|
|
114
|
+
"content-type": "application/json"
|
|
115
|
+
}
|
|
104
116
|
}
|
|
105
117
|
```
|
|
106
118
|
|
|
@@ -113,7 +125,7 @@ Fetches JCR metadata for the given page. The following transformations are appli
|
|
|
113
125
|
Raw HTTP client with `https://www.canada.ca` as the base URL. Use this for any requests not covered by the methods above. No URL transformation is applied. Response bodies with a `application/json` content type are automatically parsed.
|
|
114
126
|
|
|
115
127
|
```js
|
|
116
|
-
const response = await ca.request('/en/
|
|
128
|
+
const response = await ca.request('/en/department-national-defence.html');
|
|
117
129
|
```
|
|
118
130
|
|
|
119
131
|
All methods return the same response shape:
|
|
@@ -140,7 +152,7 @@ API multiplateforme pour récupérer des données publiques de [canada.ca](https
|
|
|
140
152
|
## Navigateur
|
|
141
153
|
|
|
142
154
|
```html
|
|
143
|
-
<script src="https://cdn.jsdelivr.net/npm/canada-api@5.1.
|
|
155
|
+
<script src="https://cdn.jsdelivr.net/npm/canada-api@5.1.4"></script>
|
|
144
156
|
```
|
|
145
157
|
|
|
146
158
|
## Node 18+
|
|
@@ -176,6 +188,22 @@ Lève {Error} si l'URL n'est pas sur canada.ca ou si le chemin ne commence pas p
|
|
|
176
188
|
|
|
177
189
|
Récupère et analyse le plan de site de la page donnée, retournant ses pages enfants. Les entrées sans élément `<loc>` sont ignorées.
|
|
178
190
|
|
|
191
|
+
```json
|
|
192
|
+
{
|
|
193
|
+
"data": [
|
|
194
|
+
{
|
|
195
|
+
"path": "/fr/ministere-defense-nationale/feuille-erable",
|
|
196
|
+
"lastmod": "2022-09-20T00:00:00.000Z"
|
|
197
|
+
}
|
|
198
|
+
],
|
|
199
|
+
"status": 200,
|
|
200
|
+
"statusText": "OK",
|
|
201
|
+
"headers": {
|
|
202
|
+
"content-type": "text/xml"
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
179
207
|
### `ca.content(url)`
|
|
180
208
|
|
|
181
209
|
- `url` {string|URL} - URL absolue ou relative
|
|
@@ -183,6 +211,17 @@ Récupère et analyse le plan de site de la page donnée, retournant ses pages e
|
|
|
183
211
|
|
|
184
212
|
Récupère le contenu HTML de la page.
|
|
185
213
|
|
|
214
|
+
```json
|
|
215
|
+
{
|
|
216
|
+
"data": "<!DOCTYPE html>...",
|
|
217
|
+
"status": 200,
|
|
218
|
+
"statusText": "OK",
|
|
219
|
+
"headers": {
|
|
220
|
+
"content-type": "text/html"
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
186
225
|
### `ca.meta(url)`
|
|
187
226
|
|
|
188
227
|
- `url` {string|URL} - URL absolue ou relative
|
|
@@ -197,6 +236,21 @@ Récupère les métadonnées JCR de la page donnée. Les transformations suivant
|
|
|
197
236
|
- Les clés sont triées alphabétiquement
|
|
198
237
|
- Un champ `peer` normalisé est ajouté lorsque `gcAltLanguagePeer` est présent
|
|
199
238
|
|
|
239
|
+
```json
|
|
240
|
+
{
|
|
241
|
+
"data": {
|
|
242
|
+
"cq:lastModified": "2022-10-25T19:16:28.000Z",
|
|
243
|
+
"fluidWidth": false,
|
|
244
|
+
"peer": "/en/department-national-defence/maple-leaf"
|
|
245
|
+
},
|
|
246
|
+
"status": 200,
|
|
247
|
+
"statusText": "OK",
|
|
248
|
+
"headers": {
|
|
249
|
+
"content-type": "application/json"
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
200
254
|
### `ca.request`
|
|
201
255
|
|
|
202
256
|
- `url` {string|URL} - URL absolue ou relative
|
|
@@ -206,7 +260,7 @@ Récupère les métadonnées JCR de la page donnée. Les transformations suivant
|
|
|
206
260
|
Client HTTP brut avec `https://www.canada.ca` comme URL de base. Utilisez-le pour toute requête non couverte par les méthodes ci-dessus. Aucune transformation d'URL n'est appliquée. Les corps de réponse avec un type de contenu `application/json` sont automatiquement analysés.
|
|
207
261
|
|
|
208
262
|
```js
|
|
209
|
-
const response = await ca.request('/fr/
|
|
263
|
+
const response = await ca.request('/fr/ministere-defense-nationale.html');
|
|
210
264
|
```
|
|
211
265
|
|
|
212
266
|
Toutes les méthodes retournent la même structure de réponse :
|
package/dist/ca.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define("ca",[],e):"object"==typeof exports?exports.ca=e():t.ca=e()}(Object("undefined"!=typeof self?self:this),()=>(()=>{"use strict";var t={d:(e,n)=>{for(var r in n)t.o(n,r)&&!t.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:n[r]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)},e={};t.d(e,{default:()=>$t});const n="https://www.canada.ca",r=t=>{if("string"==typeof t)t=new URL(t,n);else{if(!(t instanceof URL))throw new TypeError("string or URL object expected");t=new URL(t.href)}if(t.origin!==n)throw new Error("URL must start with "+n);if(t.pathname=t.pathname.replace(/^\/content\/canadasite/,""),t.pathname=t.pathname.replace(/\.[^/]*$/,"").replace(/\/+$/,""),!t.pathname.startsWith("/en/")&&!t.pathname.startsWith("/fr/"))throw new Error(`Invalid path: "${t.pathname}" must start with /en/ or /fr/`);return t},i=async(t,e={})=>{const r=await fetch(new URL(t,n),{signal:AbortSignal.timeout(3e4),headers:{"User-Agent":"canada-api/5.1.3",Accept:"*/*",...e.headers},...e});if(!r.ok){const e=new Error(`${r.status} ${r.statusText}`);throw e.status=r.status,e.url=t.toString(),e}const i=await r.text(),s=r.headers.get("content-type")?.includes("application/json");return{data:s?JSON.parse(i):i,status:r.status,statusText:r.statusText,headers:Object.fromEntries(r.headers)}},s=":A-Za-z_\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD",a=new RegExp("^["+s+"]["+s+"\\-.\\d\\u00B7\\u0300-\\u036F\\u203F-\\u2040]*$");function o(t,e){const n=[];let r=e.exec(t);for(;r;){const i=[];i.startIndex=e.lastIndex-r[0].length;const s=r.length;for(let t=0;t<s;t++)i.push(r[t]);n.push(i),r=e.exec(t)}return n}const l=function(t){return!(null==a.exec(t))},h=["hasOwnProperty","toString","valueOf","__defineGetter__","__defineSetter__","__lookupGetter__","__lookupSetter__"],c=["__proto__","constructor","prototype"],u=t=>h.includes(t)?"__"+t:t,d={preserveOrder:!1,attributeNamePrefix:"@_",attributesGroupName:!1,textNodeName:"#text",ignoreAttributes:!0,removeNSPrefix:!1,allowBooleanAttributes:!1,parseTagValue:!0,parseAttributeValue:!1,trimValues:!0,cdataPropName:!1,numberParseOptions:{hex:!0,leadingZeros:!0,eNotation:!0},tagValueProcessor:function(t,e){return e},attributeValueProcessor:function(t,e){return e},stopNodes:[],alwaysCreateTextNode:!1,isArray:()=>!1,commentPropName:!1,unpairedTags:[],processEntities:!0,htmlEntities:!1,entityDecoder:null,ignoreDeclaration:!1,ignorePiTags:!1,transformTagName:!1,transformAttributeName:!1,updateTag:function(t,e,n){return t},captureMetaData:!1,maxNestedTags:100,strictReservedNames:!0,jPath:!0,onDangerousProperty:u};function p(t,e){if("string"!=typeof t)return;const n=t.toLowerCase();if(h.some(t=>n===t.toLowerCase()))throw new Error(`[SECURITY] Invalid ${e}: "${t}" is a reserved JavaScript keyword that could cause prototype pollution`);if(c.some(t=>n===t.toLowerCase()))throw new Error(`[SECURITY] Invalid ${e}: "${t}" is a reserved JavaScript keyword that could cause prototype pollution`)}function f(t,e){return"boolean"==typeof t?{enabled:t,maxEntitySize:1e4,maxExpansionDepth:1e4,maxTotalExpansions:1/0,maxExpandedLength:1e5,maxEntityCount:1e3,allowedTags:null,tagFilter:null,appliesTo:"all"}:"object"==typeof t&&null!==t?{enabled:!1!==t.enabled,maxEntitySize:Math.max(1,t.maxEntitySize??1e4),maxExpansionDepth:Math.max(1,t.maxExpansionDepth??1e4),maxTotalExpansions:Math.max(1,t.maxTotalExpansions??1/0),maxExpandedLength:Math.max(1,t.maxExpandedLength??1e5),maxEntityCount:Math.max(1,t.maxEntityCount??1e3),allowedTags:t.allowedTags??null,tagFilter:t.tagFilter??null,appliesTo:t.appliesTo??"all"}:f(!0)}const g=function(t){const e=Object.assign({},d,t),n=[{value:e.attributeNamePrefix,name:"attributeNamePrefix"},{value:e.attributesGroupName,name:"attributesGroupName"},{value:e.textNodeName,name:"textNodeName"},{value:e.cdataPropName,name:"cdataPropName"},{value:e.commentPropName,name:"commentPropName"}];for(const{value:t,name:e}of n)t&&p(t,e);return null===e.onDangerousProperty&&(e.onDangerousProperty=u),e.processEntities=f(e.processEntities,e.htmlEntities),e.unpairedTagsSet=new Set(e.unpairedTags),e.stopNodes&&Array.isArray(e.stopNodes)&&(e.stopNodes=e.stopNodes.map(t=>"string"==typeof t&&t.startsWith("*.")?".."+t.substring(2):t)),e};let m;m="function"!=typeof Symbol?"@@xmlMetadata":Symbol("XML Node Metadata");class x{constructor(t){this.tagname=t,this.child=[],this[":@"]=Object.create(null)}add(t,e){"__proto__"===t&&(t="#__proto__"),this.child.push({[t]:e})}addChild(t,e){"__proto__"===t.tagname&&(t.tagname="#__proto__"),t[":@"]&&Object.keys(t[":@"]).length>0?this.child.push({[t.tagname]:t.child,":@":t[":@"]}):this.child.push({[t.tagname]:t.child}),void 0!==e&&(this.child[this.child.length-1][m]={startIndex:e})}static getMetaDataSymbol(){return m}}class E{constructor(t){this.suppressValidationErr=!t,this.options=t}readDocType(t,e){const n=Object.create(null);let r=0;if("O"!==t[e+3]||"C"!==t[e+4]||"T"!==t[e+5]||"Y"!==t[e+6]||"P"!==t[e+7]||"E"!==t[e+8])throw new Error("Invalid Tag instead of DOCTYPE");{e+=9;let i=1,s=!1,a=!1,o="";for(;e<t.length;e++)if("<"!==t[e]||a)if(">"===t[e]){if(a?"-"===t[e-1]&&"-"===t[e-2]&&(a=!1,i--):i--,0===i)break}else"["===t[e]?s=!0:o+=t[e];else{if(s&&y(t,"!ENTITY",e)){let i,s;if(e+=7,[i,s,e]=this.readEntityExp(t,e+1,this.suppressValidationErr),-1===s.indexOf("&")){if(!1!==this.options.enabled&&null!=this.options.maxEntityCount&&r>=this.options.maxEntityCount)throw new Error(`Entity count (${r+1}) exceeds maximum allowed (${this.options.maxEntityCount})`);n[i]=s,r++}}else if(s&&y(t,"!ELEMENT",e)){e+=8;const{index:n}=this.readElementExp(t,e+1);e=n}else if(s&&y(t,"!ATTLIST",e))e+=8;else if(s&&y(t,"!NOTATION",e)){e+=9;const{index:n}=this.readNotationExp(t,e+1,this.suppressValidationErr);e=n}else{if(!y(t,"!--",e))throw new Error("Invalid DOCTYPE");a=!0}i++,o=""}if(0!==i)throw new Error("Unclosed DOCTYPE")}return{entities:n,i:e}}readEntityExp(t,e){const n=e=w(t,e);for(;e<t.length&&!/\s/.test(t[e])&&'"'!==t[e]&&"'"!==t[e];)e++;let r=t.substring(n,e);if(b(r),e=w(t,e),!this.suppressValidationErr){if("SYSTEM"===t.substring(e,e+6).toUpperCase())throw new Error("External entities are not supported");if("%"===t[e])throw new Error("Parameter entities are not supported")}let i="";if([e,i]=this.readIdentifierVal(t,e,"entity"),!1!==this.options.enabled&&null!=this.options.maxEntitySize&&i.length>this.options.maxEntitySize)throw new Error(`Entity "${r}" size (${i.length}) exceeds maximum allowed size (${this.options.maxEntitySize})`);return[r,i,--e]}readNotationExp(t,e){const n=e=w(t,e);for(;e<t.length&&!/\s/.test(t[e]);)e++;let r=t.substring(n,e);!this.suppressValidationErr&&b(r),e=w(t,e);const i=t.substring(e,e+6).toUpperCase();if(!this.suppressValidationErr&&"SYSTEM"!==i&&"PUBLIC"!==i)throw new Error(`Expected SYSTEM or PUBLIC, found "${i}"`);e+=i.length,e=w(t,e);let s=null,a=null;if("PUBLIC"===i)[e,s]=this.readIdentifierVal(t,e,"publicIdentifier"),'"'!==t[e=w(t,e)]&&"'"!==t[e]||([e,a]=this.readIdentifierVal(t,e,"systemIdentifier"));else if("SYSTEM"===i&&([e,a]=this.readIdentifierVal(t,e,"systemIdentifier"),!this.suppressValidationErr&&!a))throw new Error("Missing mandatory system identifier for SYSTEM notation");return{notationName:r,publicIdentifier:s,systemIdentifier:a,index:--e}}readIdentifierVal(t,e,n){let r="";const i=t[e];if('"'!==i&&"'"!==i)throw new Error(`Expected quoted string, found "${i}"`);const s=++e;for(;e<t.length&&t[e]!==i;)e++;if(r=t.substring(s,e),t[e]!==i)throw new Error(`Unterminated ${n} value`);return[++e,r]}readElementExp(t,e){const n=e=w(t,e);for(;e<t.length&&!/\s/.test(t[e]);)e++;let r=t.substring(n,e);if(!this.suppressValidationErr&&!l(r))throw new Error(`Invalid element name: "${r}"`);let i="";if("E"===t[e=w(t,e)]&&y(t,"MPTY",e))e+=4;else if("A"===t[e]&&y(t,"NY",e))e+=2;else if("("===t[e]){const n=++e;for(;e<t.length&&")"!==t[e];)e++;if(i=t.substring(n,e),")"!==t[e])throw new Error("Unterminated content model")}else if(!this.suppressValidationErr)throw new Error(`Invalid Element Expression, found "${t[e]}"`);return{elementName:r,contentModel:i.trim(),index:e}}readAttlistExp(t,e){let n=e=w(t,e);for(;e<t.length&&!/\s/.test(t[e]);)e++;let r=t.substring(n,e);for(b(r),n=e=w(t,e);e<t.length&&!/\s/.test(t[e]);)e++;let i=t.substring(n,e);if(!b(i))throw new Error(`Invalid attribute name: "${i}"`);e=w(t,e);let s="";if("NOTATION"===t.substring(e,e+8).toUpperCase()){if(s="NOTATION","("!==t[e=w(t,e+=8)])throw new Error(`Expected '(', found "${t[e]}"`);e++;let n=[];for(;e<t.length&&")"!==t[e];){const r=e;for(;e<t.length&&"|"!==t[e]&&")"!==t[e];)e++;let i=t.substring(r,e);if(i=i.trim(),!b(i))throw new Error(`Invalid notation name: "${i}"`);n.push(i),"|"===t[e]&&(e++,e=w(t,e))}if(")"!==t[e])throw new Error("Unterminated list of notations");e++,s+=" ("+n.join("|")+")"}else{const n=e;for(;e<t.length&&!/\s/.test(t[e]);)e++;s+=t.substring(n,e);const r=["CDATA","ID","IDREF","IDREFS","ENTITY","ENTITIES","NMTOKEN","NMTOKENS"];if(!this.suppressValidationErr&&!r.includes(s.toUpperCase()))throw new Error(`Invalid attribute type: "${s}"`)}e=w(t,e);let a="";return"#REQUIRED"===t.substring(e,e+8).toUpperCase()?(a="#REQUIRED",e+=8):"#IMPLIED"===t.substring(e,e+7).toUpperCase()?(a="#IMPLIED",e+=7):[e,a]=this.readIdentifierVal(t,e,"ATTLIST"),{elementName:r,attributeName:i,attributeType:s,defaultValue:a,index:e}}}const w=(t,e)=>{for(;e<t.length&&/\s/.test(t[e]);)e++;return e};function y(t,e,n){for(let r=0;r<e.length;r++)if(e[r]!==t[n+r+1])return!1;return!0}function b(t){if(l(t))return t;throw new Error(`Invalid entity name ${t}`)}const N=/^[-+]?0x[a-fA-F0-9]+$/,v=/^([\-\+])?(0*)([0-9]*(\.[0-9]*)?)$/,_={hex:!0,leadingZeros:!0,decimalPoint:".",eNotation:!0,infinity:"original"};const S=/^([-+])?(0*)(\d*(\.\d*)?[eE][-\+]?\d+)$/;class T{constructor(t){this._matcher=t}get separator(){return this._matcher.separator}getCurrentTag(){const t=this._matcher.path;return t.length>0?t[t.length-1].tag:void 0}getCurrentNamespace(){const t=this._matcher.path;return t.length>0?t[t.length-1].namespace:void 0}getAttrValue(t){const e=this._matcher.path;if(0!==e.length)return e[e.length-1].values?.[t]}hasAttr(t){const e=this._matcher.path;if(0===e.length)return!1;const n=e[e.length-1];return void 0!==n.values&&t in n.values}getPosition(){const t=this._matcher.path;return 0===t.length?-1:t[t.length-1].position??0}getCounter(){const t=this._matcher.path;return 0===t.length?-1:t[t.length-1].counter??0}getIndex(){return this.getPosition()}getDepth(){return this._matcher.path.length}toString(t,e=!0){return this._matcher.toString(t,e)}toArray(){return this._matcher.path.map(t=>t.tag)}matches(t){return this._matcher.matches(t)}matchesAny(t){return t.matchesAny(this._matcher)}}class C{constructor(t={}){this.separator=t.separator||".",this.path=[],this.siblingStacks=[],this._pathStringCache=null,this._view=new T(this)}push(t,e=null,n=null){this._pathStringCache=null,this.path.length>0&&(this.path[this.path.length-1].values=void 0);const r=this.path.length;this.siblingStacks[r]||(this.siblingStacks[r]=new Map);const i=this.siblingStacks[r],s=n?`${n}:${t}`:t,a=i.get(s)||0;let o=0;for(const t of i.values())o+=t;i.set(s,a+1);const l={tag:t,position:o,counter:a};null!=n&&(l.namespace=n),null!=e&&(l.values=e),this.path.push(l)}pop(){if(0===this.path.length)return;this._pathStringCache=null;const t=this.path.pop();return this.siblingStacks.length>this.path.length+1&&(this.siblingStacks.length=this.path.length+1),t}updateCurrent(t){if(this.path.length>0){const e=this.path[this.path.length-1];null!=t&&(e.values=t)}}getCurrentTag(){return this.path.length>0?this.path[this.path.length-1].tag:void 0}getCurrentNamespace(){return this.path.length>0?this.path[this.path.length-1].namespace:void 0}getAttrValue(t){if(0!==this.path.length)return this.path[this.path.length-1].values?.[t]}hasAttr(t){if(0===this.path.length)return!1;const e=this.path[this.path.length-1];return void 0!==e.values&&t in e.values}getPosition(){return 0===this.path.length?-1:this.path[this.path.length-1].position??0}getCounter(){return 0===this.path.length?-1:this.path[this.path.length-1].counter??0}getIndex(){return this.getPosition()}getDepth(){return this.path.length}toString(t,e=!0){const n=t||this.separator;if(n===this.separator&&!0===e){if(null!==this._pathStringCache)return this._pathStringCache;const t=this.path.map(t=>t.namespace?`${t.namespace}:${t.tag}`:t.tag).join(n);return this._pathStringCache=t,t}return this.path.map(t=>e&&t.namespace?`${t.namespace}:${t.tag}`:t.tag).join(n)}toArray(){return this.path.map(t=>t.tag)}reset(){this._pathStringCache=null,this.path=[],this.siblingStacks=[]}matches(t){const e=t.segments;return 0!==e.length&&(t.hasDeepWildcard()?this._matchWithDeepWildcard(e):this._matchSimple(e))}_matchSimple(t){if(this.path.length!==t.length)return!1;for(let e=0;e<t.length;e++)if(!this._matchSegment(t[e],this.path[e],e===this.path.length-1))return!1;return!0}_matchWithDeepWildcard(t){let e=this.path.length-1,n=t.length-1;for(;n>=0&&e>=0;){const r=t[n];if("deep-wildcard"===r.type){if(n--,n<0)return!0;const r=t[n];let i=!1;for(let t=e;t>=0;t--)if(this._matchSegment(r,this.path[t],t===this.path.length-1)){e=t-1,n--,i=!0;break}if(!i)return!1}else{if(!this._matchSegment(r,this.path[e],e===this.path.length-1))return!1;e--,n--}}return n<0}_matchSegment(t,e,n){if("*"!==t.tag&&t.tag!==e.tag)return!1;if(void 0!==t.namespace&&"*"!==t.namespace&&t.namespace!==e.namespace)return!1;if(void 0!==t.attrName){if(!n)return!1;if(!e.values||!(t.attrName in e.values))return!1;if(void 0!==t.attrValue&&String(e.values[t.attrName])!==String(t.attrValue))return!1}if(void 0!==t.position){if(!n)return!1;const r=e.counter??0;if("first"===t.position&&0!==r)return!1;if("odd"===t.position&&r%2!=1)return!1;if("even"===t.position&&r%2!=0)return!1;if("nth"===t.position&&r!==t.positionValue)return!1}return!0}matchesAny(t){return t.matchesAny(this)}snapshot(){return{path:this.path.map(t=>({...t})),siblingStacks:this.siblingStacks.map(t=>new Map(t))}}restore(t){this._pathStringCache=null,this.path=t.path.map(t=>({...t})),this.siblingStacks=t.siblingStacks.map(t=>new Map(t))}readOnly(){return this._view}}class A{constructor(t,e={},n){this.pattern=t,this.separator=e.separator||".",this.segments=this._parse(t),this.data=n,this._hasDeepWildcard=this.segments.some(t=>"deep-wildcard"===t.type),this._hasAttributeCondition=this.segments.some(t=>void 0!==t.attrName),this._hasPositionSelector=this.segments.some(t=>void 0!==t.position)}_parse(t){const e=[];let n=0,r="";for(;n<t.length;)t[n]===this.separator?n+1<t.length&&t[n+1]===this.separator?(r.trim()&&(e.push(this._parseSegment(r.trim())),r=""),e.push({type:"deep-wildcard"}),n+=2):(r.trim()&&e.push(this._parseSegment(r.trim())),r="",n++):(r+=t[n],n++);return r.trim()&&e.push(this._parseSegment(r.trim())),e}_parseSegment(t){const e={type:"tag"};let n=null,r=t;const i=t.match(/^([^\[]+)(\[[^\]]*\])(.*)$/);if(i&&(r=i[1]+i[3],i[2])){const t=i[2].slice(1,-1);t&&(n=t)}let s,a,o=r;if(r.includes("::")){const e=r.indexOf("::");if(s=r.substring(0,e).trim(),o=r.substring(e+2).trim(),!s)throw new Error(`Invalid namespace in pattern: ${t}`)}let l=null;if(o.includes(":")){const t=o.lastIndexOf(":"),e=o.substring(0,t).trim(),n=o.substring(t+1).trim();["first","last","odd","even"].includes(n)||/^nth\(\d+\)$/.test(n)?(a=e,l=n):a=o}else a=o;if(!a)throw new Error(`Invalid segment pattern: ${t}`);if(e.tag=a,s&&(e.namespace=s),n)if(n.includes("=")){const t=n.indexOf("=");e.attrName=n.substring(0,t).trim(),e.attrValue=n.substring(t+1).trim()}else e.attrName=n.trim();if(l){const t=l.match(/^nth\((\d+)\)$/);t?(e.position="nth",e.positionValue=parseInt(t[1],10)):e.position=l}return e}get length(){return this.segments.length}hasDeepWildcard(){return this._hasDeepWildcard}hasAttributeCondition(){return this._hasAttributeCondition}hasPositionSelector(){return this._hasPositionSelector}toString(){return this.pattern}}class I{constructor(){this._byDepthAndTag=new Map,this._wildcardByDepth=new Map,this._deepWildcards=[],this._patterns=new Set,this._sealed=!1}add(t){if(this._sealed)throw new TypeError("ExpressionSet is sealed. Create a new ExpressionSet to add more expressions.");if(this._patterns.has(t.pattern))return this;if(this._patterns.add(t.pattern),t.hasDeepWildcard())return this._deepWildcards.push(t),this;const e=t.length,n=t.segments[t.segments.length-1],r=n?.tag;if(r&&"*"!==r){const n=`${e}:${r}`;this._byDepthAndTag.has(n)||this._byDepthAndTag.set(n,[]),this._byDepthAndTag.get(n).push(t)}else this._wildcardByDepth.has(e)||this._wildcardByDepth.set(e,[]),this._wildcardByDepth.get(e).push(t);return this}addAll(t){for(const e of t)this.add(e);return this}has(t){return this._patterns.has(t.pattern)}get size(){return this._patterns.size}seal(){return this._sealed=!0,this}get isSealed(){return this._sealed}matchesAny(t){return null!==this.findMatch(t)}findMatch(t){const e=t.getDepth(),n=`${e}:${t.getCurrentTag()}`,r=this._byDepthAndTag.get(n);if(r)for(let e=0;e<r.length;e++)if(t.matches(r[e]))return r[e];const i=this._wildcardByDepth.get(e);if(i)for(let e=0;e<i.length;e++)if(t.matches(i[e]))return i[e];for(let e=0;e<this._deepWildcards.length;e++)if(t.matches(this._deepWildcards[e]))return this._deepWildcards[e];return null}}const P={cent:"¢",pound:"£",curren:"¤",yen:"¥",euro:"€",dollar:"$",euro:"€",fnof:"ƒ",inr:"₹",af:"؋",birr:"ብር",peso:"₱",rub:"₽",won:"₩",yuan:"¥",cedil:"¸"},D={amp:"&",apos:"'",gt:">",lt:"<",quot:'"'},O={nbsp:" ",copy:"©",reg:"®",trade:"™",mdash:"—",ndash:"–",hellip:"…",laquo:"«",raquo:"»",lsquo:"‘",rsquo:"’",ldquo:"“",rdquo:"”",bull:"•",para:"¶",sect:"§",deg:"°",frac12:"½",frac14:"¼",frac34:"¾"},M=new Set("!?\\\\/[]$%{}^&*()<>|+");function $(t){if("#"===t[0])throw new Error(`[EntityReplacer] Invalid character '#' in entity name: "${t}"`);for(const e of t)if(M.has(e))throw new Error(`[EntityReplacer] Invalid character '${e}' in entity name: "${t}"`);return t}function L(...t){const e=Object.create(null);for(const n of t)if(n)for(const t of Object.keys(n)){const r=n[t];if("string"==typeof r)e[t]=r;else if(r&&"object"==typeof r&&void 0!==r.val){const n=r.val;"string"==typeof n&&(e[t]=n)}}return e}const j="external",k="base",V="all",F=Object.freeze({allow:0,leave:1,remove:2,throw:3}),R=new Set([9,10,13]);class U{constructor(t={}){var e;this._limit=t.limit||{},this._maxTotalExpansions=this._limit.maxTotalExpansions||0,this._maxExpandedLength=this._limit.maxExpandedLength||0,this._postCheck="function"==typeof t.postCheck?t.postCheck:t=>t,this._limitTiers=(e=this._limit.applyLimitsTo??j)&&e!==j?e===V?new Set([V]):e===k?new Set([k]):Array.isArray(e)?new Set(e):new Set([j]):new Set([j]),this._numericAllowed=t.numericAllowed??!0,this._baseMap=L(D,t.namedEntities||null),this._externalMap=Object.create(null),this._inputMap=Object.create(null),this._totalExpansions=0,this._expandedLength=0,this._removeSet=new Set(t.remove&&Array.isArray(t.remove)?t.remove:[]),this._leaveSet=new Set(t.leave&&Array.isArray(t.leave)?t.leave:[]);const n=function(t){if(!t)return{xmlVersion:1,onLevel:F.allow,nullLevel:F.remove};const e=1.1===t.xmlVersion?1.1:1,n=F[t.onNCR]??F.allow,r=F[t.nullNCR]??F.remove;return{xmlVersion:e,onLevel:n,nullLevel:Math.max(r,F.remove)}}(t.ncr);this._ncrXmlVersion=n.xmlVersion,this._ncrOnLevel=n.onLevel,this._ncrNullLevel=n.nullLevel}setExternalEntities(t){if(t)for(const e of Object.keys(t))$(e);this._externalMap=L(t)}addExternalEntity(t,e){$(t),"string"==typeof e&&-1===e.indexOf("&")&&(this._externalMap[t]=e)}addInputEntities(t){this._totalExpansions=0,this._expandedLength=0,this._inputMap=L(t)}reset(){return this._inputMap=Object.create(null),this._totalExpansions=0,this._expandedLength=0,this}setXmlVersion(t){this._ncrXmlVersion=1.1===t?1.1:1}decode(t){if("string"!=typeof t||0===t.length)return t;const e=t,n=[],r=t.length;let i=0,s=0;const a=this._maxTotalExpansions>0,o=this._maxExpandedLength>0,l=a||o;for(;s<r;){if(38!==t.charCodeAt(s)){s++;continue}let e=s+1;for(;e<r&&59!==t.charCodeAt(e)&&e-s<=32;)e++;if(e>=r||59!==t.charCodeAt(e)){s++;continue}const h=t.slice(s+1,e);if(0===h.length){s++;continue}let c,u;if(this._removeSet.has(h))c="",void 0===u&&(u=j);else{if(this._leaveSet.has(h)){s++;continue}if(35===h.charCodeAt(0)){const t=this._resolveNCR(h);if(void 0===t){s++;continue}c=t,u=k}else{const t=this._resolveName(h);c=t?.value,u=t?.tier}}if(void 0!==c){if(s>i&&n.push(t.slice(i,s)),n.push(c),i=e+1,s=i,l&&this._tierCounts(u)){if(a&&(this._totalExpansions++,this._totalExpansions>this._maxTotalExpansions))throw new Error(`[EntityReplacer] Entity expansion count limit exceeded: ${this._totalExpansions} > ${this._maxTotalExpansions}`);if(o){const t=c.length-(h.length+2);if(t>0&&(this._expandedLength+=t,this._expandedLength>this._maxExpandedLength))throw new Error(`[EntityReplacer] Expanded content length limit exceeded: ${this._expandedLength} > ${this._maxExpandedLength}`)}}}else s++}i<r&&n.push(t.slice(i));const h=0===n.length?t:n.join("");return this._postCheck(h,e)}_tierCounts(t){return!!this._limitTiers.has(V)||this._limitTiers.has(t)}_resolveName(t){return t in this._inputMap?{value:this._inputMap[t],tier:j}:t in this._externalMap?{value:this._externalMap[t],tier:j}:t in this._baseMap?{value:this._baseMap[t],tier:k}:void 0}_classifyNCR(t){return 0===t?this._ncrNullLevel:t>=55296&&t<=57343||1===this._ncrXmlVersion&&t>=1&&t<=31&&!R.has(t)?F.remove:-1}_applyNCRAction(t,e,n){switch(t){case F.allow:return String.fromCodePoint(n);case F.remove:return"";case F.leave:return;case F.throw:throw new Error(`[EntityDecoder] Prohibited numeric character reference &${e}; (U+${n.toString(16).toUpperCase().padStart(4,"0")})`);default:return String.fromCodePoint(n)}}_resolveNCR(t){const e=t.charCodeAt(1);let n;if(n=120===e||88===e?parseInt(t.slice(2),16):parseInt(t.slice(1),10),Number.isNaN(n)||n<0||n>1114111)return;const r=this._classifyNCR(n);if(!this._numericAllowed&&r<F.remove)return;const i=-1===r?this._ncrOnLevel:Math.max(this._ncrOnLevel,r);return this._applyNCRAction(i,t,n)}}function W(t,e){if(!t)return{};const n=e.attributesGroupName?t[e.attributesGroupName]:t;if(!n)return{};const r={};for(const t in n)t.startsWith(e.attributeNamePrefix)?r[t.substring(e.attributeNamePrefix.length)]=n[t]:r[t]=n[t];return r}function Y(t){if(!t||"string"!=typeof t)return;const e=t.indexOf(":");if(-1!==e&&e>0){const n=t.substring(0,e);if("xmlns"!==n)return n}}class X{constructor(t){var e;this.options=t,this.currentNode=null,this.tagsNodeStack=[],this.parseXml=J,this.parseTextData=z,this.resolveNameSpace=B,this.buildAttributesMap=q,this.isItStopNode=H,this.replaceEntitiesValue=K,this.readStopNodeData=rt,this.saveTextToParentTag=Q,this.addChild=Z,this.ignoreAttributesFn="function"==typeof(e=this.options.ignoreAttributes)?e:Array.isArray(e)?t=>{for(const n of e){if("string"==typeof n&&t===n)return!0;if(n instanceof RegExp&&n.test(t))return!0}}:()=>!1,this.entityExpansionCount=0,this.currentExpandedLength=0;let n={...D};this.options.entityDecoder?this.entityDecoder=this.options.entityDecoder:("object"==typeof this.options.htmlEntities?n=this.options.htmlEntities:!0===this.options.htmlEntities&&(n={...O,...P}),this.entityDecoder=new U({namedEntities:n,numericAllowed:this.options.htmlEntities,limit:{maxTotalExpansions:this.options.processEntities.maxTotalExpansions,maxExpandedLength:this.options.processEntities.maxExpandedLength,applyLimitsTo:this.options.processEntities.appliesTo}})),this.matcher=new C,this.readonlyMatcher=this.matcher.readOnly(),this.isCurrentNodeStopNode=!1,this.stopNodeExpressionsSet=new I;const r=this.options.stopNodes;if(r&&r.length>0){for(let t=0;t<r.length;t++){const e=r[t];"string"==typeof e?this.stopNodeExpressionsSet.add(new A(e)):e instanceof A&&this.stopNodeExpressionsSet.add(e)}this.stopNodeExpressionsSet.seal()}}}function z(t,e,n,r,i,s,a){const o=this.options;if(void 0!==t&&(o.trimValues&&!r&&(t=t.trim()),t.length>0)){a||(t=this.replaceEntitiesValue(t,e,n));const r=o.jPath?n.toString():n,l=o.tagValueProcessor(e,t,r,i,s);return null==l?t:typeof l!=typeof t||l!==t?l:o.trimValues||t.trim()===t?it(t,o.parseTagValue,o.numberParseOptions):t}}function B(t){if(this.options.removeNSPrefix){const e=t.split(":"),n="/"===t.charAt(0)?"/":"";if("xmlns"===e[0])return"";2===e.length&&(t=n+e[1])}return t}const G=new RegExp("([^\\s=]+)\\s*(=\\s*(['\"])([\\s\\S]*?)\\3)?","gm");function q(t,e,n,r=!1){const i=this.options;if(!0===r||!0!==i.ignoreAttributes&&"string"==typeof t){const r=o(t,G),s=r.length,a={},l=new Array(s);let h=!1;const c={};for(let t=0;t<s;t++){const e=this.resolveNameSpace(r[t][1]),s=r[t][4];if(e.length&&void 0!==s){let r=s;i.trimValues&&(r=r.trim()),r=this.replaceEntitiesValue(r,n,this.readonlyMatcher),l[t]=r,c[e]=r,h=!0}}h&&"object"==typeof e&&e.updateCurrent&&e.updateCurrent(c);const u=i.jPath?e.toString():this.readonlyMatcher;let d=!1;for(let t=0;t<s;t++){const e=this.resolveNameSpace(r[t][1]);if(this.ignoreAttributesFn(e,u))continue;let n=i.attributeNamePrefix+e;if(e.length)if(i.transformAttributeName&&(n=i.transformAttributeName(n)),n=at(n,i),void 0!==r[t][4]){const r=l[t],s=i.attributeValueProcessor(e,r,u);a[n]=null==s?r:typeof s!=typeof r||s!==r?s:it(r,i.parseAttributeValue,i.numberParseOptions),d=!0}else i.allowBooleanAttributes&&(a[n]=!0,d=!0)}if(!d)return;if(i.attributesGroupName){const t={};return t[i.attributesGroupName]=a,t}return a}}const J=function(t){t=t.replace(/\r\n?/g,"\n");const e=new x("!xml");let n=e,r="";this.matcher.reset(),this.entityDecoder.reset(),this.entityExpansionCount=0,this.currentExpandedLength=0;const i=this.options,s=new E(i.processEntities),a=t.length;for(let o=0;o<a;o++)if("<"===t[o]){const l=t.charCodeAt(o+1);if(47===l){const e=tt(t,">",o,"Closing Tag is not closed.");let s=t.substring(o+2,e).trim();if(i.removeNSPrefix){const t=s.indexOf(":");-1!==t&&(s=s.substr(t+1))}s=st(i.transformTagName,s,"",i).tagName,n&&(r=this.saveTextToParentTag(r,n,this.readonlyMatcher));const a=this.matcher.getCurrentTag();if(s&&i.unpairedTagsSet.has(s))throw new Error(`Unpaired tag can not be used as closing tag: </${s}>`);a&&i.unpairedTagsSet.has(a)&&(this.matcher.pop(),this.tagsNodeStack.pop()),this.matcher.pop(),this.isCurrentNodeStopNode=!1,n=this.tagsNodeStack.pop(),r="",o=e}else if(63===l){let e=nt(t,o,!1,"?>");if(!e)throw new Error("Pi Tag is not closed.");r=this.saveTextToParentTag(r,n,this.readonlyMatcher);const s=this.buildAttributesMap(e.tagExp,this.matcher,e.tagName,!0);if(s){const t=s[this.options.attributeNamePrefix+"version"];this.entityDecoder.setXmlVersion(Number(t)||1)}if(i.ignoreDeclaration&&"?xml"===e.tagName||i.ignorePiTags);else{const t=new x(e.tagName);t.add(i.textNodeName,""),e.tagName!==e.tagExp&&e.attrExpPresent&&!0!==i.ignoreAttributes&&(t[":@"]=s),this.addChild(n,t,this.readonlyMatcher,o)}o=e.closeIndex+1}else if(33===l&&45===t.charCodeAt(o+2)&&45===t.charCodeAt(o+3)){const e=tt(t,"--\x3e",o+4,"Comment is not closed.");if(i.commentPropName){const s=t.substring(o+4,e-2);r=this.saveTextToParentTag(r,n,this.readonlyMatcher),n.add(i.commentPropName,[{[i.textNodeName]:s}])}o=e}else if(33===l&&68===t.charCodeAt(o+2)){const e=s.readDocType(t,o);this.entityDecoder.addInputEntities(e.entities),o=e.i}else if(33===l&&91===t.charCodeAt(o+2)){const e=tt(t,"]]>",o,"CDATA is not closed.")-2,s=t.substring(o+9,e);r=this.saveTextToParentTag(r,n,this.readonlyMatcher);let a=this.parseTextData(s,n.tagname,this.readonlyMatcher,!0,!1,!0,!0);null==a&&(a=""),i.cdataPropName?n.add(i.cdataPropName,[{[i.textNodeName]:s}]):n.add(i.textNodeName,a),o=e+2}else{let s=nt(t,o,i.removeNSPrefix);if(!s){const e=t.substring(Math.max(0,o-50),Math.min(a,o+50));throw new Error(`readTagExp returned undefined at position ${o}. Context: "${e}"`)}let l=s.tagName;const h=s.rawTagName;let c=s.tagExp,u=s.attrExpPresent,d=s.closeIndex;if(({tagName:l,tagExp:c}=st(i.transformTagName,l,c,i)),i.strictReservedNames&&(l===i.commentPropName||l===i.cdataPropName||l===i.textNodeName||l===i.attributesGroupName))throw new Error(`Invalid tag name: ${l}`);n&&r&&"!xml"!==n.tagname&&(r=this.saveTextToParentTag(r,n,this.readonlyMatcher,!1));const p=n;p&&i.unpairedTagsSet.has(p.tagname)&&(n=this.tagsNodeStack.pop(),this.matcher.pop());let f=!1;c.length>0&&c.lastIndexOf("/")===c.length-1&&(f=!0,"/"===l[l.length-1]?(l=l.substr(0,l.length-1),c=l):c=c.substr(0,c.length-1),u=l!==c);let g,m=null,E={};g=Y(h),l!==e.tagname&&this.matcher.push(l,{},g),l!==c&&u&&(m=this.buildAttributesMap(c,this.matcher,l),m&&(E=W(m,i))),l!==e.tagname&&(this.isCurrentNodeStopNode=this.isItStopNode());const w=o;if(this.isCurrentNodeStopNode){let e="";if(f)o=s.closeIndex;else if(i.unpairedTagsSet.has(l))o=s.closeIndex;else{const n=this.readStopNodeData(t,h,d+1);if(!n)throw new Error(`Unexpected end of ${h}`);o=n.i,e=n.tagContent}const r=new x(l);m&&(r[":@"]=m),r.add(i.textNodeName,e),this.matcher.pop(),this.isCurrentNodeStopNode=!1,this.addChild(n,r,this.readonlyMatcher,w)}else{if(f){({tagName:l,tagExp:c}=st(i.transformTagName,l,c,i));const t=new x(l);m&&(t[":@"]=m),this.addChild(n,t,this.readonlyMatcher,w),this.matcher.pop(),this.isCurrentNodeStopNode=!1}else{if(i.unpairedTagsSet.has(l)){const t=new x(l);m&&(t[":@"]=m),this.addChild(n,t,this.readonlyMatcher,w),this.matcher.pop(),this.isCurrentNodeStopNode=!1,o=s.closeIndex;continue}{const t=new x(l);if(this.tagsNodeStack.length>i.maxNestedTags)throw new Error("Maximum nested tags exceeded");this.tagsNodeStack.push(n),m&&(t[":@"]=m),this.addChild(n,t,this.readonlyMatcher,w),n=t}}r="",o=d}}}else r+=t[o];return e.child};function Z(t,e,n,r){this.options.captureMetaData||(r=void 0);const i=this.options.jPath?n.toString():n,s=this.options.updateTag(e.tagname,i,e[":@"]);!1===s||("string"==typeof s?(e.tagname=s,t.addChild(e,r)):t.addChild(e,r))}function K(t,e,n){const r=this.options.processEntities;if(!r||!r.enabled)return t;if(r.allowedTags){const i=this.options.jPath?n.toString():n;if(!(Array.isArray(r.allowedTags)?r.allowedTags.includes(e):r.allowedTags(e,i)))return t}if(r.tagFilter){const i=this.options.jPath?n.toString():n;if(!r.tagFilter(e,i))return t}return this.entityDecoder.decode(t)}function Q(t,e,n,r){return t&&(void 0===r&&(r=0===e.child.length),void 0!==(t=this.parseTextData(t,e.tagname,n,!1,!!e[":@"]&&0!==Object.keys(e[":@"]).length,r))&&""!==t&&e.add(this.options.textNodeName,t),t=""),t}function H(){return 0!==this.stopNodeExpressionsSet.size&&this.matcher.matchesAny(this.stopNodeExpressionsSet)}function tt(t,e,n,r){const i=t.indexOf(e,n);if(-1===i)throw new Error(r);return i+e.length-1}function et(t,e,n,r){const i=t.indexOf(e,n);if(-1===i)throw new Error(r);return i}function nt(t,e,n,r=">"){const i=function(t,e,n=">"){let r=0;const i=[],s=t.length,a=n.charCodeAt(0),o=n.length>1?n.charCodeAt(1):-1;for(let n=e;n<s;n++){const e=t.charCodeAt(n);if(r)e===r&&(r=0);else if(34===e||39===e)r=e;else if(e===a){if(-1===o)return{data:String.fromCharCode(...i),index:n};if(t.charCodeAt(n+1)===o)return{data:String.fromCharCode(...i),index:n}}else if(9===e){i.push(32);continue}i.push(e)}}(t,e+1,r);if(!i)return;let s=i.data;const a=i.index,o=s.search(/\s/);let l=s,h=!0;-1!==o&&(l=s.substring(0,o),s=s.substring(o+1).trimStart());const c=l;if(n){const t=l.indexOf(":");-1!==t&&(l=l.substr(t+1),h=l!==i.data.substr(t+1))}return{tagName:l,tagExp:s,closeIndex:a,attrExpPresent:h,rawTagName:c}}function rt(t,e,n){const r=n;let i=1;const s=t.length;for(;n<s;n++)if("<"===t[n]){const s=t.charCodeAt(n+1);if(47===s){const s=et(t,">",n,`${e} is not closed`);if(t.substring(n+2,s).trim()===e&&(i--,0===i))return{tagContent:t.substring(r,n),i:s};n=s}else if(63===s)n=tt(t,"?>",n+1,"StopNode is not closed.");else if(33===s&&45===t.charCodeAt(n+2)&&45===t.charCodeAt(n+3))n=tt(t,"--\x3e",n+3,"StopNode is not closed.");else if(33===s&&91===t.charCodeAt(n+2))n=tt(t,"]]>",n,"StopNode is not closed.")-2;else{const r=nt(t,n,">");r&&((r&&r.tagName)===e&&"/"!==r.tagExp[r.tagExp.length-1]&&i++,n=r.closeIndex)}}}function it(t,e,n){if(e&&"string"==typeof t){const e=t.trim();return"true"===e||"false"!==e&&function(t,e={}){if(e=Object.assign({},_,e),!t||"string"!=typeof t)return t;let n=t.trim();if(0===n.length)return t;if(void 0!==e.skipLike&&e.skipLike.test(n))return t;if("0"===n)return 0;if(e.hex&&N.test(n))return function(t){if(parseInt)return parseInt(t,16);if(Number.parseInt)return Number.parseInt(t,16);if(window&&window.parseInt)return window.parseInt(t,16);throw new Error("parseInt, Number.parseInt, window.parseInt are not supported")}(n);if(isFinite(n)){if(n.includes("e")||n.includes("E"))return function(t,e,n){if(!n.eNotation)return t;const r=e.match(S);if(r){let i=r[1]||"";const s=-1===r[3].indexOf("e")?"E":"e",a=r[2],o=i?t[a.length+1]===s:t[a.length]===s;return a.length>1&&o?t:(1!==a.length||!r[3].startsWith(`.${s}`)&&r[3][0]!==s)&&a.length>0?n.leadingZeros&&!o?(e=(r[1]||"")+r[3],Number(e)):t:Number(e)}return t}(t,n,e);{const i=v.exec(n);if(i){const s=i[1]||"",a=i[2];let o=(r=i[3])&&-1!==r.indexOf(".")?("."===(r=r.replace(/0+$/,""))?r="0":"."===r[0]?r="0"+r:"."===r[r.length-1]&&(r=r.substring(0,r.length-1)),r):r;const l=s?"."===t[a.length+1]:"."===t[a.length];if(!e.leadingZeros&&(a.length>1||1===a.length&&!l))return t;{const r=Number(n),i=String(r);if(0===r)return r;if(-1!==i.search(/[eE]/))return e.eNotation?r:t;if(-1!==n.indexOf("."))return"0"===i||i===o||i===`${s}${o}`?r:t;let l=a?o:n;return a?l===i||s+l===i?r:t:l===i||l===s+i?r:t}}return t}}var r;return function(t,e,n){const r=e===1/0;switch(n.infinity.toLowerCase()){case"null":return null;case"infinity":return e;case"string":return r?"Infinity":"-Infinity";default:return t}}(t,Number(n),e)}(t,n)}return void 0!==t?t:""}function st(t,e,n,r){if(t){const r=t(e);n===e&&(n=r),e=r}return{tagName:e=at(e,r),tagExp:n}}function at(t,e){if(c.includes(t))throw new Error(`[SECURITY] Invalid name: "${t}" is a reserved JavaScript keyword that could cause prototype pollution`);return h.includes(t)?e.onDangerousProperty(t):t}const ot=x.getMetaDataSymbol();function lt(t,e){if(!t||"object"!=typeof t)return{};if(!e)return t;const n={};for(const r in t)r.startsWith(e)?n[r.substring(e.length)]=t[r]:n[r]=t[r];return n}function ht(t,e,n,r){return ct(t,e,n,r)}function ct(t,e,n,r){let i;const s={};for(let a=0;a<t.length;a++){const o=t[a],l=ut(o);if(void 0!==l&&l!==e.textNodeName){const t=lt(o[":@"]||{},e.attributeNamePrefix);n.push(l,t)}if(l===e.textNodeName)void 0===i?i=o[l]:i+=""+o[l];else{if(void 0===l)continue;if(o[l]){let t=ct(o[l],e,n,r);const i=pt(t,e);if(o[":@"]?dt(t,o[":@"],r,e):1!==Object.keys(t).length||void 0===t[e.textNodeName]||e.alwaysCreateTextNode?0===Object.keys(t).length&&(e.alwaysCreateTextNode?t[e.textNodeName]="":t=""):t=t[e.textNodeName],void 0!==o[ot]&&"object"==typeof t&&null!==t&&(t[ot]=o[ot]),void 0!==s[l]&&Object.prototype.hasOwnProperty.call(s,l))Array.isArray(s[l])||(s[l]=[s[l]]),s[l].push(t);else{const n=e.jPath?r.toString():r;e.isArray(l,n,i)?s[l]=[t]:s[l]=t}void 0!==l&&l!==e.textNodeName&&n.pop()}}}return"string"==typeof i?i.length>0&&(s[e.textNodeName]=i):void 0!==i&&(s[e.textNodeName]=i),s}function ut(t){const e=Object.keys(t);for(let t=0;t<e.length;t++){const n=e[t];if(":@"!==n)return n}}function dt(t,e,n,r){if(e){const i=Object.keys(e),s=i.length;for(let a=0;a<s;a++){const s=i[a],o=s.startsWith(r.attributeNamePrefix)?s.substring(r.attributeNamePrefix.length):s,l=r.jPath?n.toString()+"."+o:n;r.isArray(s,l,!0,!0)?t[s]=[e[s]]:t[s]=e[s]}}}function pt(t,e){const{textNodeName:n}=e,r=Object.keys(t).length;return 0===r||!(1!==r||!t[n]&&"boolean"!=typeof t[n]&&0!==t[n])}const ft={allowBooleanAttributes:!1,unpairedTags:[]};function gt(t,e){e=Object.assign({},ft,e);const n=[];let r=!1,i=!1;"\ufeff"===t[0]&&(t=t.substr(1));for(let s=0;s<t.length;s++)if("<"===t[s]&&"?"===t[s+1]){if(s+=2,s=xt(t,s),s.err)return s}else{if("<"!==t[s]){if(mt(t[s]))continue;return St("InvalidChar","char '"+t[s]+"' is not expected.",At(t,s))}{let a=s;if(s++,"!"===t[s]){s=Et(t,s);continue}{let o=!1;"/"===t[s]&&(o=!0,s++);let l="";for(;s<t.length&&">"!==t[s]&&" "!==t[s]&&"\t"!==t[s]&&"\n"!==t[s]&&"\r"!==t[s];s++)l+=t[s];if(l=l.trim(),"/"===l[l.length-1]&&(l=l.substring(0,l.length-1),s--),!Ct(l)){let e;return e=0===l.trim().length?"Invalid space after '<'.":"Tag '"+l+"' is an invalid name.",St("InvalidTag",e,At(t,s))}const h=bt(t,s);if(!1===h)return St("InvalidAttr","Attributes for '"+l+"' have open quote.",At(t,s));let c=h.value;if(s=h.index,"/"===c[c.length-1]){const n=s-c.length;c=c.substring(0,c.length-1);const i=vt(c,e);if(!0!==i)return St(i.err.code,i.err.msg,At(t,n+i.err.line));r=!0}else if(o){if(!h.tagClosed)return St("InvalidTag","Closing tag '"+l+"' doesn't have proper closing.",At(t,s));if(c.trim().length>0)return St("InvalidTag","Closing tag '"+l+"' can't have attributes or invalid starting.",At(t,a));if(0===n.length)return St("InvalidTag","Closing tag '"+l+"' has not been opened.",At(t,a));{const e=n.pop();if(l!==e.tagName){let n=At(t,e.tagStartPos);return St("InvalidTag","Expected closing tag '"+e.tagName+"' (opened in line "+n.line+", col "+n.col+") instead of closing tag '"+l+"'.",At(t,a))}0==n.length&&(i=!0)}}else{const o=vt(c,e);if(!0!==o)return St(o.err.code,o.err.msg,At(t,s-c.length+o.err.line));if(!0===i)return St("InvalidXml","Multiple possible root nodes found.",At(t,s));-1!==e.unpairedTags.indexOf(l)||n.push({tagName:l,tagStartPos:a}),r=!0}for(s++;s<t.length;s++)if("<"===t[s]){if("!"===t[s+1]){s++,s=Et(t,s);continue}if("?"!==t[s+1])break;if(s=xt(t,++s),s.err)return s}else if("&"===t[s]){const e=_t(t,s);if(-1==e)return St("InvalidChar","char '&' is not expected.",At(t,s));s=e}else if(!0===i&&!mt(t[s]))return St("InvalidXml","Extra text at the end",At(t,s));"<"===t[s]&&s--}}}return r?1==n.length?St("InvalidTag","Unclosed tag '"+n[0].tagName+"'.",At(t,n[0].tagStartPos)):!(n.length>0)||St("InvalidXml","Invalid '"+JSON.stringify(n.map(t=>t.tagName),null,4).replace(/\r?\n/g,"")+"' found.",{line:1,col:1}):St("InvalidXml","Start tag expected.",1)}function mt(t){return" "===t||"\t"===t||"\n"===t||"\r"===t}function xt(t,e){const n=e;for(;e<t.length;e++)if("?"==t[e]||" "==t[e]){const r=t.substr(n,e-n);if(e>5&&"xml"===r)return St("InvalidXml","XML declaration allowed only at the start of the document.",At(t,e));if("?"==t[e]&&">"==t[e+1]){e++;break}continue}return e}function Et(t,e){if(t.length>e+5&&"-"===t[e+1]&&"-"===t[e+2]){for(e+=3;e<t.length;e++)if("-"===t[e]&&"-"===t[e+1]&&">"===t[e+2]){e+=2;break}}else if(t.length>e+8&&"D"===t[e+1]&&"O"===t[e+2]&&"C"===t[e+3]&&"T"===t[e+4]&&"Y"===t[e+5]&&"P"===t[e+6]&&"E"===t[e+7]){let n=1;for(e+=8;e<t.length;e++)if("<"===t[e])n++;else if(">"===t[e]&&(n--,0===n))break}else if(t.length>e+9&&"["===t[e+1]&&"C"===t[e+2]&&"D"===t[e+3]&&"A"===t[e+4]&&"T"===t[e+5]&&"A"===t[e+6]&&"["===t[e+7])for(e+=8;e<t.length;e++)if("]"===t[e]&&"]"===t[e+1]&&">"===t[e+2]){e+=2;break}return e}const wt='"',yt="'";function bt(t,e){let n="",r="",i=!1;for(;e<t.length;e++){if(t[e]===wt||t[e]===yt)""===r?r=t[e]:r!==t[e]||(r="");else if(">"===t[e]&&""===r){i=!0;break}n+=t[e]}return""===r&&{value:n,index:e,tagClosed:i}}const Nt=new RegExp("(\\s*)([^\\s=]+)(\\s*=)?(\\s*(['\"])(([\\s\\S])*?)\\5)?","g");function vt(t,e){const n=o(t,Nt),r={};for(let t=0;t<n.length;t++){if(0===n[t][1].length)return St("InvalidAttr","Attribute '"+n[t][2]+"' has no space in starting.",It(n[t]));if(void 0!==n[t][3]&&void 0===n[t][4])return St("InvalidAttr","Attribute '"+n[t][2]+"' is without value.",It(n[t]));if(void 0===n[t][3]&&!e.allowBooleanAttributes)return St("InvalidAttr","boolean attribute '"+n[t][2]+"' is not allowed.",It(n[t]));const i=n[t][2];if(!Tt(i))return St("InvalidAttr","Attribute '"+i+"' is an invalid name.",It(n[t]));if(Object.prototype.hasOwnProperty.call(r,i))return St("InvalidAttr","Attribute '"+i+"' is repeated.",It(n[t]));r[i]=1}return!0}function _t(t,e){if(";"===t[++e])return-1;if("#"===t[e])return function(t,e){let n=/\d/;for("x"===t[e]&&(e++,n=/[\da-fA-F]/);e<t.length;e++){if(";"===t[e])return e;if(!t[e].match(n))break}return-1}(t,++e);let n=0;for(;e<t.length;e++,n++)if(!(t[e].match(/\w/)&&n<20)){if(";"===t[e])break;return-1}return e}function St(t,e,n){return{err:{code:t,msg:e,line:n.line||n,col:n.col}}}function Tt(t){return l(t)}function Ct(t){return l(t)}function At(t,e){const n=t.substring(0,e).split(/\r?\n/);return{line:n.length,col:n[n.length-1].length+1}}function It(t){return t.startIndex+t[1].length}const Pt={validate:gt},Dt=new class{constructor(t){this.externalEntities={},this.options=g(t)}parse(t,e){if("string"!=typeof t&&t.toString)t=t.toString();else if("string"!=typeof t)throw new Error("XML data is accepted in String or Bytes[] form.");if(e){!0===e&&(e={});const n=gt(t,e);if(!0!==n)throw Error(`${n.err.msg}:${n.err.line}:${n.err.col}`)}const n=new X(this.options);n.entityDecoder.setExternalEntities(this.externalEntities);const r=n.parseXml(t);return this.options.preserveOrder||void 0===r?r:ht(r,this.options,n.matcher,n.readonlyMatcher)}addEntity(t,e){if(-1!==e.indexOf("&"))throw new Error("Entity value can't have '&'");if(-1!==t.indexOf("&")||-1!==t.indexOf(";"))throw new Error("An entity must be set without '&' and ';'. Eg. use '#xD' for '
'");if("&"===e)throw new Error("An entity with value '&' is not permitted");this.externalEntities[t]=e}static getMetaDataSymbol(){return x.getMetaDataSymbol()}},Ot={Jan:"01",Feb:"02",Mar:"03",Apr:"04",May:"05",Jun:"06",Jul:"07",Aug:"08",Sep:"09",Oct:"10",Nov:"11",Dec:"12"};function Mt(t){if(/^\d{4}-\d{2}-\d{2}$/.test(t))return new Date(t).toISOString();let e=/^\w{3} (\w{3}) (\d{2}) (\d{4}) ([\d:]{8}) GMT([\-+]\d{4})$/.exec(t);return e?new Date(`${e[3]}-${Ot[e[1]]}-${e[2]}T${e[4]}${e[5]}`).toISOString():t}const $t={normalize:r,request:i,children:async t=>{const e=r(t);e.pathname+=".sitemap.xml",e.searchParams.set("_",Date.now());const n=await i(e,{redirect:"error"});return n.data=(t=>{const e=Pt.validate(t);if(!0!==e)throw new Error(e.err.msg);const n=Dt.parse(t),i=n.urlset?.url||[];return(Array.isArray(i)?i:[i]).filter(t=>t.loc).map(t=>({path:r(t.loc).pathname,lastmod:t.lastmod?new Date(t.lastmod).toISOString():null}))})(n.data),n},content:async t=>{const e=r(t);return e.pathname+=".html",e.searchParams.set("_",Date.now()),i(e,{signal:AbortSignal.timeout(1e4),redirect:"error"})},meta:async t=>{const e=r(t);e.pathname+="/_jcr_content.json",e.searchParams.set("_",Date.now());const n=await i(e,{signal:AbortSignal.timeout(1e4),redirect:"error"});return n.data=(t=>{const e={};for(const[n,i]of Object.entries(t))n.endsWith("@TypeHint")||Array.isArray(i)&&0===i.length||("true"===i?e[n]=!0:"false"===i?e[n]=!1:"gcAltLanguagePeer"===n?(e[n]=i,e.peer=r(i).pathname):e[n]="string"==typeof i?Mt(i.trim()):i);return Object.keys(e).sort().reduce((t,n)=>(t[n]=e[n],t),{})})(n.data),n}};return e.default})());
|
|
1
|
+
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define("ca",[],e):"object"==typeof exports?exports.ca=e():t.ca=e()}(Object("undefined"!=typeof self?self:this),()=>(()=>{"use strict";var t={d:(e,a)=>{for(var r in a)t.o(a,r)&&!t.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:a[r]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)},e={};t.d(e,{default:()=>c});const a="https://www.canada.ca",r=t=>{if("string"==typeof t)t=new URL(t,a);else{if(!(t instanceof URL))throw new TypeError("string or URL object expected");t=new URL(t.href)}if(t.origin!==a)throw new Error("URL must start with "+a);if(t.pathname=t.pathname.replace(/^\/content\/canadasite/,""),t.pathname=t.pathname.replace(/\.[^/]*$/,"").replace(/\/+$/,""),!t.pathname.startsWith("/en/")&&!t.pathname.startsWith("/fr/"))throw new Error(`Invalid path: "${t.pathname}" must start with /en/ or /fr/`);return t},n=async(t,e={})=>{t=new URL(t,a);const{headers:r={},...n}=e;let o;try{o=await fetch(t,{signal:AbortSignal.timeout(3e4),...n,headers:{"User-Agent":"canada-api/5.1.5",Accept:"*/*",...r}})}catch(e){throw e.url=t.toString(),e}if(!o.ok){const e=new Error(`${o.status} ${o.statusText}`);throw e.url=t.toString(),e}let s=await o.text();const c=o.headers.get("content-type")?.includes("application/json");if(c)try{s=JSON.parse(s)}catch(e){throw e.url=t.toString(),e}return{data:s,status:o.status,statusText:o.statusText,headers:Object.fromEntries(o.headers)}},o={Jan:"01",Feb:"02",Mar:"03",Apr:"04",May:"05",Jun:"06",Jul:"07",Aug:"08",Sep:"09",Oct:"10",Nov:"11",Dec:"12"};function s(t){if(/^\d{4}-\d{2}-\d{2}$/.test(t))return new Date(t).toISOString();let e=/^\w{3} (\w{3}) (\d{2}) (\d{4}) ([\d:]{8}) GMT([\-+]\d{4})$/.exec(t);return e?new Date(`${e[3]}-${o[e[1]]}-${e[2]}T${e[4]}${e[5]}`).toISOString():t}const c={normalize:r,request:n,children:async t=>{const e=r(t);e.pathname+=".sitemap.xml",e.searchParams.set("_",Date.now());const a=await n(e,{redirect:"error"});return a.data=[...a.data.matchAll(/<url>([\s\S]*?)<\/url>/g)].map(([,t])=>{const e=t.match(/<loc>([\s\S]*?)<\/loc>/)?.[1],a=t.match(/<lastmod>([\s\S]*?)<\/lastmod>/)?.[1];return{loc:e,lastmod:a}}).filter(t=>t.loc).map(t=>({path:r(t.loc).pathname,lastmod:t.lastmod?new Date(t.lastmod).toISOString():null})),a},content:async t=>{const e=r(t);return e.pathname+=".html",e.searchParams.set("_",Date.now()),n(e,{signal:AbortSignal.timeout(1e4),redirect:"error"})},meta:async t=>{const e=r(t);e.pathname+="/_jcr_content.json",e.searchParams.set("_",Date.now());const a=await n(e,{signal:AbortSignal.timeout(1e4),redirect:"error"});return a.data=(t=>{const e={};for(const[a,n]of Object.entries(t))a.endsWith("@TypeHint")||Array.isArray(n)&&0===n.length||("true"===n?e[a]=!0:"false"===n?e[a]=!1:"gcAltLanguagePeer"===a?(e[a]=n,e.peer=r(n).pathname):e[a]="string"==typeof n?s(n.trim()):n);return Object.keys(e).sort().reduce((t,a)=>(t[a]=e[a],t),{})})(a.data),a}};return e.default})());
|
package/package.json
CHANGED
|
@@ -1,47 +1,44 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "canada-api",
|
|
3
|
-
"version": "5.1.
|
|
4
|
-
"description": "Cross platform API to fetch data from canada.ca",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "src/index.js",
|
|
7
|
-
"browser": "dist/ca.js",
|
|
8
|
-
"exports": {
|
|
9
|
-
".": {
|
|
10
|
-
"browser": "./dist/ca.js",
|
|
11
|
-
"default": "./src/index.js"
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
|
-
"files": [
|
|
15
|
-
"src",
|
|
16
|
-
"dist"
|
|
17
|
-
],
|
|
18
|
-
"scripts": {
|
|
19
|
-
"test": "node --test tests/*.test.js",
|
|
20
|
-
"test:integration": "node --test tests/integration/*.js",
|
|
21
|
-
"build": "webpack",
|
|
22
|
-
"dev": "webpack --mode development"
|
|
23
|
-
},
|
|
24
|
-
"author": "National Defence",
|
|
25
|
-
"license": "MIT",
|
|
26
|
-
"engines": {
|
|
27
|
-
"node": ">=18"
|
|
28
|
-
},
|
|
29
|
-
"keywords": [
|
|
30
|
-
"canada",
|
|
31
|
-
"api",
|
|
32
|
-
"fetch"
|
|
33
|
-
],
|
|
34
|
-
"homepage": "https://github.com/dnd-mdn/canada-api#readme",
|
|
35
|
-
"bugs": "https://github.com/dnd-mdn/canada-api/issues",
|
|
36
|
-
"repository": {
|
|
37
|
-
"type": "git",
|
|
38
|
-
"url": "https://github.com/dnd-mdn/canada-api.git"
|
|
39
|
-
},
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
"webpack-cli": "^7.0.2"
|
|
46
|
-
}
|
|
47
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "canada-api",
|
|
3
|
+
"version": "5.1.5",
|
|
4
|
+
"description": "Cross platform API to fetch data from canada.ca",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"browser": "dist/ca.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"browser": "./dist/ca.js",
|
|
11
|
+
"default": "./src/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"src",
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"test": "node --test tests/*.test.js",
|
|
20
|
+
"test:integration": "node --test tests/integration/*.js",
|
|
21
|
+
"build": "webpack",
|
|
22
|
+
"dev": "webpack --mode development"
|
|
23
|
+
},
|
|
24
|
+
"author": "National Defence",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=18"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"canada",
|
|
31
|
+
"api",
|
|
32
|
+
"fetch"
|
|
33
|
+
],
|
|
34
|
+
"homepage": "https://github.com/dnd-mdn/canada-api#readme",
|
|
35
|
+
"bugs": "https://github.com/dnd-mdn/canada-api/issues",
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "https://github.com/dnd-mdn/canada-api.git"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"webpack": "^5.105.4",
|
|
42
|
+
"webpack-cli": "^7.0.2"
|
|
43
|
+
}
|
|
44
|
+
}
|
package/src/children.js
CHANGED
|
@@ -1,52 +1,49 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
*
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
*
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
target
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
export default children;
|
|
1
|
+
import normalize from "./normalize.js";
|
|
2
|
+
import request from "./request.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Represents a single URL entry from a sitemap
|
|
6
|
+
* @typedef {object} SitemapEntry
|
|
7
|
+
* @property {string} path - The normalized URL path (e.g., '/en/page')
|
|
8
|
+
* @property {string|null} lastmod - ISO 8601 timestamp or null if not present
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Parse XML sitemap data into structured URL entries
|
|
13
|
+
* @param {string} data - Raw XML sitemap content
|
|
14
|
+
* @returns {SitemapEntry[]} Array of sitemap entries with path and lastmod. Entries missing a `<loc>` element are skipped.
|
|
15
|
+
*/
|
|
16
|
+
export const parseSitemap = (xml) => {
|
|
17
|
+
return [...xml.matchAll(/<url>([\s\S]*?)<\/url>/g)]
|
|
18
|
+
.map(([, inner]) => {
|
|
19
|
+
const loc = inner.match(/<loc>([\s\S]*?)<\/loc>/)?.[1];
|
|
20
|
+
const lastmod = inner.match(/<lastmod>([\s\S]*?)<\/lastmod>/)?.[1];
|
|
21
|
+
return { loc, lastmod };
|
|
22
|
+
})
|
|
23
|
+
.filter(item => item.loc)
|
|
24
|
+
.map(item => ({
|
|
25
|
+
path: normalize(item.loc).pathname,
|
|
26
|
+
lastmod: item.lastmod ? new Date(item.lastmod).toISOString() : null,
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Fetch and parse sitemap children for a canada.ca page
|
|
32
|
+
* @param {string|URL} url - Absolute or relative URL
|
|
33
|
+
* @returns {Promise<{data: SitemapEntry[], status: number, statusText: string, headers: object}>}
|
|
34
|
+
* @throws {Error} If the request fails or returns a non-2xx status
|
|
35
|
+
*/
|
|
36
|
+
const children = async (url) => {
|
|
37
|
+
const target = normalize(url);
|
|
38
|
+
target.pathname += '.sitemap.xml';
|
|
39
|
+
target.searchParams.set('_', Date.now());
|
|
40
|
+
|
|
41
|
+
const response = await request(target, {
|
|
42
|
+
redirect: 'error'
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
response.data = parseSitemap(response.data);
|
|
46
|
+
return response;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export default children;
|
package/src/config.js
CHANGED
package/src/content.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import normalize from "./normalize.js";
|
|
2
|
-
import request from "./request.js";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Fetch HTML content for a canada.ca page
|
|
6
|
-
* @param {string|URL} url - Absolute or relative URL
|
|
7
|
-
* @returns {Promise<{data: string, status: number, statusText: string, headers: object}>}
|
|
8
|
-
* @throws {Error} If the request fails or returns a non-2xx status
|
|
9
|
-
*/
|
|
10
|
-
const content = async (url) => {
|
|
11
|
-
const target = normalize(url);
|
|
12
|
-
target.pathname += '.html';
|
|
13
|
-
target.searchParams.set('_', Date.now());
|
|
14
|
-
|
|
15
|
-
return request(target, {
|
|
16
|
-
signal: AbortSignal.timeout(10000),
|
|
17
|
-
redirect: 'error'
|
|
18
|
-
});
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export default content;
|
|
1
|
+
import normalize from "./normalize.js";
|
|
2
|
+
import request from "./request.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Fetch HTML content for a canada.ca page
|
|
6
|
+
* @param {string|URL} url - Absolute or relative URL
|
|
7
|
+
* @returns {Promise<{data: string, status: number, statusText: string, headers: object}>}
|
|
8
|
+
* @throws {Error} If the request fails or returns a non-2xx status
|
|
9
|
+
*/
|
|
10
|
+
const content = async (url) => {
|
|
11
|
+
const target = normalize(url);
|
|
12
|
+
target.pathname += '.html';
|
|
13
|
+
target.searchParams.set('_', Date.now());
|
|
14
|
+
|
|
15
|
+
return request(target, {
|
|
16
|
+
signal: AbortSignal.timeout(10000),
|
|
17
|
+
redirect: 'error'
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export default content;
|
package/src/index.js
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import normalize from "./normalize.js";
|
|
2
|
-
import request from "./request.js";
|
|
3
|
-
import children from "./children.js";
|
|
4
|
-
import content from "./content.js";
|
|
5
|
-
import meta from "./meta.js";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @typedef {object} CanadaAPI
|
|
9
|
-
* @property {function} normalize - Normalize and validate canada.ca URLs
|
|
10
|
-
* @property {function} request - Raw HTTP client for canada.ca requests
|
|
11
|
-
* @property {function} children - Fetch and parse sitemap hierarchies
|
|
12
|
-
* @property {function} content - Fetch HTML content pages
|
|
13
|
-
* @property {function} meta - Fetch and format JCR metadata
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
/** @type {CanadaAPI} */
|
|
17
|
-
const ca = {
|
|
18
|
-
normalize,
|
|
19
|
-
request,
|
|
20
|
-
children,
|
|
21
|
-
content,
|
|
22
|
-
meta
|
|
23
|
-
}
|
|
24
|
-
|
|
1
|
+
import normalize from "./normalize.js";
|
|
2
|
+
import request from "./request.js";
|
|
3
|
+
import children from "./children.js";
|
|
4
|
+
import content from "./content.js";
|
|
5
|
+
import meta from "./meta.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {object} CanadaAPI
|
|
9
|
+
* @property {function} normalize - Normalize and validate canada.ca URLs
|
|
10
|
+
* @property {function} request - Raw HTTP client for canada.ca requests
|
|
11
|
+
* @property {function} children - Fetch and parse sitemap hierarchies
|
|
12
|
+
* @property {function} content - Fetch HTML content pages
|
|
13
|
+
* @property {function} meta - Fetch and format JCR metadata
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** @type {CanadaAPI} */
|
|
17
|
+
const ca = {
|
|
18
|
+
normalize,
|
|
19
|
+
request,
|
|
20
|
+
children,
|
|
21
|
+
content,
|
|
22
|
+
meta
|
|
23
|
+
}
|
|
24
|
+
|
|
25
25
|
export default ca
|
package/src/meta.js
CHANGED
|
@@ -1,103 +1,103 @@
|
|
|
1
|
-
import normalize from "./normalize.js";
|
|
2
|
-
import request from "./request.js";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Month name to number mapping
|
|
6
|
-
* @const {Record<string, string>}
|
|
7
|
-
* @private
|
|
8
|
-
*/
|
|
9
|
-
const months = {
|
|
10
|
-
'Jan': '01',
|
|
11
|
-
'Feb': '02',
|
|
12
|
-
'Mar': '03',
|
|
13
|
-
'Apr': '04',
|
|
14
|
-
'May': '05',
|
|
15
|
-
'Jun': '06',
|
|
16
|
-
'Jul': '07',
|
|
17
|
-
'Aug': '08',
|
|
18
|
-
'Sep': '09',
|
|
19
|
-
'Oct': '10',
|
|
20
|
-
'Nov': '11',
|
|
21
|
-
'Dec': '12'
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Try to parse and format date strings from JCR into ISO 8601
|
|
26
|
-
* @param {string} text - Potential date string to format
|
|
27
|
-
* @returns {string} ISO 8601 timestamp or original text if not a recognized date
|
|
28
|
-
* @description Supports YYYY-MM-DD and JCR date format (e.g. "Wed Nov 20 2019 13:17:13 GMT-0500").
|
|
29
|
-
* Uses explicit parsing to ensure consistent output across Node.js and browsers.
|
|
30
|
-
* @private
|
|
31
|
-
*/
|
|
32
|
-
function formatDate(text) {
|
|
33
|
-
// Simple YYYY-MM-DD format
|
|
34
|
-
if (/^\d{4}-\d{2}-\d{2}$/.test(text)) {
|
|
35
|
-
return new Date(text).toISOString()
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// RFC1123 format
|
|
39
|
-
let m = /^\w{3} (\w{3}) (\d{2}) (\d{4}) ([\d:]{8}) GMT([\-+]\d{4})$/.exec(text)
|
|
40
|
-
if (m) {
|
|
41
|
-
return new Date(`${m[3]}-${months[m[1]]}-${m[2]}T${m[4]}${m[5]}`).toISOString()
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return text
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Format and normalize metadata object
|
|
49
|
-
* @param {Record<string, any>} data - Raw metadata object from JCR
|
|
50
|
-
* @returns {Record<string, any>} Formatted metadata with normalized types and sorted keys
|
|
51
|
-
* @description Converts string booleans to native booleans, formats dates to ISO 8601,
|
|
52
|
-
* removes @TypeHint properties and empty arrays, sorts keys alphabetically, and adds a
|
|
53
|
-
* normalized `peer` field when `gcAltLanguagePeer` is present.
|
|
54
|
-
*/
|
|
55
|
-
export const formatMeta = (data) => {
|
|
56
|
-
const result = {}
|
|
57
|
-
|
|
58
|
-
for (const [key, value] of Object.entries(data)) {
|
|
59
|
-
if (key.endsWith('@TypeHint')) continue
|
|
60
|
-
if (Array.isArray(value) && value.length === 0) continue
|
|
61
|
-
|
|
62
|
-
if (value === 'true') {
|
|
63
|
-
result[key] = true
|
|
64
|
-
} else if (value === 'false') {
|
|
65
|
-
result[key] = false
|
|
66
|
-
} else if (key === 'gcAltLanguagePeer') {
|
|
67
|
-
result[key] = value
|
|
68
|
-
result['peer'] = normalize(value).pathname
|
|
69
|
-
} else if (typeof value === 'string') {
|
|
70
|
-
result[key] = formatDate(value.trim())
|
|
71
|
-
} else {
|
|
72
|
-
result[key] = value
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Sort object keys alphabetically for readability
|
|
77
|
-
return Object.keys(result).sort().reduce((obj, key) => {
|
|
78
|
-
obj[key] = result[key]
|
|
79
|
-
return obj
|
|
80
|
-
}, {})
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Fetch and format JCR metadata for a canada.ca page
|
|
85
|
-
* @param {string|URL} url - Absolute or relative URL
|
|
86
|
-
* @returns {Promise<{data: Record<string, any>, status: number, statusText: string, headers: object}>}
|
|
87
|
-
* @throws {Error} If the request fails or returns a non-2xx status
|
|
88
|
-
*/
|
|
89
|
-
const meta = async (url) => {
|
|
90
|
-
const target = normalize(url);
|
|
91
|
-
target.pathname += '/_jcr_content.json';
|
|
92
|
-
target.searchParams.set('_', Date.now());
|
|
93
|
-
|
|
94
|
-
const response = await request(target, {
|
|
95
|
-
signal: AbortSignal.timeout(10000),
|
|
96
|
-
redirect: 'error'
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
response.data = formatMeta(response.data);
|
|
100
|
-
return response;
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
export default meta;
|
|
1
|
+
import normalize from "./normalize.js";
|
|
2
|
+
import request from "./request.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Month name to number mapping
|
|
6
|
+
* @const {Record<string, string>}
|
|
7
|
+
* @private
|
|
8
|
+
*/
|
|
9
|
+
const months = {
|
|
10
|
+
'Jan': '01',
|
|
11
|
+
'Feb': '02',
|
|
12
|
+
'Mar': '03',
|
|
13
|
+
'Apr': '04',
|
|
14
|
+
'May': '05',
|
|
15
|
+
'Jun': '06',
|
|
16
|
+
'Jul': '07',
|
|
17
|
+
'Aug': '08',
|
|
18
|
+
'Sep': '09',
|
|
19
|
+
'Oct': '10',
|
|
20
|
+
'Nov': '11',
|
|
21
|
+
'Dec': '12'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Try to parse and format date strings from JCR into ISO 8601
|
|
26
|
+
* @param {string} text - Potential date string to format
|
|
27
|
+
* @returns {string} ISO 8601 timestamp or original text if not a recognized date
|
|
28
|
+
* @description Supports YYYY-MM-DD and JCR date format (e.g. "Wed Nov 20 2019 13:17:13 GMT-0500").
|
|
29
|
+
* Uses explicit parsing to ensure consistent output across Node.js and browsers.
|
|
30
|
+
* @private
|
|
31
|
+
*/
|
|
32
|
+
function formatDate(text) {
|
|
33
|
+
// Simple YYYY-MM-DD format
|
|
34
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(text)) {
|
|
35
|
+
return new Date(text).toISOString()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// RFC1123 format
|
|
39
|
+
let m = /^\w{3} (\w{3}) (\d{2}) (\d{4}) ([\d:]{8}) GMT([\-+]\d{4})$/.exec(text)
|
|
40
|
+
if (m) {
|
|
41
|
+
return new Date(`${m[3]}-${months[m[1]]}-${m[2]}T${m[4]}${m[5]}`).toISOString()
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return text
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Format and normalize metadata object
|
|
49
|
+
* @param {Record<string, any>} data - Raw metadata object from JCR
|
|
50
|
+
* @returns {Record<string, any>} Formatted metadata with normalized types and sorted keys
|
|
51
|
+
* @description Converts string booleans to native booleans, formats dates to ISO 8601,
|
|
52
|
+
* removes @TypeHint properties and empty arrays, sorts keys alphabetically, and adds a
|
|
53
|
+
* normalized `peer` field when `gcAltLanguagePeer` is present.
|
|
54
|
+
*/
|
|
55
|
+
export const formatMeta = (data) => {
|
|
56
|
+
const result = {}
|
|
57
|
+
|
|
58
|
+
for (const [key, value] of Object.entries(data)) {
|
|
59
|
+
if (key.endsWith('@TypeHint')) continue
|
|
60
|
+
if (Array.isArray(value) && value.length === 0) continue
|
|
61
|
+
|
|
62
|
+
if (value === 'true') {
|
|
63
|
+
result[key] = true
|
|
64
|
+
} else if (value === 'false') {
|
|
65
|
+
result[key] = false
|
|
66
|
+
} else if (key === 'gcAltLanguagePeer') {
|
|
67
|
+
result[key] = value
|
|
68
|
+
result['peer'] = normalize(value).pathname
|
|
69
|
+
} else if (typeof value === 'string') {
|
|
70
|
+
result[key] = formatDate(value.trim())
|
|
71
|
+
} else {
|
|
72
|
+
result[key] = value
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Sort object keys alphabetically for readability
|
|
77
|
+
return Object.keys(result).sort().reduce((obj, key) => {
|
|
78
|
+
obj[key] = result[key]
|
|
79
|
+
return obj
|
|
80
|
+
}, {})
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Fetch and format JCR metadata for a canada.ca page
|
|
85
|
+
* @param {string|URL} url - Absolute or relative URL
|
|
86
|
+
* @returns {Promise<{data: Record<string, any>, status: number, statusText: string, headers: object}>}
|
|
87
|
+
* @throws {Error} If the request fails or returns a non-2xx status
|
|
88
|
+
*/
|
|
89
|
+
const meta = async (url) => {
|
|
90
|
+
const target = normalize(url);
|
|
91
|
+
target.pathname += '/_jcr_content.json';
|
|
92
|
+
target.searchParams.set('_', Date.now());
|
|
93
|
+
|
|
94
|
+
const response = await request(target, {
|
|
95
|
+
signal: AbortSignal.timeout(10000),
|
|
96
|
+
redirect: 'error'
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
response.data = formatMeta(response.data);
|
|
100
|
+
return response;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export default meta;
|
package/src/normalize.js
CHANGED
|
@@ -1,39 +1,38 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
*
|
|
6
|
-
* @
|
|
7
|
-
* @
|
|
8
|
-
* @throws {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
1
|
+
import { BASE_URL } from './config.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Normalize a canada.ca URL to a clean pathname
|
|
5
|
+
* @param {string|URL} url - A full URL or relative path (e.g., 'https://www.canada.ca/en/page' or '/en/page')
|
|
6
|
+
* @returns {URL} Normalized URL object with cleaned pathname
|
|
7
|
+
* @throws {TypeError} If url is not a string or URL object
|
|
8
|
+
* @throws {Error} If URL is not from canada.ca or path doesn't start with /en/ or /fr/
|
|
9
|
+
*/
|
|
10
|
+
const normalize = (url) => {
|
|
11
|
+
|
|
12
|
+
if (typeof url === 'string') {
|
|
13
|
+
url = new URL(url, BASE_URL)
|
|
14
|
+
} else if (url instanceof URL) {
|
|
15
|
+
url = new URL(url.href)
|
|
16
|
+
} else {
|
|
17
|
+
throw new TypeError('string or URL object expected')
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Verify domain
|
|
21
|
+
if (url.origin !== BASE_URL) {
|
|
22
|
+
throw new Error('URL must start with ' + BASE_URL)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
url.pathname = url.pathname.replace(/^\/content\/canadasite/, '');
|
|
26
|
+
|
|
27
|
+
// Remove file extensions (like .html, .xml) and trailing slashes
|
|
28
|
+
url.pathname = url.pathname.replace(/\.[^/]*$/, '').replace(/\/+$/, '');
|
|
29
|
+
|
|
30
|
+
// Verify root language
|
|
31
|
+
if (!url.pathname.startsWith('/en/') && !url.pathname.startsWith('/fr/')) {
|
|
32
|
+
throw new Error(`Invalid path: "${url.pathname}" must start with /en/ or /fr/`)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return url
|
|
36
|
+
}
|
|
37
|
+
|
|
39
38
|
export default normalize;
|
package/src/request.js
CHANGED
|
@@ -1,40 +1,57 @@
|
|
|
1
|
-
import { BASE_URL } from "./config.js";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Raw HTTP client for canada.ca
|
|
5
|
-
* @param {string|URL} url - Relative or absolute URL on canada.ca
|
|
6
|
-
* @param {RequestInit} [options] - Fetch options
|
|
7
|
-
* @returns {Promise<{data: string|object, status: number, statusText: string, headers: object}>}
|
|
8
|
-
* @throws {Error} If the request fails or returns a non-2xx status
|
|
9
|
-
*/
|
|
10
|
-
const request = async (url, options = {}) => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
1
|
+
import { BASE_URL } from "./config.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Raw HTTP client for canada.ca
|
|
5
|
+
* @param {string|URL} url - Relative or absolute URL on canada.ca
|
|
6
|
+
* @param {RequestInit} [options] - Fetch options
|
|
7
|
+
* @returns {Promise<{data: string|object, status: number, statusText: string, headers: object}>}
|
|
8
|
+
* @throws {Error} If the request fails or returns a non-2xx status
|
|
9
|
+
*/
|
|
10
|
+
const request = async (url, options = {}) => {
|
|
11
|
+
url = new URL(url, BASE_URL);
|
|
12
|
+
|
|
13
|
+
const { headers: customHeaders = {}, ...requestOptions } = options;
|
|
14
|
+
|
|
15
|
+
let response;
|
|
16
|
+
try {
|
|
17
|
+
response = await fetch(url, {
|
|
18
|
+
signal: AbortSignal.timeout(30000),
|
|
19
|
+
...requestOptions,
|
|
20
|
+
headers: {
|
|
21
|
+
'User-Agent': 'canada-api/5.1.5',
|
|
22
|
+
'Accept': '*/*',
|
|
23
|
+
...customHeaders
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
} catch (e) {
|
|
27
|
+
e.url = url.toString();
|
|
28
|
+
throw e;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!response.ok) {
|
|
32
|
+
const error = new Error(`${response.status} ${response.statusText}`);
|
|
33
|
+
error.url = url.toString();
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let data = await response.text();
|
|
38
|
+
const isJson = response.headers.get('content-type')?.includes('application/json');
|
|
39
|
+
|
|
40
|
+
if (isJson) {
|
|
41
|
+
try {
|
|
42
|
+
data = JSON.parse(data);
|
|
43
|
+
} catch (e) {
|
|
44
|
+
e.url = url.toString();
|
|
45
|
+
throw e;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
data,
|
|
51
|
+
status: response.status,
|
|
52
|
+
statusText: response.statusText,
|
|
53
|
+
headers: Object.fromEntries(response.headers)
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export default request;
|