Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#54 Computed Fields] #86

Merged
merged 4 commits into from
Dec 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/flat-bikes-own.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"mddb": minor
---

[#54 Computed Fields]
- Introduce a configuration parameter to support the inclusion of a custom function for computing fields.
37 changes: 34 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,18 +115,49 @@ const blogs = await mddb.getFiles({
});
```

# Configuring `markdowndb.config.js`
## Computed Fields

This feature helps you define functions that compute additional fields you want to include.

### Step 1: Define the Computed Field Function

Next, define a function that computes the additional field you want to include. In this example, we have a function named `addTitle` that extracts the title from the first heading in the AST (Abstract Syntax Tree) of a Markdown file.

```javascript
const addTitle = (fileInfo, ast) => {
// Find the first header node in the AST
const headerNode = ast.children.find((node) => node.type === "heading");

// Extract the text content from the header node
const title = headerNode
? headerNode.children.map((child) => child.value).join("")
: "";

// Add the title property to the fileInfo
fileInfo.title = title;
};
```

### Step 2: Indexing the Folder with Computed Fields

Now, use the `client.indexFolder` method to scan and index the folder containing your Markdown files. Pass the `addTitle` function in the `computedFields` option array to include the computed title in the database.

```javascript
client.indexFolder(folderPath: "PATH_TO_FOLDER", customConfig: { computedFields: [addTitle] });
```

## Configuring `markdowndb.config.js`

- Implement computed fields to dynamically calculate values based on specified logic or dependencies.
- Specify the patterns for including or excluding files in MarkdownDB.

## Example Configuration
### Example Configuration

Here's an example `markdowndb.config.js` with custom configurations:

```javascript
export default {
customFields: [
computedFields: [
(fileInfo, ast) => {
// Your custom logic here
},
Expand Down
6 changes: 6 additions & 0 deletions src/lib/CustomConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { FileInfo } from "./process.js";
import { Root } from "remark-parse/lib/index.js";

export interface CustomConfig {
computedFields?: ((fileInfo: FileInfo, ast: Root) => any)[];

Check warning on line 5 in src/lib/CustomConfig.ts

View workflow job for this annotation

GitHub Actions / Lint & format check

Unexpected any. Specify a different type
}
6 changes: 5 additions & 1 deletion src/lib/indexFolder.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
import { CustomConfig } from "./CustomConfig.js";
import { FileInfo, processFile } from "./process.js";
import { recursiveWalkDir } from "./recursiveWalkDir.js";

export function indexFolder(
folderPath: string,
pathToUrlResolver: (filePath: string) => string,
config: CustomConfig,
ignorePatterns?: RegExp[]
) {
const filePathsToIndex = recursiveWalkDir(folderPath);
const filteredFilePathsToIndex = filePathsToIndex.filter((filePath) =>
shouldIncludeFile(filePath, ignorePatterns)
);
const files: FileInfo[] = [];
const computedFields = config.computedFields || [];
for (const filePath of filteredFilePathsToIndex) {
const fileObject = processFile(
folderPath,
filePath,
pathToUrlResolver,
filePathsToIndex
filePathsToIndex,
computedFields
);
files.push(fileObject);
}
Expand Down
4 changes: 4 additions & 0 deletions src/lib/markdowndb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
getUniqueValues,
} from "./databaseUtils.js";
import fs from "fs";
import { CustomConfig } from "./CustomConfig.js";

const defaultFilePathToUrl = (filePath: string) => {
let url = filePath
Expand All @@ -22,7 +23,7 @@
return encodeURI(url);
};

const resolveLinkToUrlPath = (link: string, sourceFilePath?: string) => {

Check warning on line 26 in src/lib/markdowndb.ts

View workflow job for this annotation

GitHub Actions / Lint & format check

'resolveLinkToUrlPath' is assigned a value but never used
if (!sourceFilePath) {
return link;
}
Expand Down Expand Up @@ -72,16 +73,19 @@
// TODO support glob patterns
ignorePatterns = [],
pathToUrlResolver = defaultFilePathToUrl,
customConfig = {},
}: {
folderPath: string;
ignorePatterns?: RegExp[];
pathToUrlResolver?: (filePath: string) => string;
customConfig?: CustomConfig;
}) {
await resetDatabaseTables(this.db);

const fileObjects = indexFolder(
folderPath,
pathToUrlResolver,
customConfig,
ignorePatterns
);
const filesToInsert = fileObjects.map(mapFileToInsert);
Expand Down Expand Up @@ -248,7 +252,7 @@
}
}

function writeJsonToFile(filePath: string, jsonData: any[]) {

Check warning on line 255 in src/lib/markdowndb.ts

View workflow job for this annotation

GitHub Actions / Lint & format check

Unexpected any. Specify a different type
try {
const directory = path.dirname(filePath);
if (!fs.existsSync(directory)) {
Expand All @@ -257,7 +261,7 @@

const jsonString = JSON.stringify(jsonData, null, 2);
fs.writeFileSync(filePath, jsonString);
} catch (error: any) {

Check warning on line 264 in src/lib/markdowndb.ts

View workflow job for this annotation

GitHub Actions / Lint & format check

Unexpected any. Specify a different type
console.error(`Error writing data to ${filePath}: ${error}`);
}
}
1 change: 1 addition & 0 deletions src/lib/parseFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
metadata.tasks = tasks;

return {
ast,
metadata,
links,
};
Expand Down Expand Up @@ -64,7 +65,7 @@

const nodes = selectAll("*", ast);
for (let index = 0; index < nodes.length; index++) {
const node: any = nodes[index];

Check warning on line 68 in src/lib/parseFile.ts

View workflow job for this annotation

GitHub Actions / Lint & format check

Unexpected any. Specify a different type
if (node.value) {
const textTags = node.value.match(/(?:^|\s)(#(\w+|\/|-|_)+)/g);
if (textTags) {
Expand Down
10 changes: 8 additions & 2 deletions src/lib/process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import path from "path";

import { File } from "./schema.js";
import { WikiLink, parseFile } from "./parseFile.js";
import { Root } from "remark-parse/lib/index.js";

export interface FileInfo extends File {
tags: string[];
Expand All @@ -16,7 +17,8 @@ export function processFile(
rootFolder: string,
filePath: string,
pathToUrlResolver: (filePath: string) => string,
filePathsToIndex: string[]
filePathsToIndex: string[],
computedFields: ((fileInfo: FileInfo, ast: Root) => any)[]
) {
// Remove rootFolder from filePath
const relativePath = path.relative(rootFolder, filePath);
Expand Down Expand Up @@ -52,7 +54,7 @@ export function processFile(
flag: "r",
});

const { metadata, links } = parseFile(source, {
const { ast, metadata, links } = parseFile(source, {
from: relativePath,
permalinks: filePathsToIndex,
});
Expand All @@ -66,6 +68,10 @@ export function processFile(

const tags = metadata?.tags || [];
fileInfo.tags = tags;
for (let index = 0; index < computedFields.length; index++) {
const customFieldFunction = computedFields[index];
customFieldFunction(fileInfo, ast);
}

return fileInfo;
}
1 change: 1 addition & 0 deletions src/tests/process.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ describe("Can parse a file and get file info", () => {
pathToContentFixture,
fullPath,
(filePath) => filePath,
[],
[]
);

Expand Down
Loading