@helloao/cli 0.0.6 → 0.0.8-alpha

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/files.js DELETED
@@ -1,362 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.ZipUploader = exports.FilesUploader = void 0;
27
- exports.serializeOutputFiles = serializeOutputFiles;
28
- exports.serializeFile = serializeFile;
29
- exports.loadTranslationsFiles = loadTranslationsFiles;
30
- exports.loadTranslationFiles = loadTranslationFiles;
31
- exports.hashInputFiles = hashInputFiles;
32
- const promises_1 = require("fs/promises");
33
- const path_1 = require("path");
34
- const path = __importStar(require("path"));
35
- const fs_extra_1 = require("fs-extra");
36
- const zip_js_1 = require("@zip.js/zip.js");
37
- const stream_1 = require("stream");
38
- const hash_js_1 = require("hash.js");
39
- const usx_parser_1 = require("@helloao/tools/parser/usx-parser");
40
- const lodash_1 = require("lodash");
41
- const base64_js_1 = require("base64-js");
42
- /**
43
- * Serializes the given output files into serialized files using the given options.
44
- *
45
- * Each iteration of the given files will be processed as a batch, and any mergable files will automatically be merged together and serialized in the final batch.
46
- *
47
- * @param files The files that should be serialized.
48
- * @param options The options for serialization.
49
- */
50
- async function* serializeOutputFiles(files, options) {
51
- const mergableFiles = new Map();
52
- for await (let batch of files) {
53
- let serializedFiles = [];
54
- for (let file of batch) {
55
- if (file.mergable) {
56
- let arr = mergableFiles.get(file.path);
57
- if (!arr) {
58
- arr = [];
59
- mergableFiles.set(file.path, arr);
60
- }
61
- arr.push(file);
62
- continue;
63
- }
64
- const serialized = await serializeFile(file.path, file.content, options);
65
- if (serialized) {
66
- serializedFiles.push(serialized);
67
- }
68
- }
69
- yield serializedFiles;
70
- }
71
- let serializedFiles = [];
72
- for (let [path, files] of mergableFiles) {
73
- let content = {};
74
- for (let file of files) {
75
- if (!content) {
76
- content = file.content;
77
- }
78
- else {
79
- content = (0, lodash_1.mergeWith)(content, file.content, (objValue, srcValue) => {
80
- if (Array.isArray(objValue)) {
81
- return objValue.concat(srcValue);
82
- }
83
- return undefined;
84
- });
85
- }
86
- }
87
- if (content) {
88
- const serialized = await serializeFile(path, content, options);
89
- if (serialized) {
90
- serializedFiles.push(serialized);
91
- }
92
- }
93
- }
94
- yield serializedFiles;
95
- }
96
- /**
97
- * Serializes the given output file content into a serialized file.
98
- * @param path The path that the file should be saved to.
99
- * @param content The content of the file.
100
- * @param options The options for serialization.
101
- */
102
- async function serializeFile(path, content, options) {
103
- let fileContent;
104
- if (typeof content === 'function') {
105
- fileContent = await content();
106
- }
107
- else {
108
- fileContent = content;
109
- }
110
- const ext = (0, path_1.extname)(path);
111
- if (ext === '.json') {
112
- let json;
113
- if (fileContent instanceof ReadableStream) {
114
- json = '';
115
- for await (const chunk of stream_1.Readable.fromWeb(fileContent, {
116
- encoding: 'utf-8',
117
- })) {
118
- json += chunk;
119
- }
120
- }
121
- else {
122
- json = JSON.stringify(content, undefined, options.pretty ? 2 : undefined);
123
- }
124
- return {
125
- path,
126
- content: json,
127
- sha256: () => (0, base64_js_1.fromByteArray)(new Uint8Array((0, hash_js_1.sha256)().update(json).digest())),
128
- };
129
- }
130
- else if (ext === '.mp3') {
131
- if (fileContent instanceof ReadableStream) {
132
- return {
133
- path,
134
- content: stream_1.Readable.fromWeb(fileContent),
135
- };
136
- }
137
- else {
138
- console.warn('Expected content to be a readable stream for', path);
139
- console.warn('Skipping file');
140
- return null;
141
- }
142
- }
143
- console.warn('Unknown file type', path);
144
- console.warn('Skipping file');
145
- return null;
146
- }
147
- /**
148
- * Loads the files for the given translations.
149
- * @param dir The directory that the translations exist in.
150
- */
151
- async function loadTranslationsFiles(dirs) {
152
- const promises = [];
153
- for (let dir of dirs) {
154
- const fullPath = path.resolve(dir);
155
- promises.push(loadTranslationFiles(fullPath));
156
- }
157
- const allFiles = await Promise.all(promises);
158
- const files = allFiles.flat();
159
- return files;
160
- }
161
- /**
162
- * Loads the files for the given translation.
163
- * @param translation The directory that the translation exists in.
164
- * @returns
165
- */
166
- async function loadTranslationFiles(translation) {
167
- const metadata = await loadTranslationMetadata(translation);
168
- if (!metadata) {
169
- console.error('Could not load metadata for translation!', translation);
170
- return [];
171
- }
172
- let files = await (0, promises_1.readdir)(translation);
173
- let usfmFiles = files.filter((f) => (0, path_1.extname)(f) === '.usfm' ||
174
- (0, path_1.extname)(f) === '.usx' ||
175
- (0, path_1.extname)(f) === '.json');
176
- if (usfmFiles.length <= 0) {
177
- translation = path.resolve(translation, 'usfm');
178
- if ((0, fs_extra_1.existsSync)(translation)) {
179
- files = await (0, promises_1.readdir)(translation);
180
- usfmFiles = files.filter((f) => (0, path_1.extname)(f) === '.usfm');
181
- }
182
- }
183
- if (usfmFiles.length <= 0) {
184
- console.error('Could not find USFM files for translation!', translation);
185
- return [];
186
- }
187
- let promises = [];
188
- for (let file of usfmFiles) {
189
- if (path.parse(file).name === 'metadata') {
190
- continue;
191
- }
192
- const filePath = path.resolve(translation, file);
193
- promises.push(loadFile(filePath, {
194
- translation: metadata,
195
- }));
196
- }
197
- return await Promise.all(promises);
198
- }
199
- /**
200
- * Loads the metadata for the given translation.
201
- * @param translation The translation that the metadata should be loaded for.
202
- * @returns
203
- */
204
- async function loadTranslationMetadata(translation) {
205
- const metadataTs = path.resolve(translation, 'metadata.ts');
206
- if ((0, fs_extra_1.existsSync)(metadataTs)) {
207
- return (await Promise.resolve(`${metadataTs}`).then(s => __importStar(require(s)))).default;
208
- }
209
- else {
210
- const metadataJson = path.resolve(translation, 'meta.json');
211
- if ((0, fs_extra_1.existsSync)(metadataJson)) {
212
- const data = await (0, promises_1.readFile)(metadataJson, { encoding: 'utf-8' });
213
- const metadata = JSON.parse(data);
214
- return {
215
- id: metadata.id ?? metadata.source.id,
216
- language: metadata.language,
217
- name: metadata.name.local,
218
- englishName: metadata.name.english,
219
- licenseUrl: metadata.copyright.attribution_url,
220
- website: metadata.copyright.attribution_url,
221
- shortName: metadata.name.abbrev,
222
- direction: metadata.direction,
223
- };
224
- }
225
- else {
226
- const metadataJson = path.resolve(translation, 'metadata.json');
227
- if ((0, fs_extra_1.existsSync)(metadataJson)) {
228
- const data = await (0, promises_1.readFile)(metadataJson, {
229
- encoding: 'utf-8',
230
- });
231
- return JSON.parse(data);
232
- }
233
- }
234
- }
235
- console.error('Could not find metadata for translation!', translation);
236
- return null;
237
- }
238
- /**
239
- * Loads the file from the given path using the given metadata.
240
- * @param file The file that should be loaded.
241
- * @param metadata The metadata.
242
- */
243
- async function loadFile(file, metadata) {
244
- const extension = path.extname(file);
245
- const content = await (0, promises_1.readFile)(file, {
246
- encoding: 'utf-8',
247
- });
248
- const hash = (0, hash_js_1.sha256)()
249
- .update(content)
250
- // Hack to ensure that file hashes are different for different versions of the parser.
251
- .update(usx_parser_1.PARSER_VERSION)
252
- .digest('hex');
253
- return {
254
- content,
255
- metadata: metadata,
256
- name: file,
257
- sha256: hash,
258
- fileType: extension.slice(1),
259
- };
260
- }
261
- /**
262
- * Defines an uploader that is able to upload files to a directory.
263
- */
264
- class FilesUploader {
265
- _dir;
266
- constructor(dir) {
267
- this._dir = dir;
268
- }
269
- get idealBatchSize() {
270
- return null;
271
- }
272
- async upload(file, overwrite) {
273
- const filePath = path.resolve(this._dir, makeRelativePath(file.path));
274
- await (0, promises_1.mkdir)(path.dirname(filePath), { recursive: true });
275
- if (overwrite || !(0, fs_extra_1.existsSync)(filePath)) {
276
- await (0, promises_1.writeFile)(filePath, file.content, 'utf-8');
277
- return true;
278
- }
279
- return false;
280
- }
281
- }
282
- exports.FilesUploader = FilesUploader;
283
- /**
284
- * Defines an uploader that is able to upload files into a zip file.
285
- */
286
- class ZipUploader {
287
- _path;
288
- _initPromise;
289
- _fileHandle = null;
290
- _zip = null;
291
- constructor(filePath) {
292
- this._path = filePath;
293
- this._initPromise = this._init();
294
- }
295
- async _init() {
296
- this._fileHandle = await (0, promises_1.open)(path.resolve(this._path), 'w');
297
- const writableStream = this._fileHandle.createWriteStream();
298
- this._zip = new zip_js_1.ZipWriter(stream_1.Writable.toWeb(writableStream));
299
- return this._zip;
300
- }
301
- get idealBatchSize() {
302
- return 50;
303
- }
304
- async upload(file, _overwrite) {
305
- const zip = await this._initPromise;
306
- let reader;
307
- if (file.content instanceof stream_1.Readable) {
308
- reader = stream_1.Readable.toWeb(file.content);
309
- }
310
- else if (typeof file.content === 'string') {
311
- reader = new zip_js_1.TextReader(file.content);
312
- }
313
- else {
314
- throw new Error('Unknown file content type');
315
- }
316
- await zip.add(trimRelativePath(file.path), reader);
317
- return true;
318
- }
319
- async dispose() {
320
- if (this._zip) {
321
- await this._zip.close();
322
- }
323
- if (this._fileHandle) {
324
- await this._fileHandle.close();
325
- }
326
- }
327
- }
328
- exports.ZipUploader = ZipUploader;
329
- function trimRelativePath(path) {
330
- if (path.startsWith('./')) {
331
- return path.substring(2);
332
- }
333
- else if (path.startsWith('../')) {
334
- return path.substring(3);
335
- }
336
- else if (path.startsWith('/')) {
337
- return path.substring(1);
338
- }
339
- return path;
340
- }
341
- function makeRelativePath(path) {
342
- if (path.startsWith('/')) {
343
- return '.' + path;
344
- }
345
- return path;
346
- }
347
- /**
348
- * Calculates the SHa256 hash of the given input files.
349
- * @param files The files to hash.
350
- */
351
- function hashInputFiles(files) {
352
- let sha = (0, hash_js_1.sha256)();
353
- for (let file of files) {
354
- if (file.sha256) {
355
- sha.update(file.sha256);
356
- }
357
- else {
358
- sha.update(file.content);
359
- }
360
- }
361
- return sha.digest('hex');
362
- }
package/index.d.ts DELETED
@@ -1,8 +0,0 @@
1
- import * as db from './db';
2
- import * as downloads from './downloads';
3
- import * as uploads from './uploads';
4
- import * as actions from './actions';
5
- import * as files from './files';
6
- import * as s3 from './s3';
7
- export { db, downloads, uploads, actions, files, s3, };
8
- //# sourceMappingURL=index.d.ts.map
package/index.js DELETED
@@ -1,38 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.s3 = exports.files = exports.actions = exports.uploads = exports.downloads = exports.db = void 0;
27
- const db = __importStar(require("./db"));
28
- exports.db = db;
29
- const downloads = __importStar(require("./downloads"));
30
- exports.downloads = downloads;
31
- const uploads = __importStar(require("./uploads"));
32
- exports.uploads = uploads;
33
- const actions = __importStar(require("./actions"));
34
- exports.actions = actions;
35
- const files = __importStar(require("./files"));
36
- exports.files = files;
37
- const s3 = __importStar(require("./s3"));
38
- exports.s3 = s3;
package/s3.js DELETED
@@ -1,169 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.askForAccessKeyProvider = exports.S3Uploader = void 0;
4
- exports.parseS3Url = parseS3Url;
5
- exports.getHttpUrl = getHttpUrl;
6
- exports.providerChain = providerChain;
7
- exports.defaultProviderForOptions = defaultProviderForOptions;
8
- const client_s3_1 = require("@aws-sdk/client-s3");
9
- const credential_providers_1 = require("@aws-sdk/credential-providers"); // ES6 import
10
- const prompts_1 = require("@inquirer/prompts");
11
- class S3Uploader {
12
- _client;
13
- _bucketName;
14
- _keyPrefix;
15
- get idealBatchSize() {
16
- return 50;
17
- }
18
- constructor(bucketName, keyPrefix, profile) {
19
- this._bucketName = bucketName;
20
- this._keyPrefix = keyPrefix;
21
- this._client = new client_s3_1.S3Client({
22
- credentials: !profile || typeof profile === 'string'
23
- ? (0, credential_providers_1.fromNodeProviderChain)({ profile: profile ?? undefined })
24
- : profile,
25
- });
26
- }
27
- async upload(file, overwrite) {
28
- const path = file.path.startsWith('/')
29
- ? file.path.substring(1)
30
- : file.path;
31
- const key = this._keyPrefix ? `${this._keyPrefix}/${path}` : path;
32
- const hash = file.sha256?.();
33
- const head = new client_s3_1.HeadObjectCommand({
34
- Bucket: this._bucketName,
35
- Key: key,
36
- ChecksumMode: 'ENABLED',
37
- });
38
- if (hash || !overwrite) {
39
- try {
40
- const existingFile = await this._client.send(head);
41
- let matches = true;
42
- if (hash && existingFile.ChecksumSHA256) {
43
- if (hash.localeCompare(existingFile?.ChecksumSHA256 ?? '', undefined, {
44
- sensitivity: 'base',
45
- }) === 0) {
46
- // File is already uploaded and matches the checksum.
47
- return false;
48
- }
49
- else {
50
- // File is already uploaded but the checksums don't match.
51
- matches = false;
52
- }
53
- }
54
- else {
55
- // File is already uploaded but the checksum is not available.
56
- console.log(`[s3] Checksum not available: ${key}`);
57
- }
58
- if (matches && !overwrite) {
59
- return false;
60
- }
61
- }
62
- catch (err) {
63
- if (err instanceof client_s3_1.NotFound) {
64
- // not found, so we can try to write the file.
65
- }
66
- else {
67
- throw err;
68
- }
69
- }
70
- }
71
- const command = new client_s3_1.PutObjectCommand({
72
- Bucket: this._bucketName,
73
- Key: key,
74
- Body: file.content,
75
- ContentType: 'application/json',
76
- ChecksumSHA256: hash,
77
- ChecksumAlgorithm: 'SHA256',
78
- });
79
- await this._client.send(command);
80
- return true;
81
- }
82
- }
83
- exports.S3Uploader = S3Uploader;
84
- /**
85
- * Parses the given S3 URL into its bucket name and object key.
86
- * @param url The URL to parse.
87
- */
88
- function parseS3Url(url) {
89
- const regex = /^s3:\/\/([a-z0-9.\-]+)(\/[^${}]*)?$/;
90
- const matched = url.match(regex);
91
- if (matched) {
92
- const arr = [...matched];
93
- let key = arr[2] ?? '';
94
- if (key.startsWith('/')) {
95
- key = key.substring(1);
96
- }
97
- return {
98
- bucketName: arr[1],
99
- objectKey: key,
100
- };
101
- }
102
- return undefined;
103
- }
104
- /**
105
- * Gets the HTTP URL for the given S3 URL.
106
- * @param s3Url The S3 URL to convert.
107
- */
108
- function getHttpUrl(s3Url) {
109
- const parsed = parseS3Url(s3Url);
110
- if (!parsed) {
111
- return undefined;
112
- }
113
- const { bucketName, objectKey } = parsed;
114
- if (objectKey) {
115
- return `https://${bucketName}.s3.amazonaws.com/${objectKey}`;
116
- }
117
- else {
118
- return `https://${bucketName}.s3.amazonaws.com`;
119
- }
120
- }
121
- /**
122
- * A provider that gets the credentials directly from the user input.
123
- */
124
- const askForAccessKeyProvider = async () => {
125
- const accessKeyId = await (0, prompts_1.input)({
126
- message: 'Enter your AWS Access Key ID',
127
- });
128
- const secretAccessKey = await (0, prompts_1.password)({
129
- message: 'Enter your AWS Secret Access Key',
130
- });
131
- return {
132
- accessKeyId,
133
- secretAccessKey,
134
- };
135
- };
136
- exports.askForAccessKeyProvider = askForAccessKeyProvider;
137
- /**
138
- * Defines a provider that tries to get the credentials from the given list of providers.
139
- * @param providers The providers to try.
140
- */
141
- function providerChain(...providers) {
142
- return async () => {
143
- for (const provider of providers) {
144
- const creds = await provider();
145
- if (creds?.accessKeyId && creds?.secretAccessKey) {
146
- return creds;
147
- }
148
- }
149
- return {
150
- accessKeyId: '',
151
- secretAccessKey: '',
152
- };
153
- };
154
- }
155
- /**
156
- * Gets the default provider for the given options.
157
- *
158
- * Defaults first to using the provided access key and secret access key, then to using the given profile, then finally to asking the user for the access key.
159
- * @param options
160
- */
161
- function defaultProviderForOptions(options) {
162
- if (options.accessKeyId && options.secretAccessKey) {
163
- return {
164
- accessKeyId: options.accessKeyId,
165
- secretAccessKey: options.secretAccessKey,
166
- };
167
- }
168
- return providerChain((0, credential_providers_1.fromNodeProviderChain)({ profile: options.profile }), exports.askForAccessKeyProvider);
169
- }