npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@synanetics/syn-utils

v3.0.0

Published

synanetics util functionality

Downloads

92

Readme

@synanetics/syn-utils

A collection of common utility functions used across multiple Synanetics repositories

Usage

const {
  getPrefix, removePrefix
} = require('@synanetics/syn-utils');
// or
import {
  getPrefix, removePrefix
} from '@synanetics/syn-utils';

API

Paging

Function: pageBuilder

The pageBuilder function takes in an array of sorted sourceBundles and pageConfig, and returns a bundle page with those with the combined resources from all the bundles.

Arguments

function pageBuilder(sourceBundles: SourceBundle[], config: PageConfig) => PageOutput

interface SourceBundle {
  sourceId: string;
  bundle: Bundle; 
}

interface SortConfig {
  fhirSorter: FhirSorter;
  sortTerms: string[];
  allowChainedSort?: boolean;
}

interface PageConfig {
  pagingBaseUrl: URL;
  pageSize?: number;
  sortConfig?: SortConfig;
  currentPageNum?: number;
  partialPage?: Bundle;
}

interface PageOutput {
  completePage: boolean;
  page: Bundle;
  sourceBundles: SourceBundle[];
  bundleToReplace?: string;
}
  • sourceBundles
    • The Bundles to combine into a single page
    • All Bundles must have a 'Total'
    • At least one Bundle must have entries
  • config
    • The config defines how the page is to be built
    • pagingBaseUrl
      • The url to which the paging links can be appended
      • e.g https://fhir.store.nhs.uk/patient?_queryId=uuid ->
        • {relation: 'self', url: 'https://fhir.store.nhs.uk/patient?_queryId=uuid&_page=4'}
        • {relation: 'first', url: 'https://fhir.store.nhs.uk/patient?_queryId=uuid&_page=1'}
        • {relation: 'last', url: 'https://fhir.store.nhs.uk/patient?_queryId=uuid&_page=9'}
        • {relation: 'previous', url: 'https://fhir.store.nhs.uk/patient?_queryId=uuid&_page=3'}
        • {relation: 'next', url: 'https://fhir.store.nhs.uk/patient?_queryId=uuid&_page=5'}
    • pageSize
      • The desired maximum page size
      • Must be a positive integer
      • Will default to 100 if not provided
    • sortConfig?
      • This is an optional parameter, if it is not provided the pageBuilder will iterate over each source to build the page
      • fhirSorter
        • An instance of the FhirSorter from the @synanetics/fhir-sort package
      • sortTerms
        • An array of strings that will be used to sort the resources in the Bundles
        • e.g ['family', '_lastUpdated']
      • allowChainedSort
        • A boolean to allow/disallow chained sorting
        • For details on chained sorting see the @synanetics/fhir-sort package README
        • This parameter is optional and will default to false if not provided
    • currentPageNum?
      • The number of the page being built
      • e.g If you are calling the pageBuilder to build the 3rd page in a set of 5, this value should be 3
      • This value will default to 1 if not provided
    • partialPage?
      • This is an optional parameter
      • This parameter should only be provided when the pageBuilder previously returned an incomplete page
      • This happens when the pageBuilder has emptied an input bundle and requires a replacement
      • When you recall pageBuilder with the new bundle, you will pass in the incomplete page in partialPage returned by the first call

Return Values

  • completePage
    • This is a boolean
    • This is true when:
      • The pageBuilder was able to build a page of the desired maximum size
      • The page builder has emptied all the bundles and built the final page
    • This is false when:
      • The page builder emptied one of the input bundles before completing the page and has determined it needs a replacement
  • page
    • This is a FHIR Bundle
    • Its total will be the combined total of all bundles
    • It will have paging links
    • Its entries will be populated from the input bundles
      • Outcomes come first
        • Any outcomes from all input bundles will appear first on the page
        • These can be in any order
      • Matches come second
        • A sorted, if sortTerms are provided, subset of the matches from all the input bundles will come after the outcomes
        • This will most often not contain all the matches from all the inputs, as the page size will likely be smaller than the number of matches provided
      • Includes come third
        • Any includes referenced in the matches will come after the matches
        • Each include will be referenced at least once by at least one match
        • Each include will only appear once
  • sourceBundles
    • The sourceBundles outputted by the page builder are similar to the ones inputted
    • The key difference is the output bundles will not contain any matches or outcomes already put into a page
    • e.g If we have input bundles with 5 matches each for 5 sources, and a page size of 10, the output bundles may contain 3 matches each for 5 sources.
    • Bundles that are emptied of matches will not be returned by the pageBuilder
  • bundleToReplace?
    • If the pageBuilder empties a paginated Bundle that is not on its last page, it needs to request a new bundle
    • When this occurs it populates this optional string with the source id of the bundle to be replaced

