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

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 (443) hide show
  1. package/dist/__tests__/components/AppTopBar.navigation.test.d.ts +1 -0
  2. package/dist/__tests__/components/DoseCalculatorVolumeField.test.d.ts +1 -0
  3. package/dist/__tests__/components/PlateMapEditorToolbarInternal.test.d.ts +1 -0
  4. package/dist/__tests__/components/PluginWorkspaceView.controls.test.d.ts +1 -0
  5. package/dist/__tests__/components/PluginWorkspaceView.navigation.test.d.ts +1 -0
  6. package/dist/__tests__/components/PluginWorkspaceView.shell.test.d.ts +1 -0
  7. package/dist/__tests__/components/ProtocolStep.presentation.test.d.ts +1 -0
  8. package/dist/__tests__/components/ProtocolStepEditor.state.test.d.ts +1 -0
  9. package/dist/__tests__/components/ProtocolStepParameterField.test.d.ts +1 -0
  10. package/dist/__tests__/components/ReagentList.presentation.test.d.ts +1 -0
  11. package/dist/__tests__/components/SampleSelector.colors.test.d.ts +1 -0
  12. package/dist/__tests__/components/SampleSelector.drag.test.d.ts +1 -0
  13. package/dist/__tests__/components/SampleSelector.groups.test.d.ts +1 -0
  14. package/dist/__tests__/components/SampleSelector.selection.test.d.ts +1 -0
  15. package/dist/__tests__/components/SampleSelectorSampleRow.test.d.ts +1 -0
  16. package/dist/__tests__/components/ScheduleCalendar.test.d.ts +1 -0
  17. package/dist/__tests__/components/SettingsModal.schema.test.d.ts +1 -0
  18. package/dist/__tests__/components/WellPlate.colors.test.d.ts +1 -0
  19. package/dist/__tests__/components/WellPlate.conditions.test.d.ts +1 -0
  20. package/dist/__tests__/components/WellPlate.geometry.test.d.ts +1 -0
  21. package/dist/__tests__/components/WellPlate.interaction.test.d.ts +1 -0
  22. package/dist/__tests__/components/WellPlate.legend.test.d.ts +1 -0
  23. package/dist/__tests__/components/WellPlate.rendering.test.d.ts +1 -0
  24. package/dist/__tests__/components/WellPlate.sampleDrop.test.d.ts +1 -0
  25. package/dist/__tests__/composables/autoGroup/classify.test.d.ts +1 -0
  26. package/dist/__tests__/composables/autoGroup/columns.test.d.ts +1 -0
  27. package/dist/__tests__/composables/autoGroup/compose.test.d.ts +1 -0
  28. package/dist/__tests__/composables/autoGroup/cooccurrence.test.d.ts +1 -0
  29. package/dist/__tests__/composables/autoGroup/fingerprint.test.d.ts +1 -0
  30. package/dist/__tests__/composables/autoGroup/integration.test.d.ts +1 -0
  31. package/dist/__tests__/composables/autoGroup/template.test.d.ts +1 -0
  32. package/dist/__tests__/composables/autoGroup/tokenize.test.d.ts +1 -0
  33. package/dist/__tests__/composables/useAutoGroupInputSources.test.d.ts +1 -0
  34. package/dist/__tests__/composables/useScheduleCalendarLayout.test.d.ts +1 -0
  35. package/dist/__tests__/docs/extractDocsComponents.test.d.ts +1 -0
  36. package/dist/__tests__/docs/extractDocsExports.test.d.ts +1 -0
  37. package/dist/__tests__/docs/extractDocsParsing.test.d.ts +1 -0
  38. package/dist/__tests__/docs/extractDocsTemplates.test.d.ts +1 -0
  39. package/dist/__tests__/docs/extractDocsTheme.test.d.ts +1 -0
  40. package/dist/components/AppTopBar.navigation.d.ts +11 -0
  41. package/dist/components/BaseButton.vue.d.ts +1 -1
  42. package/dist/components/BaseCheckbox.vue.d.ts +1 -1
  43. package/dist/components/BaseInput.vue.d.ts +2 -2
  44. package/dist/components/BasePill.vue.d.ts +1 -1
  45. package/dist/components/BaseRadioGroup.vue.d.ts +1 -1
  46. package/dist/components/BaseSelect.vue.d.ts +1 -1
  47. package/dist/components/BaseSlider.vue.d.ts +2 -2
  48. package/dist/components/BaseTextarea.vue.d.ts +2 -2
  49. package/dist/components/BaseToggle.vue.d.ts +1 -1
  50. package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +2 -2
  51. package/dist/components/BioTemplatePackWorkspaceView.vue.d.ts +1 -1
  52. package/dist/components/ColorSlider.vue.d.ts +2 -2
  53. package/dist/components/ConcentrationInput.vue.d.ts +2 -2
  54. package/dist/components/DatePicker.vue.d.ts +1 -1
  55. package/dist/components/DateTimePicker.vue.d.ts +2 -2
  56. package/dist/components/DoseCalculatorVolumeField.vue.d.ts +15 -0
  57. package/dist/components/DropdownButton.vue.d.ts +1 -1
  58. package/dist/components/FileUploader.vue.d.ts +2 -2
  59. package/dist/components/FormulaInput.vue.d.ts +2 -2
  60. package/dist/components/IconButton.vue.d.ts +1 -1
  61. package/dist/components/LoadingSpinner.vue.d.ts +1 -1
  62. package/dist/components/MoleculeInput.vue.d.ts +2 -2
  63. package/dist/components/MultiSelect.vue.d.ts +1 -1
  64. package/dist/components/NumberInput.vue.d.ts +1 -1
  65. package/dist/components/PlateMapEditor.vue.d.ts +6 -6
  66. package/dist/components/PluginWorkspaceView.controls.d.ts +28 -0
  67. package/dist/components/PluginWorkspaceView.navigation.d.ts +29 -0
  68. package/dist/components/PluginWorkspaceView.props.d.ts +151 -0
  69. package/dist/components/PluginWorkspaceView.shell.d.ts +19 -0
  70. package/dist/components/PluginWorkspaceView.vue.d.ts +46 -195
  71. package/dist/components/ProgressBar.vue.d.ts +1 -1
  72. package/dist/components/ProtocolStep.presentation.d.ts +4 -0
  73. package/dist/components/ProtocolStepEditor.state.d.ts +18 -0
  74. package/dist/components/ProtocolStepParameterField.vue.d.ts +12 -0
  75. package/dist/components/ReagentList.presentation.d.ts +16 -0
  76. package/dist/components/ResourceCard.vue.d.ts +1 -1
  77. package/dist/components/SampleSelector.colors.d.ts +13 -0
  78. package/dist/components/SampleSelector.drag.d.ts +24 -0
  79. package/dist/components/SampleSelector.groups.d.ts +15 -0
  80. package/dist/components/SampleSelector.selection.d.ts +26 -0
  81. package/dist/components/SampleSelector.vue.d.ts +4 -1
  82. package/dist/components/SampleSelectorSampleRow.vue.d.ts +21 -0
  83. package/dist/components/SegmentedControl.vue.d.ts +1 -1
  84. package/dist/components/SequenceInput.vue.d.ts +2 -2
  85. package/dist/components/SequenceProgressBar.vue.d.ts +1 -1
  86. package/dist/components/SettingsModal.schema.d.ts +9 -0
  87. package/dist/components/StatusIndicator.vue.d.ts +1 -1
  88. package/dist/components/TagsInput.vue.d.ts +2 -2
  89. package/dist/components/TimePicker.vue.d.ts +2 -2
  90. package/dist/components/TimeRangeInput.vue.d.ts +1 -1
  91. package/dist/components/UnitInput.vue.d.ts +2 -2
  92. package/dist/components/WellPlate.colors.d.ts +9 -0
  93. package/dist/components/WellPlate.conditions.d.ts +26 -0
  94. package/dist/components/WellPlate.geometry.d.ts +23 -0
  95. package/dist/components/WellPlate.interaction.d.ts +71 -0
  96. package/dist/components/WellPlate.legend.d.ts +2 -0
  97. package/dist/components/WellPlate.rendering.d.ts +24 -0
  98. package/dist/components/WellPlate.sampleDrop.d.ts +8 -0
  99. package/dist/components/WellPlate.vue.d.ts +1 -1
  100. package/dist/components/index.js +2 -2
  101. package/dist/components/internal/ActionItemInternal.vue.d.ts +1 -1
  102. package/dist/components/internal/PlateMapEditorToolbarInternal.vue.d.ts +28 -0
  103. package/dist/{components-BhK-dW99.js → components-DtHA2bgp.js} +3754 -2991
  104. package/dist/components-DtHA2bgp.js.map +1 -0
  105. package/dist/composables/autoGroup/classKey.d.ts +4 -0
  106. package/dist/composables/autoGroup/classify.d.ts +28 -0
  107. package/dist/composables/autoGroup/colors.d.ts +2 -0
  108. package/dist/composables/autoGroup/columns.d.ts +10 -0
  109. package/dist/composables/autoGroup/compose.d.ts +8 -0
  110. package/dist/composables/autoGroup/cooccurrence.d.ts +2 -0
  111. package/dist/composables/autoGroup/csv-shim.d.ts +2 -0
  112. package/dist/composables/autoGroup/fingerprint.d.ts +3 -0
  113. package/dist/composables/autoGroup/index.d.ts +16 -0
  114. package/dist/composables/autoGroup/replicatePreGroup.d.ts +38 -0
  115. package/dist/composables/autoGroup/template.d.ts +15 -0
  116. package/dist/composables/autoGroup/tokenize.d.ts +8 -0
  117. package/dist/composables/autoGroupConstants.d.ts +1 -0
  118. package/dist/composables/autoGroupGrouping.d.ts +3 -0
  119. package/dist/composables/controlComponentBindings.d.ts +7 -0
  120. package/dist/composables/controlSchemaAdapters.d.ts +20 -0
  121. package/dist/composables/controlSchemaDoseDesign.d.ts +11 -0
  122. package/dist/composables/controlSchemaFormFields.d.ts +3 -0
  123. package/dist/composables/controlSchemaLayout.d.ts +7 -0
  124. package/dist/composables/controlSchemaModel.d.ts +5 -0
  125. package/dist/composables/controlSchemaNormalize.d.ts +15 -0
  126. package/dist/composables/controlSchemaTypes.d.ts +305 -0
  127. package/dist/composables/controlSchemaUtils.d.ts +9 -0
  128. package/dist/composables/controlWorkspaceOptions.d.ts +2 -0
  129. package/dist/composables/formBuilderSchema.d.ts +18 -0
  130. package/dist/composables/index.js +3 -3
  131. package/dist/composables/pluginEndpointBuilder.d.ts +13 -0
  132. package/dist/composables/protocolTemplateCatalog.d.ts +26 -0
  133. package/dist/composables/useAutoGroup.d.ts +61 -74
  134. package/dist/composables/useAutoGroupInputSources.d.ts +32 -0
  135. package/dist/composables/useBioTemplateControls.d.ts +1 -1
  136. package/dist/composables/useBioTemplatePresetWorkspace.d.ts +1 -1
  137. package/dist/composables/useBioTemplateWorkspace.d.ts +1 -1
  138. package/dist/composables/useControlSchema.d.ts +8 -346
  139. package/dist/composables/useControlWorkspace.d.ts +5 -0
  140. package/dist/composables/useForm.d.ts +2 -33
  141. package/dist/composables/useFormBuilder.d.ts +2 -9
  142. package/dist/composables/useFormValidation.d.ts +34 -0
  143. package/dist/composables/usePluginClient.d.ts +1 -4
  144. package/dist/composables/useProtocolTemplates.d.ts +2 -24
  145. package/dist/composables/useScheduleCalendarLayout.d.ts +49 -0
  146. package/dist/{composables-Bg7CFuNz.js → composables-Dlg8jenH.js} +33 -31
  147. package/dist/composables-Dlg8jenH.js.map +1 -0
  148. package/dist/index.js +4 -4
  149. package/dist/install.js +2 -2
  150. package/dist/styles.css +547 -516
  151. package/dist/templates/adapters.d.ts +14 -47
  152. package/dist/templates/assayLookups.d.ts +3 -0
  153. package/dist/templates/assayMatrixAdapters.d.ts +6 -0
  154. package/dist/templates/assayMatrixBuilder.d.ts +2 -0
  155. package/dist/templates/assayNormalizers.d.ts +4 -0
  156. package/dist/templates/builderDefaults.d.ts +1 -0
  157. package/dist/templates/builderIdUtils.d.ts +4 -0
  158. package/dist/templates/builderPresetControls.d.ts +10 -0
  159. package/dist/templates/builderReadUtils.d.ts +8 -0
  160. package/dist/templates/builders.d.ts +26 -67
  161. package/dist/templates/calibrationCurveAdapters.d.ts +4 -0
  162. package/dist/templates/calibrationCurveBuilder.d.ts +2 -0
  163. package/dist/templates/calibrationNormalizers.d.ts +5 -0
  164. package/dist/templates/componentBindingCatalog.d.ts +25 -0
  165. package/dist/templates/componentBindingHelpers.d.ts +17 -0
  166. package/dist/templates/componentDoseResponseProps.d.ts +3 -0
  167. package/dist/templates/componentGenericProps.d.ts +8 -0
  168. package/dist/templates/componentPlateHelpers.d.ts +5 -0
  169. package/dist/templates/componentPlateMapProps.d.ts +3 -0
  170. package/dist/templates/componentPropsFactory.d.ts +3 -0
  171. package/dist/templates/componentQpcrPlateProps.d.ts +3 -0
  172. package/dist/templates/componentTargetResolvers.d.ts +5 -0
  173. package/dist/templates/componentTemplateProps.d.ts +3 -0
  174. package/dist/templates/controlSchemaClone.d.ts +4 -0
  175. package/dist/templates/controlSchemaConstants.d.ts +10 -0
  176. package/dist/templates/controlSchemaMerge.d.ts +3 -0
  177. package/dist/templates/controlSchemaTargets.d.ts +17 -0
  178. package/dist/templates/controlSchemaTypes.d.ts +4 -0
  179. package/dist/templates/controlSchemas.d.ts +4 -4
  180. package/dist/templates/defaultBioTemplateBuilder.d.ts +2 -0
  181. package/dist/templates/doseResponseAdapters.d.ts +4 -0
  182. package/dist/templates/doseResponseBuilder.d.ts +2 -0
  183. package/dist/templates/elisaAssayCollectionBuilder.d.ts +2 -0
  184. package/dist/templates/flowCytometryAssayCollectionBuilder.d.ts +2 -0
  185. package/dist/templates/flowCytometryPanelBuilder.d.ts +2 -0
  186. package/dist/templates/flowNormalizers.d.ts +8 -0
  187. package/dist/templates/flowPanelAdapters.d.ts +4 -0
  188. package/dist/templates/index.js +1 -1
  189. package/dist/templates/instrumentRunAdapterHelpers.d.ts +8 -0
  190. package/dist/templates/instrumentRunAdapters.d.ts +8 -0
  191. package/dist/templates/instrumentRunBuilder.d.ts +2 -0
  192. package/dist/templates/lcmsBatchCollectionBuilder.d.ts +2 -0
  193. package/dist/templates/plateGeometry.d.ts +4 -0
  194. package/dist/templates/plateMapAdapters.d.ts +3 -0
  195. package/dist/templates/plateMapBuilder.d.ts +2 -0
  196. package/dist/templates/presetControlSchemas.d.ts +534 -0
  197. package/dist/templates/protocolAdapters.d.ts +5 -0
  198. package/dist/templates/protocolNormalizers.d.ts +6 -0
  199. package/dist/templates/protocolStepsBuilder.d.ts +2 -0
  200. package/dist/templates/qpcrAdapters.d.ts +5 -0
  201. package/dist/templates/qpcrExpressionCollectionBuilder.d.ts +2 -0
  202. package/dist/templates/qpcrPlateBuilder.d.ts +2 -0
  203. package/dist/templates/reagentAdapters.d.ts +5 -0
  204. package/dist/templates/reagentListBuilder.d.ts +2 -0
  205. package/dist/templates/runNormalizers.d.ts +10 -0
  206. package/dist/templates/sampleNormalizers.d.ts +4 -0
  207. package/dist/templates/samplePrepAdapters.d.ts +4 -0
  208. package/dist/templates/samplePrepBuilder.d.ts +2 -0
  209. package/dist/templates/sampleSheetAdapters.d.ts +5 -0
  210. package/dist/templates/sampleSheetBuilder.d.ts +2 -0
  211. package/dist/templates/targetedMetabolomicsCollectionBuilder.d.ts +2 -0
  212. package/dist/templates/targetedMetabolomicsHelpers.d.ts +5 -0
  213. package/dist/templates/templateAdapterTypes.d.ts +48 -0
  214. package/dist/templates/templateControlSchemas.d.ts +400 -0
  215. package/dist/templates/templateCreateOptions.d.ts +165 -0
  216. package/dist/templates/templateEnvelopes.d.ts +9 -0
  217. package/dist/templates/templatePackCollectionBuilder.d.ts +2 -0
  218. package/dist/templates/templatePresetCollectionBuilder.d.ts +18 -0
  219. package/dist/templates/templateQpcrTypes.d.ts +42 -0
  220. package/dist/templates/templateValidators.d.ts +13 -0
  221. package/dist/templates/timeCourseAdapters.d.ts +5 -0
  222. package/dist/templates/timeCourseBuilder.d.ts +2 -0
  223. package/dist/templates/types.d.ts +5 -250
  224. package/dist/templates/wellPlateScreenCollectionBuilder.d.ts +2 -0
  225. package/dist/templates/westernBlotAssayCollectionBuilder.d.ts +2 -0
  226. package/dist/{templates-BorLR_7p.js → templates-DtdUvJ4c.js} +3565 -3411
  227. package/dist/templates-DtdUvJ4c.js.map +1 -0
  228. package/dist/types/auto-group.d.ts +79 -9
  229. package/dist/types/componentLabTypes.d.ts +161 -0
  230. package/dist/types/componentWorkflowTypes.d.ts +150 -0
  231. package/dist/types/components.d.ts +2 -311
  232. package/dist/{useProtocolTemplates-n6AJqSqv.js → useProtocolTemplates-Bm5vyH4_.js} +1220 -454
  233. package/dist/useProtocolTemplates-Bm5vyH4_.js.map +1 -0
  234. package/package.json +1 -1
  235. package/src/__tests__/components/AppTopBar.navigation.test.ts +70 -0
  236. package/src/__tests__/components/DoseCalculatorVolumeField.test.ts +53 -0
  237. package/src/__tests__/components/PlateMapEditorToolbarInternal.test.ts +54 -0
  238. package/src/__tests__/components/PluginWorkspaceView.controls.test.ts +156 -0
  239. package/src/__tests__/components/PluginWorkspaceView.navigation.test.ts +102 -0
  240. package/src/__tests__/components/PluginWorkspaceView.shell.test.ts +41 -0
  241. package/src/__tests__/components/ProtocolStep.presentation.test.ts +31 -0
  242. package/src/__tests__/components/ProtocolStepEditor.state.test.ts +165 -0
  243. package/src/__tests__/components/ProtocolStepParameterField.test.ts +44 -0
  244. package/src/__tests__/components/ReagentList.presentation.test.ts +68 -0
  245. package/src/__tests__/components/SampleSelector.colors.test.ts +49 -0
  246. package/src/__tests__/components/SampleSelector.drag.test.ts +100 -0
  247. package/src/__tests__/components/SampleSelector.groups.test.ts +81 -0
  248. package/src/__tests__/components/SampleSelector.selection.test.ts +70 -0
  249. package/src/__tests__/components/SampleSelector.test.ts +32 -0
  250. package/src/__tests__/components/SampleSelectorSampleRow.test.ts +37 -0
  251. package/src/__tests__/components/ScheduleCalendar.test.ts +44 -0
  252. package/src/__tests__/components/SettingsModal.schema.test.ts +97 -0
  253. package/src/__tests__/components/WellPlate.colors.test.ts +28 -0
  254. package/src/__tests__/components/WellPlate.conditions.test.ts +68 -0
  255. package/src/__tests__/components/WellPlate.geometry.test.ts +54 -0
  256. package/src/__tests__/components/WellPlate.interaction.test.ts +171 -0
  257. package/src/__tests__/components/WellPlate.legend.test.ts +13 -0
  258. package/src/__tests__/components/WellPlate.rendering.test.ts +122 -0
  259. package/src/__tests__/components/WellPlate.sampleDrop.test.ts +70 -0
  260. package/src/__tests__/composables/autoGroup/classify.test.ts +107 -0
  261. package/src/__tests__/composables/autoGroup/columns.test.ts +135 -0
  262. package/src/__tests__/composables/autoGroup/compose.test.ts +227 -0
  263. package/src/__tests__/composables/autoGroup/cooccurrence.test.ts +91 -0
  264. package/src/__tests__/composables/autoGroup/fingerprint.test.ts +50 -0
  265. package/src/__tests__/composables/autoGroup/integration.test.ts +79 -0
  266. package/src/__tests__/composables/autoGroup/template.test.ts +70 -0
  267. package/src/__tests__/composables/autoGroup/tokenize.test.ts +33 -0
  268. package/src/__tests__/composables/useAutoGroup.test.ts +129 -625
  269. package/src/__tests__/composables/useAutoGroupInputSources.test.ts +107 -0
  270. package/src/__tests__/composables/useControlSchema.test.ts +23 -0
  271. package/src/__tests__/composables/useScheduleCalendarLayout.test.ts +89 -0
  272. package/src/__tests__/docs/extractDocsComponents.test.ts +142 -0
  273. package/src/__tests__/docs/extractDocsExports.test.ts +77 -0
  274. package/src/__tests__/docs/extractDocsParsing.test.ts +69 -0
  275. package/src/__tests__/docs/extractDocsTemplates.test.ts +54 -0
  276. package/src/__tests__/docs/extractDocsTheme.test.ts +89 -0
  277. package/src/__tests__/docs/frontendDocsCatalog.test.ts +1 -1
  278. package/src/__tests__/fixtures/auto-group/mixed-lc-ms-batch.txt +187 -0
  279. package/src/components/AppSidebar.vue +2 -6
  280. package/src/components/AppTopBar.navigation.ts +62 -0
  281. package/src/components/AppTopBar.vue +17 -44
  282. package/src/components/AutoGroupModal.story.vue +50 -0
  283. package/src/components/AutoGroupModal.vue +441 -158
  284. package/src/components/ControlWorkspaceView.vue +2 -6
  285. package/src/components/DoseCalculator.vue +13 -73
  286. package/src/components/DoseCalculatorVolumeField.vue +61 -0
  287. package/src/components/ExperimentTimeline.vue +6 -31
  288. package/src/components/FormBuilder.vue +2 -7
  289. package/src/components/PlateMapEditor.vue +32 -106
  290. package/src/components/PluginWorkspaceView.controls.ts +182 -0
  291. package/src/components/PluginWorkspaceView.navigation.ts +106 -0
  292. package/src/components/PluginWorkspaceView.props.ts +174 -0
  293. package/src/components/PluginWorkspaceView.shell.ts +66 -0
  294. package/src/components/PluginWorkspaceView.vue +85 -404
  295. package/src/components/ProtocolStep.presentation.ts +31 -0
  296. package/src/components/ProtocolStepEditor.state.ts +104 -0
  297. package/src/components/ProtocolStepEditor.vue +48 -179
  298. package/src/components/ProtocolStepParameterField.vue +134 -0
  299. package/src/components/ReagentList.presentation.ts +105 -0
  300. package/src/components/ReagentList.vue +16 -79
  301. package/src/components/SampleSelector.colors.ts +43 -0
  302. package/src/components/SampleSelector.drag.ts +164 -0
  303. package/src/components/SampleSelector.groups.ts +109 -0
  304. package/src/components/SampleSelector.selection.ts +103 -0
  305. package/src/components/SampleSelector.vue +82 -349
  306. package/src/components/SampleSelectorSampleRow.vue +64 -0
  307. package/src/components/ScheduleCalendar.vue +44 -199
  308. package/src/components/SettingsModal.schema.ts +71 -0
  309. package/src/components/SettingsModal.vue +16 -46
  310. package/src/components/WellPlate.colors.ts +56 -0
  311. package/src/components/WellPlate.conditions.ts +100 -0
  312. package/src/components/WellPlate.geometry.ts +91 -0
  313. package/src/components/WellPlate.interaction.ts +272 -0
  314. package/src/components/WellPlate.legend.ts +8 -0
  315. package/src/components/WellPlate.rendering.ts +105 -0
  316. package/src/components/WellPlate.sampleDrop.ts +73 -0
  317. package/src/components/WellPlate.vue +102 -550
  318. package/src/components/internal/PlateMapEditorToolbarInternal.vue +128 -0
  319. package/src/composables/autoGroup/classKey.ts +5 -0
  320. package/src/composables/autoGroup/classify.ts +205 -0
  321. package/src/composables/autoGroup/colors.ts +6 -0
  322. package/src/composables/autoGroup/columns.ts +226 -0
  323. package/src/composables/autoGroup/compose.ts +156 -0
  324. package/src/composables/autoGroup/cooccurrence.ts +46 -0
  325. package/src/composables/autoGroup/csv-shim.ts +44 -0
  326. package/src/composables/autoGroup/fingerprint.ts +49 -0
  327. package/src/composables/autoGroup/index.ts +20 -0
  328. package/src/composables/autoGroup/replicatePreGroup.ts +90 -0
  329. package/src/composables/autoGroup/template.ts +126 -0
  330. package/src/composables/autoGroup/tokenize.ts +41 -0
  331. package/src/composables/autoGroup/vocab.json +67 -0
  332. package/src/composables/autoGroupConstants.ts +4 -0
  333. package/src/composables/autoGroupGrouping.ts +148 -0
  334. package/src/composables/controlComponentBindings.ts +80 -0
  335. package/src/composables/controlSchemaAdapters.ts +196 -0
  336. package/src/composables/controlSchemaDoseDesign.ts +215 -0
  337. package/src/composables/controlSchemaFormFields.ts +61 -0
  338. package/src/composables/controlSchemaLayout.ts +59 -0
  339. package/src/composables/controlSchemaModel.ts +163 -0
  340. package/src/composables/controlSchemaNormalize.ts +101 -0
  341. package/src/composables/controlSchemaTypes.ts +364 -0
  342. package/src/composables/controlSchemaUtils.ts +36 -0
  343. package/src/composables/controlWorkspaceOptions.ts +21 -0
  344. package/src/composables/formBuilderSchema.ts +153 -0
  345. package/src/composables/pluginEndpointBuilder.ts +203 -0
  346. package/src/composables/protocolTemplateCatalog.ts +325 -0
  347. package/src/composables/useAutoGroup.ts +395 -549
  348. package/src/composables/useAutoGroupInputSources.ts +147 -0
  349. package/src/composables/useBioTemplateControls.ts +1 -1
  350. package/src/composables/useBioTemplatePresetWorkspace.ts +1 -1
  351. package/src/composables/useBioTemplateWorkspace.ts +1 -1
  352. package/src/composables/useControlSchema.ts +64 -1312
  353. package/src/composables/useControlWorkspace.ts +201 -0
  354. package/src/composables/useForm.ts +5 -187
  355. package/src/composables/useFormBuilder.ts +11 -153
  356. package/src/composables/useFormValidation.ts +154 -0
  357. package/src/composables/usePluginClient.ts +10 -193
  358. package/src/composables/useProtocolTemplates.ts +10 -328
  359. package/src/composables/useScheduleCalendarLayout.ts +287 -0
  360. package/src/styles/components/auto-group-modal.css +248 -310
  361. package/src/templates/adapters.ts +89 -930
  362. package/src/templates/assayLookups.ts +33 -0
  363. package/src/templates/assayMatrixAdapters.ts +78 -0
  364. package/src/templates/assayMatrixBuilder.ts +59 -0
  365. package/src/templates/assayNormalizers.ts +34 -0
  366. package/src/templates/builderDefaults.ts +11 -0
  367. package/src/templates/builderIdUtils.ts +20 -0
  368. package/src/templates/builderPresetControls.ts +165 -0
  369. package/src/templates/builderReadUtils.ts +57 -0
  370. package/src/templates/builders.ts +122 -2350
  371. package/src/templates/calibrationCurveAdapters.ts +59 -0
  372. package/src/templates/calibrationCurveBuilder.ts +99 -0
  373. package/src/templates/calibrationNormalizers.ts +60 -0
  374. package/src/templates/componentBindingCatalog.ts +90 -0
  375. package/src/templates/componentBindingHelpers.ts +93 -0
  376. package/src/templates/componentBindings.ts +12 -461
  377. package/src/templates/componentDoseResponseProps.ts +42 -0
  378. package/src/templates/componentGenericProps.ts +77 -0
  379. package/src/templates/componentPlateHelpers.ts +29 -0
  380. package/src/templates/componentPlateMapProps.ts +32 -0
  381. package/src/templates/componentPropsFactory.ts +21 -0
  382. package/src/templates/componentQpcrPlateProps.ts +28 -0
  383. package/src/templates/componentTargetResolvers.ts +69 -0
  384. package/src/templates/componentTemplateProps.ts +78 -0
  385. package/src/templates/controlSchemaClone.ts +32 -0
  386. package/src/templates/controlSchemaConstants.ts +11 -0
  387. package/src/templates/controlSchemaMerge.ts +40 -0
  388. package/src/templates/controlSchemaTargets.ts +87 -0
  389. package/src/templates/controlSchemaTypes.ts +20 -0
  390. package/src/templates/controlSchemas.ts +22 -704
  391. package/src/templates/defaultBioTemplateBuilder.ts +124 -0
  392. package/src/templates/doseResponseAdapters.ts +45 -0
  393. package/src/templates/doseResponseBuilder.ts +44 -0
  394. package/src/templates/elisaAssayCollectionBuilder.ts +62 -0
  395. package/src/templates/flowCytometryAssayCollectionBuilder.ts +41 -0
  396. package/src/templates/flowCytometryPanelBuilder.ts +53 -0
  397. package/src/templates/flowNormalizers.ts +58 -0
  398. package/src/templates/flowPanelAdapters.ts +58 -0
  399. package/src/templates/instrumentRunAdapterHelpers.ts +94 -0
  400. package/src/templates/instrumentRunAdapters.ts +163 -0
  401. package/src/templates/instrumentRunBuilder.ts +97 -0
  402. package/src/templates/lcmsBatchCollectionBuilder.ts +38 -0
  403. package/src/templates/plateGeometry.ts +62 -0
  404. package/src/templates/plateMapAdapters.ts +36 -0
  405. package/src/templates/plateMapBuilder.ts +43 -0
  406. package/src/templates/presetControlSchemas.ts +258 -0
  407. package/src/templates/protocolAdapters.ts +69 -0
  408. package/src/templates/protocolNormalizers.ts +37 -0
  409. package/src/templates/protocolStepsBuilder.ts +36 -0
  410. package/src/templates/qpcrAdapters.ts +104 -0
  411. package/src/templates/qpcrExpressionCollectionBuilder.ts +33 -0
  412. package/src/templates/qpcrPlateBuilder.ts +96 -0
  413. package/src/templates/reagentAdapters.ts +77 -0
  414. package/src/templates/reagentListBuilder.ts +30 -0
  415. package/src/templates/runNormalizers.ts +63 -0
  416. package/src/templates/sampleNormalizers.ts +58 -0
  417. package/src/templates/samplePrepAdapters.ts +63 -0
  418. package/src/templates/samplePrepBuilder.ts +51 -0
  419. package/src/templates/sampleSheetAdapters.ts +75 -0
  420. package/src/templates/sampleSheetBuilder.ts +23 -0
  421. package/src/templates/targetedMetabolomicsCollectionBuilder.ts +79 -0
  422. package/src/templates/targetedMetabolomicsHelpers.ts +102 -0
  423. package/src/templates/templateAdapterTypes.ts +58 -0
  424. package/src/templates/templateControlSchemas.ts +320 -0
  425. package/src/templates/templateCreateOptions.ts +208 -0
  426. package/src/templates/templateEnvelopes.ts +137 -0
  427. package/src/templates/templatePackCollectionBuilder.ts +23 -0
  428. package/src/templates/templatePresetCollectionBuilder.ts +139 -0
  429. package/src/templates/templateQpcrTypes.ts +48 -0
  430. package/src/templates/templateValidators.ts +414 -0
  431. package/src/templates/timeCourseAdapters.ts +73 -0
  432. package/src/templates/timeCourseBuilder.ts +64 -0
  433. package/src/templates/types.ts +79 -275
  434. package/src/templates/wellPlateScreenCollectionBuilder.ts +36 -0
  435. package/src/templates/westernBlotAssayCollectionBuilder.ts +68 -0
  436. package/src/types/auto-group.ts +107 -9
  437. package/src/types/componentLabTypes.ts +235 -0
  438. package/src/types/componentWorkflowTypes.ts +190 -0
  439. package/src/types/components.ts +74 -424
  440. package/dist/components-BhK-dW99.js.map +0 -1
  441. package/dist/composables-Bg7CFuNz.js.map +0 -1
  442. package/dist/templates-BorLR_7p.js.map +0 -1
  443. package/dist/useProtocolTemplates-n6AJqSqv.js.map +0 -1
