Comment étendre EJSON pour sérialiser RegEx pour les interactions Meteor Client-Server?

J'ai un JSON arbitraire (E) créé et envoyé sur le fil du client au serveur dans mon application Meteor. Il utilise RegExp objets RegExp pour mettre en zéro les résultats:

 # on the client selector = "roles.user": { "$ne": null } "profile.email": /^admin@/gi 

Tout est dandy bien du côté du client, mais si je le passe sur le serveur via Meteor.call ou Meteor.subscribe , le JSON résultant (E) prend cette forme:

 # on the server selector = "roles.user": { "$ne": null } "profile.email": {} 

… et quelque part un ingénieur meurt un peu à l'intérieur.

Il existe de nombreuses ressources sur le Web expliquant pourquoi RegEx est non JSON.stringify via JSON.stringify / JSON.parse ou les méthodes EJSON équivalentes.

Je ne suis pas convaincu. La sérialisation RegEx est impossible. Alors, comment peut-on faire?

Après avoir examiné ce HowTo et les Meteor EJSON Docs , nous pouvons sérialiser RegEx à l'aide de la méthode EJSON.addType .

Prolongez RegExp – Fournissez RegExp avec les méthodes EJSON.addType pour la mise en œuvre.

 RegExp::options = -> opts = [] opts.push 'g' if @global opts.push 'i' if @ignoreCase opts.push 'm' if @multiline return opts.join('') RegExp::clone = -> self = @ return new RegExp(self.source, self.options()) RegExp::equals = (other) -> self = @ if other isnt instanceOf RegExp return false return EJSON.stringify(self) is EJSON.stringify(other) RegExp::typeName = -> return "RegExp" RegExp::toJSONValue = -> self = @ return { 'regex': self.source 'options': self.options() } 

Appelez EJSON.addType – Faites-le n'importe où. Il est préférable de le rendre disponible pour le client et le serveur. Cela va désérialiser l'objet défini dans toJSONValue ci-dessus.

 EJSON.addType "RegExp", (value) -> return new RegExp(value['regex'], value['options']) 

Test dans votre console – Ne prenez pas ma parole pour cela. Voir par vous-même.

 > o = EJSON.stringify(/^Mooo/ig) "{"$type":"RegExp","$value":{"regex":"^Mooo","options":"ig"}}" > EJSON.parse(o) /^Mooo/gi 

Et là, vous avez un RegExp sérialisé et analysé sur le client et le serveur, capable de passer sur le fil, enregistré dans une session, et même éventuellement stocké dans une collection de requêtes!

EDITER à ajouter IE10 + Erreur: L'affectation aux propriétés en lecture seule n'est pas autorisée en mode strict. Avec l'aimable autorisation de @Tim Fletcher dans les commentaires

 import { EJSON } from 'meteor/ejson'; function getOptions(self) { const opts = []; if (self.global) opts.push('g'); if (self.ignoreCase) opts.push('i'); if (self.multiline) opts.push('m'); return opts.join(''); } RegExp.prototype.clone = function clone() { return new RegExp(this.source, getOptions(this)); }; RegExp.prototype.equals = function equals(other) { if (!(other instanceof RegExp)) return false; return EJSON.stringify(this) === EJSON.stringify(other); }; RegExp.prototype.typeName = function typeName() { return 'RegExp'; }; RegExp.prototype.toJSONValue = function toJSONValue() { return { regex: this.source, options: getOptions(this) }; }; EJSON.addType('RegExp', value => new RegExp(value.regex, value.options)); 

Il existe une solution beaucoup plus simple: stringify votre RegExp via .toString() , l'envoyer au serveur et ensuite l'analyser dans RegExp.