# Transform

Rewrite one module's authoring calls and emit its matching CSS and source maps.

`Transform.compile` extracts a module with [`Source.extract`](/docs/api/compiler/namespaces/Source), compiles its CSS, and replaces each definition with its compiled props. Replaced imports from `zyzz` and `zyzz/web` give way to small `zyzz/runtime` helpers, except `defineConfig`, `defineVars`, and `extendVars`, which stay imported. Unrelated imports stay as written, and the module never creates CSS rules.

```ts title="transform.ts"
import { Transform } from 'zyzz/compiler'

// Rewrites the module and returns the stylesheet beside it
const output = Transform.compile({
  moduleId: 'app/Card.tsx',
  source: `import { style } from 'zyzz'

export const card = style({ padding: '1rem' })
`,
})
```

## Signature

```ts
// Rewritten code, CSS, and maps for one module
Transform.compile(options)
```

## Parameters

### options.moduleId

* **Type:** `string`

A stable, package-relative module identity. Contextual class names include a six-character hash of it, and both source maps name it as their source.

```ts Card.tsx'/
// Keep the ID stable so class names stay stable
Transform.compile({ moduleId: 'app/Card.tsx', source })
```

### options.source

* **Type:** `string`

The complete module text, parsed as TypeScript with JSX. Lowering TypeScript and JSX in the returned `code` is left to the consuming build.

```ts
// The text is parsed, never executed
Transform.compile({ moduleId: 'app/Card.tsx', source: text })
```

### options.compiler

* **Type:** `boolean`
* **Default:** `true`

Whether to rewrite authoring calls. With `false`, `code` is the unchanged source and `css` matches the classes that runtime `style` calls compute. Each dynamic style, variant, composition, empty style, config, variable set, `variable` declaration, named stylesheet declaration, and selector reference then needs an explicit ID, or the call throws.

```ts
// Emits CSS while the calls run unchanged
Transform.compile({ compiler: false, moduleId: 'app/Card.tsx', source })
```

### options.target

* **Type:** `'web' | 'native'`
* **Default:** `'web'`

