import type { CallExpressionShape, Diagnostics, Factory, Record } from '@servicenow/sdk-build-core' import { generateDeprecatedDiagnostics } from '../utils' import { BCP47_LANGUAGE_TAG_PATTERN } from '../column-plugin' /** * Finds the documentation record for the default language and returns the label value as a string */ export function getLabelForDefaultLanguage(documentation: Record[], defaultLanguage: string): string | undefined { return documentation .find((d) => d.get('language').equals(defaultLanguage)) ?.get('label') .asString() .getValue() } export async function getChoiceRecords( callExpression: CallExpressionShape, aliasedKeys: globalThis.Record, factory: Factory, diagnostics: Diagnostics, defaultLanguage: string = 'en' ) { const column = callExpression.getArgument(0).asObject() const choiceArg = column.has('choices') ? column.get('choices').asObject().withAliasedKeys(aliasedKeys) : undefined if (!choiceArg) { return [] } const records: Record[] = [] for (const [idx, [choiceValue, choice]] of Object.entries(choiceArg.properties()).entries()) { if (choice.isString()) { records.push( await factory.createRecord({ source: callExpression, table: 'sys_choice', properties: { name: column.get('table').asString().getValue(), element: column.get('name').asString().getValue(), label: choice, value: choiceValue, sequence: idx + 1, language: defaultLanguage, }, }) ) continue } // A choice value is either a single ChoiceConfig or an array of ChoiceConfig — one entry // per language. Normalize to a list and emit one sys_choice record per entry. const isMultiChoice = choice.isArray() const entries = isMultiChoice ? choice.asArray().getElements() : [choice] const languageDepValKeys = new Set() for (const entry of entries) { const choiceObj = entry.asObject().withAliasedKeys(aliasedKeys) generateDeprecatedDiagnostics(choiceObj, diagnostics) const language = choiceObj.get('language').ifString()?.getValue() const resolvedLanguage = isMultiChoice ? (language ?? defaultLanguage) : language if (language && !BCP47_LANGUAGE_TAG_PATTERN.test(language)) { diagnostics.error( entry.getOriginalNode(), `'language' must be a valid BCP 47 language tag (e.g., 'en', 'es', 'en-US', 'zh-Hans')` ) } if (resolvedLanguage !== undefined) { const depVal = choiceObj.get('dependentValue') const dependentValue = depVal.ifString()?.getValue() ?? depVal.ifNumber()?.getValue()?.toString() ?? '' const key = `${resolvedLanguage}::${dependentValue}` if (languageDepValKeys.has(key)) { const detail = dependentValue ? ` with dependentValue '${dependentValue}'` : '' diagnostics.error( entry.getOriginalNode(), `Duplicate entry for choice value '${choiceValue}'${detail}: language '${resolvedLanguage}' is already used. Each (language, dependentValue) combination must be unique per choice value.` ) } languageDepValKeys.add(key) } records.push( await factory.createRecord({ source: callExpression, table: 'sys_choice', properties: choiceObj.transform(({ $ }) => ({ name: $.val(column.get('table')), element: $.val(column.get('name')), label: $, value: $.val(choiceValue), sequence: $, dependent_value: $.from('dependentValue'), hint: $, inactive: $.toBoolean().def(false), inactive_on_update: $.from('inactiveOnUpdate').toBoolean().def(false), language: $.def(defaultLanguage), synonyms: $.map((s) => s .ifArray() ?.map((e) => e.ifString()?.getValue() ?? '') .join(',') ), })), }) ) } } return records }