Lösung ohne [Abhängigkeiten] (ursprünglich here beantwortet, aber nicht AngularJS spezifisch)
Ihre JSON sind komplex, ja, aber es könnte auch kleiner und besser lesbar sein, ohne all die Vervielfältigung, wobei jede Umgebung hat den gleichen Satz von Attributen, die variieren können oder nicht, und würde unnötigerweise dupliziert werden.
Mit einem simple algorithm (jsFiddle) können Sie Ihre JSON-Konfiguration für bestimmte Eigenschaft-Namensuffixe (Eigenschaft @ Suffix) und haben einen Katalog von umwelt unterschiedlichen Eigenschaften neben nicht-variierenden Eigenschaften dynamisch analysieren, ohne die Konfiguration künstlich Strukturierung und ohne Wiederholung, einschließlich tief verschachtelter Konfigurationsobjekte.
Sie können auch Suffixe mischen und zusammenführen und beliebig viele Umgebungsfaktoren oder andere beliebige Faktoren kombinieren, um Ihr Konfigurationsobjekt zu optimieren.
Beispiel, Schnipsel von vorverarbeiteten JSON config:
var config = {
'help': {
'BLURB': 'This pre-production environment is not supported. Contact Development Team with questions.',
'PHONE': '808-867-5309',
'EMAIL': '[email protected]'
},
'[email protected]': {
'BLURB': 'Please contact Customer Service Center',
'[email protected]': 'S\'il vous plaît communiquer avec notre Centre de service à la clientèle',
'[email protected]': 'Bitte kontaktieren Sie unseren Kundendienst!!1!',
'PHONE': '1-800-CUS-TOMR',
'EMAIL': '[email protected]'
},
}
... und nachbearbeitet (angesichts location.hostname = 'www.productionwebsite.com' und Navigator.Sprache 'de'):
prefer(config,['www.productionwebsite.com','de']); // prefer(obj,string|Array<string>)
JSON.stringify(config); // {
'help': {
'BLURB': 'Bitte kontaktieren Sie unseren Kundendienst!!1!',
'PHONE': '1-800-CUS-TOMR',
'EMAIL': '[email protected]'
}
}
Natürlich können Sie diese Werte bei Render-Zeit mit location.hostname und window.navigator.language ziehen. Der Algorithmus, um die JSON zu verarbeiten selbst ist nicht sehr komplex (aber immer noch bequemer aus irgendeinem Grund mit einem ganzen Rahmen fühlen kann, anstelle einer einzelnen Funktion):
function prefer(obj,suf) {
function pr(o,s) {
for (var p in o) {
if (!o.hasOwnProperty(p) || !p.split('@')[1] || p.split('@@')[1]) continue; // ignore: proto-prop OR not-suffixed OR temp prop score
var b = p.split('@')[0]; // base prop name
if(!!!o['@@'+b]) o['@@'+b] = 0; // +score placeholder
var ps = p.split('@')[1].split('&'); // array of property suffixes
var sc = 0; var v = 0; // reset (running)score and value
while(ps.length) {
// suffix value: index(of found suffix in prefs)^10
v = Math.floor(Math.pow(10,s.indexOf(ps.pop())));
if(!v) { sc = 0; break; } // found suf NOT in prefs, zero score (delete later)
sc += v;
}
if(sc > o['@@'+b]) { o['@@'+b] = sc; o[b] = o[p]; } // hi-score! promote to base prop
delete o[p];
}
for (var p in o) if(p.split('@@')[1]) delete o[p]; // remove scores
for (var p in o) if(typeof o[p] === 'object') pr(o[p],s); // recurse surviving objs
}
if(typeof obj !== 'object') return; // validate
suf = ((suf || suf === 0) && (suf.length || suf === parseFloat(suf)) ? suf.toString().split(',') : []); // array|string|number|comma-separated-string -> array-of-strings
pr(obj,suf.reverse());
}
Der Eigenschaftsname Suffix eine beliebige Anzahl haben können Suffixe nach dem '@', abgegrenzt durch '&' (kaufmännisches Und) und, wo es zwei Eigenschaften mit unterschiedlichen, aber bevorzugten Suffixen gibt, werden in der Reihenfolge bevorzugt, in der sie an die Funktion übergeben werden. Suffixe, die BEIDE bevorzugte Strings enthalten, werden vor allen anderen bevorzugt. In JSON gefundene Suffixe, die nicht als bevorzugt angegeben sind, werden verworfen.
Präferenz/Diskriminierung wird von oben nach unten auf Ihren Objektbaum angewendet, und wenn Objekte auf höherer Ebene überleben, werden sie anschließend auf bevorzugte Suffixe untersucht.
Mit diesem Ansatz Ihre JSON (Ich mache einige Annahmen über welche Attribute variieren zwischen Umgebungen und die nicht) kann wie folgt vereinfacht werden:
dbConfig = {
"pool": {
"min": "2",
"max": "10"
},
"init": "init",
"migrations": {
"directory": "migrations",
"tableName": "migrations"
},
"db":
"client": "sqlite",
"filename": "data/default/sqlitedb/development.db"
"[email protected]": "data/default/sqlitedb/test.db"
"[email protected]": "data/default/sqlitedb/production.db"
},
"[email protected]": {
"client": "oracle",
"user": "devuser",
"[email protected]": "testdbuser",
"[email protected]": "testdbuser",
"pass": "devpass",
"[email protected]": "testdbpass",
"[email protected]": "testdbpass",
"db": "devdb",
"[email protected]": "testdbschema",
"[email protected]": "testdbschema"
}
};
Damit Sie diese ernähren konnte in die es vorziehen() Funktion mit diesen args + Ergebnisse:
für sQLite, Test env:
prefer(dbConfig,'tst');
JSON.stringify(dbConfig); // dbConfig: {
"pool": {
"min": "2",
"max": "10"
},
"init": "init",
"migrations": {
"directory": "migrations",
"tableName": "migrations"
},
"db": {
"client": "sqlite",
"filename": "data/default/sqlitedb/test.db"
}
};
für Oracle, default/Entwicklungsumgebung:
prefer(dbConfig,'oracle'); // oracle, dev(default) env
JSON.stringify(dbConfig); // dbConfig: {
"pool": {
"min": "2",
"max": "10"
},
"init": "init",
"migrations": {
"directory": "migrations",
"tableName": "migrations"
},
"db": {
"client": "oracle",
"user": "devdbuser",
"pass": "devdbpass",
"db": "devdbschema"
}
};
prefer(dbConfig,'oracle,prd'); // oracle, production env
JSON.stringify(dbConfig); // dbConfig: {
"pool": {
"min": "2",
"max": "10"
},
"init": "init",
"migrations": {
"directory": "migrations",
"tableName": "migrations"
},
"db": {
"client": "oracle",
"user": "prddbuser",
"pass": "prddbpass",
"db": "prddbschema"
}
};
Abstrakt Nutzung und Beispiele:
var o = { 'a':'apple', '[email protected]':'apple-dev', '[email protected]':'pomme',
'b':'banana', '[email protected]':'banane', '[email protected]&fr':'banane-dev',
'c':{ 'o':'c-dot-oh', '[email protected]':'c-point-oh' }, '[email protected]': { 'o':'c-dot-oh-dev', '[email protected]':'c-point-oh-dev' } };
/*1*/ prefer(o,'dev'); // { a:'apple-dev', b:'banana', c:{o:'c-dot-oh-dev'} }
/*2*/ prefer(o,'fr'); // { a:'pomme', b:'banane', c:{o:'c-point-oh'} }
/*3*/ prefer(o,'dev,fr'); // { a:'apple-dev', b:'banane-dev', c:{o:'c-point-oh-dev'} }
/*4*/ prefer(o,['fr','dev']); // { a:'pomme', b:'banane-dev', c:{o:'c-point-oh-dev'} }
/*5*/ prefer(o); // { a:'apple', b:'banana', c:{o:'c-dot-oh'} }
Caveats Verwendung des @ in Eigenschaftsname ist nicht Standard und ist ungültig in Punktnotation, Aber bis jetzt hat es noch keine Browser durchbrochen, in denen wir dies getestet haben. Das UPSIDE-Verfahren verhindert, dass Entwickler erwarten, dass sie auf Ihre vorverarbeiteten Attribute mit Suffix verweisen können. Ein Entwickler müsste sich dessen bewusst sein und ein bisschen unkonventionell sein und auf sein Attribut als String (obj ['key @ suf']) verweisen, um das zu tun, was übrigens der Grund dafür ist, dass diese Funktion möglich ist.
Wenn zukünftige JavaScript-Engines dies ablehnen, ersetzen Sie andere tolerierbare Konventionen, seien Sie einfach konsistent. Dieser Algorithmus wurde nicht auf seine Leistung hin profiliert oder streng auf andere potenzielle Probleme getestet. In seiner aktuellen Form, einmalig beim Start/Laden verwendet, haben wir noch Probleme mit zu bekommen. Wie immer, YMMV.
Das ist brilliant. Vielen Dank – nixgadgets
Viele Konfigurationen sind so komplex, es sieht nur schlimmer aus wegen der unnötigen Duplizierung von Nicht-Umgebung-spezifischen Eigenschaften. Das heißt, es ist nicht schlimmer als die übliche Gewohnheit, ganze .properties Dateien pro Umgebung zu duplizieren und dann zu machen Sicher, dass alle Attribute synchron bleiben, wenn neue Funktionen in die endgültige Bereitstellungsumgebung vordringen. Siehe unten für einen Null-/Minimalduplizierungsmechanismus, der Objektattributnamen eine lesbare Notation hinzufügt, die rekursiv durch eine einzige Funktion entweder zur Ausführungs-/Renderzeit oder als Teil des Vorbereitungs-Workflows gefiltert werden kann. – storsoc