@caperjs/core 0.7.2 → 0.7.4
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/build/index.mjs +1 -1
- package/build/internal/buildFlags.mjs +63 -18
- package/build/internal/schema.mjs +53 -0
- package/build/plugins/pwa.mjs +13 -7
- package/cli/doctor.mjs +53 -2
- package/cli/doctor.test.mjs +80 -1
- package/cli/native.mjs +126 -15
- package/cli/native.test.mjs +219 -3
- package/extras/llms.txt +35 -3
- package/lib/{CaptionsPlugin-COrofpHN.js → CaptionsPlugin-CAgQBcA1.js} +7 -7
- package/lib/{CaptionsPlugin-COrofpHN.js.map → CaptionsPlugin-CAgQBcA1.js.map} +1 -1
- package/lib/{DataAdapter-T-22-_D1.js → DataAdapter-CbyqWMo-.js} +5 -5
- package/lib/{DataAdapter-T-22-_D1.js.map → DataAdapter-CbyqWMo-.js.map} +1 -1
- package/lib/{DebugRenderer-ZN692Pbg.js → DebugRenderer-Bdkpyyt6.js} +2 -2
- package/lib/{DebugRenderer-ZN692Pbg.js.map → DebugRenderer-Bdkpyyt6.js.map} +1 -1
- package/lib/{DevToolsPlugin-CQXFoj1T.js → DevToolsPlugin-Cq5HHN9K.js} +2 -2
- package/lib/{DevToolsPlugin-CQXFoj1T.js.map → DevToolsPlugin-Cq5HHN9K.js.map} +1 -1
- package/lib/{GSAPPlugin-CNkncyXS.js → GSAPPlugin-D-ujhVYo.js} +2 -2
- package/lib/{GSAPPlugin-CNkncyXS.js.map → GSAPPlugin-D-ujhVYo.js.map} +1 -1
- package/lib/{LayoutPlugin-BuJgr9bd.js → LayoutPlugin-DqbwBm-X.js} +4 -4
- package/lib/{LayoutPlugin-BuJgr9bd.js.map → LayoutPlugin-DqbwBm-X.js.map} +1 -1
- package/lib/{ScreenDebugPlugin-kz9Mr6j1.js → ScreenDebugPlugin-CyT8UxEa.js} +3 -3
- package/lib/{ScreenDebugPlugin-kz9Mr6j1.js.map → ScreenDebugPlugin-CyT8UxEa.js.map} +1 -1
- package/lib/{SpinePlugin-DDzD-Qxd.js → SpinePlugin-DyXJyA3x.js} +2 -2
- package/lib/{SpinePlugin-DDzD-Qxd.js.map → SpinePlugin-DyXJyA3x.js.map} +1 -1
- package/lib/{StatsPlugin-tyFGzVjy.js → StatsPlugin-CEhgzWby.js} +4 -4
- package/lib/{StatsPlugin-tyFGzVjy.js.map → StatsPlugin-CEhgzWby.js.map} +1 -1
- package/lib/{VoiceOverPlugin-rTNz_9eb.js → VoiceOverPlugin-CSpNZjpJ.js} +2 -2
- package/lib/{VoiceOverPlugin-rTNz_9eb.js.map → VoiceOverPlugin-CSpNZjpJ.js.map} +1 -1
- package/lib/caper.mjs +126 -129
- package/lib/caper.mjs.map +1 -1
- package/lib/{const-Cj14a5U2.js → const-Bca54QyV.js} +235 -227
- package/lib/{const-Cj14a5U2.js.map → const-Bca54QyV.js.map} +1 -1
- package/lib/core/Application.d.ts +4 -0
- package/lib/core/Application.d.ts.map +1 -1
- package/lib/core/interfaces/IApplicationOptions.d.ts +21 -0
- package/lib/core/interfaces/IApplicationOptions.d.ts.map +1 -1
- package/lib/plugins/OrientationPlugin.d.ts +57 -0
- package/lib/plugins/OrientationPlugin.d.ts.map +1 -0
- package/lib/plugins/OrientationPlugin.test.d.ts +2 -0
- package/lib/plugins/OrientationPlugin.test.d.ts.map +1 -0
- package/lib/plugins/defaults.d.ts.map +1 -1
- package/lib/plugins/index.d.ts +1 -0
- package/lib/plugins/index.d.ts.map +1 -1
- package/lib/{registries-DmNGVLAi.js → registries-C1nPl8B3.js} +593 -502
- package/lib/registries-C1nPl8B3.js.map +1 -0
- package/lib/ui/UICanvas.d.ts +10 -2
- package/lib/ui/UICanvas.d.ts.map +1 -1
- package/lib/utils/index.d.ts +1 -0
- package/lib/utils/index.d.ts.map +1 -1
- package/lib/utils/orientation.d.ts +44 -0
- package/lib/utils/orientation.test.d.ts +2 -0
- package/lib/utils/orientation.test.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/core/Application.ts +10 -0
- package/src/core/interfaces/IApplicationOptions.ts +21 -0
- package/src/plugins/OrientationPlugin.test.ts +252 -0
- package/src/plugins/OrientationPlugin.ts +178 -0
- package/src/plugins/defaults.ts +6 -0
- package/src/plugins/index.ts +1 -0
- package/src/ui/UICanvas.test.ts +23 -1
- package/src/ui/UICanvas.ts +22 -3
- package/src/utils/index.ts +1 -0
- package/src/utils/orientation.d.ts +44 -0
- package/src/utils/orientation.js +37 -0
- package/src/utils/orientation.test.ts +30 -0
- package/src/version.ts +1 -1
- package/lib/registries-DmNGVLAi.js.map +0 -1
package/build/index.mjs
CHANGED
|
@@ -92,7 +92,7 @@ function caperPluginList({ assets = {}, pwa } = {}) {
|
|
|
92
92
|
// place that knows a project overrode it.
|
|
93
93
|
caperConfigPlugin(true, manifestUrl),
|
|
94
94
|
caperDevHelperPlugin(),
|
|
95
|
-
...(effectivePwa ? caperPwaPlugins(effectivePwa) : []),
|
|
95
|
+
...(effectivePwa ? caperPwaPlugins(effectivePwa, { orientation: buildFlags.orientation }) : []),
|
|
96
96
|
];
|
|
97
97
|
}
|
|
98
98
|
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Build flags read out of `caper.config.ts` before anything can execute it. See
|
|
3
|
+
* the comment on `readCaperBuildFlags` for why this is an AST parse.
|
|
4
4
|
*/
|
|
5
5
|
import fs from 'node:fs';
|
|
6
6
|
import path from 'node:path';
|
|
7
7
|
import { AST_NODE_TYPES, findConfigObject, parse } from './ast.mjs';
|
|
8
|
+
import { resolveOrientation } from '../../src/utils/orientation.js';
|
|
8
9
|
import { cwd } from './util.mjs';
|
|
9
10
|
|
|
10
11
|
export function readCaperBuildFlags() {
|
|
11
|
-
const flags = { useWasm: false };
|
|
12
|
+
const flags = { useWasm: false, orientation: undefined };
|
|
12
13
|
const configPath = path.resolve(cwd, 'caper.config.ts');
|
|
13
14
|
if (!fs.existsSync(configPath)) return flags;
|
|
14
15
|
|
|
@@ -22,6 +23,14 @@ export function readCaperBuildFlags() {
|
|
|
22
23
|
|
|
23
24
|
for (const prop of configObject.properties) {
|
|
24
25
|
if (prop.type !== AST_NODE_TYPES.Property || prop.key?.type !== AST_NODE_TYPES.Identifier) continue;
|
|
26
|
+
if (prop.key.name === 'orientation') {
|
|
27
|
+
try {
|
|
28
|
+
flags.orientation = readOrientationLock(prop.value);
|
|
29
|
+
} catch {
|
|
30
|
+
// silent here, like every other build flag; the schema reports it
|
|
31
|
+
}
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
25
34
|
if (!(prop.key.name in flags)) continue;
|
|
26
35
|
if (prop.value?.type === AST_NODE_TYPES.Literal && typeof prop.value.value === 'boolean') {
|
|
27
36
|
flags[prop.key.name] = prop.value.value;
|
|
@@ -30,21 +39,57 @@ export function readCaperBuildFlags() {
|
|
|
30
39
|
return flags;
|
|
31
40
|
}
|
|
32
41
|
|
|
42
|
+
/** A property's value node when it is a string literal, else `undefined`. */
|
|
43
|
+
function stringLiteral(node) {
|
|
44
|
+
return node?.type === AST_NODE_TYPES.Literal && typeof node.value === 'string' ? node.value : undefined;
|
|
45
|
+
}
|
|
46
|
+
|
|
33
47
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
* The lock out of an `orientation` value node: the string literal itself, or
|
|
49
|
+
* the `lock` string literal of an object literal (`overlay` is never read: it
|
|
50
|
+
* may hold a function). Normalized and validated by `resolveOrientation`.
|
|
51
|
+
*/
|
|
52
|
+
function readOrientationLock(node) {
|
|
53
|
+
if (node?.type === AST_NODE_TYPES.ObjectExpression) {
|
|
54
|
+
const lockProp = node.properties.find(
|
|
55
|
+
(p) => p.type === AST_NODE_TYPES.Property && p.key?.type === AST_NODE_TYPES.Identifier && p.key.name === 'lock',
|
|
56
|
+
);
|
|
57
|
+
if (!lockProp) throw new Error("orientation needs a lock: { lock: 'portrait' | 'landscape' }");
|
|
58
|
+
const lock = stringLiteral(lockProp.value);
|
|
59
|
+
if (lock === undefined) throw new Error("orientation.lock must be written as a string literal, 'portrait' or 'landscape'");
|
|
60
|
+
return resolveOrientation({ lock }).lock;
|
|
61
|
+
}
|
|
62
|
+
const value = stringLiteral(node);
|
|
63
|
+
if (value === undefined) {
|
|
64
|
+
throw new Error("orientation must be written as a string literal ('portrait' or 'landscape') or { lock: '...' }");
|
|
65
|
+
}
|
|
66
|
+
return resolveOrientation(value).lock;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* The orientation lock from `<root>/caper.config.ts`, for the native CLI
|
|
71
|
+
* commands and `caper doctor`: `orientation: 'portrait'` or
|
|
72
|
+
* `orientation: { lock: 'portrait', ... }`. Same AST parse as
|
|
73
|
+
* `readCaperBuildFlags`, so nothing is executed and no DOM stub is needed, but
|
|
74
|
+
* strict where that one is silent: it throws when the file does not parse,
|
|
75
|
+
* when no `defineConfig({...})` object literal is found, or when the lock is
|
|
76
|
+
* not `'portrait'` / `'landscape'` written as a string literal. Callers turn
|
|
77
|
+
* the throw into a warning.
|
|
46
78
|
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* broken references the user needs to see).
|
|
79
|
+
* @param {string} root
|
|
80
|
+
* @returns {'portrait' | 'landscape' | undefined} undefined when there is no config file or no `orientation` key
|
|
50
81
|
*/
|
|
82
|
+
export function readConfigOrientation(root) {
|
|
83
|
+
const configPath = path.resolve(root, 'caper.config.ts');
|
|
84
|
+
if (!fs.existsSync(configPath)) return undefined;
|
|
85
|
+
|
|
86
|
+
const configObject = findConfigObject(parse(fs.readFileSync(configPath, 'utf-8')));
|
|
87
|
+
if (configObject?.type !== AST_NODE_TYPES.ObjectExpression) {
|
|
88
|
+
throw new Error('no defineConfig({ ... }) object literal found');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const prop = configObject.properties.find(
|
|
92
|
+
(p) => p.type === AST_NODE_TYPES.Property && p.key?.type === AST_NODE_TYPES.Identifier && p.key.name === 'orientation',
|
|
93
|
+
);
|
|
94
|
+
return prop ? readOrientationLock(prop.value) : undefined;
|
|
95
|
+
}
|
|
@@ -17,6 +17,55 @@ export const pluginConfigSchema = z.union([
|
|
|
17
17
|
]),
|
|
18
18
|
]);
|
|
19
19
|
|
|
20
|
+
const ORIENTATION_LOCK_MESSAGE = "orientation must be 'portrait', 'landscape', or { lock: 'portrait' | 'landscape', overlay? }";
|
|
21
|
+
|
|
22
|
+
const orientationLockSchema = z.enum(['portrait', 'landscape'], { error: ORIENTATION_LOCK_MESSAGE });
|
|
23
|
+
|
|
24
|
+
const orientationObjectSchema = z.strictObject(
|
|
25
|
+
{
|
|
26
|
+
lock: z.enum(['portrait', 'landscape'], {
|
|
27
|
+
error: (issue) =>
|
|
28
|
+
issue.input === undefined
|
|
29
|
+
? "orientation.lock is required: 'portrait' or 'landscape'"
|
|
30
|
+
: "orientation.lock must be 'portrait' or 'landscape'",
|
|
31
|
+
}),
|
|
32
|
+
overlay: z
|
|
33
|
+
.union(
|
|
34
|
+
[
|
|
35
|
+
z.literal(false),
|
|
36
|
+
z.strictObject({
|
|
37
|
+
text: z.string().optional(),
|
|
38
|
+
background: z.string().optional(),
|
|
39
|
+
color: z.string().optional(),
|
|
40
|
+
fontFamily: z.string().optional(),
|
|
41
|
+
className: z.string().optional(),
|
|
42
|
+
element: z.function().optional(),
|
|
43
|
+
}),
|
|
44
|
+
],
|
|
45
|
+
{
|
|
46
|
+
error:
|
|
47
|
+
'orientation.overlay must be false or an object of text, background, color, fontFamily, className (strings) and element (a function)',
|
|
48
|
+
},
|
|
49
|
+
)
|
|
50
|
+
.optional(),
|
|
51
|
+
},
|
|
52
|
+
{ error: (issue) => (issue.code === 'unrecognized_keys' ? `orientation only takes lock and overlay (got ${issue.keys.join(', ')})` : undefined) },
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* `orientation` is a string shorthand or `{ lock, overlay? }`. Validated by
|
|
57
|
+
* picking the branch from the value's type rather than with a `z.union`, whose
|
|
58
|
+
* single "Invalid input" would hide the object branch's precise messages.
|
|
59
|
+
*/
|
|
60
|
+
const orientationSchema = z.any().superRefine((value, ctx) => {
|
|
61
|
+
const schema = value !== null && typeof value === 'object' ? orientationObjectSchema : orientationLockSchema;
|
|
62
|
+
const result = schema.safeParse(value);
|
|
63
|
+
if (result.success) return;
|
|
64
|
+
for (const issue of result.error.issues) {
|
|
65
|
+
ctx.addIssue({ code: 'custom', message: issue.message, path: issue.path });
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
20
69
|
export const caperConfigSchema = z
|
|
21
70
|
.object({
|
|
22
71
|
id: z.string().min(1).optional(),
|
|
@@ -50,6 +99,10 @@ export const caperConfigSchema = z
|
|
|
50
99
|
useHash: z.boolean().optional(),
|
|
51
100
|
// Build-time only — read by readCaperBuildFlags(), no runtime effect.
|
|
52
101
|
useWasm: z.boolean().optional(),
|
|
102
|
+
// `'portrait' | 'landscape' | { lock, overlay? }`. Read by the native CLI
|
|
103
|
+
// (`caper native init|android`), the PWA manifest default, and at runtime by
|
|
104
|
+
// the `orientation` plugin.
|
|
105
|
+
orientation: orientationSchema.optional(),
|
|
53
106
|
showStats: z.boolean().optional(),
|
|
54
107
|
showSceneDebugMenu: z.boolean().optional(),
|
|
55
108
|
resizeToContainer: z.boolean().optional(),
|
package/build/plugins/pwa.mjs
CHANGED
|
@@ -129,8 +129,12 @@ function defaultWorkbox() {
|
|
|
129
129
|
};
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
/**
|
|
133
|
-
|
|
132
|
+
/**
|
|
133
|
+
* Caper's vite-plugin-pwa defaults.
|
|
134
|
+
*
|
|
135
|
+
* @param {{ orientation?: 'portrait' | 'landscape' }} [caperConfig] `orientation` from caper.config.ts, if set
|
|
136
|
+
*/
|
|
137
|
+
export function defaultPwaOptions({ orientation } = {}) {
|
|
134
138
|
const app = readAppIdentity();
|
|
135
139
|
|
|
136
140
|
return {
|
|
@@ -162,7 +166,7 @@ export function defaultPwaOptions() {
|
|
|
162
166
|
background_color: '#000000',
|
|
163
167
|
display: 'fullscreen',
|
|
164
168
|
display_override: ['fullscreen', 'standalone', 'minimal-ui'],
|
|
165
|
-
orientation: 'any',
|
|
169
|
+
orientation: orientation ?? 'any',
|
|
166
170
|
categories: ['games', 'entertainment'],
|
|
167
171
|
},
|
|
168
172
|
workbox: defaultWorkbox(),
|
|
@@ -204,10 +208,11 @@ function caperPwaDefaultsPlugin(options, projectSetIcons) {
|
|
|
204
208
|
* defaults, producing the options vite-plugin-pwa is given.
|
|
205
209
|
*
|
|
206
210
|
* @param {object} pwa Project options, merged over `defaultPwaOptions()`.
|
|
211
|
+
* @param {{ orientation?: 'portrait' | 'landscape' }} [caperConfig] build flags read out of caper.config.ts
|
|
207
212
|
*/
|
|
208
|
-
export function resolvePwaOptions(pwa) {
|
|
213
|
+
export function resolvePwaOptions(pwa, caperConfig = {}) {
|
|
209
214
|
const { autoRegister: _autoRegister, update = 'prompt', ...projectOptions } = pwa;
|
|
210
|
-
const options = deepMerge(defaultPwaOptions(), projectOptions);
|
|
215
|
+
const options = deepMerge(defaultPwaOptions(caperConfig), projectOptions);
|
|
211
216
|
|
|
212
217
|
// `update` is caper's plain-language spelling of registerType. 'prompt' and
|
|
213
218
|
// 'manual' both wait for the user — they differ only in who draws the UI, which
|
|
@@ -222,10 +227,11 @@ export function resolvePwaOptions(pwa) {
|
|
|
222
227
|
|
|
223
228
|
/**
|
|
224
229
|
* @param {object} pwa Project options, merged over `defaultPwaOptions()`.
|
|
230
|
+
* @param {{ orientation?: 'portrait' | 'landscape' }} [caperConfig] build flags read out of caper.config.ts
|
|
225
231
|
* @returns {import('vite').PluginOption[]}
|
|
226
232
|
*/
|
|
227
|
-
export function caperPwaPlugins(pwa) {
|
|
228
|
-
const { options, projectSetIcons } = resolvePwaOptions(pwa);
|
|
233
|
+
export function caperPwaPlugins(pwa, caperConfig = {}) {
|
|
234
|
+
const { options, projectSetIcons } = resolvePwaOptions(pwa, caperConfig);
|
|
229
235
|
|
|
230
236
|
return [caperPwaDefaultsPlugin(options, projectSetIcons), VitePWA(options)];
|
|
231
237
|
}
|
package/cli/doctor.mjs
CHANGED
|
@@ -7,7 +7,17 @@ import os from 'node:os';
|
|
|
7
7
|
import path from 'node:path';
|
|
8
8
|
import { fileURLToPath } from 'node:url';
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
ANDROID_MANIFEST,
|
|
12
|
+
ANDROID_RUST_TARGETS,
|
|
13
|
+
ANDROID_SCREEN_ORIENTATION,
|
|
14
|
+
findMainActivity,
|
|
15
|
+
missingRustTargets,
|
|
16
|
+
readManifestOrientation,
|
|
17
|
+
readOrientation,
|
|
18
|
+
resolveAndroidEnv,
|
|
19
|
+
TAURI_PLUGIN_PERMISSIONS,
|
|
20
|
+
} from './native.mjs';
|
|
11
21
|
|
|
12
22
|
/**
|
|
13
23
|
* `caper doctor` — one-shot health report for a Caper app.
|
|
@@ -203,7 +213,14 @@ const resolveEffectiveCompilerOptions = (configFile, ancestors = new Set(), dept
|
|
|
203
213
|
|
|
204
214
|
export async function runChecks(
|
|
205
215
|
cwd,
|
|
206
|
-
{
|
|
216
|
+
{
|
|
217
|
+
online = true,
|
|
218
|
+
run = defaultDoctorRun,
|
|
219
|
+
platform = process.platform,
|
|
220
|
+
env = process.env,
|
|
221
|
+
homedir = os.homedir(),
|
|
222
|
+
loadConfig = undefined,
|
|
223
|
+
} = {},
|
|
207
224
|
) {
|
|
208
225
|
const checks = [];
|
|
209
226
|
const installedVersion = readInstalledVersion();
|
|
@@ -497,6 +514,40 @@ export async function runChecks(
|
|
|
497
514
|
} else {
|
|
498
515
|
push(checks, 'native-android-bars', 'warn', 'MainActivity does not hide the system bars', 'caper native android');
|
|
499
516
|
}
|
|
517
|
+
|
|
518
|
+
const { orientation, warning: orientationWarning } = await readOrientation(cwd, loadConfig);
|
|
519
|
+
let manifest = '';
|
|
520
|
+
try {
|
|
521
|
+
manifest = fs.readFileSync(path.join(srcTauriDir, ANDROID_MANIFEST), 'utf-8');
|
|
522
|
+
} catch {
|
|
523
|
+
// no lock found; compared below
|
|
524
|
+
}
|
|
525
|
+
const locked = readManifestOrientation(manifest);
|
|
526
|
+
const expected = ANDROID_SCREEN_ORIENTATION[orientation];
|
|
527
|
+
if (orientationWarning) {
|
|
528
|
+
push(checks, 'native-android-orientation', 'warn', 'could not read caper.config.ts orientation', "write it as orientation: 'portrait' or 'landscape'");
|
|
529
|
+
} else if (!expected && !locked) {
|
|
530
|
+
push(checks, 'native-android-orientation', 'ok', 'no orientation lock');
|
|
531
|
+
} else if (expected === locked) {
|
|
532
|
+
push(checks, 'native-android-orientation', 'ok', `orientation ${orientation} (AndroidManifest ${locked})`);
|
|
533
|
+
} else if (!expected) {
|
|
534
|
+
// `caper native android` leaves the manifest alone when orientation is unset, so it is not the fix here.
|
|
535
|
+
push(
|
|
536
|
+
checks,
|
|
537
|
+
'native-android-orientation',
|
|
538
|
+
'warn',
|
|
539
|
+
`AndroidManifest locks orientation to ${locked}, caper.config.ts sets none`,
|
|
540
|
+
'set orientation in caper.config.ts, or remove android:screenOrientation from AndroidManifest.xml',
|
|
541
|
+
);
|
|
542
|
+
} else {
|
|
543
|
+
push(
|
|
544
|
+
checks,
|
|
545
|
+
'native-android-orientation',
|
|
546
|
+
'warn',
|
|
547
|
+
`caper.config.ts orientation ${orientation}, AndroidManifest ${locked ? `locks ${locked}` : 'has no lock'}`,
|
|
548
|
+
'caper native android',
|
|
549
|
+
);
|
|
550
|
+
}
|
|
500
551
|
}
|
|
501
552
|
}
|
|
502
553
|
|
package/cli/doctor.test.mjs
CHANGED
|
@@ -712,8 +712,9 @@ describe('runChecks native-android rows', () => {
|
|
|
712
712
|
|
|
713
713
|
const allTargets = 'aarch64-linux-android\narmv7-linux-androideabi\ni686-linux-android\nx86_64-linux-android\n';
|
|
714
714
|
|
|
715
|
-
function check(cwd, env, responses = { 'rustup target list --installed': allTargets }) {
|
|
715
|
+
function check(cwd, env, responses = { 'rustup target list --installed': allTargets }, loadConfig = () => ({})) {
|
|
716
716
|
return runChecks(cwd, {
|
|
717
|
+
loadConfig,
|
|
717
718
|
online: false,
|
|
718
719
|
platform: 'linux',
|
|
719
720
|
env,
|
|
@@ -814,4 +815,82 @@ describe('runChecks native-android rows', () => {
|
|
|
814
815
|
expect(pageSize.hint).toMatch(/caper native android/);
|
|
815
816
|
expect(find(checks, 'native-android-bars').status).toBe('warn');
|
|
816
817
|
});
|
|
818
|
+
|
|
819
|
+
describe('native-android-orientation', () => {
|
|
820
|
+
const MANIFEST = '<manifest>\n <application>\n <activity\n android:name=".MainActivity"\n android:exported="true">\n </activity>\n </application>\n</manifest>\n';
|
|
821
|
+
const manifestPath = (cwd) => path.join(cwd, 'src-tauri/gen/android/app/src/main/AndroidManifest.xml');
|
|
822
|
+
const writeManifest = (cwd, value) =>
|
|
823
|
+
fs.writeFileSync(
|
|
824
|
+
manifestPath(cwd),
|
|
825
|
+
value ? MANIFEST.replace('android:name=".MainActivity"', `android:name=".MainActivity"\n android:screenOrientation="${value}"`) : MANIFEST,
|
|
826
|
+
'utf-8',
|
|
827
|
+
);
|
|
828
|
+
|
|
829
|
+
async function orientationRow(cwd, loadConfig) {
|
|
830
|
+
const { bin, ndk, java } = fs.existsSync(path.join(cwd, 'bin')) ? { bin: path.join(cwd, 'bin'), ndk: path.join(cwd, 'ndk'), java: path.join(cwd, 'java') } : scaffoldAndroid(cwd);
|
|
831
|
+
return find(await check(cwd, { PATH: bin, NDK_HOME: ndk, JAVA_HOME: java }, undefined, loadConfig), 'native-android-orientation');
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
it('is absent when src-tauri/gen/android does not exist', async () => {
|
|
835
|
+
const cwd = makeTempDir();
|
|
836
|
+
writeTauriConf(cwd);
|
|
837
|
+
writeTauriCli(cwd, '2.11.4');
|
|
838
|
+
const checks = await check(cwd, {}, undefined, () => ({ orientation: 'portrait' }));
|
|
839
|
+
expect(find(checks, 'native-android-orientation')).toBeUndefined();
|
|
840
|
+
});
|
|
841
|
+
|
|
842
|
+
it('is ok with no orientation lock when neither side sets one', async () => {
|
|
843
|
+
const cwd = makeTempDir();
|
|
844
|
+
scaffoldAndroid(cwd);
|
|
845
|
+
writeManifest(cwd);
|
|
846
|
+
const row = await orientationRow(cwd, () => ({}));
|
|
847
|
+
expect(row.status).toBe('ok');
|
|
848
|
+
expect(row.label).toMatch(/no orientation lock/);
|
|
849
|
+
});
|
|
850
|
+
|
|
851
|
+
it('is ok when the manifest matches caper.config', async () => {
|
|
852
|
+
const cwd = makeTempDir();
|
|
853
|
+
scaffoldAndroid(cwd);
|
|
854
|
+
writeManifest(cwd, 'sensorLandscape');
|
|
855
|
+
expect((await orientationRow(cwd, () => ({ orientation: 'landscape' }))).status).toBe('ok');
|
|
856
|
+
});
|
|
857
|
+
|
|
858
|
+
it('warns with the caper native android hint on a mismatch', async () => {
|
|
859
|
+
const cwd = makeTempDir();
|
|
860
|
+
scaffoldAndroid(cwd);
|
|
861
|
+
writeManifest(cwd, 'portrait');
|
|
862
|
+
const row = await orientationRow(cwd, () => ({ orientation: 'landscape' }));
|
|
863
|
+
expect(row.status).toBe('warn');
|
|
864
|
+
expect(row.hint).toBe('caper native android');
|
|
865
|
+
});
|
|
866
|
+
|
|
867
|
+
it('warns when caper.config sets an orientation the manifest lacks', async () => {
|
|
868
|
+
const cwd = makeTempDir();
|
|
869
|
+
scaffoldAndroid(cwd);
|
|
870
|
+
writeManifest(cwd);
|
|
871
|
+
const row = await orientationRow(cwd, () => ({ orientation: 'portrait' }));
|
|
872
|
+
expect(row.status).toBe('warn');
|
|
873
|
+
expect(row.hint).toBe('caper native android');
|
|
874
|
+
});
|
|
875
|
+
|
|
876
|
+
it('warns when the manifest has a lock but caper.config sets none', async () => {
|
|
877
|
+
const cwd = makeTempDir();
|
|
878
|
+
scaffoldAndroid(cwd);
|
|
879
|
+
writeManifest(cwd, 'portrait');
|
|
880
|
+
const row = await orientationRow(cwd, () => ({}));
|
|
881
|
+
expect(row.status).toBe('warn');
|
|
882
|
+
expect(row.hint).toMatch(/caper\.config\.ts/);
|
|
883
|
+
});
|
|
884
|
+
|
|
885
|
+
it('warns when caper.config orientation cannot be read', async () => {
|
|
886
|
+
const cwd = makeTempDir();
|
|
887
|
+
scaffoldAndroid(cwd);
|
|
888
|
+
writeManifest(cwd);
|
|
889
|
+
const row = await orientationRow(cwd, () => {
|
|
890
|
+
throw new Error('boom');
|
|
891
|
+
});
|
|
892
|
+
expect(row.status).toBe('warn');
|
|
893
|
+
expect(row.label).toMatch(/could not read caper\.config\.ts orientation/);
|
|
894
|
+
});
|
|
895
|
+
});
|
|
817
896
|
});
|