Skip to content

Commit

Permalink
fix: regexp issues in syntax highlighting
Browse files Browse the repository at this point in the history
  • Loading branch information
DylanPiercey committed Jul 15, 2022
1 parent 5f0ec0d commit c1f0d97
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 13 deletions.
2 changes: 1 addition & 1 deletion .changeset/olive-mails-clap.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
"@marko/language-server": patch
---

Implements document links provider (currently for stylesheets).
Implements document links provider.
113 changes: 113 additions & 0 deletions server/src/service/marko/document-links/extract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import type { TaglibLookup } from "@marko/babel-utils";
import { DocumentLink } from "vscode-languageserver";
import type { TextDocument } from "vscode-languageserver-textdocument";
import { URI } from "vscode-uri";
import {
type Node,
type Range,
type parse,
NodeType,
} from "../../../utils/parser";
import resolveUrl from "../../../utils/resolve-url";

const importTagReg = /(['"])<((?:[^\1\\>]+|\\.)*)>?\1/g;
const linkedAttrs: Record<string, Set<string>> = {
src: new Set([
"audio",
"embed",
"iframe",
"img",
"input",
"script",
"source",
"track",
"video",
]),
href: new Set(["a", "area", "link"]),
data: new Set(["object"]),
poster: new Set(["video"]),
};

/**
* Iterate over the Marko CST and extract all the file links in the document.
*/
export function extractDocumentLinks(
doc: TextDocument,
parsed: ReturnType<typeof parse>,
lookup: TaglibLookup
): DocumentLink[] {
if (URI.parse(doc.uri).scheme === "untitled") {
return [];
}

const links: DocumentLink[] = [];
const { program } = parsed;
const code = doc.getText();
const read = (range: Range) => code.slice(range.start, range.end);
const visit = (node: Node.ChildNode) => {
switch (node.type) {
case NodeType.Tag:
if (node.attrs && node.nameText) {
for (const attr of node.attrs) {
if (
attr.type === NodeType.AttrNamed &&
attr.value?.type === NodeType.AttrValue &&
/^['"]$/.test(code[attr.value.value.start])
) {
const attrName = read(attr.name);
if (linkedAttrs[attrName]?.has(node.nameText)) {
links.push(
DocumentLink.create(
{
start: parsed.positionAt(attr.value.value.start),
end: parsed.positionAt(attr.value.value.end),
},
resolveUrl(read(attr.value.value).slice(1, -1), doc.uri)
)
);
}
}
}
}
if (node.body) {
for (const child of node.body) {
visit(child);
}
}

break;
}
};

for (const item of program.static) {
// check for import statement (this currently only support the tag import shorthand).
if (item.type === NodeType.Statement && code[item.start] === "i") {
importTagReg.lastIndex = 0;
const value = parsed.read(item);
const match = importTagReg.exec(value);
if (match) {
const [{ length }, , tagName] = match;
const tagDef = lookup.getTag(tagName);
const fileForTag = tagDef && (tagDef.template || tagDef.renderer);

if (fileForTag) {
links.push(
DocumentLink.create(
{
start: parsed.positionAt(item.start + match.index),
end: parsed.positionAt(item.start + match.index + length),
},
fileForTag
)
);
}
}
}
}

for (const item of program.body) {
visit(item);
}

return links;
}
16 changes: 16 additions & 0 deletions server/src/service/marko/document-links/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { DocumentLink } from "vscode-languageserver";
import { getCompilerInfo, parse } from "../../../utils/compiler";
import type { Plugin } from "../../types";
import { extractDocumentLinks } from "./extract";

const cache = new WeakMap<ReturnType<typeof parse>, DocumentLink[]>();

export const findDocumentLinks: Plugin["findDocumentLinks"] = async (doc) => {
const parsed = parse(doc);
let result = cache.get(parsed);
if (!result) {
result = extractDocumentLinks(doc, parsed, getCompilerInfo(doc).lookup);
cache.set(parsed, result);
}
return result;
};
2 changes: 2 additions & 0 deletions server/src/service/marko/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import type { Plugin } from "../types";
import { doComplete } from "./complete";
import { doValidate } from "./validate";
import { findDefinition } from "./definition";
import { findDocumentLinks } from "./document-links";
import { format } from "./format";

export default {
doComplete,
doValidate,
findDefinition,
findDocumentLinks,
format,
} as Plugin;
3 changes: 1 addition & 2 deletions server/src/service/stylesheet/extract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Node, Range, NodeType } from "../../utils/parser";
export function extractStyleSheets(
code: string,
program: Node.Program,
lookup: TaglibLookup | null | undefined
lookup: TaglibLookup
) {
let placeholderId = 0;
const extractorsByExt: Record<
Expand Down Expand Up @@ -84,7 +84,6 @@ export function extractStyleSheets(
if (
name === "#style" ||
(name === "style" &&
lookup &&
node.nameText &&
name === "style" &&
lookup.getTag(node.nameText)?.html)
Expand Down
12 changes: 2 additions & 10 deletions server/src/service/stylesheet/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { getCompilerInfo, parse } from "../../utils/compiler";
import { START_OF_FILE } from "../../utils/utils";
import type { Plugin } from "../types";
import { extractStyleSheets } from "./extract";
import { displayInformation } from "../../utils/messages";
import resolveUrl from "../../utils/resolve-url";

interface StyleSheetInfo {
virtualDoc: TextDocument;
Expand Down Expand Up @@ -143,14 +143,7 @@ const StyleSheetService: Partial<Plugin> = {
const { service, virtualDoc } = info;

for (const link of service.findDocumentLinks(virtualDoc, info.parsed, {
resolveReference(ref, baseUrl) {
const resolved = new URL(ref, new URL(baseUrl, "resolve://"));
if (resolved.protocol === "resolve:") {
// `baseUrl` is a relative URL.
return resolved.pathname + resolved.search + resolved.hash;
}
return resolved.toString();
},
resolveReference: resolveUrl,
})) {
if (link.target && updateRange(doc, info, link.range)) {
result.push(link);
Expand All @@ -159,7 +152,6 @@ const StyleSheetService: Partial<Plugin> = {
}

if (result.length) {
displayInformation(result.map((it) => it.target).join(","));
return result;
}
},
Expand Down
15 changes: 15 additions & 0 deletions server/src/utils/resolve-url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { fileURLToPath } from "url";

export default function resolveUrl(ref: string, baseUrl: string) {
const resolved = new URL(ref, new URL(baseUrl, "resolve://"));
if (resolved.protocol === "resolve:") {
// `baseUrl` is a relative URL.
return resolved.pathname + resolved.search + resolved.hash;
}

try {
return fileURLToPath(resolved);
} catch {
return undefined;
}
}

0 comments on commit c1f0d97

Please sign in to comment.