@terra-graph/core 1.0.0-rc.4 → 1.0.0-rc.5

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.
@@ -1,14 +1,9 @@
1
1
  import { RuntimeProvider } from '../RuntimeProvider.js';
2
2
  import { RuntimeProviderLoadInput, RuntimeProviderLoader } from '../RuntimeProviderLoader.js';
3
- type RuntimeProviderModuleShape = RuntimeProvider | (() => RuntimeProvider | Promise<RuntimeProvider>) | {
4
- runtimeProvider?: RuntimeProvider | (() => RuntimeProvider | Promise<RuntimeProvider>);
5
- default?: RuntimeProvider | (() => RuntimeProvider | Promise<RuntimeProvider>);
6
- };
7
- export declare const __test__: {
8
- toProvider: (value: RuntimeProviderModuleShape) => Promise<RuntimeProvider>;
9
- resolveImportSpecifier: (specifier: string, sourceReference?: string) => string;
10
- };
11
3
  export declare class ModuleRuntimeProviderLoader implements RuntimeProviderLoader {
12
4
  load(input: RuntimeProviderLoadInput): Promise<RuntimeProvider>;
5
+ private isRuntimeProvider;
6
+ private isRuntimeProviderFactory;
7
+ private toProvider;
8
+ private resolveImportSpecifier;
13
9
  }
14
- export {};
@@ -33,55 +33,92 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.ModuleRuntimeProviderLoader = exports.__test__ = void 0;
36
+ exports.ModuleRuntimeProviderLoader = void 0;
37
+ const node_module_1 = require("node:module");
37
38
  const node_path_1 = require("node:path");
38
39
  const node_url_1 = require("node:url");
