@architect/inventory 2.1.3 → 2.2.1
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 +20 -0
- package/package.json +5 -5
- 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/index.js +7 -5
- package/src/config/pragmas/sort/http.js +72 -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 +2 -2
- 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/config/project/index.js +2 -2
- package/src/config/project/prefs.js +5 -5
- package/src/defaults/index.js +2 -1
- package/src/env/index.js +1 -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/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,26 @@
|
|
|
2
2
|
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
+
## [2.2.1] 2021-11-22
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Fixed HTTP route sorting; however you've organized your `@http` pragma, Sandbox should now behave much more like API Gateway; fixes #977
|
|
10
|
+
- Fixed overly strict path parameter validation; allow `_`, `.`, `-`; thanks @jkarsrud!
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## [2.2.0] 2021-11-16
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- Finally formalized `@tables-streams`, the fully customizable successor to `@tables` with `stream true`
|
|
19
|
+
- Added `@tables-indexes` pragma
|
|
20
|
+
- `@tables-indexes` has identical semantics as (and will eventually supersede) `@indexes`
|
|
21
|
+
- Until Arc 10.0 + Inventory 3.0, consumers should now check both `inv.indexes` AND `inv.tables-indexes`
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
5
25
|
## [2.1.3] 2021-11-04
|
|
6
26
|
|
|
7
27
|
### Fixed
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@architect/inventory",
|
|
3
|
-
"version": "2.1
|
|
3
|
+
"version": "2.2.1",
|
|
4
4
|
"description": "Architect project resource enumeration utility",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -23,19 +23,19 @@
|
|
|
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"
|
|
@@ -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)
|
|
@@ -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,9 +98,9 @@ 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
|
-
/* istanbul ignore else
|
|
101
|
+
if (type === ts) return getTablesStreams(params)
|
|
102
|
+
if (type === 'tables') return getTablesStreams(params) // Shortcut for creating streams
|
|
103
|
+
/* istanbul ignore else: clearer to be explicit here */
|
|
102
104
|
if (type === 'ws') return getWS(params)
|
|
103
105
|
}
|
|
104
106
|
|
|
@@ -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,72 @@
|
|
|
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
|
+
// Trailing capture sort
|
|
59
|
+
.sort((a, b) => {
|
|
60
|
+
if (!a.depth && b.depth === 1 && b.trailingCapture) return -1
|
|
61
|
+
if (a.depth - b.depth < 0) return
|
|
62
|
+
if (a.trailingCapture) return 1
|
|
63
|
+
if (b.trailingCapture) return -1
|
|
64
|
+
})
|
|
65
|
+
tree[method].forEach(({ path }) => {
|
|
66
|
+
let route = http.find(i => i.method === method && i.path === path)
|
|
67
|
+
sorted.push(route)
|
|
68
|
+
})
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
return sorted
|
|
72
|
+
}
|
|
@@ -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 => {
|
|
@@ -49,7 +49,7 @@ module.exports = function validateHTTP (http, errors) {
|
|
|
49
49
|
let params = path.match(/\/:/g)
|
|
50
50
|
if (params) {
|
|
51
51
|
// Params cannot have non-alphanumeric characters
|
|
52
|
-
let match = path.match(/\/:[
|
|
52
|
+
let match = path.match(/\/:[\w.-]+(\/|$)/g)
|
|
53
53
|
if (!match) errors.push(`Invalid @http path (parameters must have only alphanumeric characters): ${name}`)
|
|
54
54
|
}
|
|
55
55
|
|
|
@@ -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
|
}
|
|
@@ -36,7 +36,7 @@ module.exports = function getProjectConfig (params, errors) {
|
|
|
36
36
|
project[`${scope}PreferencesFile`] = p.preferencesFile
|
|
37
37
|
|
|
38
38
|
// Build out the final preferences
|
|
39
|
-
/* istanbul ignore else */
|
|
39
|
+
/* istanbul ignore else: jic */
|
|
40
40
|
if (!project.preferences) project.preferences = {}
|
|
41
41
|
Object.keys(p.preferences).forEach(pragma => {
|
|
42
42
|
// Ignore the raw data
|
|
@@ -47,7 +47,7 @@ module.exports = function getProjectConfig (params, errors) {
|
|
|
47
47
|
return
|
|
48
48
|
}
|
|
49
49
|
// Traverse and merge individual settings
|
|
50
|
-
/* istanbul ignore else */
|
|
50
|
+
/* istanbul ignore else: jic */
|
|
51
51
|
if (!project.preferences[pragma]) project.preferences[pragma] = {}
|
|
52
52
|
Object.entries(p.preferences[pragma]).forEach(([ setting, value ]) => {
|
|
53
53
|
project.preferences[pragma][setting] = value
|
|
@@ -18,13 +18,13 @@ module.exports = function getPrefs ({ scope, inventory, errors }) {
|
|
|
18
18
|
Object.entries(prefs.arc).forEach(([ key, val ]) => {
|
|
19
19
|
// TODO add additional preferences checks and normalization
|
|
20
20
|
|
|
21
|
-
/* istanbul ignore else
|
|
21
|
+
/* istanbul ignore else: Parser should get this, but jic */
|
|
22
22
|
if (!preferences[key]) preferences[key] = {}
|
|
23
|
-
/* istanbul ignore else
|
|
23
|
+
/* istanbul ignore else: Parser should only produce arrays, but jic */
|
|
24
24
|
if (is.array(val)) {
|
|
25
25
|
val.forEach(v => {
|
|
26
26
|
if (is.array(v)) {
|
|
27
|
-
/* istanbul ignore if
|
|
27
|
+
/* istanbul ignore if: Single vals should be strings, but jic */
|
|
28
28
|
if (v.length === 1) preferences[key] = v[0]
|
|
29
29
|
if (v.length === 2) preferences[key][v[0]] = v[1]
|
|
30
30
|
if (v.length > 2) preferences[key][v[0]] = [ ...v.slice(1) ]
|
|
@@ -39,7 +39,7 @@ module.exports = function getPrefs ({ scope, inventory, errors }) {
|
|
|
39
39
|
// Turn env vars with spaces into strings
|
|
40
40
|
if (key === 'env') {
|
|
41
41
|
[ 'testing', 'staging', 'production' ].forEach(e => {
|
|
42
|
-
/* istanbul ignore else
|
|
42
|
+
/* istanbul ignore else: Yet another jic */
|
|
43
43
|
if (preferences.env[e]) {
|
|
44
44
|
Object.entries(preferences.env[e]).forEach(([ key, val ]) => {
|
|
45
45
|
if (is.array(val)) preferences.env[e][key] = val.join(' ')
|
|
@@ -51,7 +51,7 @@ module.exports = function getPrefs ({ scope, inventory, errors }) {
|
|
|
51
51
|
if (key === 'sandbox-startup') {
|
|
52
52
|
preferences[key] = val.map(v => {
|
|
53
53
|
if (is.string(v)) return v
|
|
54
|
-
/* istanbul ignore else
|
|
54
|
+
/* istanbul ignore else: Yet another jic */
|
|
55
55
|
if (is.array(v)) return v.join(' ')
|
|
56
56
|
})
|
|
57
57
|
}
|
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/env/index.js
CHANGED
|
@@ -45,7 +45,7 @@ module.exports = function env (params, inventory, callback) {
|
|
|
45
45
|
}
|
|
46
46
|
}))
|
|
47
47
|
// Check for more data and, if so, recurse
|
|
48
|
-
/* istanbul ignore if
|
|
48
|
+
/* istanbul ignore if: Sadly no way to easily mock this for testing */
|
|
49
49
|
if (data.NextToken) {
|
|
50
50
|
getSomeEnvVars(name, data.NextToken, callback)
|
|
51
51
|
}
|
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/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
|
-
}
|