- App.tsx: full navigation (Auth stack + Main tabs with 5 screens) - Auth: LoginScreen, RegisterScreen, ForgotPasswordScreen - HomeScreen: dashboard with IoT metrics, weather widget, alerts, quick actions, sensors - MapScreen: interactive map with layer toggles (6 layers) - MarketplaceScreen: categories (6), products (5), search - ChatScreen: AI chat with quick prompts (4), bot responses - ProfileScreen: user info, stats, menu (9 items), logout - AlertsScreen: alert list with severity, acknowledge - SensorsScreen: sensor list with type filters (6 types), search - ZonesScreen: zone cards with stats - SettingsScreen: language picker (FR/EN/ES/DE), privacy, about - Stores: iotStore (sensors, zones, alerts), notificationStore, uiStore + i18n - Hooks: useSensors, useAlerts, useNotifications, useLocation - Components: Card, Button, LoadingSpinner, ErrorBoundary, Header - Services: iotService, notificationService (with axios API client) - Utils: formatters (temp, AQI, noise, dates), validators (email, password, IBAN) - Theme: colors.ts with full design system (Blue Ocean palette) - Ditto: fixed MongoDB connection, new JWT secrets, official gateway image
212 lines
6.2 KiB
JavaScript
212 lines
6.2 KiB
JavaScript
"use strict";
|
|
|
|
const getDefaultConfig = require("./defaults");
|
|
const validConfig = require("./defaults/validConfig");
|
|
const cosmiconfig = require("cosmiconfig");
|
|
const fs = require("fs");
|
|
const { validate } = require("jest-validate");
|
|
const MetroCache = require("metro-cache");
|
|
const path = require("path");
|
|
const { dirname, join } = require("path");
|
|
function overrideArgument(arg) {
|
|
if (arg == null) {
|
|
return arg;
|
|
}
|
|
if (Array.isArray(arg)) {
|
|
return arg[arg.length - 1];
|
|
}
|
|
return arg;
|
|
}
|
|
const explorer = cosmiconfig("metro", {
|
|
searchPlaces: [
|
|
"metro.config.js",
|
|
"metro.config.cjs",
|
|
"metro.config.json",
|
|
"package.json",
|
|
],
|
|
loaders: {
|
|
".json": cosmiconfig.loadJson,
|
|
".yaml": cosmiconfig.loadYaml,
|
|
".yml": cosmiconfig.loadYaml,
|
|
".js": cosmiconfig.loadJs,
|
|
".cjs": cosmiconfig.loadJs,
|
|
".es6": cosmiconfig.loadJs,
|
|
noExt: cosmiconfig.loadYaml,
|
|
},
|
|
});
|
|
const isFile = (filePath) =>
|
|
fs.existsSync(filePath) && !fs.lstatSync(filePath).isDirectory();
|
|
const resolve = (filePath) => {
|
|
try {
|
|
return require.resolve(filePath);
|
|
} catch (error) {
|
|
if (path.isAbsolute(filePath) || error.code !== "MODULE_NOT_FOUND") {
|
|
throw error;
|
|
}
|
|
}
|
|
const possiblePath = path.resolve(process.cwd(), filePath);
|
|
return isFile(possiblePath) ? possiblePath : filePath;
|
|
};
|
|
async function resolveConfig(filePath, cwd) {
|
|
if (filePath) {
|
|
return explorer.load(resolve(filePath));
|
|
}
|
|
const result = await explorer.search(cwd);
|
|
if (result == null) {
|
|
return {
|
|
isEmpty: true,
|
|
filepath: join(cwd || process.cwd(), "metro.config.stub.js"),
|
|
config: {},
|
|
};
|
|
}
|
|
return result;
|
|
}
|
|
function mergeConfig(defaultConfig, ...configs) {
|
|
return configs.reduce(
|
|
(totalConfig, nextConfig) => ({
|
|
...totalConfig,
|
|
...nextConfig,
|
|
cacheStores:
|
|
nextConfig.cacheStores != null
|
|
? typeof nextConfig.cacheStores === "function"
|
|
? nextConfig.cacheStores(MetroCache)
|
|
: nextConfig.cacheStores
|
|
: totalConfig.cacheStores,
|
|
resolver: {
|
|
...totalConfig.resolver,
|
|
...(nextConfig.resolver || {}),
|
|
dependencyExtractor:
|
|
nextConfig.resolver && nextConfig.resolver.dependencyExtractor != null
|
|
? resolve(nextConfig.resolver.dependencyExtractor)
|
|
: totalConfig.resolver.dependencyExtractor,
|
|
hasteImplModulePath:
|
|
nextConfig.resolver && nextConfig.resolver.hasteImplModulePath != null
|
|
? resolve(nextConfig.resolver.hasteImplModulePath)
|
|
: totalConfig.resolver.hasteImplModulePath,
|
|
},
|
|
serializer: {
|
|
...totalConfig.serializer,
|
|
...(nextConfig.serializer || {}),
|
|
},
|
|
transformer: {
|
|
...totalConfig.transformer,
|
|
...(nextConfig.transformer || {}),
|
|
babelTransformerPath:
|
|
nextConfig.transformer &&
|
|
nextConfig.transformer.babelTransformerPath != null
|
|
? resolve(nextConfig.transformer.babelTransformerPath)
|
|
: totalConfig.transformer.babelTransformerPath,
|
|
},
|
|
server: {
|
|
...totalConfig.server,
|
|
...(nextConfig.server || {}),
|
|
},
|
|
symbolicator: {
|
|
...totalConfig.symbolicator,
|
|
...(nextConfig.symbolicator || {}),
|
|
},
|
|
watcher: {
|
|
...totalConfig.watcher,
|
|
...nextConfig.watcher,
|
|
watchman: {
|
|
...totalConfig.watcher?.watchman,
|
|
...nextConfig.watcher?.watchman,
|
|
},
|
|
healthCheck: {
|
|
...totalConfig.watcher?.healthCheck,
|
|
...nextConfig.watcher?.healthCheck,
|
|
},
|
|
},
|
|
}),
|
|
defaultConfig
|
|
);
|
|
}
|
|
async function loadMetroConfigFromDisk(path, cwd, defaultConfigOverrides) {
|
|
const resolvedConfigResults = await resolveConfig(path, cwd);
|
|
const { config: configModule, filepath } = resolvedConfigResults;
|
|
const rootPath = dirname(filepath);
|
|
const defaults = await getDefaultConfig(rootPath);
|
|
const defaultConfig = mergeConfig(defaults, defaultConfigOverrides);
|
|
if (typeof configModule === "function") {
|
|
const resultedConfig = await configModule(defaultConfig);
|
|
return mergeConfig(defaultConfig, resultedConfig);
|
|
}
|
|
return mergeConfig(defaultConfig, configModule);
|
|
}
|
|
function overrideConfigWithArguments(config, argv) {
|
|
const output = {
|
|
resolver: {},
|
|
serializer: {},
|
|
server: {},
|
|
transformer: {},
|
|
};
|
|
if (argv.port != null) {
|
|
output.server.port = Number(argv.port);
|
|
}
|
|
if (argv.projectRoot != null) {
|
|
output.projectRoot = argv.projectRoot;
|
|
}
|
|
if (argv.watchFolders != null) {
|
|
output.watchFolders = argv.watchFolders;
|
|
}
|
|
if (argv.assetExts != null) {
|
|
output.resolver.assetExts = argv.assetExts;
|
|
}
|
|
if (argv.sourceExts != null) {
|
|
output.resolver.sourceExts = argv.sourceExts;
|
|
}
|
|
if (argv.platforms != null) {
|
|
output.resolver.platforms = argv.platforms;
|
|
}
|
|
if (argv["max-workers"] != null || argv.maxWorkers != null) {
|
|
output.maxWorkers = Number(argv["max-workers"] || argv.maxWorkers);
|
|
}
|
|
if (argv.transformer != null) {
|
|
output.transformer.babelTransformerPath = argv.transformer;
|
|
}
|
|
if (argv["reset-cache"] != null) {
|
|
output.resetCache = argv["reset-cache"];
|
|
}
|
|
if (argv.resetCache != null) {
|
|
output.resetCache = argv.resetCache;
|
|
}
|
|
if (argv.verbose === false) {
|
|
output.reporter = {
|
|
update: () => {},
|
|
};
|
|
}
|
|
return mergeConfig(config, output);
|
|
}
|
|
async function loadConfig(argvInput = {}, defaultConfigOverrides = {}) {
|
|
const argv = {
|
|
...argvInput,
|
|
config: overrideArgument(argvInput.config),
|
|
};
|
|
const configuration = await loadMetroConfigFromDisk(
|
|
argv.config,
|
|
argv.cwd,
|
|
defaultConfigOverrides
|
|
);
|
|
validate(configuration, {
|
|
exampleConfig: await validConfig(),
|
|
recursiveDenylist: ["reporter", "resolver", "transformer"],
|
|
deprecatedConfig: {
|
|
blacklistRE:
|
|
() => `Warning: Metro config option \`blacklistRE\` is deprecated.
|
|
Please use \`blockList\` instead.`,
|
|
},
|
|
});
|
|
const configWithArgs = overrideConfigWithArguments(configuration, argv);
|
|
const overriddenConfig = {};
|
|
overriddenConfig.watchFolders = [
|
|
configWithArgs.projectRoot,
|
|
...configWithArgs.watchFolders,
|
|
];
|
|
return mergeConfig(configWithArgs, overriddenConfig);
|
|
}
|
|
module.exports = {
|
|
loadConfig,
|
|
resolveConfig,
|
|
mergeConfig,
|
|
};
|