@diquattro/cfnassets 0.6.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.
Files changed (178) hide show
  1. package/README.md +55 -0
  2. package/lib/cli/build.d.ts +3 -0
  3. package/lib/cli/build.d.ts.map +1 -0
  4. package/lib/cli/build.js +77 -0
  5. package/lib/cli/build.js.map +1 -0
  6. package/lib/cli/cfnassets.d.ts +3 -0
  7. package/lib/cli/cfnassets.d.ts.map +1 -0
  8. package/lib/cli/cfnassets.js +7 -0
  9. package/lib/cli/cfnassets.js.map +1 -0
  10. package/lib/core/rollup/makeRollupPackageStream.d.ts +16 -0
  11. package/lib/core/rollup/makeRollupPackageStream.d.ts.map +1 -0
  12. package/lib/core/rollup/makeRollupPackageStream.js +27 -0
  13. package/lib/core/rollup/makeRollupPackageStream.js.map +1 -0
  14. package/lib/core/rollup/rollupPackageDir.d.ts +14 -0
  15. package/lib/core/rollup/rollupPackageDir.d.ts.map +1 -0
  16. package/lib/core/rollup/rollupPackageDir.js +36 -0
  17. package/lib/core/rollup/rollupPackageDir.js.map +1 -0
  18. package/lib/core/rollup/rollupPackageEntries.d.ts +5 -0
  19. package/lib/core/rollup/rollupPackageEntries.d.ts.map +1 -0
  20. package/lib/core/rollup/rollupPackageEntries.js +35 -0
  21. package/lib/core/rollup/rollupPackageEntries.js.map +1 -0
  22. package/lib/core/zip/ZipAssetEntry.d.ts +9 -0
  23. package/lib/core/zip/ZipAssetEntry.d.ts.map +1 -0
  24. package/lib/core/zip/ZipAssetEntry.js +2 -0
  25. package/lib/core/zip/ZipAssetEntry.js.map +1 -0
  26. package/lib/core/zip/getFolderEntries.d.ts +8 -0
  27. package/lib/core/zip/getFolderEntries.d.ts.map +1 -0
  28. package/lib/core/zip/getFolderEntries.js +32 -0
  29. package/lib/core/zip/getFolderEntries.js.map +1 -0
  30. package/lib/core/zip/getPackageEntries.d.ts +12 -0
  31. package/lib/core/zip/getPackageEntries.d.ts.map +1 -0
  32. package/lib/core/zip/getPackageEntries.js +73 -0
  33. package/lib/core/zip/getPackageEntries.js.map +1 -0
  34. package/lib/core/zip/makeZipPackageStream.d.ts +5 -0
  35. package/lib/core/zip/makeZipPackageStream.d.ts.map +1 -0
  36. package/lib/core/zip/makeZipPackageStream.js +29 -0
  37. package/lib/core/zip/makeZipPackageStream.js.map +1 -0
  38. package/lib/core/zip/zipDir.d.ts +8 -0
  39. package/lib/core/zip/zipDir.d.ts.map +1 -0
  40. package/lib/core/zip/zipDir.js +24 -0
  41. package/lib/core/zip/zipDir.js.map +1 -0
  42. package/lib/index.d.ts +25 -0
  43. package/lib/index.d.ts.map +1 -0
  44. package/lib/index.js +26 -0
  45. package/lib/index.js.map +1 -0
  46. package/lib/internal/HashStream.d.ts +13 -0
  47. package/lib/internal/HashStream.d.ts.map +1 -0
  48. package/lib/internal/HashStream.js +28 -0
  49. package/lib/internal/HashStream.js.map +1 -0
  50. package/lib/internal/ProgressStream.d.ts +11 -0
  51. package/lib/internal/ProgressStream.d.ts.map +1 -0
  52. package/lib/internal/ProgressStream.js +25 -0
  53. package/lib/internal/ProgressStream.js.map +1 -0
  54. package/lib/internal/addBundleInfoToPackageJson.d.ts +6 -0
  55. package/lib/internal/addBundleInfoToPackageJson.d.ts.map +1 -0
  56. package/lib/internal/addBundleInfoToPackageJson.js +36 -0
  57. package/lib/internal/addBundleInfoToPackageJson.js.map +1 -0
  58. package/lib/internal/getPackagePath.d.ts +2 -0
  59. package/lib/internal/getPackagePath.d.ts.map +1 -0
  60. package/lib/internal/getPackagePath.js +11 -0
  61. package/lib/internal/getPackagePath.js.map +1 -0
  62. package/lib/internal/hash.d.ts +3 -0
  63. package/lib/internal/hash.d.ts.map +1 -0
  64. package/lib/internal/hash.js +9 -0
  65. package/lib/internal/hash.js.map +1 -0
  66. package/lib/internal/readDotIgnoreFile.d.ts +2 -0
  67. package/lib/internal/readDotIgnoreFile.d.ts.map +1 -0
  68. package/lib/internal/readDotIgnoreFile.js +13 -0
  69. package/lib/internal/readDotIgnoreFile.js.map +1 -0
  70. package/lib/internal/readDotIgnoreForFolder.d.ts +2 -0
  71. package/lib/internal/readDotIgnoreForFolder.d.ts.map +1 -0
  72. package/lib/internal/readDotIgnoreForFolder.js +6 -0
  73. package/lib/internal/readDotIgnoreForFolder.js.map +1 -0
  74. package/lib/internal/tryStat.d.ts +4 -0
  75. package/lib/internal/tryStat.d.ts.map +1 -0
  76. package/lib/internal/tryStat.js +13 -0
  77. package/lib/internal/tryStat.js.map +1 -0
  78. package/lib/template/AssetAttributes.d.ts +5 -0
  79. package/lib/template/AssetAttributes.d.ts.map +1 -0
  80. package/lib/template/AssetAttributes.js +2 -0
  81. package/lib/template/AssetAttributes.js.map +1 -0
  82. package/lib/template/AssetBase.d.ts +14 -0
  83. package/lib/template/AssetBase.d.ts.map +1 -0
  84. package/lib/template/AssetBase.js +34 -0
  85. package/lib/template/AssetBase.js.map +1 -0
  86. package/lib/template/AssetBuilder.d.ts +6 -0
  87. package/lib/template/AssetBuilder.d.ts.map +1 -0
  88. package/lib/template/AssetBuilder.js +2 -0
  89. package/lib/template/AssetBuilder.js.map +1 -0
  90. package/lib/template/AssetContext.d.ts +7 -0
  91. package/lib/template/AssetContext.d.ts.map +1 -0
  92. package/lib/template/AssetContext.js +12 -0
  93. package/lib/template/AssetContext.js.map +1 -0
  94. package/lib/template/AssetDefinition.d.ts +8 -0
  95. package/lib/template/AssetDefinition.d.ts.map +1 -0
  96. package/lib/template/AssetDefinition.js +2 -0
  97. package/lib/template/AssetDefinition.js.map +1 -0
  98. package/lib/template/AssetGenerator.d.ts +5 -0
  99. package/lib/template/AssetGenerator.d.ts.map +1 -0
  100. package/lib/template/AssetGenerator.js +2 -0
  101. package/lib/template/AssetGenerator.js.map +1 -0
  102. package/lib/template/AssetManifest.d.ts +13 -0
  103. package/lib/template/AssetManifest.d.ts.map +1 -0
  104. package/lib/template/AssetManifest.js +12 -0
  105. package/lib/template/AssetManifest.js.map +1 -0
  106. package/lib/template/AssetOutput.d.ts +7 -0
  107. package/lib/template/AssetOutput.d.ts.map +1 -0
  108. package/lib/template/AssetOutput.js +2 -0
  109. package/lib/template/AssetOutput.js.map +1 -0
  110. package/lib/template/AssetRef.d.ts +5 -0
  111. package/lib/template/AssetRef.d.ts.map +1 -0
  112. package/lib/template/AssetRef.js +2 -0
  113. package/lib/template/AssetRef.js.map +1 -0
  114. package/lib/template/CustomAsset.d.ts +7 -0
  115. package/lib/template/CustomAsset.d.ts.map +1 -0
  116. package/lib/template/CustomAsset.js +9 -0
  117. package/lib/template/CustomAsset.js.map +1 -0
  118. package/lib/template/DeploymentBundle.d.ts +16 -0
  119. package/lib/template/DeploymentBundle.d.ts.map +1 -0
  120. package/lib/template/DeploymentBundle.js +2 -0
  121. package/lib/template/DeploymentBundle.js.map +1 -0
  122. package/lib/template/FileSystemDeploymentBundle.d.ts +20 -0
  123. package/lib/template/FileSystemDeploymentBundle.d.ts.map +1 -0
  124. package/lib/template/FileSystemDeploymentBundle.js +72 -0
  125. package/lib/template/FileSystemDeploymentBundle.js.map +1 -0
  126. package/lib/template/ProgressStats.d.ts +6 -0
  127. package/lib/template/ProgressStats.d.ts.map +1 -0
  128. package/lib/template/ProgressStats.js +2 -0
  129. package/lib/template/ProgressStats.js.map +1 -0
  130. package/lib/template/makeAsset.d.ts +5 -0
  131. package/lib/template/makeAsset.d.ts.map +1 -0
  132. package/lib/template/makeAsset.js +6 -0
  133. package/lib/template/makeAsset.js.map +1 -0
  134. package/lib/template/makeAssetFromPackage.d.ts +12 -0
  135. package/lib/template/makeAssetFromPackage.d.ts.map +1 -0
  136. package/lib/template/makeAssetFromPackage.js +29 -0
  137. package/lib/template/makeAssetFromPackage.js.map +1 -0
  138. package/lib/template/processAssets.d.ts +4 -0
  139. package/lib/template/processAssets.d.ts.map +1 -0
  140. package/lib/template/processAssets.js +24 -0
  141. package/lib/template/processAssets.js.map +1 -0
  142. package/package.json +71 -0
  143. package/src/cli/build.ts +131 -0
  144. package/src/cli/cfnassets.ts +9 -0
  145. package/src/core/rollup/makeRollupPackageStream.ts +55 -0
  146. package/src/core/rollup/rollupPackageDir.ts +64 -0
  147. package/src/core/rollup/rollupPackageEntries.ts +46 -0
  148. package/src/core/zip/ZipAssetEntry.ts +11 -0
  149. package/src/core/zip/getFolderEntries.ts +47 -0
  150. package/src/core/zip/getPackageEntries.ts +104 -0
  151. package/src/core/zip/makeZipPackageStream.ts +41 -0
  152. package/src/core/zip/zipDir.ts +43 -0
  153. package/src/index.ts +25 -0
  154. package/src/internal/HashStream.ts +36 -0
  155. package/src/internal/ProgressStream.ts +32 -0
  156. package/src/internal/addBundleInfoToPackageJson.ts +52 -0
  157. package/src/internal/getPackagePath.ts +13 -0
  158. package/src/internal/hash.ts +9 -0
  159. package/src/internal/readDotIgnoreFile.ts +15 -0
  160. package/src/internal/readDotIgnoreForFolder.ts +8 -0
  161. package/src/internal/tryStat.ts +12 -0
  162. package/src/template/AssetAttributes.ts +5 -0
  163. package/src/template/AssetBase.ts +60 -0
  164. package/src/template/AssetBuilder.ts +8 -0
  165. package/src/template/AssetContext.ts +15 -0
  166. package/src/template/AssetDefinition.ts +8 -0
  167. package/src/template/AssetGenerator.ts +5 -0
  168. package/src/template/AssetManifest.ts +25 -0
  169. package/src/template/AssetOutput.ts +6 -0
  170. package/src/template/AssetRef.ts +4 -0
  171. package/src/template/CustomAsset.ts +11 -0
  172. package/src/template/DeploymentBundle.ts +20 -0
  173. package/src/template/FileSystemDeploymentBundle.ts +112 -0
  174. package/src/template/ProgressStats.ts +5 -0
  175. package/src/template/makeAsset.ts +12 -0
  176. package/src/template/makeAssetFromPackage.ts +42 -0
  177. package/src/template/processAssets.ts +40 -0
  178. package/src/types/loadConfigFile.d.ts +20 -0
