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.
Files changed (3) hide show
  1. package/README.md +4 -5
  2. package/package.json +36 -36
  3. 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.3"><script>
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: Array of objects with `path` properties
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: Object with `meta` property
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: Object with `content` property
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.3",
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 parseDate(date) {
30
- let m = /^\w{3} (\w{3}) (\d{2}) (\d{4}) ([\d:]{8}) GMT([\-+]\d{4})$/.exec(date)
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 if fetch succeeded
102
+ * Verify response properties
99
103
  * @param {Response} response
100
- * @throws {Error} Fetch failed to load as expected
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('/errors/404.html')) {
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 by parsing sitemaps
120
- * @param {string|Object} node
121
- * @param {array} list Node list to extend
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 => xml.match(/<url>.*?<\/url>/g).map(url => {
131
- let loc = url.match(/<loc>([^<]+)<\/loc>/)
132
- let mod = url.match(/<lastmod>([^<]+)<\/lastmod>/)
133
- return {
134
- path: normalizePath(loc[1]),
135
- lastmod: mod ? Date.parse(mod[1]) : null
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
- .catch(() => [])
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
- // Format properties
154
- for (var key in meta) {
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' && meta[key].length === 33) {
162
- meta[key] = parseDate(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
-