Files
smart-city-digital-twin-mar…/smart-app-city/frontend/node_modules/joi/lib/values.js
Eric FELIXINE e30ae8ed09 feat(smart-app): implement complete mobile app MVP
- 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
2026-06-01 18:00:35 -04:00

264 lines
5.7 KiB
JavaScript
Executable File

'use strict';
const Assert = require('@hapi/hoek/lib/assert');
const DeepEqual = require('@hapi/hoek/lib/deepEqual');
const Common = require('./common');
const internals = {};
module.exports = internals.Values = class {
constructor(values, refs) {
this._values = new Set(values);
this._refs = new Set(refs);
this._lowercase = internals.lowercases(values);
this._override = false;
}
get length() {
return this._values.size + this._refs.size;
}
add(value, refs) {
// Reference
if (Common.isResolvable(value)) {
if (!this._refs.has(value)) {
this._refs.add(value);
if (refs) { // Skipped in a merge
refs.register(value);
}
}
return;
}
// Value
if (!this.has(value, null, null, false)) {
this._values.add(value);
if (typeof value === 'string') {
this._lowercase.set(value.toLowerCase(), value);
}
}
}
static merge(target, source, remove) {
target = target || new internals.Values();
if (source) {
if (source._override) {
return source.clone();
}
for (const item of [...source._values, ...source._refs]) {
target.add(item);
}
}
if (remove) {
for (const item of [...remove._values, ...remove._refs]) {
target.remove(item);
}
}
return target.length ? target : null;
}
remove(value) {
// Reference
if (Common.isResolvable(value)) {
this._refs.delete(value);
return;
}
// Value
this._values.delete(value);
if (typeof value === 'string') {
this._lowercase.delete(value.toLowerCase());
}
}
has(value, state, prefs, insensitive) {
return !!this.get(value, state, prefs, insensitive);
}
get(value, state, prefs, insensitive) {
if (!this.length) {
return false;
}
// Simple match
if (this._values.has(value)) {
return { value };
}
// Case insensitive string match
if (typeof value === 'string' &&
value &&
insensitive) {
const found = this._lowercase.get(value.toLowerCase());
if (found) {
return { value: found };
}
}
if (!this._refs.size &&
typeof value !== 'object') {
return false;
}
// Objects
if (typeof value === 'object') {
for (const item of this._values) {
if (DeepEqual(item, value)) {
return { value: item };
}
}
}
// References
if (state) {
for (const ref of this._refs) {
const resolved = ref.resolve(value, state, prefs, null, { in: true });
if (resolved === undefined) {
continue;
}
const items = !ref.in || typeof resolved !== 'object'
? [resolved]
: Array.isArray(resolved) ? resolved : Object.keys(resolved);
for (const item of items) {
if (typeof item !== typeof value) {
continue;
}
if (insensitive &&
value &&
typeof value === 'string') {
if (item.toLowerCase() === value.toLowerCase()) {
return { value: item, ref };
}
}
else {
if (DeepEqual(item, value)) {
return { value: item, ref };
}
}
}
}
}
return false;
}
override() {
this._override = true;
}
values(options) {
if (options &&
options.display) {
const values = [];
for (const item of [...this._values, ...this._refs]) {
if (item !== undefined) {
values.push(item);
}
}
return values;
}
return Array.from([...this._values, ...this._refs]);
}
clone() {
const set = new internals.Values(this._values, this._refs);
set._override = this._override;
return set;
}
concat(source) {
Assert(!source._override, 'Cannot concat override set of values');
const set = new internals.Values([...this._values, ...source._values], [...this._refs, ...source._refs]);
set._override = this._override;
return set;
}
describe() {
const normalized = [];
if (this._override) {
normalized.push({ override: true });
}
for (const value of this._values.values()) {
normalized.push(value && typeof value === 'object' ? { value } : value);
}
for (const value of this._refs.values()) {
normalized.push(value.describe());
}
return normalized;
}
};
internals.Values.prototype[Common.symbols.values] = true;
// Aliases
internals.Values.prototype.slice = internals.Values.prototype.clone;
// Helpers
internals.lowercases = function (from) {
const map = new Map();
if (from) {
for (const value of from) {
if (typeof value === 'string') {
map.set(value.toLowerCase(), value);
}
}
}
return map;
};