@architect/inventory 3.1.1 → 3.2.0-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 +21 -0
- package/package.json +1 -1
- package/src/config/pragmas/plugins.js +3 -3
- package/src/config/pragmas/populate-lambda/index.js +2 -1
- package/src/config/pragmas/populate-other/index.js +117 -0
- package/src/config/pragmas/proxy.js +34 -10
- package/src/config/pragmas/shared.js +24 -6
- package/src/config/pragmas/static.js +12 -2
- package/src/config/pragmas/tables-indexes.js +55 -35
- package/src/config/pragmas/tables.js +53 -37
- package/src/config/pragmas/validate/_shared.js +1 -1
- package/src/config/pragmas/validate/_tables.js +2 -1
- package/src/config/pragmas/views.js +27 -8
- package/src/lib/index.js +4 -0
- package/src/lib/is.js +28 -15
package/changelog.md
CHANGED
|
@@ -2,6 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
+
## [3.2.0] 2022-07-24
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added support for new setter plugin APIs, specifically: `@proxy`, `@shared`, `@static`, `@tables`, `@tables-indexes`, `@views`
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- `@tables` and `@tables-indexes` can now accept lower case key types (e.g. `*string` instead of `*String`)
|
|
15
|
+
- `@tables` and `@tables-indexes` can also accept `*` and `**` as a shortcut for string-type primary and sort keys
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- Fixed issue where Lambdas created by plugins that returned arrays did not have their `plugin` and `type` properties set
|
|
21
|
+
- Fixed issue where an absolute path in `@shared|views` `src` would incorrectly resolve
|
|
22
|
+
- Fixed issue where `@views` might incorrectly return a validation error when only HTTP setter plugins are used to define `@http` routes
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
5
26
|
## [3.1.1] 2022-05-09
|
|
6
27
|
|
|
7
28
|
### Changed
|
package/package.json
CHANGED
|
@@ -2,10 +2,10 @@ let { join } = require('path')
|
|
|
2
2
|
let { existsSync } = require('fs')
|
|
3
3
|
let { is, normalizeSrc, pragmas, tidyError, validationPatterns } = require('../../lib')
|
|
4
4
|
let { lambdas } = pragmas
|
|
5
|
-
let nonLambdaSetters = [ 'customLambdas', 'env', 'runtimes' ]
|
|
5
|
+
let nonLambdaSetters = [ 'customLambdas', 'env', 'proxy', 'runtimes', 'shared', 'static', 'views', 'tables', 'tables-indexes' ]
|
|
6
6
|
let setters = [ ...lambdas, ...nonLambdaSetters ]
|
|
7
7
|
let pluginMethods = [ 'deploy', 'sandbox' ] // TODO add more!
|
|
8
|
-
let reservedNames = [ '_methods'
|
|
8
|
+
let reservedNames = [ '_methods' ]
|
|
9
9
|
|
|
10
10
|
module.exports = function getPluginModules ({ arc, inventory, errors }) {
|
|
11
11
|
if (!arc?.plugins?.length && !arc?.macros?.length) return null
|
|
@@ -107,7 +107,7 @@ function getPath (cwd, srcDir, name) {
|
|
|
107
107
|
join(cwd, 'node_modules', name),
|
|
108
108
|
join(cwd, 'node_modules', `@${name}`),
|
|
109
109
|
]
|
|
110
|
-
if (existsSync(paths[0]))
|
|
110
|
+
/**/ if (existsSync(paths[0])) return paths[0]
|
|
111
111
|
else if (existsSync(paths[1])) return paths[1]
|
|
112
112
|
else if (existsSync(paths[2])) return paths[2]
|
|
113
113
|
else if (existsSync(paths[3])) return paths[3]
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
let { deepFrozenCopy } = require('@architect/utils')
|
|
2
|
+
let { is } = require('../../../lib')
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Build out resource pragmas (e.g. `@tables`) via plugins
|
|
6
|
+
* Returns an array of resources
|
|
7
|
+
*/
|
|
8
|
+
function resources (params) {
|
|
9
|
+
let { errors, template, plugins, inventory, type, valid } = params
|
|
10
|
+
if (plugins) {
|
|
11
|
+
let invCopy = deepFrozenCopy(inventory)
|
|
12
|
+
let pluginResults = plugins.flatMap(fn => {
|
|
13
|
+
try {
|
|
14
|
+
var result = fn({ arc: invCopy._project.arc, inventory: { inv: invCopy } })
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
err.message = `Setter plugin exception: plugin: ${fn.plugin}, method: set.${type}`
|
|
18
|
+
+ `\n` + err.message
|
|
19
|
+
throw err
|
|
20
|
+
}
|
|
21
|
+
if (!result ||
|
|
22
|
+
(!is.object(result) && !is.array(result)) ||
|
|
23
|
+
(is.array(result) && result.some(r => !is.object(r)))) {
|
|
24
|
+
errors.push(`Setter plugins must return a valid response: plugin: ${fn.plugin}, method: set.${type}`)
|
|
25
|
+
return []
|
|
26
|
+
}
|
|
27
|
+
if (is.array(result)) {
|
|
28
|
+
result.forEach((item, i) => {
|
|
29
|
+
item = populateTemplate(template, item)
|
|
30
|
+
item.plugin = fn.plugin
|
|
31
|
+
item.type = fn.type
|
|
32
|
+
result[i] = item
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
result = populateTemplate(template, result)
|
|
37
|
+
result.plugin = fn.plugin
|
|
38
|
+
result.type = fn.type
|
|
39
|
+
}
|
|
40
|
+
return result
|
|
41
|
+
})
|
|
42
|
+
// Validation pass
|
|
43
|
+
let validationErrors = []
|
|
44
|
+
pluginResults.forEach(item => {
|
|
45
|
+
let errors = validate(item, valid, type)
|
|
46
|
+
validationErrors.push(...errors)
|
|
47
|
+
})
|
|
48
|
+
if (validationErrors.length) {
|
|
49
|
+
errors = errors.push(...validationErrors)
|
|
50
|
+
return []
|
|
51
|
+
}
|
|
52
|
+
return pluginResults
|
|
53
|
+
}
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function populateTemplate (template, item) {
|
|
58
|
+
let newItem = JSON.parse(JSON.stringify(template))
|
|
59
|
+
Object.entries(item).forEach(([ setting, value ]) => {
|
|
60
|
+
if (is.defined(value)) newItem[setting] = value
|
|
61
|
+
})
|
|
62
|
+
return newItem
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function validate (item, valid, type) {
|
|
66
|
+
if (!valid) return []
|
|
67
|
+
return Object.entries(valid).map(([ setting, value ]) => {
|
|
68
|
+
if (!is[value](item[setting])) return `Invalid plugin-generated @${type} resource: ${setting}: ${item[setting]}`
|
|
69
|
+
}).filter(Boolean)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Build out settings pragmas (e.g. `@static`) via plugins
|
|
74
|
+
* Returns an object of settings
|
|
75
|
+
*/
|
|
76
|
+
function settings (params) {
|
|
77
|
+
let { errors, settings, plugins, inventory, type, valid } = params
|
|
78
|
+
if (plugins) {
|
|
79
|
+
let invCopy = deepFrozenCopy(inventory)
|
|
80
|
+
let pluginSettings = settings
|
|
81
|
+
let foundError = false
|
|
82
|
+
plugins.forEach(fn => {
|
|
83
|
+
try {
|
|
84
|
+
var result = fn({ arc: invCopy._project.arc, inventory: { inv: invCopy } })
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
err.message = `Setter plugin exception: plugin: ${fn.plugin}, method: set.${type}`
|
|
88
|
+
+ `\n` + err.message
|
|
89
|
+
throw err
|
|
90
|
+
}
|
|
91
|
+
if (!result || !is.object(result)) {
|
|
92
|
+
errors.push(`Setter plugins must return a valid response: plugin: ${fn.plugin}, method: set.${type}`)
|
|
93
|
+
foundError = true
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
Object.entries(result).forEach(([ setting, value ]) => {
|
|
97
|
+
if (is.defined(settings[setting]) && is.defined(value)) {
|
|
98
|
+
pluginSettings[setting] = value
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
})
|
|
103
|
+
if (foundError) return null
|
|
104
|
+
|
|
105
|
+
// Validation pass
|
|
106
|
+
let validationErrors = validate(pluginSettings, valid, type)
|
|
107
|
+
if (validationErrors.length) {
|
|
108
|
+
errors = errors.push(...validationErrors)
|
|
109
|
+
return null
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return pluginSettings
|
|
113
|
+
}
|
|
114
|
+
return settings
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
module.exports = { resources, settings }
|
|
@@ -1,19 +1,43 @@
|
|
|
1
|
+
let populate = require('./populate-other')
|
|
1
2
|
let validate = require('./validate')
|
|
2
3
|
|
|
3
|
-
module.exports = function configureProxy ({ arc, errors }) {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
module.exports = function configureProxy ({ arc, inventory, errors }) {
|
|
5
|
+
let proxySetters = inventory.plugins?._methods?.set?.proxy
|
|
6
|
+
let httpSetters = inventory.plugins?._methods?.set?.http
|
|
7
|
+
if ((arc.proxy || proxySetters) &&
|
|
8
|
+
(!arc.http && !httpSetters)) {
|
|
9
|
+
errors.push('Specifying @proxy requires specifying @http')
|
|
6
10
|
return null
|
|
7
11
|
}
|
|
8
|
-
if (!arc.proxy
|
|
12
|
+
if (!arc.proxy && !proxySetters) return null
|
|
9
13
|
|
|
10
|
-
let proxy = {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
let proxy = {
|
|
15
|
+
testing: null,
|
|
16
|
+
staging: null,
|
|
17
|
+
production: null,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
proxy = populate.settings({
|
|
21
|
+
errors,
|
|
22
|
+
settings: proxy,
|
|
23
|
+
plugins: proxySetters,
|
|
24
|
+
inventory,
|
|
25
|
+
type: 'proxy',
|
|
26
|
+
valid: {
|
|
27
|
+
testing: 'string',
|
|
28
|
+
staging: 'string',
|
|
29
|
+
production: 'string',
|
|
30
|
+
},
|
|
16
31
|
})
|
|
32
|
+
if (proxy === null) return null
|
|
33
|
+
|
|
34
|
+
if (arc?.proxy?.length) {
|
|
35
|
+
Object.keys(proxy).forEach(env => {
|
|
36
|
+
let setting = arc.proxy.find(s => (s[0] && s[0] === env) && s[1])
|
|
37
|
+
if (!setting) errors.push(`@proxy ${env} environment not found or invalid`)
|
|
38
|
+
else proxy[env] = setting[1]
|
|
39
|
+
})
|
|
40
|
+
}
|
|
17
41
|
|
|
18
42
|
validate.proxy(proxy, errors)
|
|
19
43
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
let { join } = require('path')
|
|
2
|
+
let populate = require('./populate-other')
|
|
2
3
|
let validate = require('./validate')
|
|
3
4
|
let { is, pragmas } = require('../../lib')
|
|
4
5
|
let lambdas = pragmas.lambdas.concat('customLambdas')
|
|
@@ -9,20 +10,34 @@ module.exports = function configureShared ({ arc, pragmas, inventory, errors })
|
|
|
9
10
|
let { cwd, src: projSrc } = inventory._project
|
|
10
11
|
let src = join(projSrc, 'shared')
|
|
11
12
|
let shared = {
|
|
12
|
-
src,
|
|
13
|
-
shared: []
|
|
13
|
+
src: null,
|
|
14
|
+
shared: []
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let foundSrcSetting = false
|
|
18
|
+
let pluginSrc = populate.settings({
|
|
19
|
+
errors,
|
|
20
|
+
settings: shared,
|
|
21
|
+
plugins: inventory.plugins?._methods?.set?.shared,
|
|
22
|
+
inventory,
|
|
23
|
+
type: 'shared',
|
|
24
|
+
valid: { src: 'string' },
|
|
25
|
+
})
|
|
26
|
+
// Shared setters only support src, and do not support specifying Lambdas
|
|
27
|
+
// Lambda paths have not yet been reified in Inventory
|
|
28
|
+
if (is.string(pluginSrc?.src)) {
|
|
29
|
+
shared.src = pluginSrc.src
|
|
30
|
+
foundSrcSetting = true
|
|
14
31
|
}
|
|
15
32
|
|
|
16
33
|
// First pass to get + check shared folder (if any)
|
|
17
|
-
let foundSrc = false
|
|
18
34
|
if (arc?.shared?.length) {
|
|
19
35
|
for (let share of arc.shared) {
|
|
20
36
|
if (is.array(share)) {
|
|
21
37
|
let key = share[0]?.toLowerCase()
|
|
22
38
|
if (key === 'src' && is.string(share[1])) {
|
|
23
39
|
shared.src = share[1]
|
|
24
|
-
|
|
25
|
-
validate.shared(shared.src, cwd, errors)
|
|
40
|
+
foundSrcSetting = true
|
|
26
41
|
continue
|
|
27
42
|
}
|
|
28
43
|
if (key === 'src' && !is.string(share[1])) {
|
|
@@ -32,11 +47,14 @@ module.exports = function configureShared ({ arc, pragmas, inventory, errors })
|
|
|
32
47
|
}
|
|
33
48
|
}
|
|
34
49
|
|
|
50
|
+
if (foundSrcSetting) validate.shared(shared.src, cwd, errors)
|
|
51
|
+
else shared.src = src
|
|
52
|
+
|
|
35
53
|
// Exit if configured shared folder doesn't exist
|
|
36
54
|
if (!is.exists(shared.src)) return null
|
|
37
55
|
|
|
38
56
|
// Proceeding from here resets all shared config, so make sure it's only if specific shared are specified
|
|
39
|
-
let some = arc.shared?.length && !(arc?.shared?.length === 1 &&
|
|
57
|
+
let some = arc.shared?.length && !(arc?.shared?.length === 1 && foundSrcSetting)
|
|
40
58
|
if (some) {
|
|
41
59
|
// Reset shared settings
|
|
42
60
|
for (let pragma of lambdas) {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
let populate = require('./populate-other')
|
|
1
2
|
let { asapSrc, is } = require('../../lib')
|
|
2
3
|
|
|
3
|
-
module.exports = function configureStatic ({ arc, inventory }) {
|
|
4
|
+
module.exports = function configureStatic ({ arc, inventory, errors }) {
|
|
5
|
+
let staticSetters = inventory.plugins?._methods?.set?.static
|
|
4
6
|
let httpSetters = inventory.plugins?._methods?.set?.http
|
|
5
7
|
|
|
6
8
|
// @static is inferred by @http
|
|
7
|
-
if (!arc.static && !arc.http && !httpSetters) return null
|
|
9
|
+
if (!arc.static && !staticSetters && !arc.http && !httpSetters) return null
|
|
8
10
|
|
|
9
11
|
let staticPragma = arc.static || []
|
|
10
12
|
let _static = {
|
|
@@ -24,6 +26,14 @@ module.exports = function configureStatic ({ arc, inventory }) {
|
|
|
24
26
|
if (isDisabled) return false
|
|
25
27
|
}
|
|
26
28
|
|
|
29
|
+
_static = populate.settings({
|
|
30
|
+
errors,
|
|
31
|
+
settings: _static,
|
|
32
|
+
plugins: staticSetters,
|
|
33
|
+
inventory,
|
|
34
|
+
type: 'static',
|
|
35
|
+
})
|
|
36
|
+
|
|
27
37
|
let settings = Object.entries(_static).map(([ setting ]) => setting)
|
|
28
38
|
for (let setting of staticPragma) {
|
|
29
39
|
let validSetting = key => settings.includes(key)
|
|
@@ -1,52 +1,72 @@
|
|
|
1
|
-
let
|
|
1
|
+
let populate = require('./populate-other')
|
|
2
|
+
let { is, capitalize } = require('../../lib')
|
|
2
3
|
let validate = require('./validate')
|
|
3
4
|
|
|
4
|
-
module.exports = function configureTablesIndexes ({ arc, errors }) {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
module.exports = function configureTablesIndexes ({ arc, inventory, errors }) {
|
|
6
|
+
let $indexes = 'tables-indexes' // It's quite long!
|
|
7
|
+
let indexesSetters = inventory.plugins?._methods?.set?.[$indexes]
|
|
8
|
+
let tablesSetters = inventory.plugins?._methods?.set?.tables
|
|
9
|
+
if ((!arc[$indexes] || !arc[$indexes].length) && !indexesSetters) return null
|
|
10
|
+
if ((arc[$indexes] || indexesSetters) &&
|
|
11
|
+
(!arc.tables && !tablesSetters)) {
|
|
7
12
|
errors.push(`Specifying @tables-indexes requires specifying corresponding @tables`)
|
|
8
13
|
return null
|
|
9
14
|
}
|
|
10
15
|
|
|
11
|
-
let
|
|
12
|
-
|
|
16
|
+
let indexTemplate = () => ({
|
|
17
|
+
name: undefined,
|
|
18
|
+
partitionKey: null,
|
|
19
|
+
partitionKeyType: null,
|
|
20
|
+
sortKey: null,
|
|
21
|
+
sortKeyType: null,
|
|
22
|
+
indexName: null,
|
|
23
|
+
})
|
|
13
24
|
|
|
14
|
-
|
|
15
|
-
|
|
25
|
+
let indexes = []
|
|
26
|
+
let plugins = populate.resources({
|
|
27
|
+
errors,
|
|
28
|
+
template: indexTemplate(),
|
|
29
|
+
plugins: indexesSetters,
|
|
30
|
+
inventory,
|
|
31
|
+
type: 'indexes',
|
|
32
|
+
valid: { name: 'string' }
|
|
33
|
+
})
|
|
34
|
+
if (plugins) indexes.push(...plugins)
|
|
16
35
|
|
|
17
|
-
let
|
|
18
|
-
let isCustomName = key => is.string(key) && key.toLowerCase() === 'name'
|
|
19
|
-
function error (item) { errors.push(`Invalid @${pragma} item: ${item}`) }
|
|
20
|
-
return arc[pragma].map(index => {
|
|
36
|
+
let userland = arc?.[$indexes]?.map(index => {
|
|
21
37
|
if (is.object(index)) {
|
|
22
|
-
let
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
let sortKey = null
|
|
26
|
-
let sortKeyType = null
|
|
27
|
-
let indexName = null
|
|
28
|
-
Object.entries(index[name]).forEach(([ key, value ]) => {
|
|
38
|
+
let i = indexTemplate()
|
|
39
|
+
i.name = Object.keys(index)[0]
|
|
40
|
+
Object.entries(index[i.name]).forEach(([ key, value ]) => {
|
|
29
41
|
if (is.sortKey(value)) {
|
|
30
|
-
sortKey = key
|
|
31
|
-
sortKeyType = value.replace('**', '')
|
|
42
|
+
i.sortKey = key
|
|
43
|
+
i.sortKeyType = value.replace('**', '').toLowerCase()
|
|
44
|
+
if (!i.sortKeyType) i.sortKeyType = 'string'
|
|
32
45
|
}
|
|
33
46
|
else if (is.primaryKey(value)) {
|
|
34
|
-
partitionKey = key
|
|
35
|
-
partitionKeyType = value.replace('*', '')
|
|
47
|
+
i.partitionKey = key
|
|
48
|
+
i.partitionKeyType = value.replace('*', '').toLowerCase()
|
|
49
|
+
if (!i.partitionKeyType) i.partitionKeyType = 'string'
|
|
36
50
|
}
|
|
37
|
-
else if (
|
|
38
|
-
indexName = value
|
|
51
|
+
else if (key?.toLowerCase() === 'name') {
|
|
52
|
+
i.indexName = value
|
|
39
53
|
}
|
|
40
54
|
})
|
|
41
|
-
return
|
|
42
|
-
indexName,
|
|
43
|
-
name,
|
|
44
|
-
partitionKey,
|
|
45
|
-
partitionKeyType,
|
|
46
|
-
sortKey,
|
|
47
|
-
sortKeyType,
|
|
48
|
-
}
|
|
55
|
+
return i
|
|
49
56
|
}
|
|
50
|
-
|
|
51
|
-
}).filter(Boolean) // Invalid indexes may create undefined entries in the map
|
|
57
|
+
errors.push(`Invalid @${$indexes} item: ${index}`)
|
|
58
|
+
}).filter(Boolean) // Invalid indexes or plugins may create undefined entries in the map
|
|
59
|
+
if (userland) indexes.push(...userland)
|
|
60
|
+
|
|
61
|
+
// Normalize key type casing
|
|
62
|
+
if (indexes.length) indexes = indexes.map(index => {
|
|
63
|
+
let { sortKeyType, partitionKeyType } = index
|
|
64
|
+
if (sortKeyType) index.sortKeyType = capitalize(index.sortKeyType)
|
|
65
|
+
if (partitionKeyType) index.partitionKeyType = capitalize(index.partitionKeyType)
|
|
66
|
+
return index
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
validate.tablesIndexes(indexes, '@tables-indexes', errors)
|
|
70
|
+
|
|
71
|
+
return indexes
|
|
52
72
|
}
|
|
@@ -1,54 +1,70 @@
|
|
|
1
|
-
let
|
|
1
|
+
let populate = require('./populate-other')
|
|
2
|
+
let { is, capitalize } = require('../../lib')
|
|
2
3
|
let validate = require('./validate')
|
|
3
4
|
|
|
4
|
-
module.exports = function configureTables ({ arc, errors }) {
|
|
5
|
-
|
|
5
|
+
module.exports = function configureTables ({ arc, inventory, errors }) {
|
|
6
|
+
let tablesSetters = inventory.plugins?._methods?.set?.tables
|
|
7
|
+
if ((!arc.tables || !arc.tables.length) && !tablesSetters) return null
|
|
6
8
|
|
|
7
9
|
let pitrLong = 'PointInTimeRecovery' // It's just so long
|
|
10
|
+
let tableTemplate = () => ({
|
|
11
|
+
name: undefined,
|
|
12
|
+
partitionKey: null,
|
|
13
|
+
partitionKeyType: null,
|
|
14
|
+
sortKey: null,
|
|
15
|
+
sortKeyType: null,
|
|
16
|
+
stream: null,
|
|
17
|
+
ttl: null,
|
|
18
|
+
encrypt: null,
|
|
19
|
+
pitr: null,
|
|
20
|
+
})
|
|
8
21
|
|
|
9
|
-
let tables =
|
|
22
|
+
let tables = []
|
|
23
|
+
let plugins = populate.resources({
|
|
24
|
+
errors,
|
|
25
|
+
template: tableTemplate(),
|
|
26
|
+
plugins: tablesSetters,
|
|
27
|
+
inventory,
|
|
28
|
+
type: 'tables',
|
|
29
|
+
valid: { name: 'string' }
|
|
30
|
+
})
|
|
31
|
+
if (plugins) tables.push(...plugins)
|
|
32
|
+
|
|
33
|
+
let userland = arc?.tables?.map(table => {
|
|
10
34
|
if (is.object(table)) {
|
|
11
|
-
let
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
let sortKey = null
|
|
15
|
-
let sortKeyType = null
|
|
16
|
-
let stream = null
|
|
17
|
-
let ttl = null
|
|
18
|
-
let encrypt = null
|
|
19
|
-
let pitr = null
|
|
20
|
-
let pitrOld // Old opt, remove in some future breaking change
|
|
21
|
-
Object.entries(table[name]).forEach(([ key, value ]) => {
|
|
35
|
+
let t = tableTemplate()
|
|
36
|
+
t.name = Object.keys(table)[0]
|
|
37
|
+
Object.entries(table[t.name]).forEach(([ key, value ]) => {
|
|
22
38
|
if (is.sortKey(value)) {
|
|
23
|
-
sortKey = key
|
|
24
|
-
sortKeyType = value.replace('**', '')
|
|
39
|
+
t.sortKey = key
|
|
40
|
+
t.sortKeyType = value.replace('**', '').toLowerCase()
|
|
41
|
+
if (!t.sortKeyType) t.sortKeyType = 'string'
|
|
25
42
|
}
|
|
26
43
|
else if (is.primaryKey(value)) {
|
|
27
|
-
partitionKey = key
|
|
28
|
-
partitionKeyType = value.replace('*', '')
|
|
44
|
+
t.partitionKey = key
|
|
45
|
+
t.partitionKeyType = value.replace('*', '').toLowerCase()
|
|
46
|
+
if (!t.partitionKeyType) t.partitionKeyType = 'string'
|
|
29
47
|
}
|
|
30
|
-
if (key === 'stream') stream = value
|
|
31
|
-
if (value === 'TTL') ttl = key
|
|
32
|
-
if (key === 'encrypt') encrypt = value
|
|
33
|
-
if (key === '
|
|
34
|
-
if (key ===
|
|
48
|
+
if (key === 'stream') t.stream = value
|
|
49
|
+
if (value === 'TTL') t.ttl = key
|
|
50
|
+
if (key === 'encrypt') t.encrypt = value
|
|
51
|
+
if (key === 'PITR') t.pitr = value
|
|
52
|
+
if (key === 'pitr') t.pitr = value
|
|
53
|
+
if (key === pitrLong) t.PointInTimeRecovery = value
|
|
35
54
|
})
|
|
36
|
-
let t = {
|
|
37
|
-
name,
|
|
38
|
-
partitionKey,
|
|
39
|
-
partitionKeyType,
|
|
40
|
-
sortKey,
|
|
41
|
-
sortKeyType,
|
|
42
|
-
stream,
|
|
43
|
-
ttl,
|
|
44
|
-
encrypt,
|
|
45
|
-
pitr,
|
|
46
|
-
}
|
|
47
|
-
if (pitrOld !== undefined) t.PointInTimeRecovery = pitrOld
|
|
48
55
|
return t
|
|
49
56
|
}
|
|
50
57
|
errors.push(`Invalid @tables item: ${table}`)
|
|
51
|
-
}).filter(Boolean) // Invalid tables may create undefined entries in the map
|
|
58
|
+
}).filter(Boolean) // Invalid tables or plugins may create undefined entries in the map
|
|
59
|
+
if (userland) tables.push(...userland)
|
|
60
|
+
|
|
61
|
+
// Normalize key type casing
|
|
62
|
+
if (tables.length) tables = tables.map(table => {
|
|
63
|
+
let { sortKeyType, partitionKeyType } = table
|
|
64
|
+
if (sortKeyType) table.sortKeyType = capitalize(table.sortKeyType)
|
|
65
|
+
if (partitionKeyType) table.partitionKeyType = capitalize(table.partitionKeyType)
|
|
66
|
+
return table
|
|
67
|
+
})
|
|
52
68
|
|
|
53
69
|
validate.tables(tables, '@tables', errors)
|
|
54
70
|
|
|
@@ -2,7 +2,7 @@ let { join, resolve, sep } = require('path')
|
|
|
2
2
|
let { is } = require('../../../lib')
|
|
3
3
|
|
|
4
4
|
module.exports = function validateShared (src, cwd, errors) {
|
|
5
|
-
let path = src && resolve(join(cwd, src))
|
|
5
|
+
let path = src && src.startsWith(cwd) ? src : resolve(join(cwd, src))
|
|
6
6
|
|
|
7
7
|
if (!is.exists(path)) errors.push(`Directory not found: ${src}`)
|
|
8
8
|
else if (!is.folder(path)) errors.push(`Must be a directory: ${src}`)
|
|
@@ -10,12 +10,13 @@ let { deepStrictEqual } = require('assert')
|
|
|
10
10
|
module.exports = function validateTablesAndIndexes (pragma, pragmaName, errors) {
|
|
11
11
|
if (pragma?.length) {
|
|
12
12
|
pragma.forEach(table => {
|
|
13
|
-
let { name, indexName, partitionKey, sortKey } = table
|
|
13
|
+
let { name, indexName, partitionKey, partitionKeyType, sortKey } = table
|
|
14
14
|
|
|
15
15
|
size(name, 3, 255, pragmaName, errors)
|
|
16
16
|
regex(name, 'veryLooseName', pragmaName, errors)
|
|
17
17
|
|
|
18
18
|
if (!partitionKey) errors.push(`Invalid ${pragmaName} item (partition key required): '${name}'`)
|
|
19
|
+
if (!partitionKeyType) errors.push(`Invalid ${pragmaName} item (partition key type required): '${name}'`)
|
|
19
20
|
if (indexName) {
|
|
20
21
|
size(indexName, 3, 255, pragmaName, errors)
|
|
21
22
|
regex(indexName, 'veryLooseName', pragmaName, errors)
|
|
@@ -1,31 +1,47 @@
|
|
|
1
1
|
let { join } = require('path')
|
|
2
|
+
let populate = require('./populate-other')
|
|
2
3
|
let validate = require('./validate')
|
|
3
4
|
let { is } = require('../../lib')
|
|
4
5
|
|
|
5
6
|
module.exports = function configureViews ({ arc, pragmas, inventory, errors }) {
|
|
6
|
-
|
|
7
|
+
let httpSetters = inventory.plugins?._methods?.set?.http
|
|
8
|
+
if (arc.views && (!arc.http && !httpSetters)) {
|
|
7
9
|
errors.push('@views requires @http')
|
|
8
10
|
return null
|
|
9
11
|
}
|
|
10
|
-
if (!arc.http) return null
|
|
12
|
+
if (!arc.http && !httpSetters) return null
|
|
11
13
|
|
|
12
14
|
let { cwd, src: projSrc } = inventory._project
|
|
13
15
|
let src = join(projSrc, 'views')
|
|
14
16
|
let views = {
|
|
15
|
-
src,
|
|
16
|
-
views: []
|
|
17
|
+
src: null,
|
|
18
|
+
views: []
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let foundSrcSetting = false
|
|
22
|
+
let pluginSrc = populate.settings({
|
|
23
|
+
errors,
|
|
24
|
+
settings: views,
|
|
25
|
+
plugins: inventory.plugins?._methods?.set?.views,
|
|
26
|
+
inventory,
|
|
27
|
+
type: 'views',
|
|
28
|
+
valid: { src: 'string' },
|
|
29
|
+
})
|
|
30
|
+
// Views setters only support src, and do not support specifying Lambdas
|
|
31
|
+
// Lambda paths have not yet been reified in Inventory
|
|
32
|
+
if (is.string(pluginSrc?.src)) {
|
|
33
|
+
views.src = pluginSrc.src
|
|
34
|
+
foundSrcSetting = true
|
|
17
35
|
}
|
|
18
36
|
|
|
19
37
|
// First pass to get + check views folder (if any)
|
|
20
|
-
let foundSrc = false
|
|
21
38
|
if (arc?.views?.length) {
|
|
22
39
|
for (let view of arc.views) {
|
|
23
40
|
if (is.array(view)) {
|
|
24
41
|
let key = view[0]?.toLowerCase()
|
|
25
42
|
if (key === 'src' && is.string(view[1])) {
|
|
26
43
|
views.src = view[1]
|
|
27
|
-
|
|
28
|
-
validate.shared(views.src, cwd, errors)
|
|
44
|
+
foundSrcSetting = true
|
|
29
45
|
continue
|
|
30
46
|
}
|
|
31
47
|
if (key === 'src' && !is.string(view[1])) {
|
|
@@ -35,11 +51,14 @@ module.exports = function configureViews ({ arc, pragmas, inventory, errors }) {
|
|
|
35
51
|
}
|
|
36
52
|
}
|
|
37
53
|
|
|
54
|
+
if (foundSrcSetting) validate.shared(views.src, cwd, errors)
|
|
55
|
+
else views.src = src
|
|
56
|
+
|
|
38
57
|
// Exit if default views folder doesn't exist
|
|
39
58
|
if (!is.exists(views.src)) return null
|
|
40
59
|
|
|
41
60
|
// Proceeding from here resets all views config, so make sure it's only if specific views are specified
|
|
42
|
-
let some = arc.views?.length && !(arc?.views?.length === 1 &&
|
|
61
|
+
let some = arc.views?.length && !(arc?.views?.length === 1 && foundSrcSetting)
|
|
43
62
|
if (some) {
|
|
44
63
|
// Reset views settings
|
|
45
64
|
for (let route of pragmas.http) {
|
package/src/lib/index.js
CHANGED
|
@@ -9,6 +9,9 @@ let pragmas = require('./pragmas')
|
|
|
9
9
|
* Why take up a whole fs block when smol libs can just live here?
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
// Capitalize a string (used to normalize table/index key types)
|
|
13
|
+
let capitalize = str => str[0].toUpperCase() + str.substr(1)
|
|
14
|
+
|
|
12
15
|
// For setting `lambda.build`, compiled + transpiled are effectively the same
|
|
13
16
|
let compiledRuntimes = [ 'compiled', 'transpiled' ]
|
|
14
17
|
|
|
@@ -29,6 +32,7 @@ let tidyError = err => err.message + `\n` + err.stack.split('\n').slice(1).join(
|
|
|
29
32
|
|
|
30
33
|
module.exports = {
|
|
31
34
|
asapSrc,
|
|
35
|
+
capitalize,
|
|
32
36
|
compiledRuntimes,
|
|
33
37
|
errorFmt,
|
|
34
38
|
getLambdaDirs,
|
package/src/lib/is.js
CHANGED
|
@@ -1,19 +1,32 @@
|
|
|
1
1
|
let { existsSync, lstatSync } = require('fs')
|
|
2
2
|
|
|
3
|
+
// Types
|
|
4
|
+
let array = item => Array.isArray(item)
|
|
5
|
+
let bool = item => typeof item === 'boolean'
|
|
6
|
+
let defined = item => typeof item !== 'undefined'
|
|
7
|
+
let fn = item => typeof item === 'function'
|
|
8
|
+
let nullish = item => typeof item === 'undefined' || item === null
|
|
9
|
+
let number = item => Number.isInteger(item)
|
|
10
|
+
let object = item => typeof item === 'object' && !Array.isArray(item)
|
|
11
|
+
let string = item => typeof item === 'string'
|
|
12
|
+
// Filesystem
|
|
13
|
+
let exists = path => existsSync(path)
|
|
14
|
+
let folder = path => existsSync(path) && lstatSync(path).isDirectory()
|
|
15
|
+
// Pragma-specific stuff
|
|
16
|
+
let primaryKey = val => string(val) && [ '*', '*string', '*number' ].includes(val.toLowerCase())
|
|
17
|
+
let sortKey = val => string(val) && [ '**', '**string', '**number' ].includes(val.toLowerCase())
|
|
18
|
+
|
|
3
19
|
module.exports = {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
// Pragma-specific stuff
|
|
17
|
-
primaryKey: val => typeof val === 'string' && (val.startsWith('*String') || val.startsWith('*Number')),
|
|
18
|
-
sortKey: val => typeof val === 'string' && (val.startsWith('**String') || val.startsWith('**Number')),
|
|
20
|
+
array,
|
|
21
|
+
bool,
|
|
22
|
+
defined,
|
|
23
|
+
fn,
|
|
24
|
+
nullish,
|
|
25
|
+
number,
|
|
26
|
+
object,
|
|
27
|
+
string,
|
|
28
|
+
exists,
|
|
29
|
+
folder,
|
|
30
|
+
primaryKey,
|
|
31
|
+
sortKey,
|
|
19
32
|
}
|