@expo-harmony/config-plugins 55.0.10-harmony.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.
package/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # @expo-harmony/config-plugins
2
+
3
+ [**GitHub 仓库**](https://github.com/renbaoshuo/expo-harmony/tree/master/packages/config-plugins)
4
+
5
+ 为 Expo Config Plugins 提供 HarmonyOS 平台扩展,包括 `expo.harmony` 配置类型、Harmony Base Mods、原生工程文件与资源 Mod、路径解析及插件资源归属管理。
6
+
7
+ ## 安装
8
+
9
+ ```sh
10
+ npm install @expo-harmony/config-plugins
11
+ ```
12
+
13
+ ## 配置类型
14
+
15
+ 在 `app.config.js` 中可使用 `defineExpoHarmonyConfig` 声明 HarmonyOS 配置:
16
+
17
+ ```js
18
+ const { defineExpoHarmonyConfig } = require('@expo-harmony/config-plugins');
19
+
20
+ module.exports = defineExpoHarmonyConfig({
21
+ name: 'Example',
22
+ slug: 'example',
23
+ platforms: ['ios', 'android', 'harmony'],
24
+ plugins: ['@expo-harmony/prebuild-config'],
25
+ harmony: {
26
+ bundleName: 'com.example.app',
27
+ versionCode: 1,
28
+ },
29
+ });
30
+ ```
31
+
32
+ ## 编写 HarmonyOS 配置插件
33
+
34
+ 使用对应的 Mod 修改生成后的 HarmonyOS 原生配置。例如,向 `module.json5` 添加信息:
35
+
36
+ ```js
37
+ const { withModuleJson } = require('@expo-harmony/config-plugins');
38
+
39
+ module.exports = function withExampleMetadata(config) {
40
+ return withModuleJson(config, (mod) => {
41
+ const moduleConfig = mod.modResults.module || {};
42
+ const metadata = Array.isArray(moduleConfig.metadata)
43
+ ? moduleConfig.metadata
44
+ : [];
45
+
46
+ mod.modResults.module = {
47
+ ...moduleConfig,
48
+ metadata: [...metadata, { name: 'example.enabled', value: 'true' }],
49
+ };
50
+ return mod;
51
+ });
52
+ };
53
+ ```
54
+
55
+ 包内提供 JSON、文本、资源、自动链接等 Harmony Mod。常用入口包括 `withModuleJson`、`withAppJson`、`withStrings`、`withColors`、`withMedia`、`withCMakeLists`、`withHarmonyDangerousMod` 等,可以在 export 中查看完整列表。
56
+
57
+ `withHarmonyBaseMods` 负责注册所有 Harmony Base Mods,通常由 `@expo-harmony/prebuild-config` 调用,应用和第三方配置插件无需重复注册。`registerHarmonyConfigPlugin` 可声明插件拥有的资源或 Ability 字段,避免多个插件在生成阶段产生归属冲突。
58
+
59
+ ## Author
60
+
61
+ **expo-harmony** © [Baoshuo](https://github.com/renbaoshuo), Released under the MIT License.<br>
62
+ Authored and maintained by Baoshuo with help from [contributors](https://github.com/renbaoshuo/expo-harmony/contributors).
63
+
64
+ > [Personal Website](https://baoshuo.ren) · [Blog](https://blog.baoshuo.ren) · GitHub [@renbaoshuo](https://github.com/renbaoshuo) · Twitter [@baoshuo](https://twitter.com/baoshuo)
package/build/index.js ADDED
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HarmonyPaths = exports.registerHarmonyConfigPlugin = exports.normalizeHarmonyConfigPlugins = exports.getHarmonyConfigPlugins = exports.withWorker = exports.withStrings = exports.withRootOhPackage = exports.withRootHvigor = exports.withReactNativeConfig = exports.withProjectBuildProfile = exports.withProfiles = exports.withNativeInputsStamp = exports.withModuleJson = exports.withMedia = exports.withIndexPage = exports.withHvigorConfig = exports.withHarmonyResources = exports.withHarmonyMod = exports.withHarmonyDangerousMod = exports.withHarmonyBaseMods = exports.withHarmonyAutolinking = exports.withEntryOhPackage = exports.withEntryHvigor = exports.withEntryBuildProfile = exports.withEntryAbility = exports.withCppPackageProvider = exports.withColors = exports.withCngManifest = exports.withCMakeLists = exports.withArkTSPackageProvider = exports.withAppJson = exports.recordManagedFile = exports.HARMONY_MOD_NAMES = exports.normalizeHarmonyConfig = exports.HarmonySdkVersions = exports.stableHarmonyJson = exports.atomicWrite = exports.HarmonyConfigPluginError = exports.defineExpoHarmonyConfig = void 0;
4
+ var config_1 = require("./config");
5
+ Object.defineProperty(exports, "defineExpoHarmonyConfig", { enumerable: true, get: function () { return config_1.defineExpoHarmonyConfig; } });
6
+ var errors_1 = require("./errors");
7
+ Object.defineProperty(exports, "HarmonyConfigPluginError", { enumerable: true, get: function () { return errors_1.HarmonyConfigPluginError; } });
8
+ var files_1 = require("./files");
9
+ Object.defineProperty(exports, "atomicWrite", { enumerable: true, get: function () { return files_1.atomicWrite; } });
10
+ Object.defineProperty(exports, "stableHarmonyJson", { enumerable: true, get: function () { return files_1.stableJson; } });
11
+ var normalizeConfig_1 = require("./normalizeConfig");
12
+ Object.defineProperty(exports, "HarmonySdkVersions", { enumerable: true, get: function () { return normalizeConfig_1.HarmonySdkVersions; } });
13
+ Object.defineProperty(exports, "normalizeHarmonyConfig", { enumerable: true, get: function () { return normalizeConfig_1.normalizeHarmonyConfig; } });
14
+ var mods_1 = require("./mods");
15
+ Object.defineProperty(exports, "HARMONY_MOD_NAMES", { enumerable: true, get: function () { return mods_1.HarmonyModNames; } });
16
+ Object.defineProperty(exports, "recordManagedFile", { enumerable: true, get: function () { return mods_1.recordManagedFile; } });
17
+ Object.defineProperty(exports, "withAppJson", { enumerable: true, get: function () { return mods_1.withAppJson; } });
18
+ Object.defineProperty(exports, "withArkTSPackageProvider", { enumerable: true, get: function () { return mods_1.withArkTSPackageProvider; } });
19
+ Object.defineProperty(exports, "withCMakeLists", { enumerable: true, get: function () { return mods_1.withCMakeLists; } });
20
+ Object.defineProperty(exports, "withCngManifest", { enumerable: true, get: function () { return mods_1.withCngManifest; } });
21
+ Object.defineProperty(exports, "withColors", { enumerable: true, get: function () { return mods_1.withColors; } });
22
+ Object.defineProperty(exports, "withCppPackageProvider", { enumerable: true, get: function () { return mods_1.withCppPackageProvider; } });
23
+ Object.defineProperty(exports, "withEntryAbility", { enumerable: true, get: function () { return mods_1.withEntryAbility; } });
24
+ Object.defineProperty(exports, "withEntryBuildProfile", { enumerable: true, get: function () { return mods_1.withEntryBuildProfile; } });
25
+ Object.defineProperty(exports, "withEntryHvigor", { enumerable: true, get: function () { return mods_1.withEntryHvigor; } });
26
+ Object.defineProperty(exports, "withEntryOhPackage", { enumerable: true, get: function () { return mods_1.withEntryOhPackage; } });
27
+ Object.defineProperty(exports, "withHarmonyAutolinking", { enumerable: true, get: function () { return mods_1.withHarmonyAutolinking; } });
28
+ Object.defineProperty(exports, "withHarmonyBaseMods", { enumerable: true, get: function () { return mods_1.withHarmonyBaseMods; } });
29
+ Object.defineProperty(exports, "withHarmonyDangerousMod", { enumerable: true, get: function () { return mods_1.withHarmonyDangerousMod; } });
30
+ Object.defineProperty(exports, "withHarmonyMod", { enumerable: true, get: function () { return mods_1.withHarmonyMod; } });
31
+ Object.defineProperty(exports, "withHarmonyResources", { enumerable: true, get: function () { return mods_1.withHarmonyResources; } });
32
+ Object.defineProperty(exports, "withHvigorConfig", { enumerable: true, get: function () { return mods_1.withHvigorConfig; } });
33
+ Object.defineProperty(exports, "withIndexPage", { enumerable: true, get: function () { return mods_1.withIndexPage; } });
34
+ Object.defineProperty(exports, "withMedia", { enumerable: true, get: function () { return mods_1.withMedia; } });
35
+ Object.defineProperty(exports, "withModuleJson", { enumerable: true, get: function () { return mods_1.withModuleJson; } });
36
+ Object.defineProperty(exports, "withNativeInputsStamp", { enumerable: true, get: function () { return mods_1.withNativeInputsStamp; } });
37
+ Object.defineProperty(exports, "withProfiles", { enumerable: true, get: function () { return mods_1.withProfiles; } });
38
+ Object.defineProperty(exports, "withProjectBuildProfile", { enumerable: true, get: function () { return mods_1.withProjectBuildProfile; } });
39
+ Object.defineProperty(exports, "withReactNativeConfig", { enumerable: true, get: function () { return mods_1.withReactNativeConfig; } });
40
+ Object.defineProperty(exports, "withRootHvigor", { enumerable: true, get: function () { return mods_1.withRootHvigor; } });
41
+ Object.defineProperty(exports, "withRootOhPackage", { enumerable: true, get: function () { return mods_1.withRootOhPackage; } });
42
+ Object.defineProperty(exports, "withStrings", { enumerable: true, get: function () { return mods_1.withStrings; } });
43
+ Object.defineProperty(exports, "withWorker", { enumerable: true, get: function () { return mods_1.withWorker; } });
44
+ var ownership_1 = require("./ownership");
45
+ Object.defineProperty(exports, "getHarmonyConfigPlugins", { enumerable: true, get: function () { return ownership_1.getHarmonyConfigPlugins; } });
46
+ Object.defineProperty(exports, "normalizeHarmonyConfigPlugins", { enumerable: true, get: function () { return ownership_1.normalizeHarmonyConfigPlugins; } });
47
+ Object.defineProperty(exports, "registerHarmonyConfigPlugin", { enumerable: true, get: function () { return ownership_1.registerHarmonyConfigPlugin; } });
48
+ var paths_1 = require("./paths");
49
+ Object.defineProperty(exports, "HarmonyPaths", { enumerable: true, get: function () { return paths_1.HarmonyPaths; } });
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@expo-harmony/config-plugins",
3
+ "version": "55.0.10-harmony.1",
4
+ "keywords": [
5
+ "react-native",
6
+ "expo",
7
+ "expo-harmony",
8
+ "harmonyos"
9
+ ],
10
+ "homepage": "https://github.com/renbaoshuo/expo-harmony/tree/master/packages/config-plugins#readme",
11
+ "bugs": "https://github.com/renbaoshuo/expo-harmony/issues",
12
+ "license": "MIT",
13
+ "author": "Baoshuo <i@baoshuo.ren>",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/renbaoshuo/expo-harmony.git",
17
+ "directory": "packages/config-plugins"
18
+ },
19
+ "main": "build/index.js",
20
+ "types": "build/index.d.ts",
21
+ "scripts": {
22
+ "build": "tsc -p tsconfig.json",
23
+ "prepare": "yarn build",
24
+ "typecheck": "tsc --noEmit -p tsconfig.json"
25
+ },
26
+ "exports": {
27
+ ".": {
28
+ "types": "./build/index.d.ts",
29
+ "require": "./build/index.js",
30
+ "default": "./build/index.js"
31
+ },
32
+ "./native-inputs": {
33
+ "types": "./build/nativeInputs.d.ts",
34
+ "require": "./build/nativeInputs.js",
35
+ "default": "./build/nativeInputs.js"
36
+ },
37
+ "./package.json": "./package.json"
38
+ },
39
+ "dependencies": {
40
+ "@expo/config-plugins": "55.0.10",
41
+ "@expo/config-types": "^55.0.5",
42
+ "json5": "2.2.3"
43
+ },
44
+ "peerDependencies": {
45
+ "@expo/config": "55.0.17"
46
+ },
47
+ "peerDependenciesMeta": {
48
+ "@expo/config": {
49
+ "optional": true
50
+ }
51
+ },
52
+ "devDependencies": {
53
+ "@types/node": "18.19.0",
54
+ "typescript": "^6.0.3"
55
+ },
56
+ "engines": {
57
+ "node": ">=20"
58
+ },
59
+ "publishConfig": {
60
+ "access": "public"
61
+ }
62
+ }
package/src/config.ts ADDED
@@ -0,0 +1,79 @@
1
+ import type { ExpoConfig } from '@expo/config-types';
2
+
3
+ export type HarmonyPlatform = 'harmony';
4
+ export type ExpoKnownPlatform = NonNullable<ExpoConfig['platforms']>[number];
5
+ export type ExpoHarmonyPlatform = ExpoKnownPlatform | HarmonyPlatform;
6
+ export type HarmonyDeviceType = 'phone' | 'tablet' | '2in1';
7
+ export type HarmonyOrientation
8
+ = | 'default'
9
+ | 'portrait'
10
+ | 'landscape'
11
+ | 'portrait_inverted'
12
+ | 'landscape_inverted'
13
+ | 'auto_rotation';
14
+
15
+ export interface HarmonyPermission {
16
+ name: string;
17
+ reason?: string;
18
+ usedScene?: { abilities?: string[]; when?: 'inuse' | 'always' };
19
+ }
20
+
21
+ export interface HarmonySkill {
22
+ entities?: string[];
23
+ actions?: string[];
24
+ uris?: Array<Record<string, string>>;
25
+ }
26
+
27
+ export interface HarmonyFontDefinition {
28
+ path: string;
29
+ weight?: number;
30
+ style?: 'normal' | 'italic';
31
+ }
32
+
33
+ export type HarmonyFont
34
+ = | string
35
+ | {
36
+ fontFamily: string;
37
+ fontDefinitions: HarmonyFontDefinition[];
38
+ };
39
+
40
+ export interface HarmonyConfig {
41
+ bundleName: string;
42
+ moduleName?: string;
43
+ abilityName?: string;
44
+ productName?: string;
45
+ vendor?: string;
46
+ versionCode?: number;
47
+ versionName?: string;
48
+ targetApiVersion?: number;
49
+ /** Harmony SDK label written to build-profile.json5, e.g. 6.0.0(20). Its API must match targetApiVersion. */
50
+ targetSdkVersion?: number | string;
51
+ /** API number, or a full Harmony SDK label ending in the API number. */
52
+ compatibleSdkVersion?: number | string;
53
+ deviceTypes?: HarmonyDeviceType[];
54
+ permissions?: HarmonyPermission[];
55
+ skills?: HarmonySkill[];
56
+ /** URL schemes the app may inspect with Linking.canOpenURL. http, https, and expo.scheme are added automatically. */
57
+ querySchemes?: string[];
58
+ icon?: string;
59
+ label?: string;
60
+ backgroundColor?: string;
61
+ orientation?: HarmonyOrientation;
62
+ userInterfaceStyle?: 'light' | 'dark' | 'automatic';
63
+ jsEngine?: 'hermes';
64
+ abiFilters?: string[];
65
+ signingConfigFile?: string;
66
+ /** Fonts bundled when the `@expo-harmony/expo-font` config plugin is registered. */
67
+ fonts?: HarmonyFont[];
68
+ }
69
+
70
+ export type ExpoConfigWithHarmony = Omit<ExpoConfig, 'platforms'> & {
71
+ platforms?: ExpoHarmonyPlatform[];
72
+ harmony?: HarmonyConfig;
73
+ };
74
+
75
+ export function defineExpoHarmonyConfig<
76
+ T extends { expo: ExpoConfigWithHarmony } | ExpoConfigWithHarmony,
77
+ >(config: T): T {
78
+ return config;
79
+ }
package/src/errors.ts ADDED
@@ -0,0 +1,21 @@
1
+ export interface HarmonyConfigPluginErrorOptions {
2
+ cause?: unknown;
3
+ file?: string;
4
+ operation?: string;
5
+ }
6
+
7
+ export class HarmonyConfigPluginError extends Error {
8
+ declare readonly code: string;
9
+ declare readonly operation: string;
10
+ declare readonly file?: string;
11
+
12
+ constructor(code: string, message: string, options: HarmonyConfigPluginErrorOptions = {}) {
13
+ super(message, options.cause === undefined ? undefined : { cause: options.cause });
14
+
15
+ this.name = 'HarmonyConfigPluginError';
16
+ this.code = code;
17
+ this.operation = options.operation || 'config-plugin';
18
+
19
+ if (options.file) this.file = options.file;
20
+ }
21
+ }
package/src/files.ts ADDED
@@ -0,0 +1,79 @@
1
+ import crypto from 'node:crypto';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import JSON5 from 'json5';
5
+
6
+ import { HarmonyConfigPluginError } from './errors';
7
+
8
+ function sortValue(value: unknown): unknown {
9
+ if (Array.isArray(value)) return value.map(sortValue);
10
+ if (value && typeof value === 'object' && !Buffer.isBuffer(value)) {
11
+ const record = value as Record<string, unknown>;
12
+ const entries = Object.keys(record).sort().map(key => [key, sortValue(record[key])]);
13
+
14
+ return Object.fromEntries(entries);
15
+ }
16
+
17
+ return value;
18
+ }
19
+
20
+ export function stableJson(value: unknown): string {
21
+ return `${JSON.stringify(sortValue(value), null, 2)}\n`;
22
+ }
23
+
24
+ export async function readJson5<T>(file: string, fallback: T, modName: string): Promise<T> {
25
+ try {
26
+ const source = await fs.promises.readFile(file, 'utf8');
27
+
28
+ return JSON5.parse(source) as T;
29
+ } catch (cause) {
30
+ if ((cause as NodeJS.ErrnoException).code === 'ENOENT') return structuredClone(fallback);
31
+
32
+ throw new HarmonyConfigPluginError(
33
+ 'ERR_HARMONY_JSON5_INVALID',
34
+ `Cannot parse ${file} for harmony.${modName}: ${(cause as Error).message}`,
35
+ { cause, file, operation: `harmony.${modName}.read` }
36
+ );
37
+ }
38
+ }
39
+
40
+ export async function readText(file: string, fallback = ''): Promise<string> {
41
+ try {
42
+ return await fs.promises.readFile(file, 'utf8');
43
+ } catch (cause) {
44
+ if ((cause as NodeJS.ErrnoException).code === 'ENOENT') return fallback;
45
+
46
+ throw new HarmonyConfigPluginError(
47
+ 'ERR_HARMONY_TEXT_INVALID',
48
+ `Cannot read ${file}: ${(cause as Error).message}`,
49
+ { cause, file, operation: 'harmony.mod.read' }
50
+ );
51
+ }
52
+ }
53
+
54
+ export async function atomicWrite(file: string, content: string | Uint8Array): Promise<void> {
55
+ const directory = path.dirname(file);
56
+ const temporary = path.join(
57
+ directory,
58
+ `.${path.basename(file)}.${process.pid}.${crypto.randomBytes(6).toString('hex')}.tmp`
59
+ );
60
+
61
+ await fs.promises.mkdir(directory, { recursive: true });
62
+
63
+ try {
64
+ await fs.promises.writeFile(temporary, content);
65
+ await fs.promises.rename(temporary, file);
66
+ } finally {
67
+ await fs.promises.rm(temporary, { force: true }).catch(() => {});
68
+ }
69
+ }
70
+
71
+ export async function writeJson5(file: string, value: unknown): Promise<void> {
72
+ await atomicWrite(file, stableJson(value));
73
+ }
74
+
75
+ export async function sha256File(file: string): Promise<string> {
76
+ const data = Uint8Array.from(await fs.promises.readFile(file));
77
+
78
+ return crypto.createHash('sha256').update(data).digest('hex');
79
+ }
package/src/index.ts ADDED
@@ -0,0 +1,71 @@
1
+ export { defineExpoHarmonyConfig } from './config';
2
+ export type {
3
+ ExpoConfigWithHarmony,
4
+ ExpoHarmonyPlatform,
5
+ ExpoKnownPlatform,
6
+ HarmonyConfig,
7
+ HarmonyDeviceType,
8
+ HarmonyFont,
9
+ HarmonyFontDefinition,
10
+ HarmonyOrientation,
11
+ HarmonyPermission,
12
+ HarmonyPlatform,
13
+ HarmonySkill,
14
+ } from './config';
15
+ export { HarmonyConfigPluginError } from './errors';
16
+ export { atomicWrite, stableJson as stableHarmonyJson } from './files';
17
+ export { HarmonySdkVersions, normalizeHarmonyConfig } from './normalizeConfig';
18
+ export type { HarmonyExpoConfig, NormalizedHarmonyConfig } from './normalizeConfig';
19
+ export {
20
+ HarmonyModNames as HARMONY_MOD_NAMES,
21
+ recordManagedFile,
22
+ withAppJson,
23
+ withArkTSPackageProvider,
24
+ withCMakeLists,
25
+ withCngManifest,
26
+ withColors,
27
+ withCppPackageProvider,
28
+ withEntryAbility,
29
+ withEntryBuildProfile,
30
+ withEntryHvigor,
31
+ withEntryOhPackage,
32
+ withHarmonyAutolinking,
33
+ withHarmonyBaseMods,
34
+ withHarmonyDangerousMod,
35
+ withHarmonyMod,
36
+ withHarmonyResources,
37
+ withHvigorConfig,
38
+ withIndexPage,
39
+ withMedia,
40
+ withModuleJson,
41
+ withNativeInputsStamp,
42
+ withProfiles,
43
+ withProjectBuildProfile,
44
+ withReactNativeConfig,
45
+ withRootHvigor,
46
+ withRootOhPackage,
47
+ withStrings,
48
+ withWorker,
49
+ } from './mods';
50
+ export type {
51
+ HarmonyJson,
52
+ HarmonyMediaDescriptor,
53
+ HarmonyMediaMap,
54
+ HarmonyModAction,
55
+ HarmonyModName,
56
+ HarmonyResourceMap,
57
+ } from './mods';
58
+ export {
59
+ getHarmonyConfigPlugins,
60
+ normalizeHarmonyConfigPlugins,
61
+ registerHarmonyConfigPlugin,
62
+ } from './ownership';
63
+ export type { HarmonyConfigPluginOwnership } from './ownership';
64
+ export { HarmonyPaths } from './paths';
65
+ export type {
66
+ HarmonyManagedPaths,
67
+ HarmonyPathsApi,
68
+ HarmonyProjectPathCandidates,
69
+ HarmonyProjectPaths,
70
+ HarmonyResourcePaths,
71
+ } from './paths';