import type { MakeLineHeightRelativeParserDefinition, MakeLineHeightRelativeParserOptions, } from './definition.js'; import { createSDTFEngine, SDTFEngine, SpecifyDesignTokenTypeName, TokenState, } from '@specifyapp/specify-design-token-format'; import { SpecifyError, specifyErrors } from '../../../errors/index.js'; import { getSdtfQuery } from '../../utils/getSdtfQuery.js'; import { DeriveBuiltInParserHandlerFromDefinition } from '../../internals/createBuiltInParserDefinition.js'; import { ParserToolbox } from '../../../parsersEngine/index.js'; export const AUTHORIZED_TOKENS: Array = [ 'border', 'shadow', 'shadows', 'textStyle', 'dimension', 'spacing', 'spacings', 'blur', 'breakpoint', 'radii', 'radius', ]; export const makeLineHeightRelativeHandler: DeriveBuiltInParserHandlerFromDefinition< MakeLineHeightRelativeParserDefinition > = async (previousDataBox, toolbox, parserOptions, _, _context) => { let sdtfEngine: SDTFEngine; switch (previousDataBox.type) { case 'SDTF': { sdtfEngine = createSDTFEngine(previousDataBox.graph, previousDataBox.metadata); break; } case 'SDTF Engine': { 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 convert-dimension parser.`, }); } } makeLineHeightRelativeInner(sdtfEngine, parserOptions, toolbox); return { type: 'SDTF Engine', engine: sdtfEngine, }; }; export function makeLineHeightRelativeInner( engine: SDTFEngine, options: MakeLineHeightRelativeParserOptions, toolbox: ParserToolbox, ) { const query = getSdtfQuery(options?.applyTo); const populateWarningMessageCallback = (token: TokenState) => { toolbox.populateMessage({ type: 'warning', content: `The token ${token.name} is not resolvable.`, errorKey: specifyErrors.PARSERS_ENGINE_PARSER_EXECUTION_FAILED.errorKey, }); return null; }; (options?.applyTo ? engine.query.run(query) : engine.query.run({ where: { token: '.*?', withTypes: { include: ['textStyle'], }, select: { token: true, }, }, }) ).forEach(tokenState => { if (!tokenState.isToken || !tokenState.isFullyResolvable) { toolbox.populateMessage({ type: 'warning', content: `Design token "${tokenState.path.toString()}" is not fully resolvable. Please check that aliases points to a valid value.`, errorKey: specifyErrors.PARSERS_ENGINE_INVALID_ALIAS.errorKey, }); return; } tokenState .getStatefulValueResult() .resolveDeepValue() .mapUnresolvableTopLevelAlias(_ => populateWarningMessageCallback(tokenState)) .mapTopLevelValue(value => { return value .resolveDeepValue() .mapUnresolvableModeLevelAlias(_ => populateWarningMessageCallback(tokenState)) .mapRawValue((rawValue, mode) => { if (!rawValue || typeof rawValue !== 'object' || !('fontSize' in rawValue)) { return; } const fontSize = rawValue.fontSize.resolveDeepValue().unwrapValue(); if ( fontSize === null || typeof fontSize !== 'object' || !('unit' in fontSize) || !('value' in fontSize) ) { return; } const fontSizeUnit = fontSize.unit.resolveDeepValue().unwrapValue(); const fontSizeValue = fontSize.value.resolveDeepValue().unwrapValue(); if (typeof fontSizeValue !== 'number' || typeof fontSizeUnit !== 'string') { return; } const lineHeight = rawValue.lineHeight.resolveDeepValue().unwrapValue(); if ( lineHeight === null || typeof lineHeight !== 'object' || !('unit' in lineHeight) || !('value' in lineHeight) ) { return rawValue.lineHeight; } let lineHeightUnit = lineHeight.unit.resolveDeepValue().unwrapValue(); let lineHeightValue = lineHeight.value.resolveDeepValue().unwrapValue(); if (typeof lineHeightValue !== 'number' || typeof lineHeightUnit !== 'string') { return rawValue.lineHeight; } const basePixelValueForRem = options?.baseValue?.rem ?? 16; if (lineHeightUnit === 'px' && fontSizeUnit === 'px') { lineHeightValue = Math.round((lineHeightValue / fontSizeValue) * 100) / 100; } else if (lineHeightUnit === 'rem' && fontSizeUnit === 'rem') { lineHeightValue = Math.round((lineHeightValue / fontSizeValue) * 100) / 100; } else if (lineHeightUnit === '%') { lineHeightValue = Math.round((lineHeightValue / 100) * 100) / 100; } else if (fontSizeUnit === 'rem' && lineHeightUnit === 'px') { lineHeightValue = Math.round((lineHeightValue / (fontSizeValue * basePixelValueForRem)) * 100) / 100; } else if (fontSizeUnit === 'px' && lineHeightUnit === 'rem') { lineHeightValue = Math.round(((lineHeightValue * basePixelValueForRem) / fontSizeValue) * 100) / 100; } else { if (lineHeightUnit !== 'px' && lineHeightUnit !== 'rem' && lineHeightUnit !== '%') { toolbox.populateMessage({ type: 'warning', content: 'The lineHeight unit is not supported. Only px, rem and % are supported.', errorKey: specifyErrors.PARSERS_ENGINE_INVALID_OUTPUT_TYPE.errorKey, }); } if (fontSizeUnit !== 'px' && fontSizeUnit !== 'rem' && fontSizeUnit !== '%') { toolbox.populateMessage({ type: 'warning', content: 'The fontSize unit is not supported. Only px, rem and % are supported.', errorKey: specifyErrors.PARSERS_ENGINE_INVALID_OUTPUT_TYPE.errorKey, }); } } tokenState.updateModeValue(mode, { ...Reflect.get(tokenState.getJSONValue(), mode), lineHeight: { unit: null, value: lineHeightValue, }, }); }); }); }); }