introspeql 0.0.4 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +286 -85
- package/dist/comments/comment-converter.d.ts +54 -0
- package/dist/comments/comment-converter.js +185 -0
- package/dist/comments/index.d.ts +2 -0
- package/dist/comments/index.js +18 -0
- package/dist/comments/prettify-comment.d.ts +1 -0
- package/dist/comments/prettify-comment.js +18 -0
- package/dist/config/connection-options.d.ts +14 -0
- package/dist/config/connection-options.js +42 -0
- package/dist/config/default-type-mappings.d.ts +13 -0
- package/dist/config/default-type-mappings.js +16 -0
- package/dist/config/entity-data.d.ts +6 -0
- package/dist/config/entity-data.js +8 -0
- package/dist/config/function-options.d.ts +23 -0
- package/dist/config/function-options.js +74 -0
- package/dist/config/general-options.d.ts +7 -0
- package/dist/config/general-options.js +75 -0
- package/dist/config/index.d.ts +71 -0
- package/dist/config/index.js +29 -0
- package/dist/config/output-options.d.ts +8 -0
- package/dist/config/output-options.js +40 -0
- package/dist/config/table-options.d.ts +21 -0
- package/dist/config/table-options.js +48 -0
- package/dist/enums/enum-data.d.ts +9 -0
- package/dist/enums/enum-data.js +11 -0
- package/dist/enums/enum-definition.d.ts +7 -0
- package/dist/enums/enum-definition.js +24 -0
- package/dist/enums/index.d.ts +4 -0
- package/dist/enums/index.js +20 -0
- package/dist/enums/is-enum-replaced-with-custom-type.d.ts +3 -0
- package/dist/enums/is-enum-replaced-with-custom-type.js +9 -0
- package/dist/enums/read-enum-data.d.ts +3 -0
- package/dist/enums/read-enum-data.js +57 -0
- package/dist/functions/function-data.d.ts +26 -0
- package/dist/functions/function-data.js +27 -0
- package/dist/functions/function-definition.d.ts +7 -0
- package/dist/functions/function-definition.js +21 -0
- package/dist/functions/index.d.ts +9 -0
- package/dist/functions/index.js +25 -0
- package/dist/functions/overload-type-definition.d.ts +8 -0
- package/dist/functions/overload-type-definition.js +21 -0
- package/dist/functions/parameter-type-definition-builder.d.ts +16 -0
- package/dist/functions/parameter-type-definition-builder.js +41 -0
- package/dist/functions/parameter-type-definition.d.ts +9 -0
- package/dist/functions/parameter-type-definition.js +28 -0
- package/dist/functions/read-function-data.d.ts +4 -0
- package/dist/functions/read-function-data.js +93 -0
- package/dist/functions/return-type-definition.d.ts +7 -0
- package/dist/functions/return-type-definition.js +20 -0
- package/dist/functions/should-include-function.d.ts +2 -0
- package/dist/functions/should-include-function.js +6 -0
- package/dist/functions/should-include-overload.d.ts +2 -0
- package/dist/functions/should-include-overload.js +23 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +7 -1
- package/dist/introspeql.d.ts +7 -0
- package/dist/introspeql.js +161 -0
- package/dist/schemas/index.d.ts +3 -0
- package/dist/schemas/index.js +19 -0
- package/dist/schemas/read-schema-data.d.ts +15 -0
- package/dist/schemas/read-schema-data.js +182 -0
- package/dist/schemas/schema-definition-factory.d.ts +15 -0
- package/dist/schemas/schema-definition-factory.js +167 -0
- package/dist/schemas/schema-definition.d.ts +11 -0
- package/dist/schemas/schema-definition.js +38 -0
- package/dist/shared/convert-pg-identifier-to-ts-identifier.d.ts +19 -0
- package/dist/shared/convert-pg-identifier-to-ts-identifier.js +57 -0
- package/dist/shared/directives.d.ts +12 -0
- package/dist/shared/directives.js +16 -0
- package/dist/shared/get-tokens.d.ts +1 -0
- package/dist/shared/get-tokens.js +7 -0
- package/dist/shared/indent.d.ts +1 -0
- package/dist/shared/indent.js +9 -0
- package/dist/shared/index.d.ts +5 -0
- package/dist/shared/index.js +21 -0
- package/dist/shared/parsing-error.d.ts +3 -0
- package/dist/shared/parsing-error.js +26 -0
- package/dist/tables/column-data.d.ts +14 -0
- package/dist/tables/column-data.js +16 -0
- package/dist/tables/column-definition.d.ts +8 -0
- package/dist/tables/column-definition.js +19 -0
- package/dist/tables/column-type-definition.d.ts +7 -0
- package/dist/tables/column-type-definition.js +19 -0
- package/dist/tables/index.d.ts +8 -0
- package/dist/tables/index.js +24 -0
- package/dist/tables/read-column-data.d.ts +3 -0
- package/dist/tables/read-column-data.js +55 -0
- package/dist/tables/read-table-data.d.ts +4 -0
- package/dist/tables/read-table-data.js +84 -0
- package/dist/tables/should-include-table.d.ts +10 -0
- package/dist/tables/should-include-table.js +24 -0
- package/dist/tables/table-data.d.ts +8 -0
- package/dist/tables/table-data.js +10 -0
- package/dist/tables/table-definition.d.ts +10 -0
- package/dist/tables/table-definition.js +43 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +17 -0
- package/dist/types/lookup-type.d.ts +15 -0
- package/dist/types/lookup-type.js +25 -0
- package/package.json +32 -17
- package/dist/append-schema.d.ts +0 -8
- package/dist/append-schema.js +0 -96
- package/dist/generate-types.d.ts +0 -8
- package/dist/generate-types.js +0 -110
- package/dist/introspect-columns.d.ts +0 -21
- package/dist/introspect-columns.js +0 -53
- package/dist/introspect-enum.d.ts +0 -20
- package/dist/introspect-enum.js +0 -24
- package/dist/introspect-procedures.d.ts +0 -53
- package/dist/introspect-procedures.js +0 -129
- package/dist/introspect-tables.d.ts +0 -19
- package/dist/introspect-tables.js +0 -43
- package/dist/introspeql-config.d.ts +0 -40
- package/dist/introspeql-config.js +0 -104
- package/dist/prepare-data-for-writing.d.ts +0 -38
- package/dist/prepare-data-for-writing.js +0 -145
- package/dist/snake-case-to-pascal-case.d.ts +0 -8
- package/dist/snake-case-to-pascal-case.js +0 -17
- package/dist/write-header.d.ts +0 -2
- package/dist/write-header.js +0 -10
package/README.md
CHANGED
|
@@ -1,113 +1,314 @@
|
|
|
1
1
|
# IntrospeQL
|
|
2
2
|
|
|
3
|
-
IntrospeQL
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
types easy, comprehensive, and accurate.
|
|
3
|
+
IntrospeQL reads information about the schemas, tables, columns, functions, and
|
|
4
|
+
enums in your PostgreSQL database and produces a TypeScript file detailing
|
|
5
|
+
type information for each database object.
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
> This library is currently in alpha. Use with caution; it is not yet hardened
|
|
10
|
-
> for production.
|
|
7
|
+
## Installation
|
|
11
8
|
|
|
12
|
-
|
|
9
|
+
Install IntrospeQL as a dev dependency:
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
```
|
|
12
|
+
npm install --save-dev introspeql
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
Install [tsx](https://tsx.is/) and [@types/node](https://www.npmjs.com/package/@types/node):
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
npm install --save-dev tsx @types/node
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Install [dotenv](https://www.npmjs.com/package/dotenv):
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
npm install --save dotenv
|
|
27
|
+
```
|
|
20
28
|
|
|
21
|
-
|
|
29
|
+
Add the following entry to the scripts object in package.json:
|
|
22
30
|
|
|
23
|
-
```
|
|
24
|
-
|
|
31
|
+
```
|
|
32
|
+
"gen-types": "npx tsx scripts/gen-types.ts"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Create a scripts directory at the root level of your project, and inside this
|
|
36
|
+
folder, create a new TypeScript file called `gen-types.ts`.
|
|
37
|
+
|
|
38
|
+
Add the following content to `scripts/gen-types.ts`:
|
|
39
|
+
|
|
40
|
+
```
|
|
25
41
|
import 'dotenv/config';
|
|
26
42
|
import path from 'node:path';
|
|
27
|
-
import {
|
|
43
|
+
import { introspeql, type IntrospeQLConfig } from 'introspeql';
|
|
44
|
+
|
|
45
|
+
const outFile = '/generated/type-definitions.ts';
|
|
28
46
|
|
|
29
47
|
const config: IntrospeQLConfig = {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
},
|
|
38
|
-
],
|
|
39
|
-
header:
|
|
40
|
-
`
|
|
41
|
-
// Custom header:
|
|
42
|
-
import type { Geography } from '../model/geography';
|
|
43
|
-
`
|
|
44
|
-
types: {
|
|
45
|
-
'public.geography': 'Geography'
|
|
48
|
+
schemas: ['public'], // Add other schemas as necessary
|
|
49
|
+
dbConnectionParams: {
|
|
50
|
+
host: process.env.DB_HOST,
|
|
51
|
+
port: +process.env.DB_PORT!,
|
|
52
|
+
database: process.env.DB_NAME,
|
|
53
|
+
user: process.env.DB_USER,
|
|
54
|
+
password: process.env.DB_PASSWORD,
|
|
46
55
|
},
|
|
56
|
+
writeToDisk: true,
|
|
57
|
+
outFile: path.join(__dirname, '..' + outFile),
|
|
58
|
+
header:
|
|
59
|
+
'/* This file has been generated by IntrospeQL and should not be edited directly. */',
|
|
60
|
+
types: {
|
|
61
|
+
'pg_catalog.void': 'void'
|
|
62
|
+
}
|
|
47
63
|
};
|
|
48
64
|
|
|
49
|
-
|
|
65
|
+
genTypes();
|
|
66
|
+
|
|
67
|
+
async function genTypes() {
|
|
68
|
+
await introspeql(config);
|
|
69
|
+
console.log("Type definition file created at " + outFile);
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Create a `.gitignore` file at the root of your project and make sure it includes
|
|
74
|
+
`node_modules` and `.env`:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
# .gitignore
|
|
78
|
+
node_modules/
|
|
79
|
+
.env
|
|
50
80
|
```
|
|
51
81
|
|
|
52
|
-
|
|
82
|
+
Create a `.env` file at the root of your project and add your database connection
|
|
83
|
+
information:
|
|
84
|
+
```
|
|
85
|
+
# .env
|
|
86
|
+
DB_HOST= # Add your host here, often just localhost
|
|
87
|
+
DB_PORT= # Add your port here
|
|
88
|
+
DB_NAME= # Add the name of the database you wish to connect to here
|
|
89
|
+
DB_USER= # Add the PostgreSQL username that should be used to connect to the db
|
|
90
|
+
DB_PASSWORD= # Add the password for this user here
|
|
91
|
+
```
|
|
53
92
|
|
|
54
|
-
|
|
55
|
-
// src/db/types.ts
|
|
93
|
+
Execute your script:
|
|
56
94
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
95
|
+
```
|
|
96
|
+
npm run gen-types
|
|
97
|
+
```
|
|
60
98
|
|
|
61
|
-
|
|
62
|
-
export const SchemaName = 'public';
|
|
99
|
+
A type definition file will have been generated at `generated/type-definitions.ts`.
|
|
63
100
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
MILES = 'MILES',
|
|
69
|
-
}
|
|
70
|
-
}
|
|
101
|
+
> ⚠️ **Important**
|
|
102
|
+
> Never hard code sensitive information directly into your project. Instead,
|
|
103
|
+
> load such information from environment variables and ensure that .env files
|
|
104
|
+
> are not committed to source control.
|
|
71
105
|
|
|
72
|
-
|
|
73
|
-
export namespace StoreLocations {
|
|
74
|
-
export const TableName = 'store_locations';
|
|
75
|
-
|
|
76
|
-
export enum ColumnNames {
|
|
77
|
-
Id = 'id',
|
|
78
|
-
Coordinates = 'coordinates',
|
|
79
|
-
StreetAddressLine1 = 'street_address_line_1',
|
|
80
|
-
StreetAddressLine2 = 'street_address_line_2',
|
|
81
|
-
City = 'city',
|
|
82
|
-
State = 'state',
|
|
83
|
-
ZipCode = 'zip_code',
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export interface RowType {
|
|
87
|
-
[ColumnNames.Id]: number;
|
|
88
|
-
[ColumnNames.Coordinates]: Geography;
|
|
89
|
-
[ColumnNames.StreetAddressLine1]: string;
|
|
90
|
-
[ColumnNames.StreetAddressLine2]: string | null;
|
|
91
|
-
[ColumnNames.City]: string;
|
|
92
|
-
[ColumnNames.State]: string;
|
|
93
|
-
[ColumnNames.ZipCode]: string;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
106
|
+
## Output
|
|
97
107
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
108
|
+
The type definitions file consists of nested
|
|
109
|
+
[namespaces](https://www.typescriptlang.org/docs/handbook/namespaces.html).
|
|
110
|
+
Each top-level namespace represents a schema and contains the name of the schema
|
|
111
|
+
as well as type definitions for its tables, functions, and enums, grouped by
|
|
112
|
+
category into nested namespaces. Each table and function, in turn, consists of a
|
|
113
|
+
namespace.
|
|
101
114
|
|
|
102
|
-
|
|
115
|
+
Table namespaces contain the name of the table, a union of string literals
|
|
116
|
+
representing the names of the columns of the table, and an object-type
|
|
117
|
+
representing the structure of each row.
|
|
103
118
|
|
|
104
|
-
|
|
119
|
+
Function namespaces contain the name of the function and an array of overloads.
|
|
120
|
+
Each overload contains an array of parameter types and (separately from the
|
|
121
|
+
array of parameter types) the return type.
|
|
122
|
+
|
|
123
|
+
Enums are represented as unions of string literals, with each string literal
|
|
124
|
+
representing one possible value of the enum.
|
|
125
|
+
|
|
126
|
+
A header can be added to the file. This is useful to import types that will be
|
|
127
|
+
used later in the file. In the example, we simply added a comment to the top of
|
|
128
|
+
the file indicating that the file was autogenerated and should not be changed
|
|
129
|
+
manually.
|
|
130
|
+
|
|
131
|
+
## Configuration
|
|
132
|
+
|
|
133
|
+
### Root-Level Configuration
|
|
134
|
+
|
|
135
|
+
The following options exist directly on the top-level configuration object.
|
|
136
|
+
|
|
137
|
+
| Option | Type | Required | Default | Description |
|
|
138
|
+
| -------------------- | ------------------------ | ----------- | ------------ | ----------------------------------------------------------------------------------------------- |
|
|
139
|
+
| `schemas` | `string[]` | No | `['public']` | PostgreSQL schemas to introspect. At least one schema must be specified. |
|
|
140
|
+
| `header` | `string` | No | — | Text inserted at the top of the generated output file (e.g., additional type imports or definitions). |
|
|
141
|
+
| `types` | `Record<string, string>` | No | — | Custom PostgreSQL-to-TypeScript type mappings that override built-in defaults. These should be specified in the format `<schema>.<type>`, e.g. `'pg_catalog.int8'` |
|
|
142
|
+
| `copyComments` | `boolean` | No | `true` | Whether database comments are copied into generated TypeScript documentation comments. |
|
|
143
|
+
| `dbConnectionString` | `string` | Conditional | — | PostgreSQL connection string. Exactly one of this or `dbConnectionParams` must be provided. |
|
|
144
|
+
| `dbConnectionParams` | `object` | Conditional | — | PostgreSQL connection parameters. Exactly one of this or `dbConnectionString` must be provided. |
|
|
145
|
+
| `writeToDisk` | `boolean` | Yes | — | Controls whether generated output is written to disk. |
|
|
146
|
+
| `outFile` | `string` | Conditional | — | Output file path. Required when `writeToDisk` is `true`. |
|
|
147
|
+
| `tables` | `TableOptions` | No | — | Table filtering configuration. |
|
|
148
|
+
| `functions` | `FunctionOptions` | No | — | Function filtering and typing configuration. |
|
|
149
|
+
|
|
150
|
+
#### `dbConnectionParams`
|
|
151
|
+
|
|
152
|
+
| Option | Type | Required | Description |
|
|
153
|
+
| ---------- | -------- | -------- | ------------------- |
|
|
154
|
+
| `user` | `string` | No | Database user name. |
|
|
155
|
+
| `password` | `string` | No | Database password. |
|
|
156
|
+
| `host` | `string` | No | Database host. |
|
|
157
|
+
| `port` | `number` | No | Database port. |
|
|
158
|
+
| `database` | `string` | No | Database name. |
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
### Table Options
|
|
163
|
+
|
|
164
|
+
Controls which database tables are included in the generated output.
|
|
165
|
+
|
|
166
|
+
| Option | Type | Required | Default | Description |
|
|
167
|
+
| --------------- | ---------------------------- | -------- | ------------- | --------------------------------------------------- |
|
|
168
|
+
| `mode` | `'inclusive' \| 'exclusive'` | No | `'inclusive'` | Determines how table filtering is applied. |
|
|
169
|
+
| `excludeTables` | `string[]` | No | `[]` | Tables to exclude when operating in inclusive mode. |
|
|
170
|
+
| `includeTables` | `string[]` | No | `[]` | Tables to include when operating in exclusive mode. |
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
### Function Options
|
|
175
|
+
|
|
176
|
+
Controls which PostgreSQL functions are included and how their types are generated.
|
|
177
|
+
|
|
178
|
+
| Option | Type | Required | Default | Description |
|
|
179
|
+
| --------------------- | ---------------------------- | -------- | ------------- | ----------------------------------------------------------- |
|
|
180
|
+
| `mode` | `'inclusive' \| 'exclusive'` | No | `'inclusive'` | Determines how function filtering is applied. |
|
|
181
|
+
| `excludeFunctions` | `string[]` | No | `[]` | Functions to exclude when operating in inclusive mode. |
|
|
182
|
+
| `includeFunctions` | `string[]` | No | `[]` | Functions to include when operating in exclusive mode. |
|
|
183
|
+
| `nullableArgs` | `boolean` | No | `false` | Treat function arguments as nullable in generated types. |
|
|
184
|
+
| `nullableReturnTypes` | `boolean` | No | `true` | Treat function return types as nullable in generated types. |
|
|
185
|
+
|
|
186
|
+
## Types
|
|
187
|
+
|
|
188
|
+
Default type mappings are based on the types produced by
|
|
189
|
+
[node-postgres](https://node-postgres.com/). These defaults can be added to or
|
|
190
|
+
overridden using configuration options described above. Type definitions for
|
|
191
|
+
enums will be generated automatically, provided that the enum is used somewhere
|
|
192
|
+
in a table or function definition.
|
|
193
|
+
|
|
194
|
+
To define custom types, use the header to import or define them and use the
|
|
195
|
+
`types` configuration option to map PostgreSQL types to your custom types.
|
|
196
|
+
|
|
197
|
+
Multi-dimensional-array-type columns are recognized. Columns to which a `NOT NULL`
|
|
198
|
+
constraint has been applied will be non-nullable. Optional and variadic function
|
|
199
|
+
parameters are recognized.
|
|
200
|
+
|
|
201
|
+
By default, node-postgres will transform the return value of a function that
|
|
202
|
+
returns void into an empty string. Therefore, by default, the generated
|
|
203
|
+
TypeScript return type of PostgreSQL functions that return void will be
|
|
204
|
+
`string`. If desired, this can be overridden using the `types` configuration
|
|
205
|
+
option.
|
|
206
|
+
|
|
207
|
+
The default value for unrecognized types is `string`.
|
|
208
|
+
|
|
209
|
+
## Functions
|
|
210
|
+
|
|
211
|
+
Only functions whose `prokind` is `'f'` in `pg_catalog.pg_proc` are recognized
|
|
212
|
+
(i.e. normal functions, not procedures or aggregate functions).
|
|
213
|
+
|
|
214
|
+
Function overloads are recognized.
|
|
215
|
+
|
|
216
|
+
## Directives
|
|
217
|
+
|
|
218
|
+
IntrospeQL supports the inclusion of several directives which, when included in
|
|
219
|
+
a PostgreSQL comment, can modify how IntrospeQL interacts with the database
|
|
220
|
+
object to which that comment is applied.
|
|
221
|
+
|
|
222
|
+
Directives are case-insensitive but must be separated from each other and from
|
|
223
|
+
other text by a whitespace character (a space, newline, etc).
|
|
224
|
+
|
|
225
|
+
Here is an example of adding a directive to the `config_key` column of a table
|
|
226
|
+
called `config` in the `reporting` schema:
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
COMMENT ON COLUMN reporting.config.config_key IS
|
|
230
|
+
'@introspeql-enable-tsdoc-comments
|
|
231
|
+
Unique configuration key.';
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Below, please find a table of all valid directives:
|
|
235
|
+
|
|
236
|
+
| Category | Directive | Effect |
|
|
237
|
+
| -------- | ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
238
|
+
| Objects | @introspeql-exclude | Excludes a table or function overload when mode is `'inclusive'` |
|
|
239
|
+
| Objects | @introspeql-include | Includes a table or function overload when mode is `'exclusive'` |
|
|
240
|
+
| Types | @introspeql-enable-nullable-args | Makes each parameter of the function overload to which it is applied nullable when `nullableArgs` is `false` in `config.functions` |
|
|
241
|
+
| Types | @introspeql-disable-nullable-args | Makes each parameter of the function overload to which it is applied non-nullable when `nullableArgs` is `true` in `config.functions` |
|
|
242
|
+
| Types | @introspeql-enable-nullable-return-types | Makes the return type of the function overload to which it is applied nullable when `nullableReturnTypes` is `false` in `config.functions` |
|
|
243
|
+
| Types | @introspeql-disable-nullable-return-types | Makes the return type of the function overload to which it is applied non-nullable when `nullableReturnTypes` is `true` in `config.functions` |
|
|
244
|
+
| Comments | @introspeql-enable-tsdoc-comments | Copies the comments of the table, column, or enum to which it is applied even when `config.copyComments` is false or is an array that does not include the given database object type. |
|
|
245
|
+
| Comments | @introspeql-disable-tsdoc-comments | Ignores the comments of the table, column, or enum to which it is applied even when `config.copyComments` is true or is an array that includes the given database object type. |
|
|
246
|
+
| Comments | @introspeql-begin-tsdoc-comment | Copies a portion of a PostgreSQL comment into the generated type definition file beginning after this directive and ending at the next `@introspeql-end-tsdoc-comment` directive or at the end of the comment. |
|
|
247
|
+
| Comments | @introspeql-end-tsdoc-comment | Omits a portion of a PostgreSQL comment from the generated type definition file beginning after this directive and ending at the next `@introspeql-begin-tsdoc-comment` directive or at the end of the comment. |
|
|
248
|
+
|
|
249
|
+
The package also exports a TypeScript enum of all valid directives:
|
|
250
|
+
|
|
251
|
+
```
|
|
252
|
+
import { Directives } from 'introspeql';
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Comments
|
|
256
|
+
|
|
257
|
+
[Comments](https://www.postgresql.org/docs/current/sql-comment.html) can be
|
|
258
|
+
applied to PostgreSQL database objects with the following syntax:
|
|
105
259
|
|
|
106
|
-
export type ReturnType = number;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
260
|
```
|
|
261
|
+
COMMENT ON COLUMN auth.users.user_id IS
|
|
262
|
+
'Unique identifier for the user.';
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
If IntrospeQL is configured to copy the comments for a given table, enum, or
|
|
266
|
+
column, PostgreSQL comments applied to that database object will be copied into
|
|
267
|
+
the type definition file as [TSDoc](https://tsdoc.org/) comments.
|
|
268
|
+
|
|
269
|
+
Note that all `@introspeql-` directives will always be removed when the copied
|
|
270
|
+
comment is formatted.
|
|
271
|
+
|
|
272
|
+
Comments cannot contain `*/` or a combination of
|
|
273
|
+
characters that results in `*/` after directives are removed. Such comments
|
|
274
|
+
will trigger a warning and will not be included in the output.
|
|
275
|
+
|
|
276
|
+
Assuming comment copying is enabled for a particular database object, you can
|
|
277
|
+
use the `@introspeql-begin-tsdoc-comment` and `@introspeql-end-tsdoc-comment`
|
|
278
|
+
directives to copy only certain excerpts of the comment:
|
|
279
|
+
|
|
280
|
+
### No Directive
|
|
281
|
+
|
|
282
|
+
If neither `@introspeql-begin-tsdoc-comment` nor `@introspeql-end-tsdoc-comment`
|
|
283
|
+
is included, the entire comment will be copied.
|
|
284
|
+
|
|
285
|
+
### Using Only `@introspeql-begin-tsdoc-comment`
|
|
286
|
+
|
|
287
|
+
If only `@introspeql-begin-tsdoc-comment` is included, everything before the
|
|
288
|
+
directive will be excluded, and everything after it will be included.
|
|
289
|
+
|
|
290
|
+
### Using Only `@introspeql-end-tsdoc-comment`
|
|
291
|
+
|
|
292
|
+
If only `@introspeql-end-tsdoc-comment` is included, everything before the
|
|
293
|
+
directive will be included, and everything after it will be excluded.
|
|
294
|
+
|
|
295
|
+
### Using Both Directives
|
|
296
|
+
|
|
297
|
+
You can alternate `@introspeql-begin-tsdoc-comment` and
|
|
298
|
+
`@introspeql-end-tsdoc-comment`.
|
|
299
|
+
|
|
300
|
+
You can begin or end with either directive, but you cannot include multiple
|
|
301
|
+
instances of the same directive in a row within the same comment (in this case,
|
|
302
|
+
a warning will be printed to the console and the comment will
|
|
303
|
+
<strong>not</strong> be copied).
|
|
304
|
+
|
|
305
|
+
When alternating between directives, content before
|
|
306
|
+
`@introspeql-end-tsdoc-comment` or after `@introspeql-begin-tsdoc-comment` will
|
|
307
|
+
be included and all other content will be excluded.
|
|
308
|
+
|
|
309
|
+
## Contributing
|
|
310
|
+
|
|
311
|
+
If you notice a bug or would like to request a feature, please submit an issue.
|
|
111
312
|
|
|
112
313
|
## License
|
|
113
314
|
|
|
@@ -131,4 +332,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
131
332
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
132
333
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
133
334
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
134
|
-
SOFTWARE.
|
|
335
|
+
SOFTWARE.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export declare class CommentConverter {
|
|
2
|
+
private static chunkExtractionDirectivesPattern;
|
|
3
|
+
private static chunkSanitizationDirectivesPattern;
|
|
4
|
+
/**
|
|
5
|
+
* Converts a PostgreSQL comment into TSDoc format, removing IntrospeQL
|
|
6
|
+
* directives, and formatting, prettifying, and validating the result.
|
|
7
|
+
*/
|
|
8
|
+
static convertComment(pgComment: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* Extracts the portions of a comment that have been flagged for inclusion
|
|
11
|
+
* with the `@introspeql-begin-tsdoc-comment` and/or
|
|
12
|
+
* `@introspeql-end-tsdoc-comment` directives, or the whole comment if no
|
|
13
|
+
* such directives are present.
|
|
14
|
+
*/
|
|
15
|
+
private static extractChunks;
|
|
16
|
+
private static findNextChunkExtractionDirective;
|
|
17
|
+
private static extractChunk;
|
|
18
|
+
/**
|
|
19
|
+
* Extracts a directive from a comment at the provided index, regardless of
|
|
20
|
+
* the case of the directive as it appears in the comment.
|
|
21
|
+
*/
|
|
22
|
+
private static extractDirective;
|
|
23
|
+
private static isEmptyChunk;
|
|
24
|
+
private static discardPreviousChunk;
|
|
25
|
+
/**
|
|
26
|
+
* Removes directives and leading/trailing new lines from each chunk. Filters
|
|
27
|
+
* out lines/chunks whose only content was directives.
|
|
28
|
+
*/
|
|
29
|
+
private static sanitizeChunks;
|
|
30
|
+
/**
|
|
31
|
+
* All chunks are separated with empty lines by default, so leading and
|
|
32
|
+
* trailing new lines are removed from each chunk.
|
|
33
|
+
*/
|
|
34
|
+
private static removeLeadingAndTrailingNewLines;
|
|
35
|
+
/**
|
|
36
|
+
* Removes all IntrospeQL directives from the provided chunks and filters
|
|
37
|
+
* out lines/chunks whose only contents were such directives.
|
|
38
|
+
*/
|
|
39
|
+
private static removeDirectives;
|
|
40
|
+
/**
|
|
41
|
+
* Merges chunks and applies basic TSDoc formatting.
|
|
42
|
+
*/
|
|
43
|
+
private static formatAndMergeChunks;
|
|
44
|
+
/**
|
|
45
|
+
* Prettifies a comment that has already received basic TSDoc formatting.
|
|
46
|
+
*/
|
|
47
|
+
private static prettifyComment;
|
|
48
|
+
/**
|
|
49
|
+
* Verifies that *\/ occurs only at the very end of a TSDoc comment. This
|
|
50
|
+
* validation must occur after the TSDoc comment is produced to guarantee that
|
|
51
|
+
* the collapse of whitespace and/or removal of directives hasn't produced *\/.
|
|
52
|
+
*/
|
|
53
|
+
private static validateComment;
|
|
54
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CommentConverter = void 0;
|
|
4
|
+
var shared_1 = require("../shared");
|
|
5
|
+
var prettify_comment_1 = require("./prettify-comment");
|
|
6
|
+
var CommentConverter = /** @class */ (function () {
|
|
7
|
+
function CommentConverter() {
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Converts a PostgreSQL comment into TSDoc format, removing IntrospeQL
|
|
11
|
+
* directives, and formatting, prettifying, and validating the result.
|
|
12
|
+
*/
|
|
13
|
+
CommentConverter.convertComment = function (pgComment) {
|
|
14
|
+
// Break the comment into chunks and sanitize them.
|
|
15
|
+
var chunks = this.extractChunks(pgComment);
|
|
16
|
+
var sanitizedChunks = this.sanitizeChunks(chunks);
|
|
17
|
+
// Convert the comment and validate it.
|
|
18
|
+
var convertedComment = this.formatAndMergeChunks(sanitizedChunks);
|
|
19
|
+
this.validateComment(convertedComment);
|
|
20
|
+
// Prettify the comment and validate it.
|
|
21
|
+
var prettifiedComment = this.prettifyComment(convertedComment);
|
|
22
|
+
this.validateComment(prettifiedComment);
|
|
23
|
+
return prettifiedComment;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Extracts the portions of a comment that have been flagged for inclusion
|
|
27
|
+
* with the `@introspeql-begin-tsdoc-comment` and/or
|
|
28
|
+
* `@introspeql-end-tsdoc-comment` directives, or the whole comment if no
|
|
29
|
+
* such directives are present.
|
|
30
|
+
*/
|
|
31
|
+
CommentConverter.extractChunks = function (pgComment) {
|
|
32
|
+
var chunks = [];
|
|
33
|
+
var previousDirective = null;
|
|
34
|
+
var indexOfDirective = this.findNextChunkExtractionDirective(pgComment);
|
|
35
|
+
var chunk = this.extractChunk(pgComment, indexOfDirective);
|
|
36
|
+
while (indexOfDirective >= 0) {
|
|
37
|
+
var directive = this.extractDirective(pgComment, indexOfDirective);
|
|
38
|
+
if (directive === previousDirective) {
|
|
39
|
+
throw new shared_1.ParsingError('Ambiguous directives: cannot have two instances of ' +
|
|
40
|
+
directive +
|
|
41
|
+
'in a row in the same comment.');
|
|
42
|
+
}
|
|
43
|
+
else if (directive === shared_1.Directives.EndTSDocComment &&
|
|
44
|
+
!this.isEmptyChunk(chunk)) {
|
|
45
|
+
chunks.push(chunk);
|
|
46
|
+
}
|
|
47
|
+
pgComment = this.discardPreviousChunk(pgComment);
|
|
48
|
+
indexOfDirective = this.findNextChunkExtractionDirective(pgComment);
|
|
49
|
+
chunk = this.extractChunk(pgComment, indexOfDirective);
|
|
50
|
+
previousDirective = directive;
|
|
51
|
+
}
|
|
52
|
+
if ((!previousDirective ||
|
|
53
|
+
previousDirective === shared_1.Directives.BeginTSDocComment) &&
|
|
54
|
+
!this.isEmptyChunk(chunk)) {
|
|
55
|
+
chunks.push(chunk);
|
|
56
|
+
}
|
|
57
|
+
return chunks;
|
|
58
|
+
};
|
|
59
|
+
CommentConverter.findNextChunkExtractionDirective = function (pgComment) {
|
|
60
|
+
return pgComment.search(this.chunkExtractionDirectivesPattern);
|
|
61
|
+
};
|
|
62
|
+
CommentConverter.extractChunk = function (pgComment, indexOfDirective) {
|
|
63
|
+
return pgComment.slice(0, indexOfDirective >= 0 ? indexOfDirective : pgComment.length);
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Extracts a directive from a comment at the provided index, regardless of
|
|
67
|
+
* the case of the directive as it appears in the comment.
|
|
68
|
+
*/
|
|
69
|
+
CommentConverter.extractDirective = function (pgComment, indexOfDirective) {
|
|
70
|
+
/*
|
|
71
|
+
Add 2 to the length of the longer directive because the pattern includes
|
|
72
|
+
up to 1 leading and 1 trailing whitespace character.
|
|
73
|
+
*/
|
|
74
|
+
var maxSearchLength = Math.max(shared_1.Directives.BeginTSDocComment.length, shared_1.Directives.EndTSDocComment.length) + 2;
|
|
75
|
+
var searchString = pgComment
|
|
76
|
+
.slice(indexOfDirective, indexOfDirective + maxSearchLength)
|
|
77
|
+
.trim()
|
|
78
|
+
.toLowerCase();
|
|
79
|
+
if (searchString.startsWith(shared_1.Directives.BeginTSDocComment.toLowerCase())) {
|
|
80
|
+
return shared_1.Directives.BeginTSDocComment;
|
|
81
|
+
}
|
|
82
|
+
else if (searchString.startsWith(shared_1.Directives.EndTSDocComment.toLowerCase())) {
|
|
83
|
+
return shared_1.Directives.EndTSDocComment;
|
|
84
|
+
}
|
|
85
|
+
throw new shared_1.ParsingError('No directive at the provided index.');
|
|
86
|
+
};
|
|
87
|
+
CommentConverter.isEmptyChunk = function (chunk) {
|
|
88
|
+
return !chunk.trim();
|
|
89
|
+
};
|
|
90
|
+
CommentConverter.discardPreviousChunk = function (pgComment) {
|
|
91
|
+
var _b = pgComment.match(this.chunkExtractionDirectivesPattern), index = _b.index, length = _b[0].length;
|
|
92
|
+
return pgComment.slice(index + length);
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Removes directives and leading/trailing new lines from each chunk. Filters
|
|
96
|
+
* out lines/chunks whose only content was directives.
|
|
97
|
+
*/
|
|
98
|
+
CommentConverter.sanitizeChunks = function (chunks) {
|
|
99
|
+
var sanitizedChunks = this.removeLeadingAndTrailingNewLines(chunks);
|
|
100
|
+
sanitizedChunks = this.removeDirectives(sanitizedChunks);
|
|
101
|
+
return sanitizedChunks;
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* All chunks are separated with empty lines by default, so leading and
|
|
105
|
+
* trailing new lines are removed from each chunk.
|
|
106
|
+
*/
|
|
107
|
+
CommentConverter.removeLeadingAndTrailingNewLines = function (chunks) {
|
|
108
|
+
return chunks.map(function (chunk) {
|
|
109
|
+
while (chunk.startsWith('\n')) {
|
|
110
|
+
chunk = chunk.slice(1);
|
|
111
|
+
}
|
|
112
|
+
while (chunk.endsWith('\n')) {
|
|
113
|
+
chunk = chunk.slice(0, chunk.length - 1);
|
|
114
|
+
}
|
|
115
|
+
return chunk;
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
/**
|
|
119
|
+
* Removes all IntrospeQL directives from the provided chunks and filters
|
|
120
|
+
* out lines/chunks whose only contents were such directives.
|
|
121
|
+
*/
|
|
122
|
+
CommentConverter.removeDirectives = function (chunks) {
|
|
123
|
+
var _this = this;
|
|
124
|
+
var result = [];
|
|
125
|
+
chunks.forEach(function (chunk) {
|
|
126
|
+
var lines = chunk.split('\n');
|
|
127
|
+
var sanitizedLines = [];
|
|
128
|
+
lines.forEach(function (line) {
|
|
129
|
+
var sanitizedLine = line.replaceAll(_this.chunkSanitizationDirectivesPattern, function (match) {
|
|
130
|
+
if (/\s\S+\s/.test(match)) {
|
|
131
|
+
return ' ';
|
|
132
|
+
}
|
|
133
|
+
return '';
|
|
134
|
+
});
|
|
135
|
+
var directiveRemoved = sanitizedLine != line;
|
|
136
|
+
if (!directiveRemoved || sanitizedLine.trim() != '') {
|
|
137
|
+
sanitizedLines.push(sanitizedLine);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
if (sanitizedLines.length) {
|
|
141
|
+
var sanitizedChunk = sanitizedLines.join('\n');
|
|
142
|
+
result.push(sanitizedChunk);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
return result;
|
|
146
|
+
};
|
|
147
|
+
/**
|
|
148
|
+
* Merges chunks and applies basic TSDoc formatting.
|
|
149
|
+
*/
|
|
150
|
+
CommentConverter.formatAndMergeChunks = function (chunks) {
|
|
151
|
+
var mergedChunks = chunks
|
|
152
|
+
.map(function (chunk) {
|
|
153
|
+
var lines = chunk.split('\n');
|
|
154
|
+
return lines.map(function (line) { return " * ".concat(line); }).join('\n');
|
|
155
|
+
})
|
|
156
|
+
.join('\n *\n');
|
|
157
|
+
return mergedChunks.length ? '/**\n' + mergedChunks + '\n */' : '';
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* Prettifies a comment that has already received basic TSDoc formatting.
|
|
161
|
+
*/
|
|
162
|
+
CommentConverter.prettifyComment = function (comment) {
|
|
163
|
+
var prettified = (0, prettify_comment_1.prettifyComment)(comment);
|
|
164
|
+
return prettified;
|
|
165
|
+
};
|
|
166
|
+
/**
|
|
167
|
+
* Verifies that *\/ occurs only at the very end of a TSDoc comment. This
|
|
168
|
+
* validation must occur after the TSDoc comment is produced to guarantee that
|
|
169
|
+
* the collapse of whitespace and/or removal of directives hasn't produced *\/.
|
|
170
|
+
*/
|
|
171
|
+
CommentConverter.validateComment = function (comment) {
|
|
172
|
+
if (comment !== '' && comment.indexOf('*/') !== comment.length - 2) {
|
|
173
|
+
throw new shared_1.ParsingError('Comments cannot contain */');
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
var _a;
|
|
177
|
+
_a = CommentConverter;
|
|
178
|
+
CommentConverter.chunkExtractionDirectivesPattern = new RegExp("(^|\\s)(".concat(shared_1.Directives.BeginTSDocComment, "|").concat(shared_1.Directives.EndTSDocComment, ")($|\\s)"), 'i');
|
|
179
|
+
(function () {
|
|
180
|
+
var directivesPattern = "(".concat(Object.values(shared_1.Directives).join('|'), ")");
|
|
181
|
+
_a.chunkSanitizationDirectivesPattern = new RegExp("(^|\\s)(".concat(directivesPattern, ")(\\s+").concat(directivesPattern, ")*($|\\s)"), 'gi');
|
|
182
|
+
})();
|
|
183
|
+
return CommentConverter;
|
|
184
|
+
}());
|
|
185
|
+
exports.CommentConverter = CommentConverter;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./comment-converter"), exports);
|
|
18
|
+
__exportStar(require("./prettify-comment"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function prettifyComment(comment: string): string;
|