Skip to content

Commit

Permalink
Throw an error if the destructured options contains an unknown key.
Browse files Browse the repository at this point in the history
This avoids silent errors when the caller misspells an option.
  • Loading branch information
LTLA committed Oct 12, 2024
1 parent f14bbe5 commit 817de5c
Show file tree
Hide file tree
Showing 45 changed files with 502 additions and 226 deletions.
5 changes: 4 additions & 1 deletion js/MultiMatrix.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ export class MultiMatrix {
* Each matrix should correspond to a different modality, named according to its key.
* All matrices should have data for the same set of cells, i.e., same number of columns.
*/
constructor({ store = {} } = {}) {
constructor(options = {}) {
const { store = {}, ...others } = options;
utils.checkOtherOptions(others);

this.#store = store;
this.#ncols = null;

Expand Down
10 changes: 8 additions & 2 deletions js/ScranMatrix.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,10 @@ export class ScranMatrix {
* If `buffer` was supplied, the returned array is a view into it.
* Note that this may be invalidated on the next allocation on the Wasm heap.
*/
row(i, { buffer = null } = {}) {
row(i, options = {}) {
let { buffer = null, ...others } = options;
utils.checkOtherOptions(others);

if (buffer != null) {
this.#matrix.row(i, buffer.offset);
return buffer.array();
Expand Down Expand Up @@ -111,7 +114,10 @@ export class ScranMatrix {
* If `buffer` was supplied, the returned array is a view into it.
* Note that this may be invalidated on the next allocation on the Wasm heap.
*/
column(i, { buffer = null } = {}) {
column(i, options = {}) {
let { buffer = null, ...others } = options;
utils.checkOtherOptions(others);

if (buffer != null) {
this.#matrix.column(i, buffer.offset);
return buffer.array();
Expand Down
20 changes: 15 additions & 5 deletions js/aggregateAcrossCells.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ export class AggregateAcrossCellsResults {
* @return {Float64Array|Float64WasmArray} Array of length equal to the number of genes, containing the per-gene sum of values across across all cells in the specified `group`.
* If `average = true` in {@linkcode aggregateAcrossCells}, each element is the mean value instead.
*/
groupSums(group, { copy = true } = {}) {
groupSums(group, options = {}) {
const { copy = true, ...others } = options;
utils.checkOtherOptions(others);
return utils.possibleCopy(this.#results.group_sums(group), copy);
}

Expand All @@ -57,7 +59,9 @@ export class AggregateAcrossCellsResults {
* If `average = true` in {@linkcode aggregateAcrossCells}, each element is the mean value instead.
* If `buffer` is supplied, the function returns `buffer` if `asTypedArray = false`, or a view on `buffer` if `asTypedArray = true`.
*/
allSums({ asTypedArray = true, buffer = null } = {}) {
allSums(options = {}) {
let { asTypedArray = true, buffer = null, ...others } = options;
utils.checkOtherOptions(others);
let tmp = null;

try {
Expand All @@ -83,7 +87,9 @@ export class AggregateAcrossCellsResults {
* @return {Float64Array|Float64WasmArray} Array of length equal to the number of genes, containing the number of cells with detected expression for each gene in the specified `group`.
* If `average = true` in {@linkcode aggregateAcrossCells}, each element is the proportion of detected cells instead.
*/
groupDetected(group, { copy = true } = {}) {
groupDetected(group, options = {}) {
const { copy = true, ...others } = options;
utils.checkOtherOptions(others);
return utils.possibleCopy(this.#results.group_detected(group), copy);
}

Expand All @@ -100,7 +106,9 @@ export class AggregateAcrossCellsResults {
* If `average = true` in {@linkcode aggregateAcrossCells}, each element is the proportion of detected cells instead.
* If `buffer` is supplied, the function returns `buffer` if `asTypedArray = false`, or a view on `buffer` if `asTypedArray = true`.
*/
allDetected({ asTypedArray = true, buffer = null } = {}) {
allDetected(options = {}) {
let { asTypedArray = true, buffer = null, ...others } = options;
utils.checkOtherOptions(others);
let tmp = null;

try {
Expand Down Expand Up @@ -144,7 +152,9 @@ export class AggregateAcrossCellsResults {
*
* @return {AggregateAcrossCellsResults} Object containing the aggregation results.
*/
export function aggregateAcrossCells(x, groups, { average = false, numberOfThreads = null } = {}) {
export function aggregateAcrossCells(x, groups, options = {}) {
const { average = false, numberOfThreads = null, ...others } = options;
utils.checkOtherOptions(others);
var group_data;
var output;
let nthreads = utils.chooseNumberOfThreads(numberOfThreads);
Expand Down
8 changes: 6 additions & 2 deletions js/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ import * as fac from "./factorize.js";
*
* If `buffer` was supplied, it is used as the return value.
*/
export function createBlock(ncells, { buffer = null } = {}) {
export function createBlock(ncells, options = {}) {
let { buffer = null, ...other } = options;
utils.checkOtherOptions(other);
let total = 0;
ncells.forEach(x => { total += x; });

Expand Down Expand Up @@ -62,7 +64,9 @@ export function subsetBlock(x, subset, { filter = null, buffer = null } = {}) {
}

// Soft-deprecated, just use subsetFactor().
export function filterBlock(x, filter, { buffer = null } = {}) {
export function filterBlock(x, filter, options = {}) {
let { buffer = null, ...other } = options;
utils.checkOtherOptions(other);
return subsetBlock(x, filter, { buffer: buffer, filter: true });
}

Expand Down
4 changes: 3 additions & 1 deletion js/buildSnnGraph.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ export class BuildSnnGraphResults {
*
* @return {BuildSnnGraphResults} Object containing the graph.
*/
export function buildSnnGraph(x, { scheme = "rank", neighbors = 10, numberOfThreads = null } = {}) {
export function buildSnnGraph(x, options = {}) {
const { scheme = "rank", neighbors = 10, numberOfThreads = null, ...others } = options;
utils.checkOtherOptions(others);
var output;
var my_neighbors;
let nthreads = utils.chooseNumberOfThreads(numberOfThreads);
Expand Down
7 changes: 6 additions & 1 deletion js/chooseHvgs.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@ import { ModelGeneVariancesResults } from "./modelGeneVariances.js";
* @return {Uint8WasmArray} Array of length equal to the number of genes.
* Highly variable genes are marked with a value of 1 and all other genes have values of zero.
*/
export function chooseHvgs(x, { number = 4000, minimum = 0 } = {}) {
export function chooseHvgs(x, options = {}) {
const { number = 4000, minimum = 0, ...others } = options;
utils.checkOtherOptions(others);
let stat;
let chosen;

try {
if (x instanceof ModelGeneVariancesResults) {
stat = x.residuals({ copy: "view" });
Expand All @@ -27,11 +30,13 @@ export function chooseHvgs(x, { number = 4000, minimum = 0 } = {}) {
}
chosen = utils.createUint8WasmArray(stat.length);
wasm.call(module => module.choose_highly_variable_genes(stat.length, stat.offset, chosen.offset, number, minimum));

} catch (e) {
chosen.free();
throw e;
} finally {
stat.free();
}

return chosen;
}
43 changes: 28 additions & 15 deletions js/clusterGraph.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export class ClusterMultilevelResults {
#id;
#results;

constructor(id, raw, filled = true) {
constructor(id, raw) {
this.#id = id;
this.#results = raw;
}
Expand All @@ -36,7 +36,9 @@ export class ClusterMultilevelResults {
*
* @return {number} The modularity at the specified level.
*/
modularity({ level = null } = {}) {
modularity(options = {}) {
let { level = null, ...others } = options;
utils.checkOtherOptions(others);
if (level == null) {
level = this.bestLevel();
}
Expand All @@ -51,7 +53,9 @@ export class ClusterMultilevelResults {
*
* @return {Int32Array|Int32WasmArray} Array containing the cluster membership for each cell.
*/
membership({ level = null, copy = true } = {}) {
membership(options = {}) {
let { level = null, copy = true, ...others } = options;
utils.checkOtherOptions(others);
if (level == null) {
level = -1;
}
Expand Down Expand Up @@ -79,7 +83,7 @@ export class ClusterWalktrapResults {
#id;
#results;

constructor(id, raw, filled = true) {
constructor(id, raw) {
this.#id = id;
this.#results = raw;
}
Expand All @@ -98,7 +102,9 @@ export class ClusterWalktrapResults {
* Set to `null` to obtain the largest modularity across all merge steps.
* @return {number} The modularity at the specified merge step, or the maximum modularity across all merge steps.
*/
modularity({ at = null } = {}) {
modularity(options = {}) {
let { at = null, ...others } = options;
utils.checkOtherOptions(others);
if (at === null) {
at = -1;
}
Expand All @@ -110,7 +116,9 @@ export class ClusterWalktrapResults {
* @param {boolean|string} [options.copy=true] - Whether to copy the results from the Wasm heap, see {@linkcode possibleCopy}.
* @return {Int32Array|Int32WasmArray} Array containing the cluster membership for each cell.
*/
membership({ copy = true } = {}) {
membership(options = {}) {
const { copy = true, ...others } = options;
utils.checkOtherOptions(others);
return utils.possibleCopy(this.#results.membership(), copy);
}

Expand Down Expand Up @@ -157,7 +165,9 @@ export class ClusterLeidenResults {
*
* @return {(Int32Array|Int32WasmArray)} Array containing the cluster membership for each cell.
*/
membership({ copy = true } = {}) {
membership(options = {}) {
const { copy = true, ...others } = options;
utils.checkOtherOptions(others);
return utils.possibleCopy(this.#results.membership(), copy);
}

Expand Down Expand Up @@ -193,15 +203,18 @@ export class ClusterLeidenResults {
* @return {ClusterMultiLevelResults|ClusterWalktrapResults|ClusterLeidenResults} Object containing the clustering results.
* The class of this object depends on the choice of `method`.
*/
export function clusterGraph(x, {
method = "multilevel",
multiLevelResolution = 1,
leidenResolution = 1,
leidenModularityObjective = false,
walktrapSteps = 4
} = {}) {
var output;
export function clusterGraph(x, options = {}) {
const {
method = "multilevel",
multiLevelResolution = 1,
leidenResolution = 1,
leidenModularityObjective = false,
walktrapSteps = 4,
...others
} = options;
utils.checkOtherOptions(others);

var output;
try {
if (method == "multilevel") {
output = gc.call(
Expand Down
44 changes: 27 additions & 17 deletions js/clusterKmeans.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export class ClusterKmeansResults {
#id;
#results;

constructor(id, raw, filled = true) {
constructor(id, raw) {
this.#results = raw;
this.#id = id;
}
Expand All @@ -34,7 +34,9 @@ export class ClusterKmeansResults {
* @param {boolean|string} [options.copy=true] - Whether to copy the results from the Wasm heap, see {@linkcode possibleCopy}.
* @return {Int32Array|Int32WasmArray} Array containing the cluster assignment for each cell.
*/
clusters({ copy = true } = {}) {
clusters(options = {}) {
const { copy = true, ...others } = options;
utils.checkOtherOptions(others);
return utils.possibleCopy(this.#results.clusters(), copy);
}

Expand All @@ -43,7 +45,9 @@ export class ClusterKmeansResults {
* @param {boolean|string} [options.copy=true] - Whether to copy the results from the Wasm heap, see {@linkcode possibleCopy}.
* @return {Int32Array|Int32WasmArray} Array containing the number of cells in each cluster.
*/
sizes({ copy = true } = {}) {
sizes(options = {}) {
const { copy = true, ...others } = options;
utils.checkOtherOptions(others);
return utils.possibleCopy(this.#results.cluster_sizes(), copy);
}

Expand All @@ -53,7 +57,9 @@ export class ClusterKmeansResults {
* @return {Float64Array|Float64WasmArray} Array containing the cluster centers in column-major format,
* where rows are dimensions and columns are the clusters.
*/
centers({ copy = true } = {}) {
centers(options = {}) {
const { copy = true, ...others } = options;
utils.checkOtherOptions(others);
return utils.possibleCopy(this.#results.centers(), copy);
}

Expand Down Expand Up @@ -88,7 +94,7 @@ export class ClusterKmeansResults {
* Cluster cells using k-means.
* A variety of initialization and refinement algorithms can be used here, see the [**kmeans** documentation](https://github.com/LTLA/CppKmeans) for more details.
*
* @param {(RunPcaResults|Float64WasmArray|Array|TypedArray)} x - Numeric coordinates of each cell in the dataset.
* @param {(RunPcaResults|Float64WasmArray|Array|TypedArray)} x - Numeric coordinates of each cell in the dataset.
* For array inputs, this is expected to be in column-major format where the rows are the variables and the columns are the cells.
* For a {@linkplain RunPcaResults} input, we extract the principal components.
* @param {number} clusters Number of clusters to create.
Expand All @@ -115,18 +121,22 @@ export class ClusterKmeansResults {
*
* @return {ClusterKmeansResults} Object containing the clustering results.
*/
export function clusterKmeans(x, clusters, {
numberOfDims = null,
numberOfCells = null,
initMethod = "var-part",
initSeed = 5768,
initVarPartSizeAdjust = 1,
initVarPartOptimize = true,
refineMethod = "hartigan-wong",
refineLloydIterations = 100,
refineHartiganWongIterations = 10,
numberOfThreads = null
} = {}) {
export function clusterKmeans(x, clusters, options = {}) {
let {
numberOfDims = null,
numberOfCells = null,
initMethod = "var-part",
initSeed = 5768,
initVarPartSizeAdjust = 1,
initVarPartOptimize = true,
refineMethod = "hartigan-wong",
refineLloydIterations = 100,
refineHartiganWongIterations = 10,
numberOfThreads = null,
...others
} = options;
utils.checkOtherOptions(others);

var buffer;
var output;
let nthreads = utils.chooseNumberOfThreads(numberOfThreads);
Expand Down
4 changes: 3 additions & 1 deletion js/computeClrm1Factors.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ import * as wa from "wasmarrays.js";
* Note that the factors are not centered and should be passed to {@linkcode centerSizeFactors} before calling {@linkcode normalizeCounts}.
* If `buffer` is supplied, the function returns `buffer` if `asTypedArray = false`, or a view on `buffer` if `asTypedArray = true`.
*/
export function computeClrm1Factors(x, { asTypedArray = true, buffer = null, priorCount = 10, numberOfThreads = null } = {}) {
export function computeClrm1Factors(x, options = {}) {
let { asTypedArray = true, buffer = null, priorCount = 10, numberOfThreads = null, ...others } = options;
utils.checkOtherOptions(others);
var local_buffer = null;
let nthreads = utils.chooseNumberOfThreads(numberOfThreads);

Expand Down
12 changes: 9 additions & 3 deletions js/delayed.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ import * as wasm from "./wasm.js";
* @return {ScranMatrix} A ScranMatrix containing the delayed arithmetic operation on `x`.
* If `inPlace = true`, this is a reference to `x`, otherwise it is a new ScranMatrix.
*/
export function delayedArithmetic(x, operation, value, { right = true, along = "row", inPlace = false } = {}) {
export function delayedArithmetic(x, operation, value, options = {}) {
const { right = true, along = "row", inPlace = false, ...others } = options;
utils.checkOtherOptions(others);
let xcopy;
let vbuffer;
let target;
Expand Down Expand Up @@ -68,7 +70,9 @@ export function delayedArithmetic(x, operation, value, { right = true, along = "
* @return {ScranMatrix} A ScranMatrix containing the delayed math operation on `x`.
* If `inPlace = true`, this is a reference to `x`, otherwise it is a new ScranMatrix.
*/
export function delayedMath(x, operation, { logBase = null, inPlace = false } = {}) {
export function delayedMath(x, operation, options = {}) {
let { logBase = null, inPlace = false, ...others } = options;
utils.checkOtherOptions(others);
let xcopy;
let target;

Expand Down Expand Up @@ -104,7 +108,9 @@ export function delayedMath(x, operation, { logBase = null, inPlace = false } =
* @return {ScranMatrix} A ScranMatrix containing the transposition of `x`.
* If `inPlace = true`, this is a reference to `x`, otherwise it is a new ScranMatrix.
*/
export function transpose(x, { inPlace = false } = {}) {
export function transpose(x, options = {}) {
const { inPlace = false, ...others } = options;
utils.checkOtherOptions(others);
let xcopy;
let target;

Expand Down
Loading

0 comments on commit 817de5c

Please sign in to comment.