@opentrons/shared-data 0.1.2-alpha.0 → 0.1.2-alpha.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.
Files changed (131) hide show
  1. package/js/__tests__/__snapshots__/pipettes.test.ts.snap +5969 -0
  2. package/js/__tests__/deckSchemas.test.ts +87 -0
  3. package/js/__tests__/errors.test.js +21 -0
  4. package/js/__tests__/getAreSlotsAdjacent.test.ts +128 -0
  5. package/js/__tests__/getWellNamePerMultiTip.test.ts +162 -0
  6. package/js/__tests__/labwareDefQuirks.test.ts +38 -0
  7. package/js/__tests__/labwareDefSchemaV1.test.ts +82 -0
  8. package/js/__tests__/labwareDefSchemaV2.test.ts +298 -0
  9. package/js/__tests__/moduleAccessors.test.ts +50 -0
  10. package/js/__tests__/moduleSpecsSchema.test.ts +77 -0
  11. package/js/__tests__/pipetteSchemaV2.test.ts +107 -0
  12. package/js/__tests__/pipetteSpecSchemas.test.ts +48 -0
  13. package/js/__tests__/pipettes.test.ts +58 -0
  14. package/js/__tests__/protocolSchemaV4.test.ts +137 -0
  15. package/js/__tests__/protocolSchemaV5.test.ts +137 -0
  16. package/js/__tests__/protocolSchemaV6.test.ts +132 -0
  17. package/js/__tests__/protocolSchemaV7.test.ts +64 -0
  18. package/js/__tests__/protocolValidation.test.ts +83 -0
  19. package/js/__tests__/sortWells.test.ts +40 -0
  20. package/js/__tests__/splitWellsOnColumn.test.ts +21 -0
  21. package/js/__tests__/validateErrors.test.js +34 -0
  22. package/js/constants.ts +405 -0
  23. package/js/cypressUtils.ts +35 -0
  24. package/js/errors.ts +33 -0
  25. package/js/fixtures.ts +156 -0
  26. package/js/getLabware.ts +145 -0
  27. package/js/gripper.ts +29 -0
  28. package/js/helpers/__tests__/getAdapterName.test.ts +31 -0
  29. package/js/helpers/__tests__/getDeckDefFromLoadedLabware.test.ts +12 -0
  30. package/js/helpers/__tests__/getSimplestFlexDeckConfig.test.ts +176 -0
  31. package/js/helpers/__tests__/getVectorDifference.test.ts +25 -0
  32. package/js/helpers/__tests__/getVectorSum.test.ts +21 -0
  33. package/js/helpers/__tests__/labwareInference.test.ts +84 -0
  34. package/js/helpers/__tests__/orderWells.test.ts +87 -0
  35. package/js/helpers/__tests__/parseProtocolData.test.ts +165 -0
  36. package/js/helpers/__tests__/volume.test.ts +108 -0
  37. package/js/helpers/__tests__/wellSets.test.ts +352 -0
  38. package/js/helpers/get96Channel384WellPlateWells.ts +44 -0
  39. package/js/helpers/getAddressableAreasInProtocol.ts +98 -0
  40. package/js/helpers/getLoadedLabwareDefinitionsByUri.ts +30 -0
  41. package/js/helpers/getModuleVizDims.ts +118 -0
  42. package/js/helpers/getOccludedSlotCountForModule.ts +13 -0
  43. package/js/helpers/getSimplestFlexDeckConfig.ts +183 -0
  44. package/js/helpers/getVectorDifference.ts +12 -0
  45. package/js/helpers/getVectorSum.ts +12 -0
  46. package/js/helpers/getWellNamePerMultiTip.ts +86 -0
  47. package/js/helpers/getWellTotalVolume.ts +16 -0
  48. package/js/helpers/index.ts +348 -0
  49. package/js/helpers/labwareInference.ts +92 -0
  50. package/js/helpers/orderWells.ts +69 -0
  51. package/js/helpers/parseProtocolData.ts +141 -0
  52. package/js/helpers/volume.ts +35 -0
  53. package/js/helpers/wellIsRect.ts +6 -0
  54. package/js/helpers/wellSets.ts +155 -0
  55. package/js/index.ts +14 -0
  56. package/js/labwareTools/__tests__/__snapshots__/createIrregularLabware.test.ts.snap +3 -0
  57. package/js/labwareTools/__tests__/__snapshots__/createLabware.test.ts.snap +3 -0
  58. package/js/labwareTools/__tests__/createDefaultDisplayName.test.ts +111 -0
  59. package/js/labwareTools/__tests__/createIrregularLabware.test.ts +226 -0
  60. package/js/labwareTools/__tests__/createLabware.test.ts +147 -0
  61. package/js/labwareTools/index.ts +452 -0
  62. package/js/modules.ts +97 -0
  63. package/js/pipettes.ts +89 -0
  64. package/js/protocols.ts +290 -0
  65. package/js/schema.ts +80 -0
  66. package/js/scripts/generateDeckLayersFromSVG.js +46 -0
  67. package/js/titleCase.ts +30 -0
  68. package/js/types.ts +561 -0
  69. package/lib/js/__tests__/deckSchemas.test.d.ts +1 -0
  70. package/lib/js/__tests__/getAreSlotsAdjacent.test.d.ts +1 -0
  71. package/lib/js/__tests__/getWellNamePerMultiTip.test.d.ts +1 -0
  72. package/lib/js/__tests__/labwareDefQuirks.test.d.ts +1 -0
  73. package/lib/js/__tests__/labwareDefSchemaV1.test.d.ts +1 -0
  74. package/lib/js/__tests__/labwareDefSchemaV2.test.d.ts +1 -0
  75. package/lib/js/__tests__/moduleAccessors.test.d.ts +1 -0
  76. package/lib/js/__tests__/moduleSpecsSchema.test.d.ts +1 -0
  77. package/lib/js/__tests__/pipetteSchemaV2.test.d.ts +1 -0
  78. package/lib/js/__tests__/pipetteSpecSchemas.test.d.ts +1 -0
  79. package/lib/js/__tests__/pipettes.test.d.ts +1 -0
  80. package/lib/js/__tests__/protocolSchemaV4.test.d.ts +1 -0
  81. package/lib/js/__tests__/protocolSchemaV5.test.d.ts +1 -0
  82. package/lib/js/__tests__/protocolSchemaV6.test.d.ts +1 -0
  83. package/lib/js/__tests__/protocolSchemaV7.test.d.ts +1 -0
  84. package/lib/js/__tests__/protocolValidation.test.d.ts +1 -0
  85. package/lib/js/__tests__/sortWells.test.d.ts +1 -0
  86. package/lib/js/__tests__/splitWellsOnColumn.test.d.ts +1 -0
  87. package/lib/js/constants.d.ts +156 -0
  88. package/lib/js/cypressUtils.d.ts +1 -0
  89. package/lib/js/errors.d.ts +13 -0
  90. package/lib/js/fixtures.d.ts +13 -0
  91. package/lib/js/getLabware.d.ts +8 -0
  92. package/lib/js/gripper.d.ts +3 -0
  93. package/lib/js/helpers/__tests__/getAdapterName.test.d.ts +1 -0
  94. package/lib/js/helpers/__tests__/getDeckDefFromLoadedLabware.test.d.ts +1 -0
  95. package/lib/js/helpers/__tests__/getSimplestFlexDeckConfig.test.d.ts +1 -0
  96. package/lib/js/helpers/__tests__/getVectorDifference.test.d.ts +1 -0
  97. package/lib/js/helpers/__tests__/getVectorSum.test.d.ts +1 -0
  98. package/lib/js/helpers/__tests__/labwareInference.test.d.ts +1 -0
  99. package/lib/js/helpers/__tests__/orderWells.test.d.ts +1 -0
  100. package/lib/js/helpers/__tests__/parseProtocolData.test.d.ts +1 -0
  101. package/lib/js/helpers/__tests__/volume.test.d.ts +1 -0
  102. package/lib/js/helpers/__tests__/wellSets.test.d.ts +1 -0
  103. package/lib/js/helpers/get96Channel384WellPlateWells.d.ts +1 -0
  104. package/lib/js/helpers/getAddressableAreasInProtocol.d.ts +4 -0
  105. package/lib/js/helpers/getLoadedLabwareDefinitionsByUri.d.ts +5 -0
  106. package/lib/js/helpers/getModuleVizDims.d.ts +16 -0
  107. package/lib/js/helpers/getOccludedSlotCountForModule.d.ts +2 -0
  108. package/lib/js/helpers/getSimplestFlexDeckConfig.d.ts +14 -0
  109. package/lib/js/helpers/getVectorDifference.d.ts +2 -0
  110. package/lib/js/helpers/getVectorSum.d.ts +2 -0
  111. package/lib/js/helpers/getWellNamePerMultiTip.d.ts +3 -0
  112. package/lib/js/helpers/getWellTotalVolume.d.ts +2 -0
  113. package/lib/js/helpers/index.d.ts +44 -0
  114. package/lib/js/helpers/labwareInference.d.ts +16 -0
  115. package/lib/js/helpers/orderWells.d.ts +2 -0
  116. package/lib/js/helpers/parseProtocolData.d.ts +23 -0
  117. package/lib/js/helpers/volume.d.ts +4 -0
  118. package/lib/js/helpers/wellIsRect.d.ts +3 -0
  119. package/lib/js/helpers/wellSets.d.ts +9 -0
  120. package/lib/js/index.d.ts +14 -0
  121. package/lib/js/labwareTools/__tests__/createDefaultDisplayName.test.d.ts +1 -0
  122. package/lib/js/labwareTools/__tests__/createIrregularLabware.test.d.ts +1 -0
  123. package/lib/js/labwareTools/__tests__/createLabware.test.d.ts +1 -0
  124. package/lib/js/labwareTools/index.d.ts +65 -0
  125. package/lib/js/modules.d.ts +6 -0
  126. package/lib/js/pipettes.d.ts +13 -0
  127. package/lib/js/protocols.d.ts +3 -0
  128. package/lib/js/schema.d.ts +90 -0
  129. package/lib/js/titleCase.d.ts +1 -0
  130. package/lib/js/types.d.ts +398 -0
  131. package/package.json +1 -1
