@atcute/lex-cli
v2.5.2
Published
cli tool to generate type definitions for atcute
Readme
@atcute/lex-cli
generate TypeScript schemas from lexicon documents.
npm install @atcute/lex-cliquick start
create a configuration file that instructs the tool on where to locate the lexicon documents and where it should put the generated TypeScript schemas:
// file: lex.config.js
import { defineLexiconConfig } from '@atcute/lex-cli';
export default defineLexiconConfig({
files: ['lexicons/**/*.json'],
outdir: 'src/lexicons/',
});then run the tool (it automatically finds lex.config.js or lex.config.ts):
npm exec lex-cli generateauthoring lexicons with TypeScript
instead of writing lexicons as JSON documents, you can author them programmatically using the
builder functions from @atcute/lexicon-doc/builder.
// file: lexicons-src/com/example/bookmark.ts
import { array, document, object, record, required, string } from '@atcute/lexicon-doc/builder';
export default document({
id: 'com.example.bookmark',
defs: {
main: record({
key: 'tid',
description: 'a saved link to come back to later',
record: object({
properties: {
subject: required(string({ format: 'uri' })),
createdAt: required(string({ format: 'datetime' })),
tags: array({ items: string(), description: 'tags for organizing bookmarks' }),
},
}),
}),
},
});update your config to point to TypeScript files:
// file: lex.config.js
import { defineLexiconConfig } from '@atcute/lex-cli';
export default defineLexiconConfig({
files: ['lexicons-src/**/*.ts'],
outdir: 'src/lexicons/',
});exporting lexicons to JSON
if you need the actual JSON lexicon documents (e.g., for publishing or sharing), configure the export command:
export default defineLexiconConfig({
files: ['lexicons-src/**/*.ts'],
outdir: 'src/lexicons/',
export: {
outdir: 'lexicons/',
clean: true,
},
});then run:
npm exec lex-cli exportpulling lexicons
you can pull lexicon files from other sources.
git sources
pull lexicons from git repositories using sparse checkout:
// file: lex.config.js
import { defineLexiconConfig } from '@atcute/lex-cli';
export default defineLexiconConfig({
files: ['lexicons/**/*.json'],
outdir: 'src/lexicons/',
pull: {
outdir: 'lexicons/',
clean: true,
sources: [
{
type: 'git',
remote: 'https://github.com/bluesky-social/atproto.git',
ref: 'main',
pattern: ['lexicons/**/*.json'],
},
],
},
});atproto sources
pull lexicons directly from the AT Protocol network.
export default defineLexiconConfig({
files: ['lexicons/**/*.json'],
outdir: 'src/lexicons/',
pull: {
outdir: 'lexicons/',
sources: [
{
type: 'atproto',
mode: 'nsids',
nsids: ['app.bsky.feed.post', 'app.bsky.actor.profile'],
},
{
type: 'atproto',
mode: 'authority',
authority: 'atproto-lexicons.bsky.social',
pattern: ['com.atproto.*'], // optional
},
],
},
});running the pull command
pull the lexicons to disk, then generate types from them:
npm exec lex-cli pull
npm exec lex-cli generatepublishing your schemas
if you're packaging your generated schemas as a publishable library, add the atcute:lexicons field
to your package.json. this allows other projects to automatically discover and import your schemas
without manual configuration.
{
"name": "@example/my-schemas",
"atcute:lexicons": {
"mappings": {
"com.example.*": {
"type": "namespace",
"path": "./types/{{nsid_remainder}}"
}
}
}
}the path field supports several template expansions:
.or./at the start is replaced with the package name (e.g.,./types/foobecomes@example/my-schemas/types/foo, or.becomes@example/my-schemas){{nsid}}- the full NSID with dots replaced by slashes (e.g.,com/example/foo/bar){{nsid_prefix}}- the part before the wildcard (e.g.,com/example){{nsid_remainder}}- the part after the prefix (e.g.,foo/bar)
external references
when your lexicons reference types from namespaces outside your configured files, you'll need to configure how these references are resolved.
for example, if your lexicon references a type from another namespace:
// file: lexdocs/tools/ozone/team/defs.json
{
"lexicon": 1,
"id": "tools.ozone.team.defs",
"defs": {
"member": {
"type": "object",
"required": ["did", "role"],
"properties": {
"profile": {
"type": "ref",
"ref": "app.bsky.actor.defs#profileViewDetailed",
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// not covered by any of our included files
},
},
},
},
}the simplest way to resolve external references is using the imports array with packages that
provide the atcute:lexicons metadata:
// file: lex.config.js
import { defineLexiconConfig } from '@atcute/lex-cli';
export default defineLexiconConfig({
files: ['lexicons/**/*.json'],
outdir: 'src/lexicons/',
imports: ['@atcute/atproto', '@atcute/bluesky'],
});the CLI will automatically discover the namespace mappings from each package's atcute:lexicons
field in their package.json.
for packages without metadata, or when you need more fine-grained control over import resolution,
use the mappings configuration instead:
// file: lex.config.js
import { defineLexiconConfig } from '@atcute/lex-cli';
export default defineLexiconConfig({
files: ['lexicons/**/*.json'],
outdir: 'src/lexicons/',
mappings: [
{
nsid: ['com.atproto.*'],
imports: (nsid) => {
const specifier = nsid.slice('com.atproto.'.length).replaceAll('.', '/');
return { type: 'namespace', from: `@atcute/atproto/types/${specifier}` };
},
},
{
nsid: ['app.bsky.*'],
imports: (nsid) => {
const specifier = nsid.slice('app.bsky.'.length).replaceAll('.', '/');
return { type: 'namespace', from: `@atcute/bluesky/types/app/${specifier}` };
},
},
],
});