@architect/inventory 3.2.0-RC.0 → 3.2.0-RC.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 CHANGED
@@ -7,12 +7,18 @@
7
7
  ### Added
8
8
 
9
9
  - Added support for new setter plugin APIs, specifically: `@proxy`, `@shared`, `@static`, `@tables`, `@tables-indexes`, `@views`
10
+ - Added new `@static` setting: `compression`
10
11
 
11
12
 
12
13
  ### Changed
13
14
 
15
+ - Lambdas defined in the userland Architect project manifest now override conflicting Lambdas returned by plugins (instead of throwing validation errors); fixes #1352
16
+ - Plugin developers can now use a `required` flag to enforce a validation error should their plugin conflict with userland Lambdas
14
17
  - `@tables` and `@tables-indexes` can now accept lower case key types (e.g. `*string` instead of `*String`)
15
18
  - `@tables` and `@tables-indexes` can also accept `*` and `**` as a shortcut for string-type primary and sort keys
19
+ - Changed plugin function property tags from `plugin|type` to `_plugin|_type` to indicate internal property namespacing
20
+ - Added `@static` pragma validation
21
+ - Fixed obscure case where `@static` `ignore` setting might only use the first list item
16
22
 
17
23
 
18
24
  ### Fixed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@architect/inventory",
3
- "version": "3.2.0-RC.0",
3
+ "version": "3.2.0-RC.1",
4
4
  "description": "Architect project resource enumeration utility",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -4,7 +4,7 @@ let { is, normalizeSrc, pragmas, tidyError, validationPatterns } = require('../.
4
4
  let { lambdas } = pragmas
5
5
  let nonLambdaSetters = [ 'customLambdas', 'env', 'proxy', 'runtimes', 'shared', 'static', 'views', 'tables', 'tables-indexes' ]
6
6
  let setters = [ ...lambdas, ...nonLambdaSetters ]
7
- let pluginMethods = [ 'deploy', 'sandbox' ] // TODO add more!
7
+ let pluginMethods = [ 'deploy', 'sandbox' ]
8
8
  let reservedNames = [ '_methods' ]
9
9
 
10
10
  module.exports = function getPluginModules ({ arc, inventory, errors }) {
@@ -67,8 +67,8 @@ module.exports = function getPluginModules ({ arc, inventory, errors }) {
67
67
  return
68
68
  }
69
69
  if (!methods.set[setter]) methods.set[setter] = []
70
- fn.plugin = name
71
- fn.type = type
70
+ fn._plugin = name
71
+ fn._type = type
72
72
  methods.set[setter].push(fn)
73
73
  }
74
74
  })
@@ -83,8 +83,8 @@ module.exports = function getPluginModules ({ arc, inventory, errors }) {
83
83
  }
84
84
  if (!methods[method]) methods[method] = {}
85
85
  if (!methods[method][hook]) methods[method][hook] = []
86
- fn.plugin = name
87
- fn.type = type
86
+ fn._plugin = name
87
+ fn._type = type
88
88
  methods[method][hook].push(fn)
89
89
  })
90
90
  }
@@ -101,14 +101,18 @@ module.exports = function getPluginModules ({ arc, inventory, errors }) {
101
101
  }
102
102
 
103
103
  function getPath (cwd, srcDir, name) {
104
- let paths = [
105
- join(cwd, 'src', srcDir, `${name}.js`),
106
- join(cwd, 'src', srcDir, name),
107
- join(cwd, 'node_modules', name),
108
- join(cwd, 'node_modules', `@${name}`),
109
- ]
110
- /**/ if (existsSync(paths[0])) return paths[0]
111
- else if (existsSync(paths[1])) return paths[1]
112
- else if (existsSync(paths[2])) return paths[2]
113
- else if (existsSync(paths[3])) return paths[3]
104
+ let path1 = join(cwd, 'src', srcDir, `${name}.js`)
105
+ let path2 = join(cwd, 'src', srcDir, name)
106
+ let path3 = join(cwd, 'node_modules', name)
107
+ let path4 = join(cwd, 'node_modules', `@${name}`)
108
+ /**/ if (existsSync(path1)) return path1
109
+ else if (existsSync(path2)) return path2
110
+ else if (existsSync(path3)) return path3
111
+ else if (existsSync(path4)) return path4
112
+ try {
113
+ return require.resolve(name)
114
+ }
115
+ catch {
116
+ return
117
+ }
114
118
  }
@@ -25,26 +25,26 @@ function populateLambda (type, params) {
25
25
  var result = fn({ arc: invCopy._project.arc, inventory: { inv: invCopy } })
26
26
  }
27
27
  catch (err) {
28
- err.message = `Setter plugin exception: plugin: ${fn.plugin}, method: set.${type}`
28
+ err.message = `Setter plugin exception: plugin: ${fn._plugin}, method: set.${type}`
29
29
  + `\n` + err.message
30
30
  throw err
31
31
  }
