import { SpecifyError, specifyErrors } from '../../../errors/index.js'; import { generateUrlDataBoxFiles } from '../../shared/to-file/generatesUrlDataBoxFiles.js'; import { createSDTFEngine, SDTFEngine, SpecifyDesignTokenFormat, TreePath, } from '@specifyapp/specify-design-token-format'; import { DEFAULT_FILENAME_TEMPLATE_WITH_MODES, DEFAULT_FILENAME_TEMPLATE_WITHOUT_MODES, makeFilename, } from '../../utils/filenameTemplateVariables.js'; import { FilesOutput } from '../../../parsersEngine/definitions/parserOutput.js'; import type { ToFileParserDefinition } from './definition.js'; import type { DeriveBuiltInParserHandlerFromDefinition } from '../../internals/createBuiltInParserDefinition.js'; export const toFileHandler: DeriveBuiltInParserHandlerFromDefinition< ToFileParserDefinition > = async (previousDataBox, toolbox, parserOptions, outputConfiguration, _context) => { let tokenTree: SpecifyDesignTokenFormat; let sdtfEngine: SDTFEngine; switch (previousDataBox.type) { case 'SDTF': { tokenTree = previousDataBox.graph; sdtfEngine = createSDTFEngine(previousDataBox.graph); break; } case 'SDTF Engine': { tokenTree = previousDataBox.engine.renderJSONTree(); sdtfEngine = previousDataBox.engine; break; } default: { throw new SpecifyError({ errorKey: specifyErrors.PARSERS_ENGINE_INVALID_PARSER_INPUT.errorKey, publicMessage: `${ (previousDataBox as any).type } is not a valid input for the to-css-custom-properties parser.`, }); } } if (outputConfiguration?.type !== 'directory') { throw new SpecifyError({ errorKey: specifyErrors.PARSERS_ENGINE_INVALID_OUTPUT_TYPE.errorKey, publicMessage: `The output type ${outputConfiguration?.type} is not supported by the to-file parser.`, }); } const urlDataBoxList = generateUrlDataBoxFiles(tokenTree, toolbox); const directoryPath = outputConfiguration.directoryPath.endsWith('/') ? outputConfiguration.directoryPath : `${outputConfiguration.directoryPath}/`; let output: FilesOutput['files'] = []; const filenamesSet = new Set(); for (const urlData of urlDataBoxList) { const tokenState = sdtfEngine.query.getTokenState(new TreePath(urlData.path)); if (!tokenState) throw new SpecifyError({ errorKey: specifyErrors.PARSERS_ENGINE_INVALID_PARSER_INPUT.errorKey, publicMessage: `Token path ${urlData.path.join('.')} is not resolved.`, }); const hasMoreThan1Mode = Object.keys(urlData.token.$value).length > 1; const template = parserOptions?.filenameTemplate && typeof parserOptions?.filenameTemplate === 'string' ? parserOptions?.filenameTemplate : parserOptions?.filenameTemplate && typeof parserOptions.filenameTemplate === 'object' && Reflect.has(parserOptions.filenameTemplate, tokenState.type) ? Reflect.get(parserOptions.filenameTemplate, tokenState.type) : hasMoreThan1Mode ? DEFAULT_FILENAME_TEMPLATE_WITH_MODES : DEFAULT_FILENAME_TEMPLATE_WITHOUT_MODES; const filename = makeFilename(template, tokenState, urlData.mode, urlData.url); if (filenamesSet.has(filename)) { toolbox.populateMessage({ type: 'warning', content: `Duplicate filename "${filename}" from token "${tokenState.path.toString()}". File will not be added to result.`, errorKey: specifyErrors.PARSERS_ENGINE_PARSER_EXECUTION_FAILED.errorKey, }); } else { filenamesSet.add(filename); output.push({ path: `${directoryPath}${filename}`, content: { type: 'url', url: urlData.url, }, }); } } toolbox.populateOutput({ type: 'files', files: output, }); return { type: 'asset', assets: urlDataBoxList, }; };