UNPKG

7.21 kBJavaScriptView Raw
1"use strict";
2// Copyright 2019 Google LLC
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15Object.defineProperty(exports, "__esModule", { value: true });
16exports.PassThroughShim = exports.formatAsUTCISO = exports.convertObjKeysToSnakeCase = exports.unicodeJSONStringify = exports.objectKeyToLowercase = exports.qsStringify = exports.encodeURI = exports.fixedEncodeURIComponent = exports.objectEntries = exports.normalize = void 0;
17const querystring = require("querystring");
18const stream_1 = require("stream");
19function normalize(optionsOrCallback, cb) {
20 const options = (typeof optionsOrCallback === 'object' ? optionsOrCallback : {});
21 const callback = (typeof optionsOrCallback === 'function' ? optionsOrCallback : cb);
22 return { options, callback };
23}
24exports.normalize = normalize;
25/**
26 * Flatten an object into an Array of arrays, [[key, value], ..].
27 * Implements Object.entries() for Node.js <8
28 * @internal
29 */
30function objectEntries(obj) {
31 return Object.keys(obj).map(key => [key, obj[key]]);
32}
33exports.objectEntries = objectEntries;
34/**
35 * Encode `str` with encodeURIComponent, plus these
36 * reserved characters: `! * ' ( )`.
37 *
38 * See {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent| MDN: fixedEncodeURIComponent}
39 *
40 * @param {string} str The URI component to encode.
41 * @return {string} The encoded string.
42 */
43function fixedEncodeURIComponent(str) {
44 return encodeURIComponent(str).replace(/[!'()*]/g, c => '%' + c.charCodeAt(0).toString(16).toUpperCase());
45}
46exports.fixedEncodeURIComponent = fixedEncodeURIComponent;
47/**
48 * URI encode `uri` for generating signed URLs, using fixedEncodeURIComponent.
49 *
50 * Encode every byte except `A-Z a-Z 0-9 ~ - . _`.
51 *
52 * @param {string} uri The URI to encode.
53 * @param [boolean=false] encodeSlash If `true`, the "/" character is not encoded.
54 * @return {string} The encoded string.
55 */
56function encodeURI(uri, encodeSlash) {
57 // Split the string by `/`, and conditionally rejoin them with either
58 // %2F if encodeSlash is `true`, or '/' if `false`.
59 return uri
60 .split('/')
61 .map(fixedEncodeURIComponent)
62 .join(encodeSlash ? '%2F' : '/');
63}
64exports.encodeURI = encodeURI;
65/**
66 * Serialize an object to a URL query string using util.encodeURI(uri, true).
67 * @param {string} url The object to serialize.
68 * @return {string} Serialized string.
69 */
70function qsStringify(qs) {
71 return querystring.stringify(qs, '&', '=', {
72 encodeURIComponent: (component) => encodeURI(component, true),
73 });
74}
75exports.qsStringify = qsStringify;
76function objectKeyToLowercase(object) {
77 const newObj = {};
78 for (let key of Object.keys(object)) {
79 const value = object[key];
80 key = key.toLowerCase();
81 newObj[key] = value;
82 }
83 return newObj;
84}
85exports.objectKeyToLowercase = objectKeyToLowercase;
86/**
87 * JSON encode str, with unicode \u+ representation.
88 * @param {object} obj The object to encode.
89 * @return {string} Serialized string.
90 */
91function unicodeJSONStringify(obj) {
92 return JSON.stringify(obj).replace(/[\u0080-\uFFFF]/g, (char) => '\\u' + ('0000' + char.charCodeAt(0).toString(16)).slice(-4));
93}
94exports.unicodeJSONStringify = unicodeJSONStringify;
95/**
96 * Converts the given objects keys to snake_case
97 * @param {object} obj object to convert keys to snake case.
98 * @returns {object} object with keys converted to snake case.
99 */
100function convertObjKeysToSnakeCase(obj) {
101 if (obj instanceof Date || obj instanceof RegExp) {
102 return obj;
103 }
104 if (Array.isArray(obj)) {
105 return obj.map(convertObjKeysToSnakeCase);
106 }
107 if (obj instanceof Object) {
108 return Object.keys(obj).reduce((acc, cur) => {
109 const s = cur[0].toLocaleLowerCase() +
110 cur.slice(1).replace(/([A-Z]+)/g, (match, p1) => {
111 return `_${p1.toLowerCase()}`;
112 });
113 acc[s] = convertObjKeysToSnakeCase(obj[cur]);
114 return acc;
115 }, Object());
116 }
117 return obj;
118}
119exports.convertObjKeysToSnakeCase = convertObjKeysToSnakeCase;
120/**
121 * Formats the provided date object as a UTC ISO string.
122 * @param {Date} dateTimeToFormat date object to be formatted.
123 * @param {boolean} includeTime flag to include hours, minutes, seconds in output.
124 * @param {string} dateDelimiter delimiter between date components.
125 * @param {string} timeDelimiter delimiter between time components.
126 * @returns {string} UTC ISO format of provided date obect.
127 */
128function formatAsUTCISO(dateTimeToFormat, includeTime = false, dateDelimiter = '', timeDelimiter = '') {
129 const year = dateTimeToFormat.getUTCFullYear();
130 const month = dateTimeToFormat.getUTCMonth() + 1;
131 const day = dateTimeToFormat.getUTCDate();
132 const hour = dateTimeToFormat.getUTCHours();
133 const minute = dateTimeToFormat.getUTCMinutes();
134 const second = dateTimeToFormat.getUTCSeconds();
135 let resultString = `${year.toString().padStart(4, '0')}${dateDelimiter}${month
136 .toString()
137 .padStart(2, '0')}${dateDelimiter}${day.toString().padStart(2, '0')}`;
138 if (includeTime) {
139 resultString = `${resultString}T${hour
140 .toString()
141 .padStart(2, '0')}${timeDelimiter}${minute
142 .toString()
143 .padStart(2, '0')}${timeDelimiter}${second.toString().padStart(2, '0')}Z`;
144 }
145 return resultString;
146}
147exports.formatAsUTCISO = formatAsUTCISO;
148class PassThroughShim extends stream_1.PassThrough {
149 constructor() {
150 super(...arguments);
151 this.shouldEmitReading = true;
152 this.shouldEmitWriting = true;
153 }
154 _read(size) {
155 if (this.shouldEmitReading) {
156 this.emit('reading');
157 this.shouldEmitReading = false;
158 }
159 super._read(size);
160 }
161 _write(chunk, encoding, callback) {
162 if (this.shouldEmitWriting) {
163 this.emit('writing');
164 this.shouldEmitWriting = false;
165 }
166 // Per the nodejs documention, callback must be invoked on the next tick
167 process.nextTick(() => {
168 super._write(chunk, encoding, callback);
169 });
170 }
171 _final(callback) {
172 // If the stream is empty (i.e. empty file) final will be invoked before _read / _write
173 // and we should still emit the proper events.
174 if (this.shouldEmitReading) {
175 this.emit('reading');
176 this.shouldEmitReading = false;
177 }
178 if (this.shouldEmitWriting) {
179 this.emit('writing');
180 this.shouldEmitWriting = false;
181 }
182 callback(null);
183 }
184}
185exports.PassThroughShim = PassThroughShim;
186//# sourceMappingURL=util.js.map
\No newline at end of file