UNPKG

4.24 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const tslib_1 = require("tslib");
4const fs_1 = tslib_1.__importDefault(require("fs"));
5const stream_1 = tslib_1.__importDefault(require("stream"));
6const elfy_1 = tslib_1.__importDefault(require("elfy"));
7const lodash_1 = tslib_1.__importDefault(require("lodash"));
8const plugin_error_1 = tslib_1.__importDefault(require("plugin-error"));
9const vinyl_1 = tslib_1.__importDefault(require("vinyl"));
10const PLUGIN_NAME = 'nativeComponents';
11function checkBufferLength(buffer, expectedLength, name) {
12 if (buffer.length !== expectedLength) {
13 throw new plugin_error_1.default(PLUGIN_NAME, `${name} must be ${expectedLength} bytes, found ${buffer.length} in ${buffer}`);
14 }
15}
16function formatUUID(buffer) {
17 const uuid = buffer.toString('hex');
18 return [
19 uuid.substr(0, 8),
20 uuid.substr(8, 4),
21 uuid.substr(12, 4),
22 uuid.substr(16, 4),
23 uuid.substr(20, 12),
24 ].join('-');
25}
26function readMetadata(elfPath) {
27 const elfData = fs_1.default.readFileSync(elfPath);
28 const elf = elfy_1.default.parse(elfData);
29 const elfSections = lodash_1.default.groupBy(elf.body.sections, (s) => s.name);
30 function findSection(name) {
31 const sectionName = `.${name}`;
32 const sections = elfSections[sectionName];
33 if (!sections) {
34 throw new plugin_error_1.default(PLUGIN_NAME, `ELF section '${name}' is missing`, {
35 fileName: elfPath,
36 });
37 }
38 if (sections.length > 1) {
39 throw new plugin_error_1.default(PLUGIN_NAME, `ELF section '${name}' is present more than once`, { fileName: elfPath });
40 }
41 return sections[0].data;
42 }
43 const buildIDData = findSection('buildid');
44 checkBufferLength(buildIDData, 8, 'Build ID');
45 const appIDData = findSection('appuuid');
46 checkBufferLength(appIDData, 16, 'App UUID');
47 const platformJSON = findSection('appplatform').toString();
48 let platform;
49 try {
50 platform = JSON.parse(platformJSON);
51 }
52 catch (ex) {
53 throw new plugin_error_1.default(PLUGIN_NAME, `Could not parse platform specification in .appplatform section: ${ex.message}`, { fileName: elfPath });
54 }
55 if (!Array.isArray(platform)) {
56 throw new plugin_error_1.default(PLUGIN_NAME, `Platform specification should be an array, but found a ${typeof platform}`, { fileName: elfPath });
57 }
58 return {
59 platform,
60 path: elfPath,
61 data: elfData,
62 appID: formatUUID(appIDData),
63 buildID: `0x${Buffer.from(buildIDData).swap64().toString('hex')}`,
64 family: findSection('appfamily').toString(),
65 };
66}
67function nativeComponents(appID, componentPaths) {
68 const components = componentPaths.map(readMetadata);
69 const buildId = components[0].buildID;
70 const divergentAppIDComponents = components.filter((c) => c.appID.toLowerCase() !== appID.toLowerCase());
71 if (divergentAppIDComponents.length > 0) {
72 const divergentAppIDsList = divergentAppIDComponents
73 .map(({ path, family, appID }) => `${path} (${family}) has appID ${appID}`)
74 .join('\n ');
75 throw new plugin_error_1.default(PLUGIN_NAME, `App IDs of native components do not match package.json.
76 Expected appID ${appID}.
77 ${divergentAppIDsList}`);
78 }
79 if (lodash_1.default.uniqBy(components, (c) => c.buildID).length > 1) {
80 const mismatchedBuildIDs = components
81 .map(({ path, family, buildID }) => `${path} (${family}) has buildID ${buildID}`)
82 .join('\n ');
83 throw new plugin_error_1.default(PLUGIN_NAME, `Build IDs of native components do not match.
84 ${mismatchedBuildIDs}`);
85 }
86 const componentStream = new stream_1.default.PassThrough({ objectMode: true });
87 components.forEach(({ family, platform, data }) => componentStream.push(new vinyl_1.default({
88 contents: data,
89 path: `${family}.bundle`,
90 componentBundle: { family, platform, type: 'device', isNative: true },
91 })));
92 componentStream.push(null);
93 return {
94 buildId,
95 existingDeviceComponents: componentStream,
96 };
97}
98exports.default = nativeComponents;