canada-api 1.0.3 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -5
- package/package.json +36 -36
- package/src/index.mjs +38 -38
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ Cross platform API for fetching public data from [canada.ca](https://www.canada.
|
|
|
5
5
|
## Install
|
|
6
6
|
### Browsers
|
|
7
7
|
|
|
8
|
-
<script src="https://cdn.jsdelivr.net/npm/canada-api@1.0
|
|
8
|
+
<script src="https://cdn.jsdelivr.net/npm/canada-api@1.1.0"><script>
|
|
9
9
|
|
|
10
10
|
### Nodejs
|
|
11
11
|
|
|
@@ -31,7 +31,7 @@ Uses sitemaps to fetch an array of child nodes
|
|
|
31
31
|
ca.children("/en/department-national-defence/maple-leaf")
|
|
32
32
|
ca.children("/fr/ministere-defense-nationale/feuille-derable")
|
|
33
33
|
|
|
34
|
-
Returns: `Promise` Resolves:
|
|
34
|
+
Returns: `Promise` Resolves: node object with `children` property
|
|
35
35
|
|
|
36
36
|
Only for page nodes, other types return an error `Not Found`
|
|
37
37
|
|
|
@@ -42,7 +42,7 @@ Fetches metadata of a node
|
|
|
42
42
|
ca.meta("/en/department-national-defence/maple-leaf")
|
|
43
43
|
ca.meta("/content/dam/dnd-mdn/images/maple-leaf/ml-logo.jpg")
|
|
44
44
|
|
|
45
|
-
Returns: `Promise` Resolves:
|
|
45
|
+
Returns: `Promise` Resolves: node object with `meta` property
|
|
46
46
|
|
|
47
47
|
### ca.content(node)
|
|
48
48
|
|
|
@@ -51,7 +51,7 @@ Fetches content of a node, as text or json
|
|
|
51
51
|
ca.content("/en/department-national-defence/maple-leaf")
|
|
52
52
|
ca.content("/content/dam/dnd-mdn/documents/json/maple-en.json")
|
|
53
53
|
|
|
54
|
-
Returns: `Promise` Resolves:
|
|
54
|
+
Returns: `Promise` Resolves: node object with `content` property
|
|
55
55
|
|
|
56
56
|
## Arguments
|
|
57
57
|
|
|
@@ -62,7 +62,6 @@ All functions take a node argument which accepts a couple types
|
|
|
62
62
|
Valid path strings include:
|
|
63
63
|
|
|
64
64
|
en/department-national-defence
|
|
65
|
-
/en/department-national-defence/
|
|
66
65
|
/en/department-national-defence.html
|
|
67
66
|
/en/department-national-defence?param=ignored
|
|
68
67
|
|
package/package.json
CHANGED
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "canada-api",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "Cross platform API to fetch data from canada.ca",
|
|
5
|
-
"browser": "dist/ca.js",
|
|
6
|
-
"main": "src/index.mjs",
|
|
7
|
-
"scripts": {
|
|
8
|
-
"test": "echo \"Error: no test specified\" && exit 1",
|
|
9
|
-
"build": "webpack",
|
|
10
|
-
"dev": "webpack --mode development"
|
|
11
|
-
},
|
|
12
|
-
"repository": {
|
|
13
|
-
"type": "git",
|
|
14
|
-
"url": "https://github.com/bsoicher/canada-api.git"
|
|
15
|
-
},
|
|
16
|
-
"keywords": [
|
|
17
|
-
"canada",
|
|
18
|
-
"api",
|
|
19
|
-
"fetch"
|
|
20
|
-
],
|
|
21
|
-
"author": "Ben Soicher",
|
|
22
|
-
"license": "MIT",
|
|
23
|
-
"homepage": "https://github.com/bsoicher/canada-api#readme",
|
|
24
|
-
"bugs": "https://github.com/bsoicher/canada-api/issues",
|
|
25
|
-
"devDependencies": {
|
|
26
|
-
"webpack": "^5.72.0",
|
|
27
|
-
"webpack-cli": "^4.9.2"
|
|
28
|
-
},
|
|
29
|
-
"dependencies": {
|
|
30
|
-
"bottleneck": "^2.19.5",
|
|
31
|
-
"cross-fetch": "^3.1.5"
|
|
32
|
-
},
|
|
33
|
-
"engines": {
|
|
34
|
-
"node": ">= 10.0.0"
|
|
35
|
-
}
|
|
36
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "canada-api",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Cross platform API to fetch data from canada.ca",
|
|
5
|
+
"browser": "dist/ca.js",
|
|
6
|
+
"main": "src/index.mjs",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
9
|
+
"build": "webpack",
|
|
10
|
+
"dev": "webpack --mode development"
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/bsoicher/canada-api.git"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"canada",
|
|
18
|
+
"api",
|
|
19
|
+
"fetch"
|
|
20
|
+
],
|
|
21
|
+
"author": "Ben Soicher",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"homepage": "https://github.com/bsoicher/canada-api#readme",
|
|
24
|
+
"bugs": "https://github.com/bsoicher/canada-api/issues",
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"webpack": "^5.72.0",
|
|
27
|
+
"webpack-cli": "^4.9.2"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"bottleneck": "^2.19.5",
|
|
31
|
+
"cross-fetch": "^3.1.5"
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">= 10.0.0"
|
|
35
|
+
}
|
|
36
|
+
}
|
package/src/index.mjs
CHANGED
|
@@ -26,8 +26,12 @@ const months = {
|
|
|
26
26
|
* @param {string} date
|
|
27
27
|
* @returns {Date}
|
|
28
28
|
*/
|
|
29
|
-
function
|
|
30
|
-
|
|
29
|
+
function maybeParseDate(date) {
|
|
30
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(date)) {
|
|
31
|
+
return Date.parse(date)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
m = /^\w{3} (\w{3}) (\d{2}) (\d{4}) ([\d:]{8}) GMT([\-+]\d{4})$/.exec(date)
|
|
31
35
|
return m ? Date.parse(m[3] + '-' + months[m[1]] + '-' + m[2] + 'T' + m[4] + m[5]) : date
|
|
32
36
|
}
|
|
33
37
|
|
|
@@ -95,20 +99,17 @@ function normalizeNode(node) {
|
|
|
95
99
|
}
|
|
96
100
|
|
|
97
101
|
/**
|
|
98
|
-
* Verify
|
|
102
|
+
* Verify response properties
|
|
99
103
|
* @param {Response} response
|
|
100
|
-
* @throws {Error}
|
|
104
|
+
* @throws {Error} Bad response
|
|
101
105
|
* @returns {Response}
|
|
102
106
|
*/
|
|
103
107
|
function verifyResponse(response) {
|
|
104
108
|
if (!response.ok) {
|
|
105
|
-
// Bad http response
|
|
106
109
|
throw new Error(response.statusText)
|
|
107
110
|
} else if (!response.url.includes(domain)) {
|
|
108
|
-
// Redirected outside of domain
|
|
109
111
|
throw new Error('Redirect')
|
|
110
|
-
} else if (response.url.includes('/
|
|
111
|
-
// 404 document was loaded
|
|
112
|
+
} else if (response.url.includes('/404.html')) {
|
|
112
113
|
throw new Error('Not Found')
|
|
113
114
|
}
|
|
114
115
|
|
|
@@ -116,10 +117,9 @@ function verifyResponse(response) {
|
|
|
116
117
|
}
|
|
117
118
|
|
|
118
119
|
/**
|
|
119
|
-
* Get node children
|
|
120
|
-
* @param {string|Object} node
|
|
121
|
-
* @
|
|
122
|
-
* @returns {Object}
|
|
120
|
+
* Get node children from XML sitemap
|
|
121
|
+
* @param {string|Object} node
|
|
122
|
+
* @returns {Promise<Object>}
|
|
123
123
|
*/
|
|
124
124
|
export function children(node) {
|
|
125
125
|
node = normalizeNode(node)
|
|
@@ -127,21 +127,30 @@ export function children(node) {
|
|
|
127
127
|
return limiter.schedule(() => fetch(formatURL(node.path, '.sitemap.xml')))
|
|
128
128
|
.then(verifyResponse)
|
|
129
129
|
.then(response => response.text())
|
|
130
|
-
.then(xml =>
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
130
|
+
.then(xml => {
|
|
131
|
+
// Parse XML
|
|
132
|
+
node.children = xml.match(/<url>.*?<\/url>/g).map(url => {
|
|
133
|
+
let loc = url.match(/<loc>([^<]+)<\/loc>/)
|
|
134
|
+
let mod = url.match(/<lastmod>([^<]+)<\/lastmod>/)
|
|
135
|
+
return {
|
|
136
|
+
path: normalizePath(loc[1]),
|
|
137
|
+
lastmod: mod ? Date.parse(mod[1]) : null
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
// First entry may be the input node
|
|
142
|
+
if (node.children.length && node.children[0].path === node.path) {
|
|
143
|
+
node.lastmod = node.children.shift().lastmod
|
|
136
144
|
}
|
|
137
|
-
|
|
138
|
-
|
|
145
|
+
|
|
146
|
+
return node
|
|
147
|
+
})
|
|
139
148
|
}
|
|
140
149
|
|
|
141
150
|
/**
|
|
142
|
-
* Get node metadata
|
|
143
|
-
* @param {string|Object} node
|
|
144
|
-
* @returns {Object}
|
|
151
|
+
* Get node metadata from jcr content
|
|
152
|
+
* @param {string|Object} node
|
|
153
|
+
* @returns {Promise<Object>}
|
|
145
154
|
*/
|
|
146
155
|
export function meta(node) {
|
|
147
156
|
node = normalizeNode(node)
|
|
@@ -150,32 +159,28 @@ export function meta(node) {
|
|
|
150
159
|
.then(verifyResponse)
|
|
151
160
|
.then(response => response.json())
|
|
152
161
|
.then(meta => {
|
|
153
|
-
//
|
|
154
|
-
|
|
162
|
+
// Reformat some meta properties
|
|
163
|
+
Object.keys(meta).forEach(key => {
|
|
155
164
|
if (meta[key] === 'true') {
|
|
156
165
|
meta[key] = true
|
|
157
166
|
} else if (meta[key] === 'false') {
|
|
158
167
|
meta[key] = false
|
|
159
168
|
} else if (key.endsWith('@TypeHint')) {
|
|
160
169
|
delete meta[key]
|
|
161
|
-
} else if (typeof meta[key] === 'string'
|
|
162
|
-
meta[key] =
|
|
170
|
+
} else if (typeof meta[key] === 'string') {
|
|
171
|
+
meta[key] = maybeParseDate(meta[key])
|
|
163
172
|
}
|
|
164
|
-
}
|
|
173
|
+
})
|
|
165
174
|
|
|
166
175
|
node.meta = meta
|
|
167
176
|
return node
|
|
168
177
|
})
|
|
169
|
-
.catch(err => {
|
|
170
|
-
node.meta = err
|
|
171
|
-
return node
|
|
172
|
-
})
|
|
173
178
|
}
|
|
174
179
|
|
|
175
180
|
/**
|
|
176
181
|
* Get node content
|
|
177
182
|
* @param {string|Object} node
|
|
178
|
-
* @returns {Object}
|
|
183
|
+
* @returns {Promise<Object>}
|
|
179
184
|
*/
|
|
180
185
|
export function content(node) {
|
|
181
186
|
node = normalizeNode(node)
|
|
@@ -193,9 +198,4 @@ export function content(node) {
|
|
|
193
198
|
node.content = content
|
|
194
199
|
return node
|
|
195
200
|
})
|
|
196
|
-
.catch(err => {
|
|
197
|
-
node.content = err
|
|
198
|
-
return node
|
|
199
|
-
})
|
|
200
201
|
}
|
|
201
|
-
|