32
32
  if (!result ||
33
33
  (!is.object(result) && !is.array(result)) ||
34
34
  (is.array(result) && result.some(r => !is.object(r)))) {
35
- errors.push(`Setter plugins must return a valid response: plugin: ${fn.plugin}, method: set.${type}`)
35
+ errors.push(`Setter plugins must return a valid response: plugin: ${fn._plugin}, method: set.${type}`)
36
36
  return []
37
37
  }
38
38
  if (is.array(result)) {
39
39
  result.forEach((item, i) => {
40
- item.plugin = fn.plugin
41
- item.type = fn.type
40
+ item._plugin = fn._plugin
41
+ item._type = fn._type
42
42
  result[i] = item
43
43
  })
44
44
  }
45
45
  else {
46
- result.plugin = fn.plugin
47
- result.type = fn.type
46
+ result._plugin = fn._plugin
47
+ result._type = fn._type
48
48
  }
49
49
  return result
50
50
  })
@@ -53,6 +53,15 @@ function populateLambda (type, params) {
53
53
 
54
54
  let pragmaLambda = populate(type, pragma || arc[type], inventory, errors) || []
55
55
  let aggregate = [ ...pluginLambda, ...pragmaLambda ]
56
+
57
+ // Filter plugins, if appropriate: not required, but do conflict with a manifest entry
58
+ aggregate = aggregate.filter(lambda => {
59
+ if (lambda._plugin && !lambda.required &&
60
+ aggregate.some(({ name, _plugin }) => !_plugin && name === lambda.name)) {
61
+ return false
62
+ }
63
+ return true
64
+ })
56
65
  return aggregate.length ? aggregate : null
57
66
  }
58
67
 
@@ -136,6 +145,12 @@ function populate (type, pragma, inventory, errors, plugin) {
136
145
  // Final tidying of any undefined properties
137
146
  Object.keys(lambda).forEach(k => !is.defined(lambda[k]) && delete lambda[k])
138
147
 
148
+ // Pass through the plugin tag and required status
149
+ if (item._plugin) {
150
+ lambda._plugin = item._plugin
151
+ if (item.required === true) lambda.required = true
152
+ }
153
+
139
154
  lambdas.push(lambda)
140
155
  }
141
156
 
@@ -14,28 +14,28 @@ function resources (params) {
14
14
  var result = fn({ arc: invCopy._project.arc, inventory: { inv: invCopy } })
15
15
  }
16
16
  catch (err) {
17
- err.message = `Setter plugin exception: plugin: ${fn.plugin}, method: set.${type}`
17
+ err.message = `Setter plugin exception: plugin: ${fn._plugin}, method: set.${type}`
18
18
  + `\n` + err.message
19
19
  throw err
20
20
  }
