@opencloning/store 1.5.0 → 1.5.2

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @opencloning/store
2
2
 
3
+ ## 1.5.2
4
+
5
+ ## 1.5.1
6
+
7
+ ### Patch Changes
8
+
9
+ - [#651](https://github.com/manulera/OpenCloning_frontend/pull/651) [`b5c89e2`](https://github.com/manulera/OpenCloning_frontend/commit/b5c89e23aa1065319cb07a9ac48a26693dd0a21a) Thanks [@manulera](https://github.com/manulera)! - Allow primer design of Gibson and similar assembly methods to include fragments that are not amplified. Similar to what the NEBuilder planner does, where not all products are amplified. Perhaps in the future it would be useful to also allow the option to restore the restriction sites on the edge.
10
+
3
11
  ## 1.5.0
4
12
 
5
13
  ## 1.4.11
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opencloning/store",
3
- "version": "1.5.0",
3
+ "version": "1.5.2",
4
4
  "type": "module",
5
5
  "main": "./src/index.js",
6
6
  "exports": {
package/src/cloning.js CHANGED
@@ -104,44 +104,50 @@ const reducer = {
104
104
  },
105
105
 
106
106
  addPCRsAndSubsequentSourcesForAssembly(state, action) {
107
- // This is used by the PCR primer design for Gibson Assemblies. You pass a
108
- // sourceId (PCR from which the primer design was started),
109
- // and a list of templateIds to be amplified by PCR. Their outputs
110
- // will be used as input for a subsequent assembly reaction.
107
+ // templateIds is the FULL ordered list of template sequence IDs.
108
+ // amplified[i] indicates whether templateIds[i] should go through PCR.
109
+ // Non-amplified templates are fed directly into the assembly.
110
+ // sourceId is the existing PCR source for position 0 (when amplified).
111
111
  const { sourceId, templateIds, sourceType, newSequence } = action.payload;
112
+ // If amplified is not provided, assume all templates are amplified
113
+ const amplified = action.payload.amplified || templateIds.map(() => true);
114
+ // Remove the current source (a PCR), in case it was not amplified,
115
+ // TODO: this needs to be improved in the UI, but it's like this for now.
116
+ state.sources = state.sources.filter((s) => s.id !== sourceId);
112
117
  const { sources, sequences } = state;
113
118
 
114
- if (sources.find((s) => s.id === sourceId) === undefined) {
115
- throw new Error('Source not found');
119
+ const pcrOutputIds = [];
120
+ const assemblyInputIds = [];
121
+
122
+ for (let i = 0; i < templateIds.length; i++) {
123
+ if (amplified[i]) {
124
+ const nextId = getNextUniqueId(state);
125
+ sources.push({
126
+ id: nextId,
127
+ input: [{ sequence: templateIds[i] }],
128
+ type: 'PCRSource',
129
+ });
130
+ pcrOutputIds.push(nextId);
131
+ assemblyInputIds.push(nextId);
132
+ } else {
133
+ assemblyInputIds.push(templateIds[i]);
134
+ }
116
135
  }
117
- const sources2update = [sourceId];
118
- // Add the PCR sources
119
- templateIds.forEach((templateId) => {
120
- const nextId = getNextUniqueId(state);
121
- const newSource = {
122
- id: nextId,
123
- input: [{ sequence: templateId }],
124
- type: 'PCRSource',
125
- };
126
- sources.push(newSource);
127
- sources2update.push(newSource.id);
128
- });
129
136
 
130
- // Add the output sequences
131
- sources2update.forEach((id) => {
132
- sequences.push({
133
- ...newSequence,
134
- id,
135
- });
137
+ pcrOutputIds.forEach((id) => {
138
+ sequences.push({ ...newSequence, id });
136
139
  });
137
140
 
138
141
  if (sourceType !== null) {
139
- // Add the Assembly that takes the PCR outputs as input
140
- sources.push({
142
+ const assemblySource = {
141
143
  id: getNextUniqueId(state),
142
- input: sources2update.map((id) => ({ sequence: id })),
144
+ input: assemblyInputIds.map((id) => ({ sequence: id })),
143
145
  type: sourceType,
144
- });
146
+ };
147
+ if (action.payload.circularAssembly !== undefined) {
148
+ assemblySource.circular_assembly = action.payload.circularAssembly;
149
+ }
150
+ sources.push(assemblySource);
145
151
  }
146
152
  },
147
153
 
@@ -52,14 +52,14 @@ export function getPrimerDesignObject({ sources, sequences }) {
52
52
  const outputSequences = sequences.filter((e) => e.type === 'TemplateSequence' && Boolean(e.primer_design));
53
53
  if (outputSequences.length === 0) {
54
54
  // return 'No primer design sequence templates found';
55
- return { finalSource: null, otherInputIds: [], pcrSources: [], outputSequences: [] };
55
+ return { finalSource: null, otherInputIds: [], pcrSources: [], outputSequences: [], assemblyInputsInOrder: [] };
56
56
  }
57
57
  const mockSequenceIds = outputSequences.map((s) => s.id);
58
58
 
59
59
  // Find the PCRs from which the mock sequences are outputs
60
60
  const pcrSources = sources.filter((s) => s.type === 'PCRSource' && mockSequenceIds.includes(s.id));
61
61
  if (pcrSources.length === 0) {
62
- return { finalSource: null, otherInputIds: [], pcrSources: [], outputSequences: [] };
62
+ return { finalSource: null, otherInputIds: [], pcrSources: [], outputSequences: [], assemblyInputsInOrder: [] };
63
63
  }
64
64
 
65
65
  // Find the template sequences for those PCRs
@@ -68,7 +68,7 @@ export function getPrimerDesignObject({ sources, sequences }) {
68
68
  // They should not be mock sequences
69
69
  if (templateSequences.some((ts) => ts.type === 'TemplateSequence')) {
70
70
  // return 'TemplateSequence input to final source is a TemplateSequence';
71
- return { finalSource: null, otherInputIds: [], pcrSources: [], outputSequences: [] };
71
+ return { finalSource: null, otherInputIds: [], pcrSources: [], outputSequences: [], assemblyInputsInOrder: [] };
72
72
  }
73
73
 
74
74
  // Find the source they are input to (there should be zero or one)
@@ -76,11 +76,11 @@ export function getPrimerDesignObject({ sources, sequences }) {
76
76
 
77
77
  if (finalSources.length === 0) {
78
78
  // return as is
79
- return { finalSource: null, otherInputIds: [], pcrSources, outputSequences };
79
+ return { finalSource: null, otherInputIds: [], pcrSources, outputSequences, assemblyInputsInOrder: [] };
80
80
  }
81
81
  if (finalSources.length > 1) {
82
82
  // error
83
- return { finalSource: null, otherInputIds: [], pcrSources: [], outputSequences: [] };
83
+ return { finalSource: null, otherInputIds: [], pcrSources: [], outputSequences: [], assemblyInputsInOrder: [] };
84
84
  }
85
85
 
86
86
  const finalSource = finalSources[0];
@@ -91,10 +91,20 @@ export function getPrimerDesignObject({ sources, sequences }) {
91
91
  // There should be no TemplateSequence as an input that does not have primer_design set
92
92
  if (otherInputs.some((i) => i.type === 'TemplateSequence' && !Boolean(i.primer_design))) {
93
93
  // return 'TemplateSequence input to final source does not have primer_design set';
94
- return { finalSource: null, otherInputIds: [], pcrSources: [], outputSequences: [] };
94
+ return { finalSource: null, otherInputIds: [], pcrSources: [], outputSequences: [], assemblyInputsInOrder: [] };
95
95
  }
96
96
 
97
- return { finalSource, otherInputIds, pcrSources, outputSequences };
97
+ // Build ordered assembly inputs for Gibson-like assemblies
98
+ const assemblyInputsInOrder = finalSource.input.map((inputItem) => {
99
+ const inputId = inputItem.sequence;
100
+ if (mockSequenceIds.includes(inputId)) {
101
+ const pcrSource = pcrSources.find((s) => s.id === inputId);
102
+ return { templateSequenceId: getPcrTemplateSequenceId(pcrSource), isAmplified: true };
103
+ }
104
+ return { templateSequenceId: inputId, isAmplified: false };
105
+ });
106
+
107
+ return { finalSource, otherInputIds, pcrSources, outputSequences, assemblyInputsInOrder };
98
108
  }
99
109
 
100
110
  const formatPrimer = (primer, position) => {