Format authored monorepo code with pinned language formatters
This commit is contained in:
@@ -17,20 +17,26 @@ export const parseQx = (source: string, fileName = "<memory>") => {
|
||||
kind: QuixosCapabilityParser.ruleNames[context.ruleIndex]!,
|
||||
start: offset(context.start?.start ?? 0),
|
||||
end: offset((context.stop?.stop ?? -1) + 1),
|
||||
children: context.children.flatMap((child) => child instanceof ParserRuleContext ? [node(child)] : []),
|
||||
children: context.children.flatMap((child) => (child instanceof ParserRuleContext ? [node(child)] : [])),
|
||||
});
|
||||
return {
|
||||
source, fileName,
|
||||
source,
|
||||
fileName,
|
||||
root: node(parsed.tree),
|
||||
diagnostics: parsed.diagnostics.map((diagnostic) => {
|
||||
const line = source.split("\n")[diagnostic.line - 1] ?? "";
|
||||
return { ...diagnostic, column: [...line].slice(0, diagnostic.column).join("").length };
|
||||
}),
|
||||
tokens: parsed.tokens.getTokens().filter((token) => token.type !== -1).map((token) => ({
|
||||
kind: QuixosCapabilityParser.symbolicNames[token.type] ?? "token",
|
||||
start: offset(token.start), end: offset(token.stop + 1),
|
||||
text: token.text ?? "", trivia: token.channel !== 0,
|
||||
})),
|
||||
tokens: parsed.tokens
|
||||
.getTokens()
|
||||
.filter((token) => token.type !== -1)
|
||||
.map((token) => ({
|
||||
kind: QuixosCapabilityParser.symbolicNames[token.type] ?? "token",
|
||||
start: offset(token.start),
|
||||
end: offset(token.stop + 1),
|
||||
text: token.text ?? "",
|
||||
trivia: token.channel !== 0,
|
||||
})),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -41,8 +47,14 @@ export const applySourceEdits = (source: string, edits: readonly SourceEdit[]) =
|
||||
let previousStart = -1;
|
||||
let result = "";
|
||||
for (const edit of sorted) {
|
||||
if (!Number.isInteger(edit.start) || !Number.isInteger(edit.end) ||
|
||||
edit.start < end || edit.start === previousStart || edit.end < edit.start || edit.end > source.length) {
|
||||
if (
|
||||
!Number.isInteger(edit.start) ||
|
||||
!Number.isInteger(edit.end) ||
|
||||
edit.start < end ||
|
||||
edit.start === previousStart ||
|
||||
edit.end < edit.start ||
|
||||
edit.end > source.length
|
||||
) {
|
||||
throw new Error("Invalid or overlapping source edits");
|
||||
}
|
||||
result += source.slice(end, edit.start) + edit.text;
|
||||
@@ -68,14 +80,27 @@ export const lintQx = (source: string, fileName = "<memory>") => {
|
||||
const importPath: string = JSON.parse(source.slice(literal.start, literal.end));
|
||||
let message: string | undefined;
|
||||
let code = "invalid-source-import";
|
||||
try { validateQxImportPath(importPath); } catch (error) { message = (error as Error).message; }
|
||||
if (!message && seen.has(importPath)) { code = "duplicate-source-import"; message = `Repeated local import ${importPath}`; }
|
||||
try {
|
||||
validateQxImportPath(importPath);
|
||||
} catch (error) {
|
||||
message = (error as Error).message;
|
||||
}
|
||||
if (!message && seen.has(importPath)) {
|
||||
code = "duplicate-source-import";
|
||||
message = `Repeated local import ${importPath}`;
|
||||
}
|
||||
seen.add(importPath);
|
||||
if (message) {
|
||||
const prefix = source.slice(0, node.start);
|
||||
diagnostics.push({ phase: "syntax", code, message, fileName,
|
||||
line: prefix.split("\n").length, column: prefix.length - prefix.lastIndexOf("\n") - 1,
|
||||
severity: code === "duplicate-source-import" ? "warning" : "error" });
|
||||
diagnostics.push({
|
||||
phase: "syntax",
|
||||
code,
|
||||
message,
|
||||
fileName,
|
||||
line: prefix.split("\n").length,
|
||||
column: prefix.length - prefix.lastIndexOf("\n") - 1,
|
||||
severity: code === "duplicate-source-import" ? "warning" : "error",
|
||||
});
|
||||
}
|
||||
}
|
||||
return diagnostics;
|
||||
@@ -117,12 +142,15 @@ export const addWorkspaceImport = (source: string, importPath: string) => {
|
||||
}
|
||||
const brace = syntax.tokens.find((token) => token.kind === "LBRACE")!;
|
||||
const newline = source.includes("\r\n") ? "\r\n" : "\n";
|
||||
return applySourceEdits(source, [{ start: brace.end, end: brace.end,
|
||||
text: `${newline} import ${JSON.stringify(importPath)};` }]);
|
||||
return applySourceEdits(source, [
|
||||
{ start: brace.end, end: brace.end, text: `${newline} import ${JSON.stringify(importPath)};` },
|
||||
]);
|
||||
};
|
||||
|
||||
export const validateQxImportPath = (value: string) => {
|
||||
if (!/^(?:[A-Za-z0-9_-][A-Za-z0-9_.-]*\/)*[A-Za-z0-9_-][A-Za-z0-9_.-]*\.qx$/.test(value) ||
|
||||
value.split("/").some((part) => part === "." || part === ".."))
|
||||
if (
|
||||
!/^(?:[A-Za-z0-9_-][A-Za-z0-9_.-]*\/)*[A-Za-z0-9_-][A-Za-z0-9_.-]*\.qx$/.test(value) ||
|
||||
value.split("/").some((part) => part === "." || part === "..")
|
||||
)
|
||||
throw new Error(`Invalid repository-relative QX import path: ${value}`);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user