Skip to content

Commit

Permalink
Rename id to location
Browse files Browse the repository at this point in the history
  • Loading branch information
ehmicky committed Feb 20, 2022
1 parent 4a1d1f5 commit 0460fe4
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 119 deletions.
2 changes: 1 addition & 1 deletion src/config/plugin/lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { safeNormalizeConfig } from './normalize.js'
// - A single item can be used instead of an array of items
// - The property name is not pluralized
// This is optimized for configuration-less plugins by providing with a shortcut
// syntax: only the plugin `id` instead of a plugin object.
// syntax: only the plugin `location` instead of a plugin object.
// Some configuration properties are shared by all plugins of a given type:
// - Top-level properties can be used to configure them for all plugins
// When merging multiple configurations (CLI flags, programmatic, child and
Expand Down
60 changes: 0 additions & 60 deletions src/config/plugin/lib/id.js

This file was deleted.

33 changes: 20 additions & 13 deletions src/config/plugin/lib/import.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,39 @@ import { pathToFileURL } from 'url'
import { wrapError } from '../../../error/wrap.js'

import { PluginError } from './error.js'
import { isBuiltinId, isInlineId } from './id.js'
import { isBuiltinLocation, isInlineLocation } from './location.js'

// Builtin modules are lazy loaded for performance reasons.
// The return value is shallow cloned to make it a plain object instead of
// a dynamic `Module` instance.
// - It also ensure plugins of same id and type but different configs do not
// share the same top-level properties. However, they will share deep
// - It also ensure plugins of same location and type but different configs do
// not share the same top-level properties. However, they will share deep
// properties by reference.
export const importPlugin = async function (id, { name, builtins }) {
export const importPlugin = async function (
location,
{ name, builtins, pluginProp },
) {
try {
return await importPluginById(id, builtins)
return await importPluginByLocation(location, builtins)
} catch (error) {
throw wrapError(error, `Could not load "${name}.id"\n`, PluginError)
throw wrapError(
error,
`Could not load "${name}.${pluginProp}"\n`,
PluginError,
)
}
}

const importPluginById = async function (id, builtins) {
if (isInlineId(id)) {
return { plugin: id }
const importPluginByLocation = async function (location, builtins) {
if (isInlineLocation(location)) {
return { plugin: location }
}

if (isBuiltinId(id, builtins)) {
const builtinPlugin = await builtins[id]()
if (isBuiltinLocation(location, builtins)) {
const builtinPlugin = await builtins[location]()
return { plugin: { ...builtinPlugin } }
}

const plugin = await import(pathToFileURL(id))
return { plugin: { ...plugin }, path: id }
const plugin = await import(pathToFileURL(location))
return { plugin: { ...plugin }, path: location }
}
10 changes: 5 additions & 5 deletions src/config/plugin/lib/info.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ import { normalizeShape } from './shape.js'
// Get each `pluginInfo`, i.e. normalized `plugin` + `pluginConfig`
export const getPluginInfo = async function (pluginConfig, opts) {
const {
[opts.pluginProp]: id,
[opts.pluginProp]: location,
moduleId,
...pluginConfigA
} = await normalizeItem(pluginConfig, opts)

try {
const { plugin, path } = await importPlugin(id, opts)
const { plugin, path } = await importPlugin(location, opts)
const { config: pluginConfigDefinitions, ...pluginA } =
await normalizeShape(plugin, moduleId, opts)
const pluginConfigB = await normalizePluginConfig({
Expand All @@ -26,12 +26,12 @@ export const getPluginInfo = async function (pluginConfig, opts) {
})
return { plugin: pluginA, path, config: pluginConfigB }
} catch (error) {
throw handlePluginError(error, id)
throw handlePluginError(error, location)
}
}

const handlePluginError = function (error, id) {
const handlePluginError = function (error, location) {
return error instanceof PluginError
? wrapError(error, `Invalid plugin "${id}":`)
? wrapError(error, `Invalid plugin "${location}":`)
: error
}
64 changes: 37 additions & 27 deletions src/config/plugin/lib/item.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ import {
import { validateDefinedString } from '../../normalize/validate/simple.js'

import { CoreError, ConsumerError } from './error.js'
import { isModuleId, isPathId, isInlineId, resolveModuleId } from './id.js'
import {
isModuleLocation,
isPathLocation,
isInlineLocation,
resolveModuleLocation,
} from './location.js'
import { safeNormalizeConfig } from './normalize.js'

// Normalize a single `pluginConfig`
Expand All @@ -29,18 +34,18 @@ export const normalizeItem = async function (
}

const getItemDefinition = function (pluginProp, builtins) {
const exampleId = getExampleId(builtins)
const exampleLocation = getExampleLocation(builtins)
return [
{ ...normalizeItemTop, example: exampleId },
normalizeItemModuleId,
{ ...normalizeItemId, name: pluginProp, example: exampleId },
{ ...normalizeItemTop, example: exampleLocation },
normalizeItemModuleLoc,
{ ...normalizeItemLocation, name: pluginProp, example: exampleLocation },
]
}

const getExampleId = function (builtins) {
const builtinIds = Object.keys(builtins)
return builtinIds.length !== 0 && builtinIds[0].trim() !== ''
? builtinIds[0]
const getExampleLocation = function (builtins) {
const builtinNames = Object.keys(builtins)
return builtinNames.length !== 0 && builtinNames[0].trim() !== ''
? builtinNames[0]
: undefined
}

Expand All @@ -56,34 +61,39 @@ const normalizeItemTop = {
},
}

const normalizeItemModuleId = {
name: 'moduleId',
compute({ context: { builtins, modulePrefix }, config: { id } }) {
return isModuleId(id, modulePrefix, builtins) ? id : undefined
const normalizeItemModuleLoc = {
name: 'moduleLocation',
compute({
context: { builtins, modulePrefix, pluginProp },
config: { [pluginProp]: location },
}) {
return isModuleLocation(location, modulePrefix, builtins)
? location
: undefined
},
}

const normalizeItemId = {
const normalizeItemLocation = {
required: true,
path(id, { context: { builtins } }) {
return isPathId(id, builtins)
path(location, { context: { builtins } }) {
return isPathLocation(location, builtins)
},
async validate(id, { context: { builtins } }) {
if (isInlineId(id)) {
validateObjectOrString(id)
async validate(location, { context: { builtins } }) {
if (isInlineLocation(location)) {
validateObjectOrString(location)
return
}

validateDefinedString(id)
validateDefinedString(location)

if (isPathId(id, builtins)) {
await validateFileExists(id)
await validateRegularFile(id)
if (isPathLocation(location, builtins)) {
await validateFileExists(location)
await validateRegularFile(location)
}
},
transform(id, { context: { builtins, modulePrefix }, cwd }) {
return isModuleId(id, modulePrefix, builtins)
? resolveModuleId({ id, modulePrefix, builtins, cwd })
: id
transform(location, { context: { builtins, modulePrefix }, cwd }) {
return isModuleLocation(location, modulePrefix, builtins)
? resolveModuleLocation({ location, modulePrefix, builtins, cwd })
: location
},
}
65 changes: 65 additions & 0 deletions src/config/plugin/lib/location.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { isAbsolute } from 'path'

import { wrapError } from '../../../error/wrap.js'

import { resolveModuleName } from './module.js'

// `pluginConfig[pluginProp]` can be:
// - The direct value
// - This is useful for programmatic usage,
// - For example, by exposing to plugin consumers a function like:
// (pluginConfig) => ({ plugin, pluginConfig })
// which is passed as argument to this library
// - A builtin identifier among `opts.builtins`
// - A file path starting with . or /
// - A Node module prefixed with `modulePrefix` (which is optional)
export const isModuleLocation = function (location, modulePrefix, builtins) {
return (
modulePrefix !== undefined &&
!isInlineLocation(location) &&
!isBuiltinLocation(location, builtins) &&
!isPathLocation(location, builtins)
)
}

export const isPathLocation = function (location, builtins) {
return (
!isInlineLocation(location) &&
!isBuiltinLocation(location, builtins) &&
(location.startsWith('.') || isAbsolute(location))
)
}

export const isBuiltinLocation = function (location, builtins) {
return builtins[location] !== undefined
}

export const isInlineLocation = function (location) {
return typeof location !== 'string'
}

export const resolveModuleLocation = function ({
location,
modulePrefix,
builtins,
cwd,
}) {
try {
return resolveModuleName(location, modulePrefix, cwd)
} catch (error) {
throw wrapError(
error,
`must be ${getBuiltinsError(builtins)}
This Node module was not found, please ensure it is installed.\n`,
)
}
}

const getBuiltinsError = function (builtins) {
const builtinNames = Object.keys(builtins)
return builtinNames.length === 0
? 'a valid package name.'
: `either:
- a valid package name
- a builtin plugin among: ${builtinNames.join(', ')}`
}
26 changes: 13 additions & 13 deletions src/config/plugin/lib/module.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
import { createRequire } from 'module'

// Resolve Node module ids to absolute file paths.
// Resolve Node module names to absolute file paths.
// We enforce a npm package naming convention for all plugins.
// TODO: use import.meta.resolve() when available
export const resolveModuleName = function (id, modulePrefix, cwd) {
const moduleName = getModuleName(id, modulePrefix)
export const resolveModuleName = function (name, modulePrefix, cwd) {
const moduleName = getModuleName(name, modulePrefix)
return createRequire(`${cwd}/`).resolve(moduleName)
}

// We allow module names to be either:
// - id -> {modulePrefix}-{id}
// - @scope/id -> @scope/{modulePrefix}-{id}
const getModuleName = function (id, modulePrefix) {
const [scope, scopedName] = getModuleScope(id)
// - name -> {modulePrefix}-{name}
// - @scope/name -> @scope/{modulePrefix}-{name}
const getModuleName = function (name, modulePrefix) {
const [scope, scopedName] = getModuleScope(name)
return `${scope}${modulePrefix}-${scopedName}`
}

const getModuleScope = function (id) {
if (!id.startsWith('@')) {
return ['', id]
const getModuleScope = function (name) {
if (!name.startsWith('@')) {
return ['', name]
}

const slashIndex = id.indexOf('/')
const slashIndex = name.indexOf('/')

if (slashIndex === -1) {
return ['', id]
return ['', name]
}

return [id.slice(0, slashIndex + 1), id.slice(slashIndex + 1)]
return [name.slice(0, slashIndex + 1), name.slice(slashIndex + 1)]
}

0 comments on commit 0460fe4

Please sign in to comment.