@architect/inventory 2.1.2 → 2.2.1-RC.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/changelog.md +27 -0
- package/package.json +12 -5
- package/readme.md +1 -1
- package/src/config/pragmas/http.js +3 -0
- package/src/config/pragmas/index.js +4 -1
- package/src/config/pragmas/indexes.js +6 -37
- package/src/config/pragmas/populate-lambda/{_streams.js → _tables-streams.js} +11 -5
- package/src/config/pragmas/populate-lambda/get-runtime.js +5 -0
- package/src/config/pragmas/populate-lambda/index.js +6 -4
- package/src/config/pragmas/sort/http.js +71 -0
- package/src/config/pragmas/tables-indexes.js +59 -0
- package/src/config/pragmas/{streams.js → tables-streams.js} +11 -11
- package/src/config/pragmas/validate/_http.js +1 -1
- package/src/config/pragmas/validate/_tables-streams.js +19 -0
- package/src/config/pragmas/validate/_tables.js +1 -1
- package/src/config/pragmas/validate/index.js +12 -12
- package/src/defaults/index.js +2 -1
- package/src/get.js +3 -2
- package/src/lib/http-methods.js +2 -0
- package/src/lib/pragmas.js +4 -3
- package/src/validate/config.js +3 -3
- package/src/validate/index.js +1 -2
- package/src/validate/tables-children.js +4 -4
- package/src/config/pragmas/validate/_streams.js +0 -19
package/changelog.md
CHANGED
|
@@ -2,6 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
+
## [2.2.1] 2021-11-22
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Adds HTTP route sorting, which should ensure Sandbox behaves much more like API Gateway despite how you've organized your `@http` pragma; fixes #977
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## [2.2.0] 2021-11-16
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- Finally formalized `@tables-streams`, the fully customizable successor to `@tables` with `stream true`
|
|
18
|
+
- Added `@tables-indexes` pragma
|
|
19
|
+
- `@tables-indexes` has identical semantics as (and will eventually supersede) `@indexes`
|
|
20
|
+
- Until Arc 10.0 + Inventory 3.0, consumers should now check both `inv.indexes` AND `inv.tables-indexes`
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## [2.1.3] 2021-11-04
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- Hardened runtime validation by ensuring non-string values will fail gracefully
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
5
32
|
## [2.1.2] 2021-10-28
|
|
6
33
|
|
|
7
34
|
### Added
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@architect/inventory",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.2.1-RC.0",
|
|
4
4
|
"description": "Architect project resource enumeration utility",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -23,21 +23,28 @@
|
|
|
23
23
|
"@architect/asap": "~4.1.0",
|
|
24
24
|
"@architect/parser": "~5.0.2",
|
|
25
25
|
"@architect/utils": "~3.0.4",
|
|
26
|
-
"lambda-runtimes": "~1.0
|
|
26
|
+
"lambda-runtimes": "~1.1.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@architect/eslint-config": "~2.0.1",
|
|
30
30
|
"aws-sdk": "2.880.0",
|
|
31
31
|
"aws-sdk-mock": "~5.4.0",
|
|
32
32
|
"cross-env": "~7.0.3",
|
|
33
|
-
"eslint": "~8.0
|
|
34
|
-
"mock-fs": "~5.1.
|
|
33
|
+
"eslint": "~8.2.0",
|
|
34
|
+
"mock-fs": "~5.1.2",
|
|
35
35
|
"mock-require": "~3.0.3",
|
|
36
36
|
"nyc": "~15.1.0",
|
|
37
37
|
"tap-spec": "^5.0.0",
|
|
38
|
-
"tape": "^5.3.
|
|
38
|
+
"tape": "^5.3.2"
|
|
39
39
|
},
|
|
40
40
|
"eslintConfig": {
|
|
41
41
|
"extends": "@architect/eslint-config"
|
|
42
|
+
},
|
|
43
|
+
"nyc": {
|
|
44
|
+
"check-coverage": true,
|
|
45
|
+
"branches": 100,
|
|
46
|
+
"lines": 100,
|
|
47
|
+
"functions": 100,
|
|
48
|
+
"statements": 100
|
|
42
49
|
}
|
|
43
50
|
}
|
package/readme.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
[<img src="https://
|
|
1
|
+
[<img src="https://assets.arc.codes/architect-logo-500b@2x.png" width=500>](https://www.npmjs.com/package/@architect/inventory)
|
|
2
2
|
|
|
3
3
|
## [`@architect/inventory`](https://www.npmjs.com/package/@architect/inventory)
|
|
4
4
|
|
|
@@ -2,6 +2,7 @@ let { join } = require('path')
|
|
|
2
2
|
let populate = require('./populate-lambda')
|
|
3
3
|
let asapSrc = require('../../lib/asap-src')
|
|
4
4
|
let validate = require('./validate')
|
|
5
|
+
let sort = require('./sort/http')
|
|
5
6
|
|
|
6
7
|
module.exports = function configureHTTP ({ arc, inventory, errors }) {
|
|
7
8
|
if (!arc.http) return null
|
|
@@ -67,7 +68,9 @@ module.exports = function configureHTTP ({ arc, inventory, errors }) {
|
|
|
67
68
|
// Impure but it's way less complicated to just do this
|
|
68
69
|
inventory._project.rootHandler = rootHandler
|
|
69
70
|
|
|
71
|
+
// Final steps: validate, then ensure the route order works as API Gateway would
|
|
70
72
|
validate.http(http, errors)
|
|
73
|
+
http = sort(http)
|
|
71
74
|
|
|
72
75
|
return http
|
|
73
76
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
let { all: allPragmas } = require('../../lib/pragmas')
|
|
2
2
|
|
|
3
3
|
// Get all pragmas except special cases
|
|
4
|
-
let isSpecial = p =>
|
|
4
|
+
let isSpecial = p => [ 'shared', 'views' ].includes(p)
|
|
5
5
|
let visitors = allPragmas.map(p => {
|
|
6
6
|
// eslint-disable-next-line
|
|
7
7
|
if (!isSpecial(p)) return require(`./${p}`)
|
|
@@ -21,6 +21,9 @@ module.exports = function configureArcPragmas ({ arc, inventory }, errors) {
|
|
|
21
21
|
visitors.forEach(visitor => {
|
|
22
22
|
// Expects pragma visitors to have function name of: `configure${pragma}`
|
|
23
23
|
let name = visitor.name.replace('configure', '').toLowerCase()
|
|
24
|
+
// Special cases for dasherization
|
|
25
|
+
if (name === 'tablesindexes') name = 'tables-indexes'
|
|
26
|
+
if (name === 'tablesstreams') name = 'tables-streams'
|
|
24
27
|
pragmas[name] = visitor({ arc, inventory, errors })
|
|
25
28
|
})
|
|
26
29
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
let is = require('../../lib/is')
|
|
2
1
|
let validate = require('./validate')
|
|
2
|
+
let { getIndexes } = require('./tables-indexes')
|
|
3
3
|
|
|
4
4
|
module.exports = function configureIndexes ({ arc, errors }) {
|
|
5
5
|
if (!arc.indexes || !arc.indexes.length) return null
|
|
@@ -7,43 +7,12 @@ module.exports = function configureIndexes ({ arc, errors }) {
|
|
|
7
7
|
errors.push(`Specifying @indexes requires specifying corresponding @tables`)
|
|
8
8
|
return null
|
|
9
9
|
}
|
|
10
|
+
if (arc['tables-indexes']?.length && arc.indexes?.length) {
|
|
11
|
+
errors.push(`Either @tables-indexes or @indexes can be specified, but not both`)
|
|
12
|
+
return null
|
|
13
|
+
}
|
|
10
14
|
|
|
11
|
-
let
|
|
12
|
-
function error (item) { errors.push(`Invalid @indexes item: ${item}`) }
|
|
13
|
-
|
|
14
|
-
let indexes = arc.indexes.map(index => {
|
|
15
|
-
if (is.object(index)) {
|
|
16
|
-
let name = Object.keys(index)[0]
|
|
17
|
-
let partitionKey = null
|
|
18
|
-
let partitionKeyType = null
|
|
19
|
-
let sortKey = null
|
|
20
|
-
let sortKeyType = null
|
|
21
|
-
let indexName = null
|
|
22
|
-
Object.entries(index[name]).forEach(([ key, value ]) => {
|
|
23
|
-
if (is.sortKey(value)) {
|
|
24
|
-
sortKey = key
|
|
25
|
-
sortKeyType = value.replace('**', '')
|
|
26
|
-
}
|
|
27
|
-
else if (is.primaryKey(value)) {
|
|
28
|
-
partitionKey = key
|
|
29
|
-
partitionKeyType = value.replace('*', '')
|
|
30
|
-
}
|
|
31
|
-
else if (isCustomName(key)) {
|
|
32
|
-
indexName = value
|
|
33
|
-
}
|
|
34
|
-
})
|
|
35
|
-
return {
|
|
36
|
-
indexName,
|
|
37
|
-
name,
|
|
38
|
-
partitionKey,
|
|
39
|
-
partitionKeyType,
|
|
40
|
-
sortKey,
|
|
41
|
-
sortKeyType,
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
error(index)
|
|
45
|
-
}).filter(Boolean) // Invalid indexes may create undefined entries in the map
|
|
46
|
-
|
|
15
|
+
let indexes = getIndexes(arc, 'indexes', errors)
|
|
47
16
|
validate.indexes(indexes, '@indexes', errors)
|
|
48
17
|
|
|
49
18
|
return indexes
|
|
@@ -2,23 +2,29 @@ let { join } = require('path')
|
|
|
2
2
|
let { existsSync } = require('fs')
|
|
3
3
|
let is = require('../../../lib/is')
|
|
4
4
|
|
|
5
|
-
module.exports = function
|
|
5
|
+
module.exports = function populateTablesStreams ({ type, item, dir, cwd, errors }) {
|
|
6
6
|
if (type === 'tables' && is.object(item)) {
|
|
7
7
|
let name = Object.keys(item)[0]
|
|
8
|
-
// Check for the legacy dir from before `@tables tablename stream true` generated
|
|
8
|
+
// Check for the legacy dir from before `@tables tablename stream true` generated a @tables-streams item
|
|
9
9
|
let legacySrc = join(cwd, dir, name)
|
|
10
10
|
let streamSrc = join(cwd, 'src', 'streams', name)
|
|
11
|
-
let
|
|
11
|
+
let tablesStreamsSrc = join(cwd, 'src', 'tables-streams', name)
|
|
12
|
+
|
|
13
|
+
let src
|
|
14
|
+
if (existsSync(legacySrc)) src = legacySrc
|
|
15
|
+
else if (existsSync(streamSrc)) src = streamSrc // TODO [remove] in 10.0
|
|
16
|
+
else src = tablesStreamsSrc
|
|
17
|
+
|
|
12
18
|
let table = name
|
|
13
19
|
return { name, src, table }
|
|
14
20
|
}
|
|
15
|
-
else if (type === 'streams' && is.string(item)) {
|
|
21
|
+
else if (type === 'tables-streams' && is.string(item)) {
|
|
16
22
|
let name = item
|
|
17
23
|
let src = join(cwd, dir, name)
|
|
18
24
|
let table = name
|
|
19
25
|
return { name, src, table }
|
|
20
26
|
}
|
|
21
|
-
else if (type === 'streams' && is.object(item)) {
|
|
27
|
+
else if (type === 'tables-streams' && is.object(item)) {
|
|
22
28
|
let name = Object.keys(item)[0]
|
|
23
29
|
let src = item[name].src
|
|
24
30
|
? join(cwd, item[name].src)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
let is = require('../../../lib/is')
|
|
1
2
|
let { aliases, runtimes, runtimeList } = require('lambda-runtimes')
|
|
2
3
|
|
|
3
4
|
// Runtime interpolater
|
|
@@ -18,5 +19,9 @@ module.exports = function getRuntime (config) {
|
|
|
18
19
|
config.runtimeAlias = runtime
|
|
19
20
|
}
|
|
20
21
|
}
|
|
22
|
+
else if (is.defined(runtime)) {
|
|
23
|
+
// Someone did something funky like specify a number or bool, so coerce and let it fail validation
|
|
24
|
+
config.runtime = `${config.runtime}`
|
|
25
|
+
}
|
|
21
26
|
return config
|
|
22
27
|
}
|
|
@@ -10,7 +10,7 @@ let getEvents = require('./_events')
|
|
|
10
10
|
let getPlugins = require('./_plugins')
|
|
11
11
|
let getScheduled = require('./_scheduled')
|
|
12
12
|
let getWS = require('./_websockets')
|
|
13
|
-
let
|
|
13
|
+
let getTablesStreams = require('./_tables-streams')
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Build out the Lambda tree
|
|
@@ -87,6 +87,8 @@ function populateLambda (type, pragma, inventory, errors) {
|
|
|
87
87
|
return lambdas
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
let ts = 'tables-streams'
|
|
91
|
+
|
|
90
92
|
function getLambda (params) {
|
|
91
93
|
let { type } = params
|
|
92
94
|
params.dir = `src/${type}/`
|
|
@@ -96,8 +98,8 @@ function getLambda (params) {
|
|
|
96
98
|
if (type === 'plugins') return getPlugins(params)
|
|
97
99
|
if (type === 'queues') return getEvents(params) // Effectively the same as events
|
|
98
100
|
if (type === 'scheduled') return getScheduled(params)
|
|
99
|
-
if (type ===
|
|
100
|
-
if (type === 'tables') return
|
|
101
|
+
if (type === ts) return getTablesStreams(params)
|
|
102
|
+
if (type === 'tables') return getTablesStreams(params) // Shortcut for creating streams
|
|
101
103
|
/* istanbul ignore else */ /* Clearer to be explicit here */
|
|
102
104
|
if (type === 'ws') return getWS(params)
|
|
103
105
|
}
|
|
@@ -108,7 +110,7 @@ module.exports = {
|
|
|
108
110
|
plugins: populateLambda.bind({}, 'plugins'),
|
|
109
111
|
queues: populateLambda.bind({}, 'queues'),
|
|
110
112
|
scheduled: populateLambda.bind({}, 'scheduled'),
|
|
111
|
-
streams: populateLambda.bind({}, 'streams'),
|
|
112
113
|
tables: populateLambda.bind({}, 'tables'),
|
|
114
|
+
[ts]: populateLambda.bind({}, ts),
|
|
113
115
|
ws: populateLambda.bind({}, 'ws'),
|
|
114
116
|
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
let methods = require('../../../lib/http-methods')
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* HTTP route sorter; this is a multifurcating tree, so we'll do a few passes
|
|
5
|
+
* Broadly in the theme of most to least specific:
|
|
6
|
+
* - First, by method, with `any` last
|
|
7
|
+
* - Then by path depth (descending)
|
|
8
|
+
* - Within each depth downrank for contained params
|
|
9
|
+
* - Then sort alphabetically
|
|
10
|
+
* - Then, ensure trailing captures are last
|
|
11
|
+
* - Finally, ensure root captures rank below a root literal
|
|
12
|
+
*/
|
|
13
|
+
module.exports = function sortHTTP (http) {
|
|
14
|
+
// Construct the tree from HTTP methods
|
|
15
|
+
let tree = {}
|
|
16
|
+
http.forEach(({ method, path }) => {
|
|
17
|
+
if (!tree[method]) tree[method] = []
|
|
18
|
+
let parts = path.split('/').filter(Boolean)
|
|
19
|
+
let depth = parts.length
|
|
20
|
+
let item = { depth, path }
|
|
21
|
+
let param = /\/:/
|
|
22
|
+
if (path.match(param)) {
|
|
23
|
+
item.hasParam = true
|
|
24
|
+
item.paramIndex = path.match(param).index // If multiple, we want the earliest
|
|
25
|
+
}
|
|
26
|
+
if (parts.length) {
|
|
27
|
+
if (parts[depth - 1] === '*') item.trailingCapture = 'catchall'
|
|
28
|
+
if (parts[depth - 1].startsWith(':')) item.trailingCapture = 'param'
|
|
29
|
+
}
|
|
30
|
+
tree[method].push(item)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
// Multi-pass route sort
|
|
34
|
+
let sorted = []
|
|
35
|
+
methods.forEach(method => {
|
|
36
|
+
if (!tree[method]) return
|
|
37
|
+
/* istanbul ignore next: random test shuffles may not trigger all paths */
|
|
38
|
+
tree[method]
|
|
39
|
+
// Sort by depth
|
|
40
|
+
.sort((a, b) => b.depth - a.depth)
|
|
41
|
+
// Sort within a given depth
|
|
42
|
+
.sort((a, b) => {
|
|
43
|
+
// Handle root (depth: 0)
|
|
44
|
+
if (a.depth - b.depth < 0) return
|
|
45
|
+
if (a.hasParam && b.hasParam) {
|
|
46
|
+
// Sort at the earliest param
|
|
47
|
+
if (a.paramIndex < b.paramIndex) return 1
|
|
48
|
+
if (a.paramIndex > b.paramIndex) return -1
|
|
49
|
+
// Then sort alphabetically
|
|
50
|
+
if (a.path < b.path) return -1
|
|
51
|
+
if (a.path > b.path) return 1
|
|
52
|
+
}
|
|
53
|
+
if (a.hasParam) return 1
|
|
54
|
+
if (b.hasParam) return -1
|
|
55
|
+
if (a.path < b.path) return -1
|
|
56
|
+
if (a.path > b.path) return 1
|
|
57
|
+
})
|
|
58
|
+
.sort((a, b) => {
|
|
59
|
+
if (!a.depth && b.depth === 1 && b.trailingCapture) return -1
|
|
60
|
+
if (a.depth - b.depth < 0) return
|
|
61
|
+
if (a.trailingCapture) return 1
|
|
62
|
+
if (b.trailingCapture) return -1
|
|
63
|
+
})
|
|
64
|
+
tree[method].forEach(({ path }) => {
|
|
65
|
+
let route = http.find(i => i.method === method && i.path === path)
|
|
66
|
+
sorted.push(route)
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
return sorted
|
|
71
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
let is = require('../../lib/is')
|
|
2
|
+
let validate = require('./validate')
|
|
3
|
+
|
|
4
|
+
function configureTablesIndexes ({ arc, errors }) {
|
|
5
|
+
if (!arc['tables-indexes'] || !arc['tables-indexes'].length) return null
|
|
6
|
+
if (arc['tables-indexes'] && !arc.tables) {
|
|
7
|
+
errors.push(`Specifying @tables-indexes requires specifying corresponding @tables`)
|
|
8
|
+
return null
|
|
9
|
+
}
|
|
10
|
+
if (arc['tables-indexes']?.length && arc.indexes?.length) {
|
|
11
|
+
errors.push(`Either @tables-indexes or @indexes can be specified, but not both`)
|
|
12
|
+
return null
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let indexes = getIndexes(arc, 'tables-indexes', errors)
|
|
16
|
+
validate.indexes(indexes, '@tables-indexes', errors)
|
|
17
|
+
|
|
18
|
+
return indexes
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let getIndexes = (arc, pragma, errors) => {
|
|
22
|
+
let isCustomName = key => is.string(key) && key.toLowerCase() === 'name'
|
|
23
|
+
function error (item) { errors.push(`Invalid @${pragma} item: ${item}`) }
|
|
24
|
+
return arc[pragma].map(index => {
|
|
25
|
+
if (is.object(index)) {
|
|
26
|
+
let name = Object.keys(index)[0]
|
|
27
|
+
let partitionKey = null
|
|
28
|
+
let partitionKeyType = null
|
|
29
|
+
let sortKey = null
|
|
30
|
+
let sortKeyType = null
|
|
31
|
+
let indexName = null
|
|
32
|
+
Object.entries(index[name]).forEach(([ key, value ]) => {
|
|
33
|
+
if (is.sortKey(value)) {
|
|
34
|
+
sortKey = key
|
|
35
|
+
sortKeyType = value.replace('**', '')
|
|
36
|
+
}
|
|
37
|
+
else if (is.primaryKey(value)) {
|
|
38
|
+
partitionKey = key
|
|
39
|
+
partitionKeyType = value.replace('*', '')
|
|
40
|
+
}
|
|
41
|
+
else if (isCustomName(key)) {
|
|
42
|
+
indexName = value
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
return {
|
|
46
|
+
indexName,
|
|
47
|
+
name,
|
|
48
|
+
partitionKey,
|
|
49
|
+
partitionKeyType,
|
|
50
|
+
sortKey,
|
|
51
|
+
sortKeyType,
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
error(index)
|
|
55
|
+
}).filter(Boolean) // Invalid indexes may create undefined entries in the map
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
configureTablesIndexes.getIndexes = getIndexes
|
|
59
|
+
module.exports = configureTablesIndexes
|
|
@@ -3,15 +3,15 @@ let validate = require('./validate')
|
|
|
3
3
|
let is = require('../../lib/is')
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* `@streams`
|
|
6
|
+
* `@tables-streams`
|
|
7
7
|
* - Originally `@tables {tablename} stream true` created a lambda at src/tables/{tablename}
|
|
8
|
-
* - This was superseded by `@streams`; `@tables` remains for backwards compat and as a convenience for creating `@streams`
|
|
8
|
+
* - This was superseded by `@tables-streams`; `@tables` remains for backwards compat and as a convenience for creating `@tables-streams`
|
|
9
9
|
* - If a project has an existing `@tables` Lambda, we'll continue using that so long as the directory exists
|
|
10
10
|
*/
|
|
11
|
-
module.exports = function
|
|
12
|
-
if (!arc
|
|
13
|
-
if (arc
|
|
14
|
-
errors.push(`Specifying @streams requires specifying corresponding @tables`)
|
|
11
|
+
module.exports = function configureTablesStreams ({ arc, inventory, errors }) {
|
|
12
|
+
if (!arc['tables-streams'] && !arc.tables) return null
|
|
13
|
+
if (arc['tables-streams'] && !arc.tables) {
|
|
14
|
+
errors.push(`Specifying @tables-streams requires specifying corresponding @tables`)
|
|
15
15
|
return null
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -22,21 +22,21 @@ module.exports = function configureStreams ({ arc, inventory, errors }) {
|
|
|
22
22
|
}
|
|
23
23
|
else tables = null
|
|
24
24
|
|
|
25
|
-
// Populate @streams
|
|
26
|
-
let streams = populate
|
|
25
|
+
// Populate @tables-streams
|
|
26
|
+
let streams = populate['tables-streams'](arc['tables-streams'], inventory, errors)
|
|
27
27
|
|
|
28
28
|
if (tables && streams) {
|
|
29
29
|
let uniqueTables = tables.filter(t => !streams.some(s => s.table === t.table))
|
|
30
30
|
let merged = streams.concat(uniqueTables)
|
|
31
|
-
validate.
|
|
31
|
+
validate.tablesStreams(merged, errors)
|
|
32
32
|
return merged
|
|
33
33
|
}
|
|
34
34
|
else if (streams) {
|
|
35
|
-
validate.
|
|
35
|
+
validate.tablesStreams(streams, errors)
|
|
36
36
|
return streams
|
|
37
37
|
}
|
|
38
38
|
else if (tables) {
|
|
39
|
-
validate.
|
|
39
|
+
validate.tablesStreams(tables, errors)
|
|
40
40
|
return tables
|
|
41
41
|
}
|
|
42
42
|
return null
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
let { unique } = require('./_lib')
|
|
2
|
+
let methods = require('../../../lib/http-methods')
|
|
2
3
|
|
|
3
4
|
module.exports = function validateHTTP (http, errors) {
|
|
4
5
|
if (http.length) {
|
|
5
6
|
unique(http, '@http routes', errors)
|
|
6
7
|
|
|
7
|
-
let methods = [ 'get', 'post', 'put', 'patch', 'delete', 'options', 'head', 'any' ]
|
|
8
8
|
let validMethod = str => methods.includes(str.toLowerCase())
|
|
9
9
|
let validPath = str => str.match(/^\/[a-zA-Z0-9/\-:._\*]*$/)
|
|
10
10
|
http.forEach(route => {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
let { regex, size, unique } = require('./_lib')
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Validate @tables-streams (& @tables streams true)
|
|
5
|
+
*
|
|
6
|
+
* Where possible, attempts to follow DynamoDB validation
|
|
7
|
+
* See: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html
|
|
8
|
+
*/
|
|
9
|
+
module.exports = function validateTablesStreams (tablesStreams, errors) {
|
|
10
|
+
if (tablesStreams.length) {
|
|
11
|
+
unique(tablesStreams, '@tables-streams', errors)
|
|
12
|
+
|
|
13
|
+
tablesStreams.forEach(stream => {
|
|
14
|
+
let { name } = stream
|
|
15
|
+
size(name, 3, 255, '@tables-streams', errors)
|
|
16
|
+
regex(name, 'veryLooseName', '@tables-streams', errors)
|
|
17
|
+
})
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -47,7 +47,7 @@ module.exports = function validateTablesAndIndexes (pragma, pragmaName, errors)
|
|
|
47
47
|
}
|
|
48
48
|
})
|
|
49
49
|
if (foundDupe) {
|
|
50
|
-
let err = `Duplicate
|
|
50
|
+
let err = `Duplicate ${pragmaName} value: '${index.name}'`
|
|
51
51
|
if (!errors.includes(err)) errors.push(err)
|
|
52
52
|
}
|
|
53
53
|
})
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/* eslint-disable global-require */
|
|
2
2
|
module.exports = {
|
|
3
3
|
// Pragmas and project validation
|
|
4
|
-
aws:
|
|
5
|
-
events:
|
|
6
|
-
http:
|
|
7
|
-
indexes:
|
|
8
|
-
proxy:
|
|
9
|
-
tables:
|
|
10
|
-
queues:
|
|
11
|
-
scheduled:
|
|
12
|
-
shared:
|
|
13
|
-
|
|
14
|
-
websockets:
|
|
4
|
+
aws: require('./_aws'),
|
|
5
|
+
events: require('./_events'),
|
|
6
|
+
http: require('./_http'),
|
|
7
|
+
indexes: require('./_tables'), // Same ruleset as @tables (more or less)
|
|
8
|
+
proxy: require('./_proxy'),
|
|
9
|
+
tables: require('./_tables'),
|
|
10
|
+
queues: require('./_events'), // Same ruleset as @events
|
|
11
|
+
scheduled: require('./_scheduled'),
|
|
12
|
+
shared: require('./_shared'), // Also includes @views
|
|
13
|
+
tablesStreams: require('./_tables-streams'),
|
|
14
|
+
websockets: require('./_websockets'),
|
|
15
15
|
|
|
16
16
|
// Misc
|
|
17
|
-
validate:
|
|
17
|
+
validate: require('./_lib')
|
|
18
18
|
}
|
package/src/defaults/index.js
CHANGED
|
@@ -60,8 +60,9 @@ module.exports = function inventoryDefaults (params = {}) {
|
|
|
60
60
|
scheduled: null,
|
|
61
61
|
shared: null,
|
|
62
62
|
static: null,
|
|
63
|
-
streams: null,
|
|
64
63
|
tables: null,
|
|
64
|
+
'tables-indexes': null,
|
|
65
|
+
'tables-streams': null,
|
|
65
66
|
views: null,
|
|
66
67
|
ws: null,
|
|
67
68
|
// Collection of all Lambda paths
|
package/src/get.js
CHANGED
|
@@ -8,7 +8,7 @@ module.exports = function _get (inventory) {
|
|
|
8
8
|
if (pragma === null) return null
|
|
9
9
|
if (is.array(pragma)) {
|
|
10
10
|
// Handle arrays of named entities or string values
|
|
11
|
-
let finder = i => i
|
|
11
|
+
let finder = i => i?.name === name || i === name
|
|
12
12
|
if (multipleResults.includes(prag)) {
|
|
13
13
|
let results = pragma.filter(finder)
|
|
14
14
|
return results.length ? results : undefined
|
|
@@ -37,5 +37,6 @@ module.exports = function _get (inventory) {
|
|
|
37
37
|
// Everything is uniquely named except in certain special-case pragmas
|
|
38
38
|
// These refer to other pragmas, and thus may allow multiple same/same-named entities
|
|
39
39
|
let multipleResults = [
|
|
40
|
-
'indexes'
|
|
40
|
+
'tables-indexes',
|
|
41
|
+
'indexes',
|
|
41
42
|
]
|
package/src/lib/pragmas.js
CHANGED
|
@@ -6,7 +6,7 @@ module.exports = {
|
|
|
6
6
|
'cdn',
|
|
7
7
|
'events',
|
|
8
8
|
'http',
|
|
9
|
-
'indexes',
|
|
9
|
+
'indexes', // -> transitioning to @tables-indexes
|
|
10
10
|
'macros',
|
|
11
11
|
'plugins',
|
|
12
12
|
'proxy',
|
|
@@ -14,8 +14,9 @@ module.exports = {
|
|
|
14
14
|
'scheduled',
|
|
15
15
|
'shared',
|
|
16
16
|
'static',
|
|
17
|
-
'streams',
|
|
18
17
|
'tables',
|
|
18
|
+
'tables-indexes',
|
|
19
|
+
'tables-streams',
|
|
19
20
|
'views',
|
|
20
21
|
'ws',
|
|
21
22
|
],
|
|
@@ -26,7 +27,7 @@ module.exports = {
|
|
|
26
27
|
'plugins',
|
|
27
28
|
'queues',
|
|
28
29
|
'scheduled',
|
|
29
|
-
'streams',
|
|
30
|
+
'tables-streams',
|
|
30
31
|
'ws',
|
|
31
32
|
],
|
|
32
33
|
}
|
package/src/validate/config.js
CHANGED
|
@@ -17,9 +17,9 @@ module.exports = function configValidator (params, inventory, errors) {
|
|
|
17
17
|
errors.push(invalidMemoryMsg(`${globalMemory} MB (@aws)`))
|
|
18
18
|
}
|
|
19
19
|
// Runtime
|
|
20
|
-
if (globalRuntime &&
|
|
21
|
-
!allRuntimes.includes(globalRuntime) &&
|
|
22
|
-
|
|
20
|
+
if ((globalRuntime && !is.string(globalRuntime)) ||
|
|
21
|
+
(globalRuntime && !allRuntimes.includes(globalRuntime) &&
|
|
22
|
+
!aliases[globalRuntime] && !aliases[globalRuntime.toLowerCase()])) {
|
|
23
23
|
errors.push(`Invalid project-level runtime: ${globalRuntime}`)
|
|
24
24
|
}
|
|
25
25
|
// Timeout
|
package/src/validate/index.js
CHANGED
|
@@ -31,8 +31,7 @@ module.exports = function finalValidation (params, inventory) {
|
|
|
31
31
|
/**
|
|
32
32
|
* Deal with project validation errors
|
|
33
33
|
*/
|
|
34
|
-
|
|
35
|
-
// Ensure @tables children (@streams, @indexes) have parent tables present
|
|
34
|
+
// Ensure @tables children (@tables-streams, @indexes) have parent tables present
|
|
36
35
|
tablesChildren(inventory, errors)
|
|
37
36
|
|
|
38
37
|
if (errors.length) {
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Ensure @tables children (@streams, @indexes) have parent tables present
|
|
2
|
+
* Ensure @tables children (@tables-streams, @indexes) have parent tables present
|
|
3
3
|
* - If not, configuration is invalid
|
|
4
4
|
*/
|
|
5
5
|
module.exports = function validateTablesChildren (inventory, errors) {
|
|
6
|
-
let { indexes, streams, tables } = inventory
|
|
6
|
+
let { indexes, 'tables-streams': tablesStreams, tables } = inventory
|
|
7
7
|
|
|
8
8
|
function check (table, type) {
|
|
9
9
|
if (!tables.some(t => t.name === table)) {
|
|
10
10
|
errors.push(`@${type} ${table} missing corresponding table`)
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
|
-
if (
|
|
14
|
-
|
|
13
|
+
if (tablesStreams) {
|
|
14
|
+
tablesStreams.forEach(stream => check(stream.table, 'tables-streams'))
|
|
15
15
|
}
|
|
16
16
|
if (indexes) {
|
|
17
17
|
indexes.forEach(index => check(index.name, 'indexes'))
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
let { regex, size, unique } = require('./_lib')
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Validate @streams (& @tables streams true)
|
|
5
|
-
*
|
|
6
|
-
* Where possible, attempts to follow DynamoDB validation
|
|
7
|
-
* See: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html
|
|
8
|
-
*/
|
|
9
|
-
module.exports = function validateStreams (streams, errors) {
|
|
10
|
-
if (streams.length) {
|
|
11
|
-
unique(streams, '@streams', errors)
|
|
12
|
-
|
|
13
|
-
streams.forEach(stream => {
|
|
14
|
-
let { name } = stream
|
|
15
|
-
size(name, 3, 255, '@streams', errors)
|
|
16
|
-
regex(name, 'veryLooseName', '@streams', errors)
|
|
17
|
-
})
|
|
18
|
-
}
|
|
19
|
-
}
|