1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
import path from 'path';
import { fdir, PathsOutput } from 'fdir';
/**
* Handling for import.meta.glob and import.meta.globEager
*/
interface GlobOptions {
namespace: string;
filename: string;
}
interface GlobResult {
/** Array of import statements to inject */
imports: Set<string>;
/** Replace original code with */
code: string;
}
const crawler = new fdir();
/** General glob handling */
function globSearch(spec: string, { filename }: { filename: string }): string[] {
try {
// Note: fdir’s glob requires you to do some work finding the closest non-glob folder.
// For example, this fails: .glob("./post/*.md").crawl("/…/src/pages") ❌
// …but this doesn’t: .glob("*.md").crawl("/…/src/pages/post") ✅
let globDir = '';
let glob = spec;
for (const part of spec.split('/')) {
if (!part.includes('*')) {
// iterate through spec until first '*' is reached
globDir = path.posix.join(globDir, part); // this must be POSIX-style
glob = glob.replace(`${part}/`, ''); // move parent dirs off spec, and onto globDir
} else {
// at first '*', exit
break;
}
}
const cwd = path.join(path.dirname(filename), globDir.replace(/\//g, path.sep)); // this must match OS (could be '/' or '\')
let found = crawler.glob(glob).crawl(cwd).sync() as PathsOutput;
if (!found.length) {
throw new Error(`No files matched "${spec}" from ${filename}`);
}
return found.map((importPath) => {
if (importPath.startsWith('http') || importPath.startsWith('.')) return importPath;
return `./` + globDir + '/' + importPath;
});
} catch (err) {
throw new Error(`No files matched "${spec}" from ${filename}`);
}
}
/** Astro.fetchContent() */
export function fetchContent(spec: string, { namespace, filename }: GlobOptions): GlobResult {
let code = '';
const imports = new Set<string>();
const importPaths = globSearch(spec, { filename });
// gather imports
importPaths.forEach((importPath, j) => {
const id = `${namespace}_${j}`;
imports.add(`import { __content as ${id} } from '${importPath}';`);
// add URL if this appears within the /pages/ directory (probably can be improved)
const fullPath = path.resolve(path.dirname(filename), importPath);
if (fullPath.includes(`${path.sep}pages${path.sep}`)) {
const url = importPath.replace(/^\./, '').replace(/\.md$/, '');
imports.add(`${id}.url = '${url}';`);
}
});
// generate replacement code
code += `${namespace} = [${importPaths.map((_, j) => `${namespace}_${j}`).join(',')}];\n`;
return { imports, code };
}
|