39
- const isRuntimeProvider = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
40
- const isRuntimeProviderFactory = (value) => typeof value === 'function';
41
- const toProvider = async (value) => {
42
- const candidate = isRuntimeProvider(value) &&
43
- ('runtimeProvider' in value || 'default' in value)
44
- ? (value.runtimeProvider ??
45
- value.default)
46
- : value;
47
- if (isRuntimeProviderFactory(candidate)) {
48
- const resolved = await candidate();
49
- if (!isRuntimeProvider(resolved)) {
40
+ class ModuleRuntimeProviderLoader {
41
+ async load(input) {
42
+ const resolvedSpecifier = this.resolveImportSpecifier(input.specifier, input.sourceReference);
43
+ const loaded = await Promise.resolve(`${resolvedSpecifier}`).then(s => __importStar(require(s)));
44
+ return this.toProvider(loaded);
45
+ }
46
+ isRuntimeProvider(value) {
47
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
48
+ }
49
+ isRuntimeProviderFactory(value) {
50
+ return typeof value === 'function';
51
+ }
52
+ async toProvider(value) {
53
+ const candidate = this.isRuntimeProvider(value) &&
54
+ ('runtimeProvider' in value || 'default' in value)
55
+ ? (value.runtimeProvider ??
56
+ value.default)
57
+ : value;
58
+ if (this.isRuntimeProviderFactory(candidate)) {
59
+ const resolved = await candidate();
60
+ if (!this.isRuntimeProvider(resolved)) {
61
+ throw new Error('Module does not export a valid runtime provider');
62
+ }
63
+ return resolved;
64
+ }
65
+ if (!this.isRuntimeProvider(candidate)) {
50
66
  throw new Error('Module does not export a valid runtime provider');
51
67
  }
52
- return resolved;
68
+ return candidate;
53
69
  }
54
- if (!isRuntimeProvider(candidate)) {
55
- throw new Error('Module does not export a valid runtime provider');
56
- }
57
- return candidate;
58
- };
59
- const resolveImportSpecifier = (specifier, sourceReference) => {
60
- if (specifier.startsWith('.') ||
61
- specifier.startsWith('/') ||
62
- specifier.startsWith('file:')) {
63
- if (specifier.startsWith('file:')) {
70
+ resolveImportSpecifier(specifier, sourceReference) {
71
+ if (specifier.startsWith('.') ||
72
+ specifier.startsWith('/') ||
73
+ specifier.startsWith('file:')) {
74
+ if (specifier.startsWith('file:')) {
75
+ return specifier;
76
+ }
77
+ if ((0, node_path_1.isAbsolute)(specifier)) {
78
+ return (0, node_url_1.pathToFileURL)(specifier).href;
79
+ }
80
+ if (!sourceReference) {
81
+ return (0, node_url_1.pathToFileURL)((0, node_path_1.resolve)(specifier)).href;
82
+ }
83
+ return (0, node_url_1.pathToFileURL)((0, node_path_1.resolve)((0, node_path_1.dirname)(sourceReference), specifier))
84
+ .href;
85
+ }
86
+ if ((0, node_module_1.isBuiltin)(specifier)) {
64
87
  return specifier;
65
88
  }
66
- if ((0, node_path_1.isAbsolute)(specifier)) {
67
- return (0, node_url_1.pathToFileURL)(specifier).href;
89
+ const resolveFromBase = (baseFile) => {
90
+ const moduleApi = node_module_1.Module;
91
+ if (!moduleApi._resolveFilename || !moduleApi._nodeModulePaths) {
92
+ return undefined;
93
+ }
94
+ try {
95
+ const parent = new node_module_1.Module(baseFile);
96
+ parent.filename = baseFile;
97
+ parent.paths = moduleApi._nodeModulePaths((0, node_path_1.dirname)(baseFile));
98
+ const resolved = moduleApi._resolveFilename(specifier, parent, false, {
99
+ conditions: new Set(['import', 'default', 'require']),
100
+ });
101
+ return (0, node_url_1.pathToFileURL)(resolved).href;
102
+ }
103
+ catch {
104
+ return undefined;
105
+ }
106
+ };
107
+ if (sourceReference) {
108
+ const basePath = sourceReference.startsWith('file:')
109
+ ? (0, node_url_1.fileURLToPath)(sourceReference)
110
+ : sourceReference;
111
+ const resolvedFromSource = resolveFromBase(basePath);
112
+ if (resolvedFromSource) {
113
+ return resolvedFromSource;
114
+ }
68
115
  }
69
- if (!sourceReference) {
70
- return (0, node_url_1.pathToFileURL)((0, node_path_1.resolve)(specifier)).href;
116
+ const cwdBase = (0, node_path_1.resolve)(process.cwd(), 'index.js');
117
+ const resolvedFromCwd = resolveFromBase(cwdBase);
118
+ if (resolvedFromCwd) {
119
+ return resolvedFromCwd;
71
120
  }
72
- return (0, node_url_1.pathToFileURL)((0, node_path_1.resolve)((0, node_path_1.dirname)(sourceReference), specifier)).href;
73
- }
74
- return specifier;
75
- };
76
- exports.__test__ = {
77
- toProvider,
78
- resolveImportSpecifier,
79
- };
80
- class ModuleRuntimeProviderLoader {
81
- async load(input) {
82
- const resolvedSpecifier = resolveImportSpecifier(input.specifier, input.sourceReference);
83
- const loaded = await Promise.resolve(`${resolvedSpecifier}`).then(s => __importStar(require(s)));
84
- return toProvider(loaded);
121
+ return specifier;
85
122
  }
86
123
  }
87
124
  exports.ModuleRuntimeProviderLoader = ModuleRuntimeProviderLoader;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const promises_1 = require("node:fs/promises");
4
+ const node_module_1 = require("node:module");
4
5
  const node_os_1 = require("node:os");
5
6
  const node_path_1 = require("node:path");
6
7
  const node_url_1 = require("node:url");
@@ -40,7 +41,9 @@ describe('ModuleRuntimeProviderLoader.load', () => {
40
41
  });
41
42
  it('shoud accept raw runtime providers without module export markers', async () => {
42
43
  const provider = {};
43
- await expect(ModuleRuntimeProviderLoader_js_1.__test__.toProvider(provider)).resolves.toBe(provider);
44
+ const loader = new ModuleRuntimeProviderLoader_js_1.ModuleRuntimeProviderLoader();
45
+ // @ts-expect-error accessing private method for test coverage
46
+ await expect(loader.toProvider(provider)).resolves.toBe(provider);
44
47
  });
45
48
  it('shoud load a provider from a default function export', async () => {
46
49
  const dir = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'runtime-provider-loader-'));
@@ -115,6 +118,152 @@ describe('ModuleRuntimeProviderLoader.load', () => {
115
118
  await (0, promises_1.rm)(dir, { recursive: true, force: true });
116
119
  }
117
120
  });
121
+ it('shoud resolve package providers from sourceReference', async () => {
122
+ const dir = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'runtime-provider-loader-'));
123
+ const packageDir = (0, node_path_1.join)(dir, 'node_modules', 'package-provider');
124
+ const configPath = (0, node_path_1.join)(dir, 'runtime.yml');
125
+ await (0, promises_1.mkdir)(packageDir, { recursive: true });
126
+ await (0, promises_1.writeFile)((0, node_path_1.join)(packageDir, 'package.json'), JSON.stringify({
127
+ name: 'package-provider',
128
+ exports: {
129
+ import: './index.cjs',
130
+ require: './index.cjs',
131
+ default: './index.cjs',
132
+ },
133
+ }), 'utf8');
134
+ await (0, promises_1.writeFile)((0, node_path_1.join)(packageDir, 'index.cjs'), 'module.exports = { supportedAdapterOperationsRegistry: { FromPackage: class FromPackage {} } };', 'utf8');
135
+ await (0, promises_1.writeFile)(configPath, 'providers: []', 'utf8');
136
+ try {
137
+ const loader = new ModuleRuntimeProviderLoader_js_1.ModuleRuntimeProviderLoader();
138
+ const provider = await loader.load({
139
+ specifier: 'package-provider',
140
+ sourceReference: configPath,
141
+ });
142
+ expect(provider.supportedAdapterOperationsRegistry).toBeDefined();
143
+ expect(provider.supportedAdapterOperationsRegistry
144
+ ? Object.keys(provider.supportedAdapterOperationsRegistry)
145
+ : []).toContain('FromPackage');
146
+ }
147
+ finally {
148
+ await (0, promises_1.rm)(dir, { recursive: true, force: true });
149
+ }
150
+ });
151
+ it('shoud resolve package providers from cwd when no reference is provided', async () => {
152
+ const dir = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'runtime-provider-loader-'));
153
+ const packageDir = (0, node_path_1.join)(dir, 'node_modules', 'cwd-provider');
154
+ const originalCwd = process.cwd();
155
+ await (0, promises_1.mkdir)(packageDir, { recursive: true });
156
+ await (0, promises_1.writeFile)((0, node_path_1.join)(packageDir, 'package.json'), JSON.stringify({
157
+ name: 'cwd-provider',
158
+ exports: {
159
+ import: './index.cjs',
160
+ require: './index.cjs',
161
+ default: './index.cjs',
162
+ },
163
+ }), 'utf8');
164
+ await (0, promises_1.writeFile)((0, node_path_1.join)(packageDir, 'index.cjs'), 'module.exports = { supportedAdapterOperationsRegistry: { FromCwdPackage: class FromCwdPackage {} } };', 'utf8');
165
+ try {
166
+ process.chdir(dir);
167
+ const loader = new ModuleRuntimeProviderLoader_js_1.ModuleRuntimeProviderLoader();
168
+ const provider = await loader.load({ specifier: 'cwd-provider' });
169
+ expect(provider.supportedAdapterOperationsRegistry).toBeDefined();
170
+ expect(provider.supportedAdapterOperationsRegistry
171
+ ? Object.keys(provider.supportedAdapterOperationsRegistry)
172
+ : []).toContain('FromCwdPackage');
173
+ }
174
+ finally {
175
+ process.chdir(originalCwd);
176
+ await (0, promises_1.rm)(dir, { recursive: true, force: true });
177
+ }
178
+ });
179
+ it('shoud resolve ESM-only package specifiers without loading', async () => {
180
+ const dir = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'runtime-provider-loader-'));
181
+ const packageDir = (0, node_path_1.join)(dir, 'node_modules', 'esm-only');
182
+ const configPath = (0, node_path_1.join)(dir, 'runtime.yml');
183
+ await (0, promises_1.mkdir)(packageDir, { recursive: true });
184
+ await (0, promises_1.writeFile)((0, node_path_1.join)(packageDir, 'package.json'), JSON.stringify({
185
+ name: 'esm-only',
186
+ type: 'module',
187
+ exports: {
188
+ import: './index.mjs',
189
+ },
190
+ }), 'utf8');
191
+ await (0, promises_1.writeFile)((0, node_path_1.join)(packageDir, 'index.mjs'), 'export default {};', 'utf8');
192
+ await (0, promises_1.writeFile)(configPath, 'providers: []', 'utf8');
193
+ try {
194
+ const loader = new ModuleRuntimeProviderLoader_js_1.ModuleRuntimeProviderLoader();
195
+ // @ts-expect-error accessing private method for test coverage
196
+ const resolved = loader.resolveImportSpecifier('esm-only', configPath);
197
+ const resolvedPath = await (0, promises_1.realpath)((0, node_url_1.fileURLToPath)(resolved));
198
+ const expectedPath = await (0, promises_1.realpath)((0, node_path_1.join)(packageDir, 'index.mjs'));
199
+ expect(resolvedPath).toBe(expectedPath);
200
+ }
201
+ finally {
202
+ await (0, promises_1.rm)(dir, { recursive: true, force: true });
203
+ }
204
+ });
205
+ it('shoud resolve package providers from file URL sourceReference', async () => {
206
+ const dir = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'runtime-provider-loader-'));
207
+ const packageDir = (0, node_path_1.join)(dir, 'node_modules', 'file-url-provider');
208
+ const configPath = (0, node_path_1.join)(dir, 'runtime.yml');
209
+ await (0, promises_1.mkdir)(packageDir, { recursive: true });
210
+ await (0, promises_1.writeFile)((0, node_path_1.join)(packageDir, 'package.json'), JSON.stringify({
211
+ name: 'file-url-provider',
212
+ exports: {
213
+ import: './index.cjs',
214
+ require: './index.cjs',
215
+ default: './index.cjs',
216
+ },
217
+ }), 'utf8');
218
+ await (0, promises_1.writeFile)((0, node_path_1.join)(packageDir, 'index.cjs'), 'module.exports = {};', 'utf8');
219
+ await (0, promises_1.writeFile)(configPath, 'providers: []', 'utf8');
220
+ try {
221
+ const loader = new ModuleRuntimeProviderLoader_js_1.ModuleRuntimeProviderLoader();
222
+ // @ts-expect-error accessing private method for test coverage
223
+ const resolved = loader.resolveImportSpecifier('file-url-provider', (0, node_url_1.pathToFileURL)(configPath).href);
224
+ const resolvedPath = await (0, promises_1.realpath)((0, node_url_1.fileURLToPath)(resolved));
225
+ const expectedPath = await (0, promises_1.realpath)((0, node_path_1.join)(packageDir, 'index.cjs'));
226
+ expect(resolvedPath).toBe(expectedPath);
227
+ }
228
+ finally {
229
+ await (0, promises_1.rm)(dir, { recursive: true, force: true });
230
+ }
231
+ });
232
+ it('shoud fall back to specifier when package cannot be resolved', async () => {
233
+ const dir = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'runtime-provider-loader-'));
234
+ const configPath = (0, node_path_1.join)(dir, 'runtime.yml');
235
+ await (0, promises_1.writeFile)(configPath, 'providers: []', 'utf8');
236
+ try {
237
+ const loader = new ModuleRuntimeProviderLoader_js_1.ModuleRuntimeProviderLoader();
238
+ // @ts-expect-error accessing private method for test coverage
239
+ const resolved = loader.resolveImportSpecifier('missing-package', configPath);
240
+ expect(resolved).toBe('missing-package');
241
+ }
242
+ finally {
243
+ await (0, promises_1.rm)(dir, { recursive: true, force: true });
244
+ }
245
+ });
246
+ it('shoud fall back when module resolve APIs are unavailable', async () => {
247
+ const dir = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'runtime-provider-loader-'));
248
+ const configPath = (0, node_path_1.join)(dir, 'runtime.yml');
249
+ await (0, promises_1.writeFile)(configPath, 'providers: []', 'utf8');
250
+ const moduleApi = node_module_1.Module;
251
+ const originalResolve = moduleApi._resolveFilename;
252
+ const originalPaths = moduleApi._nodeModulePaths;
253
+ try {
254
+ moduleApi._resolveFilename = undefined;
255
+ moduleApi._nodeModulePaths = undefined;
256
+ const loader = new ModuleRuntimeProviderLoader_js_1.ModuleRuntimeProviderLoader();
257
+ // @ts-expect-error accessing private method for test coverage
258
+ const resolved = loader.resolveImportSpecifier('missing-package', configPath);
259
+ expect(resolved).toBe('missing-package');
260
+ }
261
+ finally {
262
+ moduleApi._resolveFilename = originalResolve;
263
+ moduleApi._nodeModulePaths = originalPaths;
264
+ await (0, promises_1.rm)(dir, { recursive: true, force: true });
265
+ }
266
+ });
118
267
  it('shoud accept non-file specifiers unchanged', async () => {
119
268
  const loader = new ModuleRuntimeProviderLoader_js_1.ModuleRuntimeProviderLoader();
120
269
  const provider = await loader.load({ specifier: 'node:fs' });
@@ -1,14 +1,9 @@
1
1
  import { RuntimeProvider } from '../RuntimeProvider.js';
2
2
  import { RuntimeProviderLoadInput, RuntimeProviderLoader } from '../RuntimeProviderLoader.js';
3
- type RuntimeProviderModuleShape = RuntimeProvider | (() => RuntimeProvider | Promise<RuntimeProvider>) | {
4
- runtimeProvider?: RuntimeProvider | (() => RuntimeProvider | Promise<RuntimeProvider>);
5
- default?: RuntimeProvider | (() => RuntimeProvider | Promise<RuntimeProvider>);
6
- };
7
- export declare const __test__: {
8
- toProvider: (value: RuntimeProviderModuleShape) => Promise<RuntimeProvider>;
9
- resolveImportSpecifier: (specifier: string, sourceReference?: string) => string;
10
- };
11
3
  export declare class ModuleRuntimeProviderLoader implements RuntimeProviderLoader {
12
4
  load(input: RuntimeProviderLoadInput): Promise<RuntimeProvider>;
5
+ private isRuntimeProvider;
6
+ private isRuntimeProviderFactory;
7
+ private toProvider;
8
+ private resolveImportSpecifier;
13
9
  }
14
- export {};
@@ -1,50 +1,87 @@
1
+ import { Module, isBuiltin } from 'node:module';
1
2
  import { dirname, isAbsolute, resolve as resolvePath } from 'node:path';
2
- import { pathToFileURL } from 'node:url';
3
- const isRuntimeProvider = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
4
- const isRuntimeProviderFactory = (value) => typeof value === 'function';
5
- const toProvider = async (value) => {
6
- const candidate = isRuntimeProvider(value) &&
7
- ('runtimeProvider' in value || 'default' in value)
8
- ? (value.runtimeProvider ??
9
- value.default)
10
- : value;
11
- if (isRuntimeProviderFactory(candidate)) {
12
- const resolved = await candidate();
13
- if (!isRuntimeProvider(resolved)) {
3
+ import { fileURLToPath, pathToFileURL } from 'node:url';
4
+ export class ModuleRuntimeProviderLoader {
5
+ async load(input) {
6
+ const resolvedSpecifier = this.resolveImportSpecifier(input.specifier, input.sourceReference);
7
+ const loaded = await import(resolvedSpecifier);
8
+ return this.toProvider(loaded);
9
+ }
10
+ isRuntimeProvider(value) {
11
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
12
+ }
13
+ isRuntimeProviderFactory(value) {
14
+ return typeof value === 'function';
15
+ }
16
+ async toProvider(value) {
17
+ const candidate = this.isRuntimeProvider(value) &&
18
+ ('runtimeProvider' in value || 'default' in value)
19
+ ? (value.runtimeProvider ??
20
+ value.default)
21
+ : value;
22
+ if (this.isRuntimeProviderFactory(candidate)) {
23
+ const resolved = await candidate();
24
+ if (!this.isRuntimeProvider(resolved)) {
25
+ throw new Error('Module does not export a valid runtime provider');
26
+ }
27
+ return resolved;
28
+ }
29
+ if (!this.isRuntimeProvider(candidate)) {
14
30
  throw new Error('Module does not export a valid runtime provider');
15
31
  }
16
- return resolved;
32
+ return candidate;
17
33
  }
18
- if (!isRuntimeProvider(candidate)) {
19
- throw new Error('Module does not export a valid runtime provider');
20
- }
21
- return candidate;
22
- };
23
- const resolveImportSpecifier = (specifier, sourceReference) => {
24
- if (specifier.startsWith('.') ||
25
- specifier.startsWith('/') ||
26
- specifier.startsWith('file:')) {
27
- if (specifier.startsWith('file:')) {
34
+ resolveImportSpecifier(specifier, sourceReference) {
35
+ if (specifier.startsWith('.') ||
36
+ specifier.startsWith('/') ||
37
+ specifier.startsWith('file:')) {
38
+ if (specifier.startsWith('file:')) {
39
+ return specifier;
40
+ }
41
+ if (isAbsolute(specifier)) {
42
+ return pathToFileURL(specifier).href;
43
+ }
44
+ if (!sourceReference) {
45
+ return pathToFileURL(resolvePath(specifier)).href;
46
+ }
47
+ return pathToFileURL(resolvePath(dirname(sourceReference), specifier))
48
+ .href;
49
+ }
50
+ if (isBuiltin(specifier)) {
28
51
  return specifier;
29
52
  }
30
- if (isAbsolute(specifier)) {
31
- return pathToFileURL(specifier).href;
53
+ const resolveFromBase = (baseFile) => {
54
+ const moduleApi = Module;
55
+ if (!moduleApi._resolveFilename || !moduleApi._nodeModulePaths) {
56
+ return undefined;
57
+ }
58
+ try {
59
+ const parent = new Module(baseFile);
60
+ parent.filename = baseFile;
61
+ parent.paths = moduleApi._nodeModulePaths(dirname(baseFile));
62
+ const resolved = moduleApi._resolveFilename(specifier, parent, false, {
63
+ conditions: new Set(['import', 'default', 'require']),
64
+ });
65
+ return pathToFileURL(resolved).href;
66
+ }
67
+ catch {
68
+ return undefined;
69
+ }
70
+ };
71
+ if (sourceReference) {
72
+ const basePath = sourceReference.startsWith('file:')
73
+ ? fileURLToPath(sourceReference)
74
+ : sourceReference;
75
+ const resolvedFromSource = resolveFromBase(basePath);
76
+ if (resolvedFromSource) {
77
+ return resolvedFromSource;
78
+ }
32
79
  }
33
- if (!sourceReference) {
34
- return pathToFileURL(resolvePath(specifier)).href;
80
+ const cwdBase = resolvePath(process.cwd(), 'index.js');
81
+ const resolvedFromCwd = resolveFromBase(cwdBase);
82
+ if (resolvedFromCwd) {
83
+ return resolvedFromCwd;
35
84
  }
36
- return pathToFileURL(resolvePath(dirname(sourceReference), specifier)).href;
37
- }
38
- return specifier;
39
- };
40
- export const __test__ = {
41
- toProvider,
42
- resolveImportSpecifier,
43
- };
44
- export class ModuleRuntimeProviderLoader {
45
- async load(input) {
46
- const resolvedSpecifier = resolveImportSpecifier(input.specifier, input.sourceReference);
47
- const loaded = await import(resolvedSpecifier);
48
- return toProvider(loaded);
85
+ return specifier;
49
86
  }
50
87
  }
@@ -1,8 +1,9 @@
1
- import { mkdtemp, rm, writeFile } from 'node:fs/promises';
1
+ import { mkdir, mkdtemp, realpath, rm, writeFile } from 'node:fs/promises';
2
+ import { Module } from 'node:module';
2
3
  import { tmpdir } from 'node:os';
3
4
  import { join } from 'node:path';
4
- import { pathToFileURL } from 'node:url';
5
- import { ModuleRuntimeProviderLoader, __test__, } from './ModuleRuntimeProviderLoader.js';
5
+ import { fileURLToPath, pathToFileURL } from 'node:url';
6
+ import { ModuleRuntimeProviderLoader } from './ModuleRuntimeProviderLoader.js';
6
7
  describe('ModuleRuntimeProviderLoader.load', () => {
7
8
  it('shoud load a provider from a module default object export', async () => {
8
9
  const dir = await mkdtemp(join(tmpdir(), 'runtime-provider-loader-'));
@@ -38,7 +39,9 @@ describe('ModuleRuntimeProviderLoader.load', () => {
38
39
  });
39
40
  it('shoud accept raw runtime providers without module export markers', async () => {
40
41
  const provider = {};
41
- await expect(__test__.toProvider(provider)).resolves.toBe(provider);
42
+ const loader = new ModuleRuntimeProviderLoader();
43
+ // @ts-expect-error accessing private method for test coverage
44
+ await expect(loader.toProvider(provider)).resolves.toBe(provider);
42
45
  });
43
46
  it('shoud load a provider from a default function export', async () => {
44
47
  const dir = await mkdtemp(join(tmpdir(), 'runtime-provider-loader-'));
@@ -113,6 +116,152 @@ describe('ModuleRuntimeProviderLoader.load', () => {
113
116
  await rm(dir, { recursive: true, force: true });
114
117
  }
115
118
  });
119
+ it('shoud resolve package providers from sourceReference', async () => {
120
+ const dir = await mkdtemp(join(tmpdir(), 'runtime-provider-loader-'));
121
+ const packageDir = join(dir, 'node_modules', 'package-provider');
122
+ const configPath = join(dir, 'runtime.yml');
123
+ await mkdir(packageDir, { recursive: true });
124
+ await writeFile(join(packageDir, 'package.json'), JSON.stringify({
125
+ name: 'package-provider',
126
+ exports: {
127
+ import: './index.cjs',
128
+ require: './index.cjs',
129
+ default: './index.cjs',
130
+ },
131
+ }), 'utf8');
132
+ await writeFile(join(packageDir, 'index.cjs'), 'module.exports = { supportedAdapterOperationsRegistry: { FromPackage: class FromPackage {} } };', 'utf8');
133
+ await writeFile(configPath, 'providers: []', 'utf8');
134
+ try {
135
+ const loader = new ModuleRuntimeProviderLoader();
136
+ const provider = await loader.load({
137
+ specifier: 'package-provider',
138
+ sourceReference: configPath,
139
+ });
140
+ expect(provider.supportedAdapterOperationsRegistry).toBeDefined();
141
+ expect(provider.supportedAdapterOperationsRegistry
142
+ ? Object.keys(provider.supportedAdapterOperationsRegistry)
143
+ : []).toContain('FromPackage');
144
+ }
145
+ finally {
146
+ await rm(dir, { recursive: true, force: true });
147
+ }
148
+ });
149
+ it('shoud resolve package providers from cwd when no reference is provided', async () => {
150
+ const dir = await mkdtemp(join(tmpdir(), 'runtime-provider-loader-'));
151
+ const packageDir = join(dir, 'node_modules', 'cwd-provider');
152
+ const originalCwd = process.cwd();
153
+ await mkdir(packageDir, { recursive: true });
154
+ await writeFile(join(packageDir, 'package.json'), JSON.stringify({
155
+ name: 'cwd-provider',
156
+ exports: {
157
+ import: './index.cjs',
158
+ require: './index.cjs',
159
+ default: './index.cjs',
160
+ },
161
+ }), 'utf8');
162
+ await writeFile(join(packageDir, 'index.cjs'), 'module.exports = { supportedAdapterOperationsRegistry: { FromCwdPackage: class FromCwdPackage {} } };', 'utf8');
163
+ try {
164
+ process.chdir(dir);
165
+ const loader = new ModuleRuntimeProviderLoader();
166
+ const provider = await loader.load({ specifier: 'cwd-provider' });
167
+ expect(provider.supportedAdapterOperationsRegistry).toBeDefined();
168
+ expect(provider.supportedAdapterOperationsRegistry
169
+ ? Object.keys(provider.supportedAdapterOperationsRegistry)
170
+ : []).toContain('FromCwdPackage');
171
+ }
172
+ finally {
173
+ process.chdir(originalCwd);
174
+ await rm(dir, { recursive: true, force: true });
175
+ }
176
+ });
177
+ it('shoud resolve ESM-only package specifiers without loading', async () => {
178
+ const dir = await mkdtemp(join(tmpdir(), 'runtime-provider-loader-'));
179
+ const packageDir = join(dir, 'node_modules', 'esm-only');
180
+ const configPath = join(dir, 'runtime.yml');
181
+ await mkdir(packageDir, { recursive: true });
182
+ await writeFile(join(packageDir, 'package.json'), JSON.stringify({
183
+ name: 'esm-only',
184
+ type: 'module',
185
+ exports: {
186
+ import: './index.mjs',
187
+ },
188
+ }), 'utf8');
189
+ await writeFile(join(packageDir, 'index.mjs'), 'export default {};', 'utf8');
190
+ await writeFile(configPath, 'providers: []', 'utf8');
191
+ try {
192
+ const loader = new ModuleRuntimeProviderLoader();
193
+ // @ts-expect-error accessing private method for test coverage
194
+ const resolved = loader.resolveImportSpecifier('esm-only', configPath);
195
+ const resolvedPath = await realpath(fileURLToPath(resolved));
196
+ const expectedPath = await realpath(join(packageDir, 'index.mjs'));
197
+ expect(resolvedPath).toBe(expectedPath);
198
+ }
199
+ finally {
200
+ await rm(dir, { recursive: true, force: true });
201
+ }
202
+ });
203
+ it('shoud resolve package providers from file URL sourceReference', async () => {
204
+ const dir = await mkdtemp(join(tmpdir(), 'runtime-provider-loader-'));
205
+ const packageDir = join(dir, 'node_modules', 'file-url-provider');
206
+ const configPath = join(dir, 'runtime.yml');
207
+ await mkdir(packageDir, { recursive: true });
208
+ await writeFile(join(packageDir, 'package.json'), JSON.stringify({
209
+ name: 'file-url-provider',
210
+ exports: {
211
+ import: './index.cjs',
212
+ require: './index.cjs',
213
+ default: './index.cjs',
214
+ },
215
+ }), 'utf8');
216
+ await writeFile(join(packageDir, 'index.cjs'), 'module.exports = {};', 'utf8');
217
+ await writeFile(configPath, 'providers: []', 'utf8');
218
+ try {
219
+ const loader = new ModuleRuntimeProviderLoader();
220
+ // @ts-expect-error accessing private method for test coverage
221
+ const resolved = loader.resolveImportSpecifier('file-url-provider', pathToFileURL(configPath).href);
222
+ const resolvedPath = await realpath(fileURLToPath(resolved));
223
+ const expectedPath = await realpath(join(packageDir, 'index.cjs'));
224
+ expect(resolvedPath).toBe(expectedPath);
225
+ }
226
+ finally {
227
+ await rm(dir, { recursive: true, force: true });
228
+ }
229
+ });
230
+ it('shoud fall back to specifier when package cannot be resolved', async () => {
231
+ const dir = await mkdtemp(join(tmpdir(), 'runtime-provider-loader-'));
232
+ const configPath = join(dir, 'runtime.yml');
233
+ await writeFile(configPath, 'providers: []', 'utf8');
234
+ try {
235
+ const loader = new ModuleRuntimeProviderLoader();
236
+ // @ts-expect-error accessing private method for test coverage
237
+ const resolved = loader.resolveImportSpecifier('missing-package', configPath);
238
+ expect(resolved).toBe('missing-package');
239
+ }
240
+ finally {
241
+ await rm(dir, { recursive: true, force: true });
242
+ }
243
+ });
244
+ it('shoud fall back when module resolve APIs are unavailable', async () => {
245
+ const dir = await mkdtemp(join(tmpdir(), 'runtime-provider-loader-'));
246
+ const configPath = join(dir, 'runtime.yml');
247
+ await writeFile(configPath, 'providers: []', 'utf8');
248
+ const moduleApi = Module;
249
+ const originalResolve = moduleApi._resolveFilename;
250
+ const originalPaths = moduleApi._nodeModulePaths;
251
+ try {
252
+ moduleApi._resolveFilename = undefined;
253
+ moduleApi._nodeModulePaths = undefined;
254
+ const loader = new ModuleRuntimeProviderLoader();
255
+ // @ts-expect-error accessing private method for test coverage
256
+ const resolved = loader.resolveImportSpecifier('missing-package', configPath);
257
+ expect(resolved).toBe('missing-package');
258
+ }
259
+ finally {
260
+ moduleApi._resolveFilename = originalResolve;
261
+ moduleApi._nodeModulePaths = originalPaths;
262
+ await rm(dir, { recursive: true, force: true });
263
+ }
264
+ });
116
265
  it('shoud accept non-file specifiers unchanged', async () => {
117
266
  const loader = new ModuleRuntimeProviderLoader();
118
267
  const provider = await loader.load({ specifier: 'node:fs' });
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "type": "git",
9
9
  "url": "git+https://github.com/terra-graph/core.git"
10
10
  },
11
- "version": "1.0.0-rc.4",
11
+ "version": "1.0.0-rc.5",
12
12
  "main": "./dist/cjs/index.js",
13
13
  "module": "./dist/esm/index.js",
14
14
  "types": "./dist/esm/index.d.ts",
@@ -47,6 +47,7 @@
47
47
  "@semantic-release/changelog": "^6.0.3",
48
48
  "@semantic-release/commit-analyzer": "^13.0.0",
49
49
  "@semantic-release/git": "^10.0.1",
50
+ "@semantic-release/github": "^12.0.6",
50
51
  "@semantic-release/npm": "^12.0.1",
51
52
  "@semantic-release/release-notes-generator": "^14.0.2",
52
53
  "@types/graphlib-dot": "^0.6.4",
@@ -95,6 +96,7 @@
95
96
  "access": "public"
96
97
  }
97
98
  ],
99
+ "@semantic-release/github",
98
100
  [
99
101
  "@semantic-release/git",
100
102
  {