flowboard-react 0.6.5 → 0.6.6
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 +2 -0
- package/bin/setup.js +131 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -30,6 +30,8 @@ npx --package flowboard-react flowboard-setup --dry-run
|
|
|
30
30
|
|
|
31
31
|
`flowboard-react` keeps heavy native modules as peer dependencies to avoid duplicate binaries and version conflicts in host apps. The setup command installs the required peer set for you.
|
|
32
32
|
|
|
33
|
+
By default, `flowboard-setup` installs only missing peers. If your app already declares one of these native packages, the setup command leaves it untouched so it does not force a downgrade. Use `--upgrade` to install Flowboard's validated package matrix explicitly.
|
|
34
|
+
|
|
33
35
|
## Expo Support
|
|
34
36
|
|
|
35
37
|
Expo Go is not supported. This SDK depends on custom native modules, so Expo users need a development build, `expo prebuild`, or EAS Build.
|
package/bin/setup.js
CHANGED
|
@@ -64,6 +64,14 @@ function compareSemver(left, right) {
|
|
|
64
64
|
return left.patch - right.patch;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
function incrementPatch(version) {
|
|
68
|
+
return {
|
|
69
|
+
major: version.major,
|
|
70
|
+
minor: version.minor,
|
|
71
|
+
patch: version.patch + 1,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
67
75
|
function rangeAcceptsVersion(spec, version) {
|
|
68
76
|
const normalized = String(spec || '').trim();
|
|
69
77
|
if (!normalized) return false;
|
|
@@ -118,6 +126,74 @@ function rangeAcceptsVersion(spec, version) {
|
|
|
118
126
|
}
|
|
119
127
|
}
|
|
120
128
|
|
|
129
|
+
function extractLowerBound(spec) {
|
|
130
|
+
const normalized = String(spec || '').trim();
|
|
131
|
+
if (
|
|
132
|
+
!normalized ||
|
|
133
|
+
normalized === '*' ||
|
|
134
|
+
normalized === 'latest' ||
|
|
135
|
+
normalized.startsWith('workspace:')
|
|
136
|
+
) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (normalized.includes('||')) {
|
|
141
|
+
const bounds = normalized
|
|
142
|
+
.split('||')
|
|
143
|
+
.map((part) => extractLowerBound(part.trim()))
|
|
144
|
+
.filter(Boolean);
|
|
145
|
+
|
|
146
|
+
if (bounds.length === 0) return null;
|
|
147
|
+
|
|
148
|
+
return bounds.reduce((lowest, candidate) =>
|
|
149
|
+
compareSemver(candidate, lowest) < 0 ? candidate : lowest
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const comparators = normalized.split(/\s+/).filter(Boolean);
|
|
154
|
+
if (comparators.length > 1) {
|
|
155
|
+
const lowerBounds = comparators
|
|
156
|
+
.map((part) => extractLowerBound(part))
|
|
157
|
+
.filter(Boolean);
|
|
158
|
+
|
|
159
|
+
if (lowerBounds.length === 0) return null;
|
|
160
|
+
|
|
161
|
+
return lowerBounds.reduce((highest, candidate) =>
|
|
162
|
+
compareSemver(candidate, highest) > 0 ? candidate : highest
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const operatorMatch = normalized.match(/^(>=|<=|>|<|\^|~)/);
|
|
167
|
+
const operator = operatorMatch ? operatorMatch[1] : '';
|
|
168
|
+
const base = parseSemver(normalized.slice(operator.length));
|
|
169
|
+
if (!base) {
|
|
170
|
+
return parseSemver(normalized);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
switch (operator) {
|
|
174
|
+
case '>':
|
|
175
|
+
return incrementPatch(base);
|
|
176
|
+
case '>=':
|
|
177
|
+
case '^':
|
|
178
|
+
case '~':
|
|
179
|
+
case '':
|
|
180
|
+
return base;
|
|
181
|
+
default:
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function specMeetsValidatedFloor(spec, version) {
|
|
187
|
+
if (!spec) return false;
|
|
188
|
+
if (rangeAcceptsVersion(spec, version)) return true;
|
|
189
|
+
|
|
190
|
+
const lowerBound = extractLowerBound(spec);
|
|
191
|
+
const validated = parseSemver(version);
|
|
192
|
+
|
|
193
|
+
if (!lowerBound || !validated) return false;
|
|
194
|
+
return compareSemver(lowerBound, validated) >= 0;
|
|
195
|
+
}
|
|
196
|
+
|
|
121
197
|
function getManifest(root) {
|
|
122
198
|
const manifestPath = path.join(root, 'package.json');
|
|
123
199
|
if (!fs.existsSync(manifestPath)) {
|
|
@@ -170,13 +246,33 @@ function hasReactNative(manifest) {
|
|
|
170
246
|
}
|
|
171
247
|
|
|
172
248
|
function selectPackages(manifest, options) {
|
|
173
|
-
return BASE_PACKAGES.filter(([packageName
|
|
249
|
+
return BASE_PACKAGES.filter(([packageName]) => {
|
|
174
250
|
if (options.upgrade) return true;
|
|
175
251
|
const existingSpec = getPackageSpec(manifest, packageName);
|
|
176
|
-
|
|
252
|
+
|
|
253
|
+
// Never replace an existing host-app dependency unless the user opts into
|
|
254
|
+
// the validated matrix with --upgrade.
|
|
255
|
+
if (existingSpec) return false;
|
|
256
|
+
|
|
257
|
+
return true;
|
|
177
258
|
}).map(([name, version]) => ({ name, version }));
|
|
178
259
|
}
|
|
179
260
|
|
|
261
|
+
function collectCompatibilityWarnings(manifest, options) {
|
|
262
|
+
if (options.upgrade) return [];
|
|
263
|
+
|
|
264
|
+
return BASE_PACKAGES.reduce((warnings, [packageName, version]) => {
|
|
265
|
+
const existingSpec = getPackageSpec(manifest, packageName);
|
|
266
|
+
if (!existingSpec) return warnings;
|
|
267
|
+
if (specMeetsValidatedFloor(existingSpec, version)) return warnings;
|
|
268
|
+
|
|
269
|
+
warnings.push(
|
|
270
|
+
`${packageName}@${existingSpec} is already declared in the host app and may be below Flowboard's validated floor (${version}). flowboard-setup will leave it untouched to avoid forcing a downgrade. Use --upgrade to install the validated version explicitly.`
|
|
271
|
+
);
|
|
272
|
+
return warnings;
|
|
273
|
+
}, []);
|
|
274
|
+
}
|
|
275
|
+
|
|
180
276
|
function selectExpoExtras(manifest, options) {
|
|
181
277
|
return EXPO_EXTRA_PACKAGES.filter((packageName) => {
|
|
182
278
|
if (options.upgrade) return true;
|
|
@@ -222,7 +318,7 @@ function buildInstallCommands({ expo, packageManager, packages, expoExtras }) {
|
|
|
222
318
|
commands.push({
|
|
223
319
|
args: installArgsByManager[packageManager] || installArgsByManager.npm,
|
|
224
320
|
command: commandName(packageManager),
|
|
225
|
-
title: 'Install
|
|
321
|
+
title: 'Install missing React Native peer dependencies',
|
|
226
322
|
});
|
|
227
323
|
|
|
228
324
|
return commands;
|
|
@@ -303,7 +399,14 @@ function printNextSteps({ expo, projectRoot }) {
|
|
|
303
399
|
);
|
|
304
400
|
}
|
|
305
401
|
|
|
306
|
-
function printPlan({
|
|
402
|
+
function printPlan({
|
|
403
|
+
expo,
|
|
404
|
+
packageManager,
|
|
405
|
+
packages,
|
|
406
|
+
expoExtras,
|
|
407
|
+
commands,
|
|
408
|
+
warnings,
|
|
409
|
+
}) {
|
|
307
410
|
console.log(
|
|
308
411
|
`[flowboard-setup] Target: ${
|
|
309
412
|
expo ? 'Expo development build' : `React Native CLI (${packageManager})`
|
|
@@ -311,14 +414,23 @@ function printPlan({ expo, packageManager, packages, expoExtras, commands }) {
|
|
|
311
414
|
);
|
|
312
415
|
|
|
313
416
|
if (packages.length > 0) {
|
|
314
|
-
console.log('[flowboard-setup] Packages to install:');
|
|
417
|
+
console.log('[flowboard-setup] Packages to install (missing):');
|
|
315
418
|
packages.forEach((entry) => {
|
|
316
419
|
console.log(` - ${entry.name}${expo ? '' : `@${entry.version}`}`);
|
|
317
420
|
});
|
|
318
421
|
} else {
|
|
319
422
|
console.log(
|
|
320
|
-
'[flowboard-setup]
|
|
423
|
+
'[flowboard-setup] All required peer dependencies are already present in your package.json.'
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (warnings.length > 0) {
|
|
428
|
+
console.log(
|
|
429
|
+
'[flowboard-setup] Compatibility warnings for existing host-app packages:'
|
|
321
430
|
);
|
|
431
|
+
warnings.forEach((warning) => {
|
|
432
|
+
console.log(` - ${warning}`);
|
|
433
|
+
});
|
|
322
434
|
}
|
|
323
435
|
|
|
324
436
|
if (expoExtras.length > 0) {
|
|
@@ -329,7 +441,7 @@ function printPlan({ expo, packageManager, packages, expoExtras, commands }) {
|
|
|
329
441
|
}
|
|
330
442
|
|
|
331
443
|
if (commands.length > 0) {
|
|
332
|
-
console.log('[flowboard-setup] Commands:');
|
|
444
|
+
console.log('[flowboard-setup] Commands to be executed:');
|
|
333
445
|
commands.forEach((command) => {
|
|
334
446
|
console.log(` - ${formatCommand(command)}`);
|
|
335
447
|
});
|
|
@@ -363,6 +475,7 @@ async function main(rawArgs = process.argv.slice(2)) {
|
|
|
363
475
|
const expo = isExpoProject(manifest);
|
|
364
476
|
const packageManager = detectPackageManager(projectRoot, manifest);
|
|
365
477
|
const packages = selectPackages(manifest, options);
|
|
478
|
+
const warnings = collectCompatibilityWarnings(manifest, options);
|
|
366
479
|
const expoExtras = expo ? selectExpoExtras(manifest, options) : [];
|
|
367
480
|
const commands = buildInstallCommands({
|
|
368
481
|
expo,
|
|
@@ -371,7 +484,14 @@ async function main(rawArgs = process.argv.slice(2)) {
|
|
|
371
484
|
packages,
|
|
372
485
|
});
|
|
373
486
|
|
|
374
|
-
printPlan({
|
|
487
|
+
printPlan({
|
|
488
|
+
commands,
|
|
489
|
+
expo,
|
|
490
|
+
expoExtras,
|
|
491
|
+
packageManager,
|
|
492
|
+
packages,
|
|
493
|
+
warnings,
|
|
494
|
+
});
|
|
375
495
|
|
|
376
496
|
if (commands.length === 0) {
|
|
377
497
|
printNextSteps({ expo, projectRoot });
|
|
@@ -415,9 +535,12 @@ module.exports = {
|
|
|
415
535
|
main,
|
|
416
536
|
parseArgs,
|
|
417
537
|
parseSemver,
|
|
538
|
+
collectCompatibilityWarnings,
|
|
539
|
+
extractLowerBound,
|
|
418
540
|
rangeAcceptsVersion,
|
|
419
541
|
selectExpoExtras,
|
|
420
542
|
selectPackages,
|
|
543
|
+
specMeetsValidatedFloor,
|
|
421
544
|
};
|
|
422
545
|
|
|
423
546
|
if (require.main === module) {
|