Skip to content

Commit

Permalink
rename site.copy() to site.add()
Browse files Browse the repository at this point in the history
  • Loading branch information
oscarotero committed Jan 25, 2025
1 parent a66a47b commit ed02647
Show file tree
Hide file tree
Showing 20 changed files with 145 additions and 206 deletions.
1 change: 1 addition & 0 deletions CHANGELOGv3.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Go to the `v1` branch to see the changelog of Lume 1.
### Changed
- Refactor source.build function to give priority to load over copy statically.
- Always load files with extensions that need to be (pre)processed instead copy them.
- Rename `site.copy()` to `site.add()`.
- Lume's components are now async.
- `jsx` plugin uses SSX library instead of React.
- `mdx` plugin no longer depends on a `jsx` plugin installed before.
Expand Down
4 changes: 2 additions & 2 deletions core/formats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ export interface Format {
*/
engines?: Engine[];

/** Whether this file must be copied instead loaded */
copy?: boolean | ((path: string) => string);
/** Whether this file must be added or not */
add?: boolean | ((path: string) => string);

/** Whether this format must be (pre)processed */
process?: boolean | Loader;
Expand Down
14 changes: 7 additions & 7 deletions core/site.ts
Original file line number Diff line number Diff line change
Expand Up @@ -460,28 +460,28 @@ export default class Site {
return this;
}

/** Copy static files or directories without processing */
copy(from: string, to?: string | ((path: string) => string)): this;
copy(from: string[], to?: (path: string) => string): this;
copy(
/** Add files or directories to the site */
add(from: string, to?: string | ((path: string) => string)): this;
add(from: string[], to?: (path: string) => string): this;
add(
from: string | string[],
to?: string | ((path: string) => string),
): this {
// File extensions
if (Array.isArray(from)) {
if (typeof to === "string") {
throw new Error(
`copy() files by extension expects a function as second argument but got a string "${to}"`,
`add() files by extension expects a function as second argument but got a string "${to}"`,
);
}

from.forEach((ext) => {
this.formats.set({ ext, copy: to ? to : true });
this.formats.set({ ext, add: to ? to : true });
});
return this;
}

this.source.addStaticPath(from, to);
this.source.addPath(from, to);
return this;
}

Expand Down
210 changes: 74 additions & 136 deletions core/source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export default class Source {
prettyUrls: boolean;

/** List of static files and folders to copy */
staticPaths = new Map<
addedPaths = new Map<
string,
{ dest: string | ((path: string) => string) | undefined; dirOnly: boolean }
>();
Expand Down Expand Up @@ -115,14 +115,14 @@ export default class Source {
this.filters.push(filter);
}

addStaticPath(from: string, to?: string | ((path: string) => string)) {
addPath(from: string, to?: string | ((path: string) => string)) {
if (from.startsWith("../")) {
throw new Error(
`It's not possible to copy files outsite the src directory ("${from}")`,
);
}

this.staticPaths.set(
this.addedPaths.set(
normalizePath(from.replace(/\/$/, "")),
{
dest: typeof to === "string" ? normalizePath(to) : to,
Expand Down Expand Up @@ -156,58 +156,70 @@ export default class Source {
dir: Entry,
parentPath: string,
parentComponents: Components,
parentData: RawData,
parentData: Partial<Data>,
pages: Page[],
staticFiles: StaticFile[],
copy?: (path: string) => string,
addDest?: (path: string) => string,
ignored = false,
): Promise<void> {
if (buildFilters.some((filter) => !filter(dir))) {
return;
}

// Load _data
const dirData = await this.#loadDirData(dir, parentData);
let dirPath = posix.join(parentPath, dirData.basename!);
const dirData = ignored
? parentData
: await this.#loadDirData(dir, parentData);
let dirPath = ignored
? parentPath
: posix.join(parentPath, dirData.basename!);

// Load _components
const dirComponents = await this.#loadDirComponents(
dir,
parentComponents,
dirData,
);

// Create the components proxy only if new components were found
if (dirComponents !== parentComponents) {
dirData[this.components.variable] = toProxy(
dirComponents,
this.extraCode,
const dirComponents = ignored
? parentComponents
: await this.#loadDirComponents(
dir,
parentComponents,
dirData,
);
}

// Store the directory data to be used by other plugins
this.data.set(dirPath, dirData);
if (!ignored) {
// Create the components proxy only if new components were found
if (dirComponents !== parentComponents) {
dirData[this.components.variable] = toProxy(
dirComponents,
this.extraCode,
);
}

// Load pages created with `site.page()`
for await (const page of this.#getDirPages(dirPath, dirData)) {
if (buildFilters.some((filter) => !filter(dir, page))) {
continue;
// Store the directory data to be used by other plugins
this.data.set(dirPath, dirData);

// Load pages created with `site.page()`
for await (const page of this.#getDirPages(dirPath, dirData)) {
if (buildFilters.some((filter) => !filter(dir, page))) {
continue;
}
pages.push(page);
}
pages.push(page);
}

// The folder is copied with `site.copy("folder")`
const copyExplicit = this.staticPaths.get(dir.path) ||
this.staticPaths.get(dirPath);
// The folder is added with `site.add("folder")`
const added = this.addedPaths.get(dir.path) ||
this.addedPaths.get(dirPath);

if (copyExplicit) {
const { dest } = copyExplicit;
if (added) {
ignored = false;
const { dest } = added;

if (typeof dest === "function") {
const previousCopy = copy;
copy = previousCopy ? (path: string) => dest(previousCopy(path)) : dest;
const previousDest = addDest;
addDest = previousDest
? (path: string) => dest(previousDest(path))
: dest;
} else {
dirPath = dest ?? dirPath;
copy ??= (path: string) => path;
addDest ??= (path: string) => path;
}
}

Expand All @@ -218,27 +230,27 @@ export default class Source {
}

if (entry.type === "file") {
let copyExplicit = this.staticPaths.get(entry.path);
let added = this.addedPaths.get(entry.path);

if (copyExplicit?.dirOnly) {
// the explicit copy must be a directory and this is a file
copyExplicit = undefined;
if (added?.dirOnly) {
// the added path must be a directory and this is a file
added = undefined;
}

// Check if the file must be ignored
if (!copyExplicit && this.#isIgnored(entry)) {
if (!added && this.#isIgnored(entry)) {
continue;
}

const format = this.formats.search(entry.path);
const format = ignored ? undefined : this.formats.search(entry.path);

// It's an unknown file format
// It's an unknown file format or we're in a ignored context
if (!format) {
// Copy the file
if (copyExplicit || copy) {
if (added || (addDest && !ignored)) {
const ext = posix.extname(entry.name);
staticFiles.push(
this.#copyFile(entry, dirPath, ext, copyExplicit?.dest, copy),
this.#copyFile(entry, dirPath, ext, added?.dest, addDest),
);
}
continue;
Expand All @@ -259,8 +271,8 @@ export default class Source {
continue;
}

// The format is copied with `site.copy([".ext"])`
if (format.copy || copyExplicit) {
// The format is added with `site.add([".ext"])`
if (format.add || added) {
// The format must be processed, so it's loaded
if (format.process) {
const page = await this.#loadPage(entry, format, dirData, dirPath);
Expand All @@ -277,7 +289,7 @@ export default class Source {
entry,
dirPath,
format.ext,
typeof format.copy === "function" ? format.copy : undefined,
typeof format.add === "function" ? format.add : undefined,
),
);
continue;
Expand All @@ -290,23 +302,22 @@ export default class Source {
if (entry.type === "directory") {
// Check if the folder must be ignored
if (
!copyExplicit &&
this.#isIgnored(entry) &&
(this.#isIgnored(entry) || ignored) &&
entry.path !== "/.well-known"
) {
// Check if there's an inner entry that must be copied
for (const path of this.staticPaths.keys()) {
// Check if there's an inner entry that must be added
let stop = true;

for (const path of this.addedPaths.keys()) {
if (path.startsWith(entry.path)) {
this.#searchStaticFiles(
buildFilters,
entry,
dirPath,
staticFiles,
);
stop = false;
break;
}
}
continue;

if (stop) {
continue;
}
}

await this.#load(
Expand All @@ -317,94 +328,21 @@ export default class Source {
dirData,
pages,
staticFiles,
copy,
addDest,
ignored,
);
}
}
}

/** Check if the entry must be ignored by Lume */
#isIgnored(entry: Entry) {
return entry.name.startsWith(".") ||
entry.name.startsWith("_") ||
this.ignored.has(entry.path) ||
this.filters.some((filter) => filter(entry.path));
}

#searchStaticFiles(
buildFilters: BuildFilter[],
dir: Entry,
parentPath: string,
staticFiles: StaticFile[],
copy?: (path: string) => string,
): void {
if (buildFilters.some((filter) => !filter(dir))) {
return;
}

let dirPath = posix.join(parentPath, dir.name);

// The folder is copied with `site.copy("folder")`
const copyExplicit = this.staticPaths.get(dir.path);

if (copyExplicit) {
const { dest } = copyExplicit;

if (typeof dest === "function") {
const previousCopy = copy;
copy = previousCopy ? (path: string) => dest(previousCopy(path)) : dest;
} else {
dirPath = dest ?? dirPath;
copy ??= (path: string) => path;
}
}

// Iterate over the directory entries
for (const entry of dir.children.values()) {
if (buildFilters.some((filter) => !filter(entry))) {
continue;
}

if (entry.type === "file") {
let copyExplicit = this.staticPaths.get(entry.path);

if (copyExplicit?.dirOnly) {
// the explicit copy must be a directory and this is a file
copyExplicit = undefined;
}

// Check if the file must be ignored
if (!copyExplicit && this.#isIgnored(entry)) {
continue;
}

// Copy the file
if (copyExplicit || copy) {
const ext = posix.extname(entry.name);
staticFiles.push(
this.#copyFile(entry, dirPath, ext, copyExplicit?.dest, copy),
);
}
continue;
}

if (entry.type === "directory") {
// Check if a inner entry must be copied
for (const path of this.staticPaths.keys()) {
if (path.startsWith(entry.path)) {
this.#searchStaticFiles(
buildFilters,
entry,
dirPath,
staticFiles,
copy,
);
break;
}
}
}
}
}

/** Load a folder's _data and merge it with the parent data */
async #loadDirData(dir: Entry, parentData: RawData): Promise<Partial<Data>> {
// Parse the directory's basename
Expand Down Expand Up @@ -715,16 +653,16 @@ function getOutputPath(
entry: Entry,
path: string,
dest?: string | ((path: string) => string),
copy?: (path: string) => string,
addedDest?: (path: string) => string,
): string {
if (typeof dest === "string") {
return dest;
}

let output = posix.join(path, entry.name);

if (copy) {
output = copy(output);
if (addedDest) {
output = addedDest(output);
}

return typeof dest === "function" ? dest(output) : output;
Expand Down
Loading

0 comments on commit ed02647

Please sign in to comment.