| import getAtRuleParams from './getAtRuleParams.mjs'; |
| import getRuleSelector from './getRuleSelector.mjs'; |
| |
| import { isObject, isString } from './validateTypes.mjs'; |
| |
| /** @import {AtRule, Declaration, Rule} from 'postcss' */ |
| |
| /** |
| * @param {AtRule} atRule |
| * @returns {number} |
| */ |
| export function atRuleParamIndex(atRule) { |
| const index = atRuleAfterNameIndex(atRule); |
| |
| return index + (atRule.raws.afterName?.length ?? 0); |
| } |
| |
| /** |
| * @param {AtRule} atRule |
| * @returns {number} |
| */ |
| export function atRuleAfterIndex(atRule) { |
| // subtract 1 for `}` |
| |
| const endOffset = atRule.source?.end?.offset; |
| |
| if (!endOffset) return atRule.toString().length - 1; |
| |
| const afterLength = atRule.raws?.after?.length; |
| |
| if (!afterLength) return endOffset - 1; |
| |
| return endOffset - (afterLength + 1); |
| } |
| |
| /** |
| * @param {AtRule} atRule |
| * @returns {number} |
| */ |
| export function atRuleAfterNameIndex(atRule) { |
| // Initial 1 is for the `@` |
| return 1 + atRule.name.length; |
| } |
| |
| /** |
| * @param {AtRule} atRule |
| * @returns {number} |
| */ |
| export function atRuleBetweenIndex(atRule) { |
| return atRuleParamIndex(atRule) + getAtRuleParams(atRule).length; |
| } |
| |
| /** |
| * @param {Declaration} decl |
| * @returns {number} |
| */ |
| export function declarationBetweenIndex(decl) { |
| const { prop } = decl.raws; |
| const propIsObject = isObject(prop); |
| |
| return countChars([ |
| propIsObject && 'prefix' in prop && prop.prefix, |
| (propIsObject && 'raw' in prop && prop.raw) || decl.prop, |
| propIsObject && 'suffix' in prop && prop.suffix, |
| ]); |
| } |
| |
| /** |
| * Get the index of a declaration's value |
| * |
| * @param {Declaration} decl |
| * @returns {number} |
| */ |
| export function declarationValueIndex(decl) { |
| const { between, value } = decl.raws; |
| |
| return ( |
| declarationBetweenIndex(decl) + |
| countChars([between || ':', value && 'prefix' in value && value.prefix]) |
| ); |
| } |
| |
| /** |
| * @param {Rule} rule |
| * @returns {number} |
| */ |
| export function ruleBetweenIndex(rule) { |
| return getRuleSelector(rule).length; |
| } |
| |
| /** |
| * @param {Rule} rule |
| * @returns {number} |
| */ |
| export function ruleAfterIndex(rule) { |
| // subtract 1 for `}` |
| |
| const endOffset = rule.source?.end?.offset; |
| |
| if (!endOffset) return rule.toString().length - 1; |
| |
| const afterLength = rule.raws?.after?.length; |
| |
| if (!afterLength) return endOffset - 1; |
| |
| return endOffset - (afterLength + 1); |
| } |
| |
| /** |
| * @param {unknown[]} values |
| * @returns {number} |
| */ |
| function countChars(values) { |
| return values.reduce((/** @type {number} */ count, value) => { |
| if (isString(value)) return count + value.length; |
| |
| return count; |
| }, 0); |
| } |