@architect/inventory 2.2.1-RC.0 → 3.0.0-RC.10

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 (71) hide show
  1. package/changelog.md +54 -1
  2. package/package.json +12 -10
  3. package/readme.md +5 -4
  4. package/src/config/_upsert.js +1 -1
  5. package/src/config/arc.js +3 -3
  6. package/src/config/pragmas/app.js +1 -1
  7. package/src/config/pragmas/events.js +3 -2
  8. package/src/config/pragmas/http.js +5 -4
  9. package/src/config/pragmas/index.js +16 -5
  10. package/src/config/pragmas/meta/custom-lambdas.js +10 -0
  11. package/src/config/pragmas/{src-dirs.js → meta/src-dirs.js} +13 -10
  12. package/src/config/pragmas/plugins.js +109 -4
  13. package/src/config/pragmas/populate-lambda/_custom-lambdas.js +10 -0
  14. package/src/config/pragmas/populate-lambda/_events.js +17 -11
  15. package/src/config/pragmas/populate-lambda/_http.js +18 -10
  16. package/src/config/pragmas/populate-lambda/_scheduled.js +18 -10
  17. package/src/config/pragmas/populate-lambda/_tables-streams.js +20 -23
  18. package/src/config/pragmas/populate-lambda/_ws.js +26 -0
  19. package/src/config/pragmas/populate-lambda/get-handler.js +86 -13
  20. package/src/config/pragmas/populate-lambda/get-lambda.js +23 -0
  21. package/src/config/pragmas/populate-lambda/get-runtime.js +8 -7
  22. package/src/config/pragmas/populate-lambda/index.js +134 -84
  23. package/src/config/pragmas/queues.js +3 -2
  24. package/src/config/pragmas/scheduled.js +3 -2
  25. package/src/config/pragmas/shared.js +41 -44
  26. package/src/config/pragmas/sort/http.js +3 -2
  27. package/src/config/pragmas/static.js +5 -4
  28. package/src/config/pragmas/tables-indexes.js +3 -10
  29. package/src/config/pragmas/tables-streams.js +7 -5
  30. package/src/config/pragmas/tables.js +1 -1
  31. package/src/config/pragmas/validate/_events.js +1 -1
  32. package/src/config/pragmas/validate/_http.js +4 -4
  33. package/src/config/pragmas/validate/_lib.js +3 -10
  34. package/src/config/pragmas/validate/_scheduled.js +2 -2
  35. package/src/config/pragmas/validate/_shared.js +1 -1
  36. package/src/config/pragmas/validate/_tables-streams.js +6 -8
  37. package/src/config/pragmas/validate/_tables.js +2 -2
  38. package/src/config/pragmas/validate/index.js +2 -2
  39. package/src/config/pragmas/views.js +39 -37
  40. package/src/config/pragmas/ws.js +6 -4
  41. package/src/config/project/index.js +36 -20
  42. package/src/config/project/plugins/env.js +71 -0
  43. package/src/config/project/plugins/index.js +7 -0
  44. package/src/config/project/plugins/runtimes.js +67 -0
  45. package/src/config/project/prefs/dotenv.js +81 -0
  46. package/src/config/project/{prefs.js → prefs/index.js} +41 -22
  47. package/src/config/project/validate/index.js +15 -8
  48. package/src/defaults/index.js +20 -13
  49. package/src/env/index.js +76 -61
  50. package/src/get.js +1 -2
  51. package/src/index.js +17 -15
  52. package/src/lib/asap-src.js +3 -3
  53. package/src/lib/error-fmt.js +2 -10
  54. package/src/lib/get-lambda-dirs.js +37 -0
  55. package/src/lib/index.js +42 -0
  56. package/src/lib/is.js +3 -1
  57. package/src/lib/merge-env-vars.js +32 -0
  58. package/src/lib/pragmas.js +19 -3
  59. package/src/read/index.js +1 -3
  60. package/src/read/reader.js +2 -2
  61. package/src/validate/config.js +12 -6
  62. package/src/validate/index.js +17 -18
  63. package/src/validate/layers.js +2 -2
  64. package/src/validate/paths.js +17 -0
  65. package/src/validate/tables-children.js +5 -5
  66. package/src/config/pragmas/indexes.js +0 -19
  67. package/src/config/pragmas/macros.js +0 -5
  68. package/src/config/pragmas/populate-lambda/_plugins.js +0 -25
  69. package/src/config/pragmas/populate-lambda/_websockets.js +0 -19
  70. package/src/config/project/plugins.js +0 -31
  71. package/src/lib/http-methods.js +0 -2
