Skip to content

Configuration ​

Config File ​

Create an atscript.config.js (or .ts) in your project root:

javascript
import { defineConfig } from '@atscript/core'
import ts from '@atscript/typescript'

export default defineConfig({
  rootDir: 'src',
  format: 'dts',
  plugins: [ts()],
})

Options ​

OptionTypeDefaultDescription
rootDirstringConfig file's directoryDirectory containing your .as files
includestring[]['**/*.as']Glob patterns for .as files to compile. Exclude test-fixture directories (**/test/**, **/__test__/**, **/__tests__/**) — see Testing Fixtures for the dedicated fixture-compilation helper
excludestring[]['node_modules']Glob patterns to ignore
formatstringPlugin-dependentDefault output format for CLI. The TypeScript plugin supports 'dts' (type declarations) and 'js' (runtime code); defaults to dts when omitted
unknownAnnotation'error' | 'warn' | 'allow''error'How to handle annotations not defined in config
pluginsTAtscriptPlugin[][]Active plugins
annotationsobject—Custom annotation definitions (see Custom Annotations)
models() => unknown | Promise<unknown>—Extra Atscript models for asc db sync, on top of the compiled .as files (since 0.1.90)

models ​

asc db sync builds its table inventory from your compiled .as files. Models that ship inside a package are not on disk in your project, so declare them here — otherwise the CLI plans against a smaller set than your runtime uses and proposes dropping the tables it cannot see.

typescript
export default defineConfig({
  plugins: [ts()],
  db: { adapter: '@atscript/db-sqlite', connection: './myapp.db' },
  // a module namespace…
  models: () => import('some-package/models'),
  // …an array, or any nesting of the two
  // models: () => [PackagedOrder, PackagedInvoice],
})

Every export the callback exposes that is an annotated type carrying @db.table or @db.view is added to the inventory, deduplicated by identity. It is declared at the top level, so it works with both the declarative and the function form of db. Used only by asc db sync — it has no effect on codegen.

Plugin Options ​

The TypeScript plugin accepts options via ts({ ... }):

javascript
plugins: [ts({ jsonSchema: 'lazy' })]

jsonSchema ​

Controls how JSON Schema support is handled in generated code. On the frontend, pulling in the buildJsonSchema function adds unnecessary weight when you don't need it — so Atscript lets you choose the right trade-off for your use case.

ValueImport addedtoJsonSchema() behavior
false (default)NoneThrows a runtime error
'lazy'buildJsonSchema importedComputed on first call, cached until the next metadata write
'bundle'bundledSchemaOf (with buildJsonSchema as its fallback)Pre-computed at build time, embedded as static JSON (built at runtime instead when the loaded annotate blocks differ, see below)
javascript
// Default — no JSON schema overhead (best for frontend)
plugins: [ts()]

// Backend — lazy compute on demand
plugins: [ts({ jsonSchema: 'lazy' })]

// Backend — pre-compute at build time for fastest runtime
plugins: [ts({ jsonSchema: 'bundle' })]

A pre-computed schema is the one buildJsonSchema() returns for the types as the build saw them: with the mutating annotate blocks of the module, of the modules it imports, and of the other modules of the build annotating its types, in their fixed order. toJsonSchema() returns it while the modules whose blocks have applied are exactly the ones the build accounted for. Otherwise (a block's module is not loaded, or one the build did not see is) it builds the schema from the runtime types with buildJsonSchema(). This is why a bundle of 'bundle' modules includes buildJsonSchema.

A schema embedded at build time does not see changes made at runtime with metadata.set() or annotate(); 'lazy' schemas are rebuilt after them. Call buildJsonSchema(type) for a schema of the type as it is now.

Individual interfaces can also opt into build-time embedding via the @emit.jsonSchema annotation, regardless of the global setting. See JSON Schema for full usage details, annotation constraints, and examples.

jsonSchemaOptions ​

The buildJsonSchema options the generated toJsonSchema() uses, in every mode ('lazy', 'bundle' and @emit.jsonSchema). toJsonSchema() returns the same schema as buildJsonSchema(type, jsonSchemaOptions).

javascript
// Closed schemas: reject keys the type does not declare
plugins: [ts({ jsonSchema: 'bundle', jsonSchemaOptions: { closed: true } })]
OptionDefaultEffect
closedfalseadditionalProperties: false on every object
annotationstrue@meta.description → description, @meta.label → title
enumstrueA union of literals → enum

The strict option (LLM tool schemas) is not a plugin option: pass it to buildJsonSchema() at runtime. See Strict LLM tool schemas.

exampleData ​

Controls whether generated types include a toExampleData() static method. When enabled, each generated class gets a method that creates example data using @meta.example annotations.

ValuetoExampleData() behavior
false (default)Not rendered in .js; .d.ts marks it as optional + @deprecated
trueCalls createDataFromAnnotatedType(this, { mode: 'example' })
javascript
// Default — no example data method
plugins: [ts()]

// Enable — each type gets toExampleData()
plugins: [ts({ exampleData: true })]

Unlike toJsonSchema, there is no caching — toExampleData() creates a new data object on each call. This is intentional since it acts as a factory function.

Manual use is always available

Even with exampleData: false, you can import createDataFromAnnotatedType from @atscript/typescript/utils and call it directly. The config option only affects the generated .toExampleData() method.

typescript
import { createDataFromAnnotatedType } from '@atscript/typescript/utils'
import { Product } from './product.as'

const example = createDataFromAnnotatedType(Product, { mode: 'example' })

moduleExtension ​

Controls the extension the generated .js uses for relative .as imports (since 0.1.91). Bare specifiers (packages, e.g. some-pkg/models/user.as) always keep .as — they resolve through the package's exports map. The .d.ts output is not affected.

Valueimport { B } from "./b" renders as
'.as' (default)from "./b.as"
'.as.js'from "./b.as.js"
'.as.mjs'from "./b.as.mjs"
javascript
// Default — bundler / asc-emitted `.as.js` next to the source
plugins: [ts()]

// Load the generated modules straight from Node without a bundler
plugins: [ts({ moduleExtension: '.as.mjs' })]

asc db sync compiles with '.as.mjs' so the models it loads resolve directly in Node.

compileValidators ​

Emits a build-time compiled validator check for each type into the generated .js. validate() uses it automatically, and results stay the same as without it.

ValueGenerated .js
false (default)Interpreted at runtime, except types annotated with @emit.compiledValidator
trueAdds a compiled check per type: faster validation of valid input, more code per module
javascript
// Backend build: faster request validation
plugins: [ts({ compileValidators: true })]

Keep it off for frontend bundles. While it is off, individual types can still opt in with the @emit.compiledValidator annotation. unplugin-atscript can override it per build, for example to compile only the SSR build of a Vite app. See Compiled Validators for the per-type opt-in, when checks stay interpreted and how to change types at runtime safely.

The atscript.d.ts File ​

When you run asc -f dts, an atscript.d.ts file is generated alongside your output. It declares the global AtscriptMetadata interface and AtscriptPrimitiveTags type — these provide TypeScript IntelliSense for all annotations and semantic type tags used in your project.

Add it to your tsconfig.json:

json
{
  "include": ["src/**/*", "atscript.d.ts"]
}

Re-generate after config changes

Run npx asc -f dts whenever you change your atscript.config — for example, after adding plugins, custom annotations, or new primitives. This regenerates atscript.d.ts so that your IDE picks up the updated annotation types and semantic tags. Without this step, you may see incorrect IntelliSense or missing type information when working with .metadata and .type.tags.

Next Steps ​

Released under the MIT License.