21
21
  if (!result ||
22
22
  (!is.object(result) && !is.array(result)) ||
23
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}`)
24
+ errors.push(`Setter plugins must return a valid response: plugin: ${fn._plugin}, method: set.${type}`)
25
25
  return []
26
26
  }
27
27
  if (is.array(result)) {
28
28
  result.forEach((item, i) => {
29
29
  item = populateTemplate(template, item)
30
- item.plugin = fn.plugin
31
- item.type = fn.type
30
+ item._plugin = fn._plugin
31
+ item._type = fn._type
32
32
  result[i] = item
33
33
  })
34
34
  }
35
35
  else {
36
36
  result = populateTemplate(template, result)
37
- result.plugin = fn.plugin
38
- result.type = fn.type
37
+ result._plugin = fn._plugin
38
+ result._type = fn._type
39
39
  }
40
40
  return result
41
41
  })
@@ -84,12 +84,12 @@ function settings (params) {
84
84
  var result = fn({ arc: invCopy._project.arc, inventory: { inv: invCopy } })
85
85
  }
86
86
  catch (err) {
87
- err.message = `Setter plugin exception: plugin: ${fn.plugin}, method: set.${type}`
87
+ err.message = `Setter plugin exception: plugin: ${fn._plugin}, method: set.${type}`
88
88
  + `\n` + err.message
89
89
  throw err
90
90
  }
91
91
  if (!result || !is.object(result)) {
92
- errors.push(`Setter plugins must return a valid response: plugin: ${fn.plugin}, method: set.${type}`)
92
+ errors.push(`Setter plugins must return a valid response: plugin: ${fn._plugin}, method: set.${type}`)
93
93
  foundError = true
94
94
  }
95
95
  else {
@@ -1,5 +1,6 @@
1
1
  let populate = require('./populate-other')
2
2
  let { asapSrc, is } = require('../../lib')
3
+ let validate = require('./validate')
3
4
 
4
5
  module.exports = function configureStatic ({ arc, inventory, errors }) {
5
6
  let staticSetters = inventory.plugins?._methods?.set?.static
@@ -10,6 +11,7 @@ module.exports = function configureStatic ({ arc, inventory, errors }) {
10
11
 
11
12
  let staticPragma = arc.static || []
12
13
  let _static = {
14
+ compression: false, // Arc applied default
13
15
  fingerprint: null,
14
16
  folder: 'public', // Arc applied default
15
17
  ignore: null,
@@ -35,16 +37,14 @@ module.exports = function configureStatic ({ arc, inventory, errors }) {
35
37
  })
36
38
 
37
39
  let settings = Object.entries(_static).map(([ setting ]) => setting)
40
+ let validSetting = key => settings.includes(key)
38
41
  for (let setting of staticPragma) {
39
- let validSetting = key => settings.includes(key)
42
+ // The ignore setting can come in a couple shapes, so we have to handle those
40
43
  if (setting.ignore) {
41
44
  _static.ignore = setting.ignore
42
45
  }
43
- else if (is.array(setting) &&
44
- setting.length === 2 &&
45
- validSetting(setting[0])) {
46
- let isIgnore = setting[0] === 'ignore'
47
- _static[setting[0]] = isIgnore ? [ setting[1] ] : setting[1]
46
+ else if (is.array(setting) && validSetting(setting[0])) {
47
+ _static[setting[0]] = setting[0] === 'ignore' ? [ ...setting.slice(1) ] : setting[1]
48
48
  }
49
49
  }
50
50
 
@@ -54,5 +54,7 @@ module.exports = function configureStatic ({ arc, inventory, errors }) {
54
54
  inventory._project.asapSrc = asapSrc()
55
55
  }
56
56
 
57
+ validate.static(_static, errors)
58
+
57
59
  return _static
58
60
  }
@@ -22,10 +22,19 @@ function size (value, min, max, pragmaName, errors) {
22
22
 
23
23
  function unique (lambdas, pragmaName, errors) {
24
24
  if (!is.array(lambdas)) throw ReferenceError(`Invalid Lambda array: ${lambdas}`)
25
- let names = []
26
- if (lambdas.length) lambdas.forEach(({ name }) => {
27
- let err = `Duplicate ${pragmaName} item: ${name}`
28
- if (names.includes(name) && !errors.includes(err)) errors.push(err)
25
+ let names = [] // List of names we've looked at
26
+ let namesErrored = [] // List of any offending names
27
+ if (lambdas.length) lambdas.forEach(({ name, pragma }) => {
28
+ if (names.includes(name) && !namesErrored.includes(name)) {
29
+ let err = `Duplicate ${pragmaName} item: ${name}`
30
+
31
+ // If we find a plugin Lambda, that means the filter let it through because it's required by the plugin, so we must now error
32
+ let foundPlugin = lambdas.find(l => l._plugin && l.name === name)
33
+ if (foundPlugin) err = `Plugin requires conflicting ${pragmaName} item: ${name}, plugin: ${foundPlugin._plugin}, method: set.${pragma}`
34
+
35
+ namesErrored.push(name)
36
+ errors.push(err)
37
+ }
29
38
  names.push(name)
30
39
  })
31
40
  }
@@ -0,0 +1,40 @@
1
+ let { is } = require('../../../lib')
2
+
3
+ module.exports = function validateStatic (_static, errors) {
4
+ // `folder` validation happens elsewhere
5
+ let {
6
+ compression,
7
+ fingerprint,
8
+ ignore,
9
+ prefix,
10
+ prune,
11
+ spa,
12
+ staging,
13
+ production,
14
+ } = _static
15
+
16
+ if (compression && ![ true, 'br', 'gzip' ].includes(compression)) {
17
+ errors.push(`Compression must be 'br' or 'gzip'`)
18
+ }
19
+ if (fingerprint && ![ true, 'external' ].includes(fingerprint)) {
20
+ errors.push(`Fingerprint must be true or 'external'`)
21
+ }
22
+ if (ignore && (!is.array(ignore) || !ignore.every(i => is.string(i)))) {
23
+ errors.push(`Ignore must be a list of one or more strings`)
24
+ }
25
+ if (prefix && !is.string(prefix)) {
26
+ errors.push(`Prefix must be a string`)
27
+ }
28
+ if (!is.nullish(prune) && !is.bool(prune)) {
29
+ errors.push(`Prune must be a boolean`)
30
+ }
31
+ if (!is.nullish(spa) && !is.bool(spa)) {
32
+ errors.push(`spa must be a string`)
33
+ }
34
+ if (!is.nullish(staging) && !is.string(staging)) {
35
+ errors.push(`Staging must be a string`)
36
+ }
37
+ if (!is.nullish(production) && !is.string(production)) {
38
+ errors.push(`Production must be a string`)
39
+ }
40
+ }
@@ -8,6 +8,7 @@ module.exports = {
8
8
  queues: require('./_events'), // Same ruleset as @events
9
9
  scheduled: require('./_scheduled'),
10
10
  shared: require('./_shared'), // Also includes @views
11
+ static: require('./_static'),
11
12
  tables: require('./_tables'),
12
13
  tablesIndexes: require('./_tables'), // Same ruleset as @tables (more or less)
13
14
  tablesStreams: require('./_tables-streams'),