@@ -1,6 +1,7 @@
1
1
  let populate = require('./populate-lambda')
2
2
  let validate = require('./validate')
3
- let is = require('../../lib/is')
3
+ let { is } = require('../../lib')
4
+ let ts = 'tables-streams'
4
5
 
5
6
  /**
6
7
  * `@tables-streams`
@@ -9,8 +10,9 @@ let is = require('../../lib/is')
9
10
  * - If a project has an existing `@tables` Lambda, we'll continue using that so long as the directory exists
10
11
  */
11
12
  module.exports = function configureTablesStreams ({ arc, inventory, errors }) {
12
- if (!arc['tables-streams'] && !arc.tables) return null
13
- if (arc['tables-streams'] && !arc.tables) {
13
+ let tablesStreamsPlugins = inventory.plugins?._methods?.set?.[ts]
14
+ if (!arc[ts]?.length && !tablesStreamsPlugins?.length && !arc.tables?.length) return null
15
+ if ((arc[ts] || tablesStreamsPlugins) && !arc.tables) {
14
16
  errors.push(`Specifying @tables-streams requires specifying corresponding @tables`)
15
17
  return null
16
18
  }
@@ -18,12 +20,12 @@ module.exports = function configureTablesStreams ({ arc, inventory, errors }) {
18
20
  // Populate @tables
19
21
  let tables = arc.tables.filter(t => is.object(t) && t[Object.keys(t)[0]].stream === true)
20
22
  if (tables.length) {
21
- tables = populate.tables(tables, inventory, errors)
23
+ tables = populate.tables({ arc, inventory, errors, pragma: tables })
22
24
  }
23
25
  else tables = null
24
26
 
25
27
  // Populate @tables-streams
26
- let streams = populate['tables-streams'](arc['tables-streams'], inventory, errors)
28
+ let streams = populate[ts]({ arc, inventory, errors })
27
29
 
28
30
  if (tables && streams) {
29
31
  let uniqueTables = tables.filter(t => !streams.some(s => s.table === t.table))
@@ -1,4 +1,4 @@
1
- let is = require('../../lib/is')
1
+ let { is } = require('../../lib')
2
2
  let validate = require('./validate')
3
3
 
4
4
  module.exports = function configureTables ({ arc, errors }) {
@@ -8,7 +8,7 @@ let { regex, size, unique } = require('./_lib')
8
8
  * See: https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-message-metadata.html
9
9
  */
10
10
  module.exports = function validateEventsAndQueues (pragma, pragmaName, errors) {
11
- if (pragma.length) {
11
+ if (pragma?.length) {
12
12
  unique(pragma, pragmaName, errors)
13
13
 
14
14
  pragma.forEach(event => {
@@ -1,11 +1,11 @@
1
1
  let { unique } = require('./_lib')
2
- let methods = require('../../../lib/http-methods')
2
+ let { httpMethods } = require('../../../lib')
3
3
 
4
4
  module.exports = function validateHTTP (http, errors) {
5
- if (http.length) {
5
+ if (http?.length) {
6
6
  unique(http, '@http routes', errors)
7
7
 
8
- let validMethod = str => methods.includes(str.toLowerCase())
8
+ let validMethod = str => httpMethods.includes(str.toLowerCase())
9
9
  let validPath = str => str.match(/^\/[a-zA-Z0-9/\-:._\*]*$/)
10
10
  http.forEach(route => {
11
11
  let { name, method, path } = 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(/\/:[a-zA-Z0-9]+(\/|$)/g)
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
 
@@ -1,15 +1,8 @@
1
- let is = require('../../../lib/is')
2
-
3
- let patterns = {
4
- looseName: new RegExp(/^[a-z][a-zA-Z0-9-_]+$/),
5
- strictName: new RegExp(/^[a-z][a-z0-9-]+$/),
6
- // DynamoDB, SNS, SQS
7
- veryLooseName: new RegExp(/^[a-zA-Z0-9/\-._]*$/),
8
- }
1
+ let { is, validationPatterns } = require('../../../lib')
9
2
 
10
3
  function regex (value, pattern, pragmaName, errors) {
11
- if (!patterns[pattern]) throw ReferenceError(`Invalid validation pattern specified: ${pattern}`)
12
- if (!patterns[pattern].test(value)) errors.push(`Invalid ${pragmaName} item: '${value}' must match ${patterns[pattern]}`)
4
+ if (!validationPatterns[pattern]) throw ReferenceError(`Invalid validation pattern specified: ${pattern}`)
5
+ if (!validationPatterns[pattern].test(value)) errors.push(`Invalid ${pragmaName} item: '${value}' must match ${validationPatterns[pattern]}`)
13
6
  }
14
7
 
15
8
  function size (value, min, max, pragmaName, errors) {
@@ -1,4 +1,4 @@
1
- let is = require('../../../lib/is')
1
+ let { is } = require('../../../lib')
2
2
  let { regex, size, unique } = require('./_lib')
3
3
 
4
4
  /**
@@ -10,7 +10,7 @@ let { regex, size, unique } = require('./_lib')
10
10
  * See: https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-create-rule-schedule.html
11
11
  */
12
12
  module.exports = function validateScheduled (scheduled, errors) {
13
- if (scheduled.length) {
13
+ if (scheduled?.length) {
14
14
  unique(scheduled, '@scheduled', errors)
15
15
 
16
16
  scheduled.forEach(schedule => {
@@ -1,5 +1,5 @@
1
1
  let { join, resolve, sep } = require('path')
2
- let is = require('../../../lib/is')
2
+ let { is } = require('../../../lib')
3
3
 
4
4
  module.exports = function validateShared (src, cwd, errors) {
5
5
  let path = src && resolve(join(cwd, src))
@@ -7,13 +7,11 @@ let { regex, size, unique } = require('./_lib')
7
7
  * See: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html
8
8
  */
9
9
  module.exports = function validateTablesStreams (tablesStreams, errors) {
10
- if (tablesStreams.length) {
11
- unique(tablesStreams, '@tables-streams', errors)
10
+ unique(tablesStreams, '@tables-streams', errors)
12
11
 
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
- }
12
+ tablesStreams.forEach(stream => {
13
+ let { name } = stream
14
+ size(name, 3, 255, '@tables-streams', errors)
15
+ regex(name, 'veryLooseName', '@tables-streams', errors)
16
+ })
19
17
  }
@@ -2,13 +2,13 @@ let { regex, size, unique } = require('./_lib')
2
2
  let { deepStrictEqual } = require('assert')
3
3
 
4
4
  /**
5
- * Validate @tables + @indexes
5
+ * Validate @tables + @tables-indexes
6
6
  *
7
7
  * Where possible, attempts to follow DynamoDB validation
8
8
  * See: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html
9
9
  */
10
10
  module.exports = function validateTablesAndIndexes (pragma, pragmaName, errors) {
11
- if (pragma.length) {
11
+ if (pragma?.length) {
12
12
  pragma.forEach(table => {
13
13
  let { name, indexName, partitionKey, sortKey } = table
14
14
 
@@ -4,12 +4,12 @@ module.exports = {
4
4
  aws: require('./_aws'),
5
5
  events: require('./_events'),
6
6
  http: require('./_http'),
7
- indexes: require('./_tables'), // Same ruleset as @tables (more or less)
8
7
  proxy: require('./_proxy'),
9
- tables: require('./_tables'),
10
8
  queues: require('./_events'), // Same ruleset as @events
11
9
  scheduled: require('./_scheduled'),
12
10
  shared: require('./_shared'), // Also includes @views
11
+ tables: require('./_tables'),
12
+ tablesIndexes: require('./_tables'), // Same ruleset as @tables (more or less)
13
13
  tablesStreams: require('./_tables-streams'),
14
14
  websockets: require('./_websockets'),
15
15
 
@@ -1,6 +1,6 @@
1
1
  let { join } = require('path')
2
2
  let validate = require('./validate')
3
- let is = require('../../lib/is')
3
+ let { is } = require('../../lib')
4
4
 
5
5
  module.exports = function configureViews ({ arc, pragmas, inventory, errors }) {
6
6
  if (arc.views && !arc.http) {
@@ -9,46 +9,28 @@ module.exports = function configureViews ({ arc, pragmas, inventory, errors }) {
9
9
  }
10
10
  if (!arc.http) return null
11
11
 
12
- let cwd = inventory._project.src
13
- let src = join(cwd, 'src', 'views')
12
+ let { cwd, src: projSrc } = inventory._project
13
+ let src = join(projSrc, 'views')
14
14
  let views = {
15
15
  src,
16
16
  views: [] // Revert to null later if none are defined
17
17
  }
18
18
 
19
- if (arc.views && arc.views.length) {
20
- let foundSrc = false
21
-
22
- // First pass to get + check views folder (if any)
19
+ // First pass to get + check views folder (if any)
20
+ let foundSrc = false
21
+ if (arc?.views?.length) {
23
22
  for (let view of arc.views) {
24
- let key = view[0].toLowerCase()
25
- if (key === 'src' && is.string(view[1])) {
26
- views.src = view[1]
27
- foundSrc = true
28
- validate.shared(views.src, cwd, errors)
29
- }
30
- }
31
-
32
- // Proceeding from here resets all views config, so make sure it's only if specific views are specified
33
- let some = !(arc.views.length === 1 && foundSrc)
34
- if (some) {
35
- // Reset views settings
36
- for (let route of pragmas.http) {
37
- route.config.views = false
38
- }
39
-
40
- // Set new views settings
41
- for (let view of arc.views) {
42
- let method = view[0].toLowerCase()
43
- let path = view[1]
44
- if (method === 'src') continue
45
- let name = `${method} ${path}`
46
- let route = pragmas.http.find(n => n.name === name)
47
- if (!route) {
48
- return errors.push(`@views ${name} not found in @http routes`)
23
+ if (is.array(view)) {
24
+ let key = view[0]?.toLowerCase()
25
+ if (key === 'src' && is.string(view[1])) {
26
+ views.src = view[1]
27
+ foundSrc = true
28
+ validate.shared(views.src, cwd, errors)
29
+ continue
30
+ }
31
+ if (key === 'src' && !is.string(view[1])) {
32
+ errors.push(`@shared invalid setting: ${key}`)
49
33
  }
50
- // Ignore views into ASAP
51
- if (!route.arcStaticAssetProxy) route.config.views = true
52
34
  }
53
35
  }
54
36
  }
@@ -56,6 +38,29 @@ module.exports = function configureViews ({ arc, pragmas, inventory, errors }) {
56
38
  // Exit if default views folder doesn't exist
57
39
  if (!is.exists(views.src)) return null
58
40
 
41
+ // 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 && foundSrc)
43
+ if (some) {
44
+ // Reset views settings
45
+ for (let route of pragmas.http) {
46
+ route.config.views = false
47
+ }
48
+
49
+ // Set new views settings
50
+ for (let view of arc.views) {
51
+ let method = view?.[0]?.toLowerCase()
52
+ let path = view?.[1]
53
+ if (method === 'src') continue
54
+ let name = `${method} ${path}`
55
+ let route = pragmas.http.find(n => n.name === name)
56
+ if (!route) {
57
+ return errors.push(`@views ${name} not found in @http routes`)
58
+ }
59
+ // Ignore views into ASAP
60
+ if (!route.arcStaticAssetProxy) route.config.views = true
61
+ }
62
+ }
63
+
59
64
  // lambda.config.views was added by Lambda populator defaults, or added above
60
65
  for (let { src, config } of pragmas.http) {
61
66
  if (config.views === true && !views.views.includes(src)) {
@@ -63,8 +68,5 @@ module.exports = function configureViews ({ arc, pragmas, inventory, errors }) {
63
68
  }
64
69
  }
65
70
 
66
- // De-dupe (in case multiple functions live at the same src path)
67
- views.views = [ ...new Set(views.views) ]
68
-
69
71
  return views
70
72
  }
@@ -2,21 +2,23 @@ let populate = require('./populate-lambda')
2
2
  let validate = require('./validate')
3
3
 
4
4
  module.exports = function configureWS ({ arc, inventory, errors }) {
5
- if (!arc.ws) return null
5
+ let wsPlugins = inventory.plugins?._methods?.set?.ws
6
+ if (!arc.ws && !wsPlugins?.length) return null
6
7
 
7
- let ws = [ ...arc.ws ]
8
+ let ws = [ ]
9
+ if (arc.ws) ws.push(...arc.ws)
8
10
 
9
11
  // Backfill required routes if not already present
10
12
  let defaults = [ 'disconnect', 'default', 'connect' ]
11
13
  defaults.forEach(route => {
12
- let found = arc.ws.find(item => {
14
+ let found = arc?.ws?.find(item => {
13
15
  if (item === route) return true
14
16
  if (item[route]) return true
15
17
  })
16
18
  if (!found) ws.unshift(route)
17
19
  })
18
20
 
19
- let websockets = populate.ws(ws, inventory, errors)
21
+ let websockets = populate.ws({ arc, inventory, errors, pragma: ws })
20
22
 
21
23
  // Forgive and normalize userland use of '$default', '$connect', '$disconnect'
22
24
  websockets.forEach(({ name }, i) => {
@@ -1,60 +1,76 @@
1
+ let { join } = require('path')
1
2
  let upsert = require('../_upsert')
2
3
  let prefs = require('./prefs')
3
- let is = require('../../lib/is')
4
4
  let plugins = require('./plugins')
5
+ let { is, mergeEnvVars } = require('../../lib')
5
6
 
6
7
  /**
7
8
  * Get the project-level configuration, overlaying arc.aws settings (if present)
8
9
  */
9
- module.exports = function getProjectConfig (params, errors) {
10
- let { arc, raw, filepath, inventory } = params
11
- let project = {
10
+ module.exports = function getProjectConfig (params) {
11
+ let { arc, errors, raw, filepath, inventory } = params
12
+ let _project = {
12
13
  ...inventory._project,
13
14
  arc,
14
15
  raw,
15
16
  }
16
17
 
17
18
  if (arc.aws) {
18
- project.defaultFunctionConfig = upsert(project.defaultFunctionConfig, arc.aws)
19
+ _project.defaultFunctionConfig = upsert(_project.defaultFunctionConfig, arc.aws)
19
20
  }
20
21
 
21
22
  if (filepath) {
22
- project.manifest = filepath
23
- // TODO add manifestCreated once we determine we can get birthtime reliably
23
+ _project.manifest = filepath
24
24
  }
25
25
 
26
- // require project plugin modules
27
- project.plugins = plugins(project, errors)
28
-
29
- // parse local and global arc preferences
26
+ // Parse local and global project preferences
30
27
  let scopes = [ 'global', 'local' ]
31
28
  for (let scope of scopes) {
32
29
  let p = prefs({ scope, inventory, errors })
33
30
  if (p) {
34
31
  // Set up the scoped metadata
35
- project[`${scope}Preferences`] = p.preferences
36
- project[`${scope}PreferencesFile`] = p.preferencesFile
32
+ _project[`${scope}Preferences`] = p.preferences
33
+ _project[`${scope}PreferencesFile`] = p.preferencesFile
37
34
 
38
35
  // Build out the final preferences
39
- /* istanbul ignore else */ // jic
40
- if (!project.preferences) project.preferences = {}
36
+ /* istanbul ignore else: jic */
37
+ if (!_project.preferences) _project.preferences = {}
41
38
  Object.keys(p.preferences).forEach(pragma => {
42
39
  // Ignore the raw data
43
40
  if (pragma === '_arc' || pragma === '_raw') return
44
41
  // Allow booleans, etc.
45
42
  if (!is.object(p.preferences[pragma])) {
46
- project.preferences[pragma] = p.preferences[pragma]
43
+ _project.preferences[pragma] = p.preferences[pragma]
47
44
  return
48
45
  }
49
46
  // Traverse and merge individual settings
50
- /* istanbul ignore else */ // jic
51
- if (!project.preferences[pragma]) project.preferences[pragma] = {}
47
+ /* istanbul ignore else: jic */
48
+ if (!_project.preferences[pragma]) _project.preferences[pragma] = {}
52
49
  Object.entries(p.preferences[pragma]).forEach(([ setting, value ]) => {
53
- project.preferences[pragma][setting] = value
50
+ _project.preferences[pragma][setting] = value
54
51
  })
55
52
  })
56
53
  }
57
54
  }
58
55
 
59
- return project
56
+ // Populate local env from preferences
57
+ if (_project.preferences?.env) {
58
+ _project.env.local = _project.preferences.env
59
+ }
60
+
61
+ if (inventory.plugins?._methods) {
62
+ _project.env.plugins = plugins.env(params, _project)
63
+ _project.env.local = mergeEnvVars({
64
+ name: 'Local',
65
+ source: _project.env.plugins,
66
+ target: _project.env.local,
67
+ errors,
68
+ })
69
+
70
+ let { build, runtimes } = plugins.runtimes(params, _project)
71
+ if (build) _project.build = join(_project.cwd, build)
72
+ if (runtimes) _project.customRuntimes = runtimes
73
+ }
74
+
75
+ return _project
60
76
  }
@@ -0,0 +1,71 @@
1
+ let { deepFrozenCopy } = require('@architect/utils')
2
+ let { is, tidyError, validationPatterns: valid } = require('../../../lib')
3
+ let envs = [ 'testing', 'staging', 'production' ]
4
+ let str = value => {
5
+ if (is.object(value) || is.array(value)) return JSON.stringify(value)
6
+ return String(value)
7
+ }
8
+
9
+ module.exports = function setEnvPlugins (params, project) {
10
+ let { errors, inventory } = params
11
+ let envPlugins = inventory.plugins?._methods?.set?.env
12
+ if (envPlugins?.length) {
13
+ let env = {
14
+ testing: null,
15
+ staging: null,
16
+ production: null,
17
+ }
18
+
19
+ // inventory._project is not yet built, so provide as much as we can to plugins for now
20
+ let inv = deepFrozenCopy({ ...inventory, _project: project })
21
+ envPlugins.forEach(fn => {
22
+ let errType = `plugin: ${fn.plugin}, method: set.env`
23
+ try {
24
+ let result = fn({ arc: inv._project.arc, inventory: { inv } })
25
+ if (!is.object(result) || !Object.keys(result).length) {
26
+ return errors.push(`Env plugin returned invalid data, must return an Object with one or more keys + values: ${errType}`)
27
+ }
28
+ // Populate env vars based on environment
29
+ // If any keys are environment names, disregard all keys except environment names
30
+ if (Object.keys(result).some(k => envs.includes(k))) {
31
+ envs.forEach(e => {
32
+ if (result[e]) Object.entries(result[e]).forEach(([ k, v ]) => {
33
+ if (!valid.envVar.test(k)) {
34
+ return errors.push(`Env var '${k}' is invalid, must be [a-zA-Z0-9_]`)
35
+ }
36
+ let errored = false, val = str(v)
37
+ if (!env[e]) env[e] = { [k]: val }
38
+ else if (env[e][k] && !errored) {
39
+ errored = true
40
+ errors.push(`Env var '${k}' already registered: ${errType}`)
41
+ }
42
+ else env[e][k] = val
43
+ })
44
+ })
45
+ }
46
+ // Populate all environments based on env var
47
+ else {
48
+ Object.entries(result).forEach(([ k, v ]) => {
49
+ if (!valid.envVar.test(k)) {
50
+ return errors.push(`Env var '${k}' is invalid, must be [a-zA-Z0-9_]`)
51
+ }
52
+ let errored = false, val = str(v)
53
+ envs.forEach(e => {
54
+ if (!env[e]) env[e] = { [k]: val }
55
+ else if (env[e][k] && !errored) {
56
+ errored = true
57
+ errors.push(`Env var '${k}' already registered: ${errType}`)
58
+ }
59
+ else env[e][k] = val
60
+ })
61
+ })
62
+ }
63
+ }
64
+ catch (err) {
65
+ errors.push(`Runtime plugin '${fn.plugin}' failed: ${tidyError(err)}`)
66
+ }
67
+ })
68
+ return env
69
+ }
70
+ return inventory._project.env.plugins
71
+ }
@@ -0,0 +1,7 @@
1
+ let env = require('./env')
2
+ let runtimes = require('./runtimes')
3
+
4
+ module.exports = {
5
+ env,
6
+ runtimes,
7
+ }
@@ -0,0 +1,67 @@
1
+ let { aliases, runtimeList } = require('lambda-runtimes')
2
+ let { deepFrozenCopy } = require('@architect/utils')
3
+ let { is, validationPatterns } = require('../../../lib')
4
+ let { looserName } = validationPatterns
5
+ let allRuntimes = runtimeList.concat([ 'deno', ...Object.keys(aliases) ])
6
+ let validTypes = [ 'transpiled', 'compiled', 'interpreted' ]
7
+ let builtTypes = validTypes.filter(t => t !== 'interpreted')
8
+
9
+ module.exports = function setRuntimePlugins (params, project) {
10
+ let { errors, inventory } = params
11
+ let runtimePlugins = inventory.plugins?._methods?.set?.runtimes
12
+ if (runtimePlugins?.length) {
13
+ let runtimes = {
14
+ runtimes: [],
15
+ }
16
+ // inventory._project is not yet built, so provide as much as we can to plugins for now
17
+ let inv = deepFrozenCopy({ ...inventory, _project: project })
18
+ let build
19
+ runtimePlugins.forEach(fn => {
20
+ let errType = `plugin: ${fn.plugin}, method: set.runtimes`
21
+ try {
22
+ var result = fn({ arc: inv._project.arc, inventory: { inv } })
23
+ }
24
+ catch (err) {
25
+ err.message = `Runtime plugin exception: ${errType}`
26
+ + `\n` + err.message
27
+ throw err
28
+ }
29
+ // Accept one or more results, then loop through them
30
+ result = is.array(result) ? result : [ result ]
31
+ result.forEach(runtime => {
32
+ let { name, type, baseRuntime } = runtime
33
+ if (!name || !looserName.test(name)) {
34
+ let msg = `Runtime plugin must provide a valid name: ${errType}`
35
+ return errors.push(msg)
36
+ }
37
+ if (!type || !validTypes.includes(type)) {
38
+ let msg = `Runtime plugin must provide a valid type: ${errType}`
39
+ return errors.push(msg)
40
+ }
41
+ if (allRuntimes.includes(name)) {
42
+ let msg = `Runtime name '${name}' is reserved: ${errType}`
43
+ return errors.push(msg)
44
+ }
45
+ if (runtimes[name]) {
46
+ let msg = `Runtime name '${name}' already registered: ${errType}`
47
+ return errors.push(msg)
48
+ }
49
+ if (builtTypes.includes(type)) {
50
+ if (build && runtime.build && build !== runtime.build) {
51
+ return errors.push(`Runtime '${name}' cannot set a build directory, as it is already configured to: ${build}`)
52
+ }
53
+ // Adhere to Postel's Law
54
+ build = 'build'
55
+ if (is.string(runtime.build)) build = runtime.build
56
+ }
57
+ if (type === 'transpiled' && !allRuntimes.includes(baseRuntime)) {
58
+ return errors.push(`Runtime '${name}' must include a valid baseRuntime property corresponding to a valid Lambda runtime (e.g. 'nodejs14.x')`)
59
+ }
60
+ runtimes.runtimes.push(name)
61
+ runtimes[name] = runtime
62
+ })
63
+ })
64
+ return { build, runtimes }
65
+ }
66
+ return {}
67
+ }
@@ -0,0 +1,81 @@
1
+ // Copyright (c) 2015, Scott Motte
2
+ // All rights reserved.
3
+
4
+ /* istanbul ignore file */
5
+ /* eslint-disable */
6
+ // node_modules/dotenv/lib/main.js
7
+ var fs = require("fs");
8
+ var path = require("path");
9
+ var os = require("os");
10
+ var LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg;
11
+ function parse(src) {
12
+ const obj = {};
13
+ let lines = src.toString();
14
+ lines = lines.replace(/\r\n?/mg, "\n");
15
+ let match;
16
+ while ((match = LINE.exec(lines)) != null) {
17
+ const key = match[1];
18
+ let value = match[2] || "";
19
+ value = value.trim();
20
+ const maybeQuote = value[0];
21
+ value = value.replace(/^(['"])([\s\S]+)\1$/mg, "$2");
22
+ if (maybeQuote === '"') {
23
+ value = value.replace(/\\n/g, "\n");
24
+ value = value.replace(/\\r/g, "\r");
25
+ }
26
+ obj[key] = value;
27
+ }
28
+ return obj;
29
+ }
30
+ function _log(message) {
31
+ console.log(`[dotenv][DEBUG] ${message}`);
32
+ }
33
+ function _resolveHome(envPath) {
34
+ return envPath[0] === "~" ? path.join(os.homedir(), envPath.slice(1)) : envPath;
35
+ }
36
+ function config(options) {
37
+ let dotenvPath = path.resolve(process.cwd(), ".env");
38
+ let encoding = "utf8";
39
+ const debug = Boolean(options && options.debug);
40
+ const override = Boolean(options && options.override);
41
+ if (options) {
42
+ if (options.path != null) {
43
+ dotenvPath = _resolveHome(options.path);
44
+ }
45
+ if (options.encoding != null) {
46
+ encoding = options.encoding;
47
+ }
48
+ }
49
+ try {
50
+ const parsed = DotenvModule.parse(fs.readFileSync(dotenvPath, { encoding }));
51
+ Object.keys(parsed).forEach(function(key) {
52
+ if (!Object.prototype.hasOwnProperty.call(process.env, key)) {
53
+ process.env[key] = parsed[key];
54
+ } else {
55
+ if (override === true) {
56
+ process.env[key] = parsed[key];
57
+ }
58
+ if (debug) {
59
+ if (override === true) {
60
+ _log(`"${key}" is already defined in \`process.env\` and WAS overwritten`);
61
+ } else {
62
+ _log(`"${key}" is already defined in \`process.env\` and was NOT overwritten`);
63
+ }
64
+ }
65
+ }
66
+ });
67
+ return { parsed };
68
+ } catch (e) {
69
+ if (debug) {
70
+ _log(`Failed to load ${dotenvPath} ${e.message}`);
71
+ }
72
+ return { error: e };
73
+ }
74
+ }
75
+ var DotenvModule = {
76
+ config,
77
+ parse
78
+ };
79
+ module.exports.config = DotenvModule.config;
80
+ module.exports.parse = DotenvModule.parse;
81
+ module.exports = DotenvModule;