@@ -10,7 +10,8 @@ import type {
1010const VARIANTS = [
1111 '.simple-release.js' ,
1212 '.simple-release.mjs' ,
13- '.simple-release.cjs'
13+ '.simple-release.cjs' ,
14+ '.simple-release.json'
1415]
1516
1617export interface SimpleReleaseConfig <
@@ -46,6 +47,18 @@ type Result<
4647 ? ApplyConfigRequirement < R , C >
4748 : never
4849
50+ interface ParsedImportQuery {
51+ path : string
52+ version ?: string
53+ symbol ?: string
54+ }
55+
56+ type Loader < T = Record < string , any > > = (
57+ path : string ,
58+ version : string | undefined ,
59+ rawConfig : Record < string , any >
60+ ) => Promise < T >
61+
4962function validate ( target : Record < string , any > , rules : Record < string , any > ) {
5063 for ( const [ rule , required ] of Object . entries ( rules ) ) {
5164 if ( required && target [ rule ] === undefined ) {
@@ -54,18 +67,101 @@ function validate(target: Record<string, any>, rules: Record<string, any>) {
5467 }
5568}
5669
70+ const IMPORT_QUERY_REGEX = / ^ ( @ ? [ ^ @ # ] * ) ( @ [ ^ # ] + ) ? ( # .* ) ? $ /
71+
72+ export function parseImportQuery (
73+ importPath : string
74+ ) : ParsedImportQuery {
75+ const match = importPath . match ( IMPORT_QUERY_REGEX )
76+
77+ if ( ! match ) {
78+ return {
79+ path : importPath
80+ }
81+ }
82+
83+ const [
84+ ,
85+ path ,
86+ version ,
87+ symbol
88+ ] = match
89+
90+ return {
91+ path,
92+ version : version ?. slice ( 1 ) ,
93+ symbol : symbol ?. slice ( 1 )
94+ }
95+ }
96+
97+ export async function loadClass < T , C extends SimpleReleaseConfig > (
98+ queryWithOptions : string | [ string , Record < string , any > ] ,
99+ config : C ,
100+ loader : Loader = _ => import ( _ )
101+ ) {
102+ const [ query , options ] = Array . isArray ( queryWithOptions )
103+ ? queryWithOptions
104+ : [ queryWithOptions ]
105+ const {
106+ path,
107+ version,
108+ symbol
109+ } = parseImportQuery ( query )
110+ const module = await loader ( path , version , config )
111+ const inst = new module [ symbol || 'default' ] ( options ) as T
112+
113+ return inst
114+ }
115+
116+ export function isQuery ( value : unknown ) : value is string | [ string , Record < string , any > ] {
117+ return typeof value === 'string' || (
118+ Array . isArray ( value )
119+ && value . length === 2
120+ && typeof value [ 0 ] === 'string'
121+ && value [ 1 ] && typeof value [ 1 ] === 'object'
122+ )
123+ }
124+
125+ export function getQuery ( queryWithOptions : unknown ) : string | null {
126+ return isQuery ( queryWithOptions )
127+ ? typeof queryWithOptions === 'string'
128+ ? queryWithOptions
129+ : queryWithOptions [ 0 ]
130+ : null
131+ }
132+
133+ async function loadAndSetIfQuery (
134+ config : SimpleReleaseConfig ,
135+ key : keyof SimpleReleaseConfig ,
136+ loader ?: Loader
137+ ) {
138+ const value = config [ key ]
139+
140+ if ( value && isQuery ( value ) ) {
141+ // eslint-disable-next-line require-atomic-updates
142+ config [ key ] = await loadClass ( value , config , loader )
143+ }
144+ }
145+
57146/**
58147 * Load simple-release config.
59148 * @param requirements
149+ * @param loader
60150 * @returns simple-release config
61151 */
62152export async function load <
63153 P extends Project = Project ,
64154 G extends GitRepositoryHosting = GitRepositoryHosting ,
65155 R extends SimpleReleaseConfigRequirements = SimpleReleaseConfigRequirements
66- > ( requirements ?: R ) : Promise < Result < P , G , R > >
67-
68- export async function load ( requirements : Record < string , any > = { } ) {
156+ > (
157+ requirements ?: R ,
158+ loader ?: Loader
159+ ) : Promise < Result < P , G , R > >
160+
161+ export async function load (
162+ requirements : Record < string , any > = { } ,
163+ loader ?: Loader
164+ ) {
69165 const {
70166 config : configRequired ,
71167 ...reqs
@@ -81,6 +177,9 @@ export async function load(requirements: Record<string, any> = {}) {
81177
82178 validate ( config , reqs )
83179
180+ await loadAndSetIfQuery ( config , 'project' , loader )
181+ await loadAndSetIfQuery ( config , 'hosting' , loader )
182+
84183 return config
85184 } catch ( err ) {
86185 if ( configRequired ) {
0 commit comments