@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,156 @@
1
+ import type {
2
+ AutoGroupResult,
3
+ ClassSchema,
4
+ ColumnInfo,
5
+ MetadataRow,
6
+ NumericBinning,
7
+ SampleClass,
8
+ } from '../../types/auto-group'
9
+ import type { SampleGroup } from '../../types/components'
10
+ import { DEFAULT_COLORS, QC_OVERLAY_COLOR } from './colors'
11
+ import { classKey } from './classKey'
12
+
13
+ export interface ComposeInput {
14
+ tokenizedSamples: string[][]
15
+ sampleNames: string[]
16
+ schemas: Record<string, ClassSchema>
17
+ classes: SampleClass[]
18
+ }
19
+
20
+ /** Apply the operation pipeline to a single raw token value:
21
+ * numeric-parse → alias → exclude → bin
22
+ * Returns null if the row is excluded.
23
+ */
24
+ function applyOps(col: ColumnInfo, raw: string): string | null {
25
+ let value = raw
26
+
27
+ // alias (operates on raw source value)
28
+ if (col.ops?.alias && raw in col.ops.alias) {
29
+ value = col.ops.alias[raw]
30
+ }
31
+
32
+ // exclude (post-alias)
33
+ if (col.ops?.exclude?.includes(raw) || col.ops?.exclude?.includes(value)) {
34
+ return null
35
+ }
36
+
37
+ // bin (only when role === 'numeric' and binning.mode === 'binned')
38
+ if (col.role === 'numeric' && col.binning?.mode === 'binned') {
39
+ const parsed = col.numeric?.byValue[raw]
40
+ if (parsed && col.binning.edges) {
41
+ const bin = pickBin(parsed.value, col.binning)
42
+ if (bin !== null) value = bin
43
+ }
44
+ }
45
+
46
+ return value
47
+ }
48
+
49
+ function pickBin(value: number, b: NumericBinning): string | null {
50
+ if (!b.edges || b.edges.length === 0) return null
51
+ for (let i = 0; i < b.edges.length; i++) {
52
+ if (value < b.edges[i]) {
53
+ return b.labels?.[i] ?? `< ${b.edges[i]}`
54
+ }
55
+ }
56
+ const last = b.edges[b.edges.length - 1]
57
+ return b.labels?.[b.edges.length] ?? `> ${last}`
58
+ }
59
+
60
+ export function composeGroups(input: ComposeInput): AutoGroupResult {
61
+ const experimentalGroups: SampleGroup[] = []
62
+ const qcGroups: SampleGroup[] = []
63
+ const excludedSamples: string[] = []
64
+ const metadata: MetadataRow[] = []
65
+ let colorIdx = 0
66
+
67
+ for (const cls of input.classes) {
68
+ const schema = input.schemas[classKey(cls)]
69
+ if (!schema) continue
70
+
71
+ if (cls.disposition === 'exclude') {
72
+ for (const m of cls.members) excludedSamples.push(input.sampleNames[m])
73
+ continue
74
+ }
75
+
76
+ // Per-class group map. group key built from enabled (groupBy) columns,
77
+ // joined with ' / ' for hierarchical display.
78
+ const groupMap = new Map<string, { name: string; samples: string[] }>()
79
+ const colByIdx = new Map(schema.columns.map(c => [c.index, c]))
80
+
81
+ for (const m of cls.members) {
82
+ const tokens = input.tokenizedSamples[m]
83
+ const rowName = input.sampleNames[m]
84
+ let excluded = false
85
+ const fieldValues: Record<string, string> = {}
86
+
87
+ for (const col of schema.columns) {
88
+ const sourceValues = col.sourceIndices.map(idx => tokens[idx] ?? '')
89
+ const raw = sourceValues.join('_') // merged columns join their source tokens
90
+ const display = applyOps(col, raw)
91
+ if (display === null) {
92
+ excluded = true
93
+ break
94
+ }
95
+ fieldValues[col.displayName ?? col.name] = display
96
+ }
97
+
98
+ if (excluded) {
99
+ excludedSamples.push(rowName)
100
+ continue
101
+ }
102
+
103
+ const keyParts: string[] =
104
+ cls.disposition === 'group'
105
+ ? schema.groupBy.map(idx => {
106
+ const col = colByIdx.get(idx)!
107
+ return fieldValues[col.displayName ?? col.name]
108
+ })
109
+ : [cls.label]
110
+
111
+ // Prepend the class label to the factor-key parts so group names carry
112
+ // class context (e.g. "Biological / Tissues / POS / 5min" instead of a
113
+ // bare "5min" that collides with another class's "5min").
114
+ //
115
+ // Only fires for disposition === 'group' classes with actual factor
116
+ // keyParts: overlay/exclude classes already use cls.label AS their
117
+ // single key part, so prefixing again would produce "IQC / IQC". The
118
+ // Unknown class also opts out — its label ("Unknown") adds no signal.
119
+ const useClassPrefix =
120
+ cls.disposition === 'group' && cls.kind !== 'unknown' && keyParts.length > 0
121
+ const groupKey = useClassPrefix
122
+ ? `${cls.label} / ${keyParts.join(' / ')}`
123
+ : keyParts.length > 0
124
+ ? keyParts.join(' / ')
125
+ : cls.label
126
+
127
+ const bucket = groupMap.get(groupKey)
128
+ if (bucket) {
129
+ bucket.samples.push(rowName)
130
+ } else {
131
+ groupMap.set(groupKey, { name: groupKey, samples: [rowName] })
132
+ }
133
+
134
+ metadata.push({ sampleName: rowName, fields: fieldValues, group: groupKey })
135
+ }
136
+
137
+ for (const { name, samples } of groupMap.values()) {
138
+ const color =
139
+ cls.disposition === 'overlay'
140
+ ? QC_OVERLAY_COLOR
141
+ : DEFAULT_COLORS[colorIdx++ % DEFAULT_COLORS.length]
142
+ const g: SampleGroup = { name, color, samples }
143
+ if (cls.disposition === 'overlay') qcGroups.push(g)
144
+ else experimentalGroups.push(g)
145
+ }
146
+ }
147
+
148
+ return {
149
+ groups: [...experimentalGroups, ...qcGroups],
150
+ experimentalGroups,
151
+ qcGroups,
152
+ metadata,
153
+ excludedSamples,
154
+ schemas: Object.values(input.schemas),
155
+ }
156
+ }
@@ -0,0 +1,46 @@
1
+ import type { ClassSchema, MergeSuggestion } from '../../types/auto-group'
2
+
3
+ const THRESHOLD = 0.95
4
+ const MIN_CLASS_SIZE = 4
5
+
6
+ function functionalDependency(rows: string[][], srcIdx: number, dstIdx: number): number {
7
+ const map = new Map<string, Set<string>>()
8
+ for (const row of rows) {
9
+ const a = row[srcIdx] ?? ''
10
+ const b = row[dstIdx] ?? ''
11
+ const set = map.get(a)
12
+ if (set) set.add(b)
13
+ else map.set(a, new Set([b]))
14
+ }
15
+ if (map.size === 0) return 0
16
+ let functional = 0
17
+ for (const set of map.values()) if (set.size === 1) functional++
18
+ return functional / map.size
19
+ }
20
+
21
+ export function findMerges(schema: ClassSchema, rows: string[][]): MergeSuggestion[] {
22
+ if (rows.length < MIN_CLASS_SIZE) return []
23
+
24
+ const out: MergeSuggestion[] = []
25
+ for (let i = 0; i < schema.columns.length - 1; i++) {
26
+ const a = schema.columns[i]
27
+ const b = schema.columns[i + 1]
28
+ if (a.role !== 'factor' && b.role !== 'factor') continue
29
+
30
+ const forward = functionalDependency(rows, a.index, b.index)
31
+ const backward = functionalDependency(rows, b.index, a.index)
32
+ if (forward < THRESHOLD || backward < THRESHOLD) continue
33
+
34
+ const merged = new Set(rows.map(r => `${r[a.index] ?? ''}_${r[b.index] ?? ''}`))
35
+ if (merged.size < 2) continue
36
+
37
+ out.push({
38
+ classKind: schema.classKind,
39
+ subKind: schema.subKind,
40
+ columnIndices: [a.index, b.index],
41
+ proposedName: `Column ${a.index + 1}–${b.index + 1}`,
42
+ confidence: Math.min(forward, backward),
43
+ })
44
+ }
45
+ return out
46
+ }
@@ -0,0 +1,44 @@
1
+ import type { ParsedCsvData } from '../../types/auto-group'
2
+
3
+ function parseCSVLine(line: string, delimiter: string = ','): string[] {
4
+ const result: string[] = []
5
+ let current = ''
6
+ let inQuotes = false
7
+ for (let i = 0; i < line.length; i++) {
8
+ const char = line[i]
9
+ if (char === '"') {
10
+ if (inQuotes && line[i + 1] === '"') {
11
+ current += '"'
12
+ i++
13
+ } else {
14
+ inQuotes = !inQuotes
15
+ }
16
+ } else if (char === delimiter && !inQuotes) {
17
+ result.push(current.trim())
18
+ current = ''
19
+ } else {
20
+ current += char
21
+ }
22
+ }
23
+ result.push(current.trim())
24
+ return result
25
+ }
26
+
27
+ export function parseCSV(text: string): ParsedCsvData {
28
+ const lines = text.trim().split('\n')
29
+ if (lines.length < 2) throw new Error('CSV must have at least a header and one data row')
30
+ const firstLine = lines[0]
31
+ const csvDelimiter = firstLine.includes('\t') ? '\t' : ','
32
+ const headers = parseCSVLine(firstLine, csvDelimiter)
33
+ const rows: Record<string, string>[] = []
34
+ for (let i = 1; i < lines.length; i++) {
35
+ const values = parseCSVLine(lines[i], csvDelimiter)
36
+ if (values.length !== headers.length) continue
37
+ const row: Record<string, string> = {}
38
+ headers.forEach((h, idx) => { row[h] = values[idx] })
39
+ rows.push(row)
40
+ }
41
+ const sampleKeywords = ['sample', 'name', 'id', 'sample_name', 'samplename', 'file name', 'filename', 'file_name']
42
+ const sampleColumn = headers.find(h => sampleKeywords.includes(h.toLowerCase())) ?? headers[0]
43
+ return { columns: headers, rows, sampleColumn, delimiter: csvDelimiter }
44
+ }
@@ -0,0 +1,49 @@
1
+ import type { ClassSchema, SchemaFingerprint } from '../../types/auto-group'
2
+
3
+ export function serializeFingerprint(schemas: ClassSchema[]): SchemaFingerprint {
4
+ return {
5
+ version: 1,
6
+ classes: schemas.map(s => ({
7
+ kind: s.classKind,
8
+ subKind: s.subKind,
9
+ columns: s.columns.map(c => ({
10
+ name: c.displayName ?? c.name,
11
+ role: c.role ?? 'factor',
12
+ sourceIndices: c.sourceIndices,
13
+ binning: c.binning,
14
+ ops: c.ops,
15
+ })),
16
+ groupBy: s.groupBy,
17
+ })),
18
+ }
19
+ }
20
+
21
+ export function restoreFingerprint(
22
+ fp: SchemaFingerprint,
23
+ current: ClassSchema[],
24
+ ): ClassSchema[] {
25
+ return fp.classes.map(snap => {
26
+ const target = current.find(c => c.classKind === snap.kind && c.subKind === snap.subKind)
27
+ if (!target) {
28
+ throw new Error(
29
+ `Fingerprint class not present in current input: ${snap.kind}${snap.subKind ? '/' + snap.subKind : ''}`,
30
+ )
31
+ }
32
+ if (target.columns.length !== snap.columns.length) {
33
+ throw new Error(
34
+ `Saved schema expects ${snap.columns.length} columns, current data has ${target.columns.length} for class ${snap.kind}${snap.subKind ? '/' + snap.subKind : ''}. column count mismatch`,
35
+ )
36
+ }
37
+ return {
38
+ ...target,
39
+ groupBy: snap.groupBy,
40
+ columns: target.columns.map((col, i) => ({
41
+ ...col,
42
+ displayName: snap.columns[i].name,
43
+ role: snap.columns[i].role,
44
+ binning: snap.columns[i].binning,
45
+ ops: snap.columns[i].ops,
46
+ })),
47
+ }
48
+ })
49
+ }
@@ -0,0 +1,20 @@
1
+ export { splitMulti, pickPrimaryDelimiter } from './tokenize'
2
+ export type { Delimiter } from './tokenize'
3
+ export { detectClass, classVocab } from './classify'
4
+ export type { ClassVocab, DetectClassOptions } from './classify'
5
+ export { inferRole, parseNumeric, buildClassSchema } from './columns'
6
+ export type { InferRoleInput } from './columns'
7
+ export { findMerges } from './cooccurrence'
8
+ export { composeGroups } from './compose'
9
+ export type { ComposeInput } from './compose'
10
+ export { serializeFingerprint, restoreFingerprint } from './fingerprint'
11
+ export { composeTemplate } from './template'
12
+ export type { TemplateOptions } from './template'
13
+ export { DEFAULT_COLORS, QC_OVERLAY_COLOR } from './colors'
14
+ export { classKey } from './classKey'
15
+ export {
16
+ stripReplicateTokens,
17
+ preGroupReplicates,
18
+ expandGroupsWithReplicates,
19
+ } from './replicatePreGroup'
20
+ export type { ReplicatePreGrouping } from './replicatePreGroup'
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Replicate pre-grouping.
3
+ *
4
+ * Strip the replicate / injection-number markers from each sample's name, then
5
+ * collapse samples that share a base name. Those samples ARE replicates of one
6
+ * another by definition; the remaining unique base names are what the rest of
7
+ * the pipeline (tokenize → classify → schema → compose) should operate on.
8
+ *
9
+ * This pre-pass replaces the older "treat every sample as independent, then
10
+ * infer replicate columns" approach. Identifying replicate-equivalence by name
11
+ * before tokenisation removes a class of fragile cardinality heuristics.
12
+ */
13
+
14
+ import vocabData from './vocab.json'
15
+
16
+ const STRIP_PATTERNS: RegExp[] = (vocabData.replicateStripPatterns as string[]).map(
17
+ src => new RegExp(src, 'gi'),
18
+ )
19
+
20
+ /**
21
+ * Iteratively strip every replicate / injection-number marker from `name`.
22
+ * Each pattern is applied repeatedly until it stops matching, so a sample like
23
+ * `study_T1_Rep2_004` collapses to `study` in one call.
24
+ */
25
+ export function stripReplicateTokens(name: string): string {
26
+ let base = name
27
+ for (const re of STRIP_PATTERNS) {
28
+ let prev
29
+ do {
30
+ prev = base
31
+ base = base.replace(re, '')
32
+ re.lastIndex = 0
33
+ } while (base !== prev)
34
+ }
35
+ return base
36
+ }
37
+
38
+ export interface ReplicatePreGrouping {
39
+ /** Unique base names in first-seen order. Length === `originalSamples.length` only if every sample has a distinct base. */
40
+ baseNames: string[]
41
+ /**
42
+ * `membersByBase[i]` = original-sample indices that collapsed onto `baseNames[i]`.
43
+ * Length of each entry is the replicate count for that base.
44
+ */
45
+ membersByBase: number[][]
46
+ /** Original sample names indexed by their position in `samples`. Retained so the compose layer can expand groups back to originals. */
47
+ originalSamples: string[]
48
+ }
49
+
50
+ export function preGroupReplicates(samples: string[]): ReplicatePreGrouping {
51
+ const map = new Map<string, number[]>()
52
+ const baseOrder: string[] = []
53
+ for (let i = 0; i < samples.length; i++) {
54
+ const base = stripReplicateTokens(samples[i])
55
+ const bucket = map.get(base)
56
+ if (bucket) {
57
+ bucket.push(i)
58
+ } else {
59
+ map.set(base, [i])
60
+ baseOrder.push(base)
61
+ }
62
+ }
63
+ return {
64
+ baseNames: baseOrder,
65
+ membersByBase: baseOrder.map(b => map.get(b)!),
66
+ originalSamples: samples,
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Expand groups produced over base names back to groups of original sample
72
+ * names. Each entry in `group.samples` is treated as a base name and replaced
73
+ * by the list of original samples that collapsed onto it.
74
+ */
75
+ export function expandGroupsWithReplicates<G extends { samples: string[] }>(
76
+ groups: G[],
77
+ preGrouping: ReplicatePreGrouping,
78
+ ): G[] {
79
+ const baseToMembers = new Map<string, number[]>()
80
+ for (let i = 0; i < preGrouping.baseNames.length; i++) {
81
+ baseToMembers.set(preGrouping.baseNames[i], preGrouping.membersByBase[i])
82
+ }
83
+ return groups.map(g => ({
84
+ ...g,
85
+ samples: g.samples.flatMap(baseName => {
86
+ const indices = baseToMembers.get(baseName)
87
+ return indices ? indices.map(i => preGrouping.originalSamples[i]) : [baseName]
88
+ }),
89
+ }))
90
+ }
@@ -0,0 +1,126 @@
1
+ import type { ClassSchema, ColumnInfo, SampleClass } from '../../types/auto-group'
2
+ import { classKey } from './classKey'
3
+
4
+ export interface TemplateOptions {
5
+ mode: 'blank' | 'prefilled'
6
+ format: 'csv' | 'tsv'
7
+ /** For prefilled mode. Indexed parallel to `samples`. */
8
+ tokenizedSamples?: string[][]
9
+ /** Used to compute the filename; omitted → falls back to `sample_metadata_<date>`. */
10
+ experimentCode?: string
11
+ /** Override the blank-mode suggested headers. Defaults to ['group','class','replicate','notes']. */
12
+ suggestedColumns?: string[]
13
+ }
14
+
15
+ const DEFAULT_BLANK_HEADERS = ['group', 'class', 'replicate', 'notes']
16
+
17
+ function rfc4180Quote(cell: string): string {
18
+ if (/[",\n]/.test(cell)) {
19
+ return `"${cell.replace(/"/g, '""')}"`
20
+ }
21
+ return cell
22
+ }
23
+
24
+ function joinRow(cells: string[], sep: string): string {
25
+ return sep === ','
26
+ ? cells.map(rfc4180Quote).join(',')
27
+ : cells.join('\t')
28
+ }
29
+
30
+ function today(): string {
31
+ return new Date().toISOString().slice(0, 10)
32
+ }
33
+
34
+ export function composeTemplate(
35
+ samples: string[],
36
+ schemas: ClassSchema[] | null,
37
+ classes: SampleClass[] | null,
38
+ options: TemplateOptions,
39
+ ): { content: string; filename: string } {
40
+ const sep = options.format === 'tsv' ? '\t' : ','
41
+ const ext = options.format === 'tsv' ? 'tsv' : 'csv'
42
+
43
+ const stem = options.experimentCode ? `${options.experimentCode}_metadata` : 'sample_metadata'
44
+ const filename = `${stem}_${today()}.${ext}`
45
+
46
+ if (options.mode === 'blank' || !schemas || !classes) {
47
+ const headers = ['sample_name', ...(options.suggestedColumns ?? DEFAULT_BLANK_HEADERS)]
48
+ const rows = samples.map(s => {
49
+ const r = [s, ...Array(headers.length - 1).fill('')]
50
+ return joinRow(r, sep)
51
+ })
52
+ return { content: [joinRow(headers, sep), ...rows].join('\n'), filename }
53
+ }
54
+
55
+ // Prefilled mode: union of all class columns, wide layout.
56
+ const tokenized = options.tokenizedSamples ?? []
57
+ const allColumns: { schemaKey: string; colName: string }[] = []
58
+
59
+ // Hoist: build lookup maps before the per-sample loop.
60
+ const sampleToClass = new Map<number, SampleClass>()
61
+ for (const cls of classes) for (const m of cls.members) sampleToClass.set(m, cls)
62
+
63
+ const schemaByKey = new Map<string, ClassSchema>()
64
+ for (const s of schemas) {
65
+ const k = s.subKind ? `${s.classKind}:${s.subKind}` : s.classKind
66
+ schemaByKey.set(k, s)
67
+ }
68
+
69
+ const colByNameByKey = new Map<string, Map<string, ColumnInfo>>()
70
+ const groupBySetByKey = new Map<string, Set<number>>()
71
+ for (const s of schemas) {
72
+ const k = s.subKind ? `${s.classKind}:${s.subKind}` : s.classKind
73
+ const m = new Map<string, ColumnInfo>()
74
+ for (const c of s.columns) m.set(c.displayName ?? c.name, c)
75
+ colByNameByKey.set(k, m)
76
+ groupBySetByKey.set(k, new Set(s.groupBy))
77
+ // Collect allColumns with dedup via Set
78
+ const seenColNames = new Set<string>()
79
+ for (const c of s.columns) {
80
+ const name = c.displayName ?? c.name
81
+ if (!seenColNames.has(name)) {
82
+ seenColNames.add(name)
83
+ if (!allColumns.some(x => x.colName === name)) {
84
+ allColumns.push({ schemaKey: k, colName: name })
85
+ }
86
+ }
87
+ }
88
+ }
89
+
90
+ const headers = ['sample_name', 'class', ...allColumns.map(c => c.colName), 'group', 'notes']
91
+
92
+ const rows: string[] = []
93
+ for (let i = 0; i < samples.length; i++) {
94
+ const cls = sampleToClass.get(i)
95
+ const classLabel = cls?.label ?? ''
96
+ const tokens = tokenized[i] ?? []
97
+ const cells: string[] = [samples[i], classLabel]
98
+
99
+ if (cls) {
100
+ const k = classKey(cls)
101
+ const groupBySet = groupBySetByKey.get(k)
102
+ const colByName: Map<string, ColumnInfo> | undefined = colByNameByKey.get(k)
103
+ const keyParts: string[] = []
104
+ for (const col of allColumns) {
105
+ if (col.schemaKey === k && colByName) {
106
+ const schemaCol = colByName.get(col.colName)
107
+ const raw =
108
+ schemaCol?.sourceIndices.map(idx => tokens[idx] ?? '').join('_') ?? ''
109
+ cells.push(raw)
110
+ if (schemaCol && groupBySet?.has(schemaCol.index)) keyParts.push(raw)
111
+ } else {
112
+ cells.push('')
113
+ }
114
+ }
115
+ cells.push(keyParts.join(' / '))
116
+ } else {
117
+ for (const _ of allColumns) cells.push('')
118
+ cells.push('')
119
+ }
120
+
121
+ cells.push('') // notes
122
+ rows.push(joinRow(cells, sep))
123
+ }
124
+
125
+ return { content: [joinRow(headers, sep), ...rows].join('\n'), filename }
126
+ }
@@ -0,0 +1,41 @@
1
+ const DELIMITER_CANDIDATES = ['_', '-', '.'] as const
2
+ export type Delimiter = (typeof DELIMITER_CANDIDATES)[number]
3
+
4
+ /** Pick the delimiter whose split produces the most consistent field count across `lines`. */
5
+ export function pickPrimaryDelimiter(lines: string[]): Delimiter {
6
+ if (lines.length === 0) return '_'
7
+
8
+ let best: Delimiter = '_'
9
+ let bestScore = -1
10
+
11
+ for (const candidate of DELIMITER_CANDIDATES) {
12
+ const counts = lines.map(l => l.split(candidate).length)
13
+ const frequency = new Map<number, number>()
14
+ for (const c of counts) frequency.set(c, (frequency.get(c) ?? 0) + 1)
15
+
16
+ // Mode and its frequency
17
+ let mode = 1
18
+ let modeFreq = 0
19
+ for (const [c, f] of frequency) {
20
+ if (f > modeFreq || (f === modeFreq && c > mode)) {
21
+ mode = c
22
+ modeFreq = f
23
+ }
24
+ }
25
+
26
+ // A delimiter that produces field count 1 didn't split anything — score 0.
27
+ const score = mode > 1 ? modeFreq / lines.length : 0
28
+ if (score > bestScore) {
29
+ best = candidate
30
+ bestScore = score
31
+ }
32
+ }
33
+
34
+ return best
35
+ }
36
+
37
+ /** Split a single sample name on `delimiter`. Empty input returns `['']` so callers
38
+ * always receive at least one token. */
39
+ export function splitMulti(name: string, delimiter: Delimiter): string[] {
40
+ return name.split(delimiter)
41
+ }
@@ -0,0 +1,67 @@
1
+ {
2
+ "$schema": "./vocab.schema.json",
3
+ "_doc": {
4
+ "purpose": "Sample-name classification vocabulary for the auto-group pipeline. Edit this file to teach the classifier new sample types or matrices without changing TypeScript. All matching is case-insensitive unless a pattern's regex flags say otherwise.",
5
+ "patterns": "Regex source strings (no surrounding slashes). Compiled with the `i` flag at load time.",
6
+ "standardAllow": "Tokens that should be classified as Standard even when they don't match `patterns.standard`. Case-sensitive — use the exact spelling that appears in your filenames.",
7
+ "matrixVocab": "Lowercase token → canonical display name. Tokens are normalised to lowercase before lookup, so adding 'tissues' handles 'Tissues' / 'TISSUES' / 'tissues' uniformly. Multiple aliases map to one canonical (e.g. cell + cells → Cells).",
8
+ "ionizationModes": "Lowercase polarity tokens (pos / positive / neg / negative). Suffixed to the subKind so POS and NEG acquisitions get independent schemas.",
9
+ "tissueParentTokens": "Tokens that flag the immediately-following token as the organ subKind (so `tissues / kidney` becomes Biological/Tissues, tagging both positions).",
10
+ "replicateStripPatterns": "Regex sources stripped from each sample name during the replicate pre-grouping pass. Samples whose stripped (base) names match are treated as replicates of one another and grouped together before tokenisation. Default set covers: trailing run-order numbers, _T<n>, _B<n>, and _Rep<n> markers."
11
+ },
12
+
13
+ "patterns": {
14
+ "blank": "^(blank|blk|solv?blank|matrix.?blank)$",
15
+ "iqc": "^iqc$",
16
+ "eqc": "^eqc$",
17
+ "standard": "^(standard|std\\d*|cal(?:ibrator)?\\d*|.+standard)$",
18
+ "spikeIn": "spike.?in",
19
+ "stock": "^stock$"
20
+ },
21
+
22
+ "standardAllow": [
23
+ "ExtractionS",
24
+ "IS",
25
+ "internal.standard",
26
+ "PQC",
27
+ "pooledQC"
28
+ ],
29
+
30
+ "matrixVocab": {
31
+ "plasma": "Plasma",
32
+ "serum": "Serum",
33
+ "tissue": "Tissue",
34
+ "tissues": "Tissues",
35
+ "kidney": "Kidney",
36
+ "liver": "Liver",
37
+ "tumor": "Tumor",
38
+ "urine": "Urine",
39
+ "brain": "Brain",
40
+ "muscle": "Muscle",
41
+ "adipose": "Adipose",
42
+ "csf": "CSF",
43
+ "feces": "Feces",
44
+ "faeces": "Faeces",
45
+ "cells": "Cells",
46
+ "cell": "Cells",
47
+ "media": "Media",
48
+ "medium": "Medium",
49
+ "extract": "Extract"
50
+ },
51
+
52
+ "ionizationModes": {
53
+ "pos": "POS",
54
+ "positive": "POS",
55
+ "neg": "NEG",
56
+ "negative": "NEG"
57
+ },
58
+
59
+ "tissueParentTokens": ["tissue", "tissues"],
60
+
61
+ "replicateStripPatterns": [
62
+ "[_-]\\d{2,4}[A-Za-z]?$",
63
+ "[_-]T\\d+(?=[_-]|$)",
64
+ "[_-]B\\d+(?=[_-]|$)",
65
+ "[_-](?:rep(?:licate)?)\\d+(?=[_-]|$)"
66
+ ]
67
+ }
@@ -0,0 +1,4 @@
1
+ export const DEFAULT_COLORS = [
2
+ '#3B82F6', '#10B981', '#F59E0B', '#EF4444', '#8B5CF6',
3
+ '#EC4899', '#06B6D4', '#84CC16', '#F97316', '#6366F1',
4
+ ]