@morscherlab/mint-sdk 1.0.0-rc.2 → 1.0.0-rc.4

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 (178) hide show
  1. package/dist/components/AppSidebar.vue.d.ts +3 -3
  2. package/dist/components/ControlWorkspaceView.vue.d.ts +3 -3
  3. package/dist/components/DoseDesignWorkspaceView.vue.d.ts +1 -1
  4. package/dist/components/PluginWorkspaceView.vue.d.ts +3 -3
  5. package/dist/components/index.js +2 -2
  6. package/dist/{components-BhK-dW99.js → components-DafPc4rM.js} +3 -3
  7. package/dist/{components-BhK-dW99.js.map → components-DafPc4rM.js.map} +1 -1
  8. package/dist/composables/controlComponentBindings.d.ts +7 -0
  9. package/dist/composables/controlSchemaAdapters.d.ts +20 -0
  10. package/dist/composables/controlSchemaFormFields.d.ts +3 -0
  11. package/dist/composables/controlSchemaLayout.d.ts +7 -0
  12. package/dist/composables/controlSchemaNormalize.d.ts +15 -0
  13. package/dist/composables/controlSchemaUtils.d.ts +9 -0
  14. package/dist/composables/controlWorkspaceOptions.d.ts +2 -0
  15. package/dist/composables/index.js +3 -3
  16. package/dist/composables/useControlSchema.d.ts +4 -30
  17. package/dist/composables/useControlWorkspace.d.ts +5 -0
  18. package/dist/{composables-Bg7CFuNz.js → composables-BMkPQhVK.js} +2 -2
  19. package/dist/{composables-Bg7CFuNz.js.map → composables-BMkPQhVK.js.map} +1 -1
  20. package/dist/index.js +4 -4
  21. package/dist/install.js +2 -2
  22. package/dist/templates/adapters.d.ts +14 -47
  23. package/dist/templates/assayLookups.d.ts +3 -0
  24. package/dist/templates/assayMatrixAdapters.d.ts +6 -0
  25. package/dist/templates/assayMatrixBuilder.d.ts +2 -0
  26. package/dist/templates/assayNormalizers.d.ts +4 -0
  27. package/dist/templates/builderDefaults.d.ts +1 -0
  28. package/dist/templates/builderIdUtils.d.ts +4 -0
  29. package/dist/templates/builderPresetControls.d.ts +10 -0
  30. package/dist/templates/builderReadUtils.d.ts +8 -0
  31. package/dist/templates/builders.d.ts +26 -67
  32. package/dist/templates/calibrationCurveAdapters.d.ts +4 -0
  33. package/dist/templates/calibrationCurveBuilder.d.ts +2 -0
  34. package/dist/templates/calibrationNormalizers.d.ts +5 -0
  35. package/dist/templates/componentBindingCatalog.d.ts +25 -0
  36. package/dist/templates/componentBindingHelpers.d.ts +17 -0
  37. package/dist/templates/componentDoseResponseProps.d.ts +3 -0
  38. package/dist/templates/componentGenericProps.d.ts +8 -0
  39. package/dist/templates/componentPlateHelpers.d.ts +5 -0
  40. package/dist/templates/componentPlateMapProps.d.ts +3 -0
  41. package/dist/templates/componentPropsFactory.d.ts +3 -0
  42. package/dist/templates/componentQpcrPlateProps.d.ts +3 -0
  43. package/dist/templates/componentTargetResolvers.d.ts +5 -0
  44. package/dist/templates/componentTemplateProps.d.ts +3 -0
  45. package/dist/templates/controlSchemaClone.d.ts +4 -0
  46. package/dist/templates/controlSchemaConstants.d.ts +10 -0
  47. package/dist/templates/controlSchemaMerge.d.ts +3 -0
  48. package/dist/templates/controlSchemaTargets.d.ts +17 -0
  49. package/dist/templates/controlSchemaTypes.d.ts +4 -0
  50. package/dist/templates/controlSchemas.d.ts +4 -4
  51. package/dist/templates/defaultBioTemplateBuilder.d.ts +2 -0
  52. package/dist/templates/doseResponseAdapters.d.ts +4 -0
  53. package/dist/templates/doseResponseBuilder.d.ts +2 -0
  54. package/dist/templates/elisaAssayCollectionBuilder.d.ts +2 -0
  55. package/dist/templates/flowCytometryAssayCollectionBuilder.d.ts +2 -0
  56. package/dist/templates/flowCytometryPanelBuilder.d.ts +2 -0
  57. package/dist/templates/flowNormalizers.d.ts +8 -0
  58. package/dist/templates/flowPanelAdapters.d.ts +4 -0
  59. package/dist/templates/index.js +1 -1
  60. package/dist/templates/instrumentRunAdapterHelpers.d.ts +8 -0
  61. package/dist/templates/instrumentRunAdapters.d.ts +8 -0
  62. package/dist/templates/instrumentRunBuilder.d.ts +2 -0
  63. package/dist/templates/lcmsBatchCollectionBuilder.d.ts +2 -0
  64. package/dist/templates/plateGeometry.d.ts +4 -0
  65. package/dist/templates/plateMapAdapters.d.ts +3 -0
  66. package/dist/templates/plateMapBuilder.d.ts +2 -0
  67. package/dist/templates/presetControlSchemas.d.ts +534 -0
  68. package/dist/templates/protocolAdapters.d.ts +5 -0
  69. package/dist/templates/protocolNormalizers.d.ts +6 -0
  70. package/dist/templates/protocolStepsBuilder.d.ts +2 -0
  71. package/dist/templates/qpcrAdapters.d.ts +5 -0
  72. package/dist/templates/qpcrExpressionCollectionBuilder.d.ts +2 -0
  73. package/dist/templates/qpcrPlateBuilder.d.ts +2 -0
  74. package/dist/templates/reagentAdapters.d.ts +5 -0
  75. package/dist/templates/reagentListBuilder.d.ts +2 -0
  76. package/dist/templates/runNormalizers.d.ts +10 -0
  77. package/dist/templates/sampleNormalizers.d.ts +4 -0
  78. package/dist/templates/samplePrepAdapters.d.ts +4 -0
  79. package/dist/templates/samplePrepBuilder.d.ts +2 -0
  80. package/dist/templates/sampleSheetAdapters.d.ts +5 -0
  81. package/dist/templates/sampleSheetBuilder.d.ts +2 -0
  82. package/dist/templates/targetedMetabolomicsCollectionBuilder.d.ts +2 -0
  83. package/dist/templates/targetedMetabolomicsHelpers.d.ts +5 -0
  84. package/dist/templates/templateControlSchemas.d.ts +400 -0
  85. package/dist/templates/templateEnvelopes.d.ts +9 -0
  86. package/dist/templates/templatePackCollectionBuilder.d.ts +2 -0
  87. package/dist/templates/templatePresetCollectionBuilder.d.ts +18 -0
  88. package/dist/templates/templateValidators.d.ts +13 -0
  89. package/dist/templates/timeCourseAdapters.d.ts +5 -0
  90. package/dist/templates/timeCourseBuilder.d.ts +2 -0
  91. package/dist/templates/wellPlateScreenCollectionBuilder.d.ts +2 -0
  92. package/dist/templates/westernBlotAssayCollectionBuilder.d.ts +2 -0
  93. package/dist/{templates-BorLR_7p.js → templates-bUAWMn5L.js} +3574 -3428
  94. package/dist/templates-bUAWMn5L.js.map +1 -0
  95. package/dist/{useProtocolTemplates-n6AJqSqv.js → useProtocolTemplates-QZtHFFH2.js} +2 -2
  96. package/dist/{useProtocolTemplates-n6AJqSqv.js.map → useProtocolTemplates-QZtHFFH2.js.map} +1 -1
  97. package/package.json +1 -1
  98. package/src/composables/controlComponentBindings.ts +80 -0
  99. package/src/composables/controlSchemaAdapters.ts +196 -0
  100. package/src/composables/controlSchemaFormFields.ts +61 -0
  101. package/src/composables/controlSchemaLayout.ts +59 -0
  102. package/src/composables/controlSchemaNormalize.ts +101 -0
  103. package/src/composables/controlSchemaUtils.ts +36 -0
  104. package/src/composables/controlWorkspaceOptions.ts +21 -0
  105. package/src/composables/useControlSchema.ts +51 -628
  106. package/src/composables/useControlWorkspace.ts +207 -0
  107. package/src/templates/adapters.ts +89 -930
  108. package/src/templates/assayLookups.ts +33 -0
  109. package/src/templates/assayMatrixAdapters.ts +78 -0
  110. package/src/templates/assayMatrixBuilder.ts +59 -0
  111. package/src/templates/assayNormalizers.ts +34 -0
  112. package/src/templates/builderDefaults.ts +11 -0
  113. package/src/templates/builderIdUtils.ts +20 -0
  114. package/src/templates/builderPresetControls.ts +165 -0
  115. package/src/templates/builderReadUtils.ts +57 -0
  116. package/src/templates/builders.ts +122 -2350
  117. package/src/templates/calibrationCurveAdapters.ts +59 -0
  118. package/src/templates/calibrationCurveBuilder.ts +99 -0
  119. package/src/templates/calibrationNormalizers.ts +60 -0
  120. package/src/templates/componentBindingCatalog.ts +90 -0
  121. package/src/templates/componentBindingHelpers.ts +93 -0
  122. package/src/templates/componentBindings.ts +12 -461
  123. package/src/templates/componentDoseResponseProps.ts +42 -0
  124. package/src/templates/componentGenericProps.ts +77 -0
  125. package/src/templates/componentPlateHelpers.ts +29 -0
  126. package/src/templates/componentPlateMapProps.ts +32 -0
  127. package/src/templates/componentPropsFactory.ts +21 -0
  128. package/src/templates/componentQpcrPlateProps.ts +28 -0
  129. package/src/templates/componentTargetResolvers.ts +69 -0
  130. package/src/templates/componentTemplateProps.ts +78 -0
  131. package/src/templates/controlSchemaClone.ts +32 -0
  132. package/src/templates/controlSchemaConstants.ts +11 -0
  133. package/src/templates/controlSchemaMerge.ts +40 -0
  134. package/src/templates/controlSchemaTargets.ts +87 -0
  135. package/src/templates/controlSchemaTypes.ts +20 -0
  136. package/src/templates/controlSchemas.ts +22 -704
  137. package/src/templates/defaultBioTemplateBuilder.ts +124 -0
  138. package/src/templates/doseResponseAdapters.ts +45 -0
  139. package/src/templates/doseResponseBuilder.ts +44 -0
  140. package/src/templates/elisaAssayCollectionBuilder.ts +62 -0
  141. package/src/templates/flowCytometryAssayCollectionBuilder.ts +41 -0
  142. package/src/templates/flowCytometryPanelBuilder.ts +53 -0
  143. package/src/templates/flowNormalizers.ts +58 -0
  144. package/src/templates/flowPanelAdapters.ts +58 -0
  145. package/src/templates/instrumentRunAdapterHelpers.ts +94 -0
  146. package/src/templates/instrumentRunAdapters.ts +163 -0
  147. package/src/templates/instrumentRunBuilder.ts +97 -0
  148. package/src/templates/lcmsBatchCollectionBuilder.ts +38 -0
  149. package/src/templates/plateGeometry.ts +62 -0
  150. package/src/templates/plateMapAdapters.ts +36 -0
  151. package/src/templates/plateMapBuilder.ts +43 -0
  152. package/src/templates/presetControlSchemas.ts +258 -0
  153. package/src/templates/protocolAdapters.ts +69 -0
  154. package/src/templates/protocolNormalizers.ts +37 -0
  155. package/src/templates/protocolStepsBuilder.ts +36 -0
  156. package/src/templates/qpcrAdapters.ts +104 -0
  157. package/src/templates/qpcrExpressionCollectionBuilder.ts +33 -0
  158. package/src/templates/qpcrPlateBuilder.ts +96 -0
  159. package/src/templates/reagentAdapters.ts +77 -0
  160. package/src/templates/reagentListBuilder.ts +30 -0
  161. package/src/templates/runNormalizers.ts +63 -0
  162. package/src/templates/sampleNormalizers.ts +58 -0
  163. package/src/templates/samplePrepAdapters.ts +63 -0
  164. package/src/templates/samplePrepBuilder.ts +51 -0
  165. package/src/templates/sampleSheetAdapters.ts +75 -0
  166. package/src/templates/sampleSheetBuilder.ts +23 -0
  167. package/src/templates/targetedMetabolomicsCollectionBuilder.ts +79 -0
  168. package/src/templates/targetedMetabolomicsHelpers.ts +102 -0
  169. package/src/templates/templateControlSchemas.ts +320 -0
  170. package/src/templates/templateEnvelopes.ts +137 -0
  171. package/src/templates/templatePackCollectionBuilder.ts +23 -0
  172. package/src/templates/templatePresetCollectionBuilder.ts +139 -0
  173. package/src/templates/templateValidators.ts +414 -0
  174. package/src/templates/timeCourseAdapters.ts +73 -0
  175. package/src/templates/timeCourseBuilder.ts +64 -0
  176. package/src/templates/wellPlateScreenCollectionBuilder.ts +36 -0
  177. package/src/templates/westernBlotAssayCollectionBuilder.ts +68 -0
  178. package/dist/templates-BorLR_7p.js.map +0 -1
