mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-19 06:20:38 -07:00
feat: relativeReference for render/include/layout, #395
- `relativeReference` is enabled by default, set to `false` to disable
- Referenced files are still constrained within root/partias/layouts
- fix: relative filenames are not constrained (which allows arbitrary filesystem read)
Example Usage:
{% render "../foo/bar.html" %}
Note:
../foo/bar.html' should also be within `partials` (or `root` if `partials` not set)
This commit is contained in:
+32
-4
@@ -6,6 +6,7 @@ interface LoaderOptions {
|
||||
root: string[];
|
||||
partials: string[];
|
||||
layouts: string[];
|
||||
relativeReference: boolean;
|
||||
}
|
||||
export enum LookupType {
|
||||
Partials = 'partials',
|
||||
@@ -19,19 +20,40 @@ export class Loader {
|
||||
this.options = options
|
||||
}
|
||||
|
||||
public * lookup (file: string, type: LookupType, sync?: boolean) {
|
||||
public * lookup (file: string, type: LookupType, sync?: boolean, currentFile?: string) {
|
||||
const { fs } = this.options
|
||||
const dirs = this.options[type]
|
||||
for (const filepath of this.candidates(file, dirs)) {
|
||||
for (const filepath of this.candidates(file, dirs, currentFile)) {
|
||||
if (sync ? fs.existsSync(filepath) : yield fs.exists(filepath)) return filepath
|
||||
}
|
||||
throw this.lookupError(file, dirs)
|
||||
}
|
||||
|
||||
private * candidates (file: string, dirs: string[]) {
|
||||
public shouldLoadRelative (currentFile: string) {
|
||||
return this.options.relativeReference && this.isRelativePath(currentFile)
|
||||
}
|
||||
|
||||
public isRelativePath (path: string) {
|
||||
return path.startsWith('./') || path.startsWith('../')
|
||||
}
|
||||
|
||||
public * candidates (file: string, dirs: string[], currentFile?: string) {
|
||||
const { fs, extname } = this.options
|
||||
if (this.shouldLoadRelative(file) && currentFile) {
|
||||
const referenced = fs.resolve(this.dirname(currentFile), file, extname)
|
||||
for (const dir of dirs) {
|
||||
if (referenced.startsWith(dir)) {
|
||||
// the relatively referenced file is within one of root dirs
|
||||
yield referenced
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const dir of dirs) {
|
||||
yield fs.resolve(dir, file, extname)
|
||||
const referenced = fs.resolve(dir, file, extname)
|
||||
if (referenced.startsWith(dir)) {
|
||||
yield referenced
|
||||
}
|
||||
}
|
||||
if (fs.fallback !== undefined) {
|
||||
const filepath = fs.fallback(file)
|
||||
@@ -39,6 +61,12 @@ export class Loader {
|
||||
}
|
||||
}
|
||||
|
||||
private dirname (path: string) {
|
||||
const segments = path.split('/')
|
||||
segments.pop()
|
||||
return segments.join('/')
|
||||
}
|
||||
|
||||
private lookupError (file: string, roots: string[]) {
|
||||
const err = new Error('ENOENT') as any
|
||||
err.message = `ENOENT: Failed to lookup "${file}" in "${roots}"`
|
||||
|
||||
Reference in New Issue
Block a user