@applicaster/zapplicaster-cli 16.0.0-alpha.7128076344 → 16.0.0-alpha.7501599877
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/package.json +5 -5
- package/src/commands/prepareWorkspace/appBootstrapper.js +35 -7
- package/src/commands/prepareWorkspace/configurator.js +7 -1
- package/src/commands/prepareWorkspace/parseFonts.js +6 -0
- package/src/commands/publishPlugin/generateManifest.js +1 -0
- package/src/download/__tests__/download.test.js +53 -0
- package/src/download/index.js +65 -1
- package/src/file/__tests__/__snapshots__/file.test.js.snap +0 -19
- package/src/file/__tests__/file.test.js +16 -40
- package/src/file/index.js +16 -43
- package/src/templates/__tests__/__snapshots__/templates.test.js.snap +1 -1
- package/src/templates/index.js +1 -0
- package/test_helpers/fsMock.js +0 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapplicaster-cli",
|
|
3
|
-
"version": "16.0.0-alpha.
|
|
3
|
+
"version": "16.0.0-alpha.7501599877",
|
|
4
4
|
"description": "CLI Tool for the zapp app and Quick Brick project",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"publishConfig": {
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
},
|
|
29
29
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@applicaster/zapp-react-dom-cli-template": "16.0.0-alpha.
|
|
32
|
-
"@applicaster/zapp-react-native-android-tv-cli-template": "16.0.0-alpha.
|
|
33
|
-
"@applicaster/zapp-react-native-cli-template": "16.0.0-alpha.
|
|
34
|
-
"@applicaster/zapp-react-native-tvos-cli-template": "16.0.0-alpha.
|
|
31
|
+
"@applicaster/zapp-react-dom-cli-template": "16.0.0-alpha.7501599877",
|
|
32
|
+
"@applicaster/zapp-react-native-android-tv-cli-template": "16.0.0-alpha.7501599877",
|
|
33
|
+
"@applicaster/zapp-react-native-cli-template": "16.0.0-alpha.7501599877",
|
|
34
|
+
"@applicaster/zapp-react-native-tvos-cli-template": "16.0.0-alpha.7501599877",
|
|
35
35
|
"axios": "^0.28.0",
|
|
36
36
|
"camelize": "^1.0.0",
|
|
37
37
|
"chalk": "^2.3.2",
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
const R = require("ramda");
|
|
2
2
|
const fs = require("fs");
|
|
3
3
|
const semver = require("semver");
|
|
4
|
-
const { resolve } = require("path");
|
|
4
|
+
const { resolve, join } = require("path");
|
|
5
|
+
const { existsSync } = require("fs");
|
|
5
6
|
const packageJSON = require("../../../package.json");
|
|
6
7
|
|
|
7
8
|
const {
|
|
@@ -30,6 +31,36 @@ const {
|
|
|
30
31
|
|
|
31
32
|
const { buildMobileApp } = require("./buildMobile");
|
|
32
33
|
|
|
34
|
+
async function patchPackages() {
|
|
35
|
+
if (existsSync(join(process.cwd(), "quick_brick", "patch_rn.js"))) {
|
|
36
|
+
exec(`node ${process.cwd()}/quick_brick/patch_rn.js`);
|
|
37
|
+
} else if (
|
|
38
|
+
existsSync(join(process.cwd(), "development-app", "patch_rn.js"))
|
|
39
|
+
) {
|
|
40
|
+
exec(`node ${process.cwd()}/development-app/patch_rn.js`);
|
|
41
|
+
} else if (
|
|
42
|
+
existsSync(
|
|
43
|
+
join(
|
|
44
|
+
process.cwd(),
|
|
45
|
+
"packages",
|
|
46
|
+
"zapp-react-dom-development-app",
|
|
47
|
+
"patch_rn.js"
|
|
48
|
+
)
|
|
49
|
+
)
|
|
50
|
+
) {
|
|
51
|
+
const pathToFile = join(
|
|
52
|
+
process.cwd(),
|
|
53
|
+
"packages",
|
|
54
|
+
"zapp-react-dom-development-app",
|
|
55
|
+
"patch_rn.js"
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
exec(`node ${pathToFile}`);
|
|
59
|
+
} else {
|
|
60
|
+
logger.log("Cannot patch packages, can't find the patch_rn.js file");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
33
64
|
/**
|
|
34
65
|
* fallback to en for missing dayjslocalization
|
|
35
66
|
* converts the locale code to a dayjs compatible locale code
|
|
@@ -101,12 +132,7 @@ async function appBootstrapper(configuration) {
|
|
|
101
132
|
|
|
102
133
|
const { templatePath, filesToCopy } = template.files;
|
|
103
134
|
|
|
104
|
-
|
|
105
|
-
templatePath,
|
|
106
|
-
filesToCopy,
|
|
107
|
-
quickBrickProjectPath,
|
|
108
|
-
configuration
|
|
109
|
-
);
|
|
135
|
+
copyFiles(templatePath, filesToCopy, quickBrickProjectPath, configuration);
|
|
110
136
|
|
|
111
137
|
logger.log("injecting dependencies...");
|
|
112
138
|
const { dependencies, scripts } = template;
|
|
@@ -190,6 +216,8 @@ async function appBootstrapper(configuration) {
|
|
|
190
216
|
const quickBrickVersion = packageJSON.version;
|
|
191
217
|
checkAllPluginsSatisfiesQuickBrickVersion({ quickBrickVersion, plugins });
|
|
192
218
|
|
|
219
|
+
await patchPackages();
|
|
220
|
+
|
|
193
221
|
if (buildMobile) {
|
|
194
222
|
await buildMobileApp(configuration);
|
|
195
223
|
}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
const R = require("ramda");
|
|
2
2
|
const axios = require("axios");
|
|
3
|
+
|
|
4
|
+
const {
|
|
5
|
+
platformIsTV,
|
|
6
|
+
} = require("@applicaster/zapp-react-native-utils/manifestUtils/platformIsTV");
|
|
7
|
+
|
|
3
8
|
const { getAppVersionParams } = require("../../zapp");
|
|
4
9
|
const { resolveAppTemplate } = require("../../templates");
|
|
5
10
|
const { isZappReactNativeRepo } = require("../../settings");
|
|
@@ -11,6 +16,7 @@ const store_map = {
|
|
|
11
16
|
samsung_app_store: "samsung_tv",
|
|
12
17
|
lg_content_store: "lg_tv",
|
|
13
18
|
vizio_app_store: "vizio",
|
|
19
|
+
vidaa_app_store: "vidaa",
|
|
14
20
|
};
|
|
15
21
|
|
|
16
22
|
/**
|
|
@@ -21,7 +27,7 @@ const store_map = {
|
|
|
21
27
|
*/
|
|
22
28
|
async function retrievesSpinnerColor(url, platform) {
|
|
23
29
|
try {
|
|
24
|
-
if (!
|
|
30
|
+
if (!platformIsTV(platform)) {
|
|
25
31
|
return;
|
|
26
32
|
}
|
|
27
33
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const { saveRemoteJsonToFile, saveAssets, saveFontFiles } = require("../index");
|
|
2
2
|
const nock = require("nock");
|
|
3
3
|
const R = require("ramda");
|
|
4
|
+
const fs = require("fs");
|
|
4
5
|
const logger = require("../../logger");
|
|
5
6
|
|
|
6
7
|
const getFileName = R.compose(R.last, R.split("/"));
|
|
@@ -109,9 +110,37 @@ describe("saveAssets", () => {
|
|
|
109
110
|
|
|
110
111
|
afterEach(() => {
|
|
111
112
|
clearAllMocks();
|
|
113
|
+
|
|
114
|
+
["existsSync", "openSync", "closeSync", "readSync", "readFileSync"].forEach(
|
|
115
|
+
(method) => {
|
|
116
|
+
if (fs[method] && fs[method].mockRestore) {
|
|
117
|
+
fs[method].mockRestore();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
);
|
|
112
121
|
});
|
|
113
122
|
|
|
123
|
+
function mockDownloadedFile({ isZip, content } = {}) {
|
|
124
|
+
jest.spyOn(fs, "existsSync").mockReturnValue(true);
|
|
125
|
+
jest.spyOn(fs, "openSync").mockReturnValue(1);
|
|
126
|
+
jest.spyOn(fs, "closeSync").mockImplementation(() => ({}));
|
|
127
|
+
|
|
128
|
+
jest.spyOn(fs, "readSync").mockImplementation((fd, buffer) => {
|
|
129
|
+
const header = isZip
|
|
130
|
+
? Buffer.from([0x50, 0x4b, 0x03, 0x04])
|
|
131
|
+
: Buffer.from("<?xm");
|
|
132
|
+
|
|
133
|
+
header.copy(buffer);
|
|
134
|
+
|
|
135
|
+
return 4;
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
jest.spyOn(fs, "readFileSync").mockReturnValue(content || "");
|
|
139
|
+
}
|
|
140
|
+
|
|
114
141
|
it("downloads the files with cURL, and unzips the assets", () => {
|
|
142
|
+
mockDownloadedFile({ isZip: true });
|
|
143
|
+
|
|
115
144
|
saveAssets({ destinationPath, platform }, assetsUrl);
|
|
116
145
|
|
|
117
146
|
expect(loggerSpy).toHaveBeenCalledWith(`saving assets from ${assetsUrl}`);
|
|
@@ -122,6 +151,30 @@ describe("saveAssets", () => {
|
|
|
122
151
|
filePath
|
|
123
152
|
);
|
|
124
153
|
});
|
|
154
|
+
|
|
155
|
+
it("throws a clear error and skips unzip when the bundle is not a zip", () => {
|
|
156
|
+
mockDownloadedFile({
|
|
157
|
+
isZip: false,
|
|
158
|
+
content:
|
|
159
|
+
'<?xml version="1.0" encoding="UTF-8"?><Error><Code>AccessDenied</Code></Error>',
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
expect(() => saveAssets({ destinationPath, platform }, assetsUrl)).toThrow(
|
|
163
|
+
/AccessDenied/
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
expect(shell.unzip).not.toHaveBeenCalled();
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it("throws a clear error when the bundle was not downloaded", () => {
|
|
170
|
+
jest.spyOn(fs, "existsSync").mockReturnValue(false);
|
|
171
|
+
|
|
172
|
+
expect(() => saveAssets({ destinationPath, platform }, assetsUrl)).toThrow(
|
|
173
|
+
/was not downloaded/
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
expect(shell.unzip).not.toHaveBeenCalled();
|
|
177
|
+
});
|
|
125
178
|
});
|
|
126
179
|
|
|
127
180
|
describe("saveFontFiles", () => {
|
package/src/download/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const R = require("ramda");
|
|
2
|
+
const fs = require("fs");
|
|
2
3
|
const axios = require("axios");
|
|
3
4
|
const { resolve } = require("path");
|
|
4
5
|
const { curlFile, curlMultipleFiles, unzip } = require("../shell");
|
|
@@ -12,6 +13,64 @@ const getFileName = R.ifElse(
|
|
|
12
13
|
R.prop("name")
|
|
13
14
|
);
|
|
14
15
|
|
|
16
|
+
// Local file signature for a zip archive: "PK\x03\x04"
|
|
17
|
+
const ZIP_SIGNATURE = "504b0304";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* checks whether a file on disk is a real zip archive by reading its magic bytes.
|
|
21
|
+
* @param {String} file path to the file to inspect
|
|
22
|
+
* @returns {Boolean} true if the file starts with the zip local file signature
|
|
23
|
+
*/
|
|
24
|
+
function isZipFile(file) {
|
|
25
|
+
const fd = fs.openSync(file, "r");
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
const header = Buffer.alloc(4);
|
|
29
|
+
const bytesRead = fs.readSync(fd, header, 0, 4, 0);
|
|
30
|
+
|
|
31
|
+
return bytesRead === 4 && header.toString("hex") === ZIP_SIGNATURE;
|
|
32
|
+
} finally {
|
|
33
|
+
fs.closeSync(fd);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* verifies that the downloaded assets bundle is a real zip archive.
|
|
39
|
+
* The assets CDN responds with a small XML/HTML body (e.g. S3 "AccessDenied")
|
|
40
|
+
* when the bundle is missing or not yet published. Because the download uses
|
|
41
|
+
* `curl -O` without `-f`, that error body is saved as assets.zip and the process
|
|
42
|
+
* continues, only to crash later in webpack with a confusing parse error. This
|
|
43
|
+
* check fails fast in the prepare step with an actionable message instead.
|
|
44
|
+
* @param {String} file path to the downloaded assets bundle
|
|
45
|
+
* @param {String} assetsUrl original url, surfaced in the error message
|
|
46
|
+
*/
|
|
47
|
+
function assertValidAssetsBundle(file, assetsUrl) {
|
|
48
|
+
if (!fs.existsSync(file)) {
|
|
49
|
+
throw new Error(
|
|
50
|
+
`Assets bundle was not downloaded from ${assetsUrl}. ` +
|
|
51
|
+
"Verify the app has a published build with generated assets for this platform."
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (isZipFile(file)) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const preview = fs
|
|
60
|
+
.readFileSync(file, "utf8")
|
|
61
|
+
.replace(/\s+/g, " ")
|
|
62
|
+
.trim()
|
|
63
|
+
.slice(0, 300);
|
|
64
|
+
|
|
65
|
+
throw new Error(
|
|
66
|
+
`Invalid assets bundle downloaded from ${assetsUrl} - expected a zip archive ` +
|
|
67
|
+
`but received non-zip content:\n "${preview}"\n` +
|
|
68
|
+
"This usually means the assets bundle has not been generated/published for " +
|
|
69
|
+
'this platform, or the URL is not accessible (e.g. S3 "AccessDenied"). ' +
|
|
70
|
+
"Publish a build with assets for this platform before preparing the workspace."
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
15
74
|
/**
|
|
16
75
|
* saves a remote json file in the app's configuration folder.
|
|
17
76
|
* curried function of the shape saveRemoteJsonToFile(configuration)(fileUrl)
|
|
@@ -65,7 +124,12 @@ function saveAssets({ destinationPath, platform }, assetsUrl) {
|
|
|
65
124
|
});
|
|
66
125
|
|
|
67
126
|
curlFile(assetsUrl, filePath);
|
|
68
|
-
|
|
127
|
+
|
|
128
|
+
const downloadedFile = resolve(filePath, fileName);
|
|
129
|
+
|
|
130
|
+
assertValidAssetsBundle(downloadedFile, assetsUrl);
|
|
131
|
+
|
|
132
|
+
unzip(downloadedFile, filePath);
|
|
69
133
|
}
|
|
70
134
|
|
|
71
135
|
/**
|
|
@@ -5,27 +5,10 @@ exports[`copyFiles when destination path has no package.json doesn't skips the c
|
|
|
5
5
|
[
|
|
6
6
|
"some/source/path/foo.json",
|
|
7
7
|
"some/destination/Path/foo.json",
|
|
8
|
-
[Function],
|
|
9
8
|
],
|
|
10
9
|
[
|
|
11
10
|
"some/source/path/package.json",
|
|
12
11
|
"some/destination/Path/package.json",
|
|
13
|
-
[Function],
|
|
14
|
-
],
|
|
15
|
-
]
|
|
16
|
-
`;
|
|
17
|
-
|
|
18
|
-
exports[`copyFiles when there is no package.json to copy copies the dir 1`] = `
|
|
19
|
-
[
|
|
20
|
-
[
|
|
21
|
-
"some/source/path/files/file1.txt",
|
|
22
|
-
"some/destination/Path/files/file1.txt",
|
|
23
|
-
[Function],
|
|
24
|
-
],
|
|
25
|
-
[
|
|
26
|
-
"some/source/path/files/file2.txt",
|
|
27
|
-
"some/destination/Path/files/file2.txt",
|
|
28
|
-
[Function],
|
|
29
12
|
],
|
|
30
13
|
]
|
|
31
14
|
`;
|
|
@@ -35,12 +18,10 @@ exports[`copyFiles when there is no package.json to copy copies the files 1`] =
|
|
|
35
18
|
[
|
|
36
19
|
"some/source/path/foo.json",
|
|
37
20
|
"some/destination/Path/foo.json",
|
|
38
|
-
[Function],
|
|
39
21
|
],
|
|
40
22
|
[
|
|
41
23
|
"some/source/path/bar.json",
|
|
42
24
|
"some/destination/Path/bar.json",
|
|
43
|
-
[Function],
|
|
44
25
|
],
|
|
45
26
|
]
|
|
46
27
|
`;
|
|
@@ -38,27 +38,14 @@ describe("copyFiles", () => {
|
|
|
38
38
|
fs.writeFile("foo.json", { foo: "bar" }, jest.fn());
|
|
39
39
|
fs.writeFile("bar.json", { bar: "baz" }, jest.fn());
|
|
40
40
|
fs.writeFile("qux.json", { qux: 42 }, jest.fn());
|
|
41
|
-
fs.
|
|
42
|
-
fs.readdir.mockClear();
|
|
41
|
+
fs.copyFileSync.mockClear();
|
|
43
42
|
});
|
|
44
43
|
|
|
45
44
|
describe("when there is no package.json to copy", () => {
|
|
46
|
-
it("copies the files",
|
|
47
|
-
|
|
48
|
-
expect(fs.
|
|
49
|
-
expect(fs.
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it("copies the dir", async () => {
|
|
53
|
-
// Mock fs.readdir to return some files when the directory is read
|
|
54
|
-
fs.readdir.mockImplementationOnce((path, callback) => {
|
|
55
|
-
callback(null, ["file1.txt", "file2.txt"]);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
await copyFiles(sourcePath, ["files/"], destinationPath);
|
|
59
|
-
|
|
60
|
-
expect(fs.copyFile).toHaveBeenCalledTimes(2);
|
|
61
|
-
expect(fs.copyFile.mock.calls).toMatchSnapshot();
|
|
45
|
+
it("copies the files", () => {
|
|
46
|
+
copyFiles(sourcePath, ["foo.json", "bar.json"], destinationPath);
|
|
47
|
+
expect(fs.copyFileSync).toHaveBeenCalledTimes(2);
|
|
48
|
+
expect(fs.copyFileSync.mock.calls).toMatchSnapshot();
|
|
62
49
|
});
|
|
63
50
|
});
|
|
64
51
|
|
|
@@ -73,40 +60,29 @@ describe("copyFiles", () => {
|
|
|
73
60
|
fs.__resetFiles();
|
|
74
61
|
});
|
|
75
62
|
|
|
76
|
-
it("overrides it",
|
|
63
|
+
it("overrides it", () => {
|
|
77
64
|
const sourcePath = "some/source/path";
|
|
78
65
|
const destinationPath = "some/destination/Path";
|
|
79
66
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
["foo.json", "package.json"],
|
|
83
|
-
destinationPath
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
expect(fs.copyFile).toHaveBeenCalledTimes(2);
|
|
67
|
+
copyFiles(sourcePath, ["foo.json", "package.json"], destinationPath);
|
|
68
|
+
expect(fs.copyFileSync).toHaveBeenCalledTimes(2);
|
|
87
69
|
|
|
88
|
-
expect(fs.
|
|
70
|
+
expect(fs.copyFileSync).toHaveBeenCalledWith(
|
|
89
71
|
`${sourcePath}/foo.json`,
|
|
90
|
-
`${destinationPath}/foo.json
|
|
91
|
-
expect.any(Function)
|
|
72
|
+
`${destinationPath}/foo.json`
|
|
92
73
|
);
|
|
93
74
|
});
|
|
94
75
|
});
|
|
95
76
|
|
|
96
77
|
describe("when destination path has no package.json", () => {
|
|
97
|
-
it("doesn't skips the copy",
|
|
78
|
+
it("doesn't skips the copy", () => {
|
|
98
79
|
const sourcePath = "some/source/path";
|
|
99
80
|
const destinationPath = "some/destination/Path";
|
|
100
81
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
["foo.json", "package.json"],
|
|
104
|
-
destinationPath
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
expect(fs.copyFile).toHaveBeenCalledTimes(2);
|
|
82
|
+
copyFiles(sourcePath, ["foo.json", "package.json"], destinationPath);
|
|
83
|
+
expect(fs.copyFileSync).toHaveBeenCalledTimes(2);
|
|
108
84
|
|
|
109
|
-
expect(fs.
|
|
85
|
+
expect(fs.copyFileSync.mock.calls).toMatchSnapshot();
|
|
110
86
|
expect(logger.warn).not.toHaveBeenCalled();
|
|
111
87
|
});
|
|
112
88
|
});
|
|
@@ -124,7 +100,7 @@ describe("copyFolder", () => {
|
|
|
124
100
|
});
|
|
125
101
|
|
|
126
102
|
beforeEach(() => {
|
|
127
|
-
fs.
|
|
103
|
+
fs.copyFileSync.mockClear();
|
|
128
104
|
});
|
|
129
105
|
|
|
130
106
|
it("copies the file in the folder", async () => {
|
|
@@ -134,7 +110,7 @@ describe("copyFolder", () => {
|
|
|
134
110
|
await copyFolder(sourcePath, destinationPath);
|
|
135
111
|
|
|
136
112
|
expect(fs.readdir).toHaveBeenCalledWith(sourcePath, expect.any(Function));
|
|
137
|
-
expect(fs.
|
|
113
|
+
expect(fs.copyFileSync).toHaveBeenCalledTimes(2);
|
|
138
114
|
});
|
|
139
115
|
|
|
140
116
|
afterAll(() => {
|
package/src/file/index.js
CHANGED
|
@@ -5,16 +5,7 @@ const R = require("ramda");
|
|
|
5
5
|
* @module @applicaster/zapplicaster-cli/util/file
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
const {
|
|
9
|
-
writeFile,
|
|
10
|
-
readFile,
|
|
11
|
-
readdir,
|
|
12
|
-
copyFile,
|
|
13
|
-
lstatSync,
|
|
14
|
-
mkdirSync,
|
|
15
|
-
existsSync,
|
|
16
|
-
} = require("fs");
|
|
17
|
-
|
|
8
|
+
const { writeFile, readFile, readdir, copyFile, copyFileSync } = require("fs");
|
|
18
9
|
const { promisify } = require("util");
|
|
19
10
|
const { join } = require("path");
|
|
20
11
|
|
|
@@ -70,49 +61,31 @@ function destinationFileNameMapper(destinationFileName) {
|
|
|
70
61
|
/**
|
|
71
62
|
* Copies an array of files from a folder to another
|
|
72
63
|
*
|
|
64
|
+
* Each entry can either be a string (same relative path for source and
|
|
65
|
+
* destination) or an object `{ source, destination }` when a file should be
|
|
66
|
+
* read from one relative path and written to another. The latter lets several
|
|
67
|
+
* platforms reuse a single set of bundled assets without duplicating them.
|
|
68
|
+
*
|
|
73
69
|
* @param {String} source folder of the files
|
|
74
|
-
* @param {String[]} files list of the files
|
|
70
|
+
* @param {(String|{source: String, destination: String})[]} files list of the files
|
|
75
71
|
* @param {String} destination path
|
|
76
72
|
* @returns {Promise[]} array of promises with the status of the copied files
|
|
77
73
|
*/
|
|
78
|
-
|
|
74
|
+
function copyFiles(source, filesOrFilesGetter, destination, config) {
|
|
79
75
|
const files =
|
|
80
76
|
typeof filesOrFilesGetter === "function"
|
|
81
77
|
? filesOrFilesGetter(config)
|
|
82
78
|
: filesOrFilesGetter;
|
|
83
79
|
|
|
84
|
-
return
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
try {
|
|
89
|
-
if (Array.isArray(file)) {
|
|
90
|
-
sourcePath = join(source, file[0]);
|
|
91
|
-
|
|
92
|
-
destinationPath = destinationFileNameMapper(
|
|
93
|
-
join(destination, file[1])
|
|
94
|
-
);
|
|
95
|
-
} else {
|
|
96
|
-
sourcePath = join(source, file);
|
|
97
|
-
destinationPath = destinationFileNameMapper(join(destination, file));
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (lstatSync(sourcePath).isDirectory()) {
|
|
101
|
-
if (!existsSync(destinationPath)) {
|
|
102
|
-
mkdirSync(destinationPath, { recursive: true });
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return await copyFolder(sourcePath, destinationPath);
|
|
106
|
-
}
|
|
80
|
+
return R.map((file) => {
|
|
81
|
+
const sourceFile = typeof file === "string" ? file : file.source;
|
|
82
|
+
const destinationFile = typeof file === "string" ? file : file.destination;
|
|
107
83
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
}, files)
|
|
115
|
-
);
|
|
84
|
+
return copyFileSync(
|
|
85
|
+
join(source, sourceFile),
|
|
86
|
+
destinationFileNameMapper(join(destination, destinationFile))
|
|
87
|
+
);
|
|
88
|
+
}, files);
|
|
116
89
|
}
|
|
117
90
|
|
|
118
91
|
module.exports = {
|
|
@@ -32,4 +32,4 @@ exports[`resolveAppTemplate retrieves the template from the provided path if pro
|
|
|
32
32
|
}
|
|
33
33
|
`;
|
|
34
34
|
|
|
35
|
-
exports[`resolveAppTemplate throws if resolving a template for an unknown platform 1`] = `"could not find template for foo - available templates: ios,android,samsung_tv,lg_tv,vizio,apple_tv,android_tv,amazon"`;
|
|
35
|
+
exports[`resolveAppTemplate throws if resolving a template for an unknown platform 1`] = `"could not find template for foo - available templates: ios,android,samsung_tv,lg_tv,vidaa,vizio,apple_tv,android_tv,amazon"`;
|
package/src/templates/index.js
CHANGED
|
@@ -27,6 +27,7 @@ const templatesMap = {
|
|
|
27
27
|
android: "@applicaster/zapp-react-native-cli-template",
|
|
28
28
|
samsung_tv: "@applicaster/zapp-react-dom-cli-template",
|
|
29
29
|
lg_tv: "@applicaster/zapp-react-dom-cli-template",
|
|
30
|
+
vidaa: "@applicaster/zapp-react-dom-cli-template",
|
|
30
31
|
vizio: "@applicaster/zapp-react-dom-cli-template",
|
|
31
32
|
apple_tv: "@applicaster/zapp-react-native-tvos-cli-template",
|
|
32
33
|
android_tv: "@applicaster/zapp-react-native-android-tv-cli-template",
|
package/test_helpers/fsMock.js
CHANGED
|
@@ -2,10 +2,6 @@ const fs = jest.genMockFromModule("fs");
|
|
|
2
2
|
const _fs = jest.requireActual("fs");
|
|
3
3
|
const R = require("ramda");
|
|
4
4
|
|
|
5
|
-
function mkdirSync() {
|
|
6
|
-
return undefined;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
5
|
function readdirSync(folder) {
|
|
10
6
|
return _fs.readdirSync(folder);
|
|
11
7
|
}
|
|
@@ -81,16 +77,10 @@ function __resetFiles() {
|
|
|
81
77
|
fs.__writenFiles = [];
|
|
82
78
|
}
|
|
83
79
|
|
|
84
|
-
fs.lstatSync = (_path) => ({
|
|
85
|
-
isDirectory: () => _path.endsWith("/"),
|
|
86
|
-
isFile: () => _path.endsWith("/") === false,
|
|
87
|
-
});
|
|
88
|
-
|
|
89
80
|
fs.__writenFiles = [];
|
|
90
81
|
fs.__resetFiles = __resetFiles;
|
|
91
82
|
fs.__addMockedFiles = __addMockedFiles;
|
|
92
83
|
fs.readdirSync = readdirSync;
|
|
93
|
-
fs.mkdirSync = mkdirSync;
|
|
94
84
|
fs.readdir = jest.fn(readdir);
|
|
95
85
|
fs.writeFile = jest.fn(writeFile);
|
|
96
86
|
fs.readFile = jest.fn(readFile);
|