一尘不染

如何扩展EJSON以序列化用于流星客户端-服务器交互的RegEx?

json

我有一个任意的(E)JSON,可以在我的Meteor应用程序中通过客户端将其创建并通过电线发送到服务器。它使用RegExp对象将结果归零:

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

在客户端,一切都很好,但是如果我通过Meteor.call或将其传递给服务器Meteor.subscribe,则生成的(E)JSON采用以下形式:

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

…某处工程师在内部死亡。

Web上有大量资源说明为什么RegEx无法通过JSON.stringify/ JSON.parse或等效EJSON方法进行序列化。

我不认为RegEx序列化是不可能的。那怎么办呢?


阅读 206

收藏
2020-07-27

共1个答案

一尘不染

在查看了HowToMeteor
EJSON文档之后
,我们可以使用EJSON.addType方法序列化RegEx

扩展RegExp- 为RegExp提供EJSON.addType实现所需的方法。

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()
  }

呼叫EJSON.addType- 在任何地方进行。最好使它可用于客户端和服务器。这将反序列化toJSONValue上面定义的对象。

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

在控制台中测试 -不要相信我。你自己看。

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

这样一来,您就可以在客户端和服务器上对RegExp进行序列化和解析,可以通过有线传递,保存在Session中,甚至可以存储在查询集合中!

编辑以添加IE10 +错误:错误:在严格模式下不允许分配只读属性 由@Tim Fletcher提供

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));
2020-07-27