next-csrf
Version:
CSRF mitigation library for Next.js
254 lines (201 loc) • 7.12 kB
JavaScript
"use strict";
exports.__esModule = true;
exports["default"] = void 0;
var _stringHash = _interopRequireDefault(require("string-hash"));
var _stylesheet = _interopRequireDefault(require("./lib/stylesheet"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
var sanitize = function sanitize(rule) {
return rule.replace(/\/style/gi, '\\/style');
};
var StyleSheetRegistry =
/*#__PURE__*/
function () {
function StyleSheetRegistry(_temp) {
var _ref = _temp === void 0 ? {} : _temp,
_ref$styleSheet = _ref.styleSheet,
styleSheet = _ref$styleSheet === void 0 ? null : _ref$styleSheet,
_ref$optimizeForSpeed = _ref.optimizeForSpeed,
optimizeForSpeed = _ref$optimizeForSpeed === void 0 ? false : _ref$optimizeForSpeed,
_ref$isBrowser = _ref.isBrowser,
isBrowser = _ref$isBrowser === void 0 ? typeof window !== 'undefined' : _ref$isBrowser;
this._sheet = styleSheet || new _stylesheet["default"]({
name: 'styled-jsx',
optimizeForSpeed: optimizeForSpeed
});
this._sheet.inject();
if (styleSheet && typeof optimizeForSpeed === 'boolean') {
this._sheet.setOptimizeForSpeed(optimizeForSpeed);
this._optimizeForSpeed = this._sheet.isOptimizeForSpeed();
}
this._isBrowser = isBrowser;
this._fromServer = undefined;
this._indices = {};
this._instancesCounts = {};
this.computeId = this.createComputeId();
this.computeSelector = this.createComputeSelector();
}
var _proto = StyleSheetRegistry.prototype;
_proto.add = function add(props) {
var _this = this;
if (undefined === this._optimizeForSpeed) {
this._optimizeForSpeed = Array.isArray(props.children);
this._sheet.setOptimizeForSpeed(this._optimizeForSpeed);
this._optimizeForSpeed = this._sheet.isOptimizeForSpeed();
}
if (this._isBrowser && !this._fromServer) {
this._fromServer = this.selectFromServer();
this._instancesCounts = Object.keys(this._fromServer).reduce(function (acc, tagName) {
acc[tagName] = 0;
return acc;
}, {});
}
var _this$getIdAndRules = this.getIdAndRules(props),
styleId = _this$getIdAndRules.styleId,
rules = _this$getIdAndRules.rules; // Deduping: just increase the instances count.
if (styleId in this._instancesCounts) {
this._instancesCounts[styleId] += 1;
return;
}
var indices = rules.map(function (rule) {
return _this._sheet.insertRule(rule);
}) // Filter out invalid rules
.filter(function (index) {
return index !== -1;
});
this._indices[styleId] = indices;
this._instancesCounts[styleId] = 1;
};
_proto.remove = function remove(props) {
var _this2 = this;
var _this$getIdAndRules2 = this.getIdAndRules(props),
styleId = _this$getIdAndRules2.styleId;
invariant(styleId in this._instancesCounts, "styleId: `" + styleId + "` not found");
this._instancesCounts[styleId] -= 1;
if (this._instancesCounts[styleId] < 1) {
var tagFromServer = this._fromServer && this._fromServer[styleId];
if (tagFromServer) {
tagFromServer.parentNode.removeChild(tagFromServer);
delete this._fromServer[styleId];
} else {
this._indices[styleId].forEach(function (index) {
return _this2._sheet.deleteRule(index);
});
delete this._indices[styleId];
}
delete this._instancesCounts[styleId];
}
};
_proto.update = function update(props, nextProps) {
this.add(nextProps);
this.remove(props);
};
_proto.flush = function flush() {
this._sheet.flush();
this._sheet.inject();
this._fromServer = undefined;
this._indices = {};
this._instancesCounts = {};
this.computeId = this.createComputeId();
this.computeSelector = this.createComputeSelector();
};
_proto.cssRules = function cssRules() {
var _this3 = this;
var fromServer = this._fromServer ? Object.keys(this._fromServer).map(function (styleId) {
return [styleId, _this3._fromServer[styleId]];
}) : [];
var cssRules = this._sheet.cssRules();
return fromServer.concat(Object.keys(this._indices).map(function (styleId) {
return [styleId, _this3._indices[styleId].map(function (index) {
return cssRules[index].cssText;
}).join(_this3._optimizeForSpeed ? '' : '\n')];
}) // filter out empty rules
.filter(function (rule) {
return Boolean(rule[1]);
}));
}
/**
* createComputeId
*
* Creates a function to compute and memoize a jsx id from a basedId and optionally props.
*/
;
_proto.createComputeId = function createComputeId() {
var cache = {};
return function (baseId, props) {
if (!props) {
return "jsx-" + baseId;
}
var propsToString = String(props);
var key = baseId + propsToString; // return `jsx-${hashString(`${baseId}-${propsToString}`)}`
if (!cache[key]) {
cache[key] = "jsx-" + (0, _stringHash["default"])(baseId + "-" + propsToString);
}
return cache[key];
};
}
/**
* createComputeSelector
*
* Creates a function to compute and memoize dynamic selectors.
*/
;
_proto.createComputeSelector = function createComputeSelector(selectoPlaceholderRegexp) {
if (selectoPlaceholderRegexp === void 0) {
selectoPlaceholderRegexp = /__jsx-style-dynamic-selector/g;
}
var cache = {};
return function (id, css) {
// Sanitize SSR-ed CSS.
// Client side code doesn't need to be sanitized since we use
// document.createTextNode (dev) and the CSSOM api sheet.insertRule (prod).
if (!this._isBrowser) {
css = sanitize(css);
}
var idcss = id + css;
if (!cache[idcss]) {
cache[idcss] = css.replace(selectoPlaceholderRegexp, id);
}
return cache[idcss];
};
};
_proto.getIdAndRules = function getIdAndRules(props) {
var _this4 = this;
var css = props.children,
dynamic = props.dynamic,
id = props.id;
if (dynamic) {
var styleId = this.computeId(id, dynamic);
return {
styleId: styleId,
rules: Array.isArray(css) ? css.map(function (rule) {
return _this4.computeSelector(styleId, rule);
}) : [this.computeSelector(styleId, css)]
};
}
return {
styleId: this.computeId(id),
rules: Array.isArray(css) ? css : [css]
};
}
/**
* selectFromServer
*
* Collects style tags from the document with id __jsx-XXX
*/
;
_proto.selectFromServer = function selectFromServer() {
var elements = Array.prototype.slice.call(document.querySelectorAll('[id^="__jsx-"]'));
return elements.reduce(function (acc, element) {
var id = element.id.slice(2);
acc[id] = element;
return acc;
}, {});
};
return StyleSheetRegistry;
}();
exports["default"] = StyleSheetRegistry;
function invariant(condition, message) {
if (!condition) {
throw new Error("StyleSheetRegistry: " + message + ".");
}
}