@@ -0,0 +1,59 @@
1
+ import { getTemplateData } from './templateEnvelopes'
2
+ import { validateCalibrationCurveData } from './templateValidators'
3
+ import type {
4
+ CalibrationCurveColumnsAdapterResult,
5
+ CalibrationCurveDataFrameAdapterResult,
6
+ CalibrationCurveRowsAdapterResult,
7
+ CalibrationCurveTemplate,
8
+ CalibrationCurveTemplateData,
9
+ } from './types'
10
+
11
+ export function toCalibrationCurveRows(
12
+ template: CalibrationCurveTemplate | CalibrationCurveTemplateData
13
+ ): CalibrationCurveRowsAdapterResult {
14
+ const data = getTemplateData(template, 'calibration-curve')
15
+ validateCalibrationCurveData(data)
16
+ return [...data.points]
17
+ .sort((a, b) => a.order - b.order)
18
+ .map(point => ({
19
+ id: point.id,
20
+ order: point.order,
21
+ role: point.role,
22
+ level: point.level,
23
+ concentration: point.concentration,
24
+ unit: point.unit,
25
+ expectedResponse: point.expectedResponse,
26
+ response: point.response,
27
+ replicate: point.replicate,
28
+ include: point.include,
29
+ status: point.status,
30
+ analyte: data.analyte,
31
+ model: data.model,
32
+ ...(point.metadata ?? {}),
33
+ }))
34
+ }
35
+
36
+ export function toCalibrationCurveColumns(): CalibrationCurveColumnsAdapterResult {
37
+ return [
38
+ { key: 'order', label: 'Order', sortable: true, align: 'right' },
39
+ { key: 'role', label: 'Role', sortable: true },
40
+ { key: 'level', label: 'Level', sortable: true },
41
+ { key: 'concentration', label: 'Concentration', sortable: true, align: 'right' },
42
+ { key: 'unit', label: 'Unit', sortable: true },
43
+ { key: 'expectedResponse', label: 'Expected', sortable: true, align: 'right' },
44
+ { key: 'response', label: 'Response', sortable: true, align: 'right' },
45
+ { key: 'replicate', label: 'Replicate', sortable: true, align: 'right' },
46
+ { key: 'include', label: 'Include', sortable: true },
47
+ { key: 'status', label: 'Status', sortable: true },
48
+ ]
49
+ }
50
+
51
+ export function toCalibrationCurveDataFrame(
52
+ template: CalibrationCurveTemplate | CalibrationCurveTemplateData
53
+ ): CalibrationCurveDataFrameAdapterResult {
54
+ return {
55
+ data: toCalibrationCurveRows(template),
56
+ columns: toCalibrationCurveColumns(),
57
+ rowKey: 'id',
58
+ }
59
+ }
@@ -0,0 +1,99 @@
1
+ import { idFromName } from './builderIdUtils'
2
+ import {
3
+ normalizeCalibrationAcceptance,
4
+ normalizeCalibrationPoint,
5
+ } from './calibrationNormalizers'
6
+ import { createTemplateEnvelope } from './templateEnvelopes'
7
+ import { validateCalibrationCurveData } from './templateValidators'
8
+ import type {
9
+ CalibrationCurveTemplate,
10
+ CalibrationCurveTemplateData,
11
+ CalibrationPoint,
12
+ CreateCalibrationCurveTemplateOptions,
13
+ } from './types'
14
+
15
+ export function createCalibrationCurveTemplate(
16
+ options: CreateCalibrationCurveTemplateOptions
17
+ ): CalibrationCurveTemplate {
18
+ const unit = options.unit ?? 'uM'
19
+ const points: CalibrationPoint[] = []
20
+ let order = 1
21
+
22
+ if (options.includeBlank !== false) {
23
+ points.push({
24
+ id: 'blank',
25
+ order,
26
+ role: 'blank',
27
+ level: 'Blank',
28
+ concentration: 0,
29
+ unit,
30
+ replicate: 1,
31
+ include: true,
32
+ status: 'planned',
33
+ metadata: {},
34
+ })
35
+ order += 1
36
+ }
37
+
38
+ const standardValues: number[] = []
39
+ for (const [index, concentration] of options.concentrations.entries()) {
40
+ if (typeof concentration !== 'number') {
41
+ const point = normalizeCalibrationPoint(concentration, unit, order, index)
42
+ points.push(point)
43
+ if (point.role === 'standard') standardValues.push(point.concentration)
44
+ order = Math.max(order, point.order + 1)
45
+ continue
46
+ }
47
+ standardValues.push(concentration)
48
+ points.push({
49
+ id: `std-${index + 1}`,
50
+ order,
51
+ role: 'standard',
52
+ level: `Standard ${index + 1}`,
53
+ concentration,
54
+ unit,
55
+ replicate: 1,
56
+ include: true,
57
+ status: 'planned',
58
+ metadata: {},
59
+ })
60
+ order += 1
61
+ }
62
+
63
+ if (options.includeQc !== false) {
64
+ const positiveValues = [...standardValues].filter(value => value > 0).sort((a, b) => a - b)
65
+ const qcValues = positiveValues.length === 0
66
+ ? []
67
+ : positiveValues[0] === positiveValues[positiveValues.length - 1]
68
+ ? [positiveValues[0]]
69
+ : [positiveValues[0], positiveValues[positiveValues.length - 1]]
70
+ for (const [index, concentration] of qcValues.entries()) {
71
+ const level = index === 0 ? 'QC low' : 'QC high'
72
+ points.push({
73
+ id: idFromName(level, `qc-${index + 1}`),
74
+ order,
75
+ role: 'qc',
76
+ level,
77
+ concentration,
78
+ unit,
79
+ replicate: 1,
80
+ include: true,
81
+ status: 'planned',
82
+ metadata: {},
83
+ })
84
+ order += 1
85
+ }
86
+ }
87
+
88
+ const data: CalibrationCurveTemplateData = {
89
+ analyte: options.analyte ?? 'Analyte',
90
+ model: options.model ?? 'linear',
91
+ xUnit: unit,
92
+ responseUnit: options.responseUnit ?? 'response',
93
+ points,
94
+ acceptance: normalizeCalibrationAcceptance(options.acceptance, options.includeBlank !== false),
95
+ metadata: options.metadata ?? {},
96
+ }
97
+ validateCalibrationCurveData(data)
98
+ return createTemplateEnvelope('calibration-curve', data, options.metadata ?? {})
99
+ }
@@ -0,0 +1,60 @@
1
+ import type {
2
+ CalibrationAcceptance,
3
+ CalibrationPoint,
4
+ CalibrationPointInput,
5
+ CompoundDoseSeries,
6
+ ControlDefinition,
7
+ } from './types'
8
+ import { idFromName } from './builderIdUtils'
9
+
10
+ export function normalizeCompound(compound: CompoundDoseSeries): CompoundDoseSeries {
11
+ return {
12
+ ...compound,
13
+ concentrations: [...compound.concentrations].sort((a, b) => b - a),
14
+ metadata: compound.metadata ?? {},
15
+ }
16
+ }
17
+
18
+ export function normalizeCalibrationAcceptance(
19
+ acceptance?: Partial<CalibrationAcceptance>,
20
+ requireBlank = true
21
+ ): CalibrationAcceptance {
22
+ return {
23
+ minRSquared: acceptance?.minRSquared ?? 0.99,
24
+ standardTolerancePercent: acceptance?.standardTolerancePercent ?? 15,
25
+ qcTolerancePercent: acceptance?.qcTolerancePercent ?? 20,
26
+ requireBlank: acceptance?.requireBlank ?? requireBlank,
27
+ metadata: acceptance?.metadata ?? {},
28
+ }
29
+ }
30
+
31
+ export function normalizeCalibrationPoint(
32
+ point: CalibrationPointInput,
33
+ unit: string,
34
+ order: number,
35
+ index: number
36
+ ): CalibrationPoint {
37
+ const role = point.role ?? 'standard'
38
+ const level = point.level || `${role.charAt(0).toUpperCase()}${role.slice(1)} ${index + 1}`
39
+ return {
40
+ id: point.id || idFromName(level, `${role}-${index + 1}`),
41
+ order: point.order ?? order,
42
+ role,
43
+ level,
44
+ concentration: point.concentration ?? 0,
45
+ unit: point.unit || unit,
46
+ expectedResponse: point.expectedResponse,
47
+ response: point.response,
48
+ replicate: point.replicate ?? 1,
49
+ include: point.include ?? true,
50
+ status: point.status ?? 'planned',
51
+ metadata: point.metadata ?? {},
52
+ }
53
+ }
54
+
55
+ export function normalizeControl(control: ControlDefinition): ControlDefinition {
56
+ return {
57
+ ...control,
58
+ metadata: control.metadata ?? {},
59
+ }
60
+ }
@@ -0,0 +1,90 @@
1
+ import type { TemplateId } from './types'
2
+
3
+ interface ComponentBinding {
4
+ id: string
5
+ template_id: TemplateId
6
+ component: string
7
+ adapters: readonly string[]
8
+ props: readonly string[]
9
+ description: string
10
+ importPath: '@morscherlab/mint-sdk'
11
+ }
12
+
13
+ export const templateComponentBindings = {
14
+ 'plate-map': [
15
+ binding('plate-map', 'PlateMapEditor', ['toPlateMapEditorState'], ['modelValue', 'format', 'samples'], 'Edit plate layouts from plate-map template data.'),
16
+ binding('plate-map', 'WellPlate', ['toWellPlateWells'], ['format', 'wells', 'sampleColors', 'legendItems'], 'Render the active plate as a well grid.'),
17
+ ],
18
+ 'sample-sheet': [
19
+ binding('sample-sheet', 'DataFrame', ['toTemplateDataFrame'], ['data', 'columns', 'rowKey'], 'Render sample metadata as a sortable table.'),
20
+ binding('sample-sheet', 'SampleSelector', ['toSampleOptions'], ['samples', 'modelValue'], 'Select samples from sample-sheet records.'),
21
+ ],
22
+ 'sample-prep': [
23
+ binding('sample-prep', 'DataFrame', ['toTemplateDataFrame'], ['data', 'columns', 'rowKey'], 'Render preparation steps as a table.'),
24
+ ],
25
+ 'dose-response': [
26
+ binding('dose-response', 'DoseCalculator', ['toDoseConditions'], ['mode', 'targetWells'], 'Configure serial dilution and apply concentrations to wells.'),
27
+ binding('dose-response', 'WellPlate', ['toDoseLayoutState'], ['format', 'wells', 'sampleColors', 'legendItems'], 'Render the optional dose-response plate layout.'),
28
+ ],
29
+ 'calibration-curve': [
30
+ binding('calibration-curve', 'DataFrame', ['toTemplateDataFrame'], ['data', 'columns', 'rowKey'], 'Render standards, QC, blanks, and response values.'),
31
+ ],
32
+ 'time-course': [
33
+ binding('time-course', 'ExperimentTimeline', ['toTimeCourseSteps'], ['modelValue', 'orientation'], 'Render time points as an ordered timeline.'),
34
+ binding('time-course', 'DataFrame', ['toTemplateDataFrame'], ['data', 'columns', 'rowKey'], 'Render longitudinal samples as a table.'),
35
+ ],
36
+ 'protocol-steps': [
37
+ binding('protocol-steps', 'ExperimentTimeline', ['toProtocolSteps'], ['modelValue', 'orientation', 'editable'], 'Render protocol steps as an editable timeline.'),
38
+ binding('protocol-steps', 'DataFrame', ['toTemplateDataFrame'], ['data', 'columns', 'rowKey'], 'Render protocol steps as a table.'),
39
+ ],
40
+ 'assay-matrix': [
41
+ binding('assay-matrix', 'DataFrame', ['toTemplateDataFrame'], ['data', 'columns', 'rowKey'], 'Render sample-by-feature measurements.'),
42
+ binding('assay-matrix', 'SampleSelector', ['toAssayMatrixSampleOptions'], ['samples', 'modelValue'], 'Select samples from assay-matrix records.'),
43
+ ],
44
+ 'reagent-list': [
45
+ binding('reagent-list', 'ReagentList', ['toReagentListItems'], ['modelValue'], 'Render reagents with lot, storage, and stock metadata.'),
46
+ binding('reagent-list', 'DataFrame', ['toTemplateDataFrame'], ['data', 'columns', 'rowKey'], 'Render reagents as a table.'),
47
+ ],
48
+ 'flow-cytometry-panel': [
49
+ binding('flow-cytometry-panel', 'DataFrame', ['toTemplateDataFrame'], ['data', 'columns', 'rowKey'], 'Render markers, fluorophores, detectors, and controls.'),
50
+ ],
51
+ 'instrument-run': [
52
+ binding('instrument-run', 'DataFrame', ['toTemplateDataFrame'], ['data', 'columns', 'rowKey'], 'Render acquisition queues, methods, QC, and run status.'),
53
+ binding(
54
+ 'instrument-run',
55
+ 'ScheduleCalendar',
56
+ ['toInstrumentRunScheduleEvents'],
57
+ ['modelValue', 'events', 'view', 'readonly', 'showNavigation', 'showViewToggle'],
58
+ 'Render acquisition queues as a scheduled run calendar.',
59
+ ),
60
+ binding(
61
+ 'instrument-run',
62
+ 'ExperimentTimeline',
63
+ ['toInstrumentRunSteps'],
64
+ ['modelValue', 'orientation', 'showDuration', 'editable'],
65
+ 'Render acquisition queues as an ordered run timeline.',
66
+ ),
67
+ ],
68
+ 'qpcr-plate': [
69
+ binding('qpcr-plate', 'WellPlate', ['toQpcrWellPlateWells'], ['format', 'wells', 'sampleColors', 'legendItems'], 'Render qPCR reactions on a well plate.'),
70
+ binding('qpcr-plate', 'DataFrame', ['toTemplateDataFrame'], ['data', 'columns', 'rowKey'], 'Render qPCR reactions, targets, controls, and Cq values.'),
71
+ ],
72
+ } satisfies Record<TemplateId, readonly ComponentBinding[]>
73
+
74
+ function binding(
75
+ templateId: TemplateId,
76
+ component: string,
77
+ adapters: readonly string[],
78
+ props: readonly string[],
79
+ description: string
80
+ ): ComponentBinding {
81
+ return {
82
+ id: `${templateId}:${component}`,
83
+ template_id: templateId,
84
+ component,
85
+ adapters,
86
+ props,
87
+ description,
88
+ importPath: '@morscherlab/mint-sdk',
89
+ }
90
+ }
@@ -0,0 +1,93 @@
1
+ interface CloneableComponentBinding {
2
+ adapters: readonly string[]
3
+ props: readonly string[]
4
+ }
5
+
6
+ interface NamedComponentBinding {
7
+ template_id: string
8
+ component: string
9
+ }
10
+
11
+ interface ComponentImportStatement {
12
+ statement: string
13
+ }
14
+
15
+ export function cloneBindingMap<TName extends string, TBinding extends CloneableComponentBinding>(
16
+ bindings: Record<TName, readonly TBinding[]>
17
+ ): Record<TName, TBinding[]> {
18
+ const result = {} as Record<TName, TBinding[]>
19
+ for (const name of Object.keys(bindings) as TName[]) {
20
+ result[name] = cloneBindings(bindings[name])
21
+ }
22
+ return result
23
+ }
24
+
25
+ export function cloneBindings<TBinding extends CloneableComponentBinding>(
26
+ bindings: readonly TBinding[]
27
+ ): TBinding[] {
28
+ return bindings.map(cloneBinding)
29
+ }
30
+
31
+ export function cloneBinding<TBinding extends CloneableComponentBinding>(binding: TBinding): TBinding {
32
+ return {
33
+ ...binding,
34
+ adapters: [...binding.adapters],
35
+ props: [...binding.props],
36
+ }
37
+ }
38
+
39
+ export function uniquePropsName(
40
+ binding: NamedComponentBinding,
41
+ usedNames: Map<string, number>
42
+ ): string {
43
+ const base = toCamelIdentifier(`${binding.template_id} ${binding.component} props`)
44
+ const count = usedNames.get(base) ?? 0
45
+ usedNames.set(base, count + 1)
46
+ return count === 0 ? base : `${base}${count + 1}`
47
+ }
48
+
49
+ function toCamelIdentifier(value: string): string {
50
+ const words = value
51
+ .replace(/([a-z0-9])([A-Z])/g, '$1 $2')
52
+ .split(/[^A-Za-z0-9]+/)
53
+ .filter(Boolean)
54
+
55
+ if (words.length === 0) return 'componentProps'
56
+
57
+ return words
58
+ .map((word, index) => {
59
+ const lower = word.toLowerCase()
60
+ return index === 0 ? lower : lower.charAt(0).toUpperCase() + lower.slice(1)
61
+ })
62
+ .join('')
63
+ }
64
+
65
+ export function toVueSfc(
66
+ imports: readonly ComponentImportStatement[],
67
+ setupLines: readonly string[],
68
+ template: string,
69
+ includeTargetTypeImport: boolean
70
+ ): string {
71
+ const importLines = [
72
+ ...imports.map(item => item.statement),
73
+ "import { toBioTemplateComponentProps } from '@morscherlab/mint-sdk/templates'",
74
+ ...(includeTargetTypeImport
75
+ ? ["import type { BioTemplateEnvelope, TemplateCollectionEnvelope } from '@morscherlab/mint-sdk/templates'"]
76
+ : []),
77
+ ]
78
+ const templateLines = template
79
+ ? template.split('\n').map(line => ` ${line}`).join('\n')
80
+ : ''
81
+
82
+ return [
83
+ '<script setup lang="ts">',
84
+ ...importLines,
85
+ '',
86
+ ...setupLines,
87
+ '</script>',
88
+ '',
89
+ '<template>',
90
+ templateLines,
91
+ '</template>',
92
+ ].join('\n')
93
+ }