@blocklet/cli 1.16.33 → 1.16.34-beta-20241120-080738-bbbe036c

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.
Files changed (87) hide show
  1. package/README.md +32 -25
  2. package/bin/blocklet.js +292 -1
  3. package/config.example.yml +33 -0
  4. package/lib/arcblock.js +53 -0
  5. package/lib/commands/blocklet/add.js +124 -0
  6. package/lib/commands/blocklet/assets/git-ignore +28 -0
  7. package/lib/commands/blocklet/assets/index.html +9 -0
  8. package/lib/commands/blocklet/assets/index.js +14 -0
  9. package/lib/commands/blocklet/assets/logo.png +0 -0
  10. package/lib/commands/blocklet/bundle/bundle.js +184 -0
  11. package/lib/commands/blocklet/bundle/bundlers/blocklet.js +138 -0
  12. package/lib/commands/blocklet/bundle/bundlers/changelog.js +100 -0
  13. package/lib/commands/blocklet/bundle/bundlers/logo.js +56 -0
  14. package/lib/commands/blocklet/bundle/bundlers/markdown.js +241 -0
  15. package/lib/commands/blocklet/bundle/bundlers/preference.js +50 -0
  16. package/lib/commands/blocklet/bundle/bundlers/readme.js +43 -0
  17. package/lib/commands/blocklet/bundle/bundlers/screenshots.js +94 -0
  18. package/lib/commands/blocklet/bundle/bundlers/simple.js +70 -0
  19. package/lib/commands/blocklet/bundle/compact/bundle-compact-file.js +48 -0
  20. package/lib/commands/blocklet/bundle/compact/bundle-merge-extra.js +66 -0
  21. package/lib/commands/blocklet/bundle/compact/default-external.js +5 -0
  22. package/lib/commands/blocklet/bundle/compact/index.js +88 -0
  23. package/lib/commands/blocklet/bundle/index.js +139 -0
  24. package/lib/commands/blocklet/bundle/pack.js +8 -0
  25. package/lib/commands/blocklet/bundle/parse-external-dependencies.js +97 -0
  26. package/lib/commands/blocklet/bundle/simple/index.js +62 -0
  27. package/lib/commands/blocklet/bundle/zip/archive.js +35 -0
  28. package/lib/commands/blocklet/bundle/zip/dependencies.js +333 -0
  29. package/lib/commands/blocklet/bundle/zip/index.js +165 -0
  30. package/lib/commands/blocklet/bundle/zip/main.js +124 -0
  31. package/lib/commands/blocklet/bundle/zip/node.js +59 -0
  32. package/lib/commands/blocklet/bundle/zip/resolve.js +93 -0
  33. package/lib/commands/blocklet/cleanup.js +52 -0
  34. package/lib/commands/blocklet/config.js +108 -0
  35. package/lib/commands/blocklet/connect.js +87 -0
  36. package/lib/commands/blocklet/create.js +38 -0
  37. package/lib/commands/blocklet/deploy.js +435 -0
  38. package/lib/commands/blocklet/dev.js +1000 -0
  39. package/lib/commands/blocklet/document.js +39 -0
  40. package/lib/commands/blocklet/exec.js +106 -0
  41. package/lib/commands/blocklet/init.js +300 -0
  42. package/lib/commands/blocklet/meta.js +22 -0
  43. package/lib/commands/blocklet/remove.js +35 -0
  44. package/lib/commands/blocklet/test.js +201 -0
  45. package/lib/commands/blocklet/upload.js +105 -0
  46. package/lib/commands/blocklet/version.js +81 -0
  47. package/lib/commands/server/cleanup.js +32 -0
  48. package/lib/commands/server/command.js +131 -0
  49. package/lib/commands/server/info.js +92 -0
  50. package/lib/commands/server/init.js +433 -0
  51. package/lib/commands/server/logs.js +99 -0
  52. package/lib/commands/server/rescue.js +71 -0
  53. package/lib/commands/server/start.js +821 -0
  54. package/lib/commands/server/status.js +107 -0
  55. package/lib/commands/server/stop.js +163 -0
  56. package/lib/commands/server/upgrade.js +123 -0
  57. package/lib/constant.js +21 -2
  58. package/lib/debug.js +20 -0
  59. package/lib/manager/config.js +122 -0
  60. package/lib/manager/deploy.js +75 -0
  61. package/lib/manager/index.js +23 -0
  62. package/lib/manager/process.js +47 -0
  63. package/lib/node.js +214 -0
  64. package/lib/port.js +19 -0
  65. package/lib/postinstall.js +3 -0
  66. package/lib/process/daemon.js +196 -0
  67. package/lib/process/service.js +86 -0
  68. package/lib/ui.js +137 -0
  69. package/lib/util/blocklet/config.js +78 -0
  70. package/lib/util/blocklet/env.js +172 -0
  71. package/lib/util/blocklet/meta.js +36 -0
  72. package/lib/util/blocklet/payment.js +88 -0
  73. package/lib/util/blocklet/sign.js +21 -0
  74. package/lib/util/blocklet/tar.js +119 -0
  75. package/lib/util/convert-to-nosources-sourcemap.js +37 -0
  76. package/lib/util/docker-status-log.js +17 -0
  77. package/lib/util/exit-when-server-stopped.js +44 -0
  78. package/lib/util/get-cli-binary-name.js +8 -0
  79. package/lib/util/get-download-bundle-step.js +36 -0
  80. package/lib/util/get-service-instance-number.js +12 -0
  81. package/lib/util/index.js +626 -0
  82. package/lib/util/print-error.js +11 -0
  83. package/lib/util/print.js +9 -0
  84. package/lib/util/what-uri.js +40 -0
  85. package/package.json +123 -27
  86. package/lib/run.d.ts +0 -2
  87. package/lib/run.js +0 -73
