Add local fork of meteor-reactive-cache package

- Clone @wekanteam/meteor-reactive-cache to npm-packages/
- Add .meteorignore to exclude npm-packages from Meteor
- Update package.json to use local file path

This allows direct modification of the package for Meteor 3.0
async migration while maintaining publishability to npm.
This commit is contained in:
Harry Adel 2026-01-31 20:46:05 +02:00
parent 88b35a6415
commit e241e27ca1
40 changed files with 10369 additions and 4 deletions

1
.meteorignore Normal file
View file

@ -0,0 +1 @@
npm-packages/

View file

@ -0,0 +1,8 @@
*.swp
*~
*.iml
.*.haste_cache.*
.DS_Store
.idea
npm-debug.log
node_modules

View file

@ -0,0 +1,22 @@
sudo: false
language: node_js
node_js:
- "4.8.4"
addons:
apt:
packages:
- xvfb
install:
- export DISPLAY=':99.0'
- Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
- npm install
before_install:
- curl https://install.meteor.com/?release=1.6.1.1 | /bin/sh
- export PATH="$HOME/.meteor:$PATH"
script:
- (cd tests && meteor npm install)
- npm run lint
- npm test

View file

@ -0,0 +1,50 @@
# ChangeLog
# v1.0.7 2026-01-05 meteor-reactive-cache release
This release adds the following updates:
- Updated dependencies.
[Part 1](https://github.com/wekan/meteor-reactive-cache/commit/eed764fb54428224a970e96e5ea12a64470ea1d2),
[Part 2](https://github.com/wekan/meteor-reactive-cache/commit/32a496271ed45c2b3a8a26d6bde878e14b113637).
Thanks to xet7.
Thanks to above GitHub users for their contributions and translators for their translations.
# v1.0.6 2023-07-19 meteor-reactive-cache release
This release adds the following updates:
- [Updated dependencies](https://github.com/wekan/meteor-reactive-cache/commit/63c2ecc549e5c985be70af70a11ae4ac614e3455).
Thanks to xet7.
Thanks to above GitHub users for their contributions and translators for their translations.
# v1.0.5 2023-07-19 meteor-reactive-cache release
This release fixes the following bugs:
- [Fixed using newer fixed @wekanteam/meteor-globals package](https://github.com/wekan/meteor-reactive-cache/commit/1fe7a07c8607419c86bceabce5ca024432435fc2).
Thanks to xet7.
- [Renamed publish to release. Added release script](https://github.com/wekan/meteor-reactive-cache/commit/e43c232453c0d7267576c82c6f6463ede34a2c55).
Thanks to xet7.
Thanks to above GitHub users for their contributions and translators for their translations.
# v1.0.4 2023-07-19 meteor-reactive-cache release
This release fixes the following bugs:
- [Added PUBLISH.md about missing steps to publish npm package. Added missing published files also to git repo](https://github.com/wekan/meteor-reactive-cache/commit/b355ca815ebf9389d3a0dd57cddee7938aa4bf0c).
Thanks to xet7.
Thanks to above GitHub users for their contributions and translators for their translations.
# v1.0.3 2023-07-19 meteor-reactive-cache release
This release adds the following updates:
- [Updated dependencies in this package and @wekanteam/meteor-globals](https://github.com/wekan/meteor-reactive-cache/commit/659a4e51c11bd95ec2fc5dccfb0bf1003ca7737d).
Thanks to xet7.
Thanks to above GitHub users for their contributions and translators for their translations.

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Max Nowack
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,72 @@
# meteor-reactive-cache [![Build Status](https://travis-ci.org/maxnowack/meteor-reactive-cache.svg?branch=master)](https://travis-ci.org/maxnowack/meteor-reactive-cache)
Utilities for caching reactive data
### Installation
````bash
 $ npm install --save meteor-reactive-cache
````
### Usage
#### `ReactiveCache(compare: function)`
A simple reactive cache. It haves the same API like a `ReactiveDict`, but the values are getting deleted if all wrapped computations are stopped.
````es6
import { Tracker } from 'meteor/tracker'
import { ReactiveCache } from 'meteor-reactive-cache'
const reactiveCache = new ReactiveCache(/* compareFn */);
reactiveCache.set('foo', 'bar');
const computation = Tracker.autorun(() => {
reactiveCache.get('foo'); // reactive!
})
reactiveCache.set('foo', 'new bar');
computation.stop(); // keys will be invalidated if they don't have reactive dependants
reactiveCache.get('foo'); // undefined
````
#### `DataCache(resolve: function, { timeout: number, compare: function })`
Provides a simple reactive data cache, by passing in a function, that resolves a key to data in a reactive context.
````es6
import { Tracker } from 'meteor/tracker'
import { DataCache } from 'meteor-reactive-cache'
const dataCache = new DataCache((key) => {
// do some expensive reactive work here, which returns the same data for the same key.
// this function will only be executed if a reactive dependency changes or the requested key isn't cached.
})
const computation = Tracker.autorun(() => {
reactiveCache.get('foo'); // reactive!
})
computation.stop(); // keys will be invalidated if they don't have reactive dependants
reactiveCache.get('foo'); // undefined
````
#### `reactiveField(resolve: function, { timeout: number, compare: function })`
Like DataCache, but with a much simpler API and support for multiple function parameters.
````es6
import { Tracker } from 'meteor/tracker'
import { reactiveField } from 'meteor-reactive-cache'
const field = reactiveField((val1, val2, val3) => {
// …
})
const computation = Tracker.autorun(() => {
field('foo', 'bar', 1234); // reactive!
})
````
## License
Licensed under MIT license. Copyright (c) 2017 Max Nowack
## Contributions
Contributions are welcome. Please open issues and/or file Pull Requests.
## Maintainers
- Max Nowack ([maxnowack](https://github.com/maxnowack))

View file

@ -0,0 +1,14 @@
# Steps to release
## 1. Update these for new version info
- package.json: updated dependencies and new version info
- package-lock.json: updated dependencies and 2x new version info
- CHANGELOG.md: Newest changes and new version info
- Optionally: source code at src/ directory
## 2. Release new version number
```
./release.sh 1.0.5
```

View file

@ -0,0 +1,92 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _bindEnvironment = _interopRequireDefault(require("./meteor/bindEnvironment"));
var _tracker = _interopRequireDefault(require("./meteor/tracker"));
var _ReactiveCache = _interopRequireDefault(require("./ReactiveCache"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
var DataCache = exports["default"] = /*#__PURE__*/function () {
function DataCache(getData, options) {
_classCallCheck(this, DataCache);
this.options = _objectSpread({
timeout: 60 * 1000
}, typeof options === 'function' ? {
compare: options
} : options);
this.getData = getData;
this.cache = new _ReactiveCache["default"](this.options.compare, function () {
return false;
});
this.timeouts = {};
this.computations = {};
}
return _createClass(DataCache, [{
key: "ensureComputation",
value: function ensureComputation(key) {
var _this = this;
if (this.timeouts[key]) {
clearTimeout(this.timeouts[key]);
delete this.timeouts[key];
}
if (this.computations[key] && !this.computations[key].stopped) return;
this.computations[key] = _tracker["default"].nonreactive(function () {
return _tracker["default"].autorun(function () {
_this.cache.set(key, _this.getData(key));
});
});
// stop the computation if the key doesn't have any dependants
this.computations[key].onInvalidate(function () {
return _this.checkStop(key);
});
}
}, {
key: "checkStop",
value: function checkStop(key) {
var _this2 = this;
if (this.cache.ensureDependency(key).hasDependents()) return;
if (this.timeouts[key]) {
clearTimeout(this.timeouts[key]);
delete this.timeouts[key];
}
this.timeouts[key] = setTimeout((0, _bindEnvironment["default"])(function () {
if (!_this2.computations[key]) return;
_this2.computations[key].stop();
delete _this2.computations[key];
_this2.cache.del(key);
}), this.options.timeout);
}
}, {
key: "get",
value: function get(key) {
var _this3 = this;
if (!_tracker["default"].currentComputation) {
var _data = this.cache.get(key);
if (_data == null) {
_data = this.getData(key);
this.cache.set(key, _data);
this.checkStop(key);
}
return _data;
}
this.ensureComputation(key);
var data = this.cache.get(key);
_tracker["default"].currentComputation.onStop(function () {
return _this3.checkStop(key);
});
return data;
}
}]);
}();

View file

@ -0,0 +1,84 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _tracker = _interopRequireDefault(require("./meteor/tracker"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
var ReactiveCache = exports["default"] = /*#__PURE__*/function () {
function ReactiveCache(compare, shouldStop) {
_classCallCheck(this, ReactiveCache);
this.shouldStop = shouldStop || function () {
return true;
};
this.compare = compare || function (a, b) {
return a === b;
};
this.values = {};
this.deps = {};
}
return _createClass(ReactiveCache, [{
key: "ensureDependency",
value: function ensureDependency(key) {
if (!this.deps[key]) this.deps[key] = new _tracker["default"].Dependency();
return this.deps[key];
}
}, {
key: "checkDeletion",
value: function checkDeletion(key) {
var dep = this.ensureDependency(key);
if (dep.hasDependents()) return false;
delete this.values[key];
delete this.deps[key];
return true;
}
}, {
key: "clear",
value: function clear() {
var _this = this;
Object.keys(this.values).forEach(function (key) {
return _this.del(key);
});
}
}, {
key: "del",
value: function del(key) {
var dep = this.ensureDependency(key);
delete this.values[key];
if (this.checkDeletion(key)) return;
dep.changed();
}
}, {
key: "set",
value: function set(key, data, bypassCompare) {
var dep = this.ensureDependency(key);
var current = this.values[key];
this.values[key] = data;
if (!this.compare(current, data) || bypassCompare) {
dep.changed();
}
}
}, {
key: "get",
value: function get(key) {
var _this2 = this;
var data = this.values[key];
if (_tracker["default"].currentComputation) {
var dep = this.ensureDependency(key);
dep.depend();
_tracker["default"].currentComputation.onStop(function () {
if (!_this2.shouldStop(key)) return;
_this2.checkDeletion(key);
});
}
return data;
}
}]);
}();

View file

@ -0,0 +1,27 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "DataCache", {
enumerable: true,
get: function get() {
return _DataCache["default"];
}
});
Object.defineProperty(exports, "ReactiveCache", {
enumerable: true,
get: function get() {
return _ReactiveCache["default"];
}
});
Object.defineProperty(exports, "reactiveField", {
enumerable: true,
get: function get() {
return _reactiveField["default"];
}
});
var _DataCache = _interopRequireDefault(require("./DataCache"));
var _ReactiveCache = _interopRequireDefault(require("./ReactiveCache"));
var _reactiveField = _interopRequireDefault(require("./reactiveField"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }

View file

@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _meteorGlobals = require("@wekanteam/meteor-globals");
var Meteor = (0, _meteorGlobals.getGlobal)('meteor', 'Meteor');
var _default = exports["default"] = Meteor.bindEnvironment.bind(Meteor);

View file

@ -0,0 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _meteorGlobals = require("@wekanteam/meteor-globals");
var _default = exports["default"] = (0, _meteorGlobals.getGlobal)('ejson', 'EJSON');

View file

@ -0,0 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _meteorGlobals = require("@wekanteam/meteor-globals");
var _default = exports["default"] = (0, _meteorGlobals.getGlobal)('tracker', 'Tracker');

View file

@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _DataCache = _interopRequireDefault(require("./DataCache"));
var _ejson = _interopRequireDefault(require("./meteor/ejson"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
var _default = exports["default"] = function _default(fn, compare) {
var cache = new _DataCache["default"](function (key) {
return fn.apply(void 0, _toConsumableArray(_ejson["default"].parse(key)));
}, compare);
var resolver = function resolver() {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return cache.get(_ejson["default"].stringify(args));
};
resolver.cache = cache;
return resolver;
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,63 @@
{
"name": "@wekanteam/meteor-reactive-cache",
"version": "1.0.7",
"description": "Utilities for caching reactive data",
"main": "dist/index.js",
"scripts": {
"prepublish": "./node_modules/.bin/babel src -d dist",
"lint": "./node_modules/.bin/eslint src",
"copy": "npm link && cd tests && npm link meteor-reactive-cache",
"test": "npm run copy && cd tests && TEST_BROWSER_DRIVER=nightmare meteor test -p 3100 --once --driver-package meteortesting:mocha"
},
"repository": {
"type": "git",
"url": "git+https://github.com/maxnowack/meteor-reactive-cache.git"
},
"author": "Max Nowack <max@unsou.de>",
"license": "MIT",
"bugs": {
"url": "https://github.com/maxnowack/meteor-reactive-cache/issues"
},
"homepage": "https://github.com/maxnowack/meteor-reactive-cache#readme",
"files": [
"dist"
],
"keywords": [
"caching",
"meteor",
"react",
"reactivity",
"tracker"
],
"babel": {
"presets": [
"@babel/preset-env"
]
},
"eslintConfig": {
"extends": [
"airbnb-base"
],
"parser": "@babel/eslint-parser",
"rules": {
"no-param-reassign": [
2,
{
"props": false
}
]
}
},
"devDependencies": {
"@babel/cli": "^7.23.9",
"@babel/core": "^7.23.9",
"@babel/eslint-parser": "^7.23.9",
"@babel/preset-env": "^7.23.9",
"eslint": "^8.56.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-import": "^2.29.1"
},
"dependencies": {
"@wekanteam/meteor-globals": "^1.1.6"
}
}

View file

@ -0,0 +1,25 @@
#!/bin/bash
## 1. Copy files
npm run prepublish
npm run copy
## 2. Commit
git add --all
git commit -m "$1"
## 3. Add tags
git tag -a $1 -m "$1"
git push origin $1
git push
## 4. Publish npm package
npm publish --access public

View file

@ -0,0 +1,61 @@
import bindEnvironment from './meteor/bindEnvironment';
import Tracker from './meteor/tracker';
import ReactiveCache from './ReactiveCache';
export default class DataCache {
constructor(getData, options) {
this.options = {
timeout: 60 * 1000, // 60 seconds
...(typeof options === 'function' ? { compare: options } : options),
};
this.getData = getData;
this.cache = new ReactiveCache(this.options.compare, () => false);
this.timeouts = {};
this.computations = {};
}
ensureComputation(key) {
if (this.timeouts[key]) {
clearTimeout(this.timeouts[key]);
delete this.timeouts[key];
}
if (this.computations[key] && !this.computations[key].stopped) return;
this.computations[key] = Tracker.nonreactive(() => Tracker.autorun(() => {
this.cache.set(key, this.getData(key));
}));
// stop the computation if the key doesn't have any dependants
this.computations[key].onInvalidate(() => this.checkStop(key));
}
checkStop(key) {
if (this.cache.ensureDependency(key).hasDependents()) return;
if (this.timeouts[key]) {
clearTimeout(this.timeouts[key]);
delete this.timeouts[key];
}
this.timeouts[key] = setTimeout(bindEnvironment(() => {
if (!this.computations[key]) return;
this.computations[key].stop();
delete this.computations[key];
this.cache.del(key);
}), this.options.timeout);
}
get(key) {
if (!Tracker.currentComputation) {
let data = this.cache.get(key);
if (data == null) {
data = this.getData(key);
this.cache.set(key, data);
this.checkStop(key);
}
return data;
}
this.ensureComputation(key);
const data = this.cache.get(key);
Tracker.currentComputation.onStop(() => this.checkStop(key));
return data;
}
}

View file

@ -0,0 +1,56 @@
import Tracker from './meteor/tracker';
export default class ReactiveCache {
constructor(compare, shouldStop) {
this.shouldStop = shouldStop || (() => true);
this.compare = compare || ((a, b) => a === b);
this.values = {};
this.deps = {};
}
ensureDependency(key) {
if (!this.deps[key]) this.deps[key] = new Tracker.Dependency();
return this.deps[key];
}
checkDeletion(key) {
const dep = this.ensureDependency(key);
if (dep.hasDependents()) return false;
delete this.values[key];
delete this.deps[key];
return true;
}
clear() {
Object.keys(this.values).forEach((key) => this.del(key));
}
del(key) {
const dep = this.ensureDependency(key);
delete this.values[key];
if (this.checkDeletion(key)) return;
dep.changed();
}
set(key, data, bypassCompare) {
const dep = this.ensureDependency(key);
const current = this.values[key];
this.values[key] = data;
if (!this.compare(current, data) || bypassCompare) {
dep.changed();
}
}
get(key) {
const data = this.values[key];
if (Tracker.currentComputation) {
const dep = this.ensureDependency(key);
dep.depend();
Tracker.currentComputation.onStop(() => {
if (!this.shouldStop(key)) return;
this.checkDeletion(key);
});
}
return data;
}
}

View file

@ -0,0 +1,3 @@
export { default as DataCache } from './DataCache';
export { default as ReactiveCache } from './ReactiveCache';
export { default as reactiveField } from './reactiveField';

View file

@ -0,0 +1,4 @@
import { getGlobal } from '@wekanteam/meteor-globals';
const Meteor = getGlobal('meteor', 'Meteor');
export default Meteor.bindEnvironment.bind(Meteor);

View file

@ -0,0 +1,3 @@
import { getGlobal } from '@wekanteam/meteor-globals';
export default getGlobal('ejson', 'EJSON');

View file

@ -0,0 +1,3 @@
import { getGlobal } from '@wekanteam/meteor-globals';
export default getGlobal('tracker', 'Tracker');

View file

@ -0,0 +1,9 @@
import DataCache from './DataCache';
import ejson from './meteor/ejson';
export default (fn, compare) => {
const cache = new DataCache((key) => fn(...ejson.parse(key)), compare);
const resolver = (...args) => cache.get(ejson.stringify(args));
resolver.cache = cache;
return resolver;
};

View file

View file

@ -0,0 +1,18 @@
# This file contains information which helps Meteor properly upgrade your
# app when you run 'meteor update'. You should check it into version control
# with your project.
notices-for-0.9.0
notices-for-0.9.1
0.9.4-platform-file
notices-for-facebook-graph-api-2
1.2.0-standard-minifiers-package
1.2.0-meteor-platform-split
1.2.0-cordova-changes
1.2.0-breaking-changes
1.3.0-split-minifiers-package
1.4.0-remove-old-dev-bundle-link
1.4.1-add-shell-server-package
1.4.3-split-account-service-packages
1.5-add-dynamic-import-package
1.7-split-underscore-from-meteor-base

View file

@ -0,0 +1 @@
local

View file

@ -0,0 +1,7 @@
# This file contains a token that is unique to your project.
# Check it into your repository along with the rest of this directory.
# It can be used for purposes such as:
# - ensuring you don't accidentally deploy one app on top of another
# - providing package authors with aggregated statistics
1efzo9epsn1ob1vv1hyv

View file

@ -0,0 +1,18 @@
# Meteor packages used by this project, one per line.
# Check this file (and the other files in this directory) into your repository.
#
# 'meteor add' and 'meteor remove' will edit this file for you,
# but you can also edit it by hand.
meteor-base@1.4.0 # Packages every Meteor app needs to have
reactive-var@1.0.11 # Reactive variable for tracker
tracker@1.2.0 # Meteor's client-side reactive programming library
standard-minifier-css@1.5.2 # CSS minifier run for production mode
standard-minifier-js@2.4.0 # JS minifier run for production mode
es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers.
ecmascript@0.12.3 # Enable ECMAScript2015+ syntax in app code
shell-server@0.4.0 # Server-side component of the `meteor shell` command
reactive-dict@1.2.1
dynamic-import@0.5.0
meteortesting:mocha

View file

@ -0,0 +1,2 @@
server
browser

View file

@ -0,0 +1 @@
METEOR@1.8.0.1

View file

@ -0,0 +1,63 @@
allow-deny@1.1.0
autoupdate@1.5.0
babel-compiler@7.2.3
babel-runtime@1.3.0
base64@1.0.11
binary-heap@1.0.11
boilerplate-generator@1.6.0
callback-hook@1.1.0
check@1.3.1
ddp@1.4.0
ddp-client@2.3.3
ddp-common@1.4.0
ddp-server@2.2.0
diff-sequence@1.1.1
dynamic-import@0.5.1
ecmascript@0.12.3
ecmascript-runtime@0.7.0
ecmascript-runtime-client@0.8.0
ecmascript-runtime-server@0.7.1
ejson@1.1.0
es5-shim@4.8.0
fetch@0.1.0
geojson-utils@1.0.10
hot-code-push@1.0.4
http@1.4.2
id-map@1.1.0
inter-process-messaging@0.1.0
livedata@1.0.18
lmieulet:meteor-coverage@2.0.2
logging@1.1.20
meteor@1.9.2
meteor-base@1.4.0
meteortesting:browser-tests@1.2.0
meteortesting:mocha@1.1.0
meteortesting:mocha-core@5.2.0_3
minifier-css@1.4.1
minifier-js@2.4.0
minimongo@1.4.5
modern-browsers@0.1.3
modules@0.13.0
modules-runtime@0.10.3
mongo@1.6.0
mongo-decimal@0.1.0
mongo-dev-server@1.1.0
mongo-id@1.0.7
npm-mongo@3.1.1
ordered-dict@1.1.0
promise@0.11.1
random@1.1.0
reactive-dict@1.2.1
reactive-var@1.0.11
reload@1.2.0
retry@1.1.0
routepolicy@1.1.0
shell-server@0.4.0
socket-stream-client@0.2.2
standard-minifier-css@1.5.2
standard-minifier-js@2.4.0
tracker@1.2.0
underscore@1.0.10
url@1.2.0
webapp@1.7.2
webapp-hashing@1.0.9

View file

@ -0,0 +1,54 @@
/* global describe it */
import chai from 'chai';
import { DataCache } from 'meteor-reactive-cache';
import { Meteor } from 'meteor/meteor';
import { Tracker } from 'meteor/tracker';
import { ReactiveDict } from 'meteor/reactive-dict';
describe('DataCache', () => {
it('should be reactive', (done) => {
const reactiveDict = new ReactiveDict();
reactiveDict.set('foo', '000');
let numGets = 0;
const reactiveCache = new DataCache((key) => {
numGets += 1;
return reactiveDict.get(key);
}, {
timeout: 10,
});
let runs = 0;
const computation = Tracker.autorun(() => {
runs += 1;
const value = reactiveCache.get('foo'); // eslint-disable-line
});
chai.assert.equal(reactiveCache.get('foo'), '000');
chai.assert.equal(numGets, 1);
chai.assert.equal(runs, 1);
reactiveDict.set('foo', 'bar');
Tracker.flush({ _throwFirstError: true });
chai.assert.equal(reactiveCache.get('foo'), 'bar');
chai.assert.equal(numGets, 2);
chai.assert.equal(runs, 2);
reactiveDict.set('foo', 'bar');
Tracker.flush({ _throwFirstError: true });
chai.assert.equal(reactiveCache.get('foo'), 'bar');
chai.assert.equal(numGets, 2);
chai.assert.equal(runs, 2);
computation.stop();
chai.assert.equal(reactiveCache.get('foo'), 'bar');
chai.assert.equal(numGets, 2);
Meteor.setTimeout(() => {
chai.assert.equal(reactiveCache.get('foo'), 'bar');
chai.assert.equal(numGets, 3);
done();
}, 50);
});
});

View file

@ -0,0 +1,89 @@
/* global describe it */
import chai from 'chai';
import { ReactiveCache } from 'meteor-reactive-cache';
import { Tracker } from 'meteor/tracker';
import isEqual from 'lodash.isequal';
describe('ReactiveCache', () => {
it('should be reactive', () => {
const reactiveCache = new ReactiveCache();
let runs = 0;
Tracker.autorun(() => {
runs += 1;
const value = reactiveCache.get('foo'); // eslint-disable-line
});
chai.assert.equal(typeof reactiveCache.get('foo'), 'undefined');
chai.assert.equal(runs, 1);
reactiveCache.set('foo', 'bar');
Tracker.flush({ _throwFirstError: true });
chai.assert.equal(reactiveCache.get('foo'), 'bar');
chai.assert.equal(runs, 2);
reactiveCache.set('foo', 'bar');
Tracker.flush({ _throwFirstError: true });
chai.assert.equal(reactiveCache.get('foo'), 'bar');
chai.assert.equal(runs, 2);
reactiveCache.del('foo');
Tracker.flush({ _throwFirstError: true });
chai.assert.equal(typeof reactiveCache.get('foo'), 'undefined');
chai.assert.equal(runs, 3);
});
it('should be reactive with custom compare', () => {
const reactiveCache = new ReactiveCache();
const reactiveObjCache = new ReactiveCache((a, b) => isEqual(a, b));
reactiveCache.set('foo', { test: true });
reactiveObjCache.set('foo', { test: true });
let runs = 0;
Tracker.autorun(() => {
runs += 1;
const value = reactiveCache.get('foo'); // eslint-disable-line
});
let runsObj = 0;
Tracker.autorun(() => {
runsObj += 1;
const value = reactiveObjCache.get('foo'); // eslint-disable-line
});
chai.assert.equal(runs, 1);
chai.assert.equal(runsObj, 1);
reactiveCache.set('foo', { test: true });
reactiveObjCache.set('foo', { test: true });
Tracker.flush({ _throwFirstError: true });
chai.assert.equal(runs, 2);
chai.assert.equal(runsObj, 1);
});
it('gets invalidated if computation stops', (done) => {
const reactiveCache = new ReactiveCache();
let runs = 0;
const computation = Tracker.autorun(() => {
runs += 1;
const value = reactiveCache.get('foo'); // eslint-disable-line
});
chai.assert.equal(typeof reactiveCache.get('foo'), 'undefined');
chai.assert.equal(runs, 1);
reactiveCache.set('foo', 'bar');
Tracker.flush({ _throwFirstError: true });
chai.assert.equal(reactiveCache.get('foo'), 'bar');
chai.assert.equal(runs, 2);
computation.stop();
chai.assert.equal(typeof reactiveCache.get('foo'), 'undefined');
setTimeout(() => {
done();
}, 200);
});
});

View file

@ -0,0 +1,154 @@
/* global describe it */
import chai from 'chai';
import { reactiveField } from 'meteor-reactive-cache';
import { Meteor } from 'meteor/meteor';
import { Tracker } from 'meteor/tracker';
import { ReactiveVar } from 'meteor/reactive-var';
import { ReactiveDict } from 'meteor/reactive-dict';
describe('reactiveField', () => {
it('should be reactive', (done) => {
const reactiveDict = new ReactiveDict();
reactiveDict.set('foo', '000');
let numGets = 0;
const field = reactiveField((key) => {
numGets += 1;
return reactiveDict.get(key);
}, {
timeout: 10,
});
let runs = 0;
const computation = Tracker.autorun(() => {
runs += 1;
const value = field('foo'); // eslint-disable-line
});
chai.assert.equal(field('foo'), '000');
chai.assert.equal(numGets, 1);
chai.assert.equal(runs, 1);
reactiveDict.set('foo', 'bar');
Tracker.flush({ _throwFirstError: true });
chai.assert.equal(field('foo'), 'bar');
chai.assert.equal(numGets, 2);
chai.assert.equal(runs, 2);
reactiveDict.set('foo', 'bar');
Tracker.flush({ _throwFirstError: true });
chai.assert.equal(field('foo'), 'bar');
chai.assert.equal(numGets, 2);
chai.assert.equal(runs, 2);
computation.stop();
chai.assert.equal(field('foo'), 'bar');
chai.assert.equal(numGets, 2);
Meteor.setTimeout(() => {
chai.assert.equal(field('foo'), 'bar');
chai.assert.equal(numGets, 3);
done();
}, 50);
});
it('should be reactive with complex values', () => {
const reactiveDict = new ReactiveDict();
reactiveDict.set('foo', { date: new Date('2018-01-01') });
let numGets = 0;
const field = reactiveField((key) => {
numGets += 1;
return reactiveDict.get(key);
}, {
timeout: 10,
});
let runs = 0;
const computation = Tracker.autorun(() => {
runs += 1;
const value = field('foo'); // eslint-disable-line
});
chai.assert.instanceOf(field('foo').date, Date);
chai.assert.equal(numGets, 1);
chai.assert.equal(runs, 1);
reactiveDict.set('foo', { date: new Date('2018-01-02') });
Tracker.flush({ _throwFirstError: true });
chai.assert.instanceOf(field('foo').date, Date);
chai.assert.equal(numGets, 2);
chai.assert.equal(runs, 2);
computation.stop();
});
it('should work with multiple parameters', () => {
const reactiveDict = new ReactiveDict();
reactiveDict.set('foofoo', '000');
reactiveDict.set('foobar', '000');
reactiveDict.set('barbar', '000');
let numGets = 0;
const field = reactiveField((val1, val2) => {
numGets += 1;
return reactiveDict.get(`${val1}${val2}`);
}, {
timeout: 100,
});
const runs = {
foofoo: 0,
foobar: 0,
barbar: 0,
};
Tracker.autorun(() => {
runs.foofoo += 1;
const value = field('foo', 'foo'); // eslint-disable-line
});
Tracker.autorun(() => {
runs.foobar += 1;
const value = field('foo', 'bar'); // eslint-disable-line
});
Tracker.autorun(() => {
runs.barbar += 1;
const value = field('bar', 'bar'); // eslint-disable-line
});
chai.assert.equal(field('foo', 'foo'), '000');
chai.assert.equal(numGets, 3);
chai.assert.equal(runs.foofoo, 1);
chai.assert.equal(field('foo', 'bar'), '000');
chai.assert.equal(numGets, 3);
chai.assert.equal(runs.foobar, 1);
chai.assert.equal(field('bar', 'bar'), '000');
chai.assert.equal(numGets, 3);
chai.assert.equal(runs.barbar, 1);
reactiveDict.set('foofoo', 'bar');
Tracker.flush({ _throwFirstError: true });
chai.assert.equal(field('foo', 'foo'), 'bar');
chai.assert.equal(numGets, 4);
chai.assert.equal(runs.foofoo, 2);
chai.assert.equal(runs.foobar, 1);
chai.assert.equal(runs.barbar, 1);
reactiveDict.set('foobar', 'bar');
Tracker.flush({ _throwFirstError: true });
chai.assert.equal(field('foo', 'bar'), 'bar');
chai.assert.equal(numGets, 5);
chai.assert.equal(runs.foofoo, 2);
chai.assert.equal(runs.foobar, 2);
chai.assert.equal(runs.barbar, 1);
reactiveDict.set('barbar', 'bar');
Tracker.flush({ _throwFirstError: true });
chai.assert.equal(field('bar', 'bar'), 'bar');
chai.assert.equal(numGets, 6);
chai.assert.equal(runs.foofoo, 2);
chai.assert.equal(runs.foobar, 2);
chai.assert.equal(runs.barbar, 2);
});
});

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,39 @@
{
"name": "tests",
"private": true,
"scripts": {
"start": "meteor run"
},
"eslintConfig": {
"extends": [
"airbnb-base",
"plugin:meteor/recommended"
],
"plugins": [
"meteor"
],
"parser": "babel-eslint",
"rules": {
"meteor/audit-argument-checks": 0,
"import/no-extraneous-dependencies": 0,
"import/extensions": 0,
"import/no-unresolved": 0,
"no-underscore-dangle": 0
}
},
"dependencies": {
"@babel/runtime": "^7.1.5",
"meteor-node-stubs": "0.4.1",
"meteor-reactive-cache": "^1.0.1"
},
"devDependencies": {
"chai": "^4.2.0",
"eslint": "5.9.0",
"eslint-config-airbnb-base": "13.1.0",
"eslint-plugin-import": "2.14.0",
"eslint-plugin-meteor": "5.1.0",
"lodash.isequal": "^4.5.0",
"mocha": "^5.2.0",
"nightmare": "3.0.1"
}
}

File diff suppressed because it is too large Load diff

4
package-lock.json generated
View file

@ -205,9 +205,7 @@
}
},
"@wekanteam/meteor-reactive-cache": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@wekanteam/meteor-reactive-cache/-/meteor-reactive-cache-1.0.7.tgz",
"integrity": "sha512-PSxoCX46sGcLygaKN/i/DrtPbKbm8AOnuNzK8lBE1BQTFkdnr7KBG2neGjFDbwLRHGmvvSfYStUmPtAk6xfx8w==",
"version": "file:npm-packages/meteor-reactive-cache",
"requires": {
"@wekanteam/meteor-globals": "^1.1.6"
}

View file

@ -28,7 +28,7 @@
"@wekanteam/exceljs": "^4.6.0",
"@wekanteam/html-to-markdown": "^1.0.2",
"@wekanteam/meteor-globals": "^1.1.6",
"@wekanteam/meteor-reactive-cache": "^1.0.7",
"@wekanteam/meteor-reactive-cache": "file:./npm-packages/meteor-reactive-cache",
"ajv": "^6.12.6",
"bcryptjs": "^2.4.3",
"bson": "^4.7.2",