Usage

This is an example flow where the first call returns a complete page, and the second call requires a replacement bundle.

First Call:

  1. FHIR query received requiring pagination
  2. Gather the sorted Bundles from each source
  3. Call the pageBuilder with the source Bundles, and desired config for page 1
  4. pageBuilder returns completed page, and partially consumed input bundles
  5. Cache the page, and partially consumed input bundles
  6. Return the page

Second Call (with emptied Bundle):

  1. Second page requested
  2. Retrieve partially consumed input bundles from cache
  3. Call the pageBuilder with the partially consumed Bundles, and desired config for page 2
  4. pageBuilder responds with an incomplete page, partially consumed Bundles, and requests a replacement Bundle from "source1"
  5. Retrieve the next Bundle from "source1"
  6. Call the pageBuilder with the partially consumed Bundles, the fresh Bundle from "source1", desired config for page 2 and the incomplete page previously returned
  7. pageBuilder returns completed page, and partially consumed input bundles
  8. Cache the page, and partially consumed input bundles
  9. Return the page

Prefix

Defaults

The prefix functions have default configuration values/functions which are as below.

const defaultPrefixDelimiter: string = '.';
const defaultEscapeRegex = (string: string): string => string.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
const defaultPrefixRegex: string = `^(?:.*/)?(?<prefix>.*?)${defaultEsc
apeRegex(defaultPrefixDelimiter)}.*`;

Function: getPrefix

The get prefix function takes in a string and returns a prefix that matches the provided arguments.

Arguments

function getPrefix(value: string, validPrefixes?: string[], prefixRegex: string = defaultPrefixRegex) => string
  • value
    • The string to retrieve the prefix from
    • If no value is provided an error will be thrown
  • validPrefixes
    • An array of valid prefix strings
    • If this is not provided, all prefixes are considered valid
  • dpPrefixRegex
    • Defaults to defaultDpPrefixRegex
    • This regex is used to find the prefix in value

Usage

//Expect value: wow
getPrefix('wow.theRest');

//Expect value: apple
getPrefix('apple.pie', ['apple', 'pear']);

// Expect error: No value provided 
getPrefix();

//Expect Error: No valid prefixes found
getPrefix('this has no prefix');

//Expect Error: No valid prefixes found
getPrefix('tomato.pie', ['apple', 'pear']);

Function: removePrefix

The get prefix function takes in a string and returns a prefix that matches the provided arguments.

Arguments

function removePrefix(value: string, prefix: string, prefixDelimiter: string = defaultPrefixDelimiter, escapeRegex: (string: string) => string = defaultEscapeRegex) => string 
  • value
    • The string to remove the prefix from
    • If no value is provided an error will be thrown
  • prefix
    • The prefix to remove
    • If no prefix is provided an error will be thrown
  • prefixDelimiter
    • Defaults to defaultPrefixDelimiter
    • This string is used to split prefix from value
  • escapeRegex
    • Defaults to defaultEscapeRegex
    • This regex is applied to the prefixDelimiter to escape protected characters

Usage

//Expect value: theRest
removePrefix('wow.theRest', 'wow');

//Expect value: apple.pie
removePrefix('apple.pie', 'pear');

// Expect error: No value provided 
removePrefix();

// Expect error: No prefix provided 
removePrefix('wow');

Function: removePrefixFromFhirObj

The removePrefixFromFhirObj function removes a prefix string from all ids and reference ids in a FHIR object

function removePrefixFromFhirObj<T extends (fhir3.FhirResource | fhir4.FhirResource)>(  
    input: T,
    prefix: string,
    prefixDelimiter?: string,
    maxDepth?: number,
  ) => T

Arguments

  • input is a FHIR stu3/r4 resource as defined in the @types/fhir package such as a Patient resource
  • prefix is a string such as 'HUB' that should be removed from all ids and reference ids
  • prefixDelimiter is a string that is used to delimit where a prefix ends and an id begins, this defaults to '.'
  • maxDepth is a number that represents the maximum recursion depth that is allowed before an error is thrown, this defaults to 15

Usage

