mirror of
https://github.com/logto-io/logto.git
synced 2025-02-17 22:04:19 -05:00
refactor(schemas): support field JSDoc comments
This commit is contained in:
parent
f702cc24a3
commit
d0a44e93f8
5 changed files with 39 additions and 8 deletions
|
@ -17,6 +17,7 @@ import {
|
|||
parseType,
|
||||
removeUnrecognizedComments,
|
||||
splitTableFieldDefinitions,
|
||||
stripLeadingJsDocComments as stripComments,
|
||||
} from './utils.js';
|
||||
|
||||
const directory = 'tables';
|
||||
|
@ -61,7 +62,10 @@ const generate = async () => {
|
|||
.map((value) => normalizeWhitespaces(value))
|
||||
.filter((value) =>
|
||||
constrainedKeywords.every(
|
||||
(constraint) => !value.toLowerCase().startsWith(constraint + ' ')
|
||||
(constraint) =>
|
||||
!stripComments(value)
|
||||
.toLowerCase()
|
||||
.startsWith(constraint + ' ')
|
||||
)
|
||||
)
|
||||
.map<Field>((value) => parseType(value));
|
||||
|
|
|
@ -16,7 +16,8 @@ export const generateSchema = ({ name, fields }: TableWithType) => {
|
|||
return [
|
||||
`export type ${databaseEntryType} = {`,
|
||||
...fields.map(
|
||||
({ name, type, isArray, nullable, hasDefaultValue }) =>
|
||||
({ name, comments, type, isArray, nullable, hasDefaultValue }) =>
|
||||
conditionalString(comments && ` /** ${comments} */\n`) +
|
||||
` ${camelcase(name)}${conditionalString(
|
||||
(nullable || hasDefaultValue || name === tenantId) && '?'
|
||||
)}: ${type}${conditionalString(isArray && '[]')}${conditionalString(
|
||||
|
@ -27,7 +28,8 @@ export const generateSchema = ({ name, fields }: TableWithType) => {
|
|||
'',
|
||||
`export type ${modelName} = {`,
|
||||
...fields.map(
|
||||
({ name, type, isArray, nullable, hasDefaultValue }) =>
|
||||
({ name, comments, type, isArray, nullable, hasDefaultValue }) =>
|
||||
conditionalString(comments && ` /** ${comments} */\n`) +
|
||||
` ${camelcase(name)}: ${type}${conditionalString(isArray && '[]')}${
|
||||
nullable && !hasDefaultValue ? ' | null' : ''
|
||||
};`
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
export type Field = {
|
||||
name: string;
|
||||
/** The JSDoc comment for the field. */
|
||||
comments?: string;
|
||||
type?: string;
|
||||
customType?: string;
|
||||
tsType?: string;
|
||||
|
|
|
@ -6,6 +6,14 @@ import type { Field } from './types.js';
|
|||
export const normalizeWhitespaces = (string: string): string =>
|
||||
string.replaceAll(/\s+/g, ' ').trim();
|
||||
|
||||
// eslint-disable-next-line unicorn/prevent-abbreviations -- JSDoc is a term
|
||||
export const stripLeadingJsDocComments = (string: string): string =>
|
||||
string.replace(/^\s*\/\*\*[^*]+\*\//, '').trim();
|
||||
|
||||
// eslint-disable-next-line unicorn/prevent-abbreviations -- JSDoc is a term
|
||||
const getLeadingJsDocComments = (string: string): Optional<string> =>
|
||||
/^\s*\/\*\*([^*]+)\*\//g.exec(string)?.[1]?.trim();
|
||||
|
||||
// Remove all comments not start with @
|
||||
export const removeUnrecognizedComments = (string: string): string =>
|
||||
string.replaceAll(/\/\*(?!\s@)[^*]+\*\//g, '');
|
||||
|
@ -73,7 +81,12 @@ export const splitTableFieldDefinitions = (value: string) =>
|
|||
({ result, count: previousCount }, current) => {
|
||||
const count = previousCount + getCountDelta(current);
|
||||
|
||||
if (count === 0 && current === ',') {
|
||||
if (
|
||||
count === 0 &&
|
||||
current === ',' &&
|
||||
// Ignore commas in JSDoc comments
|
||||
!stripLeadingJsDocComments(result.at(-1) ?? '').includes('/**')
|
||||
) {
|
||||
return {
|
||||
result: [...result, ''],
|
||||
count,
|
||||
|
@ -169,9 +182,12 @@ const parseStringMaxLength = (rawType: string) => {
|
|||
};
|
||||
|
||||
export const parseType = (tableFieldDefinition: string): Field => {
|
||||
const [nameRaw, typeRaw, ...rest] = tableFieldDefinition.split(' ');
|
||||
const normalized = stripLeadingJsDocComments(tableFieldDefinition);
|
||||
const comments = getLeadingJsDocComments(tableFieldDefinition);
|
||||
|
||||
assert(nameRaw && typeRaw, new Error('Missing field name or type: ' + tableFieldDefinition));
|
||||
const [nameRaw, typeRaw, ...rest] = normalized.split(' ');
|
||||
|
||||
assert(nameRaw && typeRaw, new Error('Missing field name or type: ' + normalized));
|
||||
|
||||
const name = nameRaw.toLowerCase();
|
||||
const type = typeRaw.toLowerCase();
|
||||
|
@ -198,6 +214,7 @@ export const parseType = (tableFieldDefinition: string): Field => {
|
|||
|
||||
return {
|
||||
name,
|
||||
comments,
|
||||
type: primitiveType,
|
||||
isString,
|
||||
isArray,
|
||||
|
|
|
@ -4,16 +4,22 @@ create table sentinel_activities (
|
|||
tenant_id varchar(21) not null
|
||||
references tenants (id) on update cascade on delete cascade,
|
||||
id varchar(21) not null,
|
||||
/** The subject (actor) that performed the action. */
|
||||
subject_type varchar(32) /* @use SentinelActivitySubjectType */ not null,
|
||||
/** The target that the action was performed on. */
|
||||
target_type varchar(32) /* @use SentinelActivityTargetType */ not null,
|
||||
/** The target identifier. */
|
||||
target_id varchar(21) not null
|
||||
references users (id) on update cascade on delete cascade,
|
||||
/** The related log id if any. */
|
||||
log_id varchar(21)
|
||||
references logs (id) on update cascade on delete cascade,
|
||||
/** The action name that was performed. */
|
||||
action varchar(64) /* @use SentinelActivityAction */ not null,
|
||||
/** If the action was successful or not. */
|
||||
result sentinel_activity_result not null,
|
||||
payload jsonb /* @use LogContextPayload */ not null,
|
||||
/** Additional payload data if any. */
|
||||
payload jsonb /* @use SentinelActivityPayload */ not null,
|
||||
created_at timestamptz not null default(now()),
|
||||
primary key (id)
|
||||
);
|
||||
ex
|
||||
|
|
Loading…
Add table
Reference in a new issue