Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add config option to enable location tracking in prisma-ast #25

Merged
merged 8 commits into from
Jul 19, 2023
137 changes: 90 additions & 47 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,21 @@ produceSchema(source: string, (builder: PrismaSchemaBuilder) => void, printOptio
produceSchema is the simplest way to interact with prisma-ast; you input your schema source and a producer function to produce modifications to it, and it will output the schema source with your modifications applied.

```ts
import { produceSchema } from '@mrleebo/prisma-ast'
import { produceSchema } from '@mrleebo/prisma-ast';

const input = `
model User {
id Int @id @default(autoincrement())
name String @unique
}
`
`;

const output = produceSchema(source, (builder) => {
builder
.model("AppSetting")
.model('AppSetting')
.field('key', 'String', [{ name: 'id' }])
.field('value', 'Json')
})
.field('value', 'Json');
});
```

```prisma
Expand All @@ -59,21 +59,22 @@ For more information about what the builder can do, check out the [PrismaSchemaB
The `produceSchema()` utility will construct a builder for you, but you can also create your own instance, which may be useful for more interactive use-cases.

```ts
import { createPrismaSchemaBuilder } from '@mrleebo/prisma-ast'
import { createPrismaSchemaBuilder } from '@mrleebo/prisma-ast';

const builder = createPrismaSchemaBuilder()
const builder = createPrismaSchemaBuilder();

builder.model('User')
builder
.model('User')
.field('id', 'Int')
.attribute('id')
.attribute('default', [{ name: 'autoincrement' }])
.field('name', 'String')
.attribute('unique')
.break()
.comment("this is a comment")
.blockAttribute('index', ['name'])
.comment('this is a comment')
.blockAttribute('index', ['name']);

const output = builder.print()
const output = builder.print();
```

```prisma
Expand All @@ -91,7 +92,7 @@ model User {
prisma-ast can sort the schema for you. The default sort order is `['generator', 'datasource', 'model', 'enum']` and will sort objects of the same type alphabetically.

```ts
print(options?: {
print(options?: {
sort: boolean,
locales?: string | string[],
sortOrder?: Array<'generator' | 'datasource' | 'model' | 'enum'>
Expand All @@ -102,11 +103,13 @@ You can optionally set your own sort order, or change the locale used by the sor

```ts
// sort with default parameters
builder.print({ sort: true })
builder.print({ sort: true });

// sort with options
builder.print({
sort: true, locales: 'en-US', sortOrder: ['datasource', 'generator', 'model', 'enum']
builder.print({
sort: true,
locales: 'en-US',
sortOrder: ['datasource', 'generator', 'model', 'enum'],
});
```

Expand All @@ -121,7 +124,7 @@ datasource(provider: string, url: string | { env: string })
You can set a datasource by passing in the provider and url parameters.

```ts
builder.datasource('postgresql', { env: 'DATABASE_URL' })
builder.datasource('postgresql', { env: 'DATABASE_URL' });
```

```prisma
Expand All @@ -136,12 +139,14 @@ datasource db {
If you want to perform a custom action that there isn't a Builder method for, you can access the underlying schema object programmatically.

```ts
import { Datasource } from '@mrleebo/prisma-ast'
import { Datasource } from '@mrleebo/prisma-ast';

// rename the datasource programmatically
builder.datasource('postgresql', { env: 'DATABASE_URL' }).then<Datasource>((datasource) => {
datasource.name = "DS"
})
builder
.datasource('postgresql', { env: 'DATABASE_URL' })
.then<Datasource>((datasource) => {
datasource.name = 'DS';
});
```

```prisma
Expand All @@ -160,7 +165,7 @@ generator(name: string, provider: string)
If the schema already has a generator with the given name, it will be updated. Otherwise, a new generator will be created.

```ts
builder.generator('nexusPrisma', 'nexus-prisma')
builder.generator('nexusPrisma', 'nexus-prisma');
```

```prisma
Expand All @@ -178,7 +183,7 @@ assignment(key: string, value: string)
If your generator accepts additional assignments, they can be added by chaining .assignment() calls to your generator.

```ts
builder.generator('client', 'prisma-client-js').assignment('output', 'db.js')
builder.generator('client', 'prisma-client-js').assignment('output', 'db.js');
```

```prisma
Expand All @@ -200,12 +205,12 @@ generator client {
```

```ts
import { Generator } from '@mrleebo/prisma-ast'
import { Generator } from '@mrleebo/prisma-ast';

// rename the generator programmatically
builder.generator('client').then<Generator>((generator) => {
generator.name = "foo"
})
generator.name = 'foo';
});
```

```prisma
Expand All @@ -220,7 +225,7 @@ generator foo {
If the model with that name already exists in the schema, it will be selected and any fields that follow will be appended to the model. Otherwise, the model will be created and added to the schema.

```ts
builder.model('Project').field('name', 'String')
builder.model('Project').field('name', 'String');
```

```prisma
Expand All @@ -240,12 +245,12 @@ model Project {
```

```ts
import { Model } from '@mrleebo/prisma-ast'
import { Model } from '@mrleebo/prisma-ast';

// rename the datasource programmatically
builder.model('Project').then<Model>((model) => {
model.name = "Task"
})
model.name = 'Task';
});
```

```prisma
Expand All @@ -254,7 +259,6 @@ model Task {
}
```


### Add a field with an attribute to a model

If the entered model name already exists, that model will be used as the subject for any field and attribute calls that follow.
Expand All @@ -266,7 +270,7 @@ model Project {
```

```ts
builder.model('Project').field('projectCode', 'String').attribute('unique')
builder.model('Project').field('projectCode', 'String').attribute('unique');
```

```prisma
Expand All @@ -288,7 +292,7 @@ model Project {
```

```ts
builder.model('Project').field('name').attribute('unique')
builder.model('Project').field('name').attribute('unique');
```

```prisma
Expand All @@ -310,7 +314,7 @@ model Project {
```

```ts
builder.model('Project').removeField('projectCode')
builder.model('Project').removeField('projectCode');
```

```prisma
Expand All @@ -331,7 +335,7 @@ model Project {
```

```ts
builder.model('Project').field('projectCode').removeAttribute('unique')
builder.model('Project').field('projectCode').removeAttribute('unique');
```

```prisma
Expand All @@ -352,13 +356,13 @@ model TaskMessage {
```

```ts
import { Field, Attribute } from '@mrleebo/prisma-ast'
import { Field, Attribute } from '@mrleebo/prisma-ast';

// Replace the @db.Timestamptz(6) attribute with @default(now())
builder
.model('TaskMessage')
.field('createdAt')
.then<Field>(field => {
.then<Field>((field) => {
const attribute: Attribute = {
type: 'attribute',
kind: 'field',
Expand All @@ -385,7 +389,7 @@ model Project {
```

```ts
builder.model('Project').blockAttribute('index', ['name'])
builder.model('Project').blockAttribute('index', ['name']);
```

```prisma
Expand All @@ -399,7 +403,7 @@ model Project {
### Add an enum

```ts
builder.enum('Role', ['USER', 'ADMIN'])
builder.enum('Role', ['USER', 'ADMIN']);
```

```prisma
Expand All @@ -412,7 +416,11 @@ enum Role {
Additional enumerators can also be added to an existing Enum

```ts
builder.enum('Role').break().comment("New role added for feature #12").enumerator('ORGANIZATION')
builder
.enum('Role')
.break()
.comment('New role added for feature #12')
.enumerator('ORGANIZATION');
```

```prisma
Expand All @@ -429,9 +437,9 @@ enum Role {

```ts
builder
.model("Project")
.model('Project')
.break()
.comment("I wish I could add a color to your rainbow")
.comment('I wish I could add a color to your rainbow');
```

```prisma
Expand All @@ -444,6 +452,37 @@ model Project {
}
```

## Configuration Options

prisma-ast uses [lilconfig](https://github.com/antonk52/lilconfig) to read configuration options which
can be located in any of the following files, and in several other variations (see [the complete list of search paths](https://www.npmjs.com/package/cosmiconfig)):

- `"prisma-ast"` in `package.json`
- `.prisma-astrc`
- `.prisma-astrc.json`
- `.prisma-astrc.js`
- `.config/.prisma-astrc`

Configuration options are:

| Option | Description | Default Value |
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `parser.nodeTrackingLocation` | Include the token locations of CST Nodes in the output schema.<br>Disabled by default because it can impact parsing performance.<br>Possible values are `"none"`, `"onlyOffset"`, and `"full"`. | `"none"` |

### Example Custom Configuration

Here is an example of how you can customize your configuration options in `package.json`.

```json
{
"prisma-ast": {
"parser": {
"nodeTrackingLocation": "full"
}
}
}
```

## Underlying utility functions

The `produceSchema` and `createPrismaSchemaBuilder` functions are intended to be your interface for interacting with the prisma schema, but you can also get direct access to the AST representation if you need to edit the schema for more advanced usages that aren't covered by the methods above.
Expand All @@ -453,30 +492,34 @@ The `produceSchema` and `createPrismaSchemaBuilder` functions are intended to be
The shape of the AST is not fully documented, and it is more likely to change than the builder API.

```ts
import { getSchema } from '@mrleebo/prisma-ast'
import { getSchema } from '@mrleebo/prisma-ast';

const source = `
model User {
id Int @id @default(autoincrement())
name String @unique
}
`
`;

const schema = getSchema(source)
const schema = getSchema(source);
```

### Print a schema AST back out as a string

This is what `builder.print()` calls internally, and is what you'd use to print if you called `getSchema()`.

```ts
import { printSchema } from '@mrleebo/prisma-ast'
import { printSchema } from '@mrleebo/prisma-ast';

const source = printSchema(schema)
const source = printSchema(schema);
```

You can optionally re-sort the schema. The default sort order is `['generator', 'datasource', 'model', 'enum']`, and objects with the same type are sorted alphabetically, but the sort order can be overridden.

```ts
const source = printSchema(schema, { sort: true, locales: "en-US", sortOrder: ["datasource", "generator", "model", "enum"] })
const source = printSchema(schema, {
sort: true,
locales: 'en-US',
sortOrder: ['datasource', 'generator', 'model', 'enum'],
});
```
13 changes: 9 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"files": [
"dist"
"dist",
"src"
],
"engines": {
"node": ">=16"
Expand Down Expand Up @@ -45,18 +46,22 @@
}
],
"devDependencies": {
"@size-limit/preset-small-lib": "^4.10.2",
"@size-limit/preset-small-lib": "^8.2.6",
"@typescript-eslint/eslint-plugin": "^4.22.0",
"@typescript-eslint/parser": "^4.22.0",
"dts-cli": "^2.0.3",
"eslint": "^7.24.0",
"husky": "^6.0.0",
"size-limit": "^8.2.4",
"jest": "^29.6.0",
"prettier": "^2.8.8",
"size-limit": "^8.2.6",
"ts-jest": "^29.1.1",
"tslib": "^2.4.0",
"typescript": "^5.1.6"
},
"dependencies": {
"chevrotain": "^10.5.0"
"chevrotain": "^10.5.0",
"lilconfig": "^2.1.0"
},
"publishConfig": {
"access": "public"
Expand Down