@@ -0,0 +1,333 @@
1
+ /* eslint-disable no-use-before-define */
2
+ /* eslint-disable func-names */
3
+ const { dirname, basename, normalize, extname } = require('path');
4
+
5
+ const { glob } = require('glob');
6
+ const { not: notJunk } = require('junk');
7
+ const pkgDir = require('pkg-dir');
8
+ const precinct = require('precinct');
9
+ const requirePackageName = require('require-package-name');
10
+ const formatBackSlash = require('@abtnode/util/lib/format-back-slash');
11
+
12
+ const debug = require('../../../../debug')('bundle:zip');
13
+ const { resolvePathPreserveSymlinks, resolvePackage } = require('./resolve');
14
+
15
+ // Retrieve the paths to the Node.js files to zip.
16
+ // We only include the files actually needed by the function because AWS Lambda
17
+ // has a size limit for the zipped file. It also makes cold starts faster.
18
+ const listNodeFiles = async function ({ srcPath, mainFile, srcDir, stat, extraPaths }) {
19
+ const [treeFiles, depFiles] = await Promise.all([getTreeFiles(srcPath, stat), getDependencies(mainFile, srcDir)]);
20
+ const extraFiles = [];
21
+ for (let i = 0; i < extraPaths.length; i++) {
22
+ const extraPath = extraPaths[i];
23
+ const extension = extname(extraPath);
24
+ if (extension === '.js') {
25
+ // eslint-disable-next-line no-await-in-loop
26
+ const [extraTreeFiles, extraDepFiles] = await Promise.all([
27
+ getTreeFiles(extraPath, stat),
28
+ getDependencies(extraPath, srcDir),
29
+ ]);
30
+ extraFiles.push(...extraTreeFiles);
31
+ extraFiles.push(...extraDepFiles);
32
+ } else {
33
+ extraFiles.push(extraPath);
34
+ }
35
+ }
36
+
37
+ const files = [...treeFiles, ...depFiles, ...extraFiles].map(normalize);
38
+
39
+ const uniqueFiles = [...new Set(files)];
40
+
41
+ // We sort so that the archive's checksum is deterministic.
42
+ const filteredFiles = uniqueFiles.filter(isNotJunk).sort();
43
+ debug('listNodeFiles', {
44
+ srcPath,
45
+ mainFile,
46
+ extraPaths,
47
+ uniqueFiles: uniqueFiles.length,
48
+ filteredFiles: filteredFiles.length,
49
+ });
50
+
51
+ return filteredFiles;
52
+ };
53
+
54
+ // When using a directory, we include all its descendants except `node_modules`
55
+ const getTreeFiles = function (srcPath, stat) {
56
+ if (!stat.isDirectory()) {
57
+ return [srcPath];
58
+ }
59
+
60
+ const tmpPath = formatBackSlash(srcPath);
61
+ return glob(`${tmpPath}/**`, {
62
+ ignore: `${tmpPath}/**/node_modules/**`,
63
+ nodir: true,
64
+ absolute: true,
65
+ });
66
+ };
67
+
68
+ // Remove temporary files like *~, *.swp, etc.
69
+ const isNotJunk = function (file) {
70
+ if (file.includes('.pnpm')) {
71
+ console.warn('Maybe a dependency is missing in your package.json', file);
72
+ }
73
+ return file.includes('.pnpm') === false && notJunk(basename(file));
74
+ };
75
+
76
+ // Retrieve all the files recursively required by a Node.js file
77
+ const getDependencies = async function (mainFile, srcDir) {
78
+ const packageRoot = await pkgDir(srcDir);
79
+ const packageJson = getPackageJson(packageRoot);
80
+
81
+ const state = { localFiles: [], modulePaths: [] };
82
+
83
+ try {
84
+ return await getFileDependencies(mainFile, packageJson, state);
85
+ } catch (error) {
86
+ error.message = `In file "${mainFile}": ${error.message}`;
87
+ throw error;
88
+ }
89
+ };
90
+
91
+ const getPackageJson = function (packageRoot) {
92
+ if (packageRoot === undefined) {
93
+ return {};
94
+ }
95
+
96
+ const packageJsonPath = `${packageRoot}/package.json`;
97
+ try {
98
+ // eslint-disable-next-line
99
+ return require(packageJsonPath);
100
+ } catch (error) {
101
+ throw new Error(`${packageJsonPath} is invalid JSON: ${error.message}`);
102
+ }
103
+ };
104
+
105
+ const getFileDependencies = async function (path, packageJson, state) {
106
+ if (state.localFiles.includes(path)) {
107
+ return [];
108
+ }
109
+
110
+ state.localFiles.push(path);
111
+
112
+ const basedir = dirname(path);
113
+ // This parses JavaScript in `path` to retrieve all the `require()` statements
114
+ // TODO: `precinct.paperwork()` uses `fs.readFileSync()` under the hood,
115
+ // but should use `fs.readFile()` instead
116
+ const dependencies = precinct.paperwork(path, { includeCore: false });
117
+
118
+ const depsPaths = await Promise.all(
119
+ dependencies.map((dependency) => getImportDependencies(dependency, basedir, packageJson, state))
120
+ );
121
+ // debug('getFileDependencies', { path, depsPaths });
122
+ return [].concat(...depsPaths);
123
+ };
124
+
125
+ // `require()` statements can be either `require('moduleName')` or
126
+ // `require(path)`
127
+ const getImportDependencies = function (dependency, basedir, packageJson, state) {
128
+ if (LOCAL_IMPORT_REGEXP.test(dependency)) {
129
+ return getLocalImportDependencies(dependency, basedir, packageJson, state);
130
+ }
131
+
132
+ return getModuleDependencies(dependency, basedir, state, packageJson);
133
+ };
134
+
135
+ const LOCAL_IMPORT_REGEXP = /^(\.|\/)/;
136
+
137
+ // When a file requires another one, we apply the top-level logic recursively
138
+ const getLocalImportDependencies = async function (dependency, basedir, packageJson, state) {
139
+ const dependencyPath = await resolvePathPreserveSymlinks(dependency, basedir);
140
+ const depsPath = await getFileDependencies(dependencyPath, packageJson, state);
141
+ return [dependencyPath, ...depsPath];
142
+ };
143
+
144
+ // When a file requires a module, we find its path inside `node_modules` and
145
+ // use all its published files. We also recurse on the module's dependencies.
146
+ const getModuleDependencies = async function (dependency, basedir, state, packageJson) {
147
+ const moduleName = getModuleName(dependency);
148
+
149
+ // Happens when doing require("@scope") (not "@scope/name") or other oddities
150
+ // Ignore those.
151
+ if (moduleName === null) {
152
+ return [];
153
+ }
154
+
155
+ try {
156
+ return await getModuleNameDependencies(moduleName, basedir, state);
157
+ } catch (error) {
158
+ return handleModuleNotFound({ error, moduleName, packageJson });
159
+ }
160
+ };
161
+
162
+ // When doing require("moduleName/file/path"), only keep `moduleName`
163
+ const getModuleName = function (dependency) {
164
+ const dependencyA = dependency.replace(BACKSLASH_REGEXP, '/');
165
+ const moduleName = requirePackageName(dependencyA);
166
+ return moduleName;
167
+ };
168
+
169
+ // Windows path normalization
170
+ const BACKSLASH_REGEXP = /\\/g;
171
+
172
+ const getModuleNameDependencies = async function (moduleName, basedir, state) {
173
+ if (isExcludedModule(moduleName)) {
174
+ return [];
175
+ }
176
+
177
+ // Find the Node.js module directory path
178
+ const packagePath = await resolvePackage(moduleName, basedir);
179
+
180
+ if (packagePath === undefined) {
181
+ return [];
182
+ }
183
+
184
+ const modulePath = dirname(packagePath);
185
+
186
+ if (state.modulePaths.includes(modulePath)) {
187
+ return [];
188
+ }
189
+
190
+ state.modulePaths.push(modulePath);
191
+
192
+ // eslint-disable-next-line
193
+ const pkg = require(packagePath);
194
+
195
+ const [publishedFiles, sideFiles, depsPaths] = await Promise.all([
196
+ getPublishedFiles(modulePath),
197
+ getSideFiles(modulePath, moduleName),
198
+ getNestedModules(modulePath, state, pkg),
199
+ ]);
200
+ // debug('getModuleNameDependencies', { moduleName, basedir, packagePath, modulePath, publishedFiles, depsPaths });
201
+ return [...publishedFiles, ...sideFiles, ...depsPaths];
202
+ };
203
+
204
+ const EXCLUDED_MODULES = [];
205
+ const isExcludedModule = function (moduleName) {
206
+ return (
207
+ EXCLUDED_MODULES.includes(moduleName) || moduleName.startsWith('@types/') || moduleName.startsWith('@cypress/')
208
+ );
209
+ };
210
+
211
+ // Some modules generate source files on `postinstall` that are not located
212
+ // inside the module's directory itself.
213
+ const getSideFiles = function (modulePath, moduleName) {
214
+ const sideFiles = SIDE_FILES[moduleName];
215
+ if (sideFiles === undefined) {
216
+ return [];
217
+ }
218
+
219
+ return getPublishedFiles(`${modulePath}/${sideFiles}`);
220
+ };
221
+
222
+ const SIDE_FILES = {
223
+ '@prisma/client': '../../.prisma',
224
+ };
225
+
226
+ // We use all the files published by the Node.js except some that are not needed
227
+ const getPublishedFiles = async function (modulePath) {
228
+ const ignore = getIgnoredFiles(modulePath);
229
+ const publishedFiles = await glob(formatBackSlash(`${modulePath}/**`), {
230
+ ignore,
231
+ nodir: true,
232
+ absolute: true,
233
+ dot: false,
234
+ });
235
+ return publishedFiles;
236
+ };
237
+
238
+ const getIgnoredFiles = function (modulePath) {
239
+ return IGNORED_FILES.map((ignoreFile) => `${modulePath}/${ignoreFile}`);
240
+ };
241
+
242
+ // To make the zip archive smaller, we remove those.
243
+ const IGNORED_FILES = [
244
+ 'node_modules/**',
245
+ '.blocklet/**',
246
+ '.abtnode/**',
247
+ 'coverage/**',
248
+ 'tests/**',
249
+ 'test/**',
250
+ 'doc/**',
251
+ 'docs/**',
252
+ '.npmignore',
253
+ 'package-lock.json',
254
+ 'yarn.lock',
255
+ '**/*.js.map',
256
+ '**/*.css.map',
257
+ '**/*.d.ts',
258
+ '**/*.d.ts.map',
259
+ '*.log',
260
+ '*.lock',
261
+ '*~',
262
+ '*.ts',
263
+ '*.patch',
264
+ ];
265
+
266
+ // Apply the Node.js module logic recursively on its own dependencies, using
267
+ // the `package.json` `dependencies`, `peerDependencies` and
268
+ // `optionalDependencies` keys
269
+ const getNestedModules = async function (modulePath, state, pkg) {
270
+ const dependencies = getNestedDependencies(pkg);
271
+ const depsPaths = await Promise.all(
272
+ dependencies.map((dependency) => getModuleDependencies(dependency, modulePath, state, pkg))
273
+ );
274
+ return [].concat(...depsPaths);
275
+ };
276
+
277
+ const getNestedDependencies = function ({ dependencies = {}, peerDependencies = {}, optionalDependencies = {} }) {
278
+ return [
279
+ ...Object.keys(dependencies),
280
+ ...Object.keys(peerDependencies).filter(shouldIncludePeerDependency),
281
+ ...Object.keys(optionalDependencies),
282
+ ];
283
+ };
284
+
285
+ const shouldIncludePeerDependency = function (name) {
286
+ return !EXCLUDED_PEER_DEPENDENCIES.includes(name);
287
+ };
288
+
289
+ const EXCLUDED_PEER_DEPENDENCIES = ['@prisma/cli', 'prisma2'];
290
+
291
+ // Modules can be required conditionally (inside an `if` or `try`/`catch` block).
292
+ // When a `require()` statement is found but the module is not found, it is
293
+ // possible that that block either always evaluates to:
294
+ // - `false`: in which case, we should not bundle the dependency
295
+ // - `true`: in which case, we should report the dependency as missing
296
+ // Those conditional modules might be:
297
+ // - present in the `package.json` `dependencies`
298
+ // - present in the `package.json` `optionalDependencies`
299
+ // - present in the `package.json` `peerDependencies`
300
+ // - not present in the `package.json`, if the module author wants its users
301
+ // to explicitly install it as an optional dependency.
302
+ // The current implementation:
303
+ // - when parsing `require()` statements inside function files, always consider
304
+ // conditional modules to be included, i.e. report them if not found.
305
+ // This is because our current parsing logic does not know whether a
306
+ // `require()` is conditional or not.
307
+ // - when parsing module dependencies, ignore `require()` statements if not
308
+ // present in the `package.json` `*dependencies`. I.e. user must manually
309
+ // install them if the module is used.
310
+ // `optionalDependencies`:
311
+ // - are not reported when missing
312
+ // - are included in module dependencies
313
+ const handleModuleNotFound = function ({ error, moduleName, packageJson }) {
314
+ if (error.code === 'MODULE_NOT_FOUND' && isOptionalModule(moduleName, packageJson)) {
315
+ return [];
316
+ }
317
+
318
+ throw error;
319
+ };
320
+
321
+ const isOptionalModule = function (
322
+ moduleName,
323
+ { optionalDependencies = {}, peerDependenciesMeta = {}, peerDependencies = {} }
324
+ ) {
325
+ return (
326
+ optionalDependencies[moduleName] !== undefined ||
327
+ (peerDependenciesMeta[moduleName] &&
328
+ peerDependenciesMeta[moduleName].optional &&
329
+ peerDependencies[moduleName] !== undefined)
330
+ );
331
+ };
332
+
333
+ module.exports = { listNodeFiles };
@@ -0,0 +1,165 @@
1
+ /* eslint-disable no-console */
2
+ const fs = require('fs-extra');
3
+ const chalk = require('chalk');
4
+ const { join, dirname, basename, extname, relative } = require('path');
5
+ const { BLOCKLET_BUNDLE_FOLDER, BLOCKLET_BUNDLE_FILE, BLOCKLET_ENTRY_FILE } = require('@blocklet/constant');
6
+ const parseBlockletMeta = require('@blocklet/meta/lib/parse');
7
+ const detectWorkspace = require('@abtnode/util/lib/detect-workspace');
8
+
9
+ const { print, printInfo, printSuccess, printError } = require('../../../../util');
10
+ const { wrapSpinner } = require('../../../../ui');
11
+ const main = require('./main');
12
+ const pack = require('../pack');
13
+ const { createBlockletBundle, createBlockletEntry, getExtraFiles } = require('../bundle');
14
+ const { logTar, getContents } = require('../../../../util/blocklet/tar');
15
+
16
+ const debug = require('../../../../debug')('bundle:zip');
17
+
18
+ module.exports.run = async ({
19
+ meta,
20
+ blockletDir,
21
+ createRelease = false,
22
+ inMonoRepo = false,
23
+ withChangeLog = true,
24
+ externals = [],
25
+ externalManager = 'npm',
26
+ }) => {
27
+ // eslint-disable-next-line no-param-reassign
28
+ meta = meta || parseBlockletMeta(blockletDir, { ensureFiles: true });
29
+
30
+ const destFolder = join(blockletDir, BLOCKLET_BUNDLE_FOLDER);
31
+
32
+ if (fs.existsSync(destFolder)) {
33
+ fs.removeSync(destFolder);
34
+ } else {
35
+ fs.mkdirSync(destFolder, { recursive: true });
36
+ }
37
+
38
+ const workspace = detectWorkspace(blockletDir);
39
+ const extraFiles = getExtraFiles(blockletDir, meta);
40
+
41
+ const zipConfig = {
42
+ options: {},
43
+ destFolder,
44
+ extraPaths: [],
45
+ skippable: true,
46
+ };
47
+
48
+ const mainPath = join(blockletDir, meta.main || '/');
49
+ const hasMainFile = fs.statSync(mainPath).isFile();
50
+
51
+ // 1. for dapp entry
52
+ if (hasMainFile) {
53
+ zipConfig.srcFolder = dirname(mainPath);
54
+ zipConfig.srcFile = basename(mainPath);
55
+ zipConfig.srcFilter = (x) => [zipConfig.srcFile].includes(x);
56
+ zipConfig.skippable = false;
57
+ }
58
+
59
+ // 2. for hook scripts
60
+ if (extraFiles.length) {
61
+ zipConfig.extraPaths = extraFiles.map((x) => join(blockletDir, x));
62
+ zipConfig.skippable = false;
63
+ }
64
+
65
+ // 3. static blocklets may also include hook scripts
66
+ if (!zipConfig.srcFile && extraFiles.length) {
67
+ const srcFile = zipConfig.extraPaths.shift();
68
+ zipConfig.srcFolder = dirname(srcFile);
69
+ zipConfig.srcFile = basename(srcFile);
70
+ zipConfig.srcFilter = (x) => [zipConfig.srcFile].includes(x);
71
+ zipConfig.skippable = false;
72
+ }
73
+ debug('config', zipConfig);
74
+ debug('workspace', workspace);
75
+
76
+ // 4. create zip bundles
77
+ let archive;
78
+ if (zipConfig.skippable === false) {
79
+ const archives = await wrapSpinner(`Bundle blocklet from entry: ${chalk.cyan(meta.main)}`, () =>
80
+ main.zipEntries(zipConfig)
81
+ );
82
+ debug('archives', archives);
83
+
84
+ [archive] = archives;
85
+ if (!archive) {
86
+ printError('Failed to create zipped bundle');
87
+ process.exit(1);
88
+ }
89
+ }
90
+
91
+ // 5. handle extraFiles
92
+ const entryParts = ['.'];
93
+ let relativePath = '';
94
+
95
+ if (inMonoRepo && workspace) {
96
+ relativePath = relative(workspace.dir, blockletDir);
97
+ } else if (archive) {
98
+ relativePath = relative(archive.prefix, blockletDir);
99
+ }
100
+ if (relativePath) {
101
+ entryParts.push(relativePath);
102
+ extraFiles.forEach((f) => {
103
+ if (extname(f) === '.js') {
104
+ const absoluteFilepath = join(blockletDir, BLOCKLET_BUNDLE_FOLDER, f);
105
+ fs.ensureDirSync(dirname(absoluteFilepath));
106
+
107
+ const requirePath = relative(
108
+ dirname(absoluteFilepath),
109
+ join(blockletDir, BLOCKLET_BUNDLE_FOLDER, relativePath, f)
110
+ );
111
+ fs.writeFileSync(absoluteFilepath, createBlockletEntry(blockletDir, requirePath));
112
+ }
113
+ });
114
+ }
115
+
116
+ // 6. produce a `blocklet.js` file
117
+ let outputFile;
118
+ if (hasMainFile) {
119
+ entryParts.push(meta.main);
120
+ outputFile = join(blockletDir, BLOCKLET_BUNDLE_FOLDER, BLOCKLET_ENTRY_FILE);
121
+ fs.writeFileSync(outputFile, createBlockletEntry(blockletDir, entryParts.filter(Boolean).join('/')));
122
+ }
123
+
124
+ // 7. rename bundle to blocklet.zip
125
+ let outputZip;
126
+ if (archive) {
127
+ outputZip = join(blockletDir, BLOCKLET_BUNDLE_FOLDER, BLOCKLET_BUNDLE_FILE);
128
+ fs.renameSync(archive.path, outputZip);
129
+ }
130
+
131
+ print('');
132
+ printInfo(`Source: ${mainPath}`);
133
+ if (outputFile) {
134
+ printInfo(`Entry: ${outputFile}`);
135
+ }
136
+ if (outputZip) {
137
+ printInfo(`Archive: ${outputZip}`);
138
+ }
139
+
140
+ // 8. create bundle
141
+ await wrapSpinner(`Creating blocklet bundle in ${chalk.cyan(BLOCKLET_BUNDLE_FOLDER)}...`, async () => {
142
+ await createBlockletBundle({
143
+ blockletDir,
144
+ meta,
145
+ updates: hasMainFile ? { main: basename(outputZip) } : {},
146
+ inMonoRepo,
147
+ withChangeLog,
148
+ externals,
149
+ externalManager,
150
+ });
151
+ });
152
+
153
+ printSuccess(`Blocklet ${chalk.cyan(`${meta.name}@${meta.version}`)} is successfully bundled!`);
154
+
155
+ // 9. create release
156
+ if (createRelease) {
157
+ print('');
158
+ // eslint-disable-next-line no-shadow
159
+ const { tarball, meta } = await pack(blockletDir);
160
+ const pkgContents = await getContents(meta, tarball);
161
+ logTar(pkgContents);
162
+ }
163
+
164
+ process.exit(0);
165
+ };
@@ -0,0 +1,124 @@
1
+ /* eslint-disable no-use-before-define */
2
+ /* eslint-disable func-names */
3
+ const { readdir, lstat } = require('fs');
4
+ const { join, resolve, dirname, basename, extname } = require('path');
5
+
6
+ const cpFile = require('cp-file');
7
+ const locatePath = require('locate-path');
8
+ const makeDir = require('make-dir');
9
+ const pMap = require('p-map');
10
+ const { promisify } = require('util');
11
+
12
+ const { listNodeFiles } = require('./dependencies');
13
+ const { zipNodeJs } = require('./node');
14
+
15
+ const debug = require('../../../../debug')('bundle:zip');
16
+
17
+ const pReaddir = promisify(readdir);
18
+ const pLstat = promisify(lstat);
19
+
20
+ // reduce `srcFolder/*` (Node.js files) to `destFolder/*.zip` so it can be used by Blocklet Server
21
+ const zipEntries = async function ({ srcFolder, destFolder, srcFilter, extraPaths, options = {} }) {
22
+ const { parallelLimit = 5 } = options;
23
+ const srcPaths = await getSrcPaths(srcFolder, srcFilter);
24
+
25
+ const zipped = await pMap(srcPaths, (srcPath) => zipEntry({ srcPath, destFolder, extraPaths }), {
26
+ concurrency: parallelLimit,
27
+ });
28
+ return zipped.filter(Boolean);
29
+ };
30
+
31
+ const zipEntry = async function ({ srcPath, destFolder, extraPaths }) {
32
+ const { runtime, filename, extension, srcDir, stat, mainFile } = await getEntryInfo(srcPath);
33
+
34
+ if (runtime === undefined) {
35
+ return;
36
+ }
37
+
38
+ const srcFiles = await getSrcFiles({ runtime, filename, stat, mainFile, extension, srcPath, srcDir, extraPaths });
39
+
40
+ await makeDir(destFolder);
41
+
42
+ if (runtime === 'js') {
43
+ if (extension === '.zip') {
44
+ const destPath = join(destFolder, filename);
45
+ await cpFile(srcPath, destPath);
46
+ // eslint-disable-next-line consistent-return
47
+ return { path: destPath, runtime };
48
+ }
49
+
50
+ const destPath = join(destFolder, `${basename(filename, '.js')}.zip`);
51
+ const prefix = await zipNodeJs(srcFiles, destPath, filename, mainFile);
52
+ // eslint-disable-next-line consistent-return
53
+ return { path: destPath, prefix, runtime };
54
+ }
55
+ };
56
+
57
+ const getSrcPaths = async function (srcFolder, srcFilter) {
58
+ if (!srcFolder) {
59
+ return [];
60
+ }
61
+ const filenames = await listFilenames(srcFolder);
62
+ const srcPaths = filenames.filter(srcFilter).map((x) => resolve(srcFolder, x));
63
+ debug('getSrcPaths', { srcFolder, srcPaths });
64
+ return srcPaths;
65
+ };
66
+
67
+ const listFilenames = async function (srcFolder) {
68
+ try {
69
+ return await pReaddir(srcFolder);
70
+ } catch (error) {
71
+ throw new Error(`entry folder does not exist: ${srcFolder}`);
72
+ }
73
+ };
74
+
75
+ const getEntryInfo = async function (srcPath) {
76
+ const { filename, stat, mainFile, extension, srcDir } = await getSrcInfo(srcPath);
77
+
78
+ if (mainFile === undefined) {
79
+ return {};
80
+ }
81
+
82
+ if (extension === '.zip' || extension === '.js') {
83
+ return { runtime: 'js', filename, stat, mainFile, extension, srcPath, srcDir };
84
+ }
85
+
86
+ return {};
87
+ };
88
+
89
+ const getSrcInfo = async function (srcPath) {
90
+ const filename = basename(srcPath);
91
+ if (filename === 'node_modules') {
92
+ return {};
93
+ }
94
+
95
+ const stat = await pLstat(srcPath);
96
+ const mainFile = await getMainFile(srcPath, filename, stat);
97
+ if (mainFile === undefined) {
98
+ return {};
99
+ }
100
+
101
+ const extension = extname(mainFile);
102
+ const srcDir = stat.isDirectory() ? srcPath : dirname(srcPath);
103
+ return { filename, stat, mainFile, extension, srcDir };
104
+ };
105
+
106
+ // Each `srcPath` can also be a directory with an `index.js` file or a file
107
+ // using the same filename as its directory
108
+ const getMainFile = function (srcPath, filename, stat) {
109
+ if (!stat.isDirectory()) {
110
+ return srcPath;
111
+ }
112
+
113
+ return locatePath([join(srcPath, `${filename}.js`), join(srcPath, 'index.js')], { type: 'file' });
114
+ };
115
+
116
+ const getSrcFiles = function ({ runtime, filename, stat, mainFile, extension, srcPath, srcDir, extraPaths }) {
117
+ if (runtime === 'js' && extension === '.js') {
118
+ return listNodeFiles({ srcPath, filename, mainFile, srcDir, stat, extraPaths });
119
+ }
120
+
121
+ return [srcPath];
122
+ };
123
+
124
+ module.exports = { zipEntries, zipEntry };
@@ -0,0 +1,59 @@
1
+ /* eslint-disable no-use-before-define */
2
+ /* eslint-disable func-names */
3
+ const { stat } = require('fs');
4
+ const { dirname, normalize, sep } = require('path');
5
+
6
+ const commonPathPrefix = require('common-path-prefix');
7
+ const unixify = require('unixify');
8
+ const { promisify } = require('util');
9
+
10
+ const { startZip, addZipFile, endZip } = require('./archive');
11
+
12
+ const pStat = promisify(stat);
13
+
14
+ // zip a Node.js function file
15
+ const zipNodeJs = async function (srcFiles, destPath) {
16
+ const { archive, output } = startZip(destPath);
17
+
18
+ const dirnames = srcFiles.map(dirname);
19
+ const commonPrefix = commonPathPrefix(dirnames);
20
+
21
+ const srcFilesInfos = await Promise.all(srcFiles.map(addStat));
22
+
23
+ // We ensure this is not async, so that the archive's checksum is
24
+ // deterministic. Otherwise it depends on the order the files were added.
25
+ // eslint-disable-next-line no-shadow
26
+ srcFilesInfos.forEach(({ srcFile, stat }) => {
27
+ zipJsFile({ srcFile, commonPrefix, archive, stat });
28
+ });
29
+
30
+ await endZip(archive, output);
31
+
32
+ return commonPrefix;
33
+ };
34
+
35
+ const addStat = async function (srcFile) {
36
+ // eslint-disable-next-line no-shadow
37
+ const stat = await pStat(srcFile);
38
+ return { srcFile, stat };
39
+ };
40
+
41
+ // eslint-disable-next-line no-shadow
42
+ const zipJsFile = function ({ srcFile, commonPrefix, archive, stat }) {
43
+ const filename = normalizeFilePath(srcFile, commonPrefix);
44
+ addZipFile(archive, srcFile, filename, stat);
45
+ };
46
+
47
+ // `adm-zip` and `require()` expect Unix paths.
48
+ // We remove the common path prefix.
49
+ // With files on different Windows drives, we remove the drive letter.
50
+ const normalizeFilePath = function (path, commonPrefix) {
51
+ const pathA = normalize(path);
52
+ const pathB = pathA.replace(commonPrefix, `${ZIP_ROOT_DIR}${sep}`);
53
+ const pathC = unixify(pathB);
54
+ return pathC;
55
+ };
56
+
57
+ const ZIP_ROOT_DIR = '.';
58
+
59
+ module.exports = { zipNodeJs, ZIP_ROOT_DIR };