@@ -0,0 +1,46 @@
1
+ import { MergedRollupOptions, rollup } from 'rollup';
2
+ import { BatchWarnings } from 'rollup/loadConfigFile';
3
+ import { ZipAssetEntry } from '../zip/ZipAssetEntry.js';
4
+
5
+ const SourceMapUrl = 'sourceMappingURL';
6
+
7
+ export async function* rollupPackageEntries(
8
+ options: MergedRollupOptions[],
9
+ warnings: BatchWarnings,
10
+ ): AsyncIterableIterator<ZipAssetEntry> {
11
+ for (const inputOptions of options) {
12
+ const bundle = await rollup(inputOptions);
13
+
14
+ for (const outputOptions of inputOptions.output) {
15
+ const output = await bundle.generate(outputOptions);
16
+
17
+ for (const chunkOrAsset of output.output) {
18
+ let content: Buffer;
19
+
20
+ if (chunkOrAsset.type === 'asset') {
21
+ content = Buffer.from(chunkOrAsset.source);
22
+ } else if (chunkOrAsset.type === 'chunk') {
23
+ let code = chunkOrAsset.code;
24
+
25
+ if (chunkOrAsset.map) {
26
+ const url = `${chunkOrAsset.fileName}.map`;
27
+
28
+ yield {
29
+ archivePath: url,
30
+ content: chunkOrAsset.map.toString(),
31
+ };
32
+ code += `//# ${SourceMapUrl}=${url}\n`;
33
+ }
34
+
35
+ content = Buffer.from(code);
36
+ } else {
37
+ continue;
38
+ }
39
+
40
+ yield { archivePath: chunkOrAsset.fileName, content };
41
+ warnings?.flush();
42
+ }
43
+ }
44
+ }
45
+ warnings?.flush();
46
+ }
@@ -0,0 +1,11 @@
1
+ import { Readable } from 'stream';
2
+
3
+ export type EntryContent = Readable | string | Buffer;
4
+
5
+ export interface ZipAssetEntry {
6
+ archivePath: string;
7
+ content:
8
+ | EntryContent
9
+ | (() => EntryContent)
10
+ | (() => PromiseLike<EntryContent>);
11
+ }
@@ -0,0 +1,47 @@
1
+ import { createReadStream } from 'fs';
2
+ import { readdir } from 'fs/promises';
3
+ import ignore from 'ignore';
4
+ import { join, relative, resolve } from 'path';
5
+ import { ZipAssetEntry } from './ZipAssetEntry.js';
6
+
7
+ export interface FolderEntriesOptions {
8
+ archivePath?: string;
9
+ ignore?: string[];
10
+ source: string;
11
+ }
12
+
13
+ export async function* getFolderEntries({
14
+ archivePath: archiveBasePath = '/',
15
+ source,
16
+ ignore: ignorePaths,
17
+ }: FolderEntriesOptions): AsyncIterableIterator<ZipAssetEntry> {
18
+ const work = [resolve(source)];
19
+ const ig = ignore.default().add(ignorePaths || []);
20
+
21
+ while (work.length) {
22
+ const curr = work.pop() as string;
23
+
24
+ const entries = await readdir(curr, { withFileTypes: true });
25
+
26
+ for (const entry of entries) {
27
+ const entryPath = join(curr, entry.name);
28
+
29
+ let archivePath = relative(source, entryPath);
30
+ if (entry.isDirectory()) {
31
+ archivePath += '/';
32
+ }
33
+ if (ig.ignores(archivePath)) {
34
+ continue;
35
+ }
36
+
37
+ if (entry.isDirectory()) {
38
+ work.push(entryPath);
39
+ } else if (entry.isFile()) {
40
+ yield {
41
+ archivePath: join(archiveBasePath, archivePath),
42
+ content: () => createReadStream(entryPath),
43
+ };
44
+ }
45
+ }
46
+ }
47
+ }
@@ -0,0 +1,104 @@
1
+ import chalk from 'chalk';
2
+ import childProc from 'child_process';
3
+ import { copyFile, readFile, writeFile } from 'fs/promises';
4
+ import { basename, join } from 'path';
5
+ import { temporaryDirectory } from 'tempy';
6
+ import { getFolderEntries } from './getFolderEntries.js';
7
+ import { ZipAssetEntry } from './ZipAssetEntry.js';
8
+
9
+ export interface PackageEntriesOptions {
10
+ archivePath?: string;
11
+ ignorePaths?: string[];
12
+ packageArch?: string;
13
+ packageFilePath: string;
14
+ packagePlatform?: string;
15
+ packageLockPath: string;
16
+ packageNames: string[];
17
+ }
18
+
19
+ export async function* getPackageEntries({
20
+ archivePath = 'node_modules',
21
+ ignorePaths,
22
+ packageLockPath,
23
+ packageFilePath,
24
+ packageArch,
25
+ packagePlatform,
26
+ packageNames,
27
+ }: PackageEntriesOptions): AsyncIterableIterator<ZipAssetEntry> {
28
+ let exec: string[];
29
+ const npmConfig: string[] = [];
30
+
31
+ const lockBasename = basename(packageLockPath);
32
+ if (lockBasename === 'package-lock.json') {
33
+ exec = ['npm', 'ci'];
34
+ } else if (lockBasename === 'yarn.lock') {
35
+ exec = ['yarn', '--frozen-lockfile'];
36
+ } else if (lockBasename === 'pnpm-lock.yaml') {
37
+ exec = ['pnpm', 'install', '--frozen-lockfile'];
38
+ } else {
39
+ throw new Error(`unknown lockfile type for path '${packageLockPath}'`);
40
+ }
41
+
42
+ const pkg = JSON.parse(await readFile(packageFilePath, 'utf-8'));
43
+
44
+ const newPackageJson = {
45
+ name: 'build',
46
+ private: true,
47
+ dependencies: {} as Record<string, string>,
48
+ };
49
+
50
+ for (const dep of packageNames) {
51
+ const version =
52
+ (pkg.dependencies && pkg.dependencies[dep]) ||
53
+ (pkg.devDependencies && pkg.devDependencies[dep]);
54
+
55
+ if (!version) {
56
+ throw new Error(`cannot find dependency ${dep} in ${packageFilePath}`);
57
+ }
58
+
59
+ newPackageJson.dependencies[dep] = version;
60
+ }
61
+
62
+ if (packageArch) {
63
+ npmConfig.push(`arch=${packageArch}`);
64
+ }
65
+ if (packagePlatform) {
66
+ npmConfig.push(`platform=${packagePlatform}`);
67
+ }
68
+
69
+ const outDir = temporaryDirectory();
70
+ await writeFile(join(outDir, 'package.json'), JSON.stringify(newPackageJson));
71
+ await copyFile(packageLockPath, join(outDir, lockBasename));
72
+
73
+ if (npmConfig.length) {
74
+ await writeFile(join(outDir, '.npmrc'), npmConfig.join('\n') + '\n');
75
+ }
76
+
77
+ const [cmd, ...args] = exec;
78
+
79
+ const flags = npmConfig.join(', ');
80
+ console.log(`\n${chalk.cyan.bold(`${cmd} install`)} ${chalk.gray(flags)}`);
81
+
82
+ const proc = childProc.spawn(cmd, args, {
83
+ cwd: outDir,
84
+ stdio: 'inherit',
85
+ });
86
+
87
+ await new Promise<void>((resolve, reject) => {
88
+ proc.on('close', (code) => {
89
+ if (code === 0) {
90
+ resolve();
91
+ } else {
92
+ reject(new Error(`npm exited with non-zero error code ${code}`));
93
+ }
94
+ });
95
+ });
96
+
97
+ console.log(`\n`);
98
+
99
+ yield* getFolderEntries({
100
+ source: join(outDir, 'node_modules'),
101
+ archivePath,
102
+ ignore: ignorePaths,
103
+ });
104
+ }
@@ -0,0 +1,41 @@
1
+ import archiver from 'archiver';
2
+ import stream from 'stream';
3
+ import { ZipAssetEntry } from './ZipAssetEntry.js';
4
+
5
+ export async function makeZipPackageStream(
6
+ entries: AsyncIterable<ZipAssetEntry> | Iterable<ZipAssetEntry>,
7
+ ): Promise<stream.Readable> {
8
+ const zip = archiver('zip', { zlib: { level: 9 } });
9
+ let error: unknown;
10
+
11
+ zip.on('warning', (err: unknown) => {
12
+ console.error(`rollupPackage: WARN: `, err);
13
+ });
14
+
15
+ zip.on('error', (err: unknown) => {
16
+ error = err || new Error(`unknown error occurred`);
17
+ });
18
+
19
+ const sortedEntries: ZipAssetEntry[] = [];
20
+ for await (const entry of entries) {
21
+ sortedEntries.push(entry);
22
+ }
23
+ sortedEntries.sort((a, b) => a.archivePath.localeCompare(b.archivePath));
24
+
25
+ for await (const entry of sortedEntries) {
26
+ if (error) {
27
+ throw error;
28
+ }
29
+
30
+ const content =
31
+ typeof entry.content === 'function'
32
+ ? await entry.content()
33
+ : entry.content;
34
+
35
+ zip.append(content, { name: entry.archivePath, date: new Date(0) });
36
+ }
37
+
38
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
39
+ zip.finalize();
40
+ return zip;
41
+ }
@@ -0,0 +1,43 @@
1
+ import fs from 'fs';
2
+ import { mkdir } from 'fs/promises';
3
+ import path from 'path';
4
+ import { pipeline } from 'stream/promises';
5
+ import { addBundleInfoToPackageJson } from '../../internal/addBundleInfoToPackageJson.js';
6
+ import { readDotIgnoreForFolder } from '../../internal/readDotIgnoreForFolder.js';
7
+ import { getFolderEntries } from './getFolderEntries.js';
8
+ import { makeZipPackageStream } from './makeZipPackageStream.js';
9
+
10
+ export interface ZipDirOptions {
11
+ bundleName?: string;
12
+ ignorePaths?: string[];
13
+ outputPath?: string;
14
+ packagePath?: string;
15
+ }
16
+
17
+ export async function zipDir(
18
+ dirname: string,
19
+ opts?: ZipDirOptions,
20
+ ): Promise<void> {
21
+ const outputPath =
22
+ opts?.outputPath || `dist/${opts?.bundleName || 'bundle'}.zip`;
23
+ const fullOutputPath = path.resolve(outputPath);
24
+
25
+ const ignorePaths = opts?.ignorePaths || [];
26
+ ignorePaths.push(
27
+ ...(await readDotIgnoreForFolder(opts?.packagePath || dirname)),
28
+ );
29
+
30
+ const zip = await makeZipPackageStream(
31
+ getFolderEntries({ source: dirname, ignore: ignorePaths }),
32
+ );
33
+
34
+ await mkdir(path.dirname(fullOutputPath), { recursive: true });
35
+ await pipeline(zip, fs.createWriteStream(fullOutputPath));
36
+
37
+ if (opts?.packagePath) {
38
+ await addBundleInfoToPackageJson(opts?.packagePath, {
39
+ name: opts?.bundleName,
40
+ path: outputPath,
41
+ });
42
+ }
43
+ }
package/src/index.ts ADDED
@@ -0,0 +1,25 @@
1
+ // AUTO-GENERATED node ../makeIndex.js
2
+ export * from './core/rollup/makeRollupPackageStream.js';
3
+ export * from './core/rollup/rollupPackageDir.js';
4
+ export * from './core/rollup/rollupPackageEntries.js';
5
+ export * from './core/zip/getFolderEntries.js';
6
+ export * from './core/zip/getPackageEntries.js';
7
+ export * from './core/zip/makeZipPackageStream.js';
8
+ export * from './core/zip/ZipAssetEntry.js';
9
+ export * from './core/zip/zipDir.js';
10
+ export * from './template/AssetAttributes.js';
11
+ export * from './template/AssetBase.js';
12
+ export * from './template/AssetBuilder.js';
13
+ export * from './template/AssetContext.js';
14
+ export * from './template/AssetDefinition.js';
15
+ export * from './template/AssetGenerator.js';
16
+ export * from './template/AssetManifest.js';
17
+ export * from './template/AssetOutput.js';
18
+ export * from './template/AssetRef.js';
19
+ export * from './template/CustomAsset.js';
20
+ export * from './template/DeploymentBundle.js';
21
+ export * from './template/FileSystemDeploymentBundle.js';
22
+ export * from './template/makeAsset.js';
23
+ export * from './template/makeAssetFromPackage.js';
24
+ export * from './template/processAssets.js';
25
+ export * from './template/ProgressStats.js';
@@ -0,0 +1,36 @@
1
+ import { BinaryToTextEncoding, createHash, Hash } from 'crypto';
2
+ import { Transform, TransformCallback, TransformOptions } from 'stream';
3
+
4
+ export class HashStream extends Transform {
5
+ private readonly hash: Hash;
6
+
7
+ constructor(algorithm?: string | Hash, options?: TransformOptions) {
8
+ super(options);
9
+
10
+ if (!algorithm) {
11
+ algorithm = 'sha1';
12
+ }
13
+ this.hash =
14
+ typeof algorithm === 'string' ? createHash(algorithm) : algorithm;
15
+ }
16
+
17
+ public digest(): Buffer;
18
+ public digest(encoding: BinaryToTextEncoding): string;
19
+ public digest(encoding?: BinaryToTextEncoding): Buffer | string {
20
+ return encoding ? this.hash.digest(encoding) : this.hash.digest();
21
+ }
22
+
23
+ public override _transform(
24
+ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
25
+ chunk: any,
26
+ encoding: BufferEncoding,
27
+ callback: TransformCallback,
28
+ ): void {
29
+ try {
30
+ this.hash.update(chunk);
31
+ callback(null, chunk);
32
+ } catch (err: any) {
33
+ callback(err);
34
+ }
35
+ }
36
+ }
@@ -0,0 +1,32 @@
1
+ import stream from 'stream';
2
+
3
+ export class ProgressStream extends stream.Transform {
4
+ private _transferred = 0;
5
+
6
+ constructor(listener?: (total: number, delta: number) => void) {
7
+ super();
8
+ if (listener) {
9
+ this.on('progress', listener);
10
+ }
11
+ }
12
+
13
+ public get transferred(): number {
14
+ return this._transferred;
15
+ }
16
+
17
+ public override _transform(
18
+ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
19
+ chunk: any,
20
+ encoding: BufferEncoding,
21
+ callback: stream.TransformCallback,
22
+ ): void {
23
+ const delta = this.writableObjectMode ? 1 : chunk.length;
24
+ this._transferred += delta;
25
+ this.emit('progress', this._transferred, delta);
26
+ callback(null, chunk);
27
+ }
28
+
29
+ public override eventNames(): (string | symbol)[] {
30
+ return [...super.eventNames(), 'progress'];
31
+ }
32
+ }
@@ -0,0 +1,52 @@
1
+ import { readFile, writeFile } from 'fs/promises';
2
+ import { basename, resolve } from 'path';
3
+
4
+ const PackageJsonName = 'package.json';
5
+
6
+ export interface BundleInfo {
7
+ name?: string;
8
+ path: string;
9
+ }
10
+
11
+ export async function addBundleInfoToPackageJson(
12
+ packagePath: string,
13
+ info: BundleInfo,
14
+ ): Promise<void> {
15
+ const packageFilePath =
16
+ basename(packagePath) !== PackageJsonName
17
+ ? resolve(packagePath, PackageJsonName)
18
+ : packagePath;
19
+
20
+ const pkg = JSON.parse(await readFile(packageFilePath, 'utf8'));
21
+
22
+ if (info.name) {
23
+ if (
24
+ pkg.bundles &&
25
+ pkg.bundles[info.name] &&
26
+ pkg.bundles[info.name].path === info.path
27
+ ) {
28
+ // don't touch the file if it isn't going to change.
29
+ return;
30
+ }
31
+
32
+ if (!pkg.bundles || typeof pkg.bundles !== 'object') {
33
+ pkg.bundles = {};
34
+ }
35
+ if (!pkg.bundles[info.name] || typeof pkg.bundles[info.name] !== 'object') {
36
+ pkg.bundles[info.name] = {};
37
+ }
38
+ pkg.bundles[info.name].path = info.path;
39
+ } else {
40
+ if (pkg.bundle?.path === info.path) {
41
+ // don't touch the file if it isn't going to change.
42
+ return;
43
+ }
44
+
45
+ if (!pkg.bundle || typeof pkg.bundle !== 'object') {
46
+ pkg.bundle = {};
47
+ }
48
+ pkg.bundle.path = info.path;
49
+ }
50
+
51
+ await writeFile(packageFilePath, JSON.stringify(pkg, null, 2) + '\n');
52
+ }
@@ -0,0 +1,13 @@
1
+ import path from 'path';
2
+ import { tryStat } from './tryStat.js';
3
+
4
+ export async function getPackagePath(
5
+ search: string,
6
+ ): Promise<string | undefined> {
7
+ if (await tryStat(path.resolve(search, 'package.json'))) {
8
+ return search;
9
+ }
10
+ if (await tryStat(path.resolve(process.cwd(), 'package.json'))) {
11
+ return process.cwd();
12
+ }
13
+ }
@@ -0,0 +1,9 @@
1
+ import { createHash } from 'crypto';
2
+
3
+ export function hash(data: Iterable<string | Buffer>): string {
4
+ const sha1 = createHash('sha1');
5
+ for (const part of data) {
6
+ sha1.update(part);
7
+ }
8
+ return sha1.digest('hex');
9
+ }
@@ -0,0 +1,15 @@
1
+ import { readFile } from 'fs/promises';
2
+
3
+ export async function readDotIgnoreFile(
4
+ filename: string,
5
+ ignoreMissing = false,
6
+ ): Promise<string[]> {
7
+ try {
8
+ return (await readFile(filename, 'utf8')).split('\n');
9
+ } catch (err: any) {
10
+ if (!ignoreMissing || err.code !== 'ENOENT') {
11
+ throw err;
12
+ }
13
+ return [];
14
+ }
15
+ }
@@ -0,0 +1,8 @@
1
+ import path from 'path';
2
+ import { readDotIgnoreFile } from './readDotIgnoreFile.js';
3
+
4
+ export async function readDotIgnoreForFolder(
5
+ dirname: string,
6
+ ): Promise<string[]> {
7
+ return await readDotIgnoreFile(path.resolve(dirname, '.assetignore'), true);
8
+ }
@@ -0,0 +1,12 @@
1
+ import fs from 'fs';
2
+
3
+ export async function tryStat(path: string): Promise<fs.Stats | undefined> {
4
+ try {
5
+ return await fs.promises.stat(path);
6
+ } catch (err: any) {
7
+ if (err.code === 'ENOENT') {
8
+ return;
9
+ }
10
+ throw err;
11
+ }
12
+ }
@@ -0,0 +1,5 @@
1
+ import { AssetRef } from './AssetRef.js';
2
+
3
+ export interface AssetAttributes {
4
+ ref: AssetRef;
5
+ }
@@ -0,0 +1,60 @@
1
+ import {
2
+ BuilderContext,
3
+ makeParameter,
4
+ Template,
5
+ TemplateBuilder,
6
+ TemplateFragment,
7
+ } from '@awboost/cfntemplate';
8
+ import { AssetBuilder } from './AssetBuilder.js';
9
+ import { AssetContext } from './AssetContext.js';
10
+ import { AssetOutput } from './AssetOutput.js';
11
+ import { AssetRef } from './AssetRef.js';
12
+
13
+ export abstract class AssetBase implements AssetBuilder {
14
+ public readonly name: string;
15
+ public readonly parameters: AssetRef;
16
+ public readonly ref: AssetRef;
17
+
18
+ private readonly paramBuilder: TemplateBuilder;
19
+
20
+ constructor(name: string) {
21
+ this.name = name;
22
+
23
+ const [bucketParamBuilder, bucketParam] = makeParameter(
24
+ `${name}BucketName`,
25
+ {
26
+ Type: 'String',
27
+ },
28
+ );
29
+ const [objectParamBuilder, objectParam] = makeParameter(
30
+ `${name}ObjectKey`,
31
+ {
32
+ Type: 'String',
33
+ },
34
+ );
35
+
36
+ this.paramBuilder = TemplateFragment.compose(
37
+ bucketParamBuilder,
38
+ objectParamBuilder,
39
+ );
40
+
41
+ this.parameters = {
42
+ S3Bucket: bucketParam.name,
43
+ S3Key: objectParam.name,
44
+ };
45
+ this.ref = {
46
+ S3Bucket: bucketParam.ref,
47
+ S3Key: objectParam.ref,
48
+ };
49
+ }
50
+
51
+ public build(template: Template, ctx: BuilderContext): Template {
52
+ const assets = ctx.get(AssetContext);
53
+ if (!assets.addAsset(this.name, this)) {
54
+ return template;
55
+ }
56
+ return this.paramBuilder.build(template, ctx);
57
+ }
58
+
59
+ public abstract generate(): PromiseLike<AssetOutput> | AssetOutput;
60
+ }
@@ -0,0 +1,8 @@
1
+ import { TemplateBuilder } from '@awboost/cfntemplate';
2
+ import { AssetAttributes } from './AssetAttributes.js';
3
+ import { AssetDefinition } from './AssetDefinition.js';
4
+
5
+ export interface AssetBuilder
6
+ extends AssetDefinition,
7
+ TemplateBuilder,
8
+ AssetAttributes {}
@@ -0,0 +1,15 @@
1
+ import { AssetDefinition } from './AssetDefinition.js';
2
+
3
+ export class AssetContext {
4
+ public static readonly ContextKey = 'AssetContext';
5
+
6
+ public readonly assets: AssetDefinition[] = [];
7
+
8
+ public addAsset(name: string, value: AssetDefinition): boolean {
9
+ const add = !this.assets.find((x) => x.name === name);
10
+ if (add) {
11
+ this.assets.push(value);
12
+ }
13
+ return add;
14
+ }
15
+ }
@@ -0,0 +1,8 @@
1
+ import { AssetGenerator } from './AssetGenerator.js';
2
+ import { AssetRef } from './AssetRef.js';
3
+
4
+ export interface AssetDefinition {
5
+ generate: AssetGenerator;
6
+ name: string;
7
+ parameters: AssetRef;
8
+ }
@@ -0,0 +1,5 @@
1
+ import { AssetOutput } from './AssetOutput.js';
2
+
3
+ export interface AssetGenerator {
4
+ (): PromiseLike<AssetOutput> | AssetOutput;
5
+ }
@@ -0,0 +1,25 @@
1
+ import { array, object, text } from '@fmtk/decoders';
2
+
3
+ export const AssetManifestMetadataKey = 'DeployAssetManifest';
4
+
5
+ export interface AssetDescriptor {
6
+ name: string;
7
+ key: string;
8
+ bucketParam: string;
9
+ keyParam: string;
10
+ }
11
+
12
+ export interface AssetManifest {
13
+ assets: AssetDescriptor[];
14
+ }
15
+
16
+ export const decodeAssetDescriptor = object<AssetDescriptor>({
17
+ name: text,
18
+ key: text,
19
+ bucketParam: text,
20
+ keyParam: text,
21
+ });
22
+
23
+ export const decodeAssetManifest = object<AssetManifest>({
24
+ assets: array(decodeAssetDescriptor),
25
+ });
@@ -0,0 +1,6 @@
1
+ import { Readable } from 'stream';
2
+
3
+ export interface AssetOutput {
4
+ content: Readable;
5
+ fileName: string;
6
+ }
@@ -0,0 +1,4 @@
1
+ export interface AssetRef {
2
+ S3Bucket: string;
3
+ S3Key: string;
4
+ }
@@ -0,0 +1,11 @@
1
+ import { AssetBase } from './AssetBase.js';
2
+ import { AssetGenerator } from './AssetGenerator.js';
3
+
4
+ export class CustomAsset extends AssetBase {
5
+ constructor(
6
+ name: string,
7
+ public readonly generate: AssetGenerator,
8
+ ) {
9
+ super(name);
10
+ }
11
+ }