nativekeel 0.1.1 → 0.1.3
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 +1 -1
- package/src/known-issues.js +12 -0
- package/src/plan.js +56 -0
package/package.json
CHANGED
package/src/known-issues.js
CHANGED
|
@@ -30,6 +30,18 @@ export const KNOWN_ISSUES = [
|
|
|
30
30
|
detail: "Its TurboModule spec uses EventEmitter properties that this React Native version's codegen rejects (UnsupportedModulePropertyParserError, property 'onDownloadBegin'). Pin 2.36.2 until React Native is upgraded. Its peer range says react-native: *, so npm will not warn you.",
|
|
31
31
|
source: 'real upgrade of an RN 0.77 app, 2026-10-03',
|
|
32
32
|
},
|
|
33
|
+
{
|
|
34
|
+
id: 'linear-gradient-interop-unmount',
|
|
35
|
+
pkg: 'react-native-linear-gradient',
|
|
36
|
+
from: '2.0.0',
|
|
37
|
+
to: '2.99.99',
|
|
38
|
+
rnFrom: 76,
|
|
39
|
+
when: 'newArch',
|
|
40
|
+
severity: 'high',
|
|
41
|
+
title: 'react-native-linear-gradient 2.x crashes the New Architecture when a screen unmounts',
|
|
42
|
+
detail: "2.x has no Fabric component, so BVLinearGradient runs through the interop layer. Its children are not detached before React Native recycles them: \"RCTComponentViewRegistry: Attempt to recycle a mounted view\" (an abort on iOS, right after login in the app where it was found). React Native 0.76+ draws gradients itself: replace it with a small component that sets experimental_backgroundImage: 'linear-gradient(...)' and drop the native package.",
|
|
43
|
+
source: 'real upgrade of an RN 0.80 app, 2026-10-04 (UI test after login)',
|
|
44
|
+
},
|
|
33
45
|
];
|
|
34
46
|
|
|
35
47
|
// Semver-ish compare on major.minor.patch, ignoring pre-release tags.
|
package/src/plan.js
CHANGED
|
@@ -75,6 +75,56 @@ export function complexity(findings) {
|
|
|
75
75
|
return { score, size };
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
// UI test tooling the project already has, so the plan can say "run yours" instead of
|
|
79
|
+
// "write some". Looks for Maestro flows and the common e2e runners.
|
|
80
|
+
export function existingUiTests(root, installed) {
|
|
81
|
+
for (const name of ['detox', 'appium', 'webdriverio', '@wdio/cli']) {
|
|
82
|
+
if (installed.has(name)) return name === 'detox' ? 'Detox' : 'Appium';
|
|
83
|
+
}
|
|
84
|
+
for (const dir of ['.maestro', 'maestro', 'e2e', '.e2e']) {
|
|
85
|
+
try {
|
|
86
|
+
const files = fs.readdirSync(path.join(root, dir), { recursive: true });
|
|
87
|
+
if (files.some((f) => /\.ya?ml$/.test(String(f)))) {
|
|
88
|
+
const text = files
|
|
89
|
+
.filter((f) => /\.ya?ml$/.test(String(f)))
|
|
90
|
+
.slice(0, 20)
|
|
91
|
+
.map((f) => fs.readFileSync(path.join(root, dir, String(f)), 'utf8'))
|
|
92
|
+
.join('\n');
|
|
93
|
+
if (/^appId:/m.test(text)) return 'Maestro';
|
|
94
|
+
}
|
|
95
|
+
} catch {
|
|
96
|
+
// no such directory
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function safetyNetPhase(tool) {
|
|
103
|
+
const why =
|
|
104
|
+
'A build that compiles and launches can still crash after login or hide a button. On a real upgrade, UI flows caught three such bugs that build and launch checks missed.';
|
|
105
|
+
if (tool) {
|
|
106
|
+
return {
|
|
107
|
+
title: 'Set up a safety net',
|
|
108
|
+
why,
|
|
109
|
+
steps: [
|
|
110
|
+
`Run your ${tool} suite on both platforms on the current version before changing anything, and keep the results as the baseline.`,
|
|
111
|
+
'Make sure it covers what users do first: launch, sign-in with a test account, and every tab or main screen. Add flows where it does not.',
|
|
112
|
+
'Run it again at the end of every phase below.',
|
|
113
|
+
],
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
title: 'Set up a safety net',
|
|
118
|
+
why,
|
|
119
|
+
steps: [
|
|
120
|
+
'Before changing anything, write a few UI flows (Maestro is the quickest: maestro.mobile.dev): launch, sign-in with a test account, and every tab or main screen.',
|
|
121
|
+
'Keep test credentials in environment variables, never in the repo. Never let a flow press a button that writes to production (sign-up, purchase, posting).',
|
|
122
|
+
'Assert that no error banner or red screen appears, not only that the app is running: a native module that fails to load can leave the process alive behind a red screen.',
|
|
123
|
+
'Run the flows on both platforms on the current version, then again at the end of every phase below.',
|
|
124
|
+
],
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
78
128
|
export function buildPlan(result) {
|
|
79
129
|
const pm = commands[packageManager(result.project.root)];
|
|
80
130
|
const installed = new Set(result.deps.map((d) => d.name));
|
|
@@ -323,6 +373,12 @@ export function buildPlan(result) {
|
|
|
323
373
|
});
|
|
324
374
|
}
|
|
325
375
|
|
|
376
|
+
// Only worth it when the plan changes code: secrets alone do not need UI tests.
|
|
377
|
+
const leaksFirst = phases[0] && phases[0].title === 'Stop the leaks' ? 1 : 0;
|
|
378
|
+
if (phases.length > leaksFirst) {
|
|
379
|
+
phases.splice(leaksFirst, 0, safetyNetPhase(existingUiTests(result.project.root, installed)));
|
|
380
|
+
}
|
|
381
|
+
|
|
326
382
|
phases.push({
|
|
327
383
|
title: 'Verify before you ship',
|
|
328
384
|
why: 'An upgrade is done when the release build works on real devices, not when it compiles.',
|