import { CallExpressionShape, Plugin } from '@servicenow/sdk-build-core' import { toReference } from '../utils' import { NowIdShape } from '../now-id-plugin' import { getIncludeRecords } from './utils' export const SPWidgetDependencyPlugin = Plugin.create({ name: 'SPWidgetDependencyPlugin', records: { sp_dependency: { relationships: { m2m_sp_dependency_css_include: { via: 'sp_dependency', descendant: true }, m2m_sp_dependency_js_include: { via: 'sp_dependency', descendant: true }, }, toShape(record, { descendants }) { const cssIncludeRecords = descendants.query('m2m_sp_dependency_css_include') const cssIncludes = cssIncludeRecords .map((m2m) => ({ order: m2m.get('order').toNumber(), include: m2m.get('sp_css_include') })) .sort((a, b) => a.order.getValue() - b.order.getValue()) const jsIncludeRecords = descendants.query('m2m_sp_dependency_js_include') const jsIncludes = jsIncludeRecords .map((m2m) => ({ order: m2m.get('order').toNumber(), include: m2m.get('sp_js_include') })) .sort((a, b) => a.order.getValue() - b.order.getValue()) return { success: true, value: new CallExpressionShape({ source: record, callee: 'SPWidgetDependency', args: [ record.transform(({ $ }) => ({ $id: $.val(NowIdShape.from(record)), name: $, angularModuleName: $.from('module'), cssIncludes: $.val(cssIncludes.length > 0 ? cssIncludes : undefined), jsIncludes: $.val(jsIncludes.length > 0 ? jsIncludes : undefined), })), ], }), } }, }, sp_js_include: { relationships: { m2m_sp_dependency_js_include: { via: 'sp_js_include', descendant: true }, }, toShape(record) { return { success: true, value: new CallExpressionShape({ source: record, callee: 'JsInclude', args: [ record.transform(({ $ }) => ({ $id: $.val(NowIdShape.from(record)), name: $.from('display_name'), url: $.def(''), sysUiScript: $.from('sys_ui_script').def(''), })), ], }), } }, }, sp_css_include: { relationships: { m2m_sp_dependency_css_include: { via: 'sp_css_include', descendant: true }, }, toShape(record) { return { success: true, value: new CallExpressionShape({ source: record, callee: 'CssInclude', args: [ record.transform(({ $ }) => ({ $id: $.val(NowIdShape.from(record)), name: $, url: record.get('url').getValue() ? $ : undefined, spCss: $.from('sp_css').def(''), lazyLoad: $.from('lazy_load').toBoolean().def(false), rtlCssUrl: $.from('rtl_css_file_url').def(''), })), ], }), } }, }, m2m_sp_dependency_css_include: { coalesce: ['sp_css_include', 'sp_dependency'], }, m2m_sp_dependency_js_include: { coalesce: ['sp_js_include', 'sp_dependency'], }, }, shapes: [ { shape: CallExpressionShape, fileTypes: ['fluent'], async toRecord(callExpression, { diagnostics, factory }) { if (callExpression.getCallee() !== 'JsInclude') { return { success: false } } const jsInclude = callExpression.getArgument(0).asObject() const jsIncludeId = jsInclude.get('$id') const urlDefined = jsInclude.get('url').isDefined() const uiScriptDefined = jsInclude.get('sysUiScript').isDefined() const source = urlDefined ? 'url' : 'local' if ((!urlDefined && !uiScriptDefined) || (urlDefined && uiScriptDefined)) { diagnostics.error( jsInclude, `JsInclude must define either a url or sysUiScript property, but not both` ) } return { success: true, value: await factory.createRecord({ source: callExpression, table: 'sp_js_include', explicitId: jsIncludeId, properties: jsInclude.transform(({ $ }) => ({ display_name: $.from('name'), source: $.val(source), sys_ui_script: $.from('sysUiScript').map(toReference), url: $.from('url').def(''), })), }), } }, }, { shape: CallExpressionShape, fileTypes: ['fluent'], async toRecord(callExpression, { diagnostics, factory }) { if (callExpression.getCallee() !== 'CssInclude') { return { success: false } } const cssInclude = callExpression.getArgument(0).asObject() const cssIncludeId = cssInclude.get('$id') const urlDefined = cssInclude.get('url').isDefined() const cssDefined = cssInclude.get('spCss').isDefined() if ((!urlDefined && !cssDefined) || (urlDefined && cssDefined)) { diagnostics.error(cssInclude, `CssInclude must define either a url or spCss property, but not both`) } const source = urlDefined ? 'url' : 'local' return { success: true, value: await factory.createRecord({ source: callExpression, table: 'sp_css_include', explicitId: cssIncludeId, properties: cssInclude.transform(({ $ }) => ({ lazy_load: $.from('lazyLoad').def(false), name: $, rtl_css_file_url: $.from('rtlCssUrl').def(''), source: $.val(source), sp_css: $.from('spCss').map(toReference), url: $.from('url').def(''), })), }), } }, }, { shape: CallExpressionShape, fileTypes: ['fluent'], async toRecord(callExpression, { diagnostics, factory }) { if (callExpression.getCallee() !== 'SPWidgetDependency') { return { success: false } } const dependency = callExpression.getArgument(0).asObject() const portals = (dependency .get('portalsForPageLoad') ?.ifArray() ?.map((p) => { if (p.isString()) { return p.getValue() } if (p.isRecord()) { return p.getId() } diagnostics.error(p, `Must be a sys_id or Record<'sp_portal'>`) return undefined }) .filter((guid) => guid) as string[]) || [] const dependencyRecord = await factory.createRecord({ source: callExpression, table: 'sp_dependency', explicitId: dependency.get('$id'), properties: dependency.transform(({ $ }) => ({ name: $, module: $.from('angularModuleName').def(''), page_load: $.from('includeOnPageLoad').def(false), sp_portals: $.val(portals.toString()), })), }) const cssIncludes = await getIncludeRecords( dependency.get('cssIncludes'), dependencyRecord.getId(), factory, 'm2m_sp_dependency_css_include', 'sp_css_include', 'sp_dependency', diagnostics ) const jsIncludes = await getIncludeRecords( dependency.get('jsIncludes'), dependencyRecord.getId(), factory, 'm2m_sp_dependency_js_include', 'sp_js_include', 'sp_dependency', diagnostics ) return { success: true, value: dependencyRecord.with(...cssIncludes, ...jsIncludes), } }, }, ], })