diff --git a/docs/docs/advanced/transform-properties.md b/docs/docs/advanced/transform-properties.md new file mode 100644 index 000000000..5d6579797 --- /dev/null +++ b/docs/docs/advanced/transform-properties.md @@ -0,0 +1,34 @@ +--- +title: Properties Transform +sidebar_position: 35 +--- + +A key feature of Joist is defining custom properties on your domain model, i.e. `hasOneThrough`, `hasManyThrough`, `hasAsyncProperty`, `hasReactiveField`, etc. + +While these properties are powerful, Joist's current API involves defining them as properties directly on each instance of an entity, i.e.: + +```ts +export class Author extends AuthorCodegen { + readonly reviews: Collection = hasManyThrough((a) => a.books.reviews); +} +``` + +This means that if you load 1,000 `Author` rows from the database, there will be 1,000 `hasManyThrough` relations initialized, even if this particular endpoint/codepath doesn't end up accessing them. + +In the majority of scenarios, this is fine, but when loading ~1,000s of entities, it can become a performance issue. + +To address this, Joist provides a [ts-patch](https://github.com/nonara/ts-patch) transformer that will rewrite the fields into lazy getters on the `Author` prototype. + +To enable this, add the following to your `tsconfig.json`: + +```json +{ + "compilerOptions": { + "plugins": [ + { "transform": "joist-transform-properties", "type": "raw" } + ] + } +} +``` + +And then compile your production code with `tspc` instead of the raw `tsc` command. diff --git a/docs/docs/faq.md b/docs/docs/faq.md index ff1cba400..91747fbc4 100644 --- a/docs/docs/faq.md +++ b/docs/docs/faq.md @@ -6,3 +6,31 @@ position: 10 ## What databases does Joist support? Currently only Postgres; see [support other databases](https://github.com/joist-orm/joist-orm/issues/636). + +## Why are relations modeled as objects? + +In Joist, relations are modeled as wrapper objects, i.e. `Author.books` is not a raw array like `Book[]`, but instead a `Collection` that must have `.load()` and `.get` called on it. + +This can initially feel awkward, but it provides a truly type-safe API, given that relations may-or-may not be loaded from the database, and instead are incrementally into memory. + +This is often how business logic wants to interact with the domain model--a continual incremental loading of data as needed, as conditional codepaths are executed, instead of an endpoint/program exhaustively knowing up-front exactly what data will be necessary. + +If performance is a concern (loading thousands of entities with many custom properties), Joist provides a [ts-patch transform](/docs/advanced/transform-properties) to rewrite the properties as lazy getters in production builds. + +## Why must properties be explicitly typed? + +When declaring custom properties on entities, currently the fields must be explicitly typed, i.e. the `Collection` in the following example is required: + +```typescript +export class Author extends AuthorCodegen { + readonly reviews: Collection = hasManyThrough((author) => author.books.reviews); +} +``` + +Obviously as TypeScript fans, we'd love to have these field types inferred, and just do `readonly reviews = hasManyThrough`. + +Unfortunately, given how interconnected the types of a domain model are, and how sophisticated custom properties can rely on cross-entity typing, attempting to infer the field types quickly leads to the TypeScript compiler failing with cyclic dependency errors, i.e. the `Author`'s fields can only be inferred if `Book` is first typed, but `Book`'s fields can only be inferred if `Author` is first typed. + +And adding explicit field types short-circuits these cyclic dependency. + + diff --git a/package.json b/package.json index 979bbe598..ba76762c9 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,8 @@ "packages/tests/esm-misc", "packages/tests/number-ids", "packages/tests/untagged-ids", - "packages/tests/uuid-ids" + "packages/tests/uuid-ids", + "packages/transform-properties" ], "devDependencies": { "@semantic-release/changelog": "^6.0.3", diff --git a/packages/codegen/src/generateEntityCodegenFile.ts b/packages/codegen/src/generateEntityCodegenFile.ts index 4249d716b..b0da2b461 100644 --- a/packages/codegen/src/generateEntityCodegenFile.ts +++ b/packages/codegen/src/generateEntityCodegenFile.ts @@ -55,7 +55,6 @@ import { cleanStringValue, failNoIdYet, getField, - getInstanceData, hasLargeMany, hasLargeManyToMany, hasMany, @@ -580,8 +579,7 @@ export function generateEntityCodegenFile(config: Config, dbMeta: DbMetadata, me } else { return code` get ${r.fieldName}(): ${r.decl} { - const { relations } = ${getInstanceData}(this); - return relations.${r.fieldName} ??= ${r.init}; + return this.__data.relations.${r.fieldName} ??= ${r.init}; } `; } diff --git a/packages/graphql-resolver-utils/src/entityResolver.ts b/packages/graphql-resolver-utils/src/entityResolver.ts index 701764f40..b03d9af85 100644 --- a/packages/graphql-resolver-utils/src/entityResolver.ts +++ b/packages/graphql-resolver-utils/src/entityResolver.ts @@ -79,7 +79,7 @@ export function entityResolver !isPrimaryKeyField(ormField) && !isReferenceField(ormField) && !isCollectionField(ormField)) .map((ormField) => { if (ormField.kind === "primitive" && ormField.derived === "async") { @@ -90,7 +90,7 @@ export function entityResolver][] = Object.values(entityMetadata.fields) + const referenceResolvers: [string, Resolver][] = Object.values(entityMetadata.allFields) .filter((ormField) => isReferenceField(ormField)) .map((ormField) => [ ormField.fieldName, @@ -127,7 +127,7 @@ export function entityResolver][] = Object.values(entityMetadata.fields) + const collectionResolvers: [string, Resolver][] = Object.values(entityMetadata.allFields) .filter((ormField) => isCollectionField(ormField)) .map((ormField) => [ ormField.fieldName, @@ -154,8 +154,8 @@ export function entityResolver !ignoredKeys.includes(n)); + const alreadyFoundKeys = Object.keys(ormResolvers); + const customProperties = Object.keys(getProperties(entityMetadata)).filter((n) => !alreadyFoundKeys.includes(n)); const customResolvers: [string, Resolver][] = customProperties.map((key) => [ key, (entity) => { diff --git a/packages/orm/src/BaseEntity.ts b/packages/orm/src/BaseEntity.ts index a729c1b1e..1307d8a29 100644 --- a/packages/orm/src/BaseEntity.ts +++ b/packages/orm/src/BaseEntity.ts @@ -14,7 +14,7 @@ import { export let currentlyInstantiatingEntity: Entity | undefined; /** - * Returns the internal `#orm` tracking field for `entity`. + * Returns the internal `__data` tracking field for `entity`. * * This should be treated as an internal API and may change without notice. */ @@ -29,18 +29,18 @@ export function getInstanceData(entity: Entity): InstanceData { */ export abstract class BaseEntity implements Entity { public static getInstanceData(entity: Entity): InstanceData { - return (entity as BaseEntity).#orm; + return (entity as BaseEntity).__data; } - readonly #orm!: InstanceData; + // We use a protected field so that subclass getters can easily access `this.__data.relations`. + protected readonly __data!: InstanceData; protected constructor(em: EM, optsOrId: any) { + const isNew = typeof optsOrId !== "string"; + const data = new InstanceData(em, (this.constructor as any).metadata, isNew); + // This makes it non-enumerable to avoid Jest/recursive things tripping over it + Object.defineProperty(this, "__data", { value: data, enumerable: false, writable: false, configurable: false }); // Only do em.register for em.create-d entities, otherwise defer to hydrate to em.register - if (typeof optsOrId === "string") { - this.#orm = new InstanceData(em, (this.constructor as any).metadata, false); - } else { - this.#orm = new InstanceData(em, (this.constructor as any).metadata, true); - em.register(this); - } + if (isNew) em.register(this); currentlyInstantiatingEntity = this; } @@ -82,15 +82,15 @@ export abstract class BaseEntity { if (propertiesCache[key]) { return propertiesCache[key]; } + const instance = getFakeInstance(meta); + + // Mostly for historical reasons, we don't treat known primitives/enums as properties, + // i.e. properties were originally meant to be the wrapper objects like `hasOne`, + // `hasMany`, `ReactiveField`, etc. + // + // That said, we've since start leaking other things like getters, regular async methods, + // etc., into properties, so that `entityResolver` can pick them up as keys to put into + // the GraphQL resolvers. So we should probably just remove this filter and let everything + // get returned as properties. + const knownPrimitives = Object.values(meta.allFields) + .filter((f) => f.kind === "primaryKey" || f.kind === "primitive" || f.kind === "enum") + .map((f) => f.fieldName); + propertiesCache[key] = Object.fromEntries( - [ - ...Object.values(meta.allFields) - .filter((f) => f.kind !== "primaryKey" && f.kind !== "primitive" && f.kind !== "enum") - .map((f) => f.fieldName), - ...Object.getOwnPropertyNames(meta.cstr.prototype), - ...Object.keys(instance), - ] - .filter((key) => key !== "constructor" && !key.startsWith("__")) + // Recursively looking for ownKeys will find: + // - Custom properties set on the instance, like `readonly author: Reference = hasOneThrough(...)` + // - Getters declared within the class like `get initials()` + // - Getters auto-created by transform-properties when it lazies `readonly author = hasOneThrough(...)` relations + // - Getters declared within the codegen classes like `get books(): Reference<...>` + getRecursiveOwnNames(instance) + .filter((key) => key !== "constructor" && !key.startsWith("__") && !knownPrimitives.includes(key)) .map((key) => { // Return the value of `instance[key]` but wrap it in a try/catch in case it's // a getter that runs code that fails b/c of the dummy state we're in. @@ -75,3 +88,30 @@ export function getFakeInstance(meta: EntityMetadata): Entity { {}, )); } + +// These are keys we codegen into `AuthorCodegen` files to get the best typing +// experience, but really should be treated as BaseEntity keys that we don't +// need to expose from `getProperties`. +const ignoredKeys = new Set([ + "id", + "idMaybe", + "idTagged", + "idTaggedMaybe", + "set", + "setPartial", + "changes", + "isSoftDeletedEntity", + "load", + "populate", + "isLoaded", + "toJSON", +]); + +// function getRecursiveOwnNames(cstr: MaybeAbstractEntityConstructor): string[] { +function getRecursiveOwnNames(instance: any): string[] { + const keys: string[] = []; + for (let curr = instance; curr && curr !== BaseEntity.prototype; curr = Object.getPrototypeOf(curr)) { + keys.push(...Object.getOwnPropertyNames(curr)); + } + return keys.filter((k) => !ignoredKeys.has(k)); +} diff --git a/packages/tests/esm-misc/joist-config.json b/packages/tests/esm-misc/joist-config.json index c784fceaa..3a2341cbe 100644 --- a/packages/tests/esm-misc/joist-config.json +++ b/packages/tests/esm-misc/joist-config.json @@ -10,5 +10,5 @@ "createdAt": { "names": ["created_at", "createdAt"], "required": false }, "updatedAt": { "names": ["updated_at", "updatedAt"], "required": false } }, - "version": "1.160.4" + "version": "1.162.0" } diff --git a/packages/tests/esm-misc/src/entities/codegen/AuthorCodegen.ts b/packages/tests/esm-misc/src/entities/codegen/AuthorCodegen.ts index b08b8a39e..37bc0eab3 100644 --- a/packages/tests/esm-misc/src/entities/codegen/AuthorCodegen.ts +++ b/packages/tests/esm-misc/src/entities/codegen/AuthorCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasMany, isLoaded, loadLens, @@ -207,7 +206,13 @@ export abstract class AuthorCodegen extends BaseEntity im } get books(): Collection { - const { relations } = getInstanceData(this); - return relations.books ??= hasMany(this as any as Author, bookMeta, "books", "author", "authorId", undefined); + return this.__data.relations.books ??= hasMany( + this as any as Author, + bookMeta, + "books", + "author", + "authorId", + undefined, + ); } } diff --git a/packages/tests/esm-misc/src/entities/codegen/BookCodegen.ts b/packages/tests/esm-misc/src/entities/codegen/BookCodegen.ts index cd7c4de92..40caf0fca 100644 --- a/packages/tests/esm-misc/src/entities/codegen/BookCodegen.ts +++ b/packages/tests/esm-misc/src/entities/codegen/BookCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasOne, isLoaded, loadLens, @@ -164,7 +163,6 @@ export abstract class BookCodegen extends BaseEntity impl } get author(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.author ??= hasOne(this as any as Book, authorMeta, "author", "books"); + return this.__data.relations.author ??= hasOne(this as any as Book, authorMeta, "author", "books"); } } diff --git a/packages/tests/integration/joist-config.json b/packages/tests/integration/joist-config.json index 631521266..21740e30c 100644 --- a/packages/tests/integration/joist-config.json +++ b/packages/tests/integration/joist-config.json @@ -94,5 +94,5 @@ } }, "entitiesDirectory": "./src/entities", - "version": "1.160.4" + "version": "1.162.0" } diff --git a/packages/tests/integration/package.json b/packages/tests/integration/package.json index 96feb4e3a..8854876b1 100644 --- a/packages/tests/integration/package.json +++ b/packages/tests/integration/package.json @@ -40,11 +40,13 @@ "joist-graphql-codegen": "workspace:*", "joist-migration-utils": "workspace:*", "joist-test-utils": "workspace:*", + "joist-transform-properties": "workspace:*", "kelonio": "^0.10.0", "postgres": "^3.4.4", "prettier": "^3.2.5", "prettier-plugin-organize-imports": "^3.2.4", "superstruct": "0.15.5", + "ts-patch": "^3.1.2", "tsconfig-paths": "^4.2.0", "tsx": "^4.7.2", "typescript": "^5.4.5", diff --git a/packages/tests/integration/src/SingleTableInheritance.test.ts b/packages/tests/integration/src/SingleTableInheritance.test.ts index 2be24a91f..b070829a1 100644 --- a/packages/tests/integration/src/SingleTableInheritance.test.ts +++ b/packages/tests/integration/src/SingleTableInheritance.test.ts @@ -253,28 +253,37 @@ describe("SingleTableInheritance", () => { it("reports the right properties", () => { expect(Object.keys(getProperties(Task.metadata))).toMatchInlineSnapshot(` [ + "typeDetails", + "isOld", + "isNew", "taskTaskItems", "tags", ] `); expect(Object.keys(getProperties(TaskNew.metadata))).toMatchInlineSnapshot(` [ - "specialNewAuthor", "newTaskTaskItems", + "specialNewAuthor", + "typeDetails", + "isOld", + "isNew", "taskTaskItems", "tags", ] `); expect(Object.keys(getProperties(TaskOld.metadata))).toMatchInlineSnapshot(` [ - "parentOldTask", + "commentParentInfo", "comments", "oldTaskTaskItems", "tasks", + "parentOldTask", "publishers", + "typeDetails", + "isOld", + "isNew", "taskTaskItems", "tags", - "commentParentInfo", ] `); }); diff --git a/packages/tests/integration/src/entities/codegen/AuthorCodegen.ts b/packages/tests/integration/src/entities/codegen/AuthorCodegen.ts index 3817dcf55..bb0d3233e 100644 --- a/packages/tests/integration/src/entities/codegen/AuthorCodegen.ts +++ b/packages/tests/integration/src/entities/codegen/AuthorCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasMany, hasManyToMany, hasOne, @@ -576,8 +575,7 @@ export abstract class AuthorCodegen extends BaseEntity im } get authors(): Collection { - const { relations } = getInstanceData(this); - return relations.authors ??= hasMany( + return this.__data.relations.authors ??= hasMany( this as any as Author, authorMeta, "authors", @@ -588,8 +586,7 @@ export abstract class AuthorCodegen extends BaseEntity im } get schedules(): Collection { - const { relations } = getInstanceData(this); - return relations.schedules ??= hasMany( + return this.__data.relations.schedules ??= hasMany( this as any as Author, authorScheduleMeta, "schedules", @@ -600,16 +597,14 @@ export abstract class AuthorCodegen extends BaseEntity im } get books(): Collection { - const { relations } = getInstanceData(this); - return relations.books ??= hasMany(this as any as Author, bookMeta, "books", "author", "author_id", { + return this.__data.relations.books ??= hasMany(this as any as Author, bookMeta, "books", "author", "author_id", { "field": "order", "direction": "ASC", }); } get comments(): Collection { - const { relations } = getInstanceData(this); - return relations.comments ??= hasMany( + return this.__data.relations.comments ??= hasMany( this as any as Author, commentMeta, "comments", @@ -620,8 +615,7 @@ export abstract class AuthorCodegen extends BaseEntity im } get tasks(): Collection { - const { relations } = getInstanceData(this); - return relations.tasks ??= hasMany( + return this.__data.relations.tasks ??= hasMany( this as any as Author, taskNewMeta, "tasks", @@ -632,13 +626,11 @@ export abstract class AuthorCodegen extends BaseEntity im } get mentor(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.mentor ??= hasOne(this as any as Author, authorMeta, "mentor", "authors"); + return this.__data.relations.mentor ??= hasOne(this as any as Author, authorMeta, "mentor", "authors"); } get currentDraftBook(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.currentDraftBook ??= hasOne( + return this.__data.relations.currentDraftBook ??= hasOne( this as any as Author, bookMeta, "currentDraftBook", @@ -647,18 +639,21 @@ export abstract class AuthorCodegen extends BaseEntity im } get publisher(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.publisher ??= hasOne(this as any as Author, publisherMeta, "publisher", "authors"); + return this.__data.relations.publisher ??= hasOne(this as any as Author, publisherMeta, "publisher", "authors"); } get image(): OneToOneReference { - const { relations } = getInstanceData(this); - return relations.image ??= hasOneToOne(this as any as Author, imageMeta, "image", "author", "author_id"); + return this.__data.relations.image ??= hasOneToOne( + this as any as Author, + imageMeta, + "image", + "author", + "author_id", + ); } get userOneToOne(): OneToOneReference { - const { relations } = getInstanceData(this); - return relations.userOneToOne ??= hasOneToOne( + return this.__data.relations.userOneToOne ??= hasOneToOne( this as any as Author, userMeta, "userOneToOne", @@ -668,8 +663,7 @@ export abstract class AuthorCodegen extends BaseEntity im } get tags(): Collection { - const { relations } = getInstanceData(this); - return relations.tags ??= hasManyToMany( + return this.__data.relations.tags ??= hasManyToMany( this as any as Author, "authors_to_tags", "tags", diff --git a/packages/tests/integration/src/entities/codegen/AuthorScheduleCodegen.ts b/packages/tests/integration/src/entities/codegen/AuthorScheduleCodegen.ts index 48469dfd4..2fb5383cb 100644 --- a/packages/tests/integration/src/entities/codegen/AuthorScheduleCodegen.ts +++ b/packages/tests/integration/src/entities/codegen/AuthorScheduleCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasOne, isLoaded, loadLens, @@ -186,7 +185,6 @@ export abstract class AuthorScheduleCodegen extends BaseEntity { - const { relations } = getInstanceData(this); - return relations.author ??= hasOne(this as any as AuthorSchedule, authorMeta, "author", "schedules"); + return this.__data.relations.author ??= hasOne(this as any as AuthorSchedule, authorMeta, "author", "schedules"); } } diff --git a/packages/tests/integration/src/entities/codegen/BookAdvanceCodegen.ts b/packages/tests/integration/src/entities/codegen/BookAdvanceCodegen.ts index 1369c654f..c852f1dde 100644 --- a/packages/tests/integration/src/entities/codegen/BookAdvanceCodegen.ts +++ b/packages/tests/integration/src/entities/codegen/BookAdvanceCodegen.ts @@ -3,7 +3,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasOne, isLoaded, loadLens, @@ -218,12 +217,15 @@ export abstract class BookAdvanceCodegen extends BaseEntity { - const { relations } = getInstanceData(this); - return relations.book ??= hasOne(this as any as BookAdvance, bookMeta, "book", "advances"); + return this.__data.relations.book ??= hasOne(this as any as BookAdvance, bookMeta, "book", "advances"); } get publisher(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.publisher ??= hasOne(this as any as BookAdvance, publisherMeta, "publisher", "bookAdvances"); + return this.__data.relations.publisher ??= hasOne( + this as any as BookAdvance, + publisherMeta, + "publisher", + "bookAdvances", + ); } } diff --git a/packages/tests/integration/src/entities/codegen/BookCodegen.ts b/packages/tests/integration/src/entities/codegen/BookCodegen.ts index ec135e562..4831127f9 100644 --- a/packages/tests/integration/src/entities/codegen/BookCodegen.ts +++ b/packages/tests/integration/src/entities/codegen/BookCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasMany, hasManyToMany, hasOne, @@ -296,8 +295,7 @@ export abstract class BookCodegen extends BaseEntity impl } get advances(): Collection { - const { relations } = getInstanceData(this); - return relations.advances ??= hasMany( + return this.__data.relations.advances ??= hasMany( this as any as Book, bookAdvanceMeta, "advances", @@ -308,13 +306,18 @@ export abstract class BookCodegen extends BaseEntity impl } get reviews(): Collection { - const { relations } = getInstanceData(this); - return relations.reviews ??= hasMany(this as any as Book, bookReviewMeta, "reviews", "book", "book_id", undefined); + return this.__data.relations.reviews ??= hasMany( + this as any as Book, + bookReviewMeta, + "reviews", + "book", + "book_id", + undefined, + ); } get comments(): Collection { - const { relations } = getInstanceData(this); - return relations.comments ??= hasMany( + return this.__data.relations.comments ??= hasMany( this as any as Book, commentMeta, "comments", @@ -325,13 +328,11 @@ export abstract class BookCodegen extends BaseEntity impl } get author(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.author ??= hasOne(this as any as Book, authorMeta, "author", "books"); + return this.__data.relations.author ??= hasOne(this as any as Book, authorMeta, "author", "books"); } get currentDraftAuthor(): OneToOneReference { - const { relations } = getInstanceData(this); - return relations.currentDraftAuthor ??= hasOneToOne( + return this.__data.relations.currentDraftAuthor ??= hasOneToOne( this as any as Book, authorMeta, "currentDraftAuthor", @@ -341,13 +342,11 @@ export abstract class BookCodegen extends BaseEntity impl } get image(): OneToOneReference { - const { relations } = getInstanceData(this); - return relations.image ??= hasOneToOne(this as any as Book, imageMeta, "image", "book", "book_id"); + return this.__data.relations.image ??= hasOneToOne(this as any as Book, imageMeta, "image", "book", "book_id"); } get tags(): Collection { - const { relations } = getInstanceData(this); - return relations.tags ??= hasManyToMany( + return this.__data.relations.tags ??= hasManyToMany( this as any as Book, "books_to_tags", "tags", diff --git a/packages/tests/integration/src/entities/codegen/BookReviewCodegen.ts b/packages/tests/integration/src/entities/codegen/BookReviewCodegen.ts index ec2e6ae52..64ecf6cbb 100644 --- a/packages/tests/integration/src/entities/codegen/BookReviewCodegen.ts +++ b/packages/tests/integration/src/entities/codegen/BookReviewCodegen.ts @@ -3,7 +3,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasManyToMany, hasOne, hasOneToOne, @@ -231,18 +230,15 @@ export abstract class BookReviewCodegen extends BaseEntity { - const { relations } = getInstanceData(this); - return relations.book ??= hasOne(this as any as BookReview, bookMeta, "book", "reviews"); + return this.__data.relations.book ??= hasOne(this as any as BookReview, bookMeta, "book", "reviews"); } get critic(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.critic ??= hasOne(this as any as BookReview, criticMeta, "critic", "bookReviews"); + return this.__data.relations.critic ??= hasOne(this as any as BookReview, criticMeta, "critic", "bookReviews"); } get comment(): OneToOneReference { - const { relations } = getInstanceData(this); - return relations.comment ??= hasOneToOne( + return this.__data.relations.comment ??= hasOneToOne( this as any as BookReview, commentMeta, "comment", @@ -252,8 +248,7 @@ export abstract class BookReviewCodegen extends BaseEntity { - const { relations } = getInstanceData(this); - return relations.tags ??= hasManyToMany( + return this.__data.relations.tags ??= hasManyToMany( this as any as BookReview, "book_reviews_to_tags", "tags", diff --git a/packages/tests/integration/src/entities/codegen/ChildCodegen.ts b/packages/tests/integration/src/entities/codegen/ChildCodegen.ts index 114af65d5..ca879a8dc 100644 --- a/packages/tests/integration/src/entities/codegen/ChildCodegen.ts +++ b/packages/tests/integration/src/entities/codegen/ChildCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasMany, isLoaded, loadLens, @@ -178,8 +177,7 @@ export abstract class ChildCodegen extends BaseEntity imp } get groups(): Collection { - const { relations } = getInstanceData(this); - return relations.groups ??= hasMany( + return this.__data.relations.groups ??= hasMany( this as any as Child, childGroupMeta, "groups", diff --git a/packages/tests/integration/src/entities/codegen/ChildGroupCodegen.ts b/packages/tests/integration/src/entities/codegen/ChildGroupCodegen.ts index 319b5bd05..a5f2fd223 100644 --- a/packages/tests/integration/src/entities/codegen/ChildGroupCodegen.ts +++ b/packages/tests/integration/src/entities/codegen/ChildGroupCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasMany, hasOne, isLoaded, @@ -207,8 +206,7 @@ export abstract class ChildGroupCodegen extends BaseEntity { - const { relations } = getInstanceData(this); - return relations.childItems ??= hasMany( + return this.__data.relations.childItems ??= hasMany( this as any as ChildGroup, childItemMeta, "childItems", @@ -219,12 +217,20 @@ export abstract class ChildGroupCodegen extends BaseEntity { - const { relations } = getInstanceData(this); - return relations.childGroupId ??= hasOne(this as any as ChildGroup, childMeta, "childGroupId", "groups"); + return this.__data.relations.childGroupId ??= hasOne( + this as any as ChildGroup, + childMeta, + "childGroupId", + "groups", + ); } get parentGroup(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.parentGroup ??= hasOne(this as any as ChildGroup, parentGroupMeta, "parentGroup", "childGroups"); + return this.__data.relations.parentGroup ??= hasOne( + this as any as ChildGroup, + parentGroupMeta, + "parentGroup", + "childGroups", + ); } } diff --git a/packages/tests/integration/src/entities/codegen/ChildItemCodegen.ts b/packages/tests/integration/src/entities/codegen/ChildItemCodegen.ts index ff9f1d757..2a65a9587 100644 --- a/packages/tests/integration/src/entities/codegen/ChildItemCodegen.ts +++ b/packages/tests/integration/src/entities/codegen/ChildItemCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasOne, isLoaded, loadLens, @@ -199,12 +198,20 @@ export abstract class ChildItemCodegen extends BaseEntity } get childGroup(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.childGroup ??= hasOne(this as any as ChildItem, childGroupMeta, "childGroup", "childItems"); + return this.__data.relations.childGroup ??= hasOne( + this as any as ChildItem, + childGroupMeta, + "childGroup", + "childItems", + ); } get parentItem(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.parentItem ??= hasOne(this as any as ChildItem, parentItemMeta, "parentItem", "childItems"); + return this.__data.relations.parentItem ??= hasOne( + this as any as ChildItem, + parentItemMeta, + "parentItem", + "childItems", + ); } } diff --git a/packages/tests/integration/src/entities/codegen/CommentCodegen.ts b/packages/tests/integration/src/entities/codegen/CommentCodegen.ts index 8cec81fcb..7217cdc94 100644 --- a/packages/tests/integration/src/entities/codegen/CommentCodegen.ts +++ b/packages/tests/integration/src/entities/codegen/CommentCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasManyToMany, hasOne, hasOnePolymorphic, @@ -225,13 +224,11 @@ export abstract class CommentCodegen extends BaseEntity i } get user(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.user ??= hasOne(this as any as Comment, userMeta, "user", "createdComments"); + return this.__data.relations.user ??= hasOne(this as any as Comment, userMeta, "user", "createdComments"); } get likedByUsers(): Collection { - const { relations } = getInstanceData(this); - return relations.likedByUsers ??= hasManyToMany( + return this.__data.relations.likedByUsers ??= hasManyToMany( this as any as Comment, "users_to_comments", "likedByUsers", @@ -243,7 +240,6 @@ export abstract class CommentCodegen extends BaseEntity i } get parent(): PolymorphicReference { - const { relations } = getInstanceData(this); - return relations.parent ??= hasOnePolymorphic(this as any as Comment, "parent"); + return this.__data.relations.parent ??= hasOnePolymorphic(this as any as Comment, "parent"); } } diff --git a/packages/tests/integration/src/entities/codegen/CriticCodegen.ts b/packages/tests/integration/src/entities/codegen/CriticCodegen.ts index e00b786d5..0ab2bf5cb 100644 --- a/packages/tests/integration/src/entities/codegen/CriticCodegen.ts +++ b/packages/tests/integration/src/entities/codegen/CriticCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasMany, hasOne, hasOneToOne, @@ -220,8 +219,7 @@ export abstract class CriticCodegen extends BaseEntity im } get bookReviews(): Collection { - const { relations } = getInstanceData(this); - return relations.bookReviews ??= hasMany( + return this.__data.relations.bookReviews ??= hasMany( this as any as Critic, bookReviewMeta, "bookReviews", @@ -232,8 +230,7 @@ export abstract class CriticCodegen extends BaseEntity im } get favoriteLargePublisher(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.favoriteLargePublisher ??= hasOne( + return this.__data.relations.favoriteLargePublisher ??= hasOne( this as any as Critic, largePublisherMeta, "favoriteLargePublisher", @@ -242,13 +239,11 @@ export abstract class CriticCodegen extends BaseEntity im } get group(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.group ??= hasOne(this as any as Critic, publisherGroupMeta, "group", "critics"); + return this.__data.relations.group ??= hasOne(this as any as Critic, publisherGroupMeta, "group", "critics"); } get criticColumn(): OneToOneReference { - const { relations } = getInstanceData(this); - return relations.criticColumn ??= hasOneToOne( + return this.__data.relations.criticColumn ??= hasOneToOne( this as any as Critic, criticColumnMeta, "criticColumn", diff --git a/packages/tests/integration/src/entities/codegen/CriticColumnCodegen.ts b/packages/tests/integration/src/entities/codegen/CriticColumnCodegen.ts index 10ea64be7..ad8d4a4d9 100644 --- a/packages/tests/integration/src/entities/codegen/CriticColumnCodegen.ts +++ b/packages/tests/integration/src/entities/codegen/CriticColumnCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasOne, isLoaded, loadLens, @@ -184,7 +183,6 @@ export abstract class CriticColumnCodegen extends BaseEntity { - const { relations } = getInstanceData(this); - return relations.critic ??= hasOne(this as any as CriticColumn, criticMeta, "critic", "criticColumn"); + return this.__data.relations.critic ??= hasOne(this as any as CriticColumn, criticMeta, "critic", "criticColumn"); } } diff --git a/packages/tests/integration/src/entities/codegen/ImageCodegen.ts b/packages/tests/integration/src/entities/codegen/ImageCodegen.ts index 5c4df5be7..76253a9f4 100644 --- a/packages/tests/integration/src/entities/codegen/ImageCodegen.ts +++ b/packages/tests/integration/src/entities/codegen/ImageCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasOne, isLoaded, loadLens, @@ -237,17 +236,14 @@ export abstract class ImageCodegen extends BaseEntity imp } get author(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.author ??= hasOne(this as any as Image, authorMeta, "author", "image"); + return this.__data.relations.author ??= hasOne(this as any as Image, authorMeta, "author", "image"); } get book(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.book ??= hasOne(this as any as Image, bookMeta, "book", "image"); + return this.__data.relations.book ??= hasOne(this as any as Image, bookMeta, "book", "image"); } get publisher(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.publisher ??= hasOne(this as any as Image, publisherMeta, "publisher", "images"); + return this.__data.relations.publisher ??= hasOne(this as any as Image, publisherMeta, "publisher", "images"); } } diff --git a/packages/tests/integration/src/entities/codegen/LargePublisherCodegen.ts b/packages/tests/integration/src/entities/codegen/LargePublisherCodegen.ts index 411f69419..704923a2a 100644 --- a/packages/tests/integration/src/entities/codegen/LargePublisherCodegen.ts +++ b/packages/tests/integration/src/entities/codegen/LargePublisherCodegen.ts @@ -3,7 +3,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasMany, isLoaded, loadLens, @@ -193,8 +192,7 @@ export abstract class LargePublisherCodegen extends Publisher implements Entity } get critics(): Collection { - const { relations } = getInstanceData(this); - return relations.critics ??= hasMany( + return this.__data.relations.critics ??= hasMany( this as any as LargePublisher, criticMeta, "critics", @@ -205,8 +203,7 @@ export abstract class LargePublisherCodegen extends Publisher implements Entity } get users(): Collection { - const { relations } = getInstanceData(this); - return relations.users ??= hasMany( + return this.__data.relations.users ??= hasMany( this as any as LargePublisher, userMeta, "users", diff --git a/packages/tests/integration/src/entities/codegen/ParentGroupCodegen.ts b/packages/tests/integration/src/entities/codegen/ParentGroupCodegen.ts index f3e404ce8..cd3de8873 100644 --- a/packages/tests/integration/src/entities/codegen/ParentGroupCodegen.ts +++ b/packages/tests/integration/src/entities/codegen/ParentGroupCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasMany, isLoaded, loadLens, @@ -196,8 +195,7 @@ export abstract class ParentGroupCodegen extends BaseEntity { - const { relations } = getInstanceData(this); - return relations.childGroups ??= hasMany( + return this.__data.relations.childGroups ??= hasMany( this as any as ParentGroup, childGroupMeta, "childGroups", @@ -208,8 +206,7 @@ export abstract class ParentGroupCodegen extends BaseEntity { - const { relations } = getInstanceData(this); - return relations.parentItems ??= hasMany( + return this.__data.relations.parentItems ??= hasMany( this as any as ParentGroup, parentItemMeta, "parentItems", diff --git a/packages/tests/integration/src/entities/codegen/ParentItemCodegen.ts b/packages/tests/integration/src/entities/codegen/ParentItemCodegen.ts index 2935983d1..7707d4dd2 100644 --- a/packages/tests/integration/src/entities/codegen/ParentItemCodegen.ts +++ b/packages/tests/integration/src/entities/codegen/ParentItemCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasMany, hasOne, isLoaded, @@ -198,8 +197,7 @@ export abstract class ParentItemCodegen extends BaseEntity { - const { relations } = getInstanceData(this); - return relations.childItems ??= hasMany( + return this.__data.relations.childItems ??= hasMany( this as any as ParentItem, childItemMeta, "childItems", @@ -210,7 +208,11 @@ export abstract class ParentItemCodegen extends BaseEntity { - const { relations } = getInstanceData(this); - return relations.parentGroup ??= hasOne(this as any as ParentItem, parentGroupMeta, "parentGroup", "parentItems"); + return this.__data.relations.parentGroup ??= hasOne( + this as any as ParentItem, + parentGroupMeta, + "parentGroup", + "parentItems", + ); } } diff --git a/packages/tests/integration/src/entities/codegen/PublisherCodegen.ts b/packages/tests/integration/src/entities/codegen/PublisherCodegen.ts index ffc9f4179..74de4892f 100644 --- a/packages/tests/integration/src/entities/codegen/PublisherCodegen.ts +++ b/packages/tests/integration/src/entities/codegen/PublisherCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasMany, hasManyToMany, hasOne, @@ -375,8 +374,7 @@ export abstract class PublisherCodegen extends BaseEntity } get authors(): Collection { - const { relations } = getInstanceData(this); - return relations.authors ??= hasMany( + return this.__data.relations.authors ??= hasMany( this as any as Publisher, authorMeta, "authors", @@ -387,8 +385,7 @@ export abstract class PublisherCodegen extends BaseEntity } get bookAdvances(): Collection { - const { relations } = getInstanceData(this); - return relations.bookAdvances ??= hasMany( + return this.__data.relations.bookAdvances ??= hasMany( this as any as Publisher, bookAdvanceMeta, "bookAdvances", @@ -399,8 +396,7 @@ export abstract class PublisherCodegen extends BaseEntity } get comments(): Collection { - const { relations } = getInstanceData(this); - return relations.comments ??= hasMany( + return this.__data.relations.comments ??= hasMany( this as any as Publisher, commentMeta, "comments", @@ -411,8 +407,7 @@ export abstract class PublisherCodegen extends BaseEntity } get images(): Collection { - const { relations } = getInstanceData(this); - return relations.images ??= hasMany( + return this.__data.relations.images ??= hasMany( this as any as Publisher, imageMeta, "images", @@ -423,13 +418,11 @@ export abstract class PublisherCodegen extends BaseEntity } get group(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.group ??= hasOne(this as any as Publisher, publisherGroupMeta, "group", "publishers"); + return this.__data.relations.group ??= hasOne(this as any as Publisher, publisherGroupMeta, "group", "publishers"); } get tags(): Collection { - const { relations } = getInstanceData(this); - return relations.tags ??= hasManyToMany( + return this.__data.relations.tags ??= hasManyToMany( this as any as Publisher, "publishers_to_tags", "tags", @@ -441,8 +434,7 @@ export abstract class PublisherCodegen extends BaseEntity } get tasks(): Collection { - const { relations } = getInstanceData(this); - return relations.tasks ??= hasManyToMany( + return this.__data.relations.tasks ??= hasManyToMany( this as any as Publisher, "tasks_to_publishers", "tasks", diff --git a/packages/tests/integration/src/entities/codegen/PublisherGroupCodegen.ts b/packages/tests/integration/src/entities/codegen/PublisherGroupCodegen.ts index e25758927..48bc00160 100644 --- a/packages/tests/integration/src/entities/codegen/PublisherGroupCodegen.ts +++ b/packages/tests/integration/src/entities/codegen/PublisherGroupCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasLargeMany, hasMany, isLoaded, @@ -199,8 +198,7 @@ export abstract class PublisherGroupCodegen extends BaseEntity { - const { relations } = getInstanceData(this); - return relations.publishers ??= hasMany( + return this.__data.relations.publishers ??= hasMany( this as any as PublisherGroup, publisherMeta, "publishers", @@ -211,8 +209,7 @@ export abstract class PublisherGroupCodegen extends BaseEntity { - const { relations } = getInstanceData(this); - return relations.critics ??= hasLargeMany( + return this.__data.relations.critics ??= hasLargeMany( this as any as PublisherGroup, criticMeta, "critics", diff --git a/packages/tests/integration/src/entities/codegen/SmallPublisherCodegen.ts b/packages/tests/integration/src/entities/codegen/SmallPublisherCodegen.ts index eb4178bc5..804250dfd 100644 --- a/packages/tests/integration/src/entities/codegen/SmallPublisherCodegen.ts +++ b/packages/tests/integration/src/entities/codegen/SmallPublisherCodegen.ts @@ -3,7 +3,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasMany, isLoaded, loadLens, @@ -196,8 +195,7 @@ export abstract class SmallPublisherCodegen extends Publisher implements Entity } get users(): Collection { - const { relations } = getInstanceData(this); - return relations.users ??= hasMany( + return this.__data.relations.users ??= hasMany( this as any as SmallPublisher, userMeta, "users", diff --git a/packages/tests/integration/src/entities/codegen/TagCodegen.ts b/packages/tests/integration/src/entities/codegen/TagCodegen.ts index 0b63a83b8..8892495ff 100644 --- a/packages/tests/integration/src/entities/codegen/TagCodegen.ts +++ b/packages/tests/integration/src/entities/codegen/TagCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasManyToMany, isLoaded, loadLens, @@ -210,8 +209,7 @@ export abstract class TagCodegen extends BaseEntity imple } get authors(): Collection { - const { relations } = getInstanceData(this); - return relations.authors ??= hasManyToMany( + return this.__data.relations.authors ??= hasManyToMany( this as any as Tag, "authors_to_tags", "authors", @@ -223,8 +221,7 @@ export abstract class TagCodegen extends BaseEntity imple } get books(): Collection { - const { relations } = getInstanceData(this); - return relations.books ??= hasManyToMany( + return this.__data.relations.books ??= hasManyToMany( this as any as Tag, "books_to_tags", "books", @@ -236,8 +233,7 @@ export abstract class TagCodegen extends BaseEntity imple } get bookReviews(): Collection { - const { relations } = getInstanceData(this); - return relations.bookReviews ??= hasManyToMany( + return this.__data.relations.bookReviews ??= hasManyToMany( this as any as Tag, "book_reviews_to_tags", "bookReviews", @@ -249,8 +245,7 @@ export abstract class TagCodegen extends BaseEntity imple } get publishers(): Collection { - const { relations } = getInstanceData(this); - return relations.publishers ??= hasManyToMany( + return this.__data.relations.publishers ??= hasManyToMany( this as any as Tag, "publishers_to_tags", "publishers", @@ -262,8 +257,7 @@ export abstract class TagCodegen extends BaseEntity imple } get tasks(): Collection { - const { relations } = getInstanceData(this); - return relations.tasks ??= hasManyToMany( + return this.__data.relations.tasks ??= hasManyToMany( this as any as Tag, "task_to_tags", "tasks", diff --git a/packages/tests/integration/src/entities/codegen/TaskCodegen.ts b/packages/tests/integration/src/entities/codegen/TaskCodegen.ts index fbf719e17..3a27c9b90 100644 --- a/packages/tests/integration/src/entities/codegen/TaskCodegen.ts +++ b/packages/tests/integration/src/entities/codegen/TaskCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasMany, hasManyToMany, isLoaded, @@ -247,8 +246,7 @@ export abstract class TaskCodegen extends BaseEntity impl } get taskTaskItems(): Collection { - const { relations } = getInstanceData(this); - return relations.taskTaskItems ??= hasMany( + return this.__data.relations.taskTaskItems ??= hasMany( this as any as Task, taskItemMeta, "taskTaskItems", @@ -259,8 +257,7 @@ export abstract class TaskCodegen extends BaseEntity impl } get tags(): Collection { - const { relations } = getInstanceData(this); - return relations.tags ??= hasManyToMany( + return this.__data.relations.tags ??= hasManyToMany( this as any as Task, "task_to_tags", "tags", diff --git a/packages/tests/integration/src/entities/codegen/TaskItemCodegen.ts b/packages/tests/integration/src/entities/codegen/TaskItemCodegen.ts index 3950232a0..8c68528e4 100644 --- a/packages/tests/integration/src/entities/codegen/TaskItemCodegen.ts +++ b/packages/tests/integration/src/entities/codegen/TaskItemCodegen.ts @@ -3,7 +3,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasOne, isLoaded, loadLens, @@ -191,17 +190,24 @@ export abstract class TaskItemCodegen extends BaseEntity } get newTask(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.newTask ??= hasOne(this as any as TaskItem, taskNewMeta, "newTask", "newTaskTaskItems"); + return this.__data.relations.newTask ??= hasOne( + this as any as TaskItem, + taskNewMeta, + "newTask", + "newTaskTaskItems", + ); } get oldTask(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.oldTask ??= hasOne(this as any as TaskItem, taskOldMeta, "oldTask", "oldTaskTaskItems"); + return this.__data.relations.oldTask ??= hasOne( + this as any as TaskItem, + taskOldMeta, + "oldTask", + "oldTaskTaskItems", + ); } get task(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.task ??= hasOne(this as any as TaskItem, taskMeta, "task", "taskTaskItems"); + return this.__data.relations.task ??= hasOne(this as any as TaskItem, taskMeta, "task", "taskTaskItems"); } } diff --git a/packages/tests/integration/src/entities/codegen/TaskNewCodegen.ts b/packages/tests/integration/src/entities/codegen/TaskNewCodegen.ts index 4ae4f4fb9..4503a2864 100644 --- a/packages/tests/integration/src/entities/codegen/TaskNewCodegen.ts +++ b/packages/tests/integration/src/entities/codegen/TaskNewCodegen.ts @@ -2,7 +2,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasMany, hasOne, isLoaded, @@ -182,8 +181,7 @@ export abstract class TaskNewCodegen extends Task implements Entity { } get newTaskTaskItems(): Collection { - const { relations } = getInstanceData(this); - return relations.newTaskTaskItems ??= hasMany( + return this.__data.relations.newTaskTaskItems ??= hasMany( this as any as TaskNew, taskItemMeta, "newTaskTaskItems", @@ -194,7 +192,11 @@ export abstract class TaskNewCodegen extends Task implements Entity { } get specialNewAuthor(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.specialNewAuthor ??= hasOne(this as any as TaskNew, authorMeta, "specialNewAuthor", "tasks"); + return this.__data.relations.specialNewAuthor ??= hasOne( + this as any as TaskNew, + authorMeta, + "specialNewAuthor", + "tasks", + ); } } diff --git a/packages/tests/integration/src/entities/codegen/TaskOldCodegen.ts b/packages/tests/integration/src/entities/codegen/TaskOldCodegen.ts index d3923f144..6e5f2585a 100644 --- a/packages/tests/integration/src/entities/codegen/TaskOldCodegen.ts +++ b/packages/tests/integration/src/entities/codegen/TaskOldCodegen.ts @@ -2,7 +2,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasMany, hasManyToMany, hasOne, @@ -202,8 +201,7 @@ export abstract class TaskOldCodegen extends Task implements Entity { } get comments(): Collection { - const { relations } = getInstanceData(this); - return relations.comments ??= hasMany( + return this.__data.relations.comments ??= hasMany( this as any as TaskOld, commentMeta, "comments", @@ -214,8 +212,7 @@ export abstract class TaskOldCodegen extends Task implements Entity { } get oldTaskTaskItems(): Collection { - const { relations } = getInstanceData(this); - return relations.oldTaskTaskItems ??= hasMany( + return this.__data.relations.oldTaskTaskItems ??= hasMany( this as any as TaskOld, taskItemMeta, "oldTaskTaskItems", @@ -226,8 +223,7 @@ export abstract class TaskOldCodegen extends Task implements Entity { } get tasks(): Collection { - const { relations } = getInstanceData(this); - return relations.tasks ??= hasMany( + return this.__data.relations.tasks ??= hasMany( this as any as TaskOld, taskOldMeta, "tasks", @@ -238,13 +234,16 @@ export abstract class TaskOldCodegen extends Task implements Entity { } get parentOldTask(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.parentOldTask ??= hasOne(this as any as TaskOld, taskOldMeta, "parentOldTask", "tasks"); + return this.__data.relations.parentOldTask ??= hasOne( + this as any as TaskOld, + taskOldMeta, + "parentOldTask", + "tasks", + ); } get publishers(): Collection { - const { relations } = getInstanceData(this); - return relations.publishers ??= hasManyToMany( + return this.__data.relations.publishers ??= hasManyToMany( this as any as TaskOld, "tasks_to_publishers", "publishers", diff --git a/packages/tests/integration/src/entities/codegen/UserCodegen.ts b/packages/tests/integration/src/entities/codegen/UserCodegen.ts index 654da9c09..43f05a667 100644 --- a/packages/tests/integration/src/entities/codegen/UserCodegen.ts +++ b/packages/tests/integration/src/entities/codegen/UserCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasMany, hasManyToMany, hasOne, @@ -297,8 +296,7 @@ export abstract class UserCodegen extends BaseEntity impl } get createdComments(): Collection { - const { relations } = getInstanceData(this); - return relations.createdComments ??= hasMany( + return this.__data.relations.createdComments ??= hasMany( this as any as User, commentMeta, "createdComments", @@ -309,13 +307,16 @@ export abstract class UserCodegen extends BaseEntity impl } get authorManyToOne(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.authorManyToOne ??= hasOne(this as any as User, authorMeta, "authorManyToOne", "userOneToOne"); + return this.__data.relations.authorManyToOne ??= hasOne( + this as any as User, + authorMeta, + "authorManyToOne", + "userOneToOne", + ); } get likedComments(): Collection { - const { relations } = getInstanceData(this); - return relations.likedComments ??= hasManyToMany( + return this.__data.relations.likedComments ??= hasManyToMany( this as any as User, "users_to_comments", "likedComments", @@ -327,7 +328,6 @@ export abstract class UserCodegen extends BaseEntity impl } get favoritePublisher(): PolymorphicReference { - const { relations } = getInstanceData(this); - return relations.favoritePublisher ??= hasOnePolymorphic(this as any as User, "favoritePublisher"); + return this.__data.relations.favoritePublisher ??= hasOnePolymorphic(this as any as User, "favoritePublisher"); } } diff --git a/packages/tests/integration/src/getProperties.test.ts b/packages/tests/integration/src/getProperties.test.ts index f74f2aecf..085a9e0ed 100644 --- a/packages/tests/integration/src/getProperties.test.ts +++ b/packages/tests/integration/src/getProperties.test.ts @@ -3,12 +3,12 @@ import { AsyncPropertyImpl, CustomCollection, CustomReference, + getProperties, ManyToManyCollection, ManyToOneReferenceImpl, OneToManyCollection, OneToOneReferenceImpl, UnknownProperty, - getProperties, } from "joist-orm"; describe("getProperties", () => { @@ -66,20 +66,47 @@ describe("getProperties", () => { }); it("includes non-relations", () => { - expect(Object.keys(getProperties(authorMeta))).toEqual( - expect.arrayContaining([ - "withLoadedBooks", - "initials", - "fullName", - "isPopular", - "hasBooks", - "authors", - "books", - "mentor", - "publisher", - "image", - ]), - ); + expect(Object.keys(getProperties(authorMeta))).toMatchInlineSnapshot(` + [ + "reviews", + "reviewedBooks", + "latestComment", + "favoriteBook", + "numberOfBooks2", + "latestComment2", + "allPublisherAuthorNames", + "latestComments", + "commentParentInfo", + "booksWithTitle", + "booksTitles", + "hasLowerCaseFirstName", + "withLoadedBooks", + "fullName", + "fullName2", + "hasBooks", + "setWasEverPopular", + "isFew", + "isLot", + "favoriteColorsDetails", + "isRed", + "isGreen", + "isBlue", + "isCircle", + "isSquare", + "isTriangle", + "authors", + "schedules", + "books", + "comments", + "tasks", + "mentor", + "currentDraftBook", + "publisher", + "image", + "userOneToOne", + "tags", + ] + `); }); it("does not include fullNonReactiveAccess", () => { diff --git a/packages/tests/integration/tsconfig.json b/packages/tests/integration/tsconfig.json index 4e7405ab0..f7f1d89ba 100644 --- a/packages/tests/integration/tsconfig.json +++ b/packages/tests/integration/tsconfig.json @@ -8,6 +8,7 @@ "@src/*": ["src/*"], "src/*": ["src/*"] }, + "plugins": [{ "transform": "../../transform-properties/src/index.ts", "type": "raw" }] }, "include": ["./src", "./migrations"], "references": [ diff --git a/packages/tests/number-ids/joist-config.json b/packages/tests/number-ids/joist-config.json index 48fa5f518..b15ddd315 100644 --- a/packages/tests/number-ids/joist-config.json +++ b/packages/tests/number-ids/joist-config.json @@ -4,5 +4,5 @@ "entities": { "Author": { "tag": "a" }, "Book": { "tag": "b" } }, "entitiesDirectory": "./src/entities", "idType": "number", - "version": "1.160.4" + "version": "1.162.0" } diff --git a/packages/tests/number-ids/src/entities/codegen/AuthorCodegen.ts b/packages/tests/number-ids/src/entities/codegen/AuthorCodegen.ts index 5063615d1..8618dab24 100644 --- a/packages/tests/number-ids/src/entities/codegen/AuthorCodegen.ts +++ b/packages/tests/number-ids/src/entities/codegen/AuthorCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasMany, isLoaded, loadLens, @@ -192,7 +191,13 @@ export abstract class AuthorCodegen extends BaseEntity im } get books(): Collection { - const { relations } = getInstanceData(this); - return relations.books ??= hasMany(this as any as Author, bookMeta, "books", "author", "author_id", undefined); + return this.__data.relations.books ??= hasMany( + this as any as Author, + bookMeta, + "books", + "author", + "author_id", + undefined, + ); } } diff --git a/packages/tests/number-ids/src/entities/codegen/BookCodegen.ts b/packages/tests/number-ids/src/entities/codegen/BookCodegen.ts index f8884c114..567778b5e 100644 --- a/packages/tests/number-ids/src/entities/codegen/BookCodegen.ts +++ b/packages/tests/number-ids/src/entities/codegen/BookCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasOne, isLoaded, loadLens, @@ -182,7 +181,6 @@ export abstract class BookCodegen extends BaseEntity impl } get author(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.author ??= hasOne(this as any as Book, authorMeta, "author", "books"); + return this.__data.relations.author ??= hasOne(this as any as Book, authorMeta, "author", "books"); } } diff --git a/packages/tests/schema-misc/joist-config.json b/packages/tests/schema-misc/joist-config.json index bb2ef3a2b..091b6a3b4 100644 --- a/packages/tests/schema-misc/joist-config.json +++ b/packages/tests/schema-misc/joist-config.json @@ -15,5 +15,5 @@ "createdAt": { "names": ["created_at", "createdAt"], "required": false }, "updatedAt": { "names": ["updated_at", "updatedAt"], "required": false } }, - "version": "1.160.4" + "version": "1.162.0" } diff --git a/packages/tests/schema-misc/src/entities/codegen/ArtistCodegen.ts b/packages/tests/schema-misc/src/entities/codegen/ArtistCodegen.ts index ed7c3324b..877536a3d 100644 --- a/packages/tests/schema-misc/src/entities/codegen/ArtistCodegen.ts +++ b/packages/tests/schema-misc/src/entities/codegen/ArtistCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasMany, isLoaded, loadLens, @@ -193,8 +192,7 @@ export abstract class ArtistCodegen extends BaseEntity im } get paintings(): Collection { - const { relations } = getInstanceData(this); - return relations.paintings ??= hasMany( + return this.__data.relations.paintings ??= hasMany( this as any as Artist, paintingMeta, "paintings", diff --git a/packages/tests/schema-misc/src/entities/codegen/AuthorCodegen.ts b/packages/tests/schema-misc/src/entities/codegen/AuthorCodegen.ts index 07452bcca..9b3cb81bd 100644 --- a/packages/tests/schema-misc/src/entities/codegen/AuthorCodegen.ts +++ b/packages/tests/schema-misc/src/entities/codegen/AuthorCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasMany, isLoaded, loadLens, @@ -207,7 +206,13 @@ export abstract class AuthorCodegen extends BaseEntity im } get books(): Collection { - const { relations } = getInstanceData(this); - return relations.books ??= hasMany(this as any as Author, bookMeta, "books", "author", "authorId", undefined); + return this.__data.relations.books ??= hasMany( + this as any as Author, + bookMeta, + "books", + "author", + "authorId", + undefined, + ); } } diff --git a/packages/tests/schema-misc/src/entities/codegen/BookCodegen.ts b/packages/tests/schema-misc/src/entities/codegen/BookCodegen.ts index cb2af64d7..a0bcf6722 100644 --- a/packages/tests/schema-misc/src/entities/codegen/BookCodegen.ts +++ b/packages/tests/schema-misc/src/entities/codegen/BookCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasOne, isLoaded, loadLens, @@ -164,7 +163,6 @@ export abstract class BookCodegen extends BaseEntity impl } get author(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.author ??= hasOne(this as any as Book, authorMeta, "author", "books"); + return this.__data.relations.author ??= hasOne(this as any as Book, authorMeta, "author", "books"); } } diff --git a/packages/tests/schema-misc/src/entities/codegen/PaintingCodegen.ts b/packages/tests/schema-misc/src/entities/codegen/PaintingCodegen.ts index 8416a6311..d35cd77e7 100644 --- a/packages/tests/schema-misc/src/entities/codegen/PaintingCodegen.ts +++ b/packages/tests/schema-misc/src/entities/codegen/PaintingCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasOne, isLoaded, loadLens, @@ -182,7 +181,6 @@ export abstract class PaintingCodegen extends BaseEntity } get artist(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.artist ??= hasOne(this as any as Painting, artistMeta, "artist", "paintings"); + return this.__data.relations.artist ??= hasOne(this as any as Painting, artistMeta, "artist", "paintings"); } } diff --git a/packages/tests/untagged-ids/joist-config.json b/packages/tests/untagged-ids/joist-config.json index 51a809954..e65461ad5 100644 --- a/packages/tests/untagged-ids/joist-config.json +++ b/packages/tests/untagged-ids/joist-config.json @@ -8,5 +8,5 @@ }, "entitiesDirectory": "./src/entities", "idType": "untagged-string", - "version": "1.160.4" + "version": "1.162.0" } diff --git a/packages/tests/untagged-ids/src/entities/codegen/AuthorCodegen.ts b/packages/tests/untagged-ids/src/entities/codegen/AuthorCodegen.ts index 13437374e..f70d135f9 100644 --- a/packages/tests/untagged-ids/src/entities/codegen/AuthorCodegen.ts +++ b/packages/tests/untagged-ids/src/entities/codegen/AuthorCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasMany, isLoaded, loadLens, @@ -196,13 +195,18 @@ export abstract class AuthorCodegen extends BaseEntity im } get books(): Collection { - const { relations } = getInstanceData(this); - return relations.books ??= hasMany(this as any as Author, bookMeta, "books", "author", "author_id", undefined); + return this.__data.relations.books ??= hasMany( + this as any as Author, + bookMeta, + "books", + "author", + "author_id", + undefined, + ); } get comments(): Collection { - const { relations } = getInstanceData(this); - return relations.comments ??= hasMany( + return this.__data.relations.comments ??= hasMany( this as any as Author, commentMeta, "comments", diff --git a/packages/tests/untagged-ids/src/entities/codegen/BookCodegen.ts b/packages/tests/untagged-ids/src/entities/codegen/BookCodegen.ts index a8d5f15e8..8351015de 100644 --- a/packages/tests/untagged-ids/src/entities/codegen/BookCodegen.ts +++ b/packages/tests/untagged-ids/src/entities/codegen/BookCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasMany, hasOne, isLoaded, @@ -188,8 +187,7 @@ export abstract class BookCodegen extends BaseEntity impl } get comments(): Collection { - const { relations } = getInstanceData(this); - return relations.comments ??= hasMany( + return this.__data.relations.comments ??= hasMany( this as any as Book, commentMeta, "comments", @@ -200,7 +198,6 @@ export abstract class BookCodegen extends BaseEntity impl } get author(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.author ??= hasOne(this as any as Book, authorMeta, "author", "books"); + return this.__data.relations.author ??= hasOne(this as any as Book, authorMeta, "author", "books"); } } diff --git a/packages/tests/untagged-ids/src/entities/codegen/CommentCodegen.ts b/packages/tests/untagged-ids/src/entities/codegen/CommentCodegen.ts index 0879688ad..85d0ff09f 100644 --- a/packages/tests/untagged-ids/src/entities/codegen/CommentCodegen.ts +++ b/packages/tests/untagged-ids/src/entities/codegen/CommentCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasOnePolymorphic, isEntity, isLoaded, @@ -190,7 +189,6 @@ export abstract class CommentCodegen extends BaseEntity i } get parent(): PolymorphicReference { - const { relations } = getInstanceData(this); - return relations.parent ??= hasOnePolymorphic(this as any as Comment, "parent"); + return this.__data.relations.parent ??= hasOnePolymorphic(this as any as Comment, "parent"); } } diff --git a/packages/tests/uuid-ids/joist-config.json b/packages/tests/uuid-ids/joist-config.json index 33646e783..a65409777 100644 --- a/packages/tests/uuid-ids/joist-config.json +++ b/packages/tests/uuid-ids/joist-config.json @@ -3,5 +3,5 @@ "contextType": "Context@src/context", "entities": { "Author": { "tag": "a" }, "Book": { "tag": "b" } }, "entitiesDirectory": "./src/entities", - "version": "1.160.4" + "version": "1.162.0" } diff --git a/packages/tests/uuid-ids/src/entities/codegen/AuthorCodegen.ts b/packages/tests/uuid-ids/src/entities/codegen/AuthorCodegen.ts index c0c507574..77b357cff 100644 --- a/packages/tests/uuid-ids/src/entities/codegen/AuthorCodegen.ts +++ b/packages/tests/uuid-ids/src/entities/codegen/AuthorCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasMany, isLoaded, loadLens, @@ -192,7 +191,13 @@ export abstract class AuthorCodegen extends BaseEntity im } get books(): Collection { - const { relations } = getInstanceData(this); - return relations.books ??= hasMany(this as any as Author, bookMeta, "books", "author", "author_id", undefined); + return this.__data.relations.books ??= hasMany( + this as any as Author, + bookMeta, + "books", + "author", + "author_id", + undefined, + ); } } diff --git a/packages/tests/uuid-ids/src/entities/codegen/BookCodegen.ts b/packages/tests/uuid-ids/src/entities/codegen/BookCodegen.ts index b0577e80e..967560bcd 100644 --- a/packages/tests/uuid-ids/src/entities/codegen/BookCodegen.ts +++ b/packages/tests/uuid-ids/src/entities/codegen/BookCodegen.ts @@ -4,7 +4,6 @@ import { ConfigApi, failNoIdYet, getField, - getInstanceData, hasOne, isLoaded, loadLens, @@ -218,7 +217,6 @@ export abstract class BookCodegen extends BaseEntity impl } get author(): ManyToOneReference { - const { relations } = getInstanceData(this); - return relations.author ??= hasOne(this as any as Book, authorMeta, "author", "books"); + return this.__data.relations.author ??= hasOne(this as any as Book, authorMeta, "author", "books"); } } diff --git a/packages/transform-properties/.npmignore b/packages/transform-properties/.npmignore new file mode 100644 index 000000000..cd06ab9af --- /dev/null +++ b/packages/transform-properties/.npmignore @@ -0,0 +1,3 @@ +* +!build/**/* +!src/**/* diff --git a/packages/transform-properties/jest.config.js b/packages/transform-properties/jest.config.js new file mode 100644 index 000000000..d359f868f --- /dev/null +++ b/packages/transform-properties/jest.config.js @@ -0,0 +1,18 @@ +module.exports = { + transform: { "^.+\\.tsx?$": "@swc/jest" }, + moduleNameMapper: { + "^@src/(.*)": "/src/$1", + "^src/(.*)": "/src/$1", + }, + testMatch: ["/src/**/*.test.(ts|tsx)"], + testEnvironment: "node", + maxConcurrency: 1, + resetMocks: true, + reporters: [ + "default", + [ + "jest-junit", + { outputDirectory: "../../artifacts", outputName: `junit-transforms.xml`, usePathForSuiteName: "true" }, + ], + ], +}; diff --git a/packages/transform-properties/package.json b/packages/transform-properties/package.json new file mode 100644 index 000000000..b8d54704a --- /dev/null +++ b/packages/transform-properties/package.json @@ -0,0 +1,26 @@ +{ + "name": "joist-transform-properties", + "version": "1.161.2", + "license": "MIT", + "main": "build/index.js", + "types": "build/index.d.ts", + "files": [ + "build" + ], + "scripts": { + "format": "prettier --write '{schema,migrations,src}/**/*.{ts,js,tsx,jsx,graphql}'", + "test": "jest" + }, + "devDependencies": { + "@swc/core": "^1.4.13", + "@swc/jest": "^0.2.36", + "@types/jest": "^29.5.12", + "@types/node": "^20.12.7", + "jest": "30.0.0-alpha.3", + "prettier": "^3.2.5", + "prettier-plugin-organize-imports": "^3.2.4", + "ts-node-dev": "^2.0.0", + "tsconfig-paths": "^4.2.0", + "typescript": "^5.4.5" + } +} diff --git a/packages/transform-properties/src/index.ts b/packages/transform-properties/src/index.ts new file mode 100644 index 000000000..56be8db5b --- /dev/null +++ b/packages/transform-properties/src/index.ts @@ -0,0 +1,3 @@ +import { transformer } from "./properties-transformer"; + +export default transformer; diff --git a/packages/transform-properties/src/properties-transformer.test.ts b/packages/transform-properties/src/properties-transformer.test.ts new file mode 100644 index 000000000..977249bdd --- /dev/null +++ b/packages/transform-properties/src/properties-transformer.test.ts @@ -0,0 +1,34 @@ +import ts from "typescript"; +import { transformer } from "./properties-transformer"; + +describe("properties-transformer", () => { + it("should rewrite async properties", () => { + const source = ` + class Author { + readonly numberOfBooks: AsyncProperty = hasAsyncProperty(() => { + return 1; + }); + } + `; + const result = compile(source); + expect(result).toMatchInlineSnapshot(` + "class Author { + get numberOfBooks() { return this.__data.relations.numberOfBooks ??= hasAsyncProperty(() => { + return 1; + }); } + } + " + `); + }); +}); + +function compile(source: string): string { + const result = ts.transpileModule(source, { + compilerOptions: { + module: ts.ModuleKind.CommonJS, + target: ts.ScriptTarget.ESNext, + }, + transformers: { before: [transformer] }, + }); + return result.outputText; +} diff --git a/packages/transform-properties/src/properties-transformer.ts b/packages/transform-properties/src/properties-transformer.ts new file mode 100644 index 000000000..56e487463 --- /dev/null +++ b/packages/transform-properties/src/properties-transformer.ts @@ -0,0 +1,49 @@ +import * as ts from "typescript"; +import { SourceFile } from "typescript"; + +export const transformer: ts.TransformerFactory = (ctx) => { + const { factory: f } = ctx; + + const visit: ts.Visitor = (node) => { + if (ts.isPropertyDeclaration(node) && node.initializer && shouldRewrite(node.type?.getText())) { + const getterName = node.name; + const getter = f.createGetAccessorDeclaration( + undefined, + getterName, + [], + node.type, + f.createBlock([ + f.createReturnStatement( + f.createBinaryExpression( + f.createPropertyAccessExpression( + f.createPropertyAccessExpression( + f.createPropertyAccessExpression(f.createThis(), f.createIdentifier("__data")), + f.createIdentifier("relations"), + ), + getterName.getText(), + ), + f.createToken(ts.SyntaxKind.QuestionQuestionEqualsToken), + node.initializer, + ), + ), + ]), + ); + return [getter]; + } + return ts.visitEachChild(node, visit, ctx); + }; + + return (sourceFile) => { + return ts.visitNode(sourceFile, visit) as SourceFile; + }; +}; + +function shouldRewrite(typeName: string | undefined): boolean { + return ( + !!typeName && + (typeName.startsWith("Reactive") || + typeName.startsWith("AsyncProperty<") || + typeName.startsWith("Collection<") || + typeName.startsWith("Reference<")) + ); +} diff --git a/packages/transform-properties/tsconfig.json b/packages/transform-properties/tsconfig.json new file mode 100644 index 000000000..ba0bde3a8 --- /dev/null +++ b/packages/transform-properties/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "outDir": "./build", + "module": "CommonJS", + "esModuleInterop": true, + "skipLibCheck": true, + "target": "ES2019", + "strict": true + }, + "include": ["src/*"], + "exclude": ["dist", "../node_modules"] +} diff --git a/tsconfig.json b/tsconfig.json index 1d2b523fc..ad7d25aa4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,6 +11,7 @@ { "path": "./packages/tests/schema-misc" }, { "path": "./packages/tests/uuid-ids" }, { "path": "./packages/test-utils" }, + { "path": "./packages/transform-properties"}, { "path": "./packages/utils" } ], "files": [], diff --git a/yarn.lock b/yarn.lock index 7e1ba78d5..672e929ec 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11262,12 +11262,14 @@ __metadata: joist-orm: "workspace:*" joist-plugin-join-preloading: "workspace:*" joist-test-utils: "workspace:*" + joist-transform-properties: "workspace:*" kelonio: "npm:^0.10.0" mitata: "npm:^0.1.11" postgres: "npm:^3.4.4" prettier: "npm:^3.2.5" prettier-plugin-organize-imports: "npm:^3.2.4" superstruct: "npm:0.15.5" + ts-patch: "npm:^3.1.2" tsconfig-paths: "npm:^4.2.0" tsx: "npm:^4.7.2" typescript: "npm:^5.4.5" @@ -11371,6 +11373,23 @@ __metadata: languageName: unknown linkType: soft +"joist-transform-properties@workspace:*, joist-transform-properties@workspace:packages/transform-properties": + version: 0.0.0-use.local + resolution: "joist-transform-properties@workspace:packages/transform-properties" + dependencies: + "@swc/core": "npm:^1.4.13" + "@swc/jest": "npm:^0.2.36" + "@types/jest": "npm:^29.5.12" + "@types/node": "npm:^20.12.7" + jest: "npm:30.0.0-alpha.3" + prettier: "npm:^3.2.5" + prettier-plugin-organize-imports: "npm:^3.2.4" + ts-node-dev: "npm:^2.0.0" + tsconfig-paths: "npm:^4.2.0" + typescript: "npm:^5.4.5" + languageName: unknown + linkType: soft + "joist-utils@workspace:*, joist-utils@workspace:packages/utils": version: 0.0.0-use.local resolution: "joist-utils@workspace:packages/utils"