Last active
April 7, 2024 01:15
-
-
Save nuintun/16a4df9a115da47c0166cb1d871f783e to your computer and use it in GitHub Desktop.
rollup-import-meta-glob.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @module import-meta-glob | |
*/ | |
import path from 'path'; | |
import glob from 'fast-glob'; | |
import { Plugin } from 'rollup'; | |
import MagicString from 'magic-string'; | |
import { stripLiteral } from 'strip-literal'; | |
import acorn, { parseExpressionAt } from 'acorn'; | |
import { normalizePath } from '@rollup/pluginutils'; | |
interface ImportMatch { | |
ast: acorn.Node; | |
patterns: string[]; | |
} | |
const IMPORT_GLOB_RE = /\bimport\.meta\.glob(?:<\w+>)?\s*\(/g; | |
function getLiteral(element: acorn.Literal): string { | |
const { value } = element; | |
if (typeof value !== 'string') { | |
throw new Error(`Expected glob to be a string but got ${typeof value}`); | |
} | |
return value; | |
} | |
function getMatches(code: string): ImportMatch[] { | |
const importMatches: ImportMatch[] = []; | |
const matches = stripLiteral(code).matchAll(IMPORT_GLOB_RE); | |
for (const match of matches) { | |
const ast = parseExpressionAt(code, match.index!, { | |
ranges: true, | |
sourceType: 'module', | |
ecmaVersion: 'latest' | |
}); | |
if (ast.type === 'CallExpression') { | |
const args = ast.arguments; | |
// Only accept one argument | |
if (args.length !== 1) { | |
throw new Error('Expected 1 argument, but got ' + args.length); | |
} | |
const [argument] = args; | |
const patterns: string[] = []; | |
switch (argument.type) { | |
case 'Literal': | |
patterns.push(getLiteral(argument)); | |
break; | |
case 'ArrayExpression': | |
const { elements } = argument; | |
for (const element of elements) { | |
if (element?.type === 'Literal') { | |
patterns.push(getLiteral(element)); | |
} else { | |
throw new Error('Expected array argument to be a literal array'); | |
} | |
} | |
break; | |
default: | |
throw new Error('Expected argument to be a literal or literal array'); | |
} | |
importMatches.push({ ast, patterns }); | |
} | |
} | |
return importMatches; | |
} | |
export default (): Plugin => { | |
return { | |
name: 'import-meta-glob', | |
async transform(code: string, id: string) { | |
if (code.includes('import.meta.glob')) { | |
const matches = getMatches(code); | |
const string = new MagicString(code); | |
for (const { ast, patterns } of matches) { | |
const imports: string[] = []; | |
for (const pattern of patterns) { | |
const files = await glob.async(pattern, { | |
dot: true, | |
absolute: true, | |
cwd: path.dirname(id) | |
}); | |
for (const file of files) { | |
imports.push(`import('${normalizePath(file)}')`); | |
} | |
} | |
string.overwrite(ast.start, ast.end, `[${imports.join(',\n')}]`); | |
} | |
return string.toString(); | |
} | |
} | |
}; | |
}; |
Author
nuintun
commented
Apr 2, 2024
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment