@toa.io/operations 1.0.0-alpha.284 → 1.0.0-alpha.287

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 (50) hide show
  1. package/CHANGELOG.md +1 -224
  2. package/package.json +4 -4
  3. package/readme.md +43 -0
  4. package/src/deployment/.deployment/.describe/compositions.js +7 -5
  5. package/src/deployment/.deployment/.describe/events.js +7 -7
  6. package/src/deployment/.deployment/.describe/fold.js +10 -3
  7. package/src/deployment/.deployment/.describe/fold.test.js +30 -14
  8. package/src/deployment/.deployment/.describe/mounts.js +4 -7
  9. package/src/deployment/.deployment/.describe/resources.js +7 -5
  10. package/src/deployment/.deployment/.describe/resources.test.js +13 -6
  11. package/src/deployment/.deployment/.describe/services.js +10 -9
  12. package/src/deployment/.deployment/.describe/services.test.js +22 -5
  13. package/src/deployment/.deployment/.describe/variables.js +2 -3
  14. package/src/deployment/.deployment/describe.js +11 -7
  15. package/src/deployment/.deployment/merge.js +11 -6
  16. package/src/deployment/.deployment/merge.test.js +41 -10
  17. package/src/deployment/composition.js +1 -1
  18. package/src/deployment/deployment.js +35 -16
  19. package/src/deployment/factory.js +39 -19
  20. package/src/deployment/images/composition.Dockerfile +1 -1
  21. package/src/deployment/images/composition.js +10 -9
  22. package/src/deployment/images/factory.js +17 -6
  23. package/src/deployment/images/format.js +9 -5
  24. package/src/deployment/images/image.fixtures.js +2 -2
  25. package/src/deployment/images/image.js +38 -21
  26. package/src/deployment/images/image.test.js +7 -2
  27. package/src/deployment/images/mono.Dockerfile +1 -1
  28. package/src/deployment/images/mono.js +10 -9
  29. package/src/deployment/images/publish.js +98 -0
  30. package/src/deployment/images/runtime-base.test.js +12 -6
  31. package/src/deployment/images/service.Dockerfile +1 -1
  32. package/src/deployment/images/service.js +4 -4
  33. package/src/deployment/operator.js +8 -8
  34. package/src/deployment/registry.js +89 -61
  35. package/src/deployment/registry.test.js +117 -43
  36. package/src/deployment/service.js +3 -1
  37. package/src/deployment/workspace.js +1 -1
  38. package/src/process.js +1 -1
  39. package/src/process.test.js +8 -4
  40. package/types/_deployment/composition.d.ts +0 -2
  41. package/types/_deployment/dependency.d.ts +10 -6
  42. package/types/_deployment/deployment.d.ts +0 -4
  43. package/types/_deployment/factory.d.ts +0 -2
  44. package/types/_deployment/images/factory.d.ts +4 -6
  45. package/types/_deployment/images/image.d.ts +2 -4
  46. package/types/_deployment/images/registry.d.ts +7 -10
  47. package/types/_deployment/operator.d.ts +5 -7
  48. package/types/_deployment/registry.d.ts +6 -8
  49. package/types/_deployment/service.d.ts +0 -2
  50. package/types/dependency.ts +3 -0
