Skip to content

Commit

Permalink
Merge pull request #237 from hypermod-io/fetcher-pkgmanager
Browse files Browse the repository at this point in the history
refactors the experimental  module-loader
  • Loading branch information
danieldelcore authored Sep 20, 2024
2 parents d3efd00 + b6714d3 commit 75a871d
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 97 deletions.
6 changes: 6 additions & 0 deletions .changeset/wise-turtles-rescue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@hypermod/fetcher': minor
'@hypermod/cli': minor
---

Refactors the module loader in order to support custom npm registries + auth keys.
2 changes: 1 addition & 1 deletion packages/cli/src/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { fetchPackages } from './utils/fetch-package';
import { getHypermodPackageName } from './utils/package-names';

export default async function list(packages: string[]) {
const packageManager = new PluginManager();
const packageManager = new PluginManager() as any;
const configs = [];

for (const packageName of packages) {
Expand Down
67 changes: 11 additions & 56 deletions packages/cli/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,68 +3,21 @@ import semver from 'semver';
import chalk from 'chalk';
import findUp from 'find-up';
import inquirer from 'inquirer';
import fs from 'fs-extra';
import { PluginManager, PluginManagerOptions } from 'live-plugin-manager';
import { installPackage } from '@antfu/install-pkg';

import * as core from '@hypermod/core';
import { fetchConfigAtPath } from '@hypermod/fetcher';
import {
type ModuleLoader as MdlLoader,
fetchConfigAtPath,
} from '@hypermod/fetcher';

import { InvalidUserInputError } from './errors';
import { fetchPackages } from './utils/fetch-package';
import { mergeConfigs } from './utils/merge-configs';
import { fetchConfigsForWorkspaces, getPackageJson } from './utils/file-system';
import ModuleLoader from './utils/module-loader';
import { getConfigPrompt, getMultiConfigPrompt } from './prompt';

const ExperimentalModuleLoader = () => {
const getInfo = (packageName: string) => {
const entryPath = require.resolve(packageName);
const location = entryPath.split(packageName)[0] + packageName;
const pkgJsonRaw = fs.readFileSync(
path.join(location, 'package.json'),
'utf8',
);
const pkgJson = JSON.parse(pkgJsonRaw);

return {
location,
entryPath,
pkgJson,
};
};

const install = async (packageName: string) => {
await installPackage(packageName, {
cwd: __dirname,
packageManager: 'npm',
additionalArgs: ['--force'],
});

const { pkgJson } = getInfo(packageName);

// Install whitelisted devDependencies
if (pkgJson?.hypermod?.dependencies) {
await Promise.all(
pkgJson.hypermod.dependencies.map((dep: string) => {
const version = pkgJson.devDependencies[dep];
if (!version) return;
return installPackage(`${dep}@${version}`, {
cwd: __dirname,
packageManager: 'npm',
additionalArgs: ['--force'],
});
}),
);
}
};

return {
install,
getInfo,
require: (packageName: string) => require(packageName),
};
};

export default async function main(
paths: string[],
flags: Partial<core.Flags>,
Expand All @@ -91,9 +44,12 @@ export default async function main(
};
}

const packageManager = flags.experimentalLoader
? ExperimentalModuleLoader()
: new PluginManager(pluginManagerConfig);
const packageManager: MdlLoader = flags.experimentalLoader
? ModuleLoader({
authToken: flags.registryToken,
npmRegistryUrl: flags.registry,
})
: (new PluginManager(pluginManagerConfig) as unknown as MdlLoader);

let transforms: string[] = [];

Expand Down Expand Up @@ -235,7 +191,6 @@ export default async function main(

const { community, remote } = await fetchPackages(
pkgName,
// @ts-expect-error Experimental loader
packageManager,
);

Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/utils/fetch-package.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import ora from 'ora';
import chalk from 'chalk';
import { PluginManager } from 'live-plugin-manager';

import {
fetchPackage,
fetchRemotePackage,
ConfigMeta,
type ModuleLoader,
} from '@hypermod/fetcher';
import { isValidConfig } from '@hypermod/validator';

import { getHypermodPackageName } from './package-names';

export async function fetchPackages(
packageName: string,
packageManager: PluginManager,
packageManager: ModuleLoader,
) {
const hypermodPackageName = getHypermodPackageName(packageName);
let hypermodPackage: ConfigMeta | undefined;
Expand Down
66 changes: 66 additions & 0 deletions packages/cli/src/utils/module-loader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import path from 'path';
import fs from 'fs-extra';
import { installPackage } from '@antfu/install-pkg';

import { ModuleLoader } from '@hypermod/fetcher';

const ModuleLoader = (config: {
npmRegistryUrl?: string;
authToken?: string;
}): ModuleLoader => {
const getInfo = (packageName: string) => {
const entryPath = require.resolve(packageName);
const location = entryPath.split(packageName)[0] + packageName;
const pkgJsonRaw = fs.readFileSync(
path.join(location, 'package.json'),
'utf8',
);
const pkgJson = JSON.parse(pkgJsonRaw);

return {
location,
entryPath,
pkgJson,
};
};

const install = async (packageName: string) => {
await installPackage(packageName, {
cwd: __dirname,
packageManager: 'npm',
additionalArgs: [
'--force',
// --registry=https://your-custom-registry-url/ --//your-custom-registry-url/:_authToken=YOUR_AUTH_TOKEN
config.npmRegistryUrl ? `--registry=${config.npmRegistryUrl}` : '',
config.authToken
? `--${config.npmRegistryUrl}/:_authToken=${config.authToken}`
: '',
],
});

const { pkgJson } = getInfo(packageName);

// Install whitelisted devDependencies
if (pkgJson?.hypermod?.dependencies) {
await Promise.all(
pkgJson.hypermod.dependencies.map((dep: string) => {
const version = pkgJson.devDependencies[dep];
if (!version) return;
return installPackage(`${dep}@${version}`, {
cwd: __dirname,
packageManager: 'npm',
additionalArgs: ['--force'],
});
}),
);
}
};

return {
install,
getInfo,
require: (packageName: string) => require(packageName),
};
};

export default ModuleLoader;
60 changes: 27 additions & 33 deletions packages/fetcher/src/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ jest.mock('globby');
import fs from 'fs';
import path from 'path';
import globby from 'globby';
import { PluginManager } from 'live-plugin-manager';

import { fetchConfig, fetchPackage, fetchRemotePackage } from '.';
import {
fetchConfig,
fetchPackage,
fetchRemotePackage,
type ModuleLoader,
} from '.';

const mockBasePath = path.join(__dirname, 'path', 'to');

Expand Down Expand Up @@ -109,28 +113,23 @@ describe('fetcher', () => {
require: jest.fn().mockReturnValue(mockConfig),
};

const configMeta = await fetchPackage(
'fake-package',
mockPackageManager as unknown as PluginManager,
);
const configMeta = await fetchPackage('fake-package', mockPackageManager);

expect(configMeta!.config).toEqual(mockConfig);
expect(configMeta!.filePath).toEqual(mockFilePath);
});

it('should throw if fetching fails', async () => {
const mockPackageManager = {
const mockPackageManager: ModuleLoader = {
install: jest.fn().mockRejectedValue('Import error'),
require: jest.fn().mockReturnValue(mockConfig),
getInfo: jest.fn(),
};

expect.assertions(1);

await expect(
fetchPackage(
'fake-package',
mockPackageManager as unknown as PluginManager,
),
fetchPackage('fake-package', mockPackageManager),
).rejects.toEqual('Import error');
});
});
Expand All @@ -150,7 +149,7 @@ describe('fetcher', () => {

const configMeta = await fetchRemotePackage(
'fake-package',
mockPackageManager as unknown as PluginManager,
mockPackageManager,
);

expect(configMeta!.config).toEqual(mockConfig);
Expand All @@ -160,17 +159,16 @@ describe('fetcher', () => {
});

it('should throw if fetching fails', async () => {
const mockPackageManager = {
const mockPackageManager: ModuleLoader = {
install: jest.fn().mockRejectedValue('Import error'),
getInfo: jest.fn(),
require: jest.fn(),
};

expect.assertions(1);

await expect(
fetchRemotePackage(
'fake-package',
mockPackageManager as unknown as PluginManager,
),
fetchRemotePackage('fake-package', mockPackageManager),
).rejects.toEqual('Import error');
});

Expand All @@ -185,7 +183,7 @@ describe('fetcher', () => {

const configMeta = await fetchRemotePackage(
'fake-package',
mockPackageManager as unknown as PluginManager,
mockPackageManager,
);

expect(configMeta!.config).toEqual(mockConfig);
Expand All @@ -205,42 +203,38 @@ describe('fetcher', () => {
Promise.resolve([]),
);

const res = await fetchRemotePackage(
'fake-package',
mockPackageManager as unknown as PluginManager,
);
const res = await fetchRemotePackage('fake-package', mockPackageManager);

expect(res).toBeUndefined();
});

it('should throw if fetching fails', async () => {
const mockPackageManager = {
const mockPackageManager: ModuleLoader = {
install: jest.fn().mockRejectedValue('Import error'),
getInfo: jest.fn(),
require: jest.fn(),
};

expect.assertions(1);

await expect(
fetchRemotePackage(
'fake-package',
mockPackageManager as unknown as PluginManager,
),
fetchRemotePackage('fake-package', mockPackageManager),
).rejects.toEqual('Import error');
});

it('should throw if package source cannot be retrieved', async () => {
const mockPackageManager = {
const mockPackageManager: ModuleLoader = {
install: jest.fn(),
getInfo: () => undefined,
getInfo: () => {
throw new Error('Package not found');
},
require: jest.fn(),
};

expect.assertions(1);

await expect(
fetchRemotePackage(
'fake-package',
mockPackageManager as unknown as PluginManager,
),
fetchRemotePackage('fake-package', mockPackageManager),
).rejects.toEqual(
new Error(`Unable to locate package files for package: 'fake-package'`),
);
Expand Down
Loading

0 comments on commit 75a871d

Please sign in to comment.