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 +11 -11
- package/dist/index.cjs +103 -0
- package/dist/index.d.cts +22 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +22 -6
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +98 -6
- package/package.json +39 -24
- package/src/index.ts +7 -12
- package/src/types.ts +1 -1
- package/src/utils.ts +40 -45
- package/dist/google-sheets-mapper.cjs.development.js +0 -760
- package/dist/google-sheets-mapper.cjs.development.js.map +0 -1
- package/dist/google-sheets-mapper.cjs.production.min.js +0 -2
- package/dist/google-sheets-mapper.cjs.production.min.js.map +0 -1
- package/dist/google-sheets-mapper.esm.js +0 -756
- package/dist/google-sheets-mapper.esm.js.map +0 -1
- package/dist/types.d.ts +0 -39
- package/dist/utils.d.ts +0 -7
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
|
-
|
|
12
|
+
npm install google-sheets-mapper
|
|
15
13
|
```
|
|
16
14
|
|
|
17
|
-
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add google-sheets-mapper
|
|
17
|
+
```
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
|
|
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
|
|
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
|
|
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:
|
|
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:
|
|
122
|
+
id: "Sheet1",
|
|
123
123
|
data: [
|
|
124
|
-
{ value:
|
|
125
|
-
{ value:
|
|
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;
|
package/dist/index.d.cts
ADDED
|
@@ -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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
"
|
|
5
|
-
|
|
6
|
-
|
|
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
|
-
"
|
|
11
|
-
"
|
|
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
|
-
"
|
|
31
|
-
|
|
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
|
-
"
|
|
43
|
+
"dev": "tsdx dev",
|
|
35
44
|
"build": "tsdx build",
|
|
36
45
|
"test": "tsdx test",
|
|
37
46
|
"lint": "tsdx lint",
|
|
38
|
-
"
|
|
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
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
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
|
|
2
|
-
import { fetchBatchData, fetchAllSheetsData, mapData } from
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
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
|
|
10
|
+
} from "./types";
|
|
11
11
|
|
|
12
|
-
const GOOGLE_API_URL =
|
|
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}
|
|
26
|
+
return `${GOOGLE_API_URL}/${sheetId}?${rangesQueryString}&key=${apiKey}&includeGridData=true`;
|
|
31
27
|
};
|
|
32
28
|
|
|
33
29
|
class ApiResponseError extends Error {
|
|
34
|
-
|
|
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
|
|
35
|
+
if (Error.captureStackTrace) {
|
|
36
|
+
Error.captureStackTrace(this, ApiResponseError);
|
|
37
|
+
}
|
|
39
38
|
}
|
|
40
39
|
}
|
|
41
40
|
|
|
42
|
-
const makeFetch = async (url: string, config = {}): Promise<
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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 = (
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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(
|
|
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);
|