This repository has been archived by the owner on Jul 24, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
EleventyLoad.js
160 lines (133 loc) · 4.32 KB
/
EleventyLoad.js
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
const fs = require("fs");
const path = require("path");
const pkg = require("./package.json");
const { emitFile } = require("./utils");
module.exports = class EleventyLoad {
constructor(options, cache, resource, content, config, cachePath) {
this.options = options;
this.cache = cache;
// Create context for loaders
this.context = {
config,
addDependency: this.addDependency.bind(this),
// Explicit bindings for utils
emitFile: emitFile.bind(this),
};
// Start processing initial dependency
return this.addDependency(resource, content, cachePath);
}
debug(string, override) {
if (this.options.debug || override) {
console.info(`[${pkg.name}] ${string}`);
}
}
// Process additional dependencies straight away
async addDependency(resource, content = null, cachePath) {
const [resourcePath, resourceQuery] = resource.split(/(?=\?)/g);
// Dependent resource
const dependentResource = {
resource: this.context.resource,
resourcePath: this.context.resourcePath,
resourceQuery: this.context.resourceQuery,
};
// Resolve resource for consistency
const resolvedResource = path.resolve(
this.context.config.inputDir,
resource
);
const resolvedResourcePath = path.resolve(
this.context.config.inputDir,
resourcePath
);
// Define the current resource
const currentResource = {
resource,
resourcePath,
resourceQuery,
};
// Update context with current resource
this.context = {
...this.context,
...currentResource,
};
cachePath = cachePath || resolvedResource;
// Start processing file and add to cache
if (!this.cache.hasOwnProperty(cachePath)) {
this.debug(`Processing resource: ${resource}`);
this.cache[cachePath] = this.processFile(
resource,
resolvedResourcePath,
resourceQuery,
content
);
}
// Wait for resource to be processed
const result = await this.cache[cachePath];
// Reset to dependent resource
this.context = {
...this.context,
...dependentResource,
};
return result;
}
testCondition(condition, test) {
// If there's no condition, return true immediately
if (condition === null || condition === undefined) {
return true;
}
// If the condition is boolean, return that value
if (typeof condition === "boolean") {
return !!condition;
} else if (condition instanceof Boolean) {
return condition.valueOf();
}
// If the condition is a regular expression, test it
if (condition instanceof RegExp) {
return condition.test(test);
}
// If the condition is an array, do an OR test on its values
if (Array.isArray(condition)) {
return condition.some((value) => this.testCondition(value, test));
}
// Finally, apply a basic equality test
return "" + condition === test;
}
// Get loaders for resource
getLoaders(resourcePath, resourceQuery) {
// Find which rule matches the given resource path
const rule = this.options.rules.find(
(rule) =>
this.testCondition(rule.test, resourcePath) &&
this.testCondition(rule.resourceQuery, resourceQuery)
);
// Return loaders if they exist, else null
return rule && rule.loaders ? rule.loaders : null;
}
// Load content of file
getContent(resourcePath, loaders) {
// If loader has raw property, load content as buffer instead of string
const encoding = loaders[0].loader.raw ? null : "utf8";
return fs.readFileSync(resourcePath, { encoding });
}
// Process file with the given loaders
async processFile(resource, resourcePath, resourceQuery, content) {
// Get loaders for file
const loaders = this.getLoaders(resourcePath, resourceQuery);
// Return content or path if no loaders match
if (loaders === null) return content || resource;
// If content isn't passed in, load from path
if (content === null) {
try {
content = await this.getContent(resourcePath, loaders);
} catch {
return resource;
}
}
// Apply loaders to content in order
for (const loader of loaders) {
const loaderFunction = loader.loader.bind(this.context);
content = await loaderFunction(content, loader.options);
}
return content;
}
};