Inherited from [`Source.extract`](/docs/api/compiler/namespaces/Source#optionstarget). Only `'web'` is supported, and `'native'` throws a plain `Error` that points to [`Native.compile`](/docs/api/compiler/namespaces/Native).

```ts
// Throws: Use Native.compile for native source output.
Transform.compile({ moduleId: 'app/Card.tsx', source, target: 'native' })
```

### options.cssOutput

* **Type:** `'atomic' | 'grouped'`
* **Default:** `'atomic'`

The CSS shape for definitions without their own config setting. Atomic output emits one rule per declaration. Grouped output emits one block per style. [CSS Output](/docs/guides/css-output) compares both.

```ts
// Emits .z-ZYrHvJ-card{color:red;padding:0;}
Transform.compile({ cssOutput: 'grouped', moduleId: 'app/Card.tsx', source })
```

### options.composition

* **Type:** `'ordered' | 'independent'`
* **Default:** `'ordered'`

How class lists combine. Ordered output keeps authored precedence when applications are combined, so a later style that repeats an overridden declaration gets its own rule. Independent output reuses the first rule, and its class lists must not be combined.

```ts
import { Transform } from 'zyzz/compiler'

const output = Transform.compile({
  // `c` reuses the rule of `a` instead of emitting its own
  composition: 'independent',
  moduleId: 'app/Text.tsx',
  source: `import { style } from 'zyzz'

export const a = style({ color: 'red' })

export const b = style({ color: 'blue' })

export const c = style({ color: 'red' })
`,
})
```

### options.development

* **Type:** `boolean`
* **Default:** `false`

Keeps every definition live for development updates, including ones the module does not reach. Bundler plugins set this in development. Class names follow production rules, except that `composition: 'independent'` gives each repeated declaration its own class and rule.

```ts
// Retains unreached definitions for hot updates
Transform.compile({ development: true, moduleId: 'app/Card.tsx', source })
```

### options.schemes

* **Type:** `boolean`
* **Default:** `undefined`

Whether to emit the `color-scheme` classes (`.z_scheme-light`, `.z_scheme-dark`, and `.z_scheme-light-dark`). When omitted, they are emitted for modules that use a config's `appearance`, `script`, or `vars` selection.

```ts
// Adds the three color-scheme classes to css
Transform.compile({ moduleId: 'app/Card.tsx', schemes: true, source })
```

## Returns

### code

* **Type:** `string`

The rewritten module. A static style becomes a `Props` helper call with its compiled class list, and a direct application inlines its props. Variants, dynamic styles, and variable sets use their own `zyzz/runtime` helpers.

```ts
// Output for the overview example
import { Props as __zyzzProps } from 'zyzz/runtime'

export const card = __zyzzProps.create({
  className: 'z-p-1rem z-style-FdvK6e-card',
})
```

### css

* **Type:** `string`

The module's stylesheet, in authored order and compact form. Load it with the rewritten module.



```css
/* Output for the overview example */
.z-p-1rem{padding:1rem;}
```

### classes

* **Type:** `Readonly<Record<string, string>>`

The compiled class list of each definition, keyed by its name in [`Source.extract`](/docs/api/compiler/namespaces/Source#styles) styles.

```ts
// { 'style-…': 'z-p-1rem z-style-FdvK6e-card' }
output.classes
```

### vars

* **Type:** `Readonly<Record<string, string>>`

The scope class of each local variable set, keyed by its scope key. It is empty for a module without variable sets.

```ts
// { 'src-Card-…-style-theme': 'z-theme-theme' } for a local defineConfig
output.vars
```

### map

* **Type:** `EncodedSourceMap`

A version 3 source map from `code` to the original source, with the source content included.

```ts
// Writes the map beside the module
await Fs.writeFile('Card.js.map', JSON.stringify(output.map))
```

### cssMap

* **Type:** `EncodedSourceMap`

A version 3 source map from `css` to the authored selectors and declarations.

```ts
// Writes the map beside the stylesheet
await Fs.writeFile('Card.css.map', JSON.stringify(output.cssMap))
```

## Types

* **`Transform.compile.ErrorType`:** The errors `compile` throws.
* **`Transform.compile.Options`:** The accepted options.
* **`Transform.compile.ReturnType`:** The rewritten module, CSS, and maps.

```ts title="build.ts"
import { Transform } from 'zyzz/compiler'

// Compiles one module with options shared across a build
export function build(options: Transform.compile.Options) {
  return Transform.compile({ cssOutput: 'grouped', ...options })
}
```

An unsupported option value fails the type check.

```ts
import { Transform } from 'zyzz/compiler'

declare const source: string

Transform.compile({ cssOutput: 'nested', moduleId: 'app/Card.tsx', source })
// error: Type '"nested"' is not assignable to type '"atomic" | "grouped" | undefined'.
```

## Errors

`Transform.compile` returns no partial output. It throws `Source.ExtractError` for source outside the [static input](/docs/api/compiler/namespaces/Source#static-input) and for relative `url()` or `@import` assets, which need [`Graph.compile`](/docs/api/compiler/namespaces/Graph#outputsharedassets). It throws `Css.CompileError` when the CSS cannot compile.

It also throws a plain `Error` for `target: 'native'`, which belongs to `Native.compile`, and under `compiler: false` for definitions that need an explicit ID. `Transform.compile.ErrorType` does not include these.

```ts
import { Source, Transform } from 'zyzz/compiler'
import { Css } from 'zyzz/web'

try {
  Transform.compile({
    // Only atomic and grouped output exist
    cssOutput: 'nested' as never,
    moduleId: 'app/Card.tsx',
    source: `import { style } from 'zyzz'
export const card = style({ color: 'red' })
`,
  })
} catch (error) {
  if (error instanceof Source.ExtractError) console.error(error.diagnostics)
  if (error instanceof Css.CompileError) console.error(error.diagnostics)
}
```
