UNPKG

@dr.pogodin/react-helmet

Version:

Thread-safe Helmet for React 19+ and friends

218 lines (215 loc) 7.44 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.newServerState = newServerState; var _react = require("react"); var _constants = require("./constants"); var _utils = require("./utils"); var _jsxRuntime = require("react/jsx-runtime"); const SELF_CLOSING_TAGS = [_constants.TAG_NAMES.NOSCRIPT, _constants.TAG_NAMES.SCRIPT, _constants.TAG_NAMES.STYLE]; const encodeSpecialCharacters = function (str) { let encode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; if (!encode) return str; return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#x27;'); }; function generateElementAttributesAsString(attrs) { let res = ''; for (const [name, value] of Object.entries(attrs)) { const attr = (0, _utils.propToAttr)(name); const neu = value === undefined ? attr : `${attr}="${value}"`; if (neu && res) res += ' '; res += neu; } return res; } const generateTitleAsString = (title, attrs, encode) => { let attrsStr = generateElementAttributesAsString(attrs); if (attrsStr) attrsStr = ` ${attrsStr}`; const flattenedTitle = (0, _utils.flattenArray)(title); return `<title ${_constants.HELMET_ATTRIBUTE}="true"${attrsStr}>${encodeSpecialCharacters(flattenedTitle, encode)}</title>`; }; function generateTagsAsString(type, tags, encode) { let res = ''; for (const tag of tags) { let attributeHtml = ''; const entries = Object.entries(tag); for (const [name, value] of entries) { if (!(name === _constants.TAG_PROPERTIES.INNER_HTML || name === _constants.TAG_PROPERTIES.CSS_TEXT)) { const attrName = _constants.HTML_TAG_MAP[name] ?? name; const attr = value === undefined ? attrName : `${attrName}="${encodeSpecialCharacters(value, encode)}"`; if (attributeHtml) attributeHtml += ` ${attr}`;else attributeHtml = attr; } } const tagContent = tag.innerHTML ?? tag.cssText ?? ''; const isSelfClosing = !SELF_CLOSING_TAGS.includes(type); res += `<${type} ${_constants.HELMET_ATTRIBUTE}="true" ${attributeHtml}${isSelfClosing ? '/>' : `>${tagContent}</${type}>`}`; } return res; } /** * Given a map of element attribute names & values it returns the corresponding * map of element properties & values (i.e. replacing some attribute names by * their corresponding property names). */ function mapElementAttributesToProps(attributes) { let ops = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; const res = {}; if (ops.addHelmetDataAttr) res[_constants.HELMET_ATTRIBUTE] = true; if (ops.addKey !== undefined) res.key = ops.addKey; for (const [attrName, value] of Object.entries(attributes)) { const propName = _constants.REACT_TAG_MAP[attrName] ?? attrName; switch (propName) { // cssText and innerHTML props get a special treatment to avoid that React // escapes their values. case 'cssText': case 'innerHTML': res.dangerouslySetInnerHTML = { __html: value }; break; default: res[propName] = value; } } return res; } function renderTitle(title, attrs) { // NOTE: Rendered as array to match legacy behavior. return [/*#__PURE__*/(0, _jsxRuntime.jsx)("title", { ...mapElementAttributesToProps(attrs, { addHelmetDataAttr: true }), children: title }, title)]; } function renderElement(type, attrs, key) { return /*#__PURE__*/(0, _react.createElement)(type, mapElementAttributesToProps(attrs, { addHelmetDataAttr: true, addKey: key })); } function renderElements(type, attrs) { const res = []; for (let i = 0; i < attrs.length; ++i) { res.push(renderElement(type, attrs[i], i)); } return res; } function newServerState(heap) { // TODO: Should this function to be attached to the heap itself? const getState = () => { heap.state ??= (0, _utils.calcAggregatedState)(heap.helmets); return heap.state; }; return { base: { toComponent() { const props = getState().base; return props ? renderElements('base', [props]) : []; }, toString() { const s = getState(); return s.base ? generateTagsAsString('base', [s.base], s.encodeSpecialCharacters) : ''; } }, bodyAttributes: { toComponent() { const props = getState().bodyAttributes; return mapElementAttributesToProps(props ?? {}); }, toString() { const props = getState().bodyAttributes; return generateElementAttributesAsString(props ?? {}); } }, htmlAttributes: { toComponent() { const props = getState().htmlAttributes; return mapElementAttributesToProps(props ?? {}); }, toString() { const props = getState().htmlAttributes; return generateElementAttributesAsString(props ?? {}); } }, link: { toComponent() { return renderElements('link', getState().links ?? []); }, toString() { const s = getState(); return generateTagsAsString('link', s.links ?? [], s.encodeSpecialCharacters); } }, meta: { toComponent() { return renderElements('meta', getState().meta ?? []); }, toString() { const s = getState(); return generateTagsAsString('meta', s.meta ?? [], s.encodeSpecialCharacters); } }, noscript: { toComponent() { return renderElements('noscript', getState().noscript ?? []); }, toString() { const s = getState(); return generateTagsAsString('noscript', s.noscript ?? [], s.encodeSpecialCharacters); } }, priority: { toComponent() { const s = getState(); return [...renderElements('meta', s.priority?.meta ?? []), ...renderElements('link', s.priority?.links ?? []), ...renderElements('script', s.priority?.script ?? [])]; }, toString() { const s = getState(); const meta = generateTagsAsString('meta', s.priority?.meta ?? [], s.encodeSpecialCharacters); const link = generateTagsAsString('link', s.priority?.links ?? [], s.encodeSpecialCharacters); const script = generateTagsAsString('script', s.priority?.script ?? [], s.encodeSpecialCharacters); let res = meta; if (link) { if (res) res += ' '; res += link; } if (script) { if (res) res += ' '; res += script; } return res; } }, script: { toComponent() { return renderElements('script', getState().script ?? []); }, toString() { const s = getState(); return generateTagsAsString('script', s.script ?? [], s.encodeSpecialCharacters); } }, style: { toComponent() { return renderElements('style', getState().style ?? []); }, toString() { const s = getState(); return generateTagsAsString('style', s.style ?? [], s.encodeSpecialCharacters); } }, title: { toComponent() { const s = getState(); return renderTitle(s.title ?? '', s.titleAttributes ?? {}); }, toString() { const s = getState(); return generateTitleAsString(s.title ?? '', s.titleAttributes ?? {}, s.encodeSpecialCharacters); } } }; } //# sourceMappingURL=server.js.map