Skip to content
Open
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
10 changes: 6 additions & 4 deletions src/features/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { findHoverMatchesInDoc } from "@src/support/doc";
import { detectedRange, detectInDoc } from "@src/support/parser";
import { wordMatchRegex } from "@src/support/patterns";
import { projectPath } from "@src/support/project";
import { contract, facade } from "@src/support/util";
import { contract, facade, withLineFragment } from "@src/support/util";
import { AutocompleteParsingResult } from "@src/types";
import * as vscode from "vscode";
import {
Expand Down Expand Up @@ -167,12 +167,14 @@ export const diagnosticProvider = (
return null;
}

const pathToFile = getConfigPathByName(param.value);
const configPath = getConfigPathByName(param.value);

const code: NotFoundCode = pathToFile
const code: NotFoundCode = configPath
? {
value: "config",
target: vscode.Uri.file(projectPath(pathToFile)),
target: vscode.Uri.file(configPath.path).with(
withLineFragment(configPath.line),
),
}
: "config";

Expand Down
5 changes: 4 additions & 1 deletion src/features/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,10 @@ export const diagnosticProvider = (
return null;
}

return notFound("Env", param.value, detectedRange(param), "env");
return notFound("Env", param.value, detectedRange(param), {
value: "env",
target: vscode.Uri.file(projectPath(".env")),
});
},
);
};
Expand Down
17 changes: 12 additions & 5 deletions src/features/translation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@ import { config } from "@src/support/config";
import { findHoverMatchesInDoc } from "@src/support/doc";
import { detectedRange, detectInDoc } from "@src/support/parser";
import { wordMatchRegex } from "@src/support/patterns";
import { projectPath, relativePath } from "@src/support/project";
import { contract, createIndexMapping, facade } from "@src/support/util";
import { relativePath } from "@src/support/project";
import {
contract,
createIndexMapping,
facade,
withLineFragment,
} from "@src/support/util";
import { AutocompleteParsingResult } from "@src/types";
import * as vscode from "vscode";
import { FeatureTag, HoverProvider, LinkProvider } from "..";
Expand Down Expand Up @@ -191,15 +196,17 @@ export const diagnosticProvider = (
return null;
}

const pathToFile = getTranslationPathByName(
const translationPath = getTranslationPathByName(
param.value,
getLang(item as AutocompleteParsingResult.MethodCall),
);

const code: NotFoundCode = pathToFile
const code: NotFoundCode = translationPath
? {
value: "translation",
target: vscode.Uri.file(projectPath(pathToFile)),
target: vscode.Uri.file(translationPath.path).with(
withLineFragment(translationPath.line),
),
}
: "translation";

Expand Down
83 changes: 68 additions & 15 deletions src/repositories/configs.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { projectPath } from "@src/support/project";
import { repository } from ".";
import { Config } from "..";
import { runInLaravel, template } from "../support/php";
Expand All @@ -7,23 +8,75 @@ interface ConfigGroupResult {
paths: string[];
}

export const getConfigPathByName = (match: string): string | undefined => {
const filePath = match.replace(/\.[^.]+$/, "");

for (const tryPath of [
filePath.replaceAll(".", "/"),
filePath.replace(/^([^.]+)\..*$/, "$1"),
]) {
const configPath = getConfigs().items.paths.find((path) => {
return (
!path.startsWith("vendor/") && path.endsWith(`${tryPath}.php`)
);
});

if (configPath) {
return configPath;
interface ConfigPath {
path: string;
line?: string | null;
}

export const getConfigByName = (name: string): Config | undefined => {
return getConfigs().items.configs.find((item) => item.name === name);
};

export const getParentConfigByName = (match: string): Config | undefined => {
const name = match.match(/^(.*)\./)?.[0];

if (!name) {
return undefined;
}

return getConfigs().items.configs.find((config) =>
config.name.startsWith(name),
);
};

export const getConfigPathByName = (match: string): ConfigPath | undefined => {
// Firstly, we try to get the parent Config, because it has a path and a line
const parentItem = getParentConfigByName(match);

let path = parentItem?.file;

// If the path is not found (because, for example, config file is empty),
// we try to find the path by the file name
if (!path) {
const fileName = match.replace(/\.[^.]+$/, "");

// We have to check every possible subfolder, for example: foo.bar.baz.example
// can be: foo/bar.php with a key "baz.example" but also foo/bar/baz.php with a key "example"
const parts = fileName.split(".");
const subfolderPaths = parts
.slice(1)
.map((_, i) =>
(
parts.slice(0, i + 2).join("/") +
"." +
parts.slice(i + 2).join(".")
).replace(/^([^.]+)\..*$/, "$1"),
)
.reverse();

for (const tryPath of [
...subfolderPaths,
fileName.replace(/^([^.]+)\..*$/, "$1"),
]) {
path = getConfigs().items.paths.find((path) => {
return (
!path.startsWith("vendor/") &&
path.endsWith(`${tryPath}.php`)
);
});

if (path) {
break;
}
}
}

return path
? {
path: projectPath(path),
line: parentItem?.line,
}
: undefined;
};

export const getConfigs = repository<ConfigGroupResult>({
Expand Down
61 changes: 52 additions & 9 deletions src/repositories/translations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ interface TranslationGroupPhpResult {
languages: string[];
}

interface TranslationPath {
path: string;
line?: number;
}

let dirsToWatch: string[] | null = null;

const load = () => {
Expand Down Expand Up @@ -78,20 +83,58 @@ export const getTranslationItemByName = (
return getTranslations().items.translations[match.replaceAll("\\", "")];
};

export const getParentTranslationItemByName = (
match: string,
): TranslationItem | undefined => {
const name = match.match(/^(.*)\./)?.[0];

if (!name) {
return undefined;
}

const parentName = Object.keys(getTranslations().items.translations).find(
(key) => key.startsWith(name.replaceAll("\\", "")),
);

return parentName ? getTranslationItemByName(parentName) : undefined;
};

export const getTranslationPathByName = (
match: string,
lang: string | undefined,
): string | undefined => {
): TranslationPath | undefined => {
lang = lang ?? getTranslations().items.default;

const fileName = match.replace(/^.*::/, "").replace(/^([^.]+)\..*$/, "$1");

return getTranslations().items.paths.find((path) => {
return (
!path.startsWith("vendor/") &&
path.endsWith(`${lang}/${fileName}.php`)
);
});
// Firstly, we try to get the parent TranslationItem, because it has a path and a line
const parentItem = getParentTranslationItemByName(match);

let path = parentItem?.[lang]?.path;

// If the path is not found (because, for example, translation file is empty),
// we try to find the path by the file name
if (!path) {
const fileName = match
.replace(/^.*::/, "")
.replace(/^([^.]+)\..*$/, "$1");

path = getTranslations().items.paths.find((path) => {
return (
!path.startsWith("vendor/") &&
path.endsWith(`${lang}/${fileName}.php`)
);
});

if (path) {
path = projectPath(path);
}
}

return path
? {
path: path,
line: parentItem?.[lang]?.line,
}
: undefined;
};

export const getTranslations = repository<TranslationGroupResult>({
Expand Down
6 changes: 6 additions & 0 deletions src/support/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ export const indent = (text: string = "", repeat: number = 1): string => {
return "\t" + text;
};

export const withLineFragment = (
line: number | string | undefined | null,
): { fragment?: string } => {
return line ? { fragment: `L${line}` } : {};
};

export const trimQuotes = (text: string): string =>
text.substring(1, text.length - 1);

Expand Down