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

Add referenced node to exported discourse context #246

Merged
merged 3 commits into from
Apr 8, 2024
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
7 changes: 7 additions & 0 deletions src/discourseGraphsMode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,13 @@ const initializeDiscourseGraphsMode = async (args: OnloadArgs) => {
items: ["alias", "wikilinks"],
},
} as Field<SelectField>,
{
title: "append referenced node",
// @ts-ignore
Panel: FlagPanel,
description:
"If a referenced node is defined in a node's format, it will be appended to the discourse context",
},
],
},
],
Expand Down
55 changes: 53 additions & 2 deletions src/utils/formatUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import discourseNodeFormatToDatalog from "./discourseNodeFormatToDatalog";
import createOverlayRender from "roamjs-components/util/createOverlayRender";
import { render as renderToast } from "roamjs-components/components/Toast";
import FormDialog from "roamjs-components/components/FormDialog";
import { QBClause, Result } from "./types";
import findDiscourseNode from "./findDiscourseNode";
import extractTag from "roamjs-components/util/extractTag";
import getPageUidByPageTitle from "roamjs-components/queries/getPageUidByPageTitle";

type FormDialogProps = Parameters<typeof FormDialog>[0];
const renderFormDialog = createOverlayRender<FormDialogProps>(
Expand Down Expand Up @@ -87,12 +91,21 @@ export const getNewDiscourseNodeText = async ({
};

export const getReferencedNodeInFormat = ({
format,
uid,
format: providedFormat,
discourseNodes = getDiscourseNodes(),
}: {
format: string;
uid?: string;
format?: string;
discourseNodes?: DiscourseNode[];
}) => {
let format = providedFormat;
if (!format) {
const discourseNode = findDiscourseNode(uid);
if (discourseNode) format = discourseNode.format;
}
if (!format) return null;

const regex = /{([\w\d-]*)}/g;
const matches = [...format.matchAll(regex)];

Expand All @@ -109,3 +122,41 @@ export const getReferencedNodeInFormat = ({

return null;
};

export const findReferencedNodeInText = ({
text,
discourseNode,
}: {
text: string;
discourseNode: DiscourseNode;
}) => {
// assumes that the referenced node in format has a specification
// which includes:
// has title relation
// a (.*?) pattern in it's target
// eg: Source: /^@(.*?)$/

const specification = discourseNode.specification;
const titleCondition = specification.find(
(s): s is QBClause => s.type === "clause" && s.relation === "has title"
);
if (!titleCondition) return null;

// Remove leading and trailing slashes and start/end modifiers
const patternStr = titleCondition.target.slice(1, -1).replace(/^\^|\$$/g, "");

// Since we assume there's always a (.*?), we replace it with a specific pattern to capture text within [[ ]]
// This assumes (.*?) is meant to capture the relevant content
const modifiedPatternStr = patternStr.replace(/\(\.\*\?\)/, "(.*?)");
const dynamicPattern = new RegExp(`\\[\\[${modifiedPatternStr}\\]\\]`, "g");
const match = text.match(dynamicPattern)?.[0] || "";
if (!match) return null;

const pageTitle = extractTag(match);
const uid = getPageUidByPageTitle(pageTitle);

return {
uid,
text: pageTitle,
} as Result;
};
63 changes: 57 additions & 6 deletions src/utils/getExportTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ import getPageMetadata from "./getPageMetadata";
import getDiscourseContextResults from "./getDiscourseContextResults";
import fireQuery from "./fireQuery";
import { ExportTypes } from "./types";
import {
findReferencedNodeInText,
getReferencedNodeInFormat,
} from "./formatUtils";

export const updateExportProgress = (detail: {
progress: number;
Expand Down Expand Up @@ -219,6 +223,44 @@ const toMarkdown = ({
return `${indentation}${viewTypePrefix}${headingPrefix}${finalProcessedText}${lineBreak}${childrenMarkdown}`;
};

const handleDiscourseContext = async ({
includeDiscourseContext,
uid,
pageTitle,
isSamePageEnabled,
appendRefNodeContext,
}: {
includeDiscourseContext: boolean;
uid: string;
pageTitle: string;
isSamePageEnabled: boolean;
appendRefNodeContext: boolean;
}) => {
if (!includeDiscourseContext) return [];

const discourseResults = await getDiscourseContextResults({
uid,
isSamePageEnabled,
});
if (!appendRefNodeContext) return discourseResults;

const referencedDiscourseNode = getReferencedNodeInFormat({ uid });
if (referencedDiscourseNode) {
const referencedResult = findReferencedNodeInText({
text: pageTitle,
discourseNode: referencedDiscourseNode,
});
if (!referencedResult) return discourseResults;
const appendedContext = {
label: referencedDiscourseNode.text,
results: { [referencedResult.uid]: referencedResult },
};
return [...discourseResults, appendedContext];
}

return discourseResults;
};

type getExportTypesProps = {
results?: ExportDialogProps["results"];
exportId: string;
Expand Down Expand Up @@ -390,6 +432,10 @@ const getExportTypes = ({
tree: exportTree.children,
key: "resolve block embeds",
}).uid;
const appendRefNodeContext = !!getSubTree({
tree: exportTree.children,
key: "append referenced node",
}).uid;
const yaml = frontmatter.length
? frontmatter
: [
Expand All @@ -406,6 +452,7 @@ const getExportTypes = ({
maxFilenameLength,
removeSpecialCharacters,
linkType,
appendRefNodeContext,
};
};

Expand All @@ -424,6 +471,7 @@ const getExportTypes = ({
maxFilenameLength,
removeSpecialCharacters,
linkType,
appendRefNodeContext,
} = getExportSettings();
const allPages = await getPageData(
isSamePageEnabled,
Expand Down Expand Up @@ -452,12 +500,15 @@ const getExportTypes = ({
type,
};
const treeNode = getFullTreeByParentUid(uid);
const discourseResults = includeDiscourseContext
? await getDiscourseContextResults({
uid,
isSamePageEnabled,
})
: [];

const discourseResults = await handleDiscourseContext({
includeDiscourseContext,
pageTitle: text,
uid,
isSamePageEnabled,
appendRefNodeContext,
});

const referenceResults = isFlagEnabled("render references")
? (
window.roamAlphaAPI.data.fast.q(
Expand Down
Loading