npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@appium/css-locator-to-native

v1.0.1

Published

Platform-agnostic CSS selector parsing and normalization for native locator transformation

Readme

@appium/css-locator-to-native

Platform-agnostic CSS selector parsing and normalization for native locator transformation.

Installation

npm install @appium/css-locator-to-native

Quick start

import {
  createCssTransformer,
  type AttributeSchema,
  type ParsedSelector,
  type StrategyKey,
} from '@appium/css-locator-to-native';

const schema: AttributeSchema = {
  attributes: {
    visible: {type: 'boolean'},
    name: {type: 'string', aliases: ['id']},
    index: {type: 'numeric', aliases: ['nth-child']},
  },
  booleanFormat: 'zero-one',
};

const emitters = {
  native: {
    strategy: 'my-native-strategy',
    emit(parsed: ParsedSelector) {
      // Map ParsedSelector IR to your platform's selector syntax
      return parsed.rule.tag ?? '*';
    },
  },
};

const transformCss = createCssTransformer({
  schema,
  emitters,
  resolveStrategy(): StrategyKey<typeof emitters> {
    return 'native';
  },
});

const {strategy, selector} = transformCss('window#foo[visible]');
// => { strategy: 'my-native-strategy', selector: '...' }

API

Everything is exported from a single entry point:

| Export | Description | |---|---| | normalizeCssSelector(css, schema) | Parse and normalize a CSS selector into a ParsedSelector IR | | createCssTransformer(config) | Returns a function that parses CSS and produces a NativeLocator | | InvalidSelectorError | CSS syntax cannot be parsed | | UnsupportedSelectorError | Parsed CSS uses unsupported features or unknown attributes | | UnresolvedStrategyError | No matching emitter for the resolved strategy key |

ParsedSelector IR

Normalization produces a platform-agnostic intermediate representation. The IR captures CSS structure — tags, classes, #id, attributes, pseudos, combinators — validated against your schema. It does not encode iOS class chain, UiAutomator, or any other native syntax.

interface ParsedSelector {
  rule: ParsedRule; // first comma-separated rule only
}

interface ParsedRule {
  combinator?: 'descendant' | 'child';
  tag?: string;           // raw CSS tag (may be '*')
  classes: string[];      // raw class tokens
  id?: string;            // raw #id value
  attributes: ParsedAttribute[];
  pseudos: ParsedAttribute[];
  nested?: ParsedRule;
}

Attribute schemas

Drivers declare which CSS attributes are valid and how booleans are coerced:

interface AttributeSchema {
  attributes: Record<string, {type: 'boolean' | 'string' | 'numeric'; aliases?: string[]}>;
  booleanFormat?: 'zero-one' | 'true-false' | 'literal';
}
  • zero-onetrue/1/empty → '1', false/0'0'
  • true-falsetrue/empty → 'true', false'false'
  • literal (default) — keep the raw attribute value unchanged; implicit booleans (no value) stay unset

Tag, class, and #id mapping (e.g. XCUIElementType* prefixing, resourceId prefixing) is entirely the driver's responsibility in emitters.

Multi-strategy routing

createCssTransformer requires a registry of StrategyEmitters and a resolveStrategy callback. The resolver picks which emitter to use based on selector shape; the transformer returns both the target strategy name and the native selector string.

interface NativeLocator {
  strategy: string;
  selector: string;
}

A driver with a single target strategy uses a one-entry registry and a trivial resolver.

Driver integration pattern

Platform logic stays in the driver. A typical layout:

lib/css/
  schema.ts          # AttributeSchema for the platform
  *-emitter.ts       # StrategyEmitter implementations
  resolve-helpers.ts # isSimpleIdSelector, etc.
  index.ts           # createCssTransformer wrapper

In find commands, use the strategy from the transform result instead of hardcoding it:

if (strategy === 'css selector') {
  ({strategy, selector} = cssToNativeLocator(selector));
}

Supported CSS subset

Matches the subset accepted by existing Appium drivers:

  • Tags (including *), #id, classes, attribute selectors (=, *=, ^=, $=, ~=)
  • Child (>) and descendant (space) combinators
  • Pseudo-classes accepted as attributes per schema (e.g. :visible, :nth-child(2))
  • First comma-separated rule only (additional rules are ignored)
  • Unsupported: + / ~ combinators, pseudo-elements, nesting (&), namespaces

Development

npm install --no-package-lock
npm run typecheck   # type-check lib + test
npm run build       # compile to build/
npm test            # unit tests (compiled ESM)
npm run lint
npm run format:check

Requirements

  • Node.js ^20.19.0 || ^22.12.0 || >=24.0.0
  • npm >=10

License

Apache-2.0