p2s_mapper 1.3.0 → 2.0.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.
Files changed (94) hide show
  1. package/README.md +214 -32
  2. package/dist/alphaFoldModels.d.ts +4 -0
  3. package/dist/alphaFoldModels.js +4 -0
  4. package/dist/alphaFoldModels.js.map +1 -1
  5. package/dist/coordinates.d.ts +8 -6
  6. package/dist/coordinates.js.map +1 -1
  7. package/dist/dbIds.d.ts +1 -2
  8. package/dist/dbIds.js +5 -1
  9. package/dist/dbIds.js.map +1 -1
  10. package/dist/extractPerResidueConfidence.d.ts +1 -2
  11. package/dist/extractStructureSequences.d.ts +14 -15
  12. package/dist/fetchUtils.js +19 -1
  13. package/dist/fetchUtils.js.map +1 -1
  14. package/dist/index.d.ts +1 -3
  15. package/dist/index.js +2 -4
  16. package/dist/index.js.map +1 -1
  17. package/dist/isoformRanking.d.ts +3 -0
  18. package/dist/pairwiseAlignment.d.ts +1 -2
  19. package/dist/pdbEntry.d.ts +32 -0
  20. package/dist/pdbEntry.js +182 -0
  21. package/dist/pdbEntry.js.map +1 -0
  22. package/dist/pdbUniProtMapping.d.ts +9 -33
  23. package/dist/pdbUniProtMapping.js +17 -134
  24. package/dist/pdbUniProtMapping.js.map +1 -1
  25. package/dist/structureSources.d.ts +37 -13
  26. package/dist/structureSources.js +144 -57
  27. package/dist/structureSources.js.map +1 -1
  28. package/dist/structureUrls.d.ts +2 -0
  29. package/dist/structureUrls.js +11 -0
  30. package/dist/structureUrls.js.map +1 -1
  31. package/esm/alphaFoldModels.d.ts +4 -0
  32. package/esm/alphaFoldModels.js +4 -0
  33. package/esm/alphaFoldModels.js.map +1 -1
  34. package/esm/coordinates.d.ts +8 -6
  35. package/esm/coordinates.js.map +1 -1
  36. package/esm/dbIds.d.ts +1 -2
  37. package/esm/dbIds.js +5 -1
  38. package/esm/dbIds.js.map +1 -1
  39. package/esm/extractPerResidueConfidence.d.ts +1 -2
  40. package/esm/extractStructureSequences.d.ts +14 -15
  41. package/esm/fetchUtils.js +19 -1
  42. package/esm/fetchUtils.js.map +1 -1
  43. package/esm/index.d.ts +1 -3
  44. package/esm/index.js +2 -4
  45. package/esm/index.js.map +1 -1
  46. package/esm/isoformRanking.d.ts +3 -0
  47. package/esm/pairwiseAlignment.d.ts +1 -2
  48. package/esm/pdbEntry.d.ts +32 -0
  49. package/esm/pdbEntry.js +174 -0
  50. package/esm/pdbEntry.js.map +1 -0
  51. package/esm/pdbUniProtMapping.d.ts +9 -33
  52. package/esm/pdbUniProtMapping.js +17 -131
  53. package/esm/pdbUniProtMapping.js.map +1 -1
  54. package/esm/structureSources.d.ts +37 -13
  55. package/esm/structureSources.js +139 -55
  56. package/esm/structureSources.js.map +1 -1
  57. package/esm/structureUrls.d.ts +2 -0
  58. package/esm/structureUrls.js +9 -0
  59. package/esm/structureUrls.js.map +1 -1
  60. package/package.json +3 -2
  61. package/src/alphaFoldModels.ts +12 -0
  62. package/src/coordinates.ts +3 -4
  63. package/src/dbIds.ts +6 -2
  64. package/src/extractPerResidueConfidence.ts +1 -1
  65. package/src/extractStructureSequences.ts +14 -14
  66. package/src/fetchUtils.ts +23 -1
  67. package/src/index.ts +2 -4
  68. package/src/isoformRanking.ts +3 -3
  69. package/src/pairwiseAlignment.ts +1 -1
  70. package/src/pdbEntry.ts +240 -0
  71. package/src/pdbUniProtMapping.ts +20 -158
  72. package/src/structureSources.ts +194 -70
  73. package/src/structureUrls.ts +11 -0
  74. package/dist/pdbeBestStructures.d.ts +0 -23
  75. package/dist/pdbeBestStructures.js +0 -79
  76. package/dist/pdbeBestStructures.js.map +0 -1
  77. package/dist/pdbeEntryMolecules.d.ts +0 -7
  78. package/dist/pdbeEntryMolecules.js +0 -39
  79. package/dist/pdbeEntryMolecules.js.map +0 -1
  80. package/dist/siftsNumbering.d.ts +0 -23
  81. package/dist/siftsNumbering.js +0 -44
  82. package/dist/siftsNumbering.js.map +0 -1
  83. package/esm/pdbeBestStructures.d.ts +0 -23
  84. package/esm/pdbeBestStructures.js +0 -73
  85. package/esm/pdbeBestStructures.js.map +0 -1
  86. package/esm/pdbeEntryMolecules.d.ts +0 -7
  87. package/esm/pdbeEntryMolecules.js +0 -35
  88. package/esm/pdbeEntryMolecules.js.map +0 -1
  89. package/esm/siftsNumbering.d.ts +0 -23
  90. package/esm/siftsNumbering.js +0 -40
  91. package/esm/siftsNumbering.js.map +0 -1
  92. package/src/pdbeBestStructures.ts +0 -94
  93. package/src/pdbeEntryMolecules.ts +0 -37
  94. package/src/siftsNumbering.ts +0 -61