@@ -0,0 +1,135 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { inferRole, parseNumeric, buildClassSchema } from '../../../composables/autoGroup/columns'
3
+
4
+ describe('parseNumeric', () => {
5
+ it('parses value+unit tokens', () => {
6
+ expect(parseNumeric('5nM')).toEqual({ value: 5, unit: 'nM', raw: '5nM' })
7
+ expect(parseNumeric('400ulES')).toEqual({ value: 400, unit: 'ulES', raw: '400ulES' })
8
+ expect(parseNumeric('1ul')).toEqual({ value: 1, unit: 'ul', raw: '1ul' })
9
+ })
10
+
11
+ it('decodes the dot-encoded decimal point', () => {
12
+ expect(parseNumeric('0dot5ul')).toEqual({ value: 0.5, unit: 'ul', raw: '0dot5ul' })
13
+ })
14
+
15
+ it('parses ratios via the dedicated branch', () => {
16
+ expect(parseNumeric('1to100')).toEqual({ value: 0.01, unit: 'ratio', raw: '1to100' })
17
+ expect(parseNumeric('1to10')).toEqual({ value: 0.1, unit: 'ratio', raw: '1to10' })
18
+ })
19
+
20
+ it('rejects bare IDs, dates, and pure numbers', () => {
21
+ expect(parseNumeric('M10')).toBeNull()
22
+ expect(parseNumeric('exp281')).toBeNull()
23
+ expect(parseNumeric('260415')).toBeNull()
24
+ expect(parseNumeric('123')).toBeNull()
25
+ })
26
+ })
27
+
28
+ describe('inferRole', () => {
29
+ const make = (values: string[]) => ({
30
+ values,
31
+ position: 0,
32
+ totalPositions: 1,
33
+ classSize: values.length,
34
+ })
35
+
36
+ it('returns constant when every value is the same', () => {
37
+ expect(inferRole(make(['exp281', 'exp281', 'exp281']))).toBe('constant')
38
+ })
39
+
40
+ it('returns run-order when trailing position has high-card numeric values', () => {
41
+ expect(inferRole({
42
+ values: ['001', '002', '003', '004', '005'],
43
+ position: 4,
44
+ totalPositions: 5,
45
+ classSize: 5,
46
+ })).toBe('run-order')
47
+ })
48
+
49
+ it('returns numeric when many distinct value+unit values are present', () => {
50
+ // 6+ distinct numeric levels read as numeric (binning candidates).
51
+ expect(inferRole(make(['1nM', '5nM', '10nM', '20nM', '50nM', '100nM']))).toBe('numeric')
52
+ })
53
+
54
+ it('returns factor for low-cardinality numerics (<=5 unique levels)', () => {
55
+ // 5min / 10min and similar small dose ladders read as factors by default;
56
+ // users opt into binning via the column popover for the cases that want it.
57
+ expect(inferRole(make(['5min', '10min']))).toBe('factor')
58
+ expect(inferRole(make(['5nM', '10nM', '20nM']))).toBe('factor')
59
+ })
60
+
61
+ it('returns replicate ONLY for explicit replicate-named tokens (rep1, Rep2, replicate3, R1)', () => {
62
+ // The replicate pre-grouping pass collapses real replicates by name
63
+ // before tokenisation, so the cardinality-based ID_PATTERN heuristic
64
+ // (M1, M2, …) was removed — those reach inferRole now only when they
65
+ // represent distinct conditions, and should be treated as factors.
66
+ expect(inferRole({
67
+ values: ['M1', 'M2', 'M3', 'M4', 'M5'],
68
+ position: 1,
69
+ totalPositions: 3,
70
+ classSize: 5,
71
+ })).toBe('factor')
72
+ expect(inferRole({
73
+ values: ['rep1', 'rep2', 'rep3'],
74
+ position: 1,
75
+ totalPositions: 3,
76
+ classSize: 3,
77
+ })).toBe('replicate')
78
+ expect(inferRole({
79
+ values: ['Replicate1', 'Replicate2'],
80
+ position: 1,
81
+ totalPositions: 3,
82
+ classSize: 2,
83
+ })).toBe('replicate')
84
+ })
85
+
86
+ it('returns factor for low-cardinality categoricals', () => {
87
+ expect(inferRole(make(['Kidney', 'Liver', 'Tumor', 'Kidney', 'Liver']))).toBe('factor')
88
+ })
89
+
90
+ it('returns ignore for very-high-cardinality opaque values', () => {
91
+ // Real-world LC-MS batches routinely have 30–50 distinct conditions, so the
92
+ // factor cap was raised to 50 (was 20). 80 unique values still reads as
93
+ // ignore — likely a sample-ID column rather than a meaningful factor.
94
+ const values = Array.from({ length: 80 }, (_, i) => `opaque-${i}`)
95
+ expect(inferRole({ values, position: 0, totalPositions: 1, classSize: 80 })).toBe('ignore')
96
+ })
97
+ })
98
+
99
+ describe('buildClassSchema', () => {
100
+ it('builds one ColumnInfo per position, constant class-tag positions get class-tag role', () => {
101
+ const schema = buildClassSchema(
102
+ [
103
+ ['exp281', 'SAM_SAH', 'Tissues', 'Kidney', 'M10', '085'],
104
+ ['exp281', 'SAM_SAH', 'Tissues', 'Liver', 'M10', '047'],
105
+ ],
106
+ 'biological',
107
+ 'Tissues',
108
+ [2, 3], // positions flagged as class-related tags
109
+ )
110
+ expect(schema.classKind).toBe('biological')
111
+ expect(schema.subKind).toBe('Tissues')
112
+ // Position 2 ('Tissues') is constant → class-tag.
113
+ // Position 3 ('Kidney'/'Liver') is multi-valued → falls through to factor inference.
114
+ const tagCols = schema.columns.filter(c => c.role === 'class-tag')
115
+ expect(tagCols.length).toBe(1)
116
+ expect(tagCols[0].index).toBe(2)
117
+ const factorCols = schema.columns.filter(c => c.role === 'factor')
118
+ expect(factorCols.some(c => c.index === 3)).toBe(true)
119
+ })
120
+
121
+ it('default groupBy is every Factor column', () => {
122
+ const schema = buildClassSchema(
123
+ [
124
+ ['exp', 'Kidney', '1'],
125
+ ['exp', 'Liver', '2'],
126
+ ['exp', 'Tumor', '3'],
127
+ ],
128
+ 'biological',
129
+ 'Tissues',
130
+ [],
131
+ )
132
+ const factorIndices = schema.columns.filter(c => c.role === 'factor').map(c => c.index)
133
+ expect(schema.groupBy).toEqual(factorIndices)
134
+ })
135
+ })
@@ -0,0 +1,227 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { composeGroups } from '../../../composables/autoGroup/compose'
3
+ import type { ClassSchema } from '../../../types/auto-group'
4
+
5
+ const tissueSchema: ClassSchema = {
6
+ classKind: 'biological',
7
+ subKind: 'Tissues',
8
+ columns: [
9
+ { index: 0, name: 'Tissue', sourceIndices: [0], uniqueValues: ['Kidney', 'Liver'], cardinality: 2, role: 'factor' },
10
+ { index: 1, name: 'Animal', sourceIndices: [1], uniqueValues: ['M1', 'M2', 'M3'], cardinality: 3, role: 'replicate' },
11
+ ],
12
+ groupBy: [0],
13
+ }
14
+
15
+ const iqcSchema: ClassSchema = {
16
+ classKind: 'iqc',
17
+ columns: [
18
+ { index: 0, name: 'IQC', sourceIndices: [0], uniqueValues: ['IQC'], cardinality: 1, role: 'class-tag' },
19
+ { index: 1, name: 'Run', sourceIndices: [1], uniqueValues: ['001', '002'], cardinality: 2, role: 'run-order' },
20
+ ],
21
+ groupBy: [],
22
+ }
23
+
24
+ describe('composeGroups', () => {
25
+ it('builds groups by enabled factor columns, ignoring replicate and run-order roles', () => {
26
+ const result = composeGroups({
27
+ tokenizedSamples: [
28
+ ['Kidney', 'M1'],
29
+ ['Kidney', 'M2'],
30
+ ['Liver', 'M1'],
31
+ ],
32
+ sampleNames: ['s1', 's2', 's3'],
33
+ schemas: { 'biological:Tissues': tissueSchema },
34
+ classes: [
35
+ {
36
+ kind: 'biological',
37
+ subKind: 'Tissues',
38
+ label: 'Biological / Tissues',
39
+ members: [0, 1, 2],
40
+ classTagPositions: [],
41
+ disposition: 'group',
42
+ },
43
+ ],
44
+ })
45
+ // Group names carry class context: "Biological / Tissues / <factor>".
46
+ // The class label is prepended so labels from different classes don't
47
+ // collide when they share a factor value.
48
+ expect(result.experimentalGroups!.map(g => g.name).sort()).toEqual([
49
+ 'Biological / Tissues / Kidney',
50
+ 'Biological / Tissues / Liver',
51
+ ])
52
+ expect(
53
+ result.experimentalGroups!.find(g => g.name === 'Biological / Tissues / Kidney')!.samples,
54
+ ).toEqual(['s1', 's2'])
55
+ })
56
+
57
+ it('routes overlay classes to qcGroups (separate from experimental)', () => {
58
+ const result = composeGroups({
59
+ tokenizedSamples: [
60
+ ['Kidney', 'M1'],
61
+ ['IQC', '001'],
62
+ ['IQC', '002'],
63
+ ],
64
+ sampleNames: ['bio1', 'iqc1', 'iqc2'],
65
+ schemas: { 'biological:Tissues': tissueSchema, iqc: iqcSchema },
66
+ classes: [
67
+ {
68
+ kind: 'biological',
69
+ subKind: 'Tissues',
70
+ label: 'Biological / Tissues',
71
+ members: [0],
72
+ classTagPositions: [],
73
+ disposition: 'group',
74
+ },
75
+ {
76
+ kind: 'iqc',
77
+ label: 'IQC',
78
+ members: [1, 2],
79
+ classTagPositions: [0],
80
+ disposition: 'overlay',
81
+ },
82
+ ],
83
+ })
84
+ expect(result.qcGroups!.length).toBe(1)
85
+ expect(result.qcGroups![0].name).toBe('IQC')
86
+ expect(result.qcGroups![0].samples).toEqual(['iqc1', 'iqc2'])
87
+ expect(result.experimentalGroups!.length).toBe(1)
88
+ })
89
+
90
+ it('routes excluded-disposition classes to excludedSamples', () => {
91
+ const result = composeGroups({
92
+ tokenizedSamples: [
93
+ ['Kidney', 'M1'],
94
+ ['IQC', '001'],
95
+ ],
96
+ sampleNames: ['bio1', 'iqc1'],
97
+ schemas: { 'biological:Tissues': tissueSchema, iqc: iqcSchema },
98
+ classes: [
99
+ {
100
+ kind: 'biological',
101
+ subKind: 'Tissues',
102
+ label: 'Biological / Tissues',
103
+ members: [0],
104
+ classTagPositions: [],
105
+ disposition: 'group',
106
+ },
107
+ {
108
+ kind: 'iqc',
109
+ label: 'IQC',
110
+ members: [1],
111
+ classTagPositions: [0],
112
+ disposition: 'exclude',
113
+ },
114
+ ],
115
+ })
116
+ expect(result.excludedSamples).toEqual(['iqc1'])
117
+ expect(result.qcGroups!.length).toBe(0)
118
+ })
119
+
120
+ it('legacy groups field equals experimentalGroups concat qcGroups', () => {
121
+ const result = composeGroups({
122
+ tokenizedSamples: [
123
+ ['Kidney', 'M1'],
124
+ ['IQC', '001'],
125
+ ],
126
+ sampleNames: ['bio1', 'iqc1'],
127
+ schemas: { 'biological:Tissues': tissueSchema, iqc: iqcSchema },
128
+ classes: [
129
+ {
130
+ kind: 'biological',
131
+ subKind: 'Tissues',
132
+ label: 'Biological / Tissues',
133
+ members: [0],
134
+ classTagPositions: [],
135
+ disposition: 'group',
136
+ },
137
+ {
138
+ kind: 'iqc',
139
+ label: 'IQC',
140
+ members: [1],
141
+ classTagPositions: [0],
142
+ disposition: 'overlay',
143
+ },
144
+ ],
145
+ })
146
+ const concatNames = [
147
+ ...result.experimentalGroups!.map(g => g.name),
148
+ ...result.qcGroups!.map(g => g.name),
149
+ ]
150
+ expect(result.groups.map(g => g.name)).toEqual(concatNames)
151
+ })
152
+
153
+ it('applies alias before exclude before bin in the operation pipeline', () => {
154
+ const schema: ClassSchema = {
155
+ classKind: 'biological',
156
+ columns: [
157
+ {
158
+ index: 0,
159
+ name: 'Treatment',
160
+ sourceIndices: [0],
161
+ uniqueValues: ['Drug-A', 'drug-A', 'CTL', 'CTL'],
162
+ cardinality: 3,
163
+ role: 'factor',
164
+ ops: {
165
+ alias: { 'drug-A': 'Drug-A' },
166
+ exclude: ['CTL'],
167
+ },
168
+ },
169
+ ],
170
+ groupBy: [0],
171
+ }
172
+ const result = composeGroups({
173
+ tokenizedSamples: [['Drug-A'], ['drug-A'], ['CTL']],
174
+ sampleNames: ['s1', 's2', 's3'],
175
+ schemas: { biological: schema },
176
+ classes: [
177
+ {
178
+ kind: 'biological',
179
+ label: 'Biological',
180
+ members: [0, 1, 2],
181
+ classTagPositions: [],
182
+ disposition: 'group',
183
+ },
184
+ ],
185
+ })
186
+ expect(result.experimentalGroups!.length).toBe(1)
187
+ // Class-prefixed group name (cls.label === 'Biological' → "Biological / Drug-A").
188
+ expect(result.experimentalGroups![0].name).toBe('Biological / Drug-A')
189
+ expect(result.experimentalGroups![0].samples).toEqual(['s1', 's2'])
190
+ expect(result.excludedSamples).toEqual(['s3'])
191
+ })
192
+
193
+ it('stores post-alias / post-bin display values in MetadataRow.fields', () => {
194
+ const schema: ClassSchema = {
195
+ classKind: 'biological',
196
+ columns: [
197
+ {
198
+ index: 0,
199
+ name: 'Tissue',
200
+ sourceIndices: [0],
201
+ uniqueValues: ['Kidney', 'Liver'],
202
+ cardinality: 2,
203
+ role: 'factor',
204
+ ops: { alias: { Kidney: 'kidney_panel' } },
205
+ },
206
+ ],
207
+ groupBy: [0],
208
+ }
209
+ const result = composeGroups({
210
+ tokenizedSamples: [['Kidney']],
211
+ sampleNames: ['s1'],
212
+ schemas: { biological: schema },
213
+ classes: [
214
+ {
215
+ kind: 'biological',
216
+ label: 'Biological',
217
+ members: [0],
218
+ classTagPositions: [],
219
+ disposition: 'group',
220
+ },
221
+ ],
222
+ })
223
+ expect(result.metadata[0].fields.Tissue).toBe('kidney_panel')
224
+ // Group label is class-prefixed: cls.label ("Biological") + post-alias value.
225
+ expect(result.metadata[0].group).toBe('Biological / kidney_panel')
226
+ })
227
+ })
@@ -0,0 +1,91 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { findMerges } from '../../../composables/autoGroup/cooccurrence'
3
+ import type { ClassSchema } from '../../../types/auto-group'
4
+
5
+ const schema = (overrides: Partial<ClassSchema> = {}): ClassSchema => ({
6
+ classKind: 'biological',
7
+ columns: [
8
+ { index: 0, name: 'A', sourceIndices: [0], uniqueValues: ['SAM'], cardinality: 1, role: 'factor' },
9
+ { index: 1, name: 'B', sourceIndices: [1], uniqueValues: ['SAH'], cardinality: 1, role: 'factor' },
10
+ ],
11
+ groupBy: [],
12
+ ...overrides,
13
+ })
14
+
15
+ describe('findMerges', () => {
16
+ it('suggests merging SAM + SAH when both columns are factors and mutually paired', () => {
17
+ const s = schema({
18
+ columns: [
19
+ { index: 0, name: 'A', sourceIndices: [0], uniqueValues: ['SAM', 'WT'], cardinality: 2, role: 'factor' },
20
+ { index: 1, name: 'B', sourceIndices: [1], uniqueValues: ['SAH', 'CTL'], cardinality: 2, role: 'factor' },
21
+ ],
22
+ })
23
+ const rows = [
24
+ ['SAM', 'SAH'],
25
+ ['SAM', 'SAH'],
26
+ ['SAM', 'SAH'],
27
+ ['SAM', 'SAH'],
28
+ ['WT', 'CTL'],
29
+ ['WT', 'CTL'],
30
+ ['WT', 'CTL'],
31
+ ['WT', 'CTL'],
32
+ ]
33
+ const out = findMerges(s, rows)
34
+ expect(out.length).toBe(1)
35
+ expect(out[0].columnIndices).toEqual([0, 1])
36
+ expect(out[0].confidence).toBeGreaterThanOrEqual(0.95)
37
+ })
38
+
39
+ it('rejects merge between two adjacent constants (no factor among them)', () => {
40
+ const s = schema({
41
+ columns: [
42
+ { index: 0, name: 'A', sourceIndices: [0], uniqueValues: ['exp281'], cardinality: 1, role: 'constant' },
43
+ { index: 1, name: 'B', sourceIndices: [1], uniqueValues: ['260415'], cardinality: 1, role: 'constant' },
44
+ ],
45
+ })
46
+ const rows = Array.from({ length: 10 }, () => ['exp281', '260415'])
47
+ expect(findMerges(s, rows)).toEqual([])
48
+ })
49
+
50
+ it('rejects asymmetric pairing (forward functional but not backward)', () => {
51
+ const s = schema({
52
+ columns: [
53
+ { index: 0, name: 'A', sourceIndices: [0], uniqueValues: ['a', 'b'], cardinality: 2, role: 'factor' },
54
+ { index: 1, name: 'B', sourceIndices: [1], uniqueValues: ['x'], cardinality: 1, role: 'constant' },
55
+ ],
56
+ })
57
+ const rows = [
58
+ ['a', 'x'],
59
+ ['a', 'x'],
60
+ ['b', 'x'],
61
+ ['b', 'x'],
62
+ ]
63
+ expect(findMerges(s, rows)).toEqual([])
64
+ })
65
+
66
+ it('rejects suggestions when class size < 4', () => {
67
+ const s = schema({
68
+ columns: [
69
+ { index: 0, name: 'A', sourceIndices: [0], uniqueValues: ['a', 'b'], cardinality: 2, role: 'factor' },
70
+ { index: 1, name: 'B', sourceIndices: [1], uniqueValues: ['x', 'y'], cardinality: 2, role: 'factor' },
71
+ ],
72
+ })
73
+ const rows = [
74
+ ['a', 'x'],
75
+ ['b', 'y'],
76
+ ['a', 'x'],
77
+ ]
78
+ expect(findMerges(s, rows)).toEqual([])
79
+ })
80
+
81
+ it('rejects merge that would collapse two adjacent factors into a single constant', () => {
82
+ const s = schema({
83
+ columns: [
84
+ { index: 0, name: 'A', sourceIndices: [0], uniqueValues: ['x'], cardinality: 1, role: 'factor' },
85
+ { index: 1, name: 'B', sourceIndices: [1], uniqueValues: ['y'], cardinality: 1, role: 'factor' },
86
+ ],
87
+ })
88
+ const rows = Array.from({ length: 6 }, () => ['x', 'y'])
89
+ expect(findMerges(s, rows)).toEqual([])
90
+ })
91
+ })
@@ -0,0 +1,50 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { serializeFingerprint, restoreFingerprint } from '../../../composables/autoGroup/fingerprint'
3
+ import type { ClassSchema } from '../../../types/auto-group'
4
+
5
+ const schemas: ClassSchema[] = [
6
+ {
7
+ classKind: 'biological',
8
+ subKind: 'Tissues',
9
+ columns: [
10
+ {
11
+ index: 0,
12
+ name: 'Tissue',
13
+ sourceIndices: [0],
14
+ uniqueValues: ['Kidney', 'Liver'],
15
+ cardinality: 2,
16
+ role: 'factor',
17
+ ops: { alias: { Kidney: 'kidney_panel' } },
18
+ },
19
+ ],
20
+ groupBy: [0],
21
+ },
22
+ ]
23
+
24
+ describe('fingerprint round-trip', () => {
25
+ it('serializes to a JSON-stringify-safe object (no Maps)', () => {
26
+ const fp = serializeFingerprint(schemas)
27
+ const stringified = JSON.stringify(fp)
28
+ const reparsed = JSON.parse(stringified)
29
+ expect(reparsed.version).toBe(1)
30
+ expect(reparsed.classes[0].columns[0].ops.alias.Kidney).toBe('kidney_panel')
31
+ })
32
+
33
+ it('round-trips through restore preserving group-by and ops', () => {
34
+ const fp = serializeFingerprint(schemas)
35
+ const restored = restoreFingerprint(fp, schemas)
36
+ expect(restored[0].groupBy).toEqual([0])
37
+ expect(restored[0].columns[0].ops?.alias?.Kidney).toBe('kidney_panel')
38
+ })
39
+
40
+ it('reports a clear error when current schema column count differs', () => {
41
+ const fp = serializeFingerprint(schemas)
42
+ const mismatched: ClassSchema[] = [
43
+ {
44
+ ...schemas[0],
45
+ columns: [], // empty
46
+ },
47
+ ]
48
+ expect(() => restoreFingerprint(fp, mismatched)).toThrow(/column count/i)
49
+ })
50
+ })
@@ -0,0 +1,79 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { readFileSync } from 'node:fs'
3
+ import { resolve } from 'node:path'
4
+ import {
5
+ pickPrimaryDelimiter,
6
+ splitMulti,
7
+ detectClass,
8
+ buildClassSchema,
9
+ composeGroups,
10
+ } from '../../../composables/autoGroup'
11
+
12
+ const FIXTURE = resolve(__dirname, '../../fixtures/auto-group/mixed-lc-ms-batch.txt')
13
+
14
+ describe('mixed LC-MS batch integration', () => {
15
+ const samples = readFileSync(FIXTURE, 'utf-8').trim().split('\n')
16
+ const delim = pickPrimaryDelimiter(samples)
17
+ const tokenized = samples.map(s => splitMulti(s, delim))
18
+ const classes = detectClass(tokenized, {})
19
+
20
+ it('detects exactly 81 Biological/Tissues samples', () => {
21
+ const c = classes.find(c => c.kind === 'biological' && c.subKind === 'Tissues')
22
+ expect(c?.members.length).toBe(81)
23
+ })
24
+
25
+ it('detects exactly 81 Biological/Plasma samples', () => {
26
+ const c = classes.find(c => c.kind === 'biological' && c.subKind === 'Plasma')
27
+ expect(c?.members.length).toBe(81)
28
+ })
29
+
30
+ it('detects exactly 3 IQC and 3 EQC samples', () => {
31
+ const iqc = classes.find(c => c.kind === 'iqc')
32
+ const eqc = classes.find(c => c.kind === 'eqc')
33
+ expect(iqc?.members.length).toBe(3)
34
+ expect(eqc?.members.length).toBe(3)
35
+ })
36
+
37
+ it('totals biological + QC overlay + excluded === 187', () => {
38
+ const tissues = classes.find(c => c.kind === 'biological' && c.subKind === 'Tissues')
39
+ const plasma = classes.find(c => c.kind === 'biological' && c.subKind === 'Plasma')
40
+ const overlayKinds = ['iqc', 'eqc', 'standard', 'spike-in', 'stock', 'blank']
41
+ const overlayCount = classes
42
+ .filter(c => overlayKinds.includes(c.kind))
43
+ .reduce((acc, c) => acc + c.members.length, 0)
44
+ const unknownCount = classes
45
+ .filter(c => c.kind === 'unknown')
46
+ .reduce((acc, c) => acc + c.members.length, 0)
47
+ expect((tissues?.members.length ?? 0) + (plasma?.members.length ?? 0) + overlayCount + unknownCount).toBe(187)
48
+ })
49
+
50
+ it('default workspace produces 3 Kidney/Liver/Tumor groups of 27 each', () => {
51
+ const tissuesClass = classes.find(c => c.kind === 'biological' && c.subKind === 'Tissues')!
52
+ const tissuesTokens = tissuesClass.members.map(i => tokenized[i])
53
+ const schema = buildClassSchema(
54
+ tissuesTokens,
55
+ 'biological',
56
+ 'Tissues',
57
+ tissuesClass.classTagPositions,
58
+ )
59
+ // The Tissue column should be a factor with 3 unique values.
60
+ const tissueCol = schema.columns.find(c => c.uniqueValues.length === 3 && c.role === 'factor')
61
+ expect(tissueCol).toBeDefined()
62
+ const result = composeGroups({
63
+ tokenizedSamples: tokenized,
64
+ sampleNames: samples,
65
+ schemas: { 'biological:Tissues': { ...schema, groupBy: [tissueCol!.index] } },
66
+ classes: [tissuesClass],
67
+ })
68
+ expect(result.experimentalGroups!.length).toBe(3)
69
+ expect(result.experimentalGroups!.every(g => g.samples.length === 27)).toBe(true)
70
+ const names = result.experimentalGroups!.map(g => g.name).sort()
71
+ // Class-prefixed: "Biological / Tissues / <organ>" disambiguates from
72
+ // other classes that might also produce a Kidney/Liver/Tumor factor.
73
+ expect(names).toEqual([
74
+ 'Biological / Tissues / Kidney',
75
+ 'Biological / Tissues / Liver',
76
+ 'Biological / Tissues / Tumor',
77
+ ])
78
+ })
79
+ })
@@ -0,0 +1,70 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { composeTemplate } from '../../../composables/autoGroup/template'
3
+ import type { ClassSchema, SampleClass } from '../../../types/auto-group'
4
+
5
+ describe('composeTemplate', () => {
6
+ const samples = ['s_1', 's_2,with_comma', 's_3']
7
+ const classes: SampleClass[] = [
8
+ {
9
+ kind: 'biological',
10
+ subKind: 'Tissues',
11
+ label: 'Biological / Tissues',
12
+ members: [0, 1, 2],
13
+ classTagPositions: [],
14
+ disposition: 'group',
15
+ },
16
+ ]
17
+ const schema: ClassSchema = {
18
+ classKind: 'biological',
19
+ subKind: 'Tissues',
20
+ columns: [
21
+ { index: 0, name: 'Tissue', sourceIndices: [0], uniqueValues: ['Kidney', 'Liver'], cardinality: 2, role: 'factor' },
22
+ ],
23
+ groupBy: [0],
24
+ }
25
+
26
+ it('blank mode emits one row per sample with sample_name and header-only suggested columns', () => {
27
+ const { content } = composeTemplate(samples, null, null, { mode: 'blank', format: 'csv' })
28
+ const lines = content.split('\n')
29
+ expect(lines[0]).toBe('sample_name,group,class,replicate,notes')
30
+ expect(lines[1].startsWith('s_1,')).toBe(true)
31
+ expect(lines.length).toBe(samples.length + 1)
32
+ })
33
+
34
+ it('quotes values containing commas per RFC 4180', () => {
35
+ const { content } = composeTemplate(samples, null, null, { mode: 'blank', format: 'csv' })
36
+ expect(content).toContain('"s_2,with_comma"')
37
+ })
38
+
39
+ it('prefilled mode includes class label and schema columns', () => {
40
+ const tokenized = [['Kidney'], ['Kidney'], ['Liver']]
41
+ const { content } = composeTemplate(samples, [schema], classes, {
42
+ mode: 'prefilled',
43
+ format: 'csv',
44
+ tokenizedSamples: tokenized,
45
+ })
46
+ const lines = content.split('\n')
47
+ expect(lines[0]).toBe('sample_name,class,Tissue,group,notes')
48
+ expect(lines[1]).toContain('Biological / Tissues')
49
+ expect(lines[1]).toContain('Kidney')
50
+ })
51
+
52
+ it('TSV format uses tab separator and skips quoting commas', () => {
53
+ const { content } = composeTemplate(samples, null, null, { mode: 'blank', format: 'tsv' })
54
+ expect(content.split('\n')[2].split('\t')[0]).toBe('s_2,with_comma')
55
+ })
56
+
57
+ it('uses experiment code in filename when provided', () => {
58
+ const { filename } = composeTemplate(samples, null, null, {
59
+ mode: 'blank',
60
+ format: 'csv',
61
+ experimentCode: 'EXP-042',
62
+ })
63
+ expect(filename).toMatch(/^EXP-042_metadata_\d{4}-\d{2}-\d{2}\.csv$/)
64
+ })
65
+
66
+ it('falls back to default filename without experiment code', () => {
67
+ const { filename } = composeTemplate(samples, null, null, { mode: 'blank', format: 'csv' })
68
+ expect(filename).toMatch(/^sample_metadata_\d{4}-\d{2}-\d{2}\.csv$/)
69
+ })
70
+ })
@@ -0,0 +1,33 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { splitMulti, pickPrimaryDelimiter } from '../../../composables/autoGroup/tokenize'
3
+
4
+ describe('pickPrimaryDelimiter', () => {
5
+ it('should pick underscore when underscore field counts are most consistent', () => {
6
+ const lines = ['a_b_c', 'd_e_f', 'g_h_i']
7
+ expect(pickPrimaryDelimiter(lines)).toBe('_')
8
+ })
9
+
10
+ it('should pick hyphen when underscore is absent but hyphen is consistent', () => {
11
+ const lines = ['a-b-c', 'd-e-f']
12
+ expect(pickPrimaryDelimiter(lines)).toBe('-')
13
+ })
14
+
15
+ it('should fall back to underscore when no delimiter splits anything', () => {
16
+ const lines = ['abc', 'def']
17
+ expect(pickPrimaryDelimiter(lines)).toBe('_')
18
+ })
19
+ })
20
+
21
+ describe('splitMulti', () => {
22
+ it('should split a single sample on the primary delimiter', () => {
23
+ expect(splitMulti('a_b_c', '_')).toEqual(['a', 'b', 'c'])
24
+ })
25
+
26
+ it('should not re-split on secondary delimiters', () => {
27
+ expect(splitMulti('a-b_c-d', '_')).toEqual(['a-b', 'c-d'])
28
+ })
29
+
30
+ it('should handle empty string as a single empty token', () => {
31
+ expect(splitMulti('', '_')).toEqual([''])
32
+ })
33
+ })