@expo/repack-app 0.1.9 → 0.1.11
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/README.md +110 -0
- package/bin/cli.js +98 -2
- package/{build/types.d.ts → dist/index.d.ts} +218 -143
- package/dist/index.js +34 -0
- package/package.json +23 -19
- package/build/android/apktool.d.ts +0 -21
- package/build/android/apktool.js +0 -175
- package/build/android/build-tools.d.ts +0 -25
- package/build/android/build-tools.js +0 -122
- package/build/android/index.d.ts +0 -5
- package/build/android/index.js +0 -104
- package/build/android/resources.d.ts +0 -69
- package/build/android/resources.js +0 -198
- package/build/cli.d.ts +0 -1
- package/build/cli.js +0 -95
- package/build/expo.d.ts +0 -30
- package/build/expo.js +0 -144
- package/build/index.d.ts +0 -3
- package/build/index.js +0 -22
- package/build/ios/build-tools.d.ts +0 -22
- package/build/ios/build-tools.js +0 -123
- package/build/ios/index.d.ts +0 -9
- package/build/ios/index.js +0 -109
- package/build/ios/resources.d.ts +0 -27
- package/build/ios/resources.js +0 -111
- package/build/types.js +0 -3
- package/build/utils.d.ts +0 -25
- package/build/utils.js +0 -86
- /package/{assets → dist}/apktool_2.10.0.jar +0 -0
- /package/{assets → dist}/debug.keystore +0 -0
package/build/ios/index.js
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.repackAppIosAsync = repackAppIosAsync;
|
|
7
|
-
exports.resignIpaAsync = resignIpaAsync;
|
|
8
|
-
const node_assert_1 = __importDefault(require("node:assert"));
|
|
9
|
-
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
10
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
-
const picocolors_1 = __importDefault(require("picocolors"));
|
|
12
|
-
const build_tools_1 = require("./build-tools");
|
|
13
|
-
const resources_1 = require("./resources");
|
|
14
|
-
const expo_1 = require("../expo");
|
|
15
|
-
const utils_1 = require("../utils");
|
|
16
|
-
/**
|
|
17
|
-
* Repack an iOS app.
|
|
18
|
-
*/
|
|
19
|
-
async function repackAppIosAsync(_options) {
|
|
20
|
-
const options = await (0, utils_1.normalizeOptionAsync)(_options);
|
|
21
|
-
const { workingDirectory, logger } = options;
|
|
22
|
-
await promises_1.default.mkdir(workingDirectory, { recursive: true });
|
|
23
|
-
const { exp } = (0, expo_1.getExpoConfig)(options.projectRoot, {
|
|
24
|
-
isPublicConfig: true,
|
|
25
|
-
skipSDKVersionRequirement: true,
|
|
26
|
-
});
|
|
27
|
-
(0, node_assert_1.default)(exp.ios?.bundleIdentifier, 'Expected app ID (`ios.bundleIdentifier`) to be defined in app.json');
|
|
28
|
-
const useExpoUpdates = (0, expo_1.isExpoUpdatesInstalled)(options.projectRoot);
|
|
29
|
-
const updatesRuntimeVersion = useExpoUpdates
|
|
30
|
-
? await (0, expo_1.resolveRuntimeVersionAsync)(options, exp)
|
|
31
|
-
: null;
|
|
32
|
-
if (useExpoUpdates) {
|
|
33
|
-
logger.info(picocolors_1.default.dim(`Resolved runtime version: ${updatesRuntimeVersion}`));
|
|
34
|
-
}
|
|
35
|
-
logger.time(`Extracting artifact from ${options.sourceAppPath}`);
|
|
36
|
-
let appWorkingDirectory = await (0, build_tools_1.extractIosArtifactAsync)(options);
|
|
37
|
-
appWorkingDirectory = await (0, build_tools_1.updateFilesAsync)(exp, appWorkingDirectory);
|
|
38
|
-
const infoPlistPath = node_path_1.default.join(appWorkingDirectory, 'Info.plist');
|
|
39
|
-
const originalAppId = await (0, resources_1.queryAppIdFromPlistAsync)(infoPlistPath, options);
|
|
40
|
-
logger.timeEnd(`Extracting artifact from ${options.sourceAppPath}`);
|
|
41
|
-
if (options.exportEmbedOptions != null) {
|
|
42
|
-
logger.time(`Generating bundle`);
|
|
43
|
-
const { assetRoot, bundleOutputPath } = await (0, expo_1.generateBundleAssetsAsync)(exp, options);
|
|
44
|
-
logger.timeEnd(`Generating bundle`);
|
|
45
|
-
logger.time(`Adding bundled resources`);
|
|
46
|
-
await (0, resources_1.addBundleAssetsAsync)({
|
|
47
|
-
appWorkingDirectory,
|
|
48
|
-
assetRoot,
|
|
49
|
-
bundleOutputPath,
|
|
50
|
-
});
|
|
51
|
-
logger.timeEnd(`Adding bundled resources`);
|
|
52
|
-
if (useExpoUpdates) {
|
|
53
|
-
logger.time(`Generating 'app.manifest' for expo-updates`);
|
|
54
|
-
const updateManifestFile = await (0, expo_1.generateUpdatesEmbeddedManifestAsync)(options);
|
|
55
|
-
const updateDirectory = node_path_1.default.join(appWorkingDirectory, 'EXUpdates.bundle');
|
|
56
|
-
(0, node_assert_1.default)(await (0, utils_1.directoryExistsAsync)(updateDirectory), 'Expected EXUpdates.bundle directory to exist');
|
|
57
|
-
await promises_1.default.copyFile(updateManifestFile, node_path_1.default.join(updateDirectory, node_path_1.default.basename(updateManifestFile)));
|
|
58
|
-
logger.timeEnd(`Generating 'app.manifest' for expo-updates`);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
logger.time(`Updating Info.plist`);
|
|
62
|
-
await (0, resources_1.updateInfoPlistAsync)({ config: exp, infoPlistPath, originalAppId, options });
|
|
63
|
-
logger.timeEnd(`Updating Info.plist`);
|
|
64
|
-
logger.time(`Updating Expo.plist`);
|
|
65
|
-
await (0, resources_1.updateExpoPlistAsync)(exp, node_path_1.default.join(appWorkingDirectory, 'Expo.plist'), updatesRuntimeVersion, options);
|
|
66
|
-
logger.timeEnd(`Updating Expo.plist`);
|
|
67
|
-
logger.time(`Generating app.config`);
|
|
68
|
-
const appConfigPath = await (0, expo_1.generateAppConfigAsync)(options, exp);
|
|
69
|
-
await promises_1.default.copyFile(appConfigPath, node_path_1.default.join(appWorkingDirectory, 'EXConstants.bundle', 'app.config'));
|
|
70
|
-
logger.timeEnd(`Generating app.config`);
|
|
71
|
-
logger.time(`Creating updated artifact`);
|
|
72
|
-
let outputArtifact;
|
|
73
|
-
if (options.outputPath.endsWith('.app')) {
|
|
74
|
-
outputArtifact = await (0, build_tools_1.createAppAsync)(options, appWorkingDirectory);
|
|
75
|
-
}
|
|
76
|
-
else {
|
|
77
|
-
outputArtifact = await (0, build_tools_1.createIpaAsync)(options, appWorkingDirectory);
|
|
78
|
-
}
|
|
79
|
-
logger.timeEnd(`Creating updated artifact`);
|
|
80
|
-
if (options.iosSigningOptions) {
|
|
81
|
-
(0, node_assert_1.default)(outputArtifact.endsWith('.ipa'), 'Signing is only supported for .ipa files');
|
|
82
|
-
logger.time(`Resigning the IPA at ${outputArtifact}`);
|
|
83
|
-
await resignIpaAsync(outputArtifact, options.iosSigningOptions, options);
|
|
84
|
-
logger.timeEnd(`Resigning the IPA at ${outputArtifact}`);
|
|
85
|
-
}
|
|
86
|
-
await promises_1.default.rename(outputArtifact, options.outputPath);
|
|
87
|
-
if (!options.skipWorkingDirCleanup) {
|
|
88
|
-
try {
|
|
89
|
-
await promises_1.default.rm(workingDirectory, { recursive: true });
|
|
90
|
-
}
|
|
91
|
-
catch { }
|
|
92
|
-
}
|
|
93
|
-
return options.outputPath;
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Resign an IPA by fastlane.
|
|
97
|
-
*/
|
|
98
|
-
async function resignIpaAsync(ipaPath, signingOptions, _options) {
|
|
99
|
-
const options = await (0, utils_1.normalizeOptionAsync)(_options);
|
|
100
|
-
const { spawnAsync } = options;
|
|
101
|
-
const resignWorkingDirectory = node_path_1.default.join(options.workingDirectory, 'fastlane');
|
|
102
|
-
await promises_1.default.mkdir(resignWorkingDirectory, { recursive: true });
|
|
103
|
-
const fastfileContents = (0, build_tools_1.createResignLane)('resign_ipa', ipaPath, signingOptions);
|
|
104
|
-
await promises_1.default.writeFile(node_path_1.default.join(resignWorkingDirectory, 'Fastfile'), fastfileContents);
|
|
105
|
-
await spawnAsync('fastlane', ['resign_ipa'], {
|
|
106
|
-
cwd: resignWorkingDirectory,
|
|
107
|
-
env: options.env,
|
|
108
|
-
});
|
|
109
|
-
}
|
package/build/ios/resources.d.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { type ExpoConfig } from '@expo/config';
|
|
2
|
-
import type { NormalizedOptions } from '../types';
|
|
3
|
-
/**
|
|
4
|
-
* Update the Info.plist file.
|
|
5
|
-
*/
|
|
6
|
-
export declare function updateInfoPlistAsync({ config, infoPlistPath, originalAppId, options, }: {
|
|
7
|
-
config: ExpoConfig;
|
|
8
|
-
infoPlistPath: string;
|
|
9
|
-
originalAppId: string;
|
|
10
|
-
options: NormalizedOptions;
|
|
11
|
-
}): Promise<void>;
|
|
12
|
-
/**
|
|
13
|
-
* Update the Expo.plist file.
|
|
14
|
-
*/
|
|
15
|
-
export declare function updateExpoPlistAsync(config: ExpoConfig, expoPlistPath: string, runtimeVersion: string | null, options: NormalizedOptions): Promise<void>;
|
|
16
|
-
/**
|
|
17
|
-
* Query the app ID from the Info.plist file.
|
|
18
|
-
*/
|
|
19
|
-
export declare function queryAppIdFromPlistAsync(infoPlistPath: string, options: NormalizedOptions): Promise<string>;
|
|
20
|
-
/**
|
|
21
|
-
* Add the bundle assets to the app.
|
|
22
|
-
*/
|
|
23
|
-
export declare function addBundleAssetsAsync({ appWorkingDirectory, assetRoot, bundleOutputPath, }: {
|
|
24
|
-
appWorkingDirectory: string;
|
|
25
|
-
assetRoot: string;
|
|
26
|
-
bundleOutputPath: string;
|
|
27
|
-
}): Promise<void>;
|
package/build/ios/resources.js
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.updateInfoPlistAsync = updateInfoPlistAsync;
|
|
7
|
-
exports.updateExpoPlistAsync = updateExpoPlistAsync;
|
|
8
|
-
exports.queryAppIdFromPlistAsync = queryAppIdFromPlistAsync;
|
|
9
|
-
exports.addBundleAssetsAsync = addBundleAssetsAsync;
|
|
10
|
-
const plist_1 = __importDefault(require("@expo/plist"));
|
|
11
|
-
const node_assert_1 = __importDefault(require("node:assert"));
|
|
12
|
-
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
13
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
14
|
-
const utils_1 = require("../utils");
|
|
15
|
-
/**
|
|
16
|
-
* Update the Info.plist file.
|
|
17
|
-
*/
|
|
18
|
-
async function updateInfoPlistAsync({ config, infoPlistPath, originalAppId, options, }) {
|
|
19
|
-
const bundleIdentifier = config.ios?.bundleIdentifier;
|
|
20
|
-
(0, node_assert_1.default)(bundleIdentifier, 'The `bundleIdentifier` must be specified in the `ios` config.');
|
|
21
|
-
const firstScheme = Array.isArray(config.scheme) ? config.scheme[0] : config.scheme;
|
|
22
|
-
await updateBinaryPlistAsync(infoPlistPath, options, (data) => {
|
|
23
|
-
const urlTypes = data.CFBundleURLTypes.slice();
|
|
24
|
-
for (const urlType of urlTypes) {
|
|
25
|
-
if (Array.isArray(urlType.CFBundleURLSchemes)) {
|
|
26
|
-
const schemes = urlType.CFBundleURLSchemes.map((scheme) => {
|
|
27
|
-
let newScheme = scheme
|
|
28
|
-
// ios.bundleIdentifier in app.json
|
|
29
|
-
.replace(originalAppId, bundleIdentifier)
|
|
30
|
-
// default scheme generated from slug in app.json
|
|
31
|
-
.replace(/^exp\+.+$/g, `exp+${(0, utils_1.requireNotNull)(config.slug)}`);
|
|
32
|
-
// scheme in app.json
|
|
33
|
-
if (firstScheme) {
|
|
34
|
-
newScheme = scheme.replace(/^myapp$/g, firstScheme);
|
|
35
|
-
}
|
|
36
|
-
return newScheme;
|
|
37
|
-
});
|
|
38
|
-
urlType.CFBundleURLSchemes = schemes;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
const result = {
|
|
42
|
-
...data,
|
|
43
|
-
CFBundleDisplayName: config.name,
|
|
44
|
-
CFBundleName: config.name,
|
|
45
|
-
CFBundleExecutable: config.name,
|
|
46
|
-
CFBundleIdentifier: bundleIdentifier,
|
|
47
|
-
};
|
|
48
|
-
const userActivityTypes = data.NSUserActivityTypes?.map((activityType) => activityType.replace(originalAppId, bundleIdentifier));
|
|
49
|
-
if (userActivityTypes) {
|
|
50
|
-
result.NSUserActivityTypes = userActivityTypes;
|
|
51
|
-
}
|
|
52
|
-
return result;
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Update the Expo.plist file.
|
|
57
|
-
*/
|
|
58
|
-
async function updateExpoPlistAsync(config, expoPlistPath, runtimeVersion, options) {
|
|
59
|
-
if (!runtimeVersion) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
await updateBinaryPlistAsync(expoPlistPath, options, (data) => {
|
|
63
|
-
const updateUrl = config.updates?.url;
|
|
64
|
-
(0, node_assert_1.default)(updateUrl);
|
|
65
|
-
return {
|
|
66
|
-
...data,
|
|
67
|
-
EXUpdatesEnabled: true,
|
|
68
|
-
EXUpdatesRuntimeVersion: runtimeVersion,
|
|
69
|
-
EXUpdatesURL: updateUrl,
|
|
70
|
-
};
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Query the app ID from the Info.plist file.
|
|
75
|
-
*/
|
|
76
|
-
async function queryAppIdFromPlistAsync(infoPlistPath, options) {
|
|
77
|
-
let appId;
|
|
78
|
-
await updateBinaryPlistAsync(infoPlistPath, options, (data) => {
|
|
79
|
-
appId = data.CFBundleIdentifier;
|
|
80
|
-
return data;
|
|
81
|
-
});
|
|
82
|
-
(0, node_assert_1.default)(appId, 'Expected `CFBundleIdentifier` to be present in Info.plist');
|
|
83
|
-
return appId;
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Add the bundle assets to the app.
|
|
87
|
-
*/
|
|
88
|
-
async function addBundleAssetsAsync({ appWorkingDirectory, assetRoot, bundleOutputPath, }) {
|
|
89
|
-
await Promise.all([
|
|
90
|
-
promises_1.default.rm(node_path_1.default.join(appWorkingDirectory, 'main.jsbundle'), { force: true }),
|
|
91
|
-
promises_1.default.rm(node_path_1.default.join(appWorkingDirectory, 'assets'), { recursive: true, force: true }),
|
|
92
|
-
]);
|
|
93
|
-
await promises_1.default.copyFile(bundleOutputPath, node_path_1.default.join(appWorkingDirectory, 'main.jsbundle'));
|
|
94
|
-
// export:embed --assets-dest on iOS uses the app root as target directory,
|
|
95
|
-
// so we just need to copy the assets to the app root.
|
|
96
|
-
if (await (0, utils_1.directoryExistsAsync)(assetRoot)) {
|
|
97
|
-
await (0, utils_1.copyDirAsync)(assetRoot, appWorkingDirectory);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
//#region Internals
|
|
101
|
-
async function updateBinaryPlistAsync(plistPath, options, updater) {
|
|
102
|
-
const { spawnAsync } = options;
|
|
103
|
-
await spawnAsync('plutil', ['-convert', 'xml1', plistPath]);
|
|
104
|
-
const contents = await promises_1.default.readFile(plistPath, 'utf8');
|
|
105
|
-
const data = await plist_1.default.parse(contents);
|
|
106
|
-
const updatedData = updater(data);
|
|
107
|
-
const updatedContents = plist_1.default.build(updatedData);
|
|
108
|
-
await promises_1.default.writeFile(plistPath, updatedContents);
|
|
109
|
-
await spawnAsync('plutil', ['-convert', 'binary1', plistPath]);
|
|
110
|
-
}
|
|
111
|
-
//#endregion
|
package/build/types.js
DELETED
package/build/utils.d.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type { Logger, NormalizedOptions, Options } from './types';
|
|
2
|
-
/**
|
|
3
|
-
* Check if a directory exists.
|
|
4
|
-
*/
|
|
5
|
-
export declare function directoryExistsAsync(file: string): Promise<boolean>;
|
|
6
|
-
/**
|
|
7
|
-
* Return the non-null value.
|
|
8
|
-
*/
|
|
9
|
-
export declare function requireNotNull<T>(value: T | null | undefined): T;
|
|
10
|
-
/**
|
|
11
|
-
* Normalize the options.
|
|
12
|
-
*/
|
|
13
|
-
export declare function normalizeOptionAsync(options: Options): Promise<NormalizedOptions>;
|
|
14
|
-
export declare class ConsoleLogger implements Logger {
|
|
15
|
-
debug(...message: any[]): void;
|
|
16
|
-
info(...message: any[]): void;
|
|
17
|
-
warn(...message: any[]): void;
|
|
18
|
-
error(...message: any[]): void;
|
|
19
|
-
time(label: string): void;
|
|
20
|
-
timeEnd(label: string): void;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Copy a directory recursively.
|
|
24
|
-
*/
|
|
25
|
-
export declare function copyDirAsync(src: string, dst: string): Promise<void>;
|
package/build/utils.js
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.ConsoleLogger = void 0;
|
|
7
|
-
exports.directoryExistsAsync = directoryExistsAsync;
|
|
8
|
-
exports.requireNotNull = requireNotNull;
|
|
9
|
-
exports.normalizeOptionAsync = normalizeOptionAsync;
|
|
10
|
-
exports.copyDirAsync = copyDirAsync;
|
|
11
|
-
const spawn_async_1 = __importDefault(require("@expo/spawn-async"));
|
|
12
|
-
const node_assert_1 = __importDefault(require("node:assert"));
|
|
13
|
-
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
14
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
15
|
-
/**
|
|
16
|
-
* Check if a directory exists.
|
|
17
|
-
*/
|
|
18
|
-
async function directoryExistsAsync(file) {
|
|
19
|
-
return (await promises_1.default.stat(file).catch(() => null))?.isDirectory() ?? false;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Return the non-null value.
|
|
23
|
-
*/
|
|
24
|
-
function requireNotNull(value) {
|
|
25
|
-
(0, node_assert_1.default)(value != null, 'Expected value to be non-null');
|
|
26
|
-
return value;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Normalize the options.
|
|
30
|
-
*/
|
|
31
|
-
async function normalizeOptionAsync(options) {
|
|
32
|
-
const fileExt = options.platform === 'android' ? '.apk' : '.ipa';
|
|
33
|
-
return {
|
|
34
|
-
...options,
|
|
35
|
-
workingDirectory: options.workingDirectory ?? (await promises_1.default.mkdtemp(node_path_1.default.join(require('temp-dir'), 'repack-app-'))),
|
|
36
|
-
outputPath: options.outputPath ?? node_path_1.default.join(options.projectRoot, `repacked${fileExt}`),
|
|
37
|
-
logger: options.logger ?? new ConsoleLogger(),
|
|
38
|
-
spawnAsync: options.spawnAsync ?? createDefaultSpawnAsync(!!options.verbose),
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
class ConsoleLogger {
|
|
42
|
-
debug(...message) {
|
|
43
|
-
console.debug(...message);
|
|
44
|
-
}
|
|
45
|
-
info(...message) {
|
|
46
|
-
console.log(...message);
|
|
47
|
-
}
|
|
48
|
-
warn(...message) {
|
|
49
|
-
console.warn(...message);
|
|
50
|
-
}
|
|
51
|
-
error(...message) {
|
|
52
|
-
console.error(...message);
|
|
53
|
-
}
|
|
54
|
-
time(label) {
|
|
55
|
-
console.time(label);
|
|
56
|
-
}
|
|
57
|
-
timeEnd(label) {
|
|
58
|
-
console.timeEnd(label);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
exports.ConsoleLogger = ConsoleLogger;
|
|
62
|
-
function createDefaultSpawnAsync(verbose) {
|
|
63
|
-
return function defaultSpawnAsync(command, args, options) {
|
|
64
|
-
return (0, spawn_async_1.default)(command, args, {
|
|
65
|
-
stdio: verbose ? 'inherit' : 'pipe',
|
|
66
|
-
...options,
|
|
67
|
-
});
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Copy a directory recursively.
|
|
72
|
-
*/
|
|
73
|
-
async function copyDirAsync(src, dst) {
|
|
74
|
-
await promises_1.default.mkdir(dst, { recursive: true });
|
|
75
|
-
const entries = await promises_1.default.readdir(src, { withFileTypes: true });
|
|
76
|
-
for (const entry of entries) {
|
|
77
|
-
const srcPath = node_path_1.default.join(src, entry.name);
|
|
78
|
-
const dstPath = node_path_1.default.join(dst, entry.name);
|
|
79
|
-
if (entry.isDirectory()) {
|
|
80
|
-
await copyDirAsync(srcPath, dstPath);
|
|
81
|
-
}
|
|
82
|
-
else if (entry.isFile()) {
|
|
83
|
-
await promises_1.default.copyFile(srcPath, dstPath);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
File without changes
|
|
File without changes
|