//Input resource: 
const patient: Patient = {
    id: 'HUB.pat1',
    resourceType: 'Patient',
    generalPractitioner: [
    {
        reference: '#contained',
    },
    {
        reference: 'Organization/HUB.org1',
    },
    {
        reference: 'Organization/HUB.org1',
    },
    {
        reference: 'Practitioner/HUB.DDCR.pra1',
    },
    {
        reference: 'Practitioner/HUB.pra2/_history/4',
    },
    ],
    managingOrganization: {
    reference: 'url/fhir/Organization/HUB.DDCR.org2',
    },
};

const unprefixedPatient: Patient = removePrefixFromFhirObj(patient, 'HUB');

// expect unprefixedPatient to equal expectedPatient
const expectedPatient: Patient = {
    id: 'pat1',
    resourceType: 'Patient',
    generalPractitioner: [
    {
        reference: '#contained',
    },
    {
        reference: 'Organization/org1',
    },
    {
        reference: 'Organization/org1',
    },
    {
        reference: 'Practitioner/DDCR.pra1',
    },
    {
        reference: 'Practitioner/pra2/_history/4',
    },
    ],
    managingOrganization: {
    reference: 'url/fhir/Organization/DDCR.org2',
    },
};

Reference

Interface: ReferenceDetails

interface ReferenceDetails {
  original: string;
  contained: boolean;
  version: number;
  id?: string;
  type?: string;
  criteria?: string;
  url?: string;
  relative?: string;
}

Function: getReferenceDetails

The get getReferenceDetails function takes in a reference string and extracts the details into a ReferenceDetails object

Arguments

function getReferenceDetails(referenceString: string) => ReferenceDetails
  • referenceString
    • The string to extract the details from
    • If no referenceString is provided an error will be thrown

Usage

//Expect value: 
const expectedValue = {
    original: '#p1',
    contained: true,
    version: 1,
    id: 'p1'
}
getReferenceDetails('#p1');

//Expect value: 
const expectedValue = {
      original: 'ValueSet?url=http://hl7.org/fhir/ValueSet/my-valueset&version=0.8',
      contained: false,
      version: 1,
      type: 'ValueSet',
      criteria: 'url=http://hl7.org/fhir/ValueSet/my-valueset&version=0.8',
}
getReferenceDetails('ValueSet?url=http://hl7.org/fhir/ValueSet/my-valueset&version=0.8');

//Expect value: 
const expectedValue = {
      original: 'url/fhir/r4/Patient/12345',
      contained: false,
      version: 1,
      type: 'Patient',
      id: '12345',
      url: 'url/fhir/r4/Patient/12345',
      relative: 'Patient/12345',
}
getReferenceDetails('url/fhir/r4/Patient/12345');

//Expect value: 
const expectedValue = {
      original: 'Patient/12345/_history/5',
      contained: false,
      version: 5,
      type: 'Patient',
      id: '12345',
      relative: 'Patient/12345',
}
getReferenceDetails('Patient/12345/_history/5');

Function: getUniqueRelativeReferences

The get getUniqueRelativeReferences function takes in a fhir resource and extracts unique relative reference strings

function getUniqueRelativeReferences(
    input: Record<any, any>,  
    relativeRefs?: Set<string>,
    maxDepth?: string,
) => Set<string>

Arguments

  • input is a FHIR resource as defined in the @types/fhir package such as a Patient resource
  • relativeRefs is a set of unique relative reference strings, e.g Patient/12345, this defaults to an empty set
  • maxDepth is a number that represents the maximum recursion depth that is allowed before an error is thrown, this defaults to 15

Usage

//Input resource: 
const patient: Patient = {
    resourceType: 'Patient',
    generalPractitioner: [
    {
        reference: '#notRelative',
    },
    {
        reference: 'Organization/1',
    },
    {
        reference: 'Organization/1',
    },
    {
        reference: 'Practitioner/1',
    },
    {
        reference: 'Practitioner/2/_history/4',
    },
    ],
    managingOrganization: {
    reference: 'url/fhir/Organization/2',
    },
};

//Expect set to contain 'Organization/1', 'Practitioner/1', 'Practitioner/2', 'Organization/2' 
getUniqueRelativeReferences(patient);

Rebase References

Function: rebaseReferences

A function to prefix any identifiers or relative references with the supplied string.

Usage:

const resource = {
    id: 'DEF.123',
    subject: {
        reference: 'Patient/DEF.456',
    },
};

const rebasedResource = rebaseReferences(resource, 'ABC');
expect(resource).toEqual({
    id: 'ABC.DEF.123',
    subject: {
        reference: 'Patient/ABC.DEF.456',
    },
})