From 04dbc2561d8d1b492b77843a36bf9a5095e37c58 Mon Sep 17 00:00:00 2001 From: ckvv Date: Thu, 7 Dec 2023 15:34:49 +0800 Subject: [PATCH 1/8] fix: support nested default exports with using dynamic import --- packages/core/src/import-models.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/src/import-models.ts b/packages/core/src/import-models.ts index 78902bcf19b2..3e38f72e3008 100644 --- a/packages/core/src/import-models.ts +++ b/packages/core/src/import-models.ts @@ -34,8 +34,8 @@ export async function importModels(globPaths: string | string[], modelMatch?: Mo } async function importModelNoGlob(url: string, modelMatch?: ModelMatch): Promise { - const module = await import(url); - + const { default: _default, ...args } = await import(url); + const module = { ..._default, ...args }; return Object.keys(module) .filter(exportName => { if (!isModelStatic(module[exportName])) { From 07c03f95ad9160bcc1359d0f7bb0ea78056c4385 Mon Sep 17 00:00:00 2001 From: ckvv Date: Thu, 7 Dec 2023 15:49:36 +0800 Subject: [PATCH 2/8] style: fix eslint --- packages/core/src/import-models.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/core/src/import-models.ts b/packages/core/src/import-models.ts index 3e38f72e3008..31a91e889994 100644 --- a/packages/core/src/import-models.ts +++ b/packages/core/src/import-models.ts @@ -35,7 +35,8 @@ export async function importModels(globPaths: string | string[], modelMatch?: Mo async function importModelNoGlob(url: string, modelMatch?: ModelMatch): Promise { const { default: _default, ...args } = await import(url); - const module = { ..._default, ...args }; + const module = { ..._default, ...args }; + return Object.keys(module) .filter(exportName => { if (!isModelStatic(module[exportName])) { From 0d4e86599abf71a63b88e32696f0e389236bc759 Mon Sep 17 00:00:00 2001 From: ckvv Date: Thu, 7 Dec 2023 18:02:20 +0800 Subject: [PATCH 3/8] Update import-models.ts --- packages/core/src/import-models.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/core/src/import-models.ts b/packages/core/src/import-models.ts index 31a91e889994..6863c7aba542 100644 --- a/packages/core/src/import-models.ts +++ b/packages/core/src/import-models.ts @@ -34,8 +34,10 @@ export async function importModels(globPaths: string | string[], modelMatch?: Mo } async function importModelNoGlob(url: string, modelMatch?: ModelMatch): Promise { - const { default: _default, ...args } = await import(url); - const module = { ..._default, ...args }; + const module = await import(url); + if (module.default && !isModelStatic(module.default) && typeof module.default === 'object') { + Object.assign(module, module.default); + } return Object.keys(module) .filter(exportName => { From b8e8cf9c4bef166d36681bc68cede580b5f1997c Mon Sep 17 00:00:00 2001 From: ckvv Date: Tue, 12 Dec 2023 21:01:21 +0800 Subject: [PATCH 4/8] Update packages/core/src/import-models.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Zoé --- packages/core/src/import-models.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/core/src/import-models.ts b/packages/core/src/import-models.ts index 6863c7aba542..69251689428e 100644 --- a/packages/core/src/import-models.ts +++ b/packages/core/src/import-models.ts @@ -35,6 +35,7 @@ export async function importModels(globPaths: string | string[], modelMatch?: Mo async function importModelNoGlob(url: string, modelMatch?: ModelMatch): Promise { const module = await import(url); + // when importing a CJS file, sometimes only the default export is available, as named exports depend on the file's exports being statically analyzable by node. The default exports contains the contents of the file's `module.exports` if (module.default && !isModelStatic(module.default) && typeof module.default === 'object') { Object.assign(module, module.default); } From 40b9dd508dcb9306f9d522b31efedf359376a450 Mon Sep 17 00:00:00 2001 From: ckvv Date: Tue, 12 Dec 2023 21:01:28 +0800 Subject: [PATCH 5/8] Update packages/core/src/import-models.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Zoé --- packages/core/src/import-models.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/import-models.ts b/packages/core/src/import-models.ts index 69251689428e..7b0768fa115b 100644 --- a/packages/core/src/import-models.ts +++ b/packages/core/src/import-models.ts @@ -37,7 +37,7 @@ async function importModelNoGlob(url: string, modelMatch?: ModelMatch): Promise< const module = await import(url); // when importing a CJS file, sometimes only the default export is available, as named exports depend on the file's exports being statically analyzable by node. The default exports contains the contents of the file's `module.exports` if (module.default && !isModelStatic(module.default) && typeof module.default === 'object') { - Object.assign(module, module.default); + module = { ...module, ...module.default }; } return Object.keys(module) From e1ccfcef43998ea02e31346122f969ef88d1be52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E9=94=B4?= Date: Tue, 12 Dec 2023 21:37:36 +0800 Subject: [PATCH 6/8] fix: change module to let --- packages/core/src/import-models.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/import-models.ts b/packages/core/src/import-models.ts index 7b0768fa115b..c4b6bda4239c 100644 --- a/packages/core/src/import-models.ts +++ b/packages/core/src/import-models.ts @@ -34,7 +34,7 @@ export async function importModels(globPaths: string | string[], modelMatch?: Mo } async function importModelNoGlob(url: string, modelMatch?: ModelMatch): Promise { - const module = await import(url); + let module = await import(url); // when importing a CJS file, sometimes only the default export is available, as named exports depend on the file's exports being statically analyzable by node. The default exports contains the contents of the file's `module.exports` if (module.default && !isModelStatic(module.default) && typeof module.default === 'object') { module = { ...module, ...module.default }; From 8d5428e6177271645e4ef16f5339e8af1b4e71d8 Mon Sep 17 00:00:00 2001 From: ckvv Date: Thu, 14 Dec 2023 14:12:17 +0800 Subject: [PATCH 7/8] test: import-models add bundler mock --- .../unit/import-models/import-models.test.ts | 27 +++++++----- .../test/unit/import-models/models/bundler.js | 42 +++++++++++++++++++ 2 files changed, 58 insertions(+), 11 deletions(-) create mode 100644 packages/core/test/unit/import-models/models/bundler.js diff --git a/packages/core/test/unit/import-models/import-models.test.ts b/packages/core/test/unit/import-models/import-models.test.ts index 125abf6c5df9..ec9cafc2d106 100644 --- a/packages/core/test/unit/import-models/import-models.test.ts +++ b/packages/core/test/unit/import-models/import-models.test.ts @@ -3,6 +3,8 @@ import glob from 'fast-glob'; import type { ModelStatic } from '@sequelize/core'; import { importModels } from '@sequelize/core'; // @ts-expect-error -- commonjs file +import { Bundler } from './models/bundler'; +// @ts-expect-error -- commonjs file import Node from './models/node.abstract'; // @ts-expect-error -- commonjs file import User from './models/user'; @@ -13,17 +15,19 @@ describe('importModels', () => { it('can import models using a single glob path', async () => { const models = await importModels(`${dirname}/models/*.{ts,js}`); - expect(models).to.have.length(2); - expect(models[0]).to.eq(Node); - expect(models[1]).to.eq(User); + expect(models).to.have.length(3); + expect(models[0]).to.eq(Bundler); + expect(models[1]).to.eq(Node); + expect(models[2]).to.eq(User); }); it('can import models using multiple glob paths', async () => { - const models = await importModels([`${dirname}/models/node.abstract.js`, `${dirname}/models/user.js`]); + const models = await importModels([`${dirname}/models/bundler.js`, `${dirname}/models/node.abstract.js`, `${dirname}/models/user.js`]); - expect(models).to.have.length(2); - expect(models[0]).to.eq(Node); - expect(models[1]).to.eq(User); + expect(models).to.have.length(3); + expect(models[0]).to.eq(Bundler); + expect(models[1]).to.eq(Node); + expect(models[2]).to.eq(User); }); it('can exclude results using the second parameter', async () => { @@ -37,10 +41,11 @@ describe('importModels', () => { expect(models.length).to.eq(0); - expect(calls[0].path.endsWith('test/unit/import-models/models/node.abstract.js')); - expect(calls[0].exportName).to.eq('default'); - expect(calls[0].exportValue).to.eq(Node); + expect(calls[0].exportValue).to.eq(Bundler); + expect(calls[1].path.endsWith('test/unit/import-models/models/node.abstract.js')); + expect(calls[1].exportName).to.eq('default'); + expect(calls[1].exportValue).to.eq(Node); - expect(calls[1].exportValue).to.eq(User); + expect(calls[2].exportValue).to.eq(User); }); }); diff --git a/packages/core/test/unit/import-models/models/bundler.js b/packages/core/test/unit/import-models/models/bundler.js new file mode 100644 index 000000000000..7771a229aef4 --- /dev/null +++ b/packages/core/test/unit/import-models/models/bundler.js @@ -0,0 +1,42 @@ +/** + * + * Simulate the behavior of bundler (esbuild, rollup ...) converting `ECMAScript` to `CommonJS`. + * Source code + * +import { Model } from "@sequelize/core"; + +export class Bundler extends Model {}; + */ +const __defProp = Object.defineProperty; +const __getOwnPropDesc = Object.getOwnPropertyDescriptor; +const __getOwnPropNames = Object.getOwnPropertyNames; +const __hasOwnProp = Object.prototype.hasOwnProperty; +const __export = (target, all) => { + for (const name in all) { + __defProp(target, name, { get: all[name], enumerable: true }); + } +}; + +const __copyProps = (to, from, except, desc) => { + if (from && typeof from === 'object' || typeof from === 'function') { + for (const key of __getOwnPropNames(from)) { + if (!__hasOwnProp.call(to, key) && key !== except) { + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + } + } + + return to; +}; + +const __toCommonJS = mod => __copyProps(__defProp({}, '__esModule', { value: true }), mod); + +// src/bundler.ts +const bundler_exports = {}; +__export(bundler_exports, { + Bundler: () => Bundler, +}); +module.exports = __toCommonJS(bundler_exports); +const import_core = require('@sequelize/core'); + +const Bundler = class extends import_core.Model {}; From 6b1b29e895e018fa649c6c56dc8a453b772a5d33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zo=C3=A9=20Cox?= Date: Fri, 2 Feb 2024 22:17:33 +0100 Subject: [PATCH 8/8] only spread plain exports --- packages/core/src/import-models.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/core/src/import-models.ts b/packages/core/src/import-models.ts index c4b6bda4239c..31d58dea3e46 100644 --- a/packages/core/src/import-models.ts +++ b/packages/core/src/import-models.ts @@ -2,6 +2,7 @@ import { pathToFileURL } from 'node:url'; import glob from 'fast-glob'; import uniq from 'lodash/uniq'; import type { ModelStatic } from './model.js'; +import { isPlainObject } from './utils/check.js'; import { isModelStatic } from './utils/model-utils.js'; type ModelMatch = (path: string, exportName: string, exportValue: ModelStatic) => boolean; @@ -35,9 +36,11 @@ export async function importModels(globPaths: string | string[], modelMatch?: Mo async function importModelNoGlob(url: string, modelMatch?: ModelMatch): Promise { let module = await import(url); - // when importing a CJS file, sometimes only the default export is available, as named exports depend on the file's exports being statically analyzable by node. The default exports contains the contents of the file's `module.exports` - if (module.default && !isModelStatic(module.default) && typeof module.default === 'object') { - module = { ...module, ...module.default }; + // When importing a CJS file, sometimes only the default export is available, + // as named exports depend on the file's exports being statically analyzable by node. + // The default export contains the contents of the file's `module.exports` + if (module.default && isPlainObject(module.default)) { + module = { ...module.default, ...module }; } return Object.keys(module)