@@ -0,0 +1,290 @@
1
+ // Helper functions for validating protocols. Used only in tests right now but
2
+ // intended for use as the thing that turns something from a json document into
3
+ // a protocol inside the js ecosystem.
4
+
5
+ import Ajv from 'ajv'
6
+
7
+ import commandSchema8 from '../command/schemas/8.json'
8
+ import commandSchema7 from '../command/schemas/7.json'
9
+ import commandAnnotationSchema1 from '../commandAnnotation/schemas/1.json'
10
+ import liquidSchema1 from '../liquid/schemas/1.json'
11
+ import labwareSchema2 from '../labware/schemas/2.json'
12
+
13
+ import protocolSchema8 from '../protocol/schemas/8.json'
14
+ import protocolSchema7 from '../protocol/schemas/7.json'
15
+ import protocolSchema6 from '../protocol/schemas/6.json'
16
+ import protocolSchema5 from '../protocol/schemas/5.json'
17
+ import protocolSchema4 from '../protocol/schemas/4.json'
18
+ import protocolSchema3 from '../protocol/schemas/3.json'
19
+ import protocolSchema1 from '../protocol/schemas/1.json'
20
+
21
+ import type * as ProtocolSchemas from '../protocol'
22
+ import type { CreateCommand } from '../command/types'
23
+ import type { CommandAnnotation } from '../commandAnnotation/types'
24
+
25
+ export type { ProtocolSchemas }
26
+
27
+ const validateCommands8 = (
28
+ toValidate: ProtocolSchemas.ProtocolStructureV8
29
+ ): Promise<CreateCommand[]> =>
30
+ new Promise((resolve, reject) => {
31
+ const requestedSchema = toValidate.commandSchemaId
32
+ switch (requestedSchema) {
33
+ case 'opentronsCommandSchemaV8':
34
+ resolve(commandSchema8)
35
+ break
36
+ default:
37
+ // eslint-disable-next-line prefer-promise-reject-errors
38
+ reject([
39
+ {
40
+ keyword: 'Invalid command schema requested',
41
+ dataPath: requestedSchema,
42
+ schemaPath: '#/properties/commandSchemaId',
43
+ params: { allowedValues: ['opentronsCommandSchemaV8'] },
44
+ },
45
+ ])
46
+ break
47
+ }
48
+ }).then(
49
+ schema =>
50
+ new Promise((resolve, reject) => {
51
+ const generatedSchema = { type: 'array', items: schema }
52
+ const commandAjv = new Ajv({ allErrors: true, jsonPointers: true })
53
+ const validateCommands = commandAjv.compile(generatedSchema)
54
+ const ok = validateCommands(toValidate.commands)
55
+ if (!ok) {
56
+ // eslint-disable-next-line prefer-promise-reject-errors
57
+ reject(validateCommands.errors)
58
+ }
59
+ resolve(toValidate.commands)
60
+ })
61
+ )
62
+
63
+ const validateCommandAnnotations8 = (
64
+ toValidate: ProtocolSchemas.ProtocolStructureV8
65
+ ): Promise<CommandAnnotation[]> =>
66
+ new Promise((resolve, reject) => {
67
+ const requestedSchema = toValidate.commandAnnotationSchemaId
68
+ switch (requestedSchema) {
69
+ case 'opentronsCommandAnnotationSchemaV1':
70
+ resolve(commandAnnotationSchema1)
71
+ break
72
+ default:
73
+ // eslint-disable-next-line prefer-promise-reject-errors
74
+ reject([
75
+ {
76
+ keyword: 'Invalid command annotation schema requested',
77
+ dataPath: requestedSchema,
78
+ schemaPath: '#/properties/commandAnnotationSchemaId',
79
+ params: { allowedValues: ['opentronsCommandAnnotationSchemaV1'] },
80
+ },
81
+ ])
82
+ }
83
+ }).then(
84
+ (schema: any) =>
85
+ new Promise((resolve, reject) => {
86
+ const generatedSchema = {
87
+ type: 'array',
88
+ items: { $ref: 'opentronsCommandAnnotationSchemaV1' },
89
+ }
90
+ const annotationAjv = new Ajv({ allErrors: true, jsonPointers: true })
91
+ annotationAjv.addSchema(schema)
92
+ const validateAnnotations = annotationAjv.compile(generatedSchema)
93
+ const ok = validateAnnotations(toValidate.commandAnnotations)
94
+ if (!ok) {
95
+ // eslint-disable-next-line prefer-promise-reject-errors
96
+ reject(validateAnnotations.errors)
97
+ }
98
+ resolve(toValidate.commandAnnotations)
99
+ })
100
+ )
101
+
102
+ const validateLiquids8 = (
103
+ toValidate: ProtocolSchemas.ProtocolStructureV8
104
+ ): Promise<ProtocolSchemas.ProtocolFileV8['liquids']> =>
105
+ new Promise((resolve, reject) => {
106
+ const requestedSchema = toValidate.liquidSchemaId
107
+ switch (requestedSchema) {
108
+ case 'opentronsLiquidSchemaV1':
109
+ resolve(liquidSchema1)
110
+ break
111
+ default:
112
+ // eslint-disable-next-line prefer-promise-reject-errors
113
+ reject([
114
+ {
115
+ keyword: 'Invalid liquid schema requested',
116
+ dataPath: requestedSchema,
117
+ schemaPath: '#/properties/liquidSchemaId',
118
+ params: { allowedValues: ['opentronsLiquidSchemaV1'] },
119
+ },
120
+ ])
121
+ }
122
+ }).then(
123
+ schema =>
124
+ new Promise((resolve, reject) => {
125
+ const generatedSchema = {
126
+ type: 'object',
127
+ patternProperties: { '.+': schema },
128
+ }
129
+ const liquidAjv = new Ajv({ allErrors: true, jsonPointers: true })
130
+ const validateLiquids = liquidAjv.compile(generatedSchema)
131
+ const ok = validateLiquids(toValidate.liquids)
132
+ if (!ok) {
133
+ // eslint-disable-next-line prefer-promise-reject-errors
134
+ reject(validateLiquids.errors)
135
+ }
136
+ resolve(toValidate.liquids)
137
+ })
138
+ )
139
+
140
+ const validateLabware8 = (
141
+ toValidate: ProtocolSchemas.ProtocolStructureV8
142
+ ): Promise<ProtocolSchemas.ProtocolFileV8['labwareDefinitions']> =>
143
+ new Promise((resolve, reject) => {
144
+ const requestedSchema = toValidate.labwareDefinitionSchemaId
145
+ switch (requestedSchema) {
146
+ case 'opentronsLabwareSchemaV2':
147
+ resolve(labwareSchema2)
148
+ break
149
+ default:
150
+ // eslint-disable-next-line prefer-promise-reject-errors
151
+ reject([
152
+ {
153
+ keyword: 'Invalid labware schema requested',
154
+ dataPath: requestedSchema,
155
+ schemaPath: '#/properties/labwareSchemaId',
156
+ params: { allowedValues: ['opentronsLabwareSchemaV2'] },
157
+ },
158
+ ])
159
+ }
160
+ }).then(
161
+ schema =>
162
+ new Promise((resolve, reject) => {
163
+ const generatedSchema = {
164
+ type: 'object',
165
+ patternProperties: { '.+': schema },
166
+ }
167
+ const labwareAjv = new Ajv({ allErrors: true, jsonPointers: true })
168
+ const validateLabware = labwareAjv.compile(generatedSchema)
169
+ const ok = validateLabware(toValidate.labwareDefinitions)
170
+ if (!ok) {
171
+ // eslint-disable-next-line prefer-promise-reject-errors
172
+ reject(validateLabware.errors)
173
+ }
174
+ resolve(toValidate.labwareDefinitions)
175
+ })
176
+ )
177
+
178
+ const validate8 = (toValidate: any): Promise<ProtocolSchemas.ProtocolFileV8> =>
179
+ new Promise<ProtocolSchemas.ProtocolStructureV8>((resolve, reject) => {
180
+ const protoAjv = new Ajv({ allErrors: true, jsonPointers: true })
181
+ const validateProtocol = protoAjv.compile(protocolSchema8)
182
+ const valid = validateProtocol(toValidate)
183
+ if (!valid) {
184
+ // eslint-disable-next-line prefer-promise-reject-errors
185
+ reject(validateProtocol.errors)
186
+ }
187
+ const validatedProtocol = toValidate as ProtocolSchemas.ProtocolStructureV8
188
+ resolve(validatedProtocol)
189
+ })
190
+ .then(protocol =>
191
+ Promise.all([
192
+ validateCommands8(protocol),
193
+ validateCommandAnnotations8(protocol),
194
+ validateLiquids8(protocol),
195
+ validateLabware8(protocol),
196
+ ])
197
+ )
198
+ .then(() => Promise.resolve(toValidate as ProtocolSchemas.ProtocolFileV8))
199
+
200
+ const fakeAjvErrorForBadOTSharedSchema = (
201
+ requestedValue: any
202
+ ): Ajv.ErrorObject => ({
203
+ keyword: 'Invalid protocol schema requested',
204
+ dataPath: requestedValue,
205
+ schemaPath: '#/properties/$otSharedSchema',
206
+ params: {
207
+ allowedValues: [
208
+ '#/protocol/schemas/8',
209
+ '#/protocol/schemas/7',
210
+ '#/protocol/schemas/6',
211
+ '#/protocol/schemas/5',
212
+ '#/protocol/schemas/4',
213
+ '#/protocol/schemas/3',
214
+ '#/protocol/schemas/2',
215
+ '#/protocol/schemas/1',
216
+ ],
217
+ },
218
+ })
219
+
220
+ type ProtocolFileSub7 =
221
+ | ProtocolSchemas.ProtocolFileV6
222
+ | ProtocolSchemas.ProtocolFileV5<{}>
223
+ | ProtocolSchemas.ProtocolFileV4<{}>
224
+ | ProtocolSchemas.ProtocolFileV3<{}>
225
+ | ProtocolSchemas.ProtocolFileV1<{}>
226
+
227
+ const validateSub7 = (
228
+ toValidate: any,
229
+ schemaObj: any
230
+ ): Promise<ProtocolFileSub7> =>
231
+ new Promise((resolve, reject) => {
232
+ const ajv = new Ajv({ allErrors: true, jsonPointers: true })
233
+ ajv.addSchema(labwareSchema2)
234
+ const validateProtocol = ajv.compile(schemaObj)
235
+ const ok = validateProtocol(toValidate)
236
+ if (!ok) {
237
+ // eslint-disable-next-line prefer-promise-reject-errors
238
+ reject(validateProtocol.errors)
239
+ }
240
+ resolve(toValidate as ProtocolFileSub7)
241
+ })
242
+
243
+ const validate7 = (toValidate: any): Promise<ProtocolSchemas.ProtocolFileV7> =>
244
+ new Promise((resolve, reject) => {
245
+ const ajv = new Ajv({ allErrors: true, jsonPointers: true })
246
+ ajv.addSchema([commandSchema7, labwareSchema2])
247
+ const validateProtocol = ajv.compile(protocolSchema7)
248
+ const ok = validateProtocol(toValidate)
249
+ if (!ok) {
250
+ // eslint-disable-next-line prefer-promise-reject-errors
251
+ reject(validateProtocol.errors)
252
+ }
253
+ resolve(toValidate as ProtocolSchemas.ProtocolFileV7)
254
+ })
255
+
256
+ // note: rejects with an array of ajv errors
257
+ export function validate(
258
+ toValidate: any
259
+ ): Promise<ProtocolSchemas.JsonProtocolFile> {
260
+ // eslint-disable-next-line @typescript-eslint/dot-notation
261
+ const requestedProtocolSchema = toValidate['$otSharedSchema']
262
+ switch (requestedProtocolSchema) {
263
+ case '#/protocol/schemas/8':
264
+ return validate8(toValidate)
265
+ case '#/protocol/schemas/7':
266
+ return validate7(toValidate)
267
+ case '#/protocol/schemas/6':
268
+ return validateSub7(toValidate, protocolSchema6)
269
+ case '#/protocol/schemas/5':
270
+ return validateSub7(toValidate, protocolSchema5)
271
+ case '#/protocol/schemas/4':
272
+ return validateSub7(toValidate, protocolSchema4)
273
+ default:
274
+ if (!Object.keys(toValidate).includes('$otSharedSchema')) {
275
+ const v3SchemaVersion = toValidate.schemaVersion
276
+ if (v3SchemaVersion === '3.0.0') {
277
+ return validateSub7(toValidate, protocolSchema3)
278
+ }
279
+ const v1SchemaVersion = toValidate['protocol-schema']
280
+ if (v1SchemaVersion === '1.0.0') {
281
+ return validateSub7(toValidate, protocolSchema1)
282
+ }
283
+ }
284
+
285
+ return new Promise((resolve, reject) => {
286
+ // eslint-disable-next-line prefer-promise-reject-errors
287
+ reject([fakeAjvErrorForBadOTSharedSchema(requestedProtocolSchema)])
288
+ })
289
+ }
290
+ }
package/js/schema.ts ADDED
@@ -0,0 +1,80 @@
1
+ const NumberType = {
2
+ type: 'number',
3
+ }
4
+ const PositiveNumber = {
5
+ type: 'number',
6
+ minimum: 0,
7
+ }
8
+ const LabwareFormats = ['96-standard', '384-standard', 'trough', 'irregular']
9
+ // TODO IMMEDIATELY move to labware/flowTypes/
10
+ // TODO(mc, 2020-02-21) move to labware/schemas/1.json? delete?
11
+ // this only appears to be used in a single test file
12
+ // shared-data/js/__tests__/labwareDefSchemaV1.test.js
13
+ export const labwareSchemaV1 = {
14
+ type: 'object',
15
+ required: ['metadata', 'ordering', 'wells'],
16
+ additionalProperties: false,
17
+ properties: {
18
+ metadata: {
19
+ type: 'object',
20
+ required: ['name', 'format'],
21
+ properties: {
22
+ name: {
23
+ type: 'string',
24
+ },
25
+ format: {
26
+ enum: LabwareFormats,
27
+ },
28
+ deprecated: {
29
+ enum: [true],
30
+ },
31
+ displayName: {
32
+ type: 'string',
33
+ },
34
+ displayCategory: {
35
+ type: 'string',
36
+ },
37
+ isValidSource: {
38
+ enum: [false],
39
+ },
40
+ isTiprack: {
41
+ enum: [true],
42
+ },
43
+ tipVolume: PositiveNumber,
44
+ },
45
+ },
46
+ ordering: {
47
+ type: 'array',
48
+ items: {
49
+ type: 'array',
50
+ items: {
51
+ type: 'string',
52
+ },
53
+ },
54
+ },
55
+ wells: {
56
+ type: 'object',
57
+ patternProperties: {
58
+ '.*': {
59
+ // TODO: use ^[A-Z]+[1-9]+[0-9]*$ (eg A1, AB16, not A03) -- but make sure invalid well keys fail instead of slip past
60
+ type: 'object',
61
+ required: ['height', 'length', 'width', 'x', 'y', 'z'],
62
+ properties: {
63
+ height: NumberType,
64
+ length: PositiveNumber,
65
+ width: PositiveNumber,
66
+ x: NumberType,
67
+ y: NumberType,
68
+ z: NumberType,
69
+ // Optional
70
+ diameter: PositiveNumber,
71
+ // NOTE: presence of diameter indicates a circular well
72
+ depth: PositiveNumber,
73
+ // TODO Ian 2018-03-12: depth should be required, but is missing in MALDI-plate
74
+ 'total-liquid-volume': PositiveNumber,
75
+ },
76
+ },
77
+ },
78
+ },
79
+ },
80
+ }
@@ -0,0 +1,46 @@
1
+ const assert = require('assert')
2
+ const fs = require('fs')
3
+ const path = require('path')
4
+ const camelCase = require('lodash/camelCase')
5
+ const JSDOM = require('jsdom').JSDOM
6
+ const { promisify } = require('util')
7
+ const readFile = promisify(fs.readFile)
8
+ const writeFile = promisify(fs.writeFile)
9
+
10
+ // NOTE: the expected source SVG is an output SVG from Adobe Illustrator
11
+ // when using `Save as` or `Save as a Copy` and not `Export`
12
+ // Furthermore, the .ai file should contain no groups and all layers
13
+ // will be directly translated to layer groups in the JSON output
14
+
15
+ const svgPath = process.argv[2]
16
+ const buildDir = process.argv[3]
17
+
18
+ const USAGE =
19
+ 'Expected Params Not Present: (e.g. node ./scripts/generateDeckLayersFromSVG ./path/to/source/svg ./path/to/output/dir)'
20
+ assert(svgPath && buildDir, USAGE)
21
+
22
+ readFile(svgPath, 'utf8')
23
+ .then(data => {
24
+ const doc = new JSDOM(data, 'text/xml')
25
+ const groups = Array.from(doc.window.document.querySelectorAll('g'))
26
+
27
+ let layers = {}
28
+ groups.forEach(g => {
29
+ const groupId = g.getAttribute('id')
30
+ if (groupId && g.hasChildNodes()) {
31
+ const features = Array.from(g.querySelectorAll('path'))
32
+ const paths = features.map(f => ({
33
+ footprint: f.getAttribute('d').replace(/\s| {2}|\r\n|\n|\r/gm, ''), // clean up whitespaces and newlines
34
+ }))
35
+ layers = { ...layers, [camelCase(groupId)]: paths }
36
+ }
37
+ })
38
+
39
+ const jsonOutput = JSON.stringify(layers)
40
+ return writeFile(path.join(buildDir, 'deckLayers.json'), jsonOutput)
41
+ })
42
+ .then(() => process.exit(0))
43
+ .catch(error => {
44
+ console.error(error)
45
+ process.exit(1)
46
+ })
@@ -0,0 +1,30 @@
1
+ const SMALL_WORDS = /\b(?:an?d?|a[st]|because|but|by|en|for|i[fn]|neither|nor|o[fnr]|only|over|per|μL|so|some|tha[tn]|the|to|up|upon|vs?\.?|versus|via|when|with|without|yet)\b/i
2
+ const TOKENS = /[^\s:–—-]+|./g
3
+ const WHITESPACE = /\s/
4
+ const IS_MANUAL_CASE = /.(?=[A-Z]|\..)/
5
+ const ALPHANUMERIC_PATTERN = /[A-Za-z0-9\u00C0-\u00FF]/
6
+
7
+ export function titleCase(input: string): string {
8
+ let result = ''
9
+ let m: RegExpExecArray | null
10
+
11
+ while ((m = TOKENS.exec(input)) !== null) {
12
+ const { 0: token, index } = m
13
+
14
+ if (
15
+ !IS_MANUAL_CASE.test(token) &&
16
+ (!SMALL_WORDS.test(token) ||
17
+ index === 0 ||
18
+ index + token.length === input.length) &&
19
+ (input.charAt(index + token.length) !== ':' ||
20
+ WHITESPACE.test(input.charAt(index + token.length + 1)))
21
+ ) {
22
+ result += token.replace(ALPHANUMERIC_PATTERN, m => m.toUpperCase())
23
+ continue
24
+ }
25
+
26
+ result += token
27
+ }
28
+
29
+ return result
30
+ }