p2s_mapper 1.2.2 → 1.4.0

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/README.md CHANGED
@@ -1,16 +1,28 @@
1
1
  # p2s_mapper
2
2
 
3
- Map a transcript's translation onto a protein structure: the pairwise alignment
4
- between them, the coordinate maps that alignment implies, which chain of the
5
- structure is the gene's product, SIFTS residue numbering, and the AlphaFold,
6
- PDBe and UniProt lookups that find a structure to map in the first place.
3
+ Map a transcript's translation onto a protein structure.
4
+
5
+ - **Align** the transcript to the structure's sequence (Smith-Waterman or
6
+ Needleman-Wunsch, BLOSUM62)
7
+ - **Convert coordinates** both ways between transcript, alignment, structure,
8
+ Mol\* and UniProt numbering
9
+ - **Choose the chain** that best matches the gene's protein
10
+ - **Use SIFTS** to place UniProt annotations and drop fusion-partner residues
11
+ - **Find structures** through AlphaFold, 3D-Beacons, PDBe and UniProt
12
+
13
+ ## Works with g2p_mapper
14
+
15
+ p2s_mapper covers **protein ↔ structure**. The other half, **genome ↔ protein**,
16
+ is [g2p_mapper](https://github.com/GMOD/g2p_mapper): it turns a transcript's CDS
17
+ into per-codon genome positions, on either strand and across exon boundaries. It
18
+ is p2s_mapper's only runtime dependency, and chaining the two takes you from a
19
+ genome coordinate to a residue in 3D and back.
7
20
 
8
21
  Extracted from
9
22
  [jbrowse-plugin-protein3d](https://github.com/GMOD/jbrowse-plugin-protein3d),
10
23
  where we made the measurements behind the scoring rules. The package has no
11
- React, no JBrowse and no Mol\* dependency: a loaded Mol\* model reaches it
12
- through narrow structural interfaces, and `g2p_mapper` is the only runtime
13
- dependency.
24
+ React, JBrowse or Mol\* dependency: a loaded Mol\* model reaches it through
25
+ narrow structural interfaces.
14
26
 
15
27
  ## Install
16
28
 
@@ -18,133 +30,28 @@ dependency.
18
30
  npm install p2s_mapper
19
31
  ```
20
32
 
21
- ## Coordinate conventions
22
-
23
- One residue has up to four numbers, and mixing them causes the off-by-one bugs
24
- this package's types prevent. **Every stored or computed coordinate is a 0-based
25
- position**: an index into the ungapped structure sequence or the ungapped
26
- transcript sequence, the one numbering that is dense and zero-based whatever the
27
- file. `coordinates.ts` brands the three internal spaces — structure position,
28
- transcript position, alignment column — so the compiler rejects mixing them. Two
29
- conversions leave that space, and each has exactly one correct route. **Mol\* is
30
- addressed by `label_seq_id`**, which is `position + 1` only for a file carrying
31
- `entity_poly_seq` or SEQRES; a SEQRES-less PDB numbers its observed residues by
32
- author numbering and leaves holes at unobserved loops, so `Entity.seqIds`
33
- carries the real ids and every crossing goes through `toLabelSeqIds`,
34
- `rangeToLabelSeqIds` or `makeLabelSeqIdIndex`. **The user sees `auth_seq_id`**,
35
- the depositors' numbering that papers and UniProt cite (1TUP position 154
36
- reads 248) and that Mol\*'s own hover shows; `Entity.authSeqIds` carries it, and
37
- it is display-only. UniProt positions are 1-based, and `pdbUniProtMapping`
38
- converts them with SIFTS rather than assuming any offset.
39
-
40
- ## Exports
41
-
42
- ### Alignment
43
-
44
- `runLocalAlignment`, `scoredAlignment`, `needlemanWunsch`, `smithWaterman`,
45
- `selfScore`, `alignmentTooLarge`, `MAX_ALIGNMENT_CELLS` — Smith-Waterman and
46
- Needleman-Wunsch over BLOSUM62, with affine gaps and a packed traceback.
47
-
48
- `PairwiseAlignment`, `transcriptAlignedSeq`, `structureAlignedSeq`,
49
- `alignmentLength`, `pairwiseAlignmentProblem`,
50
- `pairwiseAlignmentSequenceProblem`, `mappedStructureIdentity`,
51
- `unmapStructurePositions` — the two-row alignment, whose **row order is a
52
- contract**: row 0 is the transcript, row 1 is the structure. Read it through the
53
- accessors, not by index.
54
-
55
- `alignmentQuality`, `isLowSimilarity`, `describeAlignmentQuality`,
56
- `describeTranscriptCoverage`, `describeCoveredRange` — identity over the shorter
57
- sequence separates a real match from a chance local alignment; local identity
58
- alone does not.
59
-
60
- `AlignmentAlgorithm`, `coerceAlignmentAlgorithm`, `ALIGNMENT_ALGORITHM_LABELS`.
61
-
62
- ### Coordinates
63
-
64
- `makeCoordinateMapper`, `CoordinateMapper`, `transcriptRangeToStructureRange`,
65
- `structurePos`, `transcriptPos`, `alignmentCol` — every conversion built once
66
- from an alignment, branded by space.
67
-
68
- `structureSeqVsTranscriptSeqMap`, `structurePositionToAlignmentMap`,
69
- `transcriptPositionToAlignmentMap`, `invertMap`, `codonGenomeSpan`,
70
- `stripStopCodon`, `stripAllStopCodons`.
71
-
72
- ### Chain choice
73
-
74
- `chooseMappedEntity`, `alignTranscriptToEntity`, `explainedFraction`,
75
- `interactionMatchesMappedEntity` — which polymer entity is the transcript's
76
- product, ranked by identical residues over the **shorter** of the two sequences.
77
- A raw match count picks the large partner of every bound peptide, and the
78
- alignment score does not separate them either.
79
-
80
- `extractEntities`, `extractStructureSequences`, `entityLabel`, `residueNumber`,
81
- `residueRangeToPositions`, `fillAuthSeqIds`, `oneLetterSequence`,
82
- `toLabelSeqIds`, `rangeToLabelSeqIds`, `makeLabelSeqIdIndex` — read a loaded
83
- Mol\* model through a structural interface. Read `sequence.code`, never
84
- `sequence.label`: `label` spells MSE, TPO and ACE by component id, so the string
85
- outgrows `seqId` and every later position addresses the wrong residue.
86
-
87
- `extractPerResidueConfidence`, `looksLikePlddt` — AlphaFold's pLDDT out of the
88
- B-factor column, keyed by `label_seq_id` because the hierarchy holds only
89
- observed residues.
90
-
91
- `classifyIsoforms`, `selectBestTranscript`, `pickStructureSequence` — rank plain
92
- `{ id, seq }` isoform records against a chain.
93
-
94
- ### SIFTS
95
-
96
- `fetchUniProtStructureMappings`, `parseUniProtStructureMappings`,
97
- `pdbeSiftsUrl`, `chooseUniProtMappingForEntity`, `makeUniProtPositionMap`,
98
- `identityUniProtPositionMap`, `fusionPartnerPositions` — the authoritative
99
- UniProt ↔ structure alignment. `fusionPartnerPositions` unmaps the residues
100
- SIFTS gives another protein on a fusion construct, which local alignment
101
- otherwise bridges (2RH1 scatters 33 receptor residues onto T4 lysozyme).
102
-
103
- `toAuthorRange`, `segmentsForAccession` — the author-numbered range a UniProt
104
- range is cited by. Haemoglobin numbers from the mature protein, so author
105
- residue 1 is UniProt residue 2.
106
-
107
- ### Structure sources
108
-
109
- `fetchAlphaFoldModels`, `parseAlphaFoldModels`, `pickAlphaFoldModel` — asked
110
- rather than derived: a protein past AlphaFold's length cap has no F1 model at
111
- all, and the model version moves.
112
-
113
- `fetchExperimentalStructures`, `parseExperimentalStructures` — 3D-Beacons'
114
- experimental entries, PDBe only, because SASBDB's scattering fits file under the
115
- same category with near-full coverage and no residue mapping.
116
-
117
- `pdbeBestStructuresUrl`, `parseBestStructures`, `isPdbId`,
118
- `pdbeEntryMoleculesUrl`, `parseEntryMolecules`, `searchUniProtEntries`,
119
- `buildGeneNameQuery`, `isRecognizedDatabaseId`, `buildUniProtXrefQuery`,
120
- `getDbIdLabel`, `stripTrailingVersion`.
121
-
122
- Every request takes its `fetch` from the call —
123
- `{ fetch?: typeof fetch, signal? }`, defaulting to `globalThis.fetch` — so a
124
- host can hand in an instrumented one and a test can hand in a double.
33
+ ## How it fits together
125
34
 
126
- ### Urls and formats
35
+ ![From a gene on the genome to a residue in 3D, and back](docs/img/pipeline.svg)
127
36
 
128
- `getPdbStructureUrl`, `getAlphaFoldStructureUrl`, `resolveStructureUrl`,
129
- `getPdbIdFromUrl`, `getUniprotIdFromAlphaFoldTarget`,
130
- `getStructureUrlFromTarget`, `getConfidenceUrlFromTarget`,
131
- `structureDisplayLabel`, `uniprotGffUrl`, `uniprotFastaUrl`, `uniprotEntryUrl`,
132
- `rcsbEntryUrl`.
37
+ ## Docs
133
38
 
134
- `structureFormatFromContent`, `structureFormatFromName`,
135
- `structureFileExtension`, `isBinaryStructureUrl` — which parser a structure
136
- needs, sniffed from **content** rather than a filename. PDB read as mmCIF
137
- throws, while mmCIF read as PDB succeeds and yields a model with thousands of
138
- misread atoms and zero polymer entities.
39
+ - [faq.md](docs/faq.md) — can I trust the mapping? What the package checks, and
40
+ what it leaves to you
41
+ - [pipeline.md](docs/pipeline.md) — the flow above, step by step, and why chain
42
+ choice divides by the shorter sequence
43
+ - [coordinates.md](docs/coordinates.md) — the four numberings of a residue and
44
+ the one route between each
45
+ - [api.md](docs/api.md) — every export, grouped by job
139
46
 
140
- `caCoordsToPdb`, `hasValidCaCoords` — a PDB file from Foldseek Cα coordinates.
47
+ ## Things to know first
141
48
 
142
- `rawfetch`, `myfetch`, `jsonfetch`, `httpError`, `HttpError`,
143
- `isDefinitiveFailure`, `networkError`, `abortError`, `timeout`, `FetchOptions`.
144
- A failed response throws an `HttpError` carrying its `status`, and
145
- `isDefinitiveFailure` is true for a 4xx — the server understood and declined, so
146
- retrying repeats the answer. `fetchUniProtStructureMappings` uses it: PDBe
147
- answers 404 for an entry it has no UniProt mapping for at all.
49
+ - Every coordinate in the API is **0-based**, branded by space so the compiler
50
+ rejects mixing them. See [coordinates.md](docs/coordinates.md).
51
+ - A `PairwiseAlignment` has **row 0 = transcript, row 1 = structure**. Use the
52
+ accessors, not indexes.
53
+ - Network functions take `{ fetch?, signal? }` and default to
54
+ `globalThis.fetch`.
148
55
 
149
56
  ## License
150
57
 
@@ -2,8 +2,12 @@ import type { FetchOptions } from './fetchUtils.ts';
2
2
  export interface AlphaFoldModel {
3
3
  /** UniProt accession, with an isoform suffix on an isoform model */
4
4
  accession: string;
5
+ /** AlphaFold DB's id for the model, e.g. AF-P04637-F1 */
6
+ entity?: string;
5
7
  url: string;
6
8
  confidenceUrl?: string;
9
+ /** mean per-residue confidence (pLDDT), 0-100 */
10
+ meanPlddt?: number;
7
11
  sequence: string;
8
12
  }
9
13
  export declare function parseAlphaFoldModels(json: unknown): AlphaFoldModel[];
@@ -16,8 +16,12 @@ function parseAlphaFoldModels(json) {
16
16
  ? [
17
17
  {
18
18
  accession: e.uniprotAccession,
19
+ entity: typeof e.modelEntityId === 'string' ? e.modelEntityId : undefined,
19
20
  url: e.cifUrl,
20
21
  confidenceUrl: typeof e.plddtDocUrl === 'string' ? e.plddtDocUrl : undefined,
22
+ meanPlddt: typeof e.globalMetricValue === 'number'
23
+ ? e.globalMetricValue
24
+ : undefined,
21
25
  sequence: e.sequence,
22
26
  },
23
27
  ]
@@ -1 +1 @@
1
- {"version":3,"file":"alphaFoldModels.js","sourceRoot":"","sources":["../src/alphaFoldModels.ts"],"names":[],"mappings":";;AAwBA,oDAiBC;AAUD,oDAaC;AAUD,gDAgBC;AA1FD,mDAAqD;AAGrD,2DAAoD;AAiBpD,SAAS,iBAAiB,CAAC,KAAc;IACvC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAA;AACpD,CAAC;AAED,SAAgB,oBAAoB,CAAC,IAAa;IAChD,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CACnD,iBAAiB,CAAC,CAAC,CAAC;QACpB,OAAO,CAAC,CAAC,gBAAgB,KAAK,QAAQ;QACtC,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ;QAC5B,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ;QAC5B,CAAC,CAAC;YACE;gBACE,SAAS,EAAE,CAAC,CAAC,gBAAgB;gBAC7B,GAAG,EAAE,CAAC,CAAC,MAAM;gBACb,aAAa,EACX,OAAO,CAAC,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS;gBAC/D,QAAQ,EAAE,CAAC,CAAC,QAAQ;aACrB;SACF;QACH,CAAC,CAAC,EAAE,CACP,CAAA;AACH,CAAC;AAED;;;;;;;GAOG;AACI,KAAK,UAAU,oBAAoB,CACxC,SAAiB,EACjB,IAAmB;IAEnB,MAAM,GAAG,GAAG,8CAA8C,kBAAkB,CAAC,SAAS,CAAC,EAAE,CAAA;IACzF,MAAM,GAAG,GAAG,MAAM,IAAA,wBAAQ,EAAC,GAAG,EAAE,IAAI,CAAC,CAAA;IACrC,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC7C,OAAO,EAAE,CAAA;IACX,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,MAAM,IAAA,yBAAS,EAAC,GAAG,EAAE,GAAG,CAAC,CAAA;IACjC,CAAC;IACD,OAAO,oBAAoB,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,CAAA;AAC/C,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,kBAAkB,CAChC,MAAwB,EACxB,gBAA6D;IAE7D,MAAM,YAAY,GAAG,IAAI,GAAG,CAC1B,MAAM,CAAC,MAAM,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAA,kCAAc,EAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CACtE,CAAA;IACD,MAAM,cAAc,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CACrC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CACxE,CAAA;IACD,OAAO,CACL,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QACtD,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QACpD,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CACrE,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"alphaFoldModels.js","sourceRoot":"","sources":["../src/alphaFoldModels.ts"],"names":[],"mappings":"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"}
package/dist/dbIds.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- type DbType = 'ensembl' | 'refseq' | 'ccds' | 'hgnc';
1
+ type DbType = 'ensembl' | 'refseq' | 'ccds' | 'hgnc' | 'geneid';
2
2
  export declare function matchDbIdPattern(id: string): {
3
3
  db: DbType;
4
4
  pattern: RegExp;
package/dist/dbIds.js CHANGED
@@ -18,6 +18,10 @@ const DB_ID_PATTERNS = [
18
18
  { db: 'refseq', pattern: /^[NXYA]P_\d+/i, label: 'RefSeq protein' },
19
19
  { db: 'ccds', pattern: /^CCDS\d+/i, label: 'CCDS' },
20
20
  { db: 'hgnc', pattern: /^HGNC:\d+/i, label: 'HGNC' },
21
+ // NCBI's GFFs carry `Dbxref=GeneID:7157`, and UniProt keeps the GeneID
22
+ // cross-reference for every organism NCBI annotates, where a symbol search
23
+ // needs a taxon and misses a TrEMBL-only gene.
24
+ { db: 'geneid', pattern: /^GeneID:\d+$/i, label: 'NCBI Gene' },
21
25
  ];
22
26
  function matchDbIdPattern(id) {
23
27
  return DB_ID_PATTERNS.find(p => p.pattern.test(id));
@@ -37,7 +41,7 @@ function getDbIdLabel(id) {
37
41
  function buildUniProtXrefQuery(id) {
38
42
  const match = matchDbIdPattern(id);
39
43
  return match
40
- ? `xref:${match.db}-${match.db === 'hgnc' ? id.replace('HGNC:', '') : id}`
44
+ ? `xref:${match.db}-${match.db === 'hgnc' || match.db === 'geneid' ? id.replace(/^[^:]+:/, '') : id}`
41
45
  : undefined;
42
46
  }
43
47
  function stripTrailingVersion(s) {
package/dist/dbIds.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"dbIds.js","sourceRoot":"","sources":["../src/dbIds.ts"],"names":[],"mappings":";;AAsBA,4CAEC;AAGD,wDAEC;AAID,oCAGC;AAID,sDAKC;AAED,oDAEC;AA1CD,MAAM,cAAc,GAAqD;IACvE,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,cAAc,EAAE;IACpE,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,oBAAoB,EAAE;IAC1E,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,iBAAiB,EAAE;IACvE,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE;IAC9D,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,cAAc,EAAE;IAC/D,4EAA4E;IAC5E,2EAA2E;IAC3E,qEAAqE;IACrE,4EAA4E;IAC5E,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,gBAAgB,EAAE;IACnE,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE;IACnD,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE;CACrD,CAAA;AAED,SAAgB,gBAAgB,CAAC,EAAU;IACzC,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;AACrD,CAAC;AAED,8DAA8D;AAC9D,SAAgB,sBAAsB,CAAC,EAAU;IAC/C,OAAO,gBAAgB,CAAC,EAAE,CAAC,KAAK,SAAS,CAAA;AAC3C,CAAC;AAED;8CAC8C;AAC9C,SAAgB,YAAY,CAAC,EAAU;IACrC,MAAM,KAAK,GAAG,gBAAgB,CAAC,EAAE,CAAC,CAAA;IAClC,OAAO,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAA;AAC9C,CAAC;AAED;4EAC4E;AAC5E,SAAgB,qBAAqB,CAAC,EAAU;IAC9C,MAAM,KAAK,GAAG,gBAAgB,CAAC,EAAE,CAAC,CAAA;IAClC,OAAO,KAAK;QACV,CAAC,CAAC,QAAQ,KAAK,CAAC,EAAE,IAAI,KAAK,CAAC,EAAE,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;QAC1E,CAAC,CAAC,SAAS,CAAA;AACf,CAAC;AAED,SAAgB,oBAAoB,CAAC,CAAU;IAC7C,OAAO,CAAC,EAAE,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;AACpC,CAAC"}
1
+ {"version":3,"file":"dbIds.js","sourceRoot":"","sources":["../src/dbIds.ts"],"names":[],"mappings":";;AA0BA,4CAEC;AAGD,wDAEC;AAID,oCAGC;AAID,sDAKC;AAED,oDAEC;AA9CD,MAAM,cAAc,GAAqD;IACvE,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,cAAc,EAAE;IACpE,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,oBAAoB,EAAE;IAC1E,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,iBAAiB,EAAE;IACvE,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE;IAC9D,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,cAAc,EAAE;IAC/D,4EAA4E;IAC5E,2EAA2E;IAC3E,qEAAqE;IACrE,4EAA4E;IAC5E,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,gBAAgB,EAAE;IACnE,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE;IACnD,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE;IACpD,uEAAuE;IACvE,2EAA2E;IAC3E,+CAA+C;IAC/C,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,WAAW,EAAE;CAC/D,CAAA;AAED,SAAgB,gBAAgB,CAAC,EAAU;IACzC,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;AACrD,CAAC;AAED,8DAA8D;AAC9D,SAAgB,sBAAsB,CAAC,EAAU;IAC/C,OAAO,gBAAgB,CAAC,EAAE,CAAC,KAAK,SAAS,CAAA;AAC3C,CAAC;AAED;8CAC8C;AAC9C,SAAgB,YAAY,CAAC,EAAU;IACrC,MAAM,KAAK,GAAG,gBAAgB,CAAC,EAAE,CAAC,CAAA;IAClC,OAAO,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAA;AAC9C,CAAC;AAED;4EAC4E;AAC5E,SAAgB,qBAAqB,CAAC,EAAU;IAC9C,MAAM,KAAK,GAAG,gBAAgB,CAAC,EAAE,CAAC,CAAA;IAClC,OAAO,KAAK;QACV,CAAC,CAAC,QAAQ,KAAK,CAAC,EAAE,IAAI,KAAK,CAAC,EAAE,KAAK,MAAM,IAAI,KAAK,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;QACrG,CAAC,CAAC,SAAS,CAAA;AACf,CAAC;AAED,SAAgB,oBAAoB,CAAC,CAAU;IAC7C,OAAO,CAAC,EAAE,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;AACpC,CAAC"}
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export * from './types.ts';
2
2
  export * from './mappings.ts';
3
3
  export * from './pairwiseAlignment.ts';
4
4
  export * from './alignmentQuality.ts';
5
+ export * from './sharedStretches.ts';
5
6
  export * from './coordinates.ts';
6
7
  export * from './invertMap.ts';
7
8
  export * from './stripStopCodon.ts';
package/dist/index.js CHANGED
@@ -19,6 +19,7 @@ __exportStar(require("./types.js"), exports);
19
19
  __exportStar(require("./mappings.js"), exports);
20
20
  __exportStar(require("./pairwiseAlignment.js"), exports);
21
21
  __exportStar(require("./alignmentQuality.js"), exports);
22
+ __exportStar(require("./sharedStretches.js"), exports);
22
23
  // Coordinates
23
24
  __exportStar(require("./coordinates.js"), exports);
24
25
  __exportStar(require("./invertMap.js"), exports);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,YAAY;AACZ,6CAA0B;AAC1B,gDAA6B;AAC7B,yDAAsC;AACtC,wDAAqC;AAErC,cAAc;AACd,mDAAgC;AAChC,iDAA8B;AAC9B,sDAAmC;AAEnC,eAAe;AACf,0DAAuC;AACvC,iEAA8C;AAC9C,mEAAgD;AAChD,sDAAmC;AAEnC,QAAQ;AACR,yDAAsC;AACtC,sDAAmC;AAEnC,oBAAoB;AACpB,uDAAoC;AACpC,0DAAuC;AACvC,0DAAuC;AACvC,wDAAqC;AACrC,qDAAkC;AAClC,6CAA0B;AAE1B,mBAAmB;AACnB,qDAAkC;AAClC,uDAAoC;AACpC,qDAAkC;AAClC,kDAA+B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,YAAY;AACZ,6CAA0B;AAC1B,gDAA6B;AAC7B,yDAAsC;AACtC,wDAAqC;AACrC,uDAAoC;AAEpC,cAAc;AACd,mDAAgC;AAChC,iDAA8B;AAC9B,sDAAmC;AAEnC,eAAe;AACf,0DAAuC;AACvC,iEAA8C;AAC9C,mEAAgD;AAChD,sDAAmC;AAEnC,QAAQ;AACR,yDAAsC;AACtC,sDAAmC;AAEnC,oBAAoB;AACpB,uDAAoC;AACpC,0DAAuC;AACvC,0DAAuC;AACvC,wDAAqC;AACrC,qDAAkC;AAClC,6CAA0B;AAE1B,mBAAmB;AACnB,qDAAkC;AAClC,uDAAoC;AACpC,qDAAkC;AAClC,kDAA+B"}
@@ -0,0 +1,17 @@
1
+ import type { PairwiseAlignment } from './mappings.ts';
2
+ /**
3
+ * Each residue of row `a` that row `b` shares, as 0-based index in `a` to
4
+ * 0-based index in `b`. A lone substitution between two kept stretches carries
5
+ * too: it is one codon two databases read differently, as MUC1's repeats are.
6
+ */
7
+ export declare function sharedResidueMap(a: string, b: string): Map<number, number>;
8
+ /** Each residue of isoform `from` that isoform `to` shares, through a global
9
+ * alignment of the two. */
10
+ export declare function sharedIsoformResidues(from: string, to: string): Map<number, number>;
11
+ /**
12
+ * The alignment of a transcript to another isoform of its protein, with every
13
+ * residue outside a shared stretch unmapped. For two isoforms, not for a
14
+ * structure: a mismatch against a structure's chain is usually a point
15
+ * mutation in the construct, at the right place in the fold.
16
+ */
17
+ export declare function keepSharedStretches(pa: PairwiseAlignment): PairwiseAlignment;
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ // Which residues two isoforms of one protein share. An alignment column pairs
3
+ // two residues whether or not one codon encodes both: a mutually exclusive exon
4
+ // sits opposite its partner (PKM's exons 9 and 10, FGFR2's IIIb and IIIc), and
5
+ // its residues align, mismatches and chance identities included. A residue
6
+ // carries across only inside a stretch the two spell letter for letter: a long
7
+ // one, or a short one bounded on both sides by a gap or a sequence end, the
8
+ // shape a short shared exon takes (VEGFA's six-residue exon 8a).
9
+ //
10
+ // Measured 2026-09-25 against codon identity on the genome, over every isoform
11
+ // of 13 genes (TP53, PKM, CDKN2A, FGFR2, TPM1, BRAF, EGFR, SCN8A, MAPT, BIN1,
12
+ // VEGFA, TPM3, CD44; 89,927 truly shared residues), on global alignments: 335
13
+ // placed wrongly and 28 missed, against 1,885 and 28 for every identical
14
+ // residue and 328 and 64 for long stretches alone. The misses are single
15
+ // residues at exon junctions, where the gap fits either side.
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.sharedResidueMap = sharedResidueMap;
18
+ exports.sharedIsoformResidues = sharedIsoformResidues;
19
+ exports.keepSharedStretches = keepSharedStretches;
20
+ const mappings_ts_1 = require("./mappings.js");
21
+ const pairwiseAlignment_ts_1 = require("./pairwiseAlignment.js");
22
+ const LONG_STRETCH = 10;
23
+ const SHORT_EXON = 3;
24
+ /**
25
+ * Each residue of row `a` that row `b` shares, as 0-based index in `a` to
26
+ * 0-based index in `b`. A lone substitution between two kept stretches carries
27
+ * too: it is one codon two databases read differently, as MUC1's repeats are.
28
+ */
29
+ function sharedResidueMap(a, b) {
30
+ const cols = [];
31
+ for (let c = 0, x = 0, y = 0; c < a.length; c++) {
32
+ const inA = a[c] !== '-';
33
+ const inB = b[c] !== '-';
34
+ cols.push({
35
+ x,
36
+ y,
37
+ kind: !inA || !inB
38
+ ? 'gap'
39
+ : a[c].toUpperCase() === b[c].toUpperCase()
40
+ ? 'same'
41
+ : 'mismatch',
42
+ });
43
+ if (inA) {
44
+ x++;
45
+ }
46
+ if (inB) {
47
+ y++;
48
+ }
49
+ }
50
+ const bounded = (c) => cols[c]?.kind !== 'mismatch';
51
+ const kept = cols.map(() => false);
52
+ for (let start = 0; start < cols.length;) {
53
+ let end = start;
54
+ while (cols[end]?.kind === 'same') {
55
+ end++;
56
+ }
57
+ const length = end - start;
58
+ if (length >= LONG_STRETCH ||
59
+ (length >= SHORT_EXON && bounded(start - 1) && bounded(end))) {
60
+ kept.fill(true, start, end);
61
+ }
62
+ start = Math.max(end, start + 1);
63
+ }
64
+ const shared = new Map();
65
+ cols.forEach((col, c) => {
66
+ if (kept[c] || (col.kind === 'mismatch' && kept[c - 1] && kept[c + 1])) {
67
+ shared.set(col.x, col.y);
68
+ }
69
+ });
70
+ return shared;
71
+ }
72
+ /** Each residue of isoform `from` that isoform `to` shares, through a global
73
+ * alignment of the two. */
74
+ function sharedIsoformResidues(from, to) {
75
+ const { alignedSeq1, alignedSeq2 } = (0, pairwiseAlignment_ts_1.needlemanWunsch)(from, to);
76
+ return sharedResidueMap(alignedSeq1, alignedSeq2);
77
+ }
78
+ /**
79
+ * The alignment of a transcript to another isoform of its protein, with every
80
+ * residue outside a shared stretch unmapped. For two isoforms, not for a
81
+ * structure: a mismatch against a structure's chain is usually a point
82
+ * mutation in the construct, at the right place in the fold.
83
+ */
84
+ function keepSharedStretches(pa) {
85
+ const structure = (0, mappings_ts_1.structureAlignedSeq)(pa);
86
+ const transcript = (0, mappings_ts_1.transcriptAlignedSeq)(pa);
87
+ const shared = sharedResidueMap(structure, transcript);
88
+ const unshared = new Set();
89
+ for (let i = 0, j = 0; i < structure.length; i++) {
90
+ if (structure[i] !== '-') {
91
+ if (transcript[i] !== '-' && !shared.has(j)) {
92
+ unshared.add(j);
93
+ }
94
+ j++;
95
+ }
96
+ }
97
+ return (0, mappings_ts_1.unmapStructurePositions)(pa, unshared);
98
+ }
99
+ //# sourceMappingURL=sharedStretches.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sharedStretches.js","sourceRoot":"","sources":["../src/sharedStretches.ts"],"names":[],"mappings":"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"}
@@ -10,8 +10,11 @@ exports.beaconsSummaryUrl = beaconsSummaryUrl;
10
10
  exports.parseExperimentalStructures = parseExperimentalStructures;
11
11
  exports.fetchExperimentalStructures = fetchExperimentalStructures;
12
12
  const fetchUtils_ts_1 = require("./fetchUtils.js");
13
+ // Unfiltered: the `?provider=pdbe` form answered BRAF, HBB and BRCA2 with a 404
14
+ // about one time in three (2026-10-09), and the parser keeps PDBe's entries
15
+ // anyway.
13
16
  function beaconsSummaryUrl(uniprotId) {
14
- return `https://www.ebi.ac.uk/pdbe/pdbe-kb/3dbeacons/api/uniprot/summary/${encodeURIComponent(uniprotId)}.json?provider=pdbe`;
17
+ return `https://www.ebi.ac.uk/pdbe/pdbe-kb/3dbeacons/api/uniprot/summary/${encodeURIComponent(uniprotId)}.json`;
15
18
  }
16
19
  function isRecord(value) {
17
20
  return typeof value === 'object' && value !== null && !Array.isArray(value);
@@ -70,7 +73,15 @@ function parseExperimentalStructures(json) {
70
73
  /** Best-effort: an unreachable API reads as "no entries", which costs a
71
74
  * structure suggestion and nothing else. */
72
75
  async function fetchExperimentalStructures(uniprotId, opts) {
73
- const res = await (0, fetchUtils_ts_1.rawfetch)(beaconsSummaryUrl(uniprotId), opts).catch(() => undefined);
74
- return res?.ok ? parseExperimentalStructures(await res.json()) : [];
76
+ for (let attempt = 0; attempt < 2; attempt++) {
77
+ const res = await (0, fetchUtils_ts_1.rawfetch)(beaconsSummaryUrl(uniprotId), opts).catch(() => undefined);
78
+ if (res?.ok) {
79
+ return parseExperimentalStructures(await res.json());
80
+ }
81
+ if (res?.status === 404 || opts?.signal?.aborted) {
82
+ return [];
83
+ }
84
+ }
85
+ return [];
75
86
  }
76
87
  //# sourceMappingURL=structureSources.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"structureSources.js","sourceRoot":"","sources":["../src/structureSources.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"structureSources.js","sourceRoot":"","sources":["../src/structureSources.ts"],"names":[],"mappings":"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"}
@@ -2,8 +2,12 @@ import type { FetchOptions } from './fetchUtils.ts';
2
2
  export interface AlphaFoldModel {
3
3
  /** UniProt accession, with an isoform suffix on an isoform model */
4
4
  accession: string;
5
+ /** AlphaFold DB's id for the model, e.g. AF-P04637-F1 */
6
+ entity?: string;
5
7
  url: string;
6
8
  confidenceUrl?: string;
9
+ /** mean per-residue confidence (pLDDT), 0-100 */
10
+ meanPlddt?: number;
7
11
  sequence: string;
8
12
  }
9
13
  export declare function parseAlphaFoldModels(json: unknown): AlphaFoldModel[];
@@ -11,8 +11,12 @@ export function parseAlphaFoldModels(json) {
11
11
  ? [
12
12
  {
13
13
  accession: e.uniprotAccession,
14
+ entity: typeof e.modelEntityId === 'string' ? e.modelEntityId : undefined,
14
15
  url: e.cifUrl,
15
16
  confidenceUrl: typeof e.plddtDocUrl === 'string' ? e.plddtDocUrl : undefined,
17
+ meanPlddt: typeof e.globalMetricValue === 'number'
18
+ ? e.globalMetricValue
19
+ : undefined,
16
20
  sequence: e.sequence,
17
21
  },
18
22
  ]
@@ -1 +1 @@
1
- {"version":3,"file":"alphaFoldModels.js","sourceRoot":"","sources":["../src/alphaFoldModels.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"alphaFoldModels.js","sourceRoot":"","sources":["../src/alphaFoldModels.ts"],"names":[],"mappings":"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"}
package/esm/dbIds.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- type DbType = 'ensembl' | 'refseq' | 'ccds' | 'hgnc';
1
+ type DbType = 'ensembl' | 'refseq' | 'ccds' | 'hgnc' | 'geneid';
2
2
  export declare function matchDbIdPattern(id: string): {
3
3
  db: DbType;
4
4
  pattern: RegExp;
package/esm/dbIds.js CHANGED
@@ -11,6 +11,10 @@ const DB_ID_PATTERNS = [
11
11
  { db: 'refseq', pattern: /^[NXYA]P_\d+/i, label: 'RefSeq protein' },
12
12
  { db: 'ccds', pattern: /^CCDS\d+/i, label: 'CCDS' },
13
13
  { db: 'hgnc', pattern: /^HGNC:\d+/i, label: 'HGNC' },
14
+ // NCBI's GFFs carry `Dbxref=GeneID:7157`, and UniProt keeps the GeneID
15
+ // cross-reference for every organism NCBI annotates, where a symbol search
16
+ // needs a taxon and misses a TrEMBL-only gene.
17
+ { db: 'geneid', pattern: /^GeneID:\d+$/i, label: 'NCBI Gene' },
14
18
  ];
15
19
  export function matchDbIdPattern(id) {
16
20
  return DB_ID_PATTERNS.find(p => p.pattern.test(id));
@@ -30,7 +34,7 @@ export function getDbIdLabel(id) {
30
34
  export function buildUniProtXrefQuery(id) {
31
35
  const match = matchDbIdPattern(id);
32
36
  return match
33
- ? `xref:${match.db}-${match.db === 'hgnc' ? id.replace('HGNC:', '') : id}`
37
+ ? `xref:${match.db}-${match.db === 'hgnc' || match.db === 'geneid' ? id.replace(/^[^:]+:/, '') : id}`
34
38
  : undefined;
35
39
  }
36
40
  export function stripTrailingVersion(s) {
package/esm/dbIds.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"dbIds.js","sourceRoot":"","sources":["../src/dbIds.ts"],"names":[],"mappings":"AAOA,MAAM,cAAc,GAAqD;IACvE,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,cAAc,EAAE;IACpE,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,oBAAoB,EAAE;IAC1E,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,iBAAiB,EAAE;IACvE,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE;IAC9D,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,cAAc,EAAE;IAC/D,4EAA4E;IAC5E,2EAA2E;IAC3E,qEAAqE;IACrE,4EAA4E;IAC5E,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,gBAAgB,EAAE;IACnE,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE;IACnD,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE;CACrD,CAAA;AAED,MAAM,UAAU,gBAAgB,CAAC,EAAU;IACzC,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;AACrD,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,sBAAsB,CAAC,EAAU;IAC/C,OAAO,gBAAgB,CAAC,EAAE,CAAC,KAAK,SAAS,CAAA;AAC3C,CAAC;AAED;8CAC8C;AAC9C,MAAM,UAAU,YAAY,CAAC,EAAU;IACrC,MAAM,KAAK,GAAG,gBAAgB,CAAC,EAAE,CAAC,CAAA;IAClC,OAAO,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAA;AAC9C,CAAC;AAED;4EAC4E;AAC5E,MAAM,UAAU,qBAAqB,CAAC,EAAU;IAC9C,MAAM,KAAK,GAAG,gBAAgB,CAAC,EAAE,CAAC,CAAA;IAClC,OAAO,KAAK;QACV,CAAC,CAAC,QAAQ,KAAK,CAAC,EAAE,IAAI,KAAK,CAAC,EAAE,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;QAC1E,CAAC,CAAC,SAAS,CAAA;AACf,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,CAAU;IAC7C,OAAO,CAAC,EAAE,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;AACpC,CAAC"}
1
+ {"version":3,"file":"dbIds.js","sourceRoot":"","sources":["../src/dbIds.ts"],"names":[],"mappings":"AAOA,MAAM,cAAc,GAAqD;IACvE,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,cAAc,EAAE;IACpE,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,oBAAoB,EAAE;IAC1E,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,iBAAiB,EAAE;IACvE,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE;IAC9D,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,cAAc,EAAE;IAC/D,4EAA4E;IAC5E,2EAA2E;IAC3E,qEAAqE;IACrE,4EAA4E;IAC5E,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,gBAAgB,EAAE;IACnE,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE;IACnD,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE;IACpD,uEAAuE;IACvE,2EAA2E;IAC3E,+CAA+C;IAC/C,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,WAAW,EAAE;CAC/D,CAAA;AAED,MAAM,UAAU,gBAAgB,CAAC,EAAU;IACzC,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;AACrD,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,sBAAsB,CAAC,EAAU;IAC/C,OAAO,gBAAgB,CAAC,EAAE,CAAC,KAAK,SAAS,CAAA;AAC3C,CAAC;AAED;8CAC8C;AAC9C,MAAM,UAAU,YAAY,CAAC,EAAU;IACrC,MAAM,KAAK,GAAG,gBAAgB,CAAC,EAAE,CAAC,CAAA;IAClC,OAAO,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAA;AAC9C,CAAC;AAED;4EAC4E;AAC5E,MAAM,UAAU,qBAAqB,CAAC,EAAU;IAC9C,MAAM,KAAK,GAAG,gBAAgB,CAAC,EAAE,CAAC,CAAA;IAClC,OAAO,KAAK;QACV,CAAC,CAAC,QAAQ,KAAK,CAAC,EAAE,IAAI,KAAK,CAAC,EAAE,KAAK,MAAM,IAAI,KAAK,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;QACrG,CAAC,CAAC,SAAS,CAAA;AACf,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,CAAU;IAC7C,OAAO,CAAC,EAAE,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;AACpC,CAAC"}
package/esm/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export * from './types.ts';
2
2
  export * from './mappings.ts';
3
3
  export * from './pairwiseAlignment.ts';
4
4
  export * from './alignmentQuality.ts';
5
+ export * from './sharedStretches.ts';
5
6
  export * from './coordinates.ts';
6
7
  export * from './invertMap.ts';
7
8
  export * from './stripStopCodon.ts';
package/esm/index.js CHANGED
@@ -3,6 +3,7 @@ export * from "./types.js";
3
3
  export * from "./mappings.js";
4
4
  export * from "./pairwiseAlignment.js";
5
5
  export * from "./alignmentQuality.js";
6
+ export * from "./sharedStretches.js";
6
7
  // Coordinates
7
8
  export * from "./coordinates.js";
8
9
  export * from "./invertMap.js";
package/esm/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY;AACZ,cAAc,YAAY,CAAA;AAC1B,cAAc,eAAe,CAAA;AAC7B,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AAErC,cAAc;AACd,cAAc,kBAAkB,CAAA;AAChC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,qBAAqB,CAAA;AAEnC,eAAe;AACf,cAAc,yBAAyB,CAAA;AACvC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,kCAAkC,CAAA;AAChD,cAAc,qBAAqB,CAAA;AAEnC,QAAQ;AACR,cAAc,wBAAwB,CAAA;AACtC,cAAc,qBAAqB,CAAA;AAEnC,oBAAoB;AACpB,cAAc,sBAAsB,CAAA;AACpC,cAAc,yBAAyB,CAAA;AACvC,cAAc,yBAAyB,CAAA;AACvC,cAAc,uBAAuB,CAAA;AACrC,cAAc,oBAAoB,CAAA;AAClC,cAAc,YAAY,CAAA;AAE1B,mBAAmB;AACnB,cAAc,oBAAoB,CAAA;AAClC,cAAc,sBAAsB,CAAA;AACpC,cAAc,oBAAoB,CAAA;AAClC,cAAc,iBAAiB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY;AACZ,cAAc,YAAY,CAAA;AAC1B,cAAc,eAAe,CAAA;AAC7B,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,sBAAsB,CAAA;AAEpC,cAAc;AACd,cAAc,kBAAkB,CAAA;AAChC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,qBAAqB,CAAA;AAEnC,eAAe;AACf,cAAc,yBAAyB,CAAA;AACvC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,kCAAkC,CAAA;AAChD,cAAc,qBAAqB,CAAA;AAEnC,QAAQ;AACR,cAAc,wBAAwB,CAAA;AACtC,cAAc,qBAAqB,CAAA;AAEnC,oBAAoB;AACpB,cAAc,sBAAsB,CAAA;AACpC,cAAc,yBAAyB,CAAA;AACvC,cAAc,yBAAyB,CAAA;AACvC,cAAc,uBAAuB,CAAA;AACrC,cAAc,oBAAoB,CAAA;AAClC,cAAc,YAAY,CAAA;AAE1B,mBAAmB;AACnB,cAAc,oBAAoB,CAAA;AAClC,cAAc,sBAAsB,CAAA;AACpC,cAAc,oBAAoB,CAAA;AAClC,cAAc,iBAAiB,CAAA"}
@@ -0,0 +1,17 @@
1
+ import type { PairwiseAlignment } from './mappings.ts';
2
+ /**
3
+ * Each residue of row `a` that row `b` shares, as 0-based index in `a` to
4
+ * 0-based index in `b`. A lone substitution between two kept stretches carries
5
+ * too: it is one codon two databases read differently, as MUC1's repeats are.
6
+ */
7
+ export declare function sharedResidueMap(a: string, b: string): Map<number, number>;
8
+ /** Each residue of isoform `from` that isoform `to` shares, through a global
9
+ * alignment of the two. */
10
+ export declare function sharedIsoformResidues(from: string, to: string): Map<number, number>;
11
+ /**
12
+ * The alignment of a transcript to another isoform of its protein, with every
13
+ * residue outside a shared stretch unmapped. For two isoforms, not for a
14
+ * structure: a mismatch against a structure's chain is usually a point
15
+ * mutation in the construct, at the right place in the fold.
16
+ */
17
+ export declare function keepSharedStretches(pa: PairwiseAlignment): PairwiseAlignment;
@@ -0,0 +1,94 @@
1
+ // Which residues two isoforms of one protein share. An alignment column pairs
2
+ // two residues whether or not one codon encodes both: a mutually exclusive exon
3
+ // sits opposite its partner (PKM's exons 9 and 10, FGFR2's IIIb and IIIc), and
4
+ // its residues align, mismatches and chance identities included. A residue
5
+ // carries across only inside a stretch the two spell letter for letter: a long
6
+ // one, or a short one bounded on both sides by a gap or a sequence end, the
7
+ // shape a short shared exon takes (VEGFA's six-residue exon 8a).
8
+ //
9
+ // Measured 2026-09-25 against codon identity on the genome, over every isoform
10
+ // of 13 genes (TP53, PKM, CDKN2A, FGFR2, TPM1, BRAF, EGFR, SCN8A, MAPT, BIN1,
11
+ // VEGFA, TPM3, CD44; 89,927 truly shared residues), on global alignments: 335
12
+ // placed wrongly and 28 missed, against 1,885 and 28 for every identical
13
+ // residue and 328 and 64 for long stretches alone. The misses are single
14
+ // residues at exon junctions, where the gap fits either side.
15
+ import { structureAlignedSeq, transcriptAlignedSeq, unmapStructurePositions, } from "./mappings.js";
16
+ import { needlemanWunsch } from "./pairwiseAlignment.js";
17
+ const LONG_STRETCH = 10;
18
+ const SHORT_EXON = 3;
19
+ /**
20
+ * Each residue of row `a` that row `b` shares, as 0-based index in `a` to
21
+ * 0-based index in `b`. A lone substitution between two kept stretches carries
22
+ * too: it is one codon two databases read differently, as MUC1's repeats are.
23
+ */
24
+ export function sharedResidueMap(a, b) {
25
+ const cols = [];
26
+ for (let c = 0, x = 0, y = 0; c < a.length; c++) {
27
+ const inA = a[c] !== '-';
28
+ const inB = b[c] !== '-';
29
+ cols.push({
30
+ x,
31
+ y,
32
+ kind: !inA || !inB
33
+ ? 'gap'
34
+ : a[c].toUpperCase() === b[c].toUpperCase()
35
+ ? 'same'
36
+ : 'mismatch',
37
+ });
38
+ if (inA) {
39
+ x++;
40
+ }
41
+ if (inB) {
42
+ y++;
43
+ }
44
+ }
45
+ const bounded = (c) => cols[c]?.kind !== 'mismatch';
46
+ const kept = cols.map(() => false);
47
+ for (let start = 0; start < cols.length;) {
48
+ let end = start;
49
+ while (cols[end]?.kind === 'same') {
50
+ end++;
51
+ }
52
+ const length = end - start;
53
+ if (length >= LONG_STRETCH ||
54
+ (length >= SHORT_EXON && bounded(start - 1) && bounded(end))) {
55
+ kept.fill(true, start, end);
56
+ }
57
+ start = Math.max(end, start + 1);
58
+ }
59
+ const shared = new Map();
60
+ cols.forEach((col, c) => {
61
+ if (kept[c] || (col.kind === 'mismatch' && kept[c - 1] && kept[c + 1])) {
62
+ shared.set(col.x, col.y);
63
+ }
64
+ });
65
+ return shared;
66
+ }
67
+ /** Each residue of isoform `from` that isoform `to` shares, through a global
68
+ * alignment of the two. */
69
+ export function sharedIsoformResidues(from, to) {
70
+ const { alignedSeq1, alignedSeq2 } = needlemanWunsch(from, to);
71
+ return sharedResidueMap(alignedSeq1, alignedSeq2);
72
+ }
73
+ /**
74
+ * The alignment of a transcript to another isoform of its protein, with every
75
+ * residue outside a shared stretch unmapped. For two isoforms, not for a
76
+ * structure: a mismatch against a structure's chain is usually a point
77
+ * mutation in the construct, at the right place in the fold.
78
+ */
79
+ export function keepSharedStretches(pa) {
80
+ const structure = structureAlignedSeq(pa);
81
+ const transcript = transcriptAlignedSeq(pa);
82
+ const shared = sharedResidueMap(structure, transcript);
83
+ const unshared = new Set();
84
+ for (let i = 0, j = 0; i < structure.length; i++) {
85
+ if (structure[i] !== '-') {
86
+ if (transcript[i] !== '-' && !shared.has(j)) {
87
+ unshared.add(j);
88
+ }
89
+ j++;
90
+ }
91
+ }
92
+ return unmapStructurePositions(pa, unshared);
93
+ }
94
+ //# sourceMappingURL=sharedStretches.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sharedStretches.js","sourceRoot":"","sources":["../src/sharedStretches.ts"],"names":[],"mappings":"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"}
@@ -5,8 +5,11 @@
5
5
  // the entry id from here and ask `fetchUniProtStructureMappings` for its
6
6
  // residue mapping.
7
7
  import { rawfetch } from "./fetchUtils.js";
8
+ // Unfiltered: the `?provider=pdbe` form answered BRAF, HBB and BRCA2 with a 404
9
+ // about one time in three (2026-10-09), and the parser keeps PDBe's entries
10
+ // anyway.
8
11
  export function beaconsSummaryUrl(uniprotId) {
9
- return `https://www.ebi.ac.uk/pdbe/pdbe-kb/3dbeacons/api/uniprot/summary/${encodeURIComponent(uniprotId)}.json?provider=pdbe`;
12
+ return `https://www.ebi.ac.uk/pdbe/pdbe-kb/3dbeacons/api/uniprot/summary/${encodeURIComponent(uniprotId)}.json`;
10
13
  }
11
14
  function isRecord(value) {
12
15
  return typeof value === 'object' && value !== null && !Array.isArray(value);
@@ -65,7 +68,15 @@ export function parseExperimentalStructures(json) {
65
68
  /** Best-effort: an unreachable API reads as "no entries", which costs a
66
69
  * structure suggestion and nothing else. */
67
70
  export async function fetchExperimentalStructures(uniprotId, opts) {
68
- const res = await rawfetch(beaconsSummaryUrl(uniprotId), opts).catch(() => undefined);
69
- return res?.ok ? parseExperimentalStructures(await res.json()) : [];
71
+ for (let attempt = 0; attempt < 2; attempt++) {
72
+ const res = await rawfetch(beaconsSummaryUrl(uniprotId), opts).catch(() => undefined);
73
+ if (res?.ok) {
74
+ return parseExperimentalStructures(await res.json());
75
+ }
76
+ if (res?.status === 404 || opts?.signal?.aborted) {
77
+ return [];
78
+ }
79
+ }
80
+ return [];
70
81
  }
71
82
  //# sourceMappingURL=structureSources.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"structureSources.js","sourceRoot":"","sources":["../src/structureSources.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,0EAA0E;AAC1E,yEAAyE;AACzE,8EAA8E;AAC9E,yEAAyE;AACzE,mBAAmB;AAEnB,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAgB1C,MAAM,UAAU,iBAAiB,CAAC,SAAiB;IACjD,OAAO,oEAAoE,kBAAkB,CAAC,SAAS,CAAC,qBAAqB,CAAA;AAC/H,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;AAC7E,CAAC;AAED,SAAS,YAAY,CAAC,KAAc;IAClC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAA;AAChF,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,2BAA2B,CACzC,IAAa;IAEb,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAA;IAC/D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,OAAO,EAAE,CAAA;IACX,CAAC;IACD,OAAO,UAAU;SACd,OAAO,CAAC,KAAK,CAAC,EAAE;QACf,MAAM,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAA;QACrD,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;YACjB,OAAO,EAAE,CAAA;QACX,CAAC;QACD,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,aAAa,CAAC,CAAA;QAC3C,MAAM,GAAG,GAAG,YAAY,CAAC,CAAC,CAAC,WAAW,CAAC,CAAA;QACvC,MAAM,QAAQ,GAAG,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAA;QACzC,OAAO,OAAO,CAAC,CAAC,gBAAgB,KAAK,QAAQ;YAC3C,CAAC,CAAC,QAAQ,KAAK,MAAM;YACrB,CAAC,CAAC,cAAc,KAAK,2BAA2B;YAChD,KAAK,KAAK,SAAS;YACnB,GAAG,KAAK,SAAS;YACjB,QAAQ,KAAK,SAAS;YACtB,CAAC,CAAC;gBACE;oBACE,KAAK,EAAE,CAAC,CAAC,gBAAgB,CAAC,WAAW,EAAE;oBACvC,MAAM,EACJ,OAAO,CAAC,CAAC,mBAAmB,KAAK,QAAQ;wBACvC,CAAC,CAAC,CAAC,CAAC,mBAAmB;wBACvB,CAAC,CAAC,cAAc;oBACpB,UAAU,EAAE,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC;oBACtC,KAAK;oBACL,GAAG;oBACH,QAAQ;iBACT;aACF;YACH,CAAC,CAAC,EAAE,CAAA;IACR,CAAC,CAAC;SACD,IAAI,CACH,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ;QACvB,CAAC,CAAC,CAAC,UAAU,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,IAAI,QAAQ,CAAC,CAC1D,CAAA;AACL,CAAC;AAED;4CAC4C;AAC5C,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,SAAiB,EACjB,IAAmB;IAEnB,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,iBAAiB,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,CAClE,GAAG,EAAE,CAAC,SAAS,CAChB,CAAA;IACD,OAAO,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,2BAA2B,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;AACrE,CAAC"}
1
+ {"version":3,"file":"structureSources.js","sourceRoot":"","sources":["../src/structureSources.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "p2s_mapper",
3
3
  "description": "Map a transcript's translation onto a protein structure: alignment, coordinates, chain choice, SIFTS, and the AlphaFold and PDBe lookups that find the structure",
4
- "version": "1.2.2",
4
+ "version": "1.4.0",
5
5
  "packageManager": "pnpm@11.15.1",
6
6
  "repository": {
7
7
  "type": "git",
@@ -6,15 +6,21 @@ import { stripStopCodon } from './stripStopCodon.ts'
6
6
  export interface AlphaFoldModel {
7
7
  /** UniProt accession, with an isoform suffix on an isoform model */
8
8
  accession: string
9
+ /** AlphaFold DB's id for the model, e.g. AF-P04637-F1 */
10
+ entity?: string
9
11
  url: string
10
12
  confidenceUrl?: string
13
+ /** mean per-residue confidence (pLDDT), 0-100 */
14
+ meanPlddt?: number
11
15
  sequence: string
12
16
  }
13
17
 
14
18
  interface PredictionEntry {
15
19
  uniprotAccession?: unknown
20
+ modelEntityId?: unknown
16
21
  cifUrl?: unknown
17
22
  plddtDocUrl?: unknown
23
+ globalMetricValue?: unknown
18
24
  sequence?: unknown
19
25
  }
20
26
 
@@ -31,9 +37,15 @@ export function parseAlphaFoldModels(json: unknown): AlphaFoldModel[] {
31
37
  ? [
32
38
  {
33
39
  accession: e.uniprotAccession,
40
+ entity:
41
+ typeof e.modelEntityId === 'string' ? e.modelEntityId : undefined,
34
42
  url: e.cifUrl,
35
43
  confidenceUrl:
36
44
  typeof e.plddtDocUrl === 'string' ? e.plddtDocUrl : undefined,
45
+ meanPlddt:
46
+ typeof e.globalMetricValue === 'number'
47
+ ? e.globalMetricValue
48
+ : undefined,
37
49
  sequence: e.sequence,
38
50
  },
39
51
  ]
package/src/dbIds.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  // keyword, the regex (Ensembl patterns cover human ENS, mouse ENSMUS, zebrafish
4
4
  // ENSDAR, etc.), and a human-readable label. Recognition, label rendering, and
5
5
  // xref-query building all derive from this list, so a new ID type is one entry.
6
- type DbType = 'ensembl' | 'refseq' | 'ccds' | 'hgnc'
6
+ type DbType = 'ensembl' | 'refseq' | 'ccds' | 'hgnc' | 'geneid'
7
7
 
8
8
  const DB_ID_PATTERNS: { db: DbType; pattern: RegExp; label: string }[] = [
9
9
  { db: 'ensembl', pattern: /^ENS[A-Z]*G\d+/i, label: 'Ensembl gene' },
@@ -18,6 +18,10 @@ const DB_ID_PATTERNS: { db: DbType; pattern: RegExp; label: string }[] = [
18
18
  { db: 'refseq', pattern: /^[NXYA]P_\d+/i, label: 'RefSeq protein' },
19
19
  { db: 'ccds', pattern: /^CCDS\d+/i, label: 'CCDS' },
20
20
  { db: 'hgnc', pattern: /^HGNC:\d+/i, label: 'HGNC' },
21
+ // NCBI's GFFs carry `Dbxref=GeneID:7157`, and UniProt keeps the GeneID
22
+ // cross-reference for every organism NCBI annotates, where a symbol search
23
+ // needs a taxon and misses a TrEMBL-only gene.
24
+ { db: 'geneid', pattern: /^GeneID:\d+$/i, label: 'NCBI Gene' },
21
25
  ]
22
26
 
23
27
  export function matchDbIdPattern(id: string) {
@@ -41,7 +45,7 @@ export function getDbIdLabel(id: string) {
41
45
  export function buildUniProtXrefQuery(id: string) {
42
46
  const match = matchDbIdPattern(id)
43
47
  return match
44
- ? `xref:${match.db}-${match.db === 'hgnc' ? id.replace('HGNC:', '') : id}`
48
+ ? `xref:${match.db}-${match.db === 'hgnc' || match.db === 'geneid' ? id.replace(/^[^:]+:/, '') : id}`
45
49
  : undefined
46
50
  }
47
51
 
package/src/index.ts CHANGED
@@ -3,6 +3,7 @@ export * from './types.ts'
3
3
  export * from './mappings.ts'
4
4
  export * from './pairwiseAlignment.ts'
5
5
  export * from './alignmentQuality.ts'
6
+ export * from './sharedStretches.ts'
6
7
 
7
8
  // Coordinates
8
9
  export * from './coordinates.ts'
@@ -0,0 +1,109 @@
1
+ // Which residues two isoforms of one protein share. An alignment column pairs
2
+ // two residues whether or not one codon encodes both: a mutually exclusive exon
3
+ // sits opposite its partner (PKM's exons 9 and 10, FGFR2's IIIb and IIIc), and
4
+ // its residues align, mismatches and chance identities included. A residue
5
+ // carries across only inside a stretch the two spell letter for letter: a long
6
+ // one, or a short one bounded on both sides by a gap or a sequence end, the
7
+ // shape a short shared exon takes (VEGFA's six-residue exon 8a).
8
+ //
9
+ // Measured 2026-09-25 against codon identity on the genome, over every isoform
10
+ // of 13 genes (TP53, PKM, CDKN2A, FGFR2, TPM1, BRAF, EGFR, SCN8A, MAPT, BIN1,
11
+ // VEGFA, TPM3, CD44; 89,927 truly shared residues), on global alignments: 335
12
+ // placed wrongly and 28 missed, against 1,885 and 28 for every identical
13
+ // residue and 328 and 64 for long stretches alone. The misses are single
14
+ // residues at exon junctions, where the gap fits either side.
15
+
16
+ import {
17
+ structureAlignedSeq,
18
+ transcriptAlignedSeq,
19
+ unmapStructurePositions,
20
+ } from './mappings.ts'
21
+ import { needlemanWunsch } from './pairwiseAlignment.ts'
22
+
23
+ import type { PairwiseAlignment } from './mappings.ts'
24
+
25
+ const LONG_STRETCH = 10
26
+ const SHORT_EXON = 3
27
+
28
+ type ColumnKind = 'same' | 'mismatch' | 'gap'
29
+
30
+ /**
31
+ * Each residue of row `a` that row `b` shares, as 0-based index in `a` to
32
+ * 0-based index in `b`. A lone substitution between two kept stretches carries
33
+ * too: it is one codon two databases read differently, as MUC1's repeats are.
34
+ */
35
+ export function sharedResidueMap(a: string, b: string) {
36
+ const cols: { x: number; y: number; kind: ColumnKind }[] = []
37
+ for (let c = 0, x = 0, y = 0; c < a.length; c++) {
38
+ const inA = a[c] !== '-'
39
+ const inB = b[c] !== '-'
40
+ cols.push({
41
+ x,
42
+ y,
43
+ kind:
44
+ !inA || !inB
45
+ ? 'gap'
46
+ : a[c]!.toUpperCase() === b[c]!.toUpperCase()
47
+ ? 'same'
48
+ : 'mismatch',
49
+ })
50
+ if (inA) {
51
+ x++
52
+ }
53
+ if (inB) {
54
+ y++
55
+ }
56
+ }
57
+ const bounded = (c: number) => cols[c]?.kind !== 'mismatch'
58
+ const kept = cols.map(() => false)
59
+ for (let start = 0; start < cols.length;) {
60
+ let end = start
61
+ while (cols[end]?.kind === 'same') {
62
+ end++
63
+ }
64
+ const length = end - start
65
+ if (
66
+ length >= LONG_STRETCH ||
67
+ (length >= SHORT_EXON && bounded(start - 1) && bounded(end))
68
+ ) {
69
+ kept.fill(true, start, end)
70
+ }
71
+ start = Math.max(end, start + 1)
72
+ }
73
+ const shared = new Map<number, number>()
74
+ cols.forEach((col, c) => {
75
+ if (kept[c] || (col.kind === 'mismatch' && kept[c - 1] && kept[c + 1])) {
76
+ shared.set(col.x, col.y)
77
+ }
78
+ })
79
+ return shared
80
+ }
81
+
82
+ /** Each residue of isoform `from` that isoform `to` shares, through a global
83
+ * alignment of the two. */
84
+ export function sharedIsoformResidues(from: string, to: string) {
85
+ const { alignedSeq1, alignedSeq2 } = needlemanWunsch(from, to)
86
+ return sharedResidueMap(alignedSeq1, alignedSeq2)
87
+ }
88
+
89
+ /**
90
+ * The alignment of a transcript to another isoform of its protein, with every
91
+ * residue outside a shared stretch unmapped. For two isoforms, not for a
92
+ * structure: a mismatch against a structure's chain is usually a point
93
+ * mutation in the construct, at the right place in the fold.
94
+ */
95
+ export function keepSharedStretches(pa: PairwiseAlignment) {
96
+ const structure = structureAlignedSeq(pa)
97
+ const transcript = transcriptAlignedSeq(pa)
98
+ const shared = sharedResidueMap(structure, transcript)
99
+ const unshared = new Set<number>()
100
+ for (let i = 0, j = 0; i < structure.length; i++) {
101
+ if (structure[i] !== '-') {
102
+ if (transcript[i] !== '-' && !shared.has(j)) {
103
+ unshared.add(j)
104
+ }
105
+ j++
106
+ }
107
+ }
108
+ return unmapStructurePositions(pa, unshared)
109
+ }
@@ -21,8 +21,11 @@ export interface ExperimentalStructure {
21
21
  coverage: number
22
22
  }
23
23
 
24
+ // Unfiltered: the `?provider=pdbe` form answered BRAF, HBB and BRCA2 with a 404
25
+ // about one time in three (2026-10-09), and the parser keeps PDBe's entries
26
+ // anyway.
24
27
  export function beaconsSummaryUrl(uniprotId: string) {
25
- return `https://www.ebi.ac.uk/pdbe/pdbe-kb/3dbeacons/api/uniprot/summary/${encodeURIComponent(uniprotId)}.json?provider=pdbe`
28
+ return `https://www.ebi.ac.uk/pdbe/pdbe-kb/3dbeacons/api/uniprot/summary/${encodeURIComponent(uniprotId)}.json`
26
29
  }
27
30
 
28
31
  function isRecord(value: unknown): value is Record<string, unknown> {
@@ -94,8 +97,16 @@ export async function fetchExperimentalStructures(
94
97
  uniprotId: string,
95
98
  opts?: FetchOptions,
96
99
  ): Promise<ExperimentalStructure[]> {
97
- const res = await rawfetch(beaconsSummaryUrl(uniprotId), opts).catch(
98
- () => undefined,
99
- )
100
- return res?.ok ? parseExperimentalStructures(await res.json()) : []
100
+ for (let attempt = 0; attempt < 2; attempt++) {
101
+ const res = await rawfetch(beaconsSummaryUrl(uniprotId), opts).catch(
102
+ () => undefined,
103
+ )
104
+ if (res?.ok) {
105
+ return parseExperimentalStructures(await res.json())
106
+ }
107
+ if (res?.status === 404 || opts?.signal?.aborted) {
108
+ return []
109
+ }
110
+ }
111
+ return []
101
112
  }