gcf-common-lib 0.5.6 → 0.8.1
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/index.js +59 -190
- package/index.ts +67 -43
- package/package.json +10 -4
- package/tsconfig.json +32 -0
- package/utils.js +46 -0
- package/utils.ts +57 -0
package/index.js
CHANGED
|
@@ -1,194 +1,63 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
-
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
-
function step(op) {
|
|
16
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
-
while (_) try {
|
|
18
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
-
switch (op[0]) {
|
|
21
|
-
case 0: case 1: t = op; break;
|
|
22
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
-
default:
|
|
26
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
-
if (t[2]) _.ops.pop();
|
|
31
|
-
_.trys.pop(); continue;
|
|
32
|
-
}
|
|
33
|
-
op = body.call(thisArg, _);
|
|
34
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.GcfCommon = void 0;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
// console.log('res:', res);
|
|
67
|
-
return [4 /*yield*/, this.publish(event, context, res !== null && res !== void 0 ? res : {})];
|
|
68
|
-
case 1:
|
|
69
|
-
// console.log('res:', res);
|
|
70
|
-
_a.sent();
|
|
71
|
-
return [2 /*return*/];
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
}); })
|
|
75
|
-
.catch(function (err) { return __awaiter(_this, void 0, void 0, function () {
|
|
76
|
-
var fname, dataJSON;
|
|
77
|
-
var _a, _b;
|
|
78
|
-
return __generator(this, function (_c) {
|
|
79
|
-
switch (_c.label) {
|
|
80
|
-
case 0:
|
|
81
|
-
fname = (_b = (_a = process === null || process === void 0 ? void 0 : process.env) === null || _a === void 0 ? void 0 : _a.K_SERVICE) !== null && _b !== void 0 ? _b : 'UNKNOWN';
|
|
82
|
-
dataJSON = { error: { name: err.name, message: "GCF [" + fname + "]: " + err.message, stack: err.stack } };
|
|
83
|
-
return [4 /*yield*/, this.publish(event, context, dataJSON).catch(lodash_1.noop)];
|
|
84
|
-
case 1:
|
|
85
|
-
_c.sent();
|
|
86
|
-
throw err;
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
}); })];
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
};
|
|
93
|
-
/**
|
|
94
|
-
*
|
|
95
|
-
* @param {!Object} event Event payload.
|
|
96
|
-
* @param {!Object} context Metadata for the event.
|
|
97
|
-
* @param json
|
|
98
|
-
*/
|
|
99
|
-
GcfCommon.publish = function (event, context, json) {
|
|
100
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
101
|
-
var topic;
|
|
102
|
-
return __generator(this, function (_a) {
|
|
103
|
-
switch (_a.label) {
|
|
104
|
-
case 0: return [4 /*yield*/, this.getTopic(event, context)];
|
|
105
|
-
case 1:
|
|
106
|
-
topic = _a.sent();
|
|
107
|
-
console.log('publish:', topic === null || topic === void 0 ? void 0 : topic.name, json);
|
|
108
|
-
if (!topic) return [3 /*break*/, 3];
|
|
109
|
-
return [4 /*yield*/, topic.publishMessage({ json: json })];
|
|
110
|
-
case 2: return [2 /*return*/, _a.sent()];
|
|
111
|
-
case 3: return [2 /*return*/];
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
};
|
|
116
|
-
/**
|
|
117
|
-
*
|
|
118
|
-
* @param {!Object} event Event payload.
|
|
119
|
-
* @param {!Object} context Metadata for the event.
|
|
120
|
-
*/
|
|
121
|
-
GcfCommon.getTopic = function (event, context) {
|
|
122
|
-
var _a, _b, _c;
|
|
123
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
124
|
-
var pubSub, topicName, storage, file, meta, topic;
|
|
125
|
-
return __generator(this, function (_d) {
|
|
126
|
-
switch (_d.label) {
|
|
127
|
-
case 0:
|
|
128
|
-
pubSub = new pubsub_1.PubSub();
|
|
129
|
-
topicName = (_a = event === null || event === void 0 ? void 0 : event.metadata) === null || _a === void 0 ? void 0 : _a.topic;
|
|
130
|
-
if (!(!topicName && ((_b = context === null || context === void 0 ? void 0 : context.resource) === null || _b === void 0 ? void 0 : _b.type) === 'storage#object')) return [3 /*break*/, 2];
|
|
131
|
-
storage = new storage_1.Storage();
|
|
132
|
-
file = storage.bucket(event.bucket).file(event.name);
|
|
133
|
-
return [4 /*yield*/, file.getMetadata()];
|
|
134
|
-
case 1:
|
|
135
|
-
meta = (_d.sent())[0];
|
|
136
|
-
topicName = (_c = meta === null || meta === void 0 ? void 0 : meta.metadata) === null || _c === void 0 ? void 0 : _c.topic;
|
|
137
|
-
console.log('topic:', topicName);
|
|
138
|
-
_d.label = 2;
|
|
139
|
-
case 2:
|
|
140
|
-
if (!!(0, lodash_1.isEmpty)(topicName)) return [3 /*break*/, 4];
|
|
141
|
-
topic = pubSub.topic(topicName);
|
|
142
|
-
return [4 /*yield*/, topic.setMetadata({ labels: { date: topicName.split('__')[1] } })];
|
|
143
|
-
case 3:
|
|
144
|
-
_d.sent();
|
|
145
|
-
return [2 /*return*/, topic];
|
|
146
|
-
case 4: return [2 /*return*/];
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
});
|
|
150
|
-
};
|
|
151
|
-
/**
|
|
152
|
-
*
|
|
153
|
-
* @param {!Object} event Event payload.
|
|
154
|
-
* @param {!Object} context Metadata for the event.
|
|
155
|
-
*/
|
|
156
|
-
GcfCommon.getOptions = function (event, context) {
|
|
157
|
-
var _a, _b, _c, _d, _e;
|
|
158
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
159
|
-
var storage, file, meta;
|
|
160
|
-
return __generator(this, function (_f) {
|
|
161
|
-
switch (_f.label) {
|
|
162
|
-
case 0:
|
|
163
|
-
if (!((_a = event === null || event === void 0 ? void 0 : event.metadata) === null || _a === void 0 ? void 0 : _a.options)) return [3 /*break*/, 1];
|
|
164
|
-
return [2 /*return*/, JSON.parse((_c = (_b = event === null || event === void 0 ? void 0 : event.metadata) === null || _b === void 0 ? void 0 : _b.options) !== null && _c !== void 0 ? _c : '{}')];
|
|
165
|
-
case 1:
|
|
166
|
-
storage = new storage_1.Storage();
|
|
167
|
-
file = storage.bucket(event.bucket).file(event.name);
|
|
168
|
-
return [4 /*yield*/, file.getMetadata()];
|
|
169
|
-
case 2:
|
|
170
|
-
meta = (_f.sent())[0];
|
|
171
|
-
return [2 /*return*/, JSON.parse((_e = (_d = meta === null || meta === void 0 ? void 0 : meta.metadata) === null || _d === void 0 ? void 0 : _d.options) !== null && _e !== void 0 ? _e : '{}')];
|
|
172
|
-
}
|
|
173
|
-
});
|
|
3
|
+
exports.GcfCommon = exports.storage = exports.pubSub = void 0;
|
|
4
|
+
const lodash_1 = require("lodash");
|
|
5
|
+
const storage_1 = require("@google-cloud/storage");
|
|
6
|
+
const pubsub_1 = require("@google-cloud/pubsub");
|
|
7
|
+
const utils_1 = require("./utils");
|
|
8
|
+
exports.pubSub = new pubsub_1.PubSub();
|
|
9
|
+
exports.storage = new storage_1.Storage();
|
|
10
|
+
class GcfCommon {
|
|
11
|
+
static async process(event, context, handler, timeout = 535) {
|
|
12
|
+
return Promise.race([
|
|
13
|
+
(0, utils_1.timeoutAfter)(timeout),
|
|
14
|
+
handler(event, context),
|
|
15
|
+
])
|
|
16
|
+
.then(async (res) => {
|
|
17
|
+
await this.publish(event, context, res ?? {});
|
|
18
|
+
})
|
|
19
|
+
.catch(async (err) => {
|
|
20
|
+
const fname = process?.env?.K_SERVICE ?? 'UNKNOWN';
|
|
21
|
+
const response = {
|
|
22
|
+
error: {
|
|
23
|
+
name: err.name,
|
|
24
|
+
message: `GCF [${fname}]: ${err.message}`,
|
|
25
|
+
stack: err.stack,
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
await this.publish(event, context, response).catch(lodash_1.noop);
|
|
29
|
+
throw err;
|
|
174
30
|
});
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
31
|
+
}
|
|
32
|
+
static async publish(event, context, json) {
|
|
33
|
+
const topic = await this.getTopic(event, context);
|
|
34
|
+
console.log('publish:', topic?.name, json);
|
|
35
|
+
if (topic)
|
|
36
|
+
return await topic.publishMessage({ json });
|
|
37
|
+
}
|
|
38
|
+
static async getTopic(event, context) {
|
|
39
|
+
let topicName = event?.metadata?.topic;
|
|
40
|
+
if (!topicName && context?.resource?.type === 'storage#object') {
|
|
41
|
+
const file = exports.storage.bucket(event.bucket).file(event.name);
|
|
42
|
+
const [meta] = await file.getMetadata();
|
|
43
|
+
topicName = meta?.metadata?.topic;
|
|
44
|
+
console.log('topic:', topicName);
|
|
45
|
+
}
|
|
46
|
+
if (topicName && !(0, lodash_1.isEmpty)(topicName)) {
|
|
47
|
+
const topic = exports.pubSub.topic(topicName);
|
|
48
|
+
await topic.setMetadata({ labels: { date: topicName.split('__')[1] } });
|
|
49
|
+
return topic;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
static async getOptions(event, context) {
|
|
53
|
+
if (event?.metadata?.options) {
|
|
54
|
+
return JSON.parse(event?.metadata?.options ?? '{}');
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
const file = exports.storage.bucket(event.bucket).file(event.name);
|
|
58
|
+
const [meta] = await file.getMetadata();
|
|
59
|
+
return JSON.parse(meta?.metadata?.options ?? '{}');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
194
63
|
exports.GcfCommon = GcfCommon;
|
package/index.ts
CHANGED
|
@@ -1,19 +1,68 @@
|
|
|
1
|
-
import {File, Storage} from '@google-cloud/storage';
|
|
2
|
-
import {PubSub, Topic} from '@google-cloud/pubsub';
|
|
3
1
|
import {isEmpty, noop} from 'lodash';
|
|
2
|
+
import {File, Storage} from "@google-cloud/storage";
|
|
3
|
+
import {PubSub} from "@google-cloud/pubsub";
|
|
4
|
+
import {timeoutAfter} from "./utils";
|
|
5
|
+
|
|
6
|
+
export type TEvent = {
|
|
7
|
+
bucket: string;
|
|
8
|
+
contentType: string;
|
|
9
|
+
crc32c: string;
|
|
10
|
+
etag: string;
|
|
11
|
+
generation: string;
|
|
12
|
+
id: string;
|
|
13
|
+
kind: string; // 'storage#object'
|
|
14
|
+
md5Hash: string;
|
|
15
|
+
mediaLink: string;
|
|
16
|
+
metadata: { [key: string]: string, topic: string, options?: any };
|
|
17
|
+
metageneration: string;
|
|
18
|
+
name: string;
|
|
19
|
+
selfLink: string;
|
|
20
|
+
size: string;
|
|
21
|
+
storageClass: string;
|
|
22
|
+
timeCreated: string;
|
|
23
|
+
timeStorageClassUpdated: string;
|
|
24
|
+
updated: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type TContext = {
|
|
28
|
+
eventId: string;
|
|
29
|
+
timestamp: string;
|
|
30
|
+
eventType: string; // 'google.storage.object.finalize'
|
|
31
|
+
resource: {
|
|
32
|
+
service: string; // 'storage.googleapis.com'
|
|
33
|
+
name: string;
|
|
34
|
+
type: string; // 'storage#object'
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export type TResponse = {
|
|
39
|
+
error?: {
|
|
40
|
+
name: string,
|
|
41
|
+
message: string,
|
|
42
|
+
stack?: string,
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const pubSub = new PubSub();
|
|
47
|
+
export const storage = new Storage();
|
|
4
48
|
|
|
5
49
|
export class GcfCommon {
|
|
6
50
|
|
|
7
51
|
/**
|
|
8
52
|
*
|
|
9
|
-
* @param {!
|
|
10
|
-
* @param {!
|
|
53
|
+
* @param {!TEvent} event Event payload.
|
|
54
|
+
* @param {!TContext} context Metadata for the event.
|
|
11
55
|
* @param handler
|
|
12
56
|
* @param timeout Seconds
|
|
13
57
|
*/
|
|
14
|
-
static async process(
|
|
58
|
+
static async process<T>(
|
|
59
|
+
event: TEvent,
|
|
60
|
+
context: TContext,
|
|
61
|
+
handler: (event: TEvent, context: TContext) => Promise<T>,
|
|
62
|
+
timeout = 535,
|
|
63
|
+
) {
|
|
15
64
|
return Promise.race([
|
|
16
|
-
|
|
65
|
+
timeoutAfter(timeout),
|
|
17
66
|
handler(event, context),
|
|
18
67
|
])
|
|
19
68
|
.then(async (res: any) => {
|
|
@@ -22,76 +71,51 @@ export class GcfCommon {
|
|
|
22
71
|
})
|
|
23
72
|
.catch(async (err: Error) => {
|
|
24
73
|
const fname = process?.env?.K_SERVICE ?? 'UNKNOWN';
|
|
25
|
-
const
|
|
26
|
-
|
|
74
|
+
const response: TResponse = {
|
|
75
|
+
error: {
|
|
76
|
+
name: err.name,
|
|
77
|
+
message: `GCF [${fname}]: ${err.message}`,
|
|
78
|
+
stack: err.stack,
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
await this.publish(event, context, response).catch(noop);
|
|
27
82
|
throw err;
|
|
28
83
|
})
|
|
29
84
|
;
|
|
30
85
|
}
|
|
31
86
|
|
|
32
|
-
|
|
33
|
-
*
|
|
34
|
-
* @param {!Object} event Event payload.
|
|
35
|
-
* @param {!Object} context Metadata for the event.
|
|
36
|
-
* @param json
|
|
37
|
-
*/
|
|
38
|
-
static async publish(event, context, json) {
|
|
87
|
+
static async publish(event: TEvent, context: TContext, json: TResponse) {
|
|
39
88
|
const topic = await this.getTopic(event, context);
|
|
40
89
|
console.log('publish:', topic?.name, json);
|
|
41
90
|
if (topic) return await topic.publishMessage({json});
|
|
42
91
|
}
|
|
43
92
|
|
|
44
|
-
|
|
45
|
-
*
|
|
46
|
-
* @param {!Object} event Event payload.
|
|
47
|
-
* @param {!Object} context Metadata for the event.
|
|
48
|
-
*/
|
|
49
|
-
static async getTopic(event, context): Promise<Topic | undefined> {
|
|
50
|
-
const pubSub = new PubSub();
|
|
93
|
+
static async getTopic(event: TEvent, context: TContext) {
|
|
51
94
|
|
|
52
95
|
/** t_{GUID}__{YYYY-MM-DD} */
|
|
53
96
|
let topicName: string | undefined = event?.metadata?.topic;
|
|
54
97
|
|
|
55
98
|
if (!topicName && context?.resource?.type === 'storage#object') {
|
|
56
|
-
const storage = new Storage();
|
|
57
99
|
const file: File = storage.bucket(event.bucket).file(event.name);
|
|
58
100
|
const [meta] = await file.getMetadata();
|
|
59
101
|
topicName = meta?.metadata?.topic;
|
|
60
102
|
console.log('topic:', topicName);
|
|
61
103
|
}
|
|
62
104
|
|
|
63
|
-
if (!isEmpty(topicName)) {
|
|
105
|
+
if (topicName && !isEmpty(topicName)) {
|
|
64
106
|
const topic = pubSub.topic(topicName);
|
|
65
107
|
await topic.setMetadata({labels: {date: topicName.split('__')[1]}});
|
|
66
108
|
return topic;
|
|
67
109
|
}
|
|
68
110
|
}
|
|
69
111
|
|
|
70
|
-
|
|
71
|
-
*
|
|
72
|
-
* @param {!Object} event Event payload.
|
|
73
|
-
* @param {!Object} context Metadata for the event.
|
|
74
|
-
*/
|
|
75
|
-
static async getOptions(event, context) {
|
|
112
|
+
static async getOptions(event: TEvent, context: TContext) {
|
|
76
113
|
if (event?.metadata?.options) {
|
|
77
114
|
return JSON.parse(event?.metadata?.options ?? '{}');
|
|
78
115
|
} else {
|
|
79
|
-
const storage = new Storage();
|
|
80
116
|
const file: File = storage.bucket(event.bucket).file(event.name);
|
|
81
117
|
const [meta] = await file.getMetadata();
|
|
82
118
|
return JSON.parse(meta?.metadata?.options ?? '{}');
|
|
83
119
|
}
|
|
84
120
|
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
*
|
|
88
|
-
* @param s Google function time limit (max: 9 min)
|
|
89
|
-
*/
|
|
90
|
-
static async delay(s: number = 540) {
|
|
91
|
-
return new Promise<undefined>((resolve, reject) => {
|
|
92
|
-
setTimeout(() => {
|
|
93
|
-
reject(new Error(`${s} seconds timeout exceeded`));
|
|
94
|
-
}, s * 1000);
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
121
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gcf-common-lib",
|
|
3
3
|
"description": "",
|
|
4
|
-
"version": "0.
|
|
5
|
-
"publishConfig": {
|
|
4
|
+
"version": "0.8.1",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public",
|
|
7
|
+
"branches": [
|
|
8
|
+
"master"
|
|
9
|
+
]
|
|
10
|
+
},
|
|
6
11
|
"engines": {},
|
|
7
12
|
"scripts": {
|
|
8
13
|
"test": "echo \"Error: no test specified\" || exit 0"
|
|
@@ -13,11 +18,12 @@
|
|
|
13
18
|
},
|
|
14
19
|
"dependencies": {
|
|
15
20
|
"@google-cloud/pubsub": "^2.18.4",
|
|
16
|
-
"@google-cloud/storage": "^5.
|
|
21
|
+
"@google-cloud/storage": "^5.17.0",
|
|
17
22
|
"lodash": "^4.17.21"
|
|
18
23
|
},
|
|
19
24
|
"devDependencies": {
|
|
20
|
-
"@types/lodash": "^4.14.178"
|
|
25
|
+
"@types/lodash": "^4.14.178",
|
|
26
|
+
"@tsconfig/node14": "^1.0.1"
|
|
21
27
|
},
|
|
22
28
|
"keywords": [],
|
|
23
29
|
"author": "alert83@gmail.com",
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json.schemastore.org/tsconfig",
|
|
3
|
+
"extends": "@tsconfig/node14/tsconfig.json",
|
|
4
|
+
"compilerOptions": {
|
|
5
|
+
"allowJs": false,
|
|
6
|
+
"removeComments": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"allowSyntheticDefaultImports": true,
|
|
9
|
+
"isolatedModules": false,
|
|
10
|
+
"emitDecoratorMetadata": true,
|
|
11
|
+
"experimentalDecorators": true,
|
|
12
|
+
"module": "commonjs",
|
|
13
|
+
"moduleResolution": "node",
|
|
14
|
+
"target": "ES2020",
|
|
15
|
+
"typeRoots": [
|
|
16
|
+
"node_modules/@types"
|
|
17
|
+
],
|
|
18
|
+
"lib": [
|
|
19
|
+
"ES2018",
|
|
20
|
+
"ES2019",
|
|
21
|
+
"ES2020",
|
|
22
|
+
"ES2021",
|
|
23
|
+
"ESNext"
|
|
24
|
+
],
|
|
25
|
+
"types": [],
|
|
26
|
+
"plugins": []
|
|
27
|
+
},
|
|
28
|
+
"exclude": [
|
|
29
|
+
"node_modules/**",
|
|
30
|
+
"**/*.d.ts"
|
|
31
|
+
]
|
|
32
|
+
}
|
package/utils.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.A1ToColNum = exports.A1ToIndex = exports.colNumToA1 = exports.indexToA1 = exports.timeoutAfter = void 0;
|
|
4
|
+
async function timeoutAfter(seconds = 540) {
|
|
5
|
+
return new Promise((resolve, reject) => {
|
|
6
|
+
setTimeout(() => {
|
|
7
|
+
reject(new Error(`${seconds} seconds timeout exceeded`));
|
|
8
|
+
}, seconds * 1000);
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
exports.timeoutAfter = timeoutAfter;
|
|
12
|
+
function indexToA1(idx) {
|
|
13
|
+
return colNumToA1(idx + 1);
|
|
14
|
+
}
|
|
15
|
+
exports.indexToA1 = indexToA1;
|
|
16
|
+
function colNumToA1(columnNumber) {
|
|
17
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
18
|
+
const charIdxArr = [];
|
|
19
|
+
while (columnNumber > 0) {
|
|
20
|
+
const rem = columnNumber % chars.length;
|
|
21
|
+
if (rem === 0) {
|
|
22
|
+
charIdxArr.push(chars.length - 1);
|
|
23
|
+
columnNumber = Math.floor(columnNumber / chars.length) - 1;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
charIdxArr.push(rem - 1);
|
|
27
|
+
columnNumber = Math.floor(columnNumber / chars.length);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return charIdxArr.reverse().map((n) => chars[n]).join('');
|
|
31
|
+
}
|
|
32
|
+
exports.colNumToA1 = colNumToA1;
|
|
33
|
+
function A1ToIndex(value) {
|
|
34
|
+
return A1ToColNum(value) - 1;
|
|
35
|
+
}
|
|
36
|
+
exports.A1ToIndex = A1ToIndex;
|
|
37
|
+
function A1ToColNum(value) {
|
|
38
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
39
|
+
let result = 0;
|
|
40
|
+
for (let i = 0; i < value.length; i++) {
|
|
41
|
+
result *= chars.length;
|
|
42
|
+
result += chars.indexOf(value[i]) + 1;
|
|
43
|
+
}
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
exports.A1ToColNum = A1ToColNum;
|
package/utils.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* @param seconds Google function timeout limit (max: 9 min)
|
|
4
|
+
*/
|
|
5
|
+
export async function timeoutAfter(seconds: number = 540) {
|
|
6
|
+
return new Promise<undefined>((resolve, reject) => {
|
|
7
|
+
setTimeout(() => {
|
|
8
|
+
reject(new Error(`${seconds} seconds timeout exceeded`));
|
|
9
|
+
}, seconds * 1000);
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
//
|
|
14
|
+
|
|
15
|
+
export function indexToA1(idx: number) {
|
|
16
|
+
return colNumToA1(idx + 1);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function colNumToA1(columnNumber: number) {
|
|
20
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
21
|
+
|
|
22
|
+
// To store result (Excel column name)
|
|
23
|
+
const charIdxArr: number[] = [];
|
|
24
|
+
|
|
25
|
+
while (columnNumber > 0) {
|
|
26
|
+
// Find remainder
|
|
27
|
+
const rem = columnNumber % chars.length;
|
|
28
|
+
|
|
29
|
+
// If remainder is 0, then a
|
|
30
|
+
// 'Z' must be there in output
|
|
31
|
+
if (rem === 0) {
|
|
32
|
+
charIdxArr.push(chars.length - 1);
|
|
33
|
+
columnNumber = Math.floor(columnNumber / chars.length) - 1;
|
|
34
|
+
} else { // If remainder is non-zero
|
|
35
|
+
charIdxArr.push(rem - 1);
|
|
36
|
+
columnNumber = Math.floor(columnNumber / chars.length);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Reverse the string and print result
|
|
41
|
+
return charIdxArr.reverse().map((n) => chars[n]).join('');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function A1ToIndex(value: string) {
|
|
45
|
+
return A1ToColNum(value) - 1;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function A1ToColNum(value: string) {
|
|
49
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
50
|
+
let result = 0;
|
|
51
|
+
// tslint:disable-next-line:prefer-for-of
|
|
52
|
+
for (let i = 0; i < value.length; i++) {
|
|
53
|
+
result *= chars.length;
|
|
54
|
+
result += chars.indexOf(value[i]) + 1;
|
|
55
|
+
}
|
|
56
|
+
return result;
|
|
57
|
+
}
|