# AUR9989

## Error Message

`AUR9989: Invalid query selector. Only selectors with alpha-numeric characters, or $all are allowed. Got <selector> instead.`

Where `<selector>` is the invalid query string provided.

## Description

This error occurs when the query selector string provided to the `@children` decorator or its options does not meet the validation criteria enforced by Aurelia.

## Cause

The `@children` decorator uses a simplified query mechanism compared to standard `document.querySelectorAll`. Based on the implementation in `packages/runtime-html/src/templating/children.ts`, the query selector string must conform to one of the following:

1. **The special value `$all`:** This selects all direct child elements.
2. **A selector matching the pattern `/^(?:[$a-z](?:[$a-z0-9]*))(?:\.(?:[$a-z0-9]+))+$/i`:**
   * Starts with a letter (`a-z`, case-insensitive) or a dollar sign (`$`).
   * Followed by zero or more letters, numbers, or dollar signs. (This part seems intended to match element tag names, potentially including custom elements).
   * Followed by *one or more* class selectors (e.g., `.class1`, `.class2`). Each class name must consist only of letters and numbers (`a-z`, `0-9`, case-insensitive).

This means the following are **not** allowed:

* Selectors with spaces (e.g., `div .item`)
* ID selectors (e.g., `#my-id`)
* Attribute selectors (e.g., `[data-value="foo"]`)
* Pseudo-classes or pseudo-elements (e.g., `:first-child`, `::before`)
* Combinators (e.g., `div > span`, `h2 + p`)
* Complex type selectors beyond the initial simple one (e.g., `div.container span`)
* Selectors without at least one class name (unless it's `$all`).

The error message simplifies this, stating only "alpha-numeric characters or $all" are allowed, but the underlying check is slightly more specific as described above.

## Solution

Modify the query selector provided to `@children` to conform to the allowed patterns:

1. Use `$all` to select all direct child elements.
2. Use a simple selector consisting of an optional element name followed by one or more class names composed only of letters and numbers (e.g., `div.item`, `.product-card`, `my-element.active.highlight`).

If you need more complex selection logic, query the elements manually within the component's lifecycle hooks (e.g., `attached`) using standard DOM methods like `this.$host.querySelectorAll()` and filter the results as needed.

## Example

```typescript
import { customElement, children, ILifecycleHooks, LifecycleHooks } from 'aurelia';

// Assume $all is imported or defined if used directly
const $all = '$all';

@customElement({ /* ... */ })
@LifecycleHooks() // Needed for manual query in attached
export class MyListComponent implements ILifecycleHooks {

  // Correct: Select all children
  @children({ query: $all })
  allChildren: Element[];

  // Correct: Select children matching 'list-item.active'
  @children({ query: 'list-item.active' })
  activeItems: Element[];

  // Correct: Select children with class '.highlight' (element tag implicitly *)
  @children('.highlight')
  highlightedItems: Element[];

  // Incorrect: Contains space/combinator
  // @children('div .item')
  // invalidItems1: Element[];

  // Incorrect: Contains ID selector
  // @children('#main-item')
  // invalidItems2: Element[];

  // Incorrect: Contains attribute selector
  // @children('[data-id]')
  // invalidItems3: Element[];

  // Incorrect: Contains pseudo-class
  // @children(':nth-child(odd)')
  // invalidItems4: Element[];

  // Incorrect: No class name provided (and not $all)
  // @children('button')
  // invalidItems5: Element[];

  complexItems: Element[] = [];

  constructor(private readonly $host: HTMLElement) {}

  // Solution for complex queries: Manual query
  attached() {
    this.complexItems = Array.from(this.$host.querySelectorAll('div > .item[data-value="special"]:not(.disabled)'));
    console.log('Found complex items:', this.complexItems);
  }
}
```

## Debugging Tips

* Carefully examine the selector string passed to `@children`.
* Remove any characters or syntax elements other than letters, numbers, dots (`.`) for classes, and the initial optional `$`.
* Ensure the selector includes at least one class name if it's not `$all`.
* Test the selector against the regex `/^(?:[$a-z](?:[$a-z0-9]*))(?:\.(?:[$a-z0-9]+))+$/i` or simplify it to meet the requirements.
* If complex selection is necessary, switch to manual querying using `this.$host.querySelectorAll()` in appropriate lifecycle hooks.
