diff --git a/eslint.config.mjs b/eslint.config.mjs index fd7789c..0bf5335 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -11,36 +11,79 @@ export default tsEslint.config( plugins: { '@stylistic': stylisticEslint, }, - rules:{ - 'prefer-const': 'off', + rules: { + // Relax recommended rules + 'prefer-const': ['error', { + destructuring: 'all', // Allow `let` when at least one destructured element will be changed + }], '@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-inferrable-types': 'off', '@typescript-eslint/consistent-indexed-object-style': 'off', '@typescript-eslint/no-namespace': 'off', '@typescript-eslint/no-unused-vars': 'off', - '@typescript-eslint/consistent-type-definitions': 'off', - '@typescript-eslint/no-unused-expressions': 'off', - '@typescript-eslint/no-empty-object-type': 'off', + // Additional rules - general + 'eqeqeq': 'error', // Forbid using `==`, enforce `===` + 'no-eval': 'error', // Forbid using `eval` + 'no-new-wrappers': 'error', + 'no-restricted-syntax': ['error', { + selector: 'ExportDefaultDeclaration', + message: 'Default exports are not allowed', + }], + 'no-var': 'error', // Forbid using `var` + 'no-throw-literal': 'error', // Forbid throwing anything that's not Error, e.g. `throw 'Blabla'` + '@typescript-eslint/prefer-namespace-keyword': 'error', // Forbid `module` keyword + + // Additional rules - @stylistic '@stylistic/indent': ['error', 4], - '@stylistic/quotes': ['error', 'single', { + '@stylistic/semi': 'error', // Enforce trailing semicolons, including after type definitions + '@stylistic/comma-dangle': ['error', 'always-multiline'], // Enforce comma after last listed item when closing ] or } is on the next line + '@stylistic/quotes': ['error', 'single', { // Enforce single quotes: 'hello' avoidEscape: true, allowTemplateLiterals: true, }], - '@stylistic/semi': 'off', - '@stylistic/type-annotation-spacing': 'error', - '@stylistic/brace-style': ['error', '1tbs', { + '@stylistic/brace-style': ['error', '1tbs', { // Enforce line break after { and before } allowSingleLine: true, }], - '@stylistic/comma-spacing': 'error', - '@stylistic/space-infix-ops': 'error', + '@stylistic/member-delimiter-style': ['error', { // Enforce commas in interfaces and types + multiline: { + delimiter: 'comma', + requireLast: true, + }, + singleline: { + delimiter: 'comma', + requireLast: false, + }, + 'multilineDetection': 'brackets', + }], + + // Additional rules - @stylistic - spacing + '@stylistic/array-bracket-spacing': 'error', // Forbid spaces in array: [_1, 2_] + '@stylistic/arrow-spacing': 'error', // Enforce space in lambda function: x_=>_x**2 + '@stylistic/block-spacing': 'error', // Enforce space in one-line block: () => {_return true;_} + '@stylistic/comma-spacing': 'error', // Enforce space after comma: [1,_2,_3] + '@stylistic/computed-property-spacing': 'error', // Forbid spaces in indexing: a[_0_] + '@stylistic/function-call-spacing': 'error', // Forbid space when calling function: f_(0) + '@stylistic/key-spacing': 'error', // Enforce space after colon in object: { a:_1, b:_2 } + '@stylistic/keyword-spacing': 'error', // Enforce space after `if`, `try`, etc.: if_(true) + '@stylistic/no-multi-spaces': 'error', // Forbid more than one space: x =__5 + '@stylistic/no-trailing-spaces': 'error', // No spaces at the end of line: foo()_ + '@stylistic/object-curly-spacing': ['error', 'always'], // Enforce spaces in object: {_a: 1, b: 2_} + '@stylistic/semi-spacing': 'error', // Enforce space after semicolon: for (let i = 0;_i < n;_i++) + '@stylistic/space-before-blocks': 'error', // Enforce space before block: if (true)_{} '@stylistic/space-before-function-paren': ['error', { - anonymous: 'always', - named: 'never', - asyncArrow: 'always', + anonymous: 'always', // function_() {} + named: 'never', // function foo_() {} + asyncArrow: 'always', // async_() {} + }], + '@stylistic/space-in-parens': 'error', // Forbid spaces in parentheses: (_1, 2_) + '@stylistic/space-infix-ops': 'error', // Enforce space around infix operators: 1_+_2 + '@stylistic/spaced-comment': ['error', 'always', { // Enforce space in comment: /**_Comment_*/ //_comment + block: { + balanced: true, + }, }], - '@stylistic/func-call-spacing': ['error'], - '@stylistic/keyword-spacing': ['error'], + '@stylistic/type-annotation-spacing': 'error', // Enforce space after type annotation colon: let x:_string; }, }, ); diff --git a/src/_spec/_utils.ts b/src/_spec/_utils.ts index 80429c1..067b103 100644 --- a/src/_spec/_utils.ts +++ b/src/_spec/_utils.ts @@ -20,7 +20,7 @@ import { setFSModule } from 'molstar/lib/commonjs/mol-util/data-source'; export const TESTING_PDBS = ['1hda', '1ad5', '176d', 'AF-Q8W3K0-F1-model_v4'] as const; -export type TestingPdb = typeof TESTING_PDBS[number] +export type TestingPdb = typeof TESTING_PDBS[number]; /** Timeout for long-running tests (in ms) */ export const LONG_TEST_TIMEOUT = 600_000; diff --git a/src/_spec/api.spec.ts b/src/_spec/api.spec.ts index f2ff888..dc4c59a 100644 --- a/src/_spec/api.spec.ts +++ b/src/_spec/api.spec.ts @@ -68,7 +68,7 @@ describe('api', () => { it('getModifiedResidue', async () => { expect(await API.getModifiedResidue('1hda')).toEqual([] as PDBeAPIReturn<'getModifiedResidue'>); expect(await API.getModifiedResidue('1gkt')).toEqual([ - { authChainId: 'A', compoundId: 'SUI', compoundName: '(3-AMINO-2,5-DIOXO-1-PYRROLIDINYL)ACETIC ACID', entityId: 1, labelChainId: 'A', residueNumber: 54 } + { authChainId: 'A', compoundId: 'SUI', compoundName: '(3-AMINO-2,5-DIOXO-1-PYRROLIDINYL)ACETIC ACID', entityId: 1, labelChainId: 'A', residueNumber: 54 }, ] as PDBeAPIReturn<'getModifiedResidue'>); expect(await API.getModifiedResidue('1l7c')).toEqual([ { authChainId: 'A', compoundId: 'MSE', compoundName: 'SELENOMETHIONINE', entityId: 1, labelChainId: 'A', residueNumber: 70 }, @@ -166,7 +166,7 @@ describe('api', () => { { chunks: [{ endResidue: 125, startResidue: 1, chainId: 'B', authChainId: 'B', entityId: '2', segment: 1 }], family: 'RF00234', familyName: 'glmS glucosamine-6-phosphate activated ribozyme', id: 'RF00234_1', source: 'Rfam' }, ], }, - SCOP: {} + SCOP: {}, } as PDBeAPIReturn<'getSiftsMappings'>); }); diff --git a/src/_spec/expected-files.spec.ts b/src/_spec/expected-files.spec.ts index 27677cb..5a7f390 100644 --- a/src/_spec/expected-files.spec.ts +++ b/src/_spec/expected-files.spec.ts @@ -9,7 +9,6 @@ import { checkMissingFiles, getExpectedFiles } from '../expected-files'; const API = new PDBeAPI('file://./test_data/api'); -const NO_API = new PDBeAPI('', true); describe('expected-filenames', () => { diff --git a/src/_spec/image-generator.spec.ts b/src/_spec/image-generator.spec.ts index c343ec7..1e9aa4e 100644 --- a/src/_spec/image-generator.spec.ts +++ b/src/_spec/image-generator.spec.ts @@ -14,7 +14,8 @@ import { ImageGenerator } from '../image-generator'; import { TestingPdb, getTestingHeadlessPlugin } from './_utils'; -PluginContext; // ensure PluginContext is imported before ImageGenerator +// Ensure PluginContext is imported before ImageGenerator: +PluginContext; // eslint-disable-line @typescript-eslint/no-unused-expressions const TEST_TIMEOUT = 180_000; // ms diff --git a/src/_spec/save.spec.ts b/src/_spec/save.spec.ts index 3823002..7f5d1d1 100644 --- a/src/_spec/save.spec.ts +++ b/src/_spec/save.spec.ts @@ -8,7 +8,7 @@ import fs from 'fs'; import path from 'path'; import { loadPngToRaw } from '../image/resize'; -import { makeSaveFunction, } from '../save'; +import { makeSaveFunction } from '../save'; import { getTestingHeadlessPlugin, isBorderBlank, isImageBlank } from './_utils'; diff --git a/src/api.ts b/src/api.ts index bf92202..3347ecd 100644 --- a/src/api.ts +++ b/src/api.ts @@ -309,8 +309,8 @@ export class PDBeAPI { } } -export type PDBeAPIMethod = 'pdbeStructureQualityReportPrefix' | 'getEntityNames' | 'getEntityTypes' | 'getAssemblies' | 'getPreferredAssemblyId' | 'getModifiedResidue' | 'getSiftsMappings' | 'getExperimentalMethods' | 'getChainCoverages' | 'getChainCoverageRatios' -export type PDBeAPIReturn = Awaited> +export type PDBeAPIMethod = 'pdbeStructureQualityReportPrefix' | 'getEntityNames' | 'getEntityTypes' | 'getAssemblies' | 'getPreferredAssemblyId' | 'getModifiedResidue' | 'getSiftsMappings' | 'getExperimentalMethods' | 'getChainCoverages' | 'getChainCoverageRatios'; +export type PDBeAPIReturn = Awaited>; /** Represents one instance of a modified residue. */ @@ -346,7 +346,7 @@ export type SiftsSource = typeof SIFTS_SOURCES[number]; /** */ export interface DomainRecord { id: string, - source: string + source: string, family: string, familyName: string, chunks: DomainChunkRecord[], @@ -366,5 +366,5 @@ interface DomainChunkRecord { endResidue: number, /** No idea what this was supposed to mean in the original process (probably segment number * from the API before cutting into smaller segments by removing missing residues) */ - segment: number + segment: number, } diff --git a/src/args.ts b/src/args.ts index 3140985..3877aab 100644 --- a/src/args.ts +++ b/src/args.ts @@ -10,12 +10,12 @@ import { LogLevel } from './helpers/logging'; /** Modes of operation of PDBImages */ export const Modes = ['pdb', 'alphafold'] as const; /** Modes of operation of PDBImages */ -export type Mode = typeof Modes[number] +export type Mode = typeof Modes[number]; /** Types of images that can be generated */ export const ImageTypes = ['entry', 'assembly', 'entity', 'domain', 'ligand', 'modres', 'bfactor', 'validation', 'plddt', 'all'] as const; /** Types of images that can be generated */ -export type ImageType = typeof ImageTypes[number] +export type ImageType = typeof ImageTypes[number]; /** Types of images that can be generated for each mode */ export const ImageTypesForModes = { @@ -72,7 +72,7 @@ export interface Args { log: LogLevel, } -export type OptionalArgs = Omit +export type OptionalArgs = Omit; /** Default values for `Args` */ export const Defaults = { diff --git a/src/captions/_spec/captions.spec.ts b/src/captions/_spec/captions.spec.ts index 6b50d80..9e576fd 100644 --- a/src/captions/_spec/captions.spec.ts +++ b/src/captions/_spec/captions.spec.ts @@ -16,11 +16,11 @@ const COMMON_CONTEXT = { '1': { description: 'HEMOGLOBIN (DEOXY) (ALPHA CHAIN)', type: 'polymer', chains: [0, 1] as any, index: 0 }, '2': { description: 'HEMOGLOBIN (DEOXY) (BETA CHAIN)', type: 'polymer', chains: [2, 3] as any, index: 1 }, '3': { description: 'PROTOPORPHYRIN IX CONTAINING FE', type: 'non-polymer', chains: [4, 5, 6, 7] as any, index: 2 }, - '4': { description: 'water', type: 'water', chains: [8] as any, index: 3 } + '4': { description: 'water', type: 'water', chains: [8] as any, index: 3 }, } as EntityInfo, entityNames: { '1': ['Hemoglobin alpha chain'], '2': ['Hemoglobin beta chain', 'blablabla'], '3': [] }, nModels: 1, - view: undefined + view: undefined, }; @@ -116,7 +116,7 @@ describe('captions', () => { it('domain', () => { expect(Captions.forDomain({ ...COMMON_CONTEXT, entityId: '2', - source: 'CATH', familyId: '1.10.490.10', familyName: 'Globin-like', totalCopies: 2, shownCopies: 1, outOfRangeCopies: 0, chainId: 'B', authChainId: 'B', view: 'front' + source: 'CATH', familyId: '1.10.490.10', familyName: 'Globin-like', totalCopies: 2, shownCopies: 1, outOfRangeCopies: 0, chainId: 'B', authChainId: 'B', view: 'front', })).toEqual({ _entry_id: '1hda', _extras: undefined, diff --git a/src/captions/captions.ts b/src/captions/captions.ts index 2f4987d..20eb42e 100644 --- a/src/captions/captions.ts +++ b/src/captions/captions.ts @@ -11,7 +11,7 @@ import { TextBuilder } from './text-builder'; /** Orientation of a 3D view. * Use `undefined` when only one view is being rendered, thus it is not necessary to specify orientation. */ -export type ViewType = 'front' | 'side' | 'top' | undefined +export type ViewType = 'front' | 'side' | 'top' | undefined; /** Data needed to save an image, related captions, and metadata. */ @@ -24,7 +24,7 @@ export interface ImageSpec { description: string, /** Image caption, plain-text */ clean_description: string, - /** PDB or AlphaFoldDB identifier*/ + /** PDB or AlphaFoldDB identifier */ _entry_id: string, /** View orientation */ _view: ViewType, @@ -172,7 +172,7 @@ export namespace Captions { shownCopies: number, /** Number of domain instances in the shown chain which are completely out of the observed residue range (therefore not visible) */ outOfRangeCopies: number, - view: ViewType + view: ViewType, }): ImageSpec { const { entryId, source, familyId, familyName, entityId, chainId, authChainId, totalCopies, shownCopies, outOfRangeCopies, view } = context; const name = entityName(context, entityId); diff --git a/src/expected-files.ts b/src/expected-files.ts index ecaf681..d152160 100644 --- a/src/expected-files.ts +++ b/src/expected-files.ts @@ -77,7 +77,7 @@ async function getExpectedFilenameStemsForPdbMode(entryId: string, types: Set { const plugin = await getTestingPlugin(); try { const oldSnapshot = plugin.canvas3d?.camera.getSnapshot(); - adjustCamera(plugin, s => ({ ...Camera.createDefaultSnapshot(), position: Vec3.create(11, 1, 1) })); + adjustCamera(plugin, () => ({ ...Camera.createDefaultSnapshot(), position: Vec3.create(11, 1, 1) })); const newSnapshot = plugin.canvas3d?.camera.getSnapshot(); expect(newSnapshot).not.toEqual(oldSnapshot); } finally { diff --git a/src/helpers/_spec/helpers.spec.ts b/src/helpers/_spec/helpers.spec.ts index afdc476..735f373 100644 --- a/src/helpers/_spec/helpers.spec.ts +++ b/src/helpers/_spec/helpers.spec.ts @@ -57,7 +57,7 @@ describe('helpers', () => { label: undefined, sets: { 'X': [123] }, }, - } + }, }); expect(getModifiedResidueInfo([ @@ -85,7 +85,7 @@ describe('helpers', () => { label: undefined, sets: { 'Z': [999] }, }, - } + }, }); }); diff --git a/src/helpers/_spec/structure-info.spec.ts b/src/helpers/_spec/structure-info.spec.ts index 489bd1c..15a73f5 100644 --- a/src/helpers/_spec/structure-info.spec.ts +++ b/src/helpers/_spec/structure-info.spec.ts @@ -35,7 +35,7 @@ describe('structure-info', () => { description: 'water', index: 3, type: 'water', - } + }, }); }); @@ -65,7 +65,7 @@ describe('structure-info', () => { expect(countChainResidues(model)).toEqual({ A: 141, B: 145, C: 141, D: 145, // proteins E: 1, F: 1, G: 1, H: 1, // hems - I: 19, J: 8, K: 10, L: 5 // waters + I: 19, J: 8, K: 10, L: 5, // waters }); }); diff --git a/src/helpers/helpers.ts b/src/helpers/helpers.ts index e0e0e87..00973eb 100644 --- a/src/helpers/helpers.ts +++ b/src/helpers/helpers.ts @@ -16,7 +16,7 @@ import { SubstructureDef } from './substructure-def'; /** Like `Partial` but recursive (i.e. values themselves can be partial). */ -export type PPartial = T extends {} ? { [P in keyof T]?: PPartial } | undefined : T +export type PPartial = T extends object ? { [P in keyof T]?: PPartial } | undefined : T; /** Create a new object with values from `first`, optionally overridden by values from `second`, recursively. * (I know there is `mergeDeep` in `immutable` but this implementation also gives type hints). */ @@ -151,7 +151,7 @@ export function safePromise(asyncFunction: () => Promise): SafePromise } else { throw theReason; } - } + }, }; } diff --git a/src/helpers/logging.ts b/src/helpers/logging.ts index dc68503..35d428b 100644 --- a/src/helpers/logging.ts +++ b/src/helpers/logging.ts @@ -11,7 +11,7 @@ import util from 'util'; /** Available levels for logging */ export const LogLevels = ['ALL', 'TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL', 'MARK', 'OFF'] as const; -export type LogLevel = typeof LogLevels[number] +export type LogLevel = typeof LogLevels[number]; const ROOT_DIRS = ['src', 'lib', 'build']; diff --git a/src/helpers/structure-info.ts b/src/helpers/structure-info.ts index e474fc8..b794716 100644 --- a/src/helpers/structure-info.ts +++ b/src/helpers/structure-info.ts @@ -13,10 +13,17 @@ import { getLogger } from './logging'; const logger = getLogger(module); /** Entity type (i.e. value of _entity.type in mmCIF): polymer, non-polymer, water... */ -type EntityType = ReturnType +type EntityType = ReturnType; /** Basic info about several entities, mapped by entityId */ -export type EntityInfo = { [entityId: string]: { description: string, type: EntityType, chains: ChainIndex[], index: number } } +export interface EntityInfo { + [entityId: string]: { + description: string, + type: EntityType, + chains: ChainIndex[], + index: number, + }, +} /** Return basic info about entities in the structure, mapped by entityId */ export function getEntityInfo(structure: Structure) { diff --git a/src/helpers/substructure-def.ts b/src/helpers/substructure-def.ts index 66e5546..bc47c48 100644 --- a/src/helpers/substructure-def.ts +++ b/src/helpers/substructure-def.ts @@ -9,7 +9,7 @@ import { Expression } from 'molstar/lib/commonjs/mol-script/language/expression' /** Definition of a substructure */ -export type SubstructureDef = SubstructureDef.Domain | SubstructureDef.Sets +export type SubstructureDef = SubstructureDef.Domain | SubstructureDef.Sets; export namespace SubstructureDef { /** Definition of a Domain substructure, i.e. set of residue ranges within one chain */ @@ -19,7 +19,7 @@ export namespace SubstructureDef { chainId: string, /** List of residue ranges `[from, to]`, including both `from` and `to` */ ranges: [number, number][], - label?: string + label?: string, } export namespace Domain { /** Return a new Domain substructure definition */ @@ -31,7 +31,7 @@ export namespace SubstructureDef { const rangeSubexprs = def.ranges.map(r => MolScriptBuilder.core.rel.inRange([MolScriptBuilder.struct.atomProperty.macromolecular.label_seq_id(), r[0], r[1]])); return MolScriptBuilder.struct.generator.atomGroups({ 'chain-test': MolScriptBuilder.core.rel.eq([MolScriptBuilder.struct.atomProperty.macromolecular.label_asym_id(), def.chainId]), - 'residue-test': MolScriptBuilder.core.logic.or(rangeSubexprs) + 'residue-test': MolScriptBuilder.core.logic.or(rangeSubexprs), }); } } @@ -41,7 +41,7 @@ export namespace SubstructureDef { kind: 'sets', /** List of residue numbers in each chain (label_seq_id, label_asym_id) */ sets: { [chainId: string]: number[] }, - label?: string + label?: string, } export namespace Sets { /** Return a new Sets substructure definition */ @@ -56,9 +56,9 @@ export namespace SubstructureDef { MolScriptBuilder.core.logic.and([ MolScriptBuilder.core.rel.eq([MolScriptBuilder.struct.atomProperty.macromolecular.label_asym_id(), chainId]), MolScriptBuilder.core.logic.or( - def.sets[chainId].map(r => MolScriptBuilder.core.rel.eq([MolScriptBuilder.struct.atomProperty.macromolecular.label_seq_id(), r])) - ) - ]) + def.sets[chainId].map(r => MolScriptBuilder.core.rel.eq([MolScriptBuilder.struct.atomProperty.macromolecular.label_seq_id(), r])), + ), + ]), ); } return MolScriptBuilder.struct.generator.atomGroups({ diff --git a/src/image-generator.ts b/src/image-generator.ts index 4088bde..05267db 100644 --- a/src/image-generator.ts +++ b/src/image-generator.ts @@ -134,7 +134,7 @@ export class ImageGenerator { const context = { entryId, assemblyId: undefined, isPreferredAssembly: false, nModels, entityNames: await this.api.getEntityNames(entryId), - entityInfo: getEntityInfo(structure.data!) + entityInfo: getEntityInfo(structure.data!), }; const colors = assignEntityAndUnitColors(structure.data!); @@ -231,7 +231,7 @@ export class ImageGenerator { const context = { entryId, assemblyId, isPreferredAssembly, nModels: 1, entityNames: await this.api.getEntityNames(entryId), - entityInfo: getEntityInfo(structure.data!) + entityInfo: getEntityInfo(structure.data!), }; const colors = assignEntityAndUnitColors(structure.data!); const group = await structure.makeGroup({ label: 'Whole Assembly' }, { state: { isGhost: ALLOW_GHOST_NODES } }); diff --git a/src/image/draw.ts b/src/image/draw.ts index d8b96bb..c4099e2 100644 --- a/src/image/draw.ts +++ b/src/image/draw.ts @@ -147,8 +147,8 @@ function addTriangle(img: RawImageData, triangle: [Point, Point, Point], color: } } -type Point = [number, number] -type Vector = [number, number] +type Point = [number, number]; +type Vector = [number, number]; /** Return the vector from point `A` to `B` (i.e. B minus A) */ function diff(B: Point, A: Point): Vector { diff --git a/src/tree-manipulation.ts b/src/tree-manipulation.ts index eed2a23..e98c68b 100644 --- a/src/tree-manipulation.ts +++ b/src/tree-manipulation.ts @@ -60,15 +60,15 @@ const STICK_SIZE_ASPECT_RATIO = 0.5; const VALIDATION_UNAVAILABLE_COLOR = FADED_COLOR; -export type StructureObjSelector = StateObjectSelector +export type StructureObjSelector = StateObjectSelector; -type StandardComponentType = 'polymer' | 'branched' | 'branchedLinkage' | 'ligand' | 'ion' | 'nonstandard' -type LigEnvComponentType = 'ligand' | 'environment' | 'wideEnvironment' | 'linkage' -type StandardVisualType = 'polymerCartoon' | 'branchedCarbohydrate' | 'branchedSticks' | 'branchedLinkageSticks' | 'ligandSticks' | 'ionSticks' | 'nonstandardSticks' -type LigEnvVisualType = 'ligandSticks' | 'environmentSticks' | 'linkageSticks' | 'wideEnvironmentCartoon' +type StandardComponentType = 'polymer' | 'branched' | 'branchedLinkage' | 'ligand' | 'ion' | 'nonstandard'; +type LigEnvComponentType = 'ligand' | 'environment' | 'wideEnvironment' | 'linkage'; +type StandardVisualType = 'polymerCartoon' | 'branchedCarbohydrate' | 'branchedSticks' | 'branchedLinkageSticks' | 'ligandSticks' | 'ionSticks' | 'nonstandardSticks'; +type LigEnvVisualType = 'ligandSticks' | 'environmentSticks' | 'linkageSticks' | 'wideEnvironmentCartoon'; -type StructureParams = ParamDefinition.Values> -type VisualParams = ReturnType +type StructureParams = ParamDefinition.Values>; +type VisualParams = ReturnType; /** Handle for manipulating state tree node */ @@ -190,9 +190,9 @@ export class ModelNode extends Node { const customPropsNode = await this.state.build().to(this.node).apply(CustomModelProperties, { properties: { pdbe_structure_quality_report: { - serverUrl: api?.pdbeStructureQualityReportPrefix() - } - } + serverUrl: api?.pdbeStructureQualityReportPrefix(), + }, + }, }, { ref }).commit(); return new ModelNode(customPropsNode); } @@ -250,7 +250,7 @@ export class StructureNode extends Node { MolScriptBuilder.core.rel.eq([ MolScriptBuilder.struct.atomProperty.macromolecular.label_entity_id(), ligandInfo.entityId]), - ]) + ]), }); const envExpr = MolScriptBuilder.struct.modifier.exceptBy({ 0: MolScriptBuilder.struct.modifier.includeSurroundings({ @@ -264,7 +264,7 @@ export class StructureNode extends Node { const bondTest = MolScriptBuilder.core.flags.hasAny([ MolScriptBuilder.struct.bondProperty.flags(), MolScriptBuilder.core.type.bitflags([BondType.Flag.Covalent | BondType.Flag.MetallicCoordination - | BondType.Flag.HydrogenBond | BondType.Flag.Disulfide | BondType.Flag.Aromatic | BondType.Flag.Computed]) + | BondType.Flag.HydrogenBond | BondType.Flag.Disulfide | BondType.Flag.Aromatic | BondType.Flag.Computed]), ]); // taken from ligandPlusConnected (static component 'ligand') const linkageExpr = MolScriptBuilder.struct.modifier.intersectBy({ 0: MolScriptBuilder.struct.modifier.includeConnected({ 0: ligExpr, 'layer-count': 1, 'bond-test': bondTest }), @@ -273,19 +273,19 @@ export class StructureNode extends Node { const ligand = await this.makeComponent({ type: { name: 'expression', params: ligExpr }, - label: ligandLabel + label: ligandLabel, }, options, `lig-${ligandLabel}`); const environment = await this.makeComponent({ type: { name: 'expression', params: envExpr }, - label: envLabel + label: envLabel, }, options, `env-${ligandLabel}`); const wideEnvironment = await this.makeComponent({ type: { name: 'expression', params: wideEnvExpr }, - label: 'Wider environment' + label: 'Wider environment', }, options, `wide-${ligandLabel}`); const linkage = await this.makeComponent({ type: { name: 'expression', params: linkageExpr }, - label: 'Linkage' + label: 'Linkage', }, options, `link-${ligandLabel}`); return new LigandEnvironmentComponents({ ligand, environment, wideEnvironment, linkage }); } @@ -298,11 +298,11 @@ export class StructureNode extends Node { for (const entityId in entityInfo) { const description = entityInfo[entityId].description; const expression = MolScriptBuilder.struct.generator.atomGroups({ - 'entity-test': MolScriptBuilder.core.rel.eq([MolScriptBuilder.struct.atomProperty.macromolecular.label_entity_id(), entityId]) + 'entity-test': MolScriptBuilder.core.rel.eq([MolScriptBuilder.struct.atomProperty.macromolecular.label_entity_id(), entityId]), }); const entitySelection = await this.makeComponent({ type: { name: 'expression', params: expression }, - label: `Entity ${entityId} (${description})` + label: `Entity ${entityId} (${description})`, }, undefined, `entity-${entityId}`); selections[entityId] = entitySelection; } @@ -312,7 +312,7 @@ export class StructureNode extends Node { /** Create a component from a stucture, based on chainId (label_asym_id) */ async makeChain(chainId: string, authChainId?: string): Promise { const expression = MolScriptBuilder.struct.generator.atomGroups({ - 'chain-test': MolScriptBuilder.core.rel.eq([MolScriptBuilder.struct.atomProperty.macromolecular.label_asym_id(), chainId]) + 'chain-test': MolScriptBuilder.core.rel.eq([MolScriptBuilder.struct.atomProperty.macromolecular.label_asym_id(), chainId]), }); return await this.makeComponent({ type: { name: 'expression', params: expression }, @@ -323,7 +323,7 @@ export class StructureNode extends Node { /** Create a component from a stucture, based on authChainId (auth_asym_id) */ async makeAuthChain(authChainId: string, labelChainId?: string): Promise { const expression = MolScriptBuilder.struct.generator.atomGroups({ - 'chain-test': MolScriptBuilder.core.rel.eq([MolScriptBuilder.struct.atomProperty.macromolecular.auth_asym_id(), authChainId]) + 'chain-test': MolScriptBuilder.core.rel.eq([MolScriptBuilder.struct.atomProperty.macromolecular.auth_asym_id(), authChainId]), }); return await this.makeComponent({ type: { name: 'expression', params: expression }, @@ -400,7 +400,7 @@ export class VisualNode extends Node deepMerge(old, change instanceof Function ? change(old, tags) : change) + old => deepMerge(old, change instanceof Function ? change(old, tags) : change), ); } await update.commit(); @@ -423,7 +423,7 @@ export class VisualNode extends Node ({ colorTheme: (old.type.name === 'ball-and-stick' && !options?.ignoreElementColors) ? { name: 'element-symbol', params: { carbonColor: { name: 'entity-id', params: { palette } } } } - : { name: 'entity-id', params: { palette } } + : { name: 'entity-id', params: { palette } }, })); } /** Color this visual by auth chain ID (i.e. copies of the same chain in an assembly will have the same color), color balls-and-sticks by element with chainId-colored carbons. */ @@ -432,7 +432,7 @@ export class VisualNode extends Node ({ colorTheme: (old.type.name === 'ball-and-stick' && !options?.ignoreElementColors) ? { name: 'element-symbol', params: { carbonColor: { name: 'chain-id', params: { palette } } } } - : { name: 'chain-id', params: { palette } } + : { name: 'chain-id', params: { palette } }, })); } /** Color this visual by chain instance (i.e. copies of the same chain in an assembly will have different colors), color balls-and-sticks by element with gray carbons. */ @@ -441,7 +441,7 @@ export class VisualNode extends Node ({ colorTheme: (old.type.name === 'ball-and-stick' && !options?.ignoreElementColors) ? { name: 'element-symbol', params: { carbonColor: { name: 'unit-index', params: { palette } } } } - : { name: 'unit-index', params: { palette } } + : { name: 'unit-index', params: { palette } }, })); } /** Color this visual with a single colore. */ @@ -457,7 +457,7 @@ export class VisualNode extends Node