Skip to content

Commit

Permalink
feat: modules db integration with nuxi module add (#197)
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 authored Sep 19, 2023
1 parent fe8ef7c commit 1a62c13
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 10 deletions.
3 changes: 3 additions & 0 deletions src/commands/module/_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ export const categories = [
export interface ModuleCompatibility {
nuxt: string
requires: { bridge?: boolean | 'optional' }
versionMap: {
[nuxtVersion: string]: string
}
}

export interface MaintainerInfo {
Expand Down
123 changes: 113 additions & 10 deletions src/commands/module/add.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ import { existsSync } from 'node:fs'
import { loadFile, writeFile, parseModule, ProxifiedModule } from 'magicast'
import consola from 'consola'
import { addDependency } from 'nypm'
import {
NuxtModule,
checkNuxtCompatibility,
fetchModules,
getNuxtVersion,
} from './_utils'
import { satisfies } from 'semver'

export default defineCommand({
meta: {
Expand All @@ -29,16 +36,18 @@ export default defineCommand({
async setup(ctx) {
const cwd = resolve(ctx.args.cwd || '.')

// TODO: Resolve and validate npm package name first
const npmPackage = ctx.args.moduleName
const r = await resolveModule(ctx.args.moduleName, cwd)
if (r === false) {
return
}

// Add npm dependency
if (!ctx.args.skipInstall) {
consola.info(`Installing dev dependency \`${npmPackage}\``)
await addDependency(npmPackage, { cwd, dev: true }).catch((err) => {
consola.info(`Installing dev dependency \`${r.pkg}\``)
await addDependency(r.pkg, { cwd, dev: true }).catch((err) => {
consola.error(err)
consola.error(
`Please manually install \`${npmPackage}\` as a dev dependency`,
`Please manually install \`${r.pkg}\` as a dev dependency`,
)
})
}
Expand All @@ -50,17 +59,17 @@ export default defineCommand({
config.modules = []
}
for (let i = 0; i < config.modules.length; i++) {
if (config.modules[i] === npmPackage) {
consola.info(`\`${npmPackage}\` is already in the \`modules\``)
if (config.modules[i] === r.pkgName) {
consola.info(`\`${r.pkgName}\` is already in the \`modules\``)
return
}
}
consola.info(`Adding \`${npmPackage}\` to the \`modules\``)
config.modules.push(npmPackage)
consola.info(`Adding \`${r.pkgName}\` to the \`modules\``)
config.modules.push(r.pkgName)
}).catch((err) => {
consola.error(err)
consola.error(
`Please manually add \`${npmPackage}\` to the \`modules\` in \`nuxt.config.ts\``,
`Please manually add \`${r.pkgName}\` to the \`modules\` in \`nuxt.config.ts\``,
)
})
}
Expand Down Expand Up @@ -102,3 +111,97 @@ export default defineNuxtConfig({
modules: []
})`
}

// Based on https://github.com/dword-design/package-name-regex
const packageRegex =
/^(@[a-z0-9-~][a-z0-9-._~]*\/)?([a-z0-9-~][a-z0-9-._~]*)(@[^@]+)?$/

async function resolveModule(
moduleName: string,
cwd: string,
): Promise<
| false
| {
nuxtModule?: NuxtModule
pkg: string
pkgName: string
pkgVersion: string
}
> {
let pkgName = moduleName
let pkgVersion: string | undefined

const reMatch = moduleName.match(packageRegex)
if (reMatch) {
if (reMatch[3]) {
pkgName = `${reMatch[1] || ''}${reMatch[2] || ''}`
pkgVersion = reMatch[3].slice(1)
}
} else {
consola.error(`Invalid package name \`${pkgName}\`.`)
return false
}

const modulesDB = await fetchModules().catch((err) => {
consola.warn('Cannot search in the Nuxt Modules database: ' + err)
return []
})

const matchedModule = modulesDB.find(
(module) => module.name === moduleName || module.npm === pkgName,
)

if (matchedModule?.npm) {
pkgName = matchedModule.npm
}

if (matchedModule && matchedModule.compatibility.nuxt) {
// Get local Nuxt version
const nuxtVersion = await getNuxtVersion(cwd)

// Check for Module Compatibility
if (!checkNuxtCompatibility(matchedModule, nuxtVersion)) {
consola.warn(
`The module \`${pkgName}\` is not compatible with Nuxt \`${nuxtVersion}\` (requires \`${matchedModule.compatibility.nuxt}\`)`,
)
const shouldContinue = await consola.prompt(
'Do you want to continue installing incompatible version?',
{
type: 'confirm',
initial: false,
},
)
if (shouldContinue !== true) {
return false
}
}

// Match corresponding version of module for local Nuxt version
const versionMap = matchedModule.compatibility.versionMap
if (versionMap) {
for (const [_nuxtVersion, _moduleVersion] of Object.entries(versionMap)) {
if (satisfies(nuxtVersion, _nuxtVersion)) {
if (!pkgVersion) {
pkgVersion = _moduleVersion
} else {
consola.warn(
`Recommended version of \`${pkgName}\` for Nuxt \`${nuxtVersion}\` is \`${_moduleVersion}\` but you have requested \`${pkgVersion}\``,
)
pkgVersion = await consola.prompt('Choose a version:', {
type: 'select',
options: [_moduleVersion, pkgVersion],
})
}
break
}
}
}
}

return {
nuxtModule: matchedModule,
pkg: `${pkgName}@${pkgVersion || 'latest'}`,
pkgName,
pkgVersion: pkgVersion || 'latest',
}
}

0 comments on commit 1a62c13

Please sign in to comment.