@@ -14,7 +14,8 @@ export const describe = (context, compositions, dependency, image) => {
14
14
  {
15
15
  name: 'TOA_CONTEXT',
16
16
  value: context.name
17
- }, {
17
+ },
18
+ {
18
19
  name: 'TOA_ENV',
19
20
  value: context.environment
20
21
  }
@@ -28,8 +29,10 @@ export const describe = (context, compositions, dependency, image) => {
28
29
  // a lock is taken on `floor(n / 2) + 1` of them, so an even number tolerates no more
29
30
  // losses than the odd number below it, and two tolerate fewer than one does
30
31
  if (addresses.length % 2 === 0)
31
- throw new Error(`'atomicity.redis' takes an odd number of addresses, ` +
32
- `${addresses.length} given`)
32
+ throw new Error(
33
+ `'atomicity.redis' takes an odd number of addresses, ` +
34
+ `${addresses.length} given`
35
+ )
33
36
 
34
37
  dependency.variables.global.push({
35
38
  name: 'TOA_ATOMICITY_REDIS',
@@ -102,8 +105,10 @@ export const describe = (context, compositions, dependency, image) => {
102
105
  return values
103
106
  }
104
107
 
105
- function unit (context, dependency) {
106
- const components = (context.components ?? []).map((component) => component.locator.label)
108
+ function unit(context, dependency) {
109
+ const components = (context.components ?? []).map(
110
+ (component) => component.locator.label
111
+ )
107
112
 
108
113
  const variables = dependency.variables ?? {}
109
114
  const mounts = dependency.mounts ?? {}
@@ -115,8 +120,7 @@ function unit (context, dependency) {
115
120
  variables: []
116
121
  }
117
122
 
118
- if (context.ingress !== undefined)
119
- mono.ingress = Object.assign({}, context.ingress)
123
+ if (context.ingress !== undefined) mono.ingress = Object.assign({}, context.ingress)
120
124
 
121
125
  addVariables(mono, variables, Object.keys(variables))
122
126
  addMounts(mono, dependency.mounts, Object.keys(mounts))
@@ -61,22 +61,27 @@ const reserve = (services, probe) => {
61
61
  const conflicting = claimed.get(port)
62
62
 
63
63
  if (conflicting !== undefined)
64
- throw new Error(`Port ${port} is claimed by both ${conflicting} and ${claimant}` +
65
- (service.workload === undefined ? '' : ` in '${workload}'`))
64
+ throw new Error(
65
+ `Port ${port} is claimed by both ${conflicting} and ${claimant}` +
66
+ (service.workload === undefined ? '' : ` in '${workload}'`)
67
+ )
66
68
 
67
69
  claimed.set(port, claimant)
68
70
  }
69
71
  }
70
72
  }
71
73
 
72
- function * ports (service) {
74
+ function* ports(service) {
73
75
  // every service reaching here is named the way it is deployed, `<group>-<name>`
74
76
  const name = `'${service.name}'`
75
77
 
76
- if (service.port !== undefined)
77
- yield [service.port, name]
78
+ if (service.port !== undefined) yield [service.port, name]
78
79
 
79
- if (service.probe !== undefined && service.probe !== false && service.probe.port !== service.port)
80
+ if (
81
+ service.probe !== undefined &&
82
+ service.probe !== false &&
83
+ service.probe.port !== service.port
84
+ )
80
85
  yield [service.probe.port, `the readiness probe of ${name}`]
81
86
  }
82
87
 
@@ -4,7 +4,12 @@ import assert from 'node:assert/strict'
4
4
  import { merge } from './merge.js'
5
5
 
6
6
  // a service is named the way it is deployed by the time it reaches `merge`
7
- const service = (name, extra = {}) => ({ group: 'group', name: `group-${name}`, version: '0', ...extra })
7
+ const service = (name, extra = {}) => ({
8
+ group: 'group',
9
+ name: `group-${name}`,
10
+ version: '0',
11
+ ...extra
12
+ })
8
13
 
9
14
  it('should merge services of all dependencies', () => {
10
15
  const merged = merge([
@@ -28,7 +33,13 @@ describe('port reservation', () => {
28
33
  { services: [hosted('two', { port: 8000 })] }
29
34
  ]
30
35
 
31
- assert.throws(() => merge(dependencies), (error) => /Port 8000 is claimed by both 'group-one' and 'group-two' in 'mono'/.test(error.message))
36
+ assert.throws(
37
+ () => merge(dependencies),
38
+ (error) =>
39
+ /Port 8000 is claimed by both 'group-one' and 'group-two' in 'mono'/.test(
40
+ error.message
41
+ )
42
+ )
32
43
  })
33
44
 
34
45
  it('should allow two workloads to claim one port', () => {
@@ -46,7 +57,13 @@ describe('port reservation', () => {
46
57
  { services: [service('two', { port: 8000, workload: ['inner'] })] }
47
58
  ]
48
59
 
49
- assert.throws(() => merge(dependencies), (error) => /Port 8000 is claimed by both 'group-one' and 'group-two' in 'inner'/.test(error.message))
60
+ assert.throws(
61
+ () => merge(dependencies),
62
+ (error) =>
63
+ /Port 8000 is claimed by both 'group-one' and 'group-two' in 'inner'/.test(
64
+ error.message
65
+ )
66
+ )
50
67
  })
51
68
 
52
69
  it('should allow two services deployed on their own to claim one port', () => {
@@ -64,30 +81,44 @@ describe('port reservation', () => {
64
81
  { services: [service('one', { port: 8001 })] }
65
82
  ]
66
83
 
67
- assert.throws(() => merge(dependencies), (error) => /Port 8001 is claimed by both the readiness probe and 'group-one'/.test(error.message))
84
+ assert.throws(
85
+ () => merge(dependencies),
86
+ (error) =>
87
+ /Port 8001 is claimed by both the readiness probe and 'group-one'/.test(
88
+ error.message
89
+ )
90
+ )
68
91
  })
69
92
 
70
93
  it('should reject a probe claiming the port of another service of the workload', () => {
71
94
  const dependencies = [
72
95
  { services: [hosted('one', { port: 8000 })] },
73
- { services: [hosted('two', { port: 8002, probe: { path: '/.ready', port: 8000 } })] }
96
+ {
97
+ services: [hosted('two', { port: 8002, probe: { path: '/.ready', port: 8000 } })]
98
+ }
74
99
  ]
75
100
 
76
- assert.throws(() => merge(dependencies), (error) => /Port 8000 is claimed by both 'group-one' and the readiness probe of 'group-two' in 'mono'/.test(error.message))
101
+ assert.throws(
102
+ () => merge(dependencies),
103
+ (error) =>
104
+ /Port 8000 is claimed by both 'group-one' and the readiness probe of 'group-two' in 'mono'/.test(
105
+ error.message
106
+ )
107
+ )
77
108
  })
78
109
 
79
110
  it('should allow a service to probe its own port', () => {
80
111
  const dependencies = [
81
- { services: [service('one', { port: 8000, probe: { path: '/.ready', port: 8000 } })] }
112
+ {
113
+ services: [service('one', { port: 8000, probe: { path: '/.ready', port: 8000 } })]
114
+ }
82
115
  ]
83
116
 
84
117
  assert.doesNotThrow(() => merge(dependencies))
85
118
  })
86
119
 
87
120
  it('should ignore services without a port', () => {
88
- const dependencies = [
89
- { services: [service('one'), service('two')] }
90
- ]
121
+ const dependencies = [{ services: [service('one'), service('two')] }]
91
122
 
92
123
  assert.doesNotThrow(() => merge(dependencies))
93
124
  })
@@ -4,7 +4,7 @@ export class Composition {
4
4
  /** @type {string[]} */
5
5
  components
6
6
 
7
- constructor (composition, image) {
7
+ constructor(composition, image) {
8
8
  this.name = composition.name
9
9
  this.image = image.reference
10
10
  this.components = composition.components.map(component)
@@ -11,7 +11,7 @@ export class Deployment {
11
11
  #process
12
12
  #target
13
13
 
14
- constructor (context, compositions, dependencies, process, image) {
14
+ constructor(context, compositions, dependencies, process, image) {
15
15
  const dependency = merge(dependencies)
16
16
 
17
17
  this.#chart = declare(context, dependency)
@@ -19,7 +19,7 @@ export class Deployment {
19
19
  this.#process = process
20
20
  }
21
21
 
22
- async export (target) {
22
+ async export(target) {
23
23
  const chart = dump(this.#chart)
24
24
  const values = dump(this.#values)
25
25
 
@@ -32,9 +32,9 @@ export class Deployment {
32
32
  this.#target = target
33
33
  }
34
34
 
35
- async install (options) {
35
+ async install(options) {
36
36
  if (options.target) this.#target = options.target
37
- if (this.#target === undefined) throw new Error('Deployment hasn\'t been exported')
37
+ if (this.#target === undefined) throw new Error("Deployment hasn't been exported")
38
38
 
39
39
  const args = []
40
40
 
@@ -42,25 +42,46 @@ export class Deployment {
42
42
  if (options.wait === true) args.push('--wait')
43
43
  if (options.timeout !== undefined) args.push('--timeout', options.timeout)
44
44
 
45
- await this.#process.execute('helm', ['dependency', 'update', this.#target])
46
- await this.#process.execute('helm', ['upgrade', this.#chart.name, '-i', ...args, this.#target])
45
+ await this.#update()
46
+ await this.#process.execute('helm', [
47
+ 'upgrade',
48
+ this.#chart.name,
49
+ '-i',
50
+ ...args,
51
+ this.#target
52
+ ])
47
53
  }
48
54
 
49
- async template (options) {
50
- if (this.#target === undefined) throw new Error('Deployment hasn\'t been exported')
55
+ async template(options) {
56
+ if (this.#target === undefined) throw new Error("Deployment hasn't been exported")
51
57
 
52
- await this.#process.execute('helm', ['dependency', 'update', this.#target], { silently: true })
58
+ await this.#update({ silently: true })
53
59
 
54
60
  const args = []
55
61
 
56
62
  if (options.namespace !== undefined) args.push('-n', options.namespace)
57
63
 
58
- return await this.#process.execute('helm',
64
+ return await this.#process.execute(
65
+ 'helm',
59
66
  ['template', this.#chart.name, ...args, this.#target],
60
- { silently: true })
67
+ { silently: true }
68
+ )
69
+ }
70
+
71
+ /**
72
+ * A chart with no subcharts has nothing to resolve, and the call still reaches out for
73
+ * the repositories it would have read.
74
+ *
75
+ * @param {object} [options]
76
+ * @returns {Promise<void>}
77
+ */
78
+ async #update(options = {}) {
79
+ if (this.#chart.dependencies.length === 0) return
80
+
81
+ await this.#process.execute('helm', ['dependency', 'update', this.#target], options)
61
82
  }
62
83
 
63
- variables () {
84
+ variables() {
64
85
  const variables = []
65
86
  const used = new Set()
66
87
 
@@ -74,7 +95,7 @@ export class Deployment {
74
95
  }
75
96
  }
76
97
 
77
- function addVariables (list, variables, used = new Set()) {
98
+ function addVariables(list, variables, used = new Set()) {
78
99
  for (const item of list) {
79
100
  if (item.variables === undefined) continue
80
101
 
@@ -89,9 +110,7 @@ function addVariables (list, variables, used = new Set()) {
89
110
 
90
111
  const TEMPLATES = join(import.meta.dirname, 'chart/templates')
91
112
 
92
-
93
-
94
- function dump (object) {
113
+ function dump(object) {
95
114
  // js-yaml writes plain objects only, and the values carry locators and images
96
115
  return jsyaml.dump(JSON.parse(JSON.stringify(object)), { noRefs: true, lineWidth: -1 })
97
116
  }
@@ -29,14 +29,18 @@ export class Factory {
29
29
  * @type {Map<string, string[]>} */
30
30
  #claims
31
31
 
32
- constructor (context, options = {}) {
32
+ constructor(context, options = {}) {
33
33
  this.#context = context
34
34
  this.#mono = options.mono === true
35
35
  this.#process = new Process()
36
36
 
37
- const imagesFactory = new ImagesFactory(context.name, context.runtime, context.registry)
37
+ const imagesFactory = new ImagesFactory(
38
+ context.name,
39
+ context.runtime,
40
+ context.registry
41
+ )
38
42
 
39
- this.#registry = new Registry(context.name, context.registry, imagesFactory, this.#process)
43
+ this.#registry = new Registry(context.registry, imagesFactory, this.#process)
40
44
  this.#claims = claims(context)
41
45
  this.#dependencies = this.#getDependencies()
42
46
  this.#compositions = []
@@ -46,10 +50,12 @@ export class Factory {
46
50
  components: context.components
47
51
  })
48
52
  else
49
- this.#compositions = context.compositions.map((composition) => this.#composition(composition))
53
+ this.#compositions = context.compositions.map((composition) =>
54
+ this.#composition(composition)
55
+ )
50
56
  }
51
57
 
52
- async operator () {
58
+ async operator() {
53
59
  const deployment = new Deployment(
54
60
  this.#context,
55
61
  this.#compositions,
@@ -62,17 +68,17 @@ export class Factory {
62
68
  return new Operator(deployment, this.#registry)
63
69
  }
64
70
 
65
- registry () {
71
+ registry() {
66
72
  return this.#registry
67
73
  }
68
74
 
69
- #composition (composition) {
75
+ #composition(composition) {
70
76
  const image = this.#registry.composition(composition)
71
77
 
72
78
  return new Composition(composition, image)
73
79
  }
74
80
 
75
- async #getDependencies () {
81
+ async #getDependencies() {
76
82
  /** @type {toa.deployment.Dependency[]} */
77
83
  const dependencies = []
78
84
 
@@ -95,17 +101,21 @@ export class Factory {
95
101
  // point where a reference that yields nothing can be told from one that yields a service
96
102
  for (const [reference, compositions] of this.#claims)
97
103
  if (!contributing.has(reference))
98
- throw new Error(`Composition '${compositions[0]}' lists '${reference}', ` +
99
- 'which contributes no service.')
104
+ throw new Error(
105
+ `Composition '${compositions[0]}' lists '${reference}', ` +
106
+ 'which contributes no service.'
107
+ )
100
108
 
101
109
  return dependencies
102
110
  }
103
111
 
104
- async #getDependency (reference, instances) {
112
+ async #getDependency(reference, instances) {
105
113
  // a dependency may be named the way a package is or written as a directory,
106
114
  // and a module is loaded by file
107
115
  const module = await import(pathToFileURL(require.resolve(reference)).href)
108
- const pkg = JSON.parse(readFileSync(require.resolve(join(reference, 'package.json')), 'utf8'))
116
+ const pkg = JSON.parse(
117
+ readFileSync(require.resolve(join(reference, 'package.json')), 'utf8')
118
+ )
109
119
 
110
120
  if (module.deployment === undefined) return
111
121
 
@@ -121,9 +131,10 @@ export class Factory {
121
131
  /** @type {toa.deployment.Service[]} */
122
132
  const services = dependency.services?.map((service) =>
123
133
  workload === undefined
124
- ? this.#service(reference, service) // its own deployment, its own image
125
- // named the way `Service` would name it, since it skips that wrapper
126
- : { ...service, name: `${service.group}-${service.name}`, workload })
134
+ ? this.#service(reference, service) // its own deployment, its own image
135
+ : // named the way `Service` would name it, since it skips that wrapper
136
+ { ...service, name: `${service.group}-${service.name}`, workload }
137
+ )
127
138
 
128
139
  return { ...dependency, services }
129
140
  }
@@ -133,13 +144,20 @@ export class Factory {
133
144
  * @param service {toa.deployment.dependency.Service}
134
145
  * @returns {Service}
135
146
  */
136
- #service (path, service) {
137
- const image = this.#registry.service(path, service)
147
+ #service(path, service) {
148
+ // an extension that publishes its service's image is taken at its word: nothing is
149
+ // added to the registry, so nothing is prepared, probed, built or pushed for it
150
+ const published =
151
+ service.image !== undefined && this.#context.registry?.services === PUBLISHED
152
+
153
+ const image = published
154
+ ? { reference: `${service.image}:${this.#context.runtime.version}` }
155
+ : this.#registry.service(path, service)
138
156
 
139
157
  return new Service(service, image)
140
158
  }
141
159
 
142
- static async create (path, environment, options = {}) {
160
+ static async create(path, environment, options = {}) {
143
161
  const context = await load(path, environment)
144
162
 
145
163
  return new Factory(context, options)
@@ -148,11 +166,13 @@ export class Factory {
148
166
 
149
167
  const MONO = 'mono'
150
168
 
169
+ const PUBLISHED = 'published'
170
+
151
171
  /**
152
172
  * @param {toa.norm.Context} context
153
173
  * @returns {Map<string, string[]>}
154
174
  */
155
- function claims (context) {
175
+ function claims(context) {
156
176
  const map = new Map()
157
177
 
158
178
  for (const composition of context.compositions ?? [])
@@ -12,7 +12,7 @@ COPY --chown=node:node . /composition
12
12
  {{build.run}}
13
13
 
14
14
  # run 'npm i' in each component
15
- RUN --mount=type=cache,target=/root/.npm \
15
+ RUN --mount=type=cache,target=/root/.npm,sharing=locked \
16
16
  for entry in *; do if grep -qs '"dependencies"' "$entry/package.json"; then (cd $entry && npm i --omit=dev); fi; done
17
17
 
18
18
  USER node
@@ -12,7 +12,7 @@ export class Composition extends Image {
12
12
  #image
13
13
  #components
14
14
 
15
- constructor (scope, runtime, registry, composition) {
15
+ constructor(scope, runtime, registry, composition) {
16
16
  super(scope, runtime, registry)
17
17
 
18
18
  this.#name = composition.name
@@ -20,11 +20,11 @@ export class Composition extends Image {
20
20
  this.#components = composition.components
21
21
  }
22
22
 
23
- get name () {
23
+ get name() {
24
24
  return 'composition-' + this.#name
25
25
  }
26
26
 
27
- get version () {
27
+ get version() {
28
28
  const hash = createHash('sha256')
29
29
 
30
30
  for (const component of this.#components) {
@@ -35,31 +35,32 @@ export class Composition extends Image {
35
35
  return hash.digest('hex').slice(0, 8)
36
36
  }
37
37
 
38
- get base () {
38
+ get base() {
39
39
  if (this.#image !== undefined) return this.#image
40
40
 
41
41
  const images = new Set(this.#components.map((component) => component.build?.image))
42
42
 
43
43
  if (images.size > 1)
44
- throw new Error(`Composition '${this.#name}' requires different base images for its components. Specify base image for the composition in the context.`)
44
+ throw new Error(
45
+ `Composition '${this.#name}' requires different base images for its components. Specify base image for the composition in the context.`
46
+ )
45
47
 
46
48
  return images.values().next().value
47
49
  }
48
50
 
49
- get run () {
51
+ get run() {
50
52
  const commands = []
51
53
 
52
54
  for (const component of this.#components) {
53
55
  const run = component.build?.run
54
56
 
55
- if (run !== undefined)
56
- commands.push(run)
57
+ if (run !== undefined) commands.push(run)
57
58
  }
58
59
 
59
60
  return commands.join('\n')
60
61
  }
61
62
 
62
- async prepare (root) {
63
+ async prepare(root) {
63
64
  const context = await super.prepare(root)
64
65
 
65
66
  for (const component of this.#components) {
@@ -17,7 +17,7 @@ export class Factory {
17
17
  * @param {toa.norm.context.Runtime} runtime
18
18
  * @param {toa.norm.context.Registry} registry
19
19
  */
20
- constructor (scope, runtime, registry) {
20
+ constructor(scope, runtime, registry) {
21
21
  this.#scope = scope
22
22
  this.#runtime = runtime
23
23
  this.#registry = registry
@@ -26,8 +26,13 @@ export class Factory {
26
26
  /**
27
27
  * @returns {Composition}
28
28
  */
29
- composition (composition) {
30
- const instance = new Composition(this.#scope, this.#runtime, this.#registry, composition)
29
+ composition(composition) {
30
+ const instance = new Composition(
31
+ this.#scope,
32
+ this.#runtime,
33
+ this.#registry,
34
+ composition
35
+ )
31
36
 
32
37
  instance.tag()
33
38
 
@@ -37,8 +42,14 @@ export class Factory {
37
42
  /**
38
43
  * @returns {Service}
39
44
  */
40
- service (path, service) {
41
- const instance = new Service(this.#scope, this.#runtime, this.#registry, path, service)
45
+ service(path, service) {
46
+ const instance = new Service(
47
+ this.#scope,
48
+ this.#runtime,
49
+ this.#registry,
50
+ path,
51
+ service
52
+ )
42
53
 
43
54
  instance.tag()
44
55
 
@@ -48,7 +59,7 @@ export class Factory {
48
59
  /**
49
60
  * @returns {Mono}
50
61
  */
51
- mono (composition) {
62
+ mono(composition) {
52
63
  const instance = new Mono(this.#scope, this.#runtime, this.#registry, composition)
53
64
 
54
65
  instance.tag()
@@ -14,11 +14,13 @@ import { dirname, join, parse } from 'node:path'
14
14
  * @param {string} target where it was copied
15
15
  * @param {string} name
16
16
  */
17
- export async function declare (source, target, name) {
17
+ export async function declare(source, target, name) {
18
18
  if (existsSync(join(target, MANIFEST))) return
19
19
 
20
- await writeFile(join(target, MANIFEST),
21
- JSON.stringify({ name, private: true, type: format(source) }, null, 2) + '\n')
20
+ await writeFile(
21
+ join(target, MANIFEST),
22
+ JSON.stringify({ name, private: true, type: format(source) }, null, 2) + '\n'
23
+ )
22
24
  }
23
25
 
24
26
  /**
@@ -28,7 +30,7 @@ export async function declare (source, target, name) {
28
30
  * @param {string} directory
29
31
  * @returns {'module' | 'commonjs'}
30
32
  */
31
- export function format (directory) {
33
+ export function format(directory) {
32
34
  const { root } = parse(directory)
33
35
 
34
36
  let current = directory
@@ -37,7 +39,9 @@ export function format (directory) {
37
39
  const manifest = join(current, MANIFEST)
38
40
 
39
41
  if (existsSync(manifest))
40
- return JSON.parse(readFileSync(manifest, 'utf8')).type === 'module' ? 'module' : 'commonjs'
42
+ return JSON.parse(readFileSync(manifest, 'utf8')).type === 'module'
43
+ ? 'module'
44
+ : 'commonjs'
41
45
 
42
46
  current = dirname(current)
43
47
  }
@@ -8,11 +8,11 @@ const name = generate()
8
8
  * @implements {toa.deployment.images.Image}
9
9
  */
10
10
  class Class extends Image {
11
- get name () {
11
+ get name() {
12
12
  return name
13
13
  }
14
14
 
15
- get version () {
15
+ get version() {
16
16
  return version
17
17
  }
18
18
  }