diff --git a/.changeset/new-things-change.md b/.changeset/new-things-change.md
new file mode 100644
index 0000000000..ee1c3b8abf
--- /dev/null
+++ b/.changeset/new-things-change.md
@@ -0,0 +1,47 @@
+---
+'@openfn/language-googlesheets': major
+---
+
+Updated `appendValues()`, `batchUpdateValues()`, and `getValues()` to use positional arguments instead of a single params object.
+
+### Migration Guide
+
+**`appendValues`**
+
+```js
+// Before
+appendValues({
+ spreadsheetId: '1abc...',
+ range: 'Sheet1!A1:E1',
+ values: [['a', 'b']],
+});
+
+// Now
+appendValues(
+ '1abc...',
+ 'Sheet1!A1:E1',
+ [['a', 'b']],
+);
+```
+
+**`batchUpdateValues`**
+
+```js
+// Before
+batchUpdateValues({
+ spreadsheetId: '1abc...',
+ range: 'Sheet1!A1',
+ values: [['a']],
+ valueInputOption: 'RAW',
+});
+
+// Now
+batchUpdateValues(
+ '1abc...',
+ [{ range: 'Sheet1!A1', values: [['a']] }],
+ { valueInputOption: 'RAW' }
+);
+```
+
+Callback parameter has been removed from `appendValues()`, `batchUpdateValues()`, and `getValues()` in favor of a promise-based API.
+
diff --git a/packages/googlesheets/ast.json b/packages/googlesheets/ast.json
index 9d269ab4d1..0ba36a1476 100644
--- a/packages/googlesheets/ast.json
+++ b/packages/googlesheets/ast.json
@@ -3,11 +3,13 @@
{
"name": "appendValues",
"params": [
- "params",
- "callback"
+ "spreadsheetId",
+ "range",
+ "values",
+ "options"
],
"docs": {
- "description": "Add an array of rows to the spreadsheet.\nhttps://developers.google.com/sheets/api/samples/writing#append_values",
+ "description": "Append one or more rows to a spreadsheet range.\nhttps://developers.google.com/sheets/api/samples/writing#append_values",
"tags": [
{
"title": "public",
@@ -16,7 +18,7 @@
},
{
"title": "example",
- "description": "appendValues({\n spreadsheetId: '1O-a4_RgPF_p8W3I6b5M9wobA3-CBW8hLClZfUik5sos',\n range: 'Sheet1!A1:E1',\n values: [\n ['From expression', '$15', '2', '3/15/2016'],\n ['Really now!', '$100', '1', '3/20/2016'],\n ],\n})"
+ "description": "appendValues(\n '1O-a4_RgPF_p8W3I6b5M9wobA3-CBW8hLClZfUik5sos',\n 'Sheet1!A1:E1',\n [['From expression', '$15', '2', '3/15/2016'], ['Really now!', '$100', '1', '3/20/2016']]\n)"
},
{
"title": "function",
@@ -25,57 +27,54 @@
},
{
"title": "param",
- "description": "Data object to add to the spreadsheet.",
+ "description": "The spreadsheet ID.",
"type": {
"type": "NameExpression",
- "name": "Object"
+ "name": "string"
},
- "name": "params"
+ "name": "spreadsheetId"
},
{
"title": "param",
- "description": "The spreadsheet ID.",
+ "description": "The sheet range.",
"type": {
- "type": "OptionalType",
- "expression": {
- "type": "NameExpression",
- "name": "string"
- }
+ "type": "NameExpression",
+ "name": "string"
},
- "name": "params.spreadsheetId"
+ "name": "range"
},
{
"title": "param",
- "description": "The range of values to update.",
+ "description": "The values to append.",
"type": {
- "type": "OptionalType",
- "expression": {
- "type": "NameExpression",
- "name": "string"
- }
+ "type": "NameExpression",
+ "name": "array"
},
- "name": "params.range"
+ "name": "values"
},
{
"title": "param",
- "description": "A 2d array of values to update.",
+ "description": "Optional settings.",
"type": {
"type": "OptionalType",
"expression": {
"type": "NameExpression",
- "name": "array"
+ "name": "Object"
}
},
- "name": "params.values"
+ "name": "options"
},
{
"title": "param",
- "description": "(Optional) Callback function",
+ "description": "Defaults to 'USER_ENTERED'.",
"type": {
- "type": "NameExpression",
- "name": "function"
+ "type": "OptionalType",
+ "expression": {
+ "type": "NameExpression",
+ "name": "string"
+ }
},
- "name": "callback"
+ "name": "options.valueInputOption"
},
{
"title": "returns",
@@ -92,15 +91,17 @@
{
"name": "batchUpdateValues",
"params": [
- "params",
- "callback"
+ "spreadsheetId",
+ "data",
+ "options"
],
"docs": {
"description": "Batch update values in a Spreadsheet.",
"tags": [
{
"title": "example",
- "description": "batchUpdateValues({\n spreadsheetId: '1O-a4_RgPF_p8W3I6b5M9wobA3-CBW8hLClZfUik5sos',\n range: 'Sheet1!A1:E1',\n values: [\n ['From expression', '$15', '2', '3/15/2016'],\n ['Really now!', '$100', '1', '3/20/2016'],\n ],\n})"
+ "description": "batchUpdateValues(\n '1O-a4_RgPF_p8W3I6b5M9wobA3-CBW8hLClZfUik5sos',\n [\n { range: 'Sheet1!A1', values: [['value1']] },\n { range: 'Sheet1!B5', values: [['value2']] },\n { range: 'Sheet1!D10:E11', values: [['a', 'b'], ['c', 'd']] },\n ],\n { valueInputOption: 'RAW' }\n)",
+ "caption": "Update multiple separate ranges"
},
{
"title": "function",
@@ -114,40 +115,63 @@
},
{
"title": "param",
- "description": "Data object to add to the spreadsheet.",
+ "description": "The spreadsheet ID.",
"type": {
"type": "NameExpression",
- "name": "Object"
+ "name": "string"
},
- "name": "params"
+ "name": "spreadsheetId"
},
{
"title": "param",
- "description": "The spreadsheet ID.",
+ "description": "Array of range/values objects to update.",
"type": {
- "type": "OptionalType",
+ "type": "TypeApplication",
"expression": {
"type": "NameExpression",
- "name": "string"
- }
- },
- "name": "params.spreadsheetId"
- },
- {
- "title": "param",
- "description": "The range of values to update.",
+ "name": "Array"
+ },
+ "applications": [
+ {
+ "type": "RecordType",
+ "fields": [
+ {
+ "type": "FieldType",
+ "key": "range",
+ "value": {
+ "type": "NameExpression",
+ "name": "string"
+ }
+ },
+ {
+ "type": "FieldType",
+ "key": "values",
+ "value": {
+ "type": "NameExpression",
+ "name": "array"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "name": "data"
+ },
+ {
+ "title": "param",
+ "description": "Optional settings.",
"type": {
"type": "OptionalType",
"expression": {
"type": "NameExpression",
- "name": "string"
+ "name": "Object"
}
},
- "name": "params.range"
+ "name": "options"
},
{
"title": "param",
- "description": "(Optional) Value update options. Defaults to 'USER_ENTERED'",
+ "description": "Defaults to 'USER_ENTERED'.",
"type": {
"type": "OptionalType",
"expression": {
@@ -155,28 +179,7 @@
"name": "string"
}
},
- "name": "params.valueInputOption"
- },
- {
- "title": "param",
- "description": "A 2d array of values to update.",
- "type": {
- "type": "OptionalType",
- "expression": {
- "type": "NameExpression",
- "name": "array"
- }
- },
- "name": "params.values"
- },
- {
- "title": "param",
- "description": "(Optional) callback function",
- "type": {
- "type": "NameExpression",
- "name": "function"
- },
- "name": "callback"
+ "name": "options.valueInputOption"
},
{
"title": "returns",
@@ -194,8 +197,7 @@
"name": "getValues",
"params": [
"spreadsheetId",
- "range",
- "callback"
+ "range"
],
"docs": {
"description": "Gets cell values from a Spreadsheet.",
@@ -232,15 +234,6 @@
},
"name": "range"
},
- {
- "title": "param",
- "description": "(Optional) callback function",
- "type": {
- "type": "NameExpression",
- "name": "function"
- },
- "name": "callback"
- },
{
"title": "returns",
"description": "spreadsheet information",
diff --git a/packages/googlesheets/package.json b/packages/googlesheets/package.json
index 175b546e54..8d157d0b26 100644
--- a/packages/googlesheets/package.json
+++ b/packages/googlesheets/package.json
@@ -41,7 +41,8 @@
"chai": "4.3.6",
"deep-eql": "4.1.1",
"nock": "13.2.9",
- "rimraf": "3.0.2"
+ "rimraf": "3.0.2",
+ "sinon": "^21.1.2"
},
"type": "module",
"types": "types/index.d.ts",
diff --git a/packages/googlesheets/src/Adaptor.js b/packages/googlesheets/src/Adaptor.js
index 9a17e0cb4f..1e4d70d304 100644
--- a/packages/googlesheets/src/Adaptor.js
+++ b/packages/googlesheets/src/Adaptor.js
@@ -64,7 +64,7 @@ export function execute(...operations) {
return commonExecute(
createConnection,
...operations,
- removeConnection
+ removeConnection,
)({
...initialState,
...state,
@@ -74,32 +74,34 @@ export function execute(...operations) {
}
/**
- * Add an array of rows to the spreadsheet.
+ * Append one or more rows to a spreadsheet range.
* https://developers.google.com/sheets/api/samples/writing#append_values
* @public
* @example
- * appendValues({
- * spreadsheetId: '1O-a4_RgPF_p8W3I6b5M9wobA3-CBW8hLClZfUik5sos',
- * range: 'Sheet1!A1:E1',
- * values: [
- * ['From expression', '$15', '2', '3/15/2016'],
- * ['Really now!', '$100', '1', '3/20/2016'],
- * ],
- * })
+ * appendValues(
+ * '1O-a4_RgPF_p8W3I6b5M9wobA3-CBW8hLClZfUik5sos',
+ * 'Sheet1!A1:E1',
+ * [['From expression', '$15', '2', '3/15/2016'], ['Really now!', '$100', '1', '3/20/2016']]
+ * )
* @function
- * @param {Object} params - Data object to add to the spreadsheet.
- * @param {string} [params.spreadsheetId] The spreadsheet ID.
- * @param {string} [params.range] The range of values to update.
- * @param {array} [params.values] A 2d array of values to update.
- * @param {function} callback - (Optional) Callback function
+ * @param {string} spreadsheetId - The spreadsheet ID.
+ * @param {string} range - The sheet range.
+ * @param {array} values - The values to append.
+ * @param {Object} [options] - Optional settings.
+ * @param {string} [options.valueInputOption] - Defaults to 'USER_ENTERED'.
* @returns {Operation}
*/
-export function appendValues(params, callback = s => s) {
+export function appendValues(spreadsheetId, range, values, options = {}) {
return state => {
- const [resolvedParams] = expandReferences(state, params);
- const { spreadsheetId, range, values } = resolvedParams;
-
- if (!values || values.length === 0) {
+ const [
+ resolvedSpreadsheetId,
+ resolvedRange,
+ resolvedValues,
+ resolvedOptions,
+ ] = expandReferences(state, spreadsheetId, range, values, options);
+ const { valueInputOption = 'USER_ENTERED' } = resolvedOptions;
+
+ if (!resolvedValues || resolvedValues.length === 0) {
console.log('Warning: empty values array');
return state;
}
@@ -107,13 +109,13 @@ export function appendValues(params, callback = s => s) {
return new Promise((resolve, reject) => {
client.spreadsheets.values.append(
{
- spreadsheetId,
- range,
- valueInputOption: 'USER_ENTERED',
+ spreadsheetId: resolvedSpreadsheetId,
+ range: resolvedRange,
+ valueInputOption,
resource: {
- range,
+ range: resolvedRange,
majorDimension: 'ROWS',
- values: values,
+ values: resolvedValues,
},
},
function (err, response) {
@@ -123,14 +125,12 @@ export function appendValues(params, callback = s => s) {
} else {
console.log('Success! Here is the response from Google:');
console.log(response.data);
- resolve(
- callback({
- ...composeNextState(state, response.data),
- response,
- })
- );
+ resolve({
+ ...composeNextState(state, response.data),
+ response,
+ });
}
- }
+ },
);
});
};
@@ -139,56 +139,46 @@ export function appendValues(params, callback = s => s) {
/**
* Batch update values in a Spreadsheet.
* @example
- * batchUpdateValues({
- * spreadsheetId: '1O-a4_RgPF_p8W3I6b5M9wobA3-CBW8hLClZfUik5sos',
- * range: 'Sheet1!A1:E1',
- * values: [
- * ['From expression', '$15', '2', '3/15/2016'],
- * ['Really now!', '$100', '1', '3/20/2016'],
+ *
Update multiple separate ranges
+ * batchUpdateValues(
+ * '1O-a4_RgPF_p8W3I6b5M9wobA3-CBW8hLClZfUik5sos',
+ * [
+ * { range: 'Sheet1!A1', values: [['value1']] },
+ * { range: 'Sheet1!B5', values: [['value2']] },
+ * { range: 'Sheet1!D10:E11', values: [['a', 'b'], ['c', 'd']] },
* ],
- * })
+ * { valueInputOption: 'RAW' }
+ * )
* @function
* @public
- * @param {Object} params - Data object to add to the spreadsheet.
- * @param {string} [params.spreadsheetId] The spreadsheet ID.
- * @param {string} [params.range] The range of values to update.
- * @param {string} [params.valueInputOption] (Optional) Value update options. Defaults to 'USER_ENTERED'
- * @param {array} [params.values] A 2d array of values to update.
- * @param {function} callback - (Optional) callback function
+ * @param {string} spreadsheetId - The spreadsheet ID.
+ * @param {Array<{range: string, values: array}>} data - Array of range/values objects to update.
+ * @param {Object} [options] - Optional settings.
+ * @param {string} [options.valueInputOption] - Defaults to 'USER_ENTERED'.
* @returns {Operation} spreadsheet information
*/
-export function batchUpdateValues(params, callback = s => s) {
+export function batchUpdateValues(spreadsheetId, data, options = {}) {
return async state => {
- const [resolvedParams] = expandReferences(state, params);
-
- const {
- spreadsheetId,
- range,
- valueInputOption = 'USER_ENTERED',
- values,
- } = resolvedParams;
+ const [resolvedSpreadsheetId, resolvedData, resolvedOptions] =
+ expandReferences(state, spreadsheetId, data, options);
+ const { valueInputOption = 'USER_ENTERED' } = resolvedOptions;
- if (!values || values.length === 0) {
- console.log('Warning: empty values array');
+ if (!resolvedData || resolvedData.length === 0) {
+ console.log('Warning: empty data array');
return state;
}
const resource = {
- data: [
- {
- range,
- values,
- },
- ],
+ data: resolvedData,
valueInputOption,
};
try {
const response = await client.spreadsheets.values.batchUpdate({
- spreadsheetId,
+ spreadsheetId: resolvedSpreadsheetId,
resource,
});
console.log('%d cells updated.', response.data.totalUpdatedCells);
- return callback({ ...composeNextState(state, response.data), response });
+ return { ...composeNextState(state, response.data), response };
} catch (err) {
logError(err);
throw err;
@@ -204,15 +194,14 @@ export function batchUpdateValues(params, callback = s => s) {
* @function
* @param {string} spreadsheetId The spreadsheet ID.
* @param {string} range The sheet range.
- * @param {function} callback - (Optional) callback function
* @returns {Operation} spreadsheet information
*/
-export function getValues(spreadsheetId, range, callback = s => s) {
+export function getValues(spreadsheetId, range) {
return async state => {
const [resolvedSheetId, resolvedRange] = expandReferences(
state,
spreadsheetId,
- range
+ range,
);
try {
@@ -225,7 +214,7 @@ export function getValues(spreadsheetId, range, callback = s => s) {
const nextState = { ...composeNextState(state, response.data), response };
- return callback(nextState);
+ return nextState;
} catch (err) {
logError(err);
throw err;
diff --git a/packages/googlesheets/test/index.js b/packages/googlesheets/test/index.js
index 18a84935a7..de377fd9cc 100644
--- a/packages/googlesheets/test/index.js
+++ b/packages/googlesheets/test/index.js
@@ -1,70 +1,140 @@
import { expect } from 'chai';
+import sinon from 'sinon';
+import { google } from 'googleapis';
-import { execute ,appendValues, batchUpdateValues } from '../src/index.js';
+import { execute, appendValues, batchUpdateValues, getValues } from '../src/index.js';
+describe('appendValues', () => {
+ let sandbox;
+ let mockAppend;
-describe('execute', () => {
- it('executes each operation in sequence', done => {
- const state = { configuration: {}, data: {} };
- let operations = [
- state => {
- return { counter: 1 };
- },
- state => {
- return { counter: 2 };
+ beforeEach(() => {
+ sandbox = sinon.createSandbox();
+
+ mockAppend = sandbox.stub().callsArgWith(1, null, {
+ data: { updates: { updatedCells: 4 } },
+ });
+
+ sandbox.stub(google, 'sheets').returns({
+ spreadsheets: {
+ values: { append: mockAppend },
},
- state => {
- return { counter: 3 };
+ });
+ });
+
+ afterEach(() => {
+ sandbox.restore();
+ });
+
+ it('appends rows to the given range', async () => {
+ const state = { configuration: { access_token: 'mock-token' }, data: {} };
+
+ const result = await execute(
+ appendValues('123-456-789', 'Sheet1!A1:B1', [['a', 'b'], ['c', 'd']])
+ )(state);
+
+ expect(mockAppend.calledOnce).to.be.true;
+ const callArgs = mockAppend.firstCall.args[0];
+ expect(callArgs.spreadsheetId).to.equal('123-456-789');
+ expect(callArgs.range).to.equal('Sheet1!A1:B1');
+ expect(callArgs.resource.values).to.deep.equal([['a', 'b'], ['c', 'd']]);
+ expect(result.data).to.deep.equal({ updates: { updatedCells: 4 } });
+ });
+});
+
+describe('batchUpdateValues', () => {
+ let sandbox;
+ let mockBatchUpdate;
+
+ beforeEach(() => {
+ sandbox = sinon.createSandbox();
+
+ mockBatchUpdate = sandbox.stub().resolves({
+ data: { totalUpdatedCells: 3 },
+ });
+
+ sandbox.stub(google, 'sheets').returns({
+ spreadsheets: {
+ values: { batchUpdate: mockBatchUpdate },
},
+ });
+ });
+
+ afterEach(() => {
+ sandbox.restore();
+ });
+
+ it('sends multi-range data to the API', async () => {
+ const state = { configuration: { access_token: 'mock-token' }, data: {} };
+ const multiRangeData = [
+ { range: 'Sheet1!A1', values: [['value1']] },
+ { range: 'Sheet1!B5', values: [['value2']] },
+ { range: 'Sheet1!D10:E11', values: [['a', 'b'], ['c', 'd']] },
];
- execute(...operations)(state)
- .then(finalState => {
- expect(finalState).to.eql({ counter: 3 });
- })
- .then(done)
- .catch(done);
+ await execute(
+ batchUpdateValues('123-456-789', multiRangeData, { valueInputOption: 'RAW' })
+ )(state);
+
+ expect(mockBatchUpdate.calledOnce).to.be.true;
+ const { resource } = mockBatchUpdate.firstCall.args[0];
+ expect(resource.data).to.deep.equal(multiRangeData);
+ expect(resource.valueInputOption).to.equal('RAW');
});
- it('assigns references, data to the initialState', () => {
- const state = { configuration: {}, data: {} };
+ it('sends a single range entry to the API', async () => {
+ const state = { configuration: { access_token: 'mock-token' }, data: {} };
- execute()(state).then(finalState => {
- expect(finalState).to.eql({
- references: [],
- data: null,
- });
- });
+ await execute(
+ batchUpdateValues(
+ '123-456-789',
+ [{ range: 'Sheet1!A1:B2', values: [['a', 'b'], ['c', 'd']] }],
+ { valueInputOption: 'USER_ENTERED' }
+ )
+ )(state);
+
+ expect(mockBatchUpdate.calledOnce).to.be.true;
+ const { resource } = mockBatchUpdate.firstCall.args[0];
+ expect(resource.data).to.deep.equal([
+ { range: 'Sheet1!A1:B2', values: [['a', 'b'], ['c', 'd']] },
+ ]);
+ expect(resource.valueInputOption).to.equal('USER_ENTERED');
});
});
+describe('getValues', () => {
+ let sandbox;
+ let mockGet;
-describe('append', () =>{
- it('should return early if the values array is undefined or nullish', async() => {
- const state = {
- data: [],
- }
+ beforeEach(() => {
+ sandbox = sinon.createSandbox();
- const result = await appendValues({
- spreadsheetId: '123-456-789',
- range: 'Sheet!A1:E1',
- values: state.values,
- })(state);
- expect(result).to.eql(state);
+ mockGet = sandbox.stub().resolves({
+ data: { values: [['a', 'b'], ['c', 'd']] },
+ });
+
+ sandbox.stub(google, 'sheets').returns({
+ spreadsheets: {
+ values: { get: mockGet },
+ },
+ });
});
-});
-describe('batchUpdateValues', () =>{
- it('should return early if the values array is undefined or nullish', async() => {
- const state = {
- data: [],
- }
-
- const result = await batchUpdateValues({
- spreadsheetId: '123-456-789',
- range: 'Sheet!A1:E1',
- values: state.values,
- })(state);
- expect(result).to.eql(state);
+ afterEach(() => {
+ sandbox.restore();
+ });
+
+ it('returns state with the values from the API', async () => {
+ const state = { configuration: { access_token: 'mock-token' }, data: {} };
+
+ const result = await execute(
+ getValues('123-456-789', 'Sheet1!A1:B2')
+ )(state);
+
+ expect(mockGet.calledOnce).to.be.true;
+ const callArgs = mockGet.firstCall.args[0];
+ expect(callArgs.spreadsheetId).to.equal('123-456-789');
+ expect(callArgs.range).to.equal('Sheet1!A1:B2');
+ expect(result.data).to.deep.equal({ values: [['a', 'b'], ['c', 'd']] });
});
});
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 519efacada..1ed33ca19e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1127,6 +1127,9 @@ importers:
rimraf:
specifier: 3.0.2
version: 3.0.2
+ sinon:
+ specifier: ^21.1.2
+ version: 21.1.2
packages/hive:
dependencies:
@@ -5228,12 +5231,18 @@ packages:
'@sinonjs/fake-timers@15.1.0':
resolution: {integrity: sha512-cqfapCxwTGsrR80FEgOoPsTonoefMBY7dnUEbQ+GRcved0jvkJLzvX6F4WtN+HBqbPX/SiFsIRUp+IrCW/2I2w==}
+ '@sinonjs/fake-timers@15.3.2':
+ resolution: {integrity: sha512-mrn35Jl2pCpns+mE3HaZa1yPN5EYCRgiMI+135COjr2hr8Cls9DXqIZ57vZe2cz7y2XVSq92tcs6kGQcT1J8Rw==}
+
'@sinonjs/fake-timers@6.0.1':
resolution: {integrity: sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==}
'@sinonjs/fake-timers@9.1.2':
resolution: {integrity: sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==}
+ '@sinonjs/samsam@10.0.2':
+ resolution: {integrity: sha512-8lVwD1Df1BmzoaOLhMcGGcz/Jyr5QY2KSB75/YK1QgKzoabTeLdIVyhXNZK9ojfSKSdirbXqdbsXXqP9/Ve8+A==}
+
'@sinonjs/samsam@5.3.1':
resolution: {integrity: sha512-1Hc0b1TtyfBu8ixF/tpfSHTVWKwCBLY4QJbkgnE7HcwyvT2xArDxb4K7dMgqRm3szI+LJbzmW/s4xxEhv6hwDg==}
@@ -7319,6 +7328,10 @@ packages:
resolution: {integrity: sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==}
engines: {node: '>=0.3.1'}
+ diff@8.0.4:
+ resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==}
+ engines: {node: '>=0.3.1'}
+
dir-glob@3.0.1:
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
engines: {node: '>=8'}
@@ -10901,6 +10914,9 @@ packages:
sinon@21.0.1:
resolution: {integrity: sha512-Z0NVCW45W8Mg5oC/27/+fCqIHFnW8kpkFOq0j9XJIev4Ld0mKmERaZv5DMLAb9fGCevjKwaEeIQz5+MBXfZcDw==}
+ sinon@21.1.2:
+ resolution: {integrity: sha512-FS6mN+/bx7e2ajpXkEmOcWB6xBzWiuNoAQT18/+a20SS4U7FSYl8Ms7N6VTUxN/1JAjkx7aXp+THMC8xdpp0gA==}
+
sinon@9.2.3:
resolution: {integrity: sha512-m+DyAWvqVHZtjnjX/nuShasykFeiZ+nPuEfD4G3gpvKGkXRhkF/6NSt2qN2FjZhfrcHXFzUzI+NLnk+42fnLEw==}
deprecated: 16.1.1
@@ -14456,6 +14472,10 @@ snapshots:
dependencies:
'@sinonjs/commons': 3.0.1
+ '@sinonjs/fake-timers@15.3.2':
+ dependencies:
+ '@sinonjs/commons': 3.0.1
+
'@sinonjs/fake-timers@6.0.1':
dependencies:
'@sinonjs/commons': 1.8.6
@@ -14464,6 +14484,11 @@ snapshots:
dependencies:
'@sinonjs/commons': 1.8.6
+ '@sinonjs/samsam@10.0.2':
+ dependencies:
+ '@sinonjs/commons': 3.0.1
+ type-detect: 4.1.0
+
'@sinonjs/samsam@5.3.1':
dependencies:
'@sinonjs/commons': 1.8.6
@@ -17161,6 +17186,8 @@ snapshots:
diff@8.0.3: {}
+ diff@8.0.4: {}
+
dir-glob@3.0.1:
dependencies:
path-type: 4.0.0
@@ -21287,6 +21314,13 @@ snapshots:
diff: 8.0.3
supports-color: 7.2.0
+ sinon@21.1.2:
+ dependencies:
+ '@sinonjs/commons': 3.0.1
+ '@sinonjs/fake-timers': 15.3.2
+ '@sinonjs/samsam': 10.0.2
+ diff: 8.0.4
+
sinon@9.2.3:
dependencies:
'@sinonjs/commons': 1.8.6