google-sheets-mapper 2.0.0 → 2.1.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.
package/README.md CHANGED
@@ -8,16 +8,16 @@
8
8
 
9
9
  ## Installation
10
10
 
11
- Package can be added using **yarn**:
12
-
13
11
  ```bash
14
- yarn add google-sheets-mapper
12
+ npm install google-sheets-mapper
15
13
  ```
16
14
 
17
- Or, use **NPM**:
15
+ ```bash
16
+ pnpm add google-sheets-mapper
17
+ ```
18
18
 
19
19
  ```bash
20
- npm install google-sheets-mapper
20
+ bun add google-sheets-mapper
21
21
  ```
22
22
 
23
23
  UMD build available on [unpkg](https://www.unpkg.com/browse/google-sheets-mapper@1.0.0/dist/google-sheets-mapper.cjs.production.min.js).
@@ -44,7 +44,7 @@ https://docs.google.com/spreadsheets/d/[THIS-IS-THE-SHEET-ID]/
44
44
  ### Get data from all sheets inside the spreadsheet
45
45
 
46
46
  ```js
47
- import { fetchGoogleSheetsData } from 'google-sheets-mapper';
47
+ import { fetchGoogleSheetsData } from "google-sheets-mapper";
48
48
 
49
49
  const getData = async () => {
50
50
  try {
@@ -63,14 +63,14 @@ const getData = async () => {
63
63
  Don't use single quotes on sheet names, they will be removed because when using space in sheet name it will be returned wrapped with single quotes and plugin will remove them for clean string id.
64
64
 
65
65
  ```js
66
- import { fetchGoogleSheetsData } from 'google-sheets-mapper';
66
+ import { fetchGoogleSheetsData } from "google-sheets-mapper";
67
67
 
68
68
  const getData = async () => {
69
69
  try {
70
70
  return await fetchGoogleSheetsData({
71
71
  apiKey: process.env.REACT_APP_GOOGLE_API_KEY,
72
72
  sheetId: process.env.REACT_APP_GOOGLE_SHEETS_ID,
73
- sheetsOptions: [{ id: 'Sheet1' }],
73
+ sheetsOptions: [{ id: "Sheet1" }],
74
74
  });
75
75
  } catch (error) {
76
76
  console.error(error);
@@ -119,10 +119,10 @@ try {
119
119
  ```js
120
120
  [
121
121
  {
122
- id: 'Sheet1',
122
+ id: "Sheet1",
123
123
  data: [
124
- { value: 'et', key: 'language' },
125
- { value: 'Test sheet', key: 'title' },
124
+ { value: "et", key: "language" },
125
+ { value: "Test sheet", key: "title" },
126
126
  ],
127
127
  },
128
128
  ];
package/dist/index.cjs ADDED
@@ -0,0 +1,103 @@
1
+ Object.defineProperty(exports, '__esModule', { value: true });
2
+
3
+ const GOOGLE_API_URL = "https://sheets.googleapis.com/v4/spreadsheets";
4
+ const getRanges = (sheetNames = [])=>{
5
+ // ranges=Sheet1&ranges=Sheet2
6
+ return sheetNames.map((sheetName)=>`ranges=${sheetName}`).join("&");
7
+ };
8
+ const getSheetsTitleUrl = (sheetId, apiKey)=>{
9
+ return `${GOOGLE_API_URL}/${sheetId}?fields=sheets%2Fproperties%2Ftitle&key=${apiKey}`;
10
+ };
11
+ const getBatchUrl = (sheetId, ranges, apiKey)=>{
12
+ const rangesQueryString = getRanges(ranges);
13
+ return `${GOOGLE_API_URL}/${sheetId}?${rangesQueryString}&key=${apiKey}&includeGridData=true`;
14
+ };
15
+ class ApiResponseError extends Error {
16
+ constructor(message, response){
17
+ super(message);
18
+ Object.setPrototypeOf(this, ApiResponseError.prototype);
19
+ this.response = response;
20
+ if (Error.captureStackTrace) {
21
+ Error.captureStackTrace(this, ApiResponseError);
22
+ }
23
+ }
24
+ }
25
+ const makeFetch = async (url, config = {})=>{
26
+ const response = await fetch(url, config);
27
+ if (!response.ok) {
28
+ throw new ApiResponseError(`Request to '${url}' failed with ${response.status}${response.statusText ? `: ${response.statusText}` : ""}`, {
29
+ status: response.status,
30
+ statusText: response.statusText,
31
+ url: response.url
32
+ });
33
+ }
34
+ return await response.json();
35
+ };
36
+ const mapRecords = (records, headerData)=>{
37
+ return records.filter((record)=>record.length > 0).map((record)=>record.reduce((obj, item, index)=>{
38
+ const key = headerData[index];
39
+ if (key !== undefined) {
40
+ obj[key] = item;
41
+ }
42
+ return obj;
43
+ }, {}));
44
+ };
45
+ const mapData = ({ sheets, sheetsOptions = [] })=>{
46
+ return sheets.map((sheet)=>{
47
+ const id = sheet.range.split("!")[0].replace(/'/g, "");
48
+ const rows = sheet.values || [];
49
+ if (rows.length > 0) {
50
+ const sheetsOptionsSheet = sheetsOptions.find((option)=>option.id === id);
51
+ const headerRowIndex = sheetsOptionsSheet?.headerRowIndex ?? 0;
52
+ const header = rows[headerRowIndex];
53
+ const records = rows.filter((_, index)=>index > headerRowIndex);
54
+ const recordsData = mapRecords(records, header);
55
+ return {
56
+ id,
57
+ data: recordsData
58
+ };
59
+ }
60
+ return {
61
+ id,
62
+ data: []
63
+ };
64
+ });
65
+ };
66
+ const fetchBatchData = async ({ apiKey, sheetId, sheetsOptions = [] })=>{
67
+ const sheetsNames = sheetsOptions.map((option)=>option.id);
68
+ const url = getBatchUrl(sheetId, sheetsNames, apiKey);
69
+ return await makeFetch(url);
70
+ };
71
+ const fetchAllSheetsData = async ({ apiKey, sheetId })=>{
72
+ const urlTitles = getSheetsTitleUrl(sheetId, apiKey);
73
+ const { sheets } = await makeFetch(urlTitles);
74
+ const sheetsOptions = sheets.map((sheet)=>({
75
+ id: sheet.properties.title
76
+ }));
77
+ return await fetchBatchData({
78
+ apiKey,
79
+ sheetId,
80
+ sheetsOptions
81
+ });
82
+ };
83
+
84
+ const GoogleSheetsMapper = {
85
+ async fetchGoogleSheetsData ({ apiKey, sheetId, sheetsOptions = [] }) {
86
+ const response = sheetsOptions.length === 0 ? await fetchAllSheetsData({
87
+ apiKey,
88
+ sheetId
89
+ }) : await fetchBatchData({
90
+ apiKey,
91
+ sheetId,
92
+ sheetsOptions
93
+ });
94
+ return mapData({
95
+ sheets: response.valueRanges,
96
+ sheetsOptions
97
+ });
98
+ }
99
+ };
100
+ const fetchGoogleSheetsData = GoogleSheetsMapper.fetchGoogleSheetsData;
101
+
102
+ exports.default = GoogleSheetsMapper;
103
+ exports.fetchGoogleSheetsData = fetchGoogleSheetsData;
@@ -0,0 +1,22 @@
1
+ interface SheetsOption {
2
+ id: string;
3
+ headerRowIndex?: number;
4
+ }
5
+ interface MapperOptions {
6
+ apiKey: string;
7
+ sheetId: string;
8
+ sheetsOptions?: SheetsOption[];
9
+ }
10
+ interface MapperState {
11
+ id: string;
12
+ data: Record<string, string>[];
13
+ }
14
+
15
+ declare const GoogleSheetsMapper: {
16
+ fetchGoogleSheetsData({ apiKey, sheetId, sheetsOptions, }: MapperOptions): Promise<MapperState[]>;
17
+ };
18
+
19
+ declare const fetchGoogleSheetsData: ({ apiKey, sheetId, sheetsOptions, }: MapperOptions) => Promise<MapperState[]>;
20
+
21
+ export { GoogleSheetsMapper as default, fetchGoogleSheetsData };
22
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","sources":["../src/types.ts","../src/index.ts"],"sourcesContent":["export interface SheetsOption {\n id: string;\n headerRowIndex?: number;\n}\n\nexport interface MapperOptions {\n apiKey: string;\n sheetId: string;\n sheetsOptions?: SheetsOption[];\n}\n\nexport interface ValueRange {\n majorDimensions: string;\n range: string;\n values: string[][];\n}\n\nexport interface ValueRangesResponse {\n spreadsheetId: string;\n valueRanges: ValueRange[];\n}\n\nexport interface PropertiesFromResponse {\n title: string;\n}\n\nexport interface SheetFromResponse {\n properties: PropertiesFromResponse;\n}\n\nexport interface SheetsResponse {\n sheets: SheetFromResponse[];\n}\n\nexport interface MapperState {\n id: string;\n data: Record<string, string>[];\n}\n\nexport interface ApiResponse {\n url: string;\n status: number;\n statusText: string;\n}\n\nexport interface ErrorResponse {\n response: ApiResponse;\n}\n","import type { MapperOptions, MapperState, ValueRangesResponse } from \"./types\";\nimport { fetchBatchData, fetchAllSheetsData, mapData } from \"./utils\";\n\nconst GoogleSheetsMapper = {\n async fetchGoogleSheetsData({\n apiKey,\n sheetId,\n sheetsOptions = [],\n }: MapperOptions): Promise<MapperState[]> {\n const response: ValueRangesResponse =\n sheetsOptions.length === 0\n ? await fetchAllSheetsData({ apiKey, sheetId })\n : await fetchBatchData({ apiKey, sheetId, sheetsOptions });\n return mapData({ sheets: response.valueRanges, sheetsOptions });\n },\n};\n\nexport default GoogleSheetsMapper;\nexport const fetchGoogleSheetsData = GoogleSheetsMapper.fetchGoogleSheetsData;\n"],"names":[],"mappings":"AAAO,UAAA,YAAA;AACP;AACA;AACA;AACO,UAAA,aAAA;AACP;AACA;AACA,oBAAA,YAAA;AACA;AAmBO,UAAA,WAAA;AACP;AACA,UAAA,MAAA;AACA;;AC7BA,cAAA,kBAAA;AACA,+DAAA,aAAA,GAAA,OAAA,CAAA,WAAA;AACA;;AAEO,cAAA,qBAAA,wCAAA,aAAA,KAAA,OAAA,CAAA,WAAA;;;;"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,22 @@
1
- import { MapperOptions, MapperState } from './types';
2
- declare const GoogleSheetsMapper: {
3
- fetchGoogleSheetsData({ apiKey, sheetId, sheetsOptions, }: MapperOptions): Promise<MapperState[]>;
4
- };
5
- export default GoogleSheetsMapper;
6
- export declare const fetchGoogleSheetsData: ({ apiKey, sheetId, sheetsOptions, }: MapperOptions) => Promise<MapperState[]>;
1
+ interface SheetsOption {
2
+ id: string;
3
+ headerRowIndex?: number;
4
+ }
5
+ interface MapperOptions {
6
+ apiKey: string;
7
+ sheetId: string;
8
+ sheetsOptions?: SheetsOption[];
9
+ }
10
+ interface MapperState {
11
+ id: string;
12
+ data: Record<string, string>[];
13
+ }
14
+
15
+ declare const GoogleSheetsMapper: {
16
+ fetchGoogleSheetsData({ apiKey, sheetId, sheetsOptions, }: MapperOptions): Promise<MapperState[]>;
17
+ };
18
+
19
+ declare const fetchGoogleSheetsData: ({ apiKey, sheetId, sheetsOptions, }: MapperOptions) => Promise<MapperState[]>;
20
+
21
+ export { GoogleSheetsMapper as default, fetchGoogleSheetsData };
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sources":["../src/types.ts","../src/index.ts"],"sourcesContent":["export interface SheetsOption {\n id: string;\n headerRowIndex?: number;\n}\n\nexport interface MapperOptions {\n apiKey: string;\n sheetId: string;\n sheetsOptions?: SheetsOption[];\n}\n\nexport interface ValueRange {\n majorDimensions: string;\n range: string;\n values: string[][];\n}\n\nexport interface ValueRangesResponse {\n spreadsheetId: string;\n valueRanges: ValueRange[];\n}\n\nexport interface PropertiesFromResponse {\n title: string;\n}\n\nexport interface SheetFromResponse {\n properties: PropertiesFromResponse;\n}\n\nexport interface SheetsResponse {\n sheets: SheetFromResponse[];\n}\n\nexport interface MapperState {\n id: string;\n data: Record<string, string>[];\n}\n\nexport interface ApiResponse {\n url: string;\n status: number;\n statusText: string;\n}\n\nexport interface ErrorResponse {\n response: ApiResponse;\n}\n","import type { MapperOptions, MapperState, ValueRangesResponse } from \"./types\";\nimport { fetchBatchData, fetchAllSheetsData, mapData } from \"./utils\";\n\nconst GoogleSheetsMapper = {\n async fetchGoogleSheetsData({\n apiKey,\n sheetId,\n sheetsOptions = [],\n }: MapperOptions): Promise<MapperState[]> {\n const response: ValueRangesResponse =\n sheetsOptions.length === 0\n ? await fetchAllSheetsData({ apiKey, sheetId })\n : await fetchBatchData({ apiKey, sheetId, sheetsOptions });\n return mapData({ sheets: response.valueRanges, sheetsOptions });\n },\n};\n\nexport default GoogleSheetsMapper;\nexport const fetchGoogleSheetsData = GoogleSheetsMapper.fetchGoogleSheetsData;\n"],"names":[],"mappings":"AAAO,UAAA,YAAA;AACP;AACA;AACA;AACO,UAAA,aAAA;AACP;AACA;AACA,oBAAA,YAAA;AACA;AAmBO,UAAA,WAAA;AACP;AACA,UAAA,MAAA;AACA;;AC7BA,cAAA,kBAAA;AACA,+DAAA,aAAA,GAAA,OAAA,CAAA,WAAA;AACA;;AAEO,cAAA,qBAAA,wCAAA,aAAA,KAAA,OAAA,CAAA,WAAA;;;;"}
package/dist/index.js CHANGED
@@ -1,8 +1,100 @@
1
+ const GOOGLE_API_URL = "https://sheets.googleapis.com/v4/spreadsheets";
2
+ const getRanges = (sheetNames = [])=>{
3
+ // ranges=Sheet1&ranges=Sheet2
4
+ return sheetNames.map((sheetName)=>`ranges=${sheetName}`).join("&");
5
+ };
6
+ const getSheetsTitleUrl = (sheetId, apiKey)=>{
7
+ return `${GOOGLE_API_URL}/${sheetId}?fields=sheets%2Fproperties%2Ftitle&key=${apiKey}`;
8
+ };
9
+ const getBatchUrl = (sheetId, ranges, apiKey)=>{
10
+ const rangesQueryString = getRanges(ranges);
11
+ return `${GOOGLE_API_URL}/${sheetId}?${rangesQueryString}&key=${apiKey}&includeGridData=true`;
12
+ };
13
+ class ApiResponseError extends Error {
14
+ constructor(message, response){
15
+ super(message);
16
+ Object.setPrototypeOf(this, ApiResponseError.prototype);
17
+ this.response = response;
18
+ if (Error.captureStackTrace) {
19
+ Error.captureStackTrace(this, ApiResponseError);
20
+ }
21
+ }
22
+ }
23
+ const makeFetch = async (url, config = {})=>{
24
+ const response = await fetch(url, config);
25
+ if (!response.ok) {
26
+ throw new ApiResponseError(`Request to '${url}' failed with ${response.status}${response.statusText ? `: ${response.statusText}` : ""}`, {
27
+ status: response.status,
28
+ statusText: response.statusText,
29
+ url: response.url
30
+ });
31
+ }
32
+ return await response.json();
33
+ };
34
+ const mapRecords = (records, headerData)=>{
35
+ return records.filter((record)=>record.length > 0).map((record)=>record.reduce((obj, item, index)=>{
36
+ const key = headerData[index];
37
+ if (key !== undefined) {
38
+ obj[key] = item;
39
+ }
40
+ return obj;
41
+ }, {}));
42
+ };
43
+ const mapData = ({ sheets, sheetsOptions = [] })=>{
44
+ return sheets.map((sheet)=>{
45
+ const id = sheet.range.split("!")[0].replace(/'/g, "");
46
+ const rows = sheet.values || [];
47
+ if (rows.length > 0) {
48
+ const sheetsOptionsSheet = sheetsOptions.find((option)=>option.id === id);
49
+ const headerRowIndex = sheetsOptionsSheet?.headerRowIndex ?? 0;
50
+ const header = rows[headerRowIndex];
51
+ const records = rows.filter((_, index)=>index > headerRowIndex);
52
+ const recordsData = mapRecords(records, header);
53
+ return {
54
+ id,
55
+ data: recordsData
56
+ };
57
+ }
58
+ return {
59
+ id,
60
+ data: []
61
+ };
62
+ });
63
+ };
64
+ const fetchBatchData = async ({ apiKey, sheetId, sheetsOptions = [] })=>{
65
+ const sheetsNames = sheetsOptions.map((option)=>option.id);
66
+ const url = getBatchUrl(sheetId, sheetsNames, apiKey);
67
+ return await makeFetch(url);
68
+ };
69
+ const fetchAllSheetsData = async ({ apiKey, sheetId })=>{
70
+ const urlTitles = getSheetsTitleUrl(sheetId, apiKey);
71
+ const { sheets } = await makeFetch(urlTitles);
72
+ const sheetsOptions = sheets.map((sheet)=>({
73
+ id: sheet.properties.title
74
+ }));
75
+ return await fetchBatchData({
76
+ apiKey,
77
+ sheetId,
78
+ sheetsOptions
79
+ });
80
+ };
1
81
 
2
- 'use strict'
82
+ const GoogleSheetsMapper = {
83
+ async fetchGoogleSheetsData ({ apiKey, sheetId, sheetsOptions = [] }) {
84
+ const response = sheetsOptions.length === 0 ? await fetchAllSheetsData({
85
+ apiKey,
86
+ sheetId
87
+ }) : await fetchBatchData({
88
+ apiKey,
89
+ sheetId,
90
+ sheetsOptions
91
+ });
92
+ return mapData({
93
+ sheets: response.valueRanges,
94
+ sheetsOptions
95
+ });
96
+ }
97
+ };
98
+ const fetchGoogleSheetsData = GoogleSheetsMapper.fetchGoogleSheetsData;
3
99
 
4
- if (process.env.NODE_ENV === 'production') {
5
- module.exports = require('./google-sheets-mapper.cjs.production.min.js')
6
- } else {
7
- module.exports = require('./google-sheets-mapper.cjs.development.js')
8
- }
100
+ export { GoogleSheetsMapper as default, fetchGoogleSheetsData };
package/package.json CHANGED
@@ -1,47 +1,62 @@
1
1
  {
2
2
  "name": "google-sheets-mapper",
3
+ "version": "2.1.0",
3
4
  "description": "### A library for getting data from Google Sheets API v4",
4
- "version": "2.0.0",
5
- "author": "Gert Glükmann <gglukmann@gmail.com>",
6
- "license": "MIT",
5
+ "keywords": [
6
+ "google-sheets",
7
+ "google-sheets-api",
8
+ "google-sheets-api-v4",
9
+ "google-sheets-mapper"
10
+ ],
11
+ "homepage": "https://github.com/gglukmann/use-google-sheets#readme",
7
12
  "bugs": {
8
13
  "url": "https://github.com/gglukmann/use-google-sheets/issues"
9
14
  },
10
- "homepage": "https://github.com/gglukmann/use-google-sheets#readme",
11
- "directories": {
12
- "test": "test"
13
- },
15
+ "license": "MIT",
16
+ "author": "Gert Glükmann <gglukmann@gmail.com>",
14
17
  "repository": {
15
18
  "type": "git",
16
19
  "url": "git+https://github.com/gglukmann/google-sheets-mapper.git"
17
20
  },
18
- "keywords": [
19
- "google-sheets-mapper",
20
- "google-sheets",
21
- "google-sheets-api",
22
- "google-sheets-api-v4"
23
- ],
24
- "main": "dist/index.js",
25
- "typings": "dist/index.d.ts",
26
21
  "files": [
27
22
  "dist",
28
23
  "src"
29
24
  ],
30
- "engines": {
31
- "node": ">=16"
25
+ "type": "module",
26
+ "main": "./dist/index.cjs",
27
+ "module": "./dist/index.js",
28
+ "types": "./dist/index.d.ts",
29
+ "exports": {
30
+ ".": {
31
+ "import": {
32
+ "types": "./dist/index.d.ts",
33
+ "default": "./dist/index.js"
34
+ },
35
+ "require": {
36
+ "types": "./dist/index.d.cts",
37
+ "default": "./dist/index.cjs"
38
+ }
39
+ },
40
+ "./package.json": "./package.json"
32
41
  },
33
42
  "scripts": {
34
- "start": "tsdx watch",
43
+ "dev": "tsdx dev",
35
44
  "build": "tsdx build",
36
45
  "test": "tsdx test",
37
46
  "lint": "tsdx lint",
38
- "prepare": "tsdx build"
47
+ "format": "tsdx format",
48
+ "typecheck": "tsdx typecheck",
49
+ "prepublishOnly": "bun run build"
39
50
  },
40
- "peerDependencies": {},
41
- "module": "dist/google-sheets-mapper.esm.js",
42
51
  "devDependencies": {
43
- "tsdx": "^0.14.1",
44
- "tslib": "^2.4.0",
45
- "typescript": "^4.7.4"
52
+ "bunchee": "^6.9.4",
53
+ "oxfmt": "^0.27.0",
54
+ "oxlint": "^1.42.0",
55
+ "tsdx": "^2.0.0",
56
+ "typescript": "^5.9.3",
57
+ "vitest": "^4.0.18"
58
+ },
59
+ "engines": {
60
+ "node": ">=20"
46
61
  }
47
62
  }
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { MapperOptions, MapperState, ValueRangesResponse } from './types';
2
- import { fetchBatchData, fetchAllSheetsData, mapData } from './utils';
1
+ import type { MapperOptions, MapperState, ValueRangesResponse } from "./types";
2
+ import { fetchBatchData, fetchAllSheetsData, mapData } from "./utils";
3
3
 
4
4
  const GoogleSheetsMapper = {
5
5
  async fetchGoogleSheetsData({
@@ -7,16 +7,11 @@ const GoogleSheetsMapper = {
7
7
  sheetId,
8
8
  sheetsOptions = [],
9
9
  }: MapperOptions): Promise<MapperState[]> {
10
- try {
11
- const response: ValueRangesResponse =
12
- sheetsOptions.length === 0
13
- ? await fetchAllSheetsData({ apiKey, sheetId })
14
- : await fetchBatchData({ apiKey, sheetId, sheetsOptions });
15
-
16
- return mapData({ sheets: response.valueRanges, sheetsOptions });
17
- } catch (error) {
18
- throw error;
19
- }
10
+ const response: ValueRangesResponse =
11
+ sheetsOptions.length === 0
12
+ ? await fetchAllSheetsData({ apiKey, sheetId })
13
+ : await fetchBatchData({ apiKey, sheetId, sheetsOptions });
14
+ return mapData({ sheets: response.valueRanges, sheetsOptions });
20
15
  },
21
16
  };
22
17
 
package/src/types.ts CHANGED
@@ -34,7 +34,7 @@ export interface SheetsResponse {
34
34
 
35
35
  export interface MapperState {
36
36
  id: string;
37
- data: object[];
37
+ data: Record<string, string>[];
38
38
  }
39
39
 
40
40
  export interface ApiResponse {
package/src/utils.ts CHANGED
@@ -1,4 +1,4 @@
1
- import {
1
+ import type {
2
2
  MapperOptions,
3
3
  MapperState,
4
4
  ApiResponse,
@@ -7,73 +7,70 @@ import {
7
7
  SheetFromResponse,
8
8
  ValueRangesResponse,
9
9
  SheetsOption,
10
- } from './types';
10
+ } from "./types";
11
11
 
12
- const GOOGLE_API_URL = 'https://sheets.googleapis.com/v4/spreadsheets';
12
+ const GOOGLE_API_URL = "https://sheets.googleapis.com/v4/spreadsheets";
13
13
 
14
14
  const getRanges = (sheetNames: string[] = []): string => {
15
15
  // ranges=Sheet1&ranges=Sheet2
16
- return sheetNames.map((sheetName) => `ranges=${sheetName}`).join('&');
16
+ return sheetNames.map((sheetName) => `ranges=${sheetName}`).join("&");
17
17
  };
18
18
 
19
19
  const getSheetsTitleUrl = (sheetId: string, apiKey: string): string => {
20
20
  return `${GOOGLE_API_URL}/${sheetId}?fields=sheets%2Fproperties%2Ftitle&key=${apiKey}`;
21
21
  };
22
22
 
23
- const getBatchUrl = (
24
- sheetId: string,
25
- ranges: Array<string>,
26
- apiKey: string,
27
- ): string => {
23
+ const getBatchUrl = (sheetId: string, ranges: Array<string>, apiKey: string): string => {
28
24
  const rangesQueryString = getRanges(ranges);
29
25
 
30
- return `${GOOGLE_API_URL}/${sheetId}/values:batchGet?${rangesQueryString}&key=${apiKey}`;
26
+ return `${GOOGLE_API_URL}/${sheetId}?${rangesQueryString}&key=${apiKey}&includeGridData=true`;
31
27
  };
32
28
 
33
29
  class ApiResponseError extends Error {
34
- constructor(message: string, public readonly response: ApiResponse) {
30
+ response: ApiResponse;
31
+ constructor(message: string, response: ApiResponse) {
35
32
  super(message);
36
33
  Object.setPrototypeOf(this, ApiResponseError.prototype);
37
34
  this.response = response;
38
- Error.captureStackTrace(this, ApiResponseError);
35
+ if (Error.captureStackTrace) {
36
+ Error.captureStackTrace(this, ApiResponseError);
37
+ }
39
38
  }
40
39
  }
41
40
 
42
- const makeFetch = async (url: string, config = {}): Promise<any> => {
43
- try {
44
- const response = await fetch(url, config);
45
-
46
- if (!response.ok) {
47
- throw new ApiResponseError(
48
- `Request to '${url}' failed with ${response.status}${
49
- response.statusText ? `: ${response.statusText}` : ''
50
- }`,
51
- {
52
- status: response.status,
53
- statusText: response.statusText,
54
- url: response.url,
55
- },
56
- );
57
- }
58
-
59
- return await response.json();
60
- } catch (error) {
61
- console.error(error);
62
- throw error;
41
+ const makeFetch = async <T>(url: string, config = {}): Promise<T> => {
42
+ const response = await fetch(url, config);
43
+
44
+ if (!response.ok) {
45
+ throw new ApiResponseError(
46
+ `Request to '${url}' failed with ${response.status}${
47
+ response.statusText ? `: ${response.statusText}` : ""
48
+ }`,
49
+ {
50
+ status: response.status,
51
+ statusText: response.statusText,
52
+ url: response.url,
53
+ },
54
+ );
63
55
  }
56
+
57
+ return await response.json();
64
58
  };
65
59
 
66
- const mapRecords = (records: ValueRange['values'], headerData: string[]) => {
60
+ const mapRecords = (
61
+ records: ValueRange["values"],
62
+ headerData: string[],
63
+ ): Record<string, string>[] => {
67
64
  return records
68
65
  .filter((record: string[]) => record.length > 0)
69
66
  .map((record: string[]) =>
70
- record.reduce(
71
- (obj: { [key: string]: unknown }, item: string, index: number) => {
72
- obj[headerData[index]] = item;
73
- return obj;
74
- },
75
- {},
76
- ),
67
+ record.reduce((obj: Record<string, string>, item: string, index: number) => {
68
+ const key = headerData[index];
69
+ if (key !== undefined) {
70
+ obj[key] = item;
71
+ }
72
+ return obj;
73
+ }, {}),
77
74
  );
78
75
  };
79
76
 
@@ -85,13 +82,11 @@ export const mapData = ({
85
82
  sheetsOptions?: SheetsOption[];
86
83
  }): MapperState[] => {
87
84
  return sheets.map((sheet: ValueRange) => {
88
- const id = sheet.range.split('!')[0].replace(/'/g, '');
85
+ const id = sheet.range.split("!")[0].replace(/'/g, "");
89
86
  const rows = sheet.values || [];
90
87
 
91
88
  if (rows.length > 0) {
92
- const sheetsOptionsSheet = sheetsOptions.find(
93
- (sheet: SheetsOption) => sheet.id === id,
94
- );
89
+ const sheetsOptionsSheet = sheetsOptions.find((option: SheetsOption) => option.id === id);
95
90
  const headerRowIndex = sheetsOptionsSheet?.headerRowIndex ?? 0;
96
91
  const header = rows[headerRowIndex];
97
92
  const records = rows.filter((_, index: number) => index > headerRowIndex);