@@ -1 +0,0 @@
1
- {"version":3,"file":"pdbeBestStructures.js","sourceRoot":"","sources":["../src/pdbeBestStructures.ts"],"names":[],"mappings":"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"}
@@ -1,7 +0,0 @@
1
- export declare function pdbeEntryMoleculesUrl(pdbId: string): string;
2
- /**
3
- * One sequence per protein entity, in entity order. Nucleic-acid entities are
4
- * left out: A, C, G, T and U are amino-acid letters too, so a DNA chain scores
5
- * as a candidate rather than losing honestly.
6
- */
7
- export declare function parseEntryMolecules(json: unknown): string[];
@@ -1,35 +0,0 @@
1
- // The polymer entities of a PDB entry, as PDBe already knows them. The dialog
2
- // wants the entry's residues only to annotate the isoform list, and reading
3
- // them out of the structure file meant downloading and parsing the whole
4
- // mmCIF — minutes for a ribosome, for a label. This is a few kB of JSON, and
5
- // the view downloads the file itself when the user actually launches.
6
- export function pdbeEntryMoleculesUrl(pdbId) {
7
- return `https://www.ebi.ac.uk/pdbe/api/pdb/entry/molecules/${pdbId.toLowerCase()}`;
8
- }
9
- function isRecord(value) {
10
- return typeof value === 'object' && value !== null && !Array.isArray(value);
11
- }
12
- /**
13
- * One sequence per protein entity, in entity order. Nucleic-acid entities are
14
- * left out: A, C, G, T and U are amino-acid letters too, so a DNA chain scores
15
- * as a candidate rather than losing honestly.
16
- */
17
- export function parseEntryMolecules(json) {
18
- const entities = isRecord(json) ? Object.values(json)[0] : undefined;
19
- if (!Array.isArray(entities)) {
20
- return [];
21
- }
22
- return entities.flatMap(entity => {
23
- if (!isRecord(entity)) {
24
- return [];
25
- }
26
- const { molecule_type: type, sequence } = entity;
27
- return typeof type === 'string' &&
28
- type.startsWith('polypeptide') &&
29
- typeof sequence === 'string' &&
30
- sequence.length > 0
31
- ? [sequence]
32
- : [];
33
- });
34
- }
35
- //# sourceMappingURL=pdbeEntryMolecules.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pdbeEntryMolecules.js","sourceRoot":"","sources":["../src/pdbeEntryMolecules.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,4EAA4E;AAC5E,yEAAyE;AACzE,6EAA6E;AAC7E,sEAAsE;AAEtE,MAAM,UAAU,qBAAqB,CAAC,KAAa;IACjD,OAAO,sDAAsD,KAAK,CAAC,WAAW,EAAE,EAAE,CAAA;AACpF,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;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAa;IAC/C,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IACpE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,CAAA;IACX,CAAC;IACD,OAAO,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;QAC/B,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YACtB,OAAO,EAAE,CAAA;QACX,CAAC;QACD,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAA;QAChD,OAAO,OAAO,IAAI,KAAK,QAAQ;YAC7B,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC;YAC9B,OAAO,QAAQ,KAAK,QAAQ;YAC5B,QAAQ,CAAC,MAAM,GAAG,CAAC;YACnB,CAAC,CAAC,CAAC,QAAQ,CAAC;YACZ,CAAC,CAAC,EAAE,CAAA;IACR,CAAC,CAAC,CAAA;AACJ,CAAC"}
@@ -1,23 +0,0 @@
1
- import type { UniProtStructureSegment } from './pdbUniProtMapping.ts';
2
- export interface AuthorRange {
3
- start: number;
4
- end: number;
5
- chain: string;
6
- /** author number minus UniProt number in the chosen segment */
7
- shift: number;
8
- }
9
- /** The segments SIFTS gives one accession, chain ids and author numbers
10
- * included, out of a whole entry's mappings. */
11
- export declare function segmentsForAccession(mappings: readonly {
12
- accession: string;
13
- segments: UniProtStructureSegment[];
14
- }[], accession: string): UniProtStructureSegment[];
15
- /**
16
- * The author-numbered range a UniProt range is cited by in the entry: the
17
- * segment overlapping most of the range decides the shift. Undefined when no
18
- * chain of the entry covers any of it, or when SIFTS named no author numbers.
19
- */
20
- export declare function toAuthorRange(segments: readonly UniProtStructureSegment[], range: {
21
- start: number;
22
- end: number;
23
- }): AuthorRange | undefined;
@@ -1,40 +0,0 @@
1
- // How a PDB entry numbers the residues of a UniProt sequence. Author numbering
2
- // is what a paper cites and what a viewer lights a named residue by, and it is
3
- // not the UniProt numbering for every entry: haemoglobin's chains number from
4
- // the mature protein, so author residue 1 is UniProt residue 2 (2HHB, measured
5
- // 2026-09-12). SIFTS records the correspondence per chain segment, and
6
- // `fetchUniProtStructureMappings` is what asks PDBe for it.
7
- /** The segments SIFTS gives one accession, chain ids and author numbers
8
- * included, out of a whole entry's mappings. */
9
- export function segmentsForAccession(mappings, accession) {
10
- return mappings.find(m => m.accession === accession)?.segments ?? [];
11
- }
12
- /**
13
- * The author-numbered range a UniProt range is cited by in the entry: the
14
- * segment overlapping most of the range decides the shift. Undefined when no
15
- * chain of the entry covers any of it, or when SIFTS named no author numbers.
16
- */
17
- export function toAuthorRange(segments, range) {
18
- const overlap = (s) => Math.min(s.unpEnd, range.end) - Math.max(s.unpStart, range.start) + 1;
19
- const best = segments
20
- .flatMap(s => {
21
- const { chainId, authorStart, unpStart, unpEnd } = s;
22
- return chainId !== undefined &&
23
- authorStart !== undefined &&
24
- overlap(s) > 0
25
- ? [{ chainId, authorStart, unpStart, unpEnd, overlap: overlap(s) }]
26
- : [];
27
- })
28
- .toSorted((a, b) => b.overlap - a.overlap)[0];
29
- if (!best) {
30
- return undefined;
31
- }
32
- const shift = best.authorStart - best.unpStart;
33
- return {
34
- start: Math.max(range.start, best.unpStart) + shift,
35
- end: Math.min(range.end, best.unpEnd) + shift,
36
- chain: best.chainId,
37
- shift,
38
- };
39
- }
40
- //# sourceMappingURL=siftsNumbering.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"siftsNumbering.js","sourceRoot":"","sources":["../src/siftsNumbering.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,+EAA+E;AAC/E,8EAA8E;AAC9E,+EAA+E;AAC/E,uEAAuE;AACvE,4DAA4D;AAY5D;gDACgD;AAChD,MAAM,UAAU,oBAAoB,CAClC,QAGG,EACH,SAAiB;IAEjB,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC,EAAE,QAAQ,IAAI,EAAE,CAAA;AACtE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAC3B,QAA4C,EAC5C,KAAqC;IAErC,MAAM,OAAO,GAAG,CAAC,CAA0B,EAAE,EAAE,CAC7C,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IACvE,MAAM,IAAI,GAAG,QAAQ;SAClB,OAAO,CAAC,CAAC,CAAC,EAAE;QACX,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,CAAA;QACpD,OAAO,OAAO,KAAK,SAAS;YAC1B,WAAW,KAAK,SAAS;YACzB,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;YACd,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;YACnE,CAAC,CAAC,EAAE,CAAA;IACR,CAAC,CAAC;SACD,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;IAC/C,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAA;IAC9C,OAAO;QACL,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,KAAK;QACnD,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,KAAK;QAC7C,KAAK,EAAE,IAAI,CAAC,OAAO;QACnB,KAAK;KACN,CAAA;AACH,CAAC"}
@@ -1,94 +0,0 @@
1
- // PDBe's SIFTS-derived list of the experimental structures covering a UniProt
2
- // entry, one row per chain, ranked by PDBe (coverage, then resolution). The
3
- // dialog shows one row per entry, so the chains of a homomer collapse into it.
4
-
5
- export interface PdbStructureEntry {
6
- pdbId: string
7
- experimentalMethod: string
8
- /** Å; absent for NMR and some EM entries */
9
- resolution?: number
10
- /** 1-based inclusive UniProt positions the entry covers */
11
- unpStart: number
12
- unpEnd: number
13
- /** share of the UniProt sequence the entry covers, 0..1 */
14
- coverage: number
15
- chains: string[]
16
- }
17
-
18
- export function pdbeBestStructuresUrl(uniprotId: string) {
19
- return `https://www.ebi.ac.uk/pdbe/api/mappings/best_structures/${uniprotId}`
20
- }
21
-
22
- // A PDB id is four characters, the first a digit: 1TUP, 6ZIO. Checked before
23
- // a typed one reaches a fetch, so three characters on the way to four are not
24
- // a 404 apiece.
25
- export function isPdbId(value: string) {
26
- return /^[1-9][A-Za-z0-9]{3}$/.test(value)
27
- }
28
-
29
- export function rcsbEntryUrl(pdbId: string) {
30
- return `https://www.rcsb.org/structure/${pdbId.toUpperCase()}`
31
- }
32
-
33
- function isRecord(value: unknown): value is Record<string, unknown> {
34
- return typeof value === 'object' && value !== null && !Array.isArray(value)
35
- }
36
-
37
- function finiteNumber(value: unknown) {
38
- return typeof value === 'number' && Number.isFinite(value) ? value : undefined
39
- }
40
-
41
- /**
42
- * Groups the per-chain rows into one entry per PDB id, keeping PDBe's order.
43
- * An entry whose chains cover different UniProt ranges (a construct
44
- * crystallised beside a different fragment of itself) keeps its first row's
45
- * range, which is the one PDBe ranked it by. The response is keyed by
46
- * accession, so the single entry is taken whatever its key.
47
- */
48
- export function parseBestStructures(json: unknown): PdbStructureEntry[] {
49
- const rows = isRecord(json) ? Object.values(json)[0] : undefined
50
- if (!Array.isArray(rows)) {
51
- return []
52
- }
53
- const byId = new Map<string, PdbStructureEntry>()
54
- for (const row of rows) {
55
- if (!isRecord(row)) {
56
- continue
57
- }
58
- const pdbId = typeof row.pdb_id === 'string' ? row.pdb_id : undefined
59
- const chain = typeof row.chain_id === 'string' ? row.chain_id : undefined
60
- const unpStart = finiteNumber(row.unp_start)
61
- const unpEnd = finiteNumber(row.unp_end)
62
- const coverage = finiteNumber(row.coverage)
63
- if (
64
- pdbId === undefined ||
65
- chain === undefined ||
66
- unpStart === undefined ||
67
- unpEnd === undefined ||
68
- coverage === undefined
69
- ) {
70
- continue
71
- }
72
- const existing = byId.get(pdbId)
73
- if (existing) {
74
- if (!existing.chains.includes(chain)) {
75
- existing.chains.push(chain)
76
- }
77
- continue
78
- }
79
- const resolution = finiteNumber(row.resolution)
80
- byId.set(pdbId, {
81
- pdbId,
82
- experimentalMethod:
83
- typeof row.experimental_method === 'string'
84
- ? row.experimental_method
85
- : 'unknown',
86
- ...(resolution === undefined ? {} : { resolution }),
87
- unpStart,
88
- unpEnd,
89
- coverage,
90
- chains: [chain],
91
- })
92
- }
93
- return [...byId.values()]
94
- }
@@ -1,37 +0,0 @@
1
- // The polymer entities of a PDB entry, as PDBe already knows them. The dialog
2
- // wants the entry's residues only to annotate the isoform list, and reading
3
- // them out of the structure file meant downloading and parsing the whole
4
- // mmCIF — minutes for a ribosome, for a label. This is a few kB of JSON, and
5
- // the view downloads the file itself when the user actually launches.
6
-
7
- export function pdbeEntryMoleculesUrl(pdbId: string) {
8
- return `https://www.ebi.ac.uk/pdbe/api/pdb/entry/molecules/${pdbId.toLowerCase()}`
9
- }
10
-
11
- function isRecord(value: unknown): value is Record<string, unknown> {
12
- return typeof value === 'object' && value !== null && !Array.isArray(value)
13
- }
14
-
15
- /**
16
- * One sequence per protein entity, in entity order. Nucleic-acid entities are
17
- * left out: A, C, G, T and U are amino-acid letters too, so a DNA chain scores
18
- * as a candidate rather than losing honestly.
19
- */
20
- export function parseEntryMolecules(json: unknown): string[] {
21
- const entities = isRecord(json) ? Object.values(json)[0] : undefined
22
- if (!Array.isArray(entities)) {
23
- return []
24
- }
25
- return entities.flatMap(entity => {
26
- if (!isRecord(entity)) {
27
- return []
28
- }
29
- const { molecule_type: type, sequence } = entity
30
- return typeof type === 'string' &&
31
- type.startsWith('polypeptide') &&
32
- typeof sequence === 'string' &&
33
- sequence.length > 0
34
- ? [sequence]
35
- : []
36
- })
37
- }
@@ -1,61 +0,0 @@
1
- // How a PDB entry numbers the residues of a UniProt sequence. Author numbering
2
- // is what a paper cites and what a viewer lights a named residue by, and it is
3
- // not the UniProt numbering for every entry: haemoglobin's chains number from
4
- // the mature protein, so author residue 1 is UniProt residue 2 (2HHB, measured
5
- // 2026-09-12). SIFTS records the correspondence per chain segment, and
6
- // `fetchUniProtStructureMappings` is what asks PDBe for it.
7
-
8
- import type { UniProtStructureSegment } from './pdbUniProtMapping.ts'
9
-
10
- export interface AuthorRange {
11
- start: number
12
- end: number
13
- chain: string
14
- /** author number minus UniProt number in the chosen segment */
15
- shift: number
16
- }
17
-
18
- /** The segments SIFTS gives one accession, chain ids and author numbers
19
- * included, out of a whole entry's mappings. */
20
- export function segmentsForAccession(
21
- mappings: readonly {
22
- accession: string
23
- segments: UniProtStructureSegment[]
24
- }[],
25
- accession: string,
26
- ) {
27
- return mappings.find(m => m.accession === accession)?.segments ?? []
28
- }
29
-
30
- /**
31
- * The author-numbered range a UniProt range is cited by in the entry: the
32
- * segment overlapping most of the range decides the shift. Undefined when no
33
- * chain of the entry covers any of it, or when SIFTS named no author numbers.
34
- */
35
- export function toAuthorRange(
36
- segments: readonly UniProtStructureSegment[],
37
- range: { start: number; end: number },
38
- ): AuthorRange | undefined {
39
- const overlap = (s: UniProtStructureSegment) =>
40
- Math.min(s.unpEnd, range.end) - Math.max(s.unpStart, range.start) + 1
41
- const best = segments
42
- .flatMap(s => {
43
- const { chainId, authorStart, unpStart, unpEnd } = s
44
- return chainId !== undefined &&
45
- authorStart !== undefined &&
46
- overlap(s) > 0
47
- ? [{ chainId, authorStart, unpStart, unpEnd, overlap: overlap(s) }]
48
- : []
49
- })
50
- .toSorted((a, b) => b.overlap - a.overlap)[0]
51
- if (!best) {
52
- return undefined
53
- }
54
- const shift = best.authorStart - best.unpStart
55
- return {
56
- start: Math.max(range.start, best.unpStart) + shift,
57
- end: Math.min(range.end, best.unpEnd) + shift,
58
- chain: best.chainId,
59
- shift,
60
- }
61
- }