UNPKG

@silexlabs/grapesjs-data-source

Version:
380 lines 14.3 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.NOTIFICATION_GROUP = void 0; exports.cleanStateName = cleanStateName; exports.getComponentDebug = getComponentDebug; exports.concatWithLength = concatWithLength; exports.getTokenDisplayName = getTokenDisplayName; exports.groupByType = groupByType; exports.getFixedToken = getFixedToken; exports.toValue = toValue; exports.toId = toId; exports.fromString = fromString; exports.isExpression = isExpression; exports.toExpression = toExpression; exports.convertKind = convertKind; exports.getFieldType = getFieldType; exports.optionsFormKeySelector = optionsFormKeySelector; exports.getElementFromOption = getElementFromOption; exports.getDefaultOptions = getDefaultOptions; exports.createDataSource = createDataSource; const state_1 = require("./model/state"); const lit_1 = require("lit"); const token_1 = require("./model/token"); const GraphQL_1 = __importDefault(require("./datasources/GraphQL")); const dataSourceRegistry_1 = require("./model/dataSourceRegistry"); const types_1 = require("./types"); exports.NOTIFICATION_GROUP = 'Data source'; /** * Get the display name of a field */ function cleanStateName(name) { var _a, _b; return (_b = (_a = name === null || name === void 0 ? void 0 : name.toLowerCase()) === null || _a === void 0 ? void 0 : _a.replace(/[^a-z0-9:._-]/g, '-')) === null || _b === void 0 ? void 0 : _b.replace(/^[0-9]+/, '-'); // HTML attributes cannot start with digits } /** * Get the display type of a field * For the dropdown in expressions * @example "String", "String [ ]", "String { }" */ function getTypeDisplayName(typeIds, kind) { const typeIdsStr = typeIds.join(', ').toLowerCase(); return kind === 'list' ? ` (${typeIdsStr}[])` : kind === 'object' ? ` (${typeIdsStr}{})` : ` (${typeIdsStr})`; } function getComponentDebug(component) { const parent = component.parent(); const parentName = parent === null || parent === void 0 ? void 0 : parent.getName(); const parentTagName = parent === null || parent === void 0 ? void 0 : parent.get('tagName'); const parentDebug = parentName ? `${parentName} (${parentTagName})` : parentTagName; const id = component.cid; const tagName = component.get('tagName'); const classes = component.getClasses(); const classesStr = classes.length ? `.${classes.join('.')}` : ''; const name = component.getName(); return `${parentDebug} > ${name} (${tagName}#${id}${classesStr})`; } /** * Concatenate strings to get a desired length string as result * Exported for tests */ function concatWithLength(desiredNumChars, ...strings) { // const diff = desiredNumChars - `${token.label} ${type}`.length // return `${token.label}${'\xA0'.repeat(diff * 2)} ${type} ${desiredNumChars}` // Get current string length const len = strings.reduce((acc, str) => acc + str.length, 0); const diff = Math.max(desiredNumChars - len, 0); // Give the fist string the desired length const [first, ...rest] = strings; const newFirst = first + '\xA0'.repeat(diff); // Return the concatenated string return [newFirst, ...rest].join(''); } /** * Get the label for a token * This is mostly about formatting a string for the dropdowns */ function getTokenDisplayName(component, token) { switch (token.type) { case 'property': { const type = getTypeDisplayName(token.typeIds, token.kind); return `${token.label} ${type}`; } case 'filter': return token.label; case 'state': return (0, state_1.getStateDisplayName)(component, token); default: console.error('Unknown token type (reading type)', token); throw new Error('Unknown token type'); } } /** * Group tokens by type * This is used to create the groups in dropdowns */ function groupByType(editor, component, completion, expression) { return completion .reduce((acc, token) => { var _a, _b, _c, _d; let label; switch (token.type) { case 'filter': label = 'Filters'; break; case 'property': { if (token.dataSourceId) { if (expression.length > 0) { try { const type = (0, token_1.getExpressionResultType)(expression, component); label = (_b = (_a = type === null || type === void 0 ? void 0 : type.label) !== null && _a !== void 0 ? _a : type === null || type === void 0 ? void 0 : type.id) !== null && _b !== void 0 ? _b : 'Unknown'; } catch (e) { // FIXME: notify user console.error('Error while getting expression result type in groupByType', { expression, component }); label = 'Unknown'; } } else { const dataSource = (0, dataSourceRegistry_1.getDataSource)(token.dataSourceId); if (dataSource) { label = dataSource.label || ((_d = (_c = dataSource).get) === null || _d === void 0 ? void 0 : _d.call(_c, 'label')) || token.dataSourceId; } else { console.error('Data source not found', token.dataSourceId); editor.runCommand('notifications:add', { type: 'error', group: exports.NOTIFICATION_GROUP, message: `Data source not found: ${token.dataSourceId}`, }); throw new Error(`Data source not found: ${token.dataSourceId}`); } } } else { label = 'Fields'; } break; } case 'state': { const parent = (0, state_1.getParentByPersistentId)(token.componentId, component); const name = (parent === null || parent === void 0 ? void 0 : parent.get('tagName')) === 'body' ? 'Website' : parent === null || parent === void 0 ? void 0 : parent.getName(); label = name ? `${name}'s states` : 'States'; break; } default: console.error('Unknown token type (reading type)', token); throw new Error('Unknown token type'); } if (!acc[label]) acc[label] = []; acc[label].push(token); return acc; }, {}); } /** * Create a "fixed" token * It is a hard coded content with which you can start an expression */ function getFixedToken(value) { return { type: 'property', propType: 'field', fieldId: types_1.FIXED_TOKEN_ID, label: 'Fixed value', kind: 'scalar', typeIds: ['String'], options: { value, }, optionsForm: () => (0, lit_1.html) ` <label>Value <input type="text" name="value" .value=${value}> </label> `, }; } /** * Convert a token to a string * This is used to store the token in the component */ function toValue(token) { return JSON.stringify(Object.assign({}, token)); } /** * Convert a token to an option's tag value (json string) */ function toId(token) { switch (token.type) { case 'property': return `property__${token.dataSourceId || ''}__${token.fieldId}__${token.kind}__${token.typeIds.join(',')}`; case 'filter': return `filter____${token.id}`; case 'state': return `state__${token.componentId}__${token.storedStateId}`; default: console.error('Unknown token type (reading type)', token); throw new Error('Unknown token type'); } } /** * Revert an option's tag value to a token * @throws Error if the token type is not found */ function fromString(editor, id, componentId) { return (0, token_1.fromStored)(JSON.parse(id), componentId); } /** * Check if a json is an expression, i.e. an array of tokens */ function isExpression(json) { if (typeof json === 'string') throw new Error('json must be parsed'); if (!Array.isArray(json)) return false; return json.every(token => { var _a; if (typeof token !== 'object') return false; if (!token.type) return false; switch (token.type) { case 'property': { if (!token.fieldId) return false; if (token.fieldId === types_1.FIXED_TOKEN_ID) { if (!((_a = token.options) === null || _a === void 0 ? void 0 : _a.value)) return false; } break; } case 'state': { if (!token.componentId) return false; if (!token.storedStateId) return false; break; } case 'filter': { if (!token.id) return false; break; } } return true; }); } /** * Convert a json to an expression */ function toExpression(json) { try { if (typeof json === 'string') json = JSON.parse(json); if (isExpression(json)) return json; return null; } catch (e) { return null; } } /** * Apply a kind to a field */ function convertKind(field, from, to) { if (!field) { return null; } if (field.kind !== from) { console.error(`Field is not a ${from}`, field); throw new Error(`Field ${field.label} is not a ${from}`); } return Object.assign(Object.assign({}, field), { kind: to }); } /** * Get the type of a field, as provided by the data source * @throws Error if the field has a token with an unknown type */ function getFieldType(editor, field, key, componentId) { if (!field || !key) return null; const allDataSources = (0, dataSourceRegistry_1.getAllDataSources)(); const dataSource = allDataSources.find((ds) => ds.id === field.dataSourceId); if (!(dataSource === null || dataSource === void 0 ? void 0 : dataSource.isConnected())) return null; const types = field.typeIds.map(typeId => { const dsTypes = dataSource.getTypes(); return dsTypes.find((type) => type.id === typeId); }).filter(Boolean); const fields = types.map((type) => type === null || type === void 0 ? void 0 : type.fields.find((f) => f.label === key)).filter(Boolean); switch (fields.length) { case 0: return null; case 1: return fields[0]; default: return { id: `${field.id}.${key}`, label: `${field.label}.${key}`, typeIds: fields.reduce((typeIds, field) => typeIds .concat(field.typeIds.filter((t) => !typeIds.includes(t))), []), kind: 'object', dataSourceId: field.dataSourceId }; } } /** * Generate a form to edit the options of a token * @throws Error if the field has a token with an unknown type */ function optionsFormKeySelector(editor, field, options, name) { if (!field) return (0, lit_1.html) ` <label>${name} <input type="text" name=${name} /> </label> `; const allDataSources = (0, dataSourceRegistry_1.getAllDataSources)(); const dataSource = allDataSources.find((ds) => ds.id === field.dataSourceId); if (!(dataSource === null || dataSource === void 0 ? void 0 : dataSource.isConnected())) { return (0, lit_1.html) ` <select name=${name}> <option value="">Data source not connected</option> </select> `; } const dsTypes = dataSource.getTypes(); const fieldOptions = field.typeIds .flatMap(typeId => { var _a; return ((_a = dsTypes.find((type) => type.id === typeId)) === null || _a === void 0 ? void 0 : _a.fields) || []; }); return (0, lit_1.html) ` <select name=${name}> <option value="">Select a ${name}</option> ${fieldOptions.map(f => (0, lit_1.html) `<option value=${f.label} .selected=${f.label === options.key}>${f.label}</option>`)} </select> `; } /** * Get a container element from an option * @throws Error if the option is not a string or an HTMLElement or a function * @throws Error if the element is not found */ function getElementFromOption(option, optionNameForError) { // Get the container element for the UI if (typeof option === 'undefined') { // This should never happen as we set a default value in /index.ts throw new Error('el option must be set'); } else if (typeof option === 'string') { const el = document.querySelector(option); if (!el) throw new Error(`Element ${option} not found`); return el; } else if (typeof option === 'function') { const el = option(); if (!el) throw new Error('el option must be a returned by the provided function'); return el; } else if (option instanceof HTMLElement) { return option; } throw new Error(`${optionNameForError} must be a string or an HTMLElement or a function`); } function getDefaultOptions(postFix = Math.random().toString(36).slice(2, 8)) { return { id: `ds-${postFix}`, label: 'New data source', type: 'graphql', url: '', method: 'POST', headers: {}, readonly: false, }; } function createDataSource(opts = {}, postFix) { const options = Object.assign(Object.assign({}, getDefaultOptions(postFix)), opts); switch (options.type) { case 'graphql': return new GraphQL_1.default(options); default: throw new Error(`Unknown data source type: ${options.type}`); } } //# sourceMappingURL=utils.js.map