library-skills 0.0.7 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/ts/dist/cli.d.ts +8 -0
- package/ts/dist/cli.js +278 -44
- package/ts/dist/deps.cjs +29 -6
- package/ts/dist/deps.d.cts +3 -1
- package/ts/dist/deps.d.ts +3 -1
- package/ts/dist/deps.js +27 -6
- package/ts/dist/python-env.cjs +211 -33
- package/ts/dist/python-env.js +205 -27
package/package.json
CHANGED
package/ts/dist/cli.d.ts
CHANGED
|
@@ -15,12 +15,20 @@ interface InstallTarget {
|
|
|
15
15
|
path: string;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
interface UvWorkspace {
|
|
19
|
+
root: string;
|
|
20
|
+
members: string[];
|
|
21
|
+
currentMember: string | null;
|
|
22
|
+
}
|
|
23
|
+
|
|
18
24
|
interface ProjectContext {
|
|
19
25
|
cwd: string;
|
|
20
26
|
projectRoot: string;
|
|
21
27
|
targetEnvironment: string | null;
|
|
22
28
|
sitePackagesDir: string | null;
|
|
23
29
|
nodeModulesDir: string | null;
|
|
30
|
+
workspace: UvWorkspace | null;
|
|
31
|
+
dependencyFiles: string[];
|
|
24
32
|
}
|
|
25
33
|
interface InstalledStatus {
|
|
26
34
|
target: InstallTarget;
|
package/ts/dist/cli.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
// ts/src/cli.ts
|
|
4
4
|
import checkbox from "@inquirer/checkbox";
|
|
5
5
|
import { Command } from "commander";
|
|
6
|
-
import { realpathSync as realpathSync2, statSync as
|
|
7
|
-
import { isAbsolute as isAbsolute3, relative as
|
|
6
|
+
import { realpathSync as realpathSync2, statSync as statSync5 } from "fs";
|
|
7
|
+
import { isAbsolute as isAbsolute3, relative as relative4, resolve as resolve5 } from "path";
|
|
8
8
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
9
9
|
|
|
10
10
|
// ts/src/deps.ts
|
|
@@ -468,13 +468,30 @@ function getPythonTopLevelDeps(projectRoot) {
|
|
|
468
468
|
if (!existsSync2(pyproject)) {
|
|
469
469
|
return null;
|
|
470
470
|
}
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
471
|
+
return getPythonTopLevelDepsFromFiles([pyproject]);
|
|
472
|
+
}
|
|
473
|
+
function getPythonTopLevelDepsFromFiles(pyprojects) {
|
|
474
|
+
if (pyprojects.length === 0) {
|
|
475
475
|
return null;
|
|
476
476
|
}
|
|
477
477
|
const deps = /* @__PURE__ */ new Set();
|
|
478
|
+
let found = false;
|
|
479
|
+
for (const pyproject of pyprojects) {
|
|
480
|
+
if (!existsSync2(pyproject)) {
|
|
481
|
+
continue;
|
|
482
|
+
}
|
|
483
|
+
let data;
|
|
484
|
+
try {
|
|
485
|
+
data = parse2(readFileSync2(pyproject, "utf8"));
|
|
486
|
+
} catch {
|
|
487
|
+
return null;
|
|
488
|
+
}
|
|
489
|
+
found = true;
|
|
490
|
+
extractPythonTopLevelDeps(data, deps);
|
|
491
|
+
}
|
|
492
|
+
return found ? deps : null;
|
|
493
|
+
}
|
|
494
|
+
function extractPythonTopLevelDeps(data, deps) {
|
|
478
495
|
const project = data["project"];
|
|
479
496
|
if (isRecord2(project)) {
|
|
480
497
|
const dependencies = project["dependencies"];
|
|
@@ -496,7 +513,6 @@ function getPythonTopLevelDeps(projectRoot) {
|
|
|
496
513
|
extractDepsFromDependencyGroup(groupName, dependencyGroups, deps, /* @__PURE__ */ new Set());
|
|
497
514
|
}
|
|
498
515
|
}
|
|
499
|
-
return deps;
|
|
500
516
|
}
|
|
501
517
|
function getNodeTopLevelDeps(projectRoot) {
|
|
502
518
|
const packageJson = join2(projectRoot, "package.json");
|
|
@@ -539,12 +555,15 @@ function getTopLevelDeps(projectRoot) {
|
|
|
539
555
|
}
|
|
540
556
|
return new Set(dependencySets.flatMap((deps) => [...deps]));
|
|
541
557
|
}
|
|
558
|
+
function getWorkspaceTopLevelDeps(pyprojects) {
|
|
559
|
+
return getPythonTopLevelDepsFromFiles(pyprojects);
|
|
560
|
+
}
|
|
542
561
|
function extractDepsFromSpecs(depSpecs, deps) {
|
|
543
562
|
for (const depSpec of depSpecs) {
|
|
544
563
|
if (typeof depSpec !== "string") {
|
|
545
564
|
continue;
|
|
546
565
|
}
|
|
547
|
-
const packageName = depSpec.split(/[
|
|
566
|
+
const packageName = depSpec.split(/[~>=<![\];,\s]/)[0]?.trim();
|
|
548
567
|
if (packageName && !packageName.startsWith("#")) {
|
|
549
568
|
deps.add(normalizePackageName(packageName));
|
|
550
569
|
}
|
|
@@ -688,17 +707,201 @@ function isDirectory2(path) {
|
|
|
688
707
|
}
|
|
689
708
|
|
|
690
709
|
// ts/src/python-env.ts
|
|
691
|
-
import { readFileSync as
|
|
692
|
-
import { dirname as dirname3, isAbsolute as isAbsolute2, join as join4, resolve as
|
|
693
|
-
|
|
710
|
+
import { readFileSync as readFileSync4, readdirSync as readdirSync4, statSync as statSync4 } from "fs";
|
|
711
|
+
import { dirname as dirname3, isAbsolute as isAbsolute2, join as join4, resolve as resolve4, sep as sep2 } from "path";
|
|
712
|
+
|
|
713
|
+
// ts/src/workspace.ts
|
|
714
|
+
import { existsSync as existsSync4, readdirSync as readdirSync3, readFileSync as readFileSync3, statSync as statSync3 } from "fs";
|
|
715
|
+
import { relative as relative3, resolve as resolve3, sep } from "path";
|
|
716
|
+
import { parse as parse3 } from "smol-toml";
|
|
717
|
+
function findUvWorkspace(cwd) {
|
|
694
718
|
for (const directory of ancestors(cwd)) {
|
|
695
|
-
|
|
719
|
+
const pyproject = `${directory}/pyproject.toml`;
|
|
720
|
+
if (!existsSync4(pyproject)) {
|
|
721
|
+
continue;
|
|
722
|
+
}
|
|
723
|
+
const data = readPyproject(pyproject);
|
|
724
|
+
if (!hasUvWorkspace(data)) {
|
|
725
|
+
continue;
|
|
726
|
+
}
|
|
727
|
+
const members = findWorkspaceMembers(directory, data);
|
|
728
|
+
return {
|
|
729
|
+
root: directory,
|
|
730
|
+
members,
|
|
731
|
+
currentMember: findCurrentMember(cwd, members)
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
return null;
|
|
735
|
+
}
|
|
736
|
+
function workspaceDependencyFiles(workspace) {
|
|
737
|
+
if (workspace.currentMember !== null) {
|
|
738
|
+
return [`${workspace.currentMember}/pyproject.toml`];
|
|
739
|
+
}
|
|
740
|
+
return [
|
|
741
|
+
`${workspace.root}/pyproject.toml`,
|
|
742
|
+
...workspace.members.map((member) => `${member}/pyproject.toml`)
|
|
743
|
+
].filter((path) => existsSync4(path));
|
|
744
|
+
}
|
|
745
|
+
function readPyproject(path) {
|
|
746
|
+
try {
|
|
747
|
+
const data = parse3(readFileSync3(path, "utf8"));
|
|
748
|
+
return isRecord3(data) ? data : {};
|
|
749
|
+
} catch {
|
|
750
|
+
return {};
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
function hasUvWorkspace(data) {
|
|
754
|
+
const tool = data["tool"];
|
|
755
|
+
if (!isRecord3(tool)) {
|
|
756
|
+
return false;
|
|
757
|
+
}
|
|
758
|
+
const uv = tool["uv"];
|
|
759
|
+
if (!isRecord3(uv)) {
|
|
760
|
+
return false;
|
|
761
|
+
}
|
|
762
|
+
return isRecord3(uv["workspace"]);
|
|
763
|
+
}
|
|
764
|
+
function findWorkspaceMembers(root, data) {
|
|
765
|
+
const workspace = getWorkspaceTable(data);
|
|
766
|
+
if (workspace === null || !Array.isArray(workspace["members"])) {
|
|
767
|
+
return [];
|
|
768
|
+
}
|
|
769
|
+
const excludes = Array.isArray(workspace["exclude"]) ? workspace["exclude"].filter(
|
|
770
|
+
(value) => typeof value === "string"
|
|
771
|
+
) : [];
|
|
772
|
+
const members = /* @__PURE__ */ new Set();
|
|
773
|
+
for (const memberGlob of workspace["members"]) {
|
|
774
|
+
if (typeof memberGlob !== "string") {
|
|
775
|
+
continue;
|
|
776
|
+
}
|
|
777
|
+
for (const member of expandMemberGlob(root, memberGlob)) {
|
|
778
|
+
const relativePath = relative3(root, member).split(sep).join("/");
|
|
779
|
+
if (isExcluded(relativePath, excludes)) {
|
|
780
|
+
continue;
|
|
781
|
+
}
|
|
782
|
+
if (isFile(`${member}/pyproject.toml`)) {
|
|
783
|
+
members.add(resolve3(member));
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
return [...members].sort();
|
|
788
|
+
}
|
|
789
|
+
function getWorkspaceTable(data) {
|
|
790
|
+
const tool = data["tool"];
|
|
791
|
+
if (!isRecord3(tool)) {
|
|
792
|
+
return null;
|
|
793
|
+
}
|
|
794
|
+
const uv = tool["uv"];
|
|
795
|
+
if (!isRecord3(uv)) {
|
|
796
|
+
return null;
|
|
797
|
+
}
|
|
798
|
+
const workspace = uv["workspace"];
|
|
799
|
+
return isRecord3(workspace) ? workspace : null;
|
|
800
|
+
}
|
|
801
|
+
function expandMemberGlob(root, pattern) {
|
|
802
|
+
const parts = pattern.split("/");
|
|
803
|
+
const results = [];
|
|
804
|
+
walkGlob(root, parts, results);
|
|
805
|
+
return results;
|
|
806
|
+
}
|
|
807
|
+
function walkGlob(directory, parts, results) {
|
|
808
|
+
if (parts.length === 0) {
|
|
809
|
+
if (isDirectory3(directory)) {
|
|
810
|
+
results.push(directory);
|
|
811
|
+
}
|
|
812
|
+
return;
|
|
813
|
+
}
|
|
814
|
+
const [part, ...rest] = parts;
|
|
815
|
+
if (part === "*") {
|
|
816
|
+
for (const entry of readDirSafe(directory)) {
|
|
817
|
+
const child = `${directory}/${entry}`;
|
|
818
|
+
if (isDirectory3(child)) {
|
|
819
|
+
walkGlob(child, rest, results);
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
walkGlob(`${directory}/${part}`, rest, results);
|
|
825
|
+
}
|
|
826
|
+
function isExcluded(relativePath, excludes) {
|
|
827
|
+
return excludes.some(
|
|
828
|
+
(pattern) => globMatches(relativePath, pattern.replace(/\/$/, ""))
|
|
829
|
+
);
|
|
830
|
+
}
|
|
831
|
+
function globMatches(value, pattern) {
|
|
832
|
+
if (pattern === value) {
|
|
833
|
+
return true;
|
|
834
|
+
}
|
|
835
|
+
const regex = new RegExp(`^${pattern.split("*").map(escapeRegex).join(".*")}$`);
|
|
836
|
+
return regex.test(value);
|
|
837
|
+
}
|
|
838
|
+
function findCurrentMember(cwd, members) {
|
|
839
|
+
const resolvedCwd = resolve3(cwd);
|
|
840
|
+
const matches = members.filter((member) => isRelativeTo2(resolvedCwd, member));
|
|
841
|
+
if (matches.length === 0) {
|
|
842
|
+
return null;
|
|
843
|
+
}
|
|
844
|
+
return matches.sort((left, right) => right.length - left.length)[0] ?? null;
|
|
845
|
+
}
|
|
846
|
+
function ancestors(start) {
|
|
847
|
+
const result = [];
|
|
848
|
+
let directory = resolve3(start);
|
|
849
|
+
while (true) {
|
|
850
|
+
result.push(directory);
|
|
851
|
+
const parent = resolve3(directory, "..");
|
|
852
|
+
if (parent === directory) {
|
|
853
|
+
break;
|
|
854
|
+
}
|
|
855
|
+
directory = parent;
|
|
856
|
+
}
|
|
857
|
+
return result;
|
|
858
|
+
}
|
|
859
|
+
function isRelativeTo2(path, parent) {
|
|
860
|
+
const normalizedPath = resolve3(path);
|
|
861
|
+
const normalizedParent = resolve3(parent);
|
|
862
|
+
return normalizedPath === normalizedParent || normalizedPath.startsWith(`${normalizedParent}${sep}`);
|
|
863
|
+
}
|
|
864
|
+
function isRecord3(value) {
|
|
865
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
866
|
+
}
|
|
867
|
+
function isFile(path) {
|
|
868
|
+
try {
|
|
869
|
+
return statSync3(path).isFile();
|
|
870
|
+
} catch {
|
|
871
|
+
return false;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
function isDirectory3(path) {
|
|
875
|
+
try {
|
|
876
|
+
return statSync3(path).isDirectory();
|
|
877
|
+
} catch {
|
|
878
|
+
return false;
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
function readDirSafe(path) {
|
|
882
|
+
try {
|
|
883
|
+
return isDirectory3(path) ? readdirSync3(path) : [];
|
|
884
|
+
} catch {
|
|
885
|
+
return [];
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
var escapeRegex = (value) => value.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
889
|
+
|
|
890
|
+
// ts/src/python-env.ts
|
|
891
|
+
function findProjectRoot(cwd) {
|
|
892
|
+
const workspace = findUvWorkspace(cwd);
|
|
893
|
+
if (workspace !== null) {
|
|
894
|
+
return workspace.root;
|
|
895
|
+
}
|
|
896
|
+
for (const directory of ancestors2(cwd)) {
|
|
897
|
+
if (isFile2(join4(directory, "pyproject.toml")) || isFile2(join4(directory, "uv.lock")) || venvFromDotVenv(directory) !== null || isFile2(join4(directory, "package.json")) || isDirectory4(join4(directory, "node_modules"))) {
|
|
696
898
|
return directory;
|
|
697
899
|
}
|
|
698
900
|
}
|
|
699
901
|
return null;
|
|
700
902
|
}
|
|
701
903
|
function findVenv(cwd = process.cwd()) {
|
|
904
|
+
const workspace = findUvWorkspace(cwd);
|
|
702
905
|
const projectRoot = findProjectRoot(cwd) ?? cwd;
|
|
703
906
|
const uvProjectEnvironment = process.env["UV_PROJECT_ENVIRONMENT"];
|
|
704
907
|
if (uvProjectEnvironment) {
|
|
@@ -707,35 +910,38 @@ function findVenv(cwd = process.cwd()) {
|
|
|
707
910
|
return path;
|
|
708
911
|
}
|
|
709
912
|
}
|
|
710
|
-
|
|
913
|
+
if (workspace !== null) {
|
|
914
|
+
return venvFromDotVenv(workspace.root);
|
|
915
|
+
}
|
|
916
|
+
for (const directory of ancestors2(cwd)) {
|
|
711
917
|
const venv = venvFromDotVenv(directory);
|
|
712
918
|
if (venv !== null) {
|
|
713
919
|
return venv;
|
|
714
920
|
}
|
|
715
921
|
}
|
|
716
922
|
const virtualEnv = process.env["VIRTUAL_ENV"];
|
|
717
|
-
if (virtualEnv && isVenvDir(virtualEnv) &&
|
|
923
|
+
if (virtualEnv && isVenvDir(virtualEnv) && isRelativeTo3(virtualEnv, projectRoot)) {
|
|
718
924
|
return virtualEnv;
|
|
719
925
|
}
|
|
720
926
|
const condaPrefix = process.env["CONDA_PREFIX"];
|
|
721
|
-
if (condaPrefix &&
|
|
927
|
+
if (condaPrefix && isDirectory4(condaPrefix)) {
|
|
722
928
|
return condaPrefix;
|
|
723
929
|
}
|
|
724
930
|
return null;
|
|
725
931
|
}
|
|
726
932
|
function getSitePackagesDir(venvPath) {
|
|
727
933
|
const windowsSitePackages = join4(venvPath, "Lib", "site-packages");
|
|
728
|
-
if (
|
|
934
|
+
if (isDirectory4(windowsSitePackages)) {
|
|
729
935
|
return windowsSitePackages;
|
|
730
936
|
}
|
|
731
937
|
for (const libName of ["lib", "lib64"]) {
|
|
732
938
|
const libDir = join4(venvPath, libName);
|
|
733
|
-
if (!
|
|
939
|
+
if (!isDirectory4(libDir)) {
|
|
734
940
|
continue;
|
|
735
941
|
}
|
|
736
|
-
for (const child of
|
|
942
|
+
for (const child of readdirSync4(libDir).sort().reverse()) {
|
|
737
943
|
const sitePackages = join4(libDir, child, "site-packages");
|
|
738
|
-
if (child.startsWith("python") &&
|
|
944
|
+
if (child.startsWith("python") && isDirectory4(sitePackages)) {
|
|
739
945
|
return sitePackages;
|
|
740
946
|
}
|
|
741
947
|
}
|
|
@@ -743,23 +949,23 @@ function getSitePackagesDir(venvPath) {
|
|
|
743
949
|
return null;
|
|
744
950
|
}
|
|
745
951
|
function findNodeModules(cwd = process.cwd()) {
|
|
746
|
-
for (const directory of
|
|
952
|
+
for (const directory of ancestors2(cwd)) {
|
|
747
953
|
const nodeModules = join4(directory, "node_modules");
|
|
748
|
-
if (
|
|
954
|
+
if (isDirectory4(nodeModules)) {
|
|
749
955
|
return nodeModules;
|
|
750
956
|
}
|
|
751
957
|
}
|
|
752
958
|
return null;
|
|
753
959
|
}
|
|
754
960
|
function isVenvDir(directory) {
|
|
755
|
-
return
|
|
961
|
+
return isFile2(join4(directory, "pyvenv.cfg"));
|
|
756
962
|
}
|
|
757
963
|
function venvFromDotVenv(projectRoot) {
|
|
758
964
|
const dotVenv = join4(projectRoot, ".venv");
|
|
759
|
-
if (
|
|
965
|
+
if (isDirectory4(dotVenv)) {
|
|
760
966
|
return isVenvDir(dotVenv) ? dotVenv : null;
|
|
761
967
|
}
|
|
762
|
-
if (
|
|
968
|
+
if (isFile2(dotVenv)) {
|
|
763
969
|
return readVenvRedirectFile(dotVenv);
|
|
764
970
|
}
|
|
765
971
|
return null;
|
|
@@ -767,7 +973,7 @@ function venvFromDotVenv(projectRoot) {
|
|
|
767
973
|
function readVenvRedirectFile(path) {
|
|
768
974
|
let content;
|
|
769
975
|
try {
|
|
770
|
-
content =
|
|
976
|
+
content = readFileSync4(path, "utf8");
|
|
771
977
|
} catch {
|
|
772
978
|
return null;
|
|
773
979
|
}
|
|
@@ -778,9 +984,9 @@ function readVenvRedirectFile(path) {
|
|
|
778
984
|
const venv = isAbsolute2(redirect) ? redirect : join4(dirname3(path), redirect);
|
|
779
985
|
return isVenvDir(venv) ? venv : null;
|
|
780
986
|
}
|
|
781
|
-
function
|
|
987
|
+
function ancestors2(start) {
|
|
782
988
|
const result = [];
|
|
783
|
-
let directory =
|
|
989
|
+
let directory = resolve4(start);
|
|
784
990
|
while (true) {
|
|
785
991
|
result.push(directory);
|
|
786
992
|
const parent = dirname3(directory);
|
|
@@ -791,21 +997,21 @@ function ancestors(start) {
|
|
|
791
997
|
}
|
|
792
998
|
return result;
|
|
793
999
|
}
|
|
794
|
-
function
|
|
795
|
-
const normalizedPath =
|
|
796
|
-
const normalizedParent =
|
|
797
|
-
return normalizedPath === normalizedParent || normalizedPath.startsWith(`${normalizedParent}${
|
|
1000
|
+
function isRelativeTo3(path, parent) {
|
|
1001
|
+
const normalizedPath = resolve4(path);
|
|
1002
|
+
const normalizedParent = resolve4(parent);
|
|
1003
|
+
return normalizedPath === normalizedParent || normalizedPath.startsWith(`${normalizedParent}${sep2}`);
|
|
798
1004
|
}
|
|
799
|
-
function
|
|
1005
|
+
function isFile2(path) {
|
|
800
1006
|
try {
|
|
801
|
-
return
|
|
1007
|
+
return statSync4(path).isFile();
|
|
802
1008
|
} catch {
|
|
803
1009
|
return false;
|
|
804
1010
|
}
|
|
805
1011
|
}
|
|
806
|
-
function
|
|
1012
|
+
function isDirectory4(path) {
|
|
807
1013
|
try {
|
|
808
|
-
return
|
|
1014
|
+
return statSync4(path).isDirectory();
|
|
809
1015
|
} catch {
|
|
810
1016
|
return false;
|
|
811
1017
|
}
|
|
@@ -813,11 +1019,20 @@ function isDirectory3(path) {
|
|
|
813
1019
|
|
|
814
1020
|
// ts/src/cli.ts
|
|
815
1021
|
function getProjectContext(cwd = process.cwd()) {
|
|
816
|
-
const
|
|
1022
|
+
const workspace = findUvWorkspace(cwd);
|
|
1023
|
+
const projectRoot = workspace?.root ?? findProjectRoot(cwd) ?? cwd;
|
|
817
1024
|
const targetEnvironment = findVenv(cwd);
|
|
818
1025
|
const sitePackagesDir = targetEnvironment === null ? null : getSitePackagesDir(targetEnvironment);
|
|
819
1026
|
const nodeModulesDir = findNodeModules(cwd);
|
|
820
|
-
return {
|
|
1027
|
+
return {
|
|
1028
|
+
cwd,
|
|
1029
|
+
projectRoot,
|
|
1030
|
+
targetEnvironment,
|
|
1031
|
+
sitePackagesDir,
|
|
1032
|
+
nodeModulesDir,
|
|
1033
|
+
workspace,
|
|
1034
|
+
dependencyFiles: workspace ? workspaceDependencyFiles(workspace) : []
|
|
1035
|
+
};
|
|
821
1036
|
}
|
|
822
1037
|
function scanContext(context) {
|
|
823
1038
|
const result = {
|
|
@@ -830,6 +1045,14 @@ function scanContext(context) {
|
|
|
830
1045
|
result.skills.push(...pythonResult.skills);
|
|
831
1046
|
result.warnings.push(...pythonResult.warnings);
|
|
832
1047
|
}
|
|
1048
|
+
if (context.workspace?.currentMember) {
|
|
1049
|
+
const memberVenv = `${context.workspace.currentMember}/.venv`;
|
|
1050
|
+
if (exists(memberVenv)) {
|
|
1051
|
+
result.warnings.push(
|
|
1052
|
+
`Ignoring member-local .venv in uv workspace: ${memberVenv}`
|
|
1053
|
+
);
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
833
1056
|
if (context.nodeModulesDir !== null) {
|
|
834
1057
|
const nodeResult = scanNodePackages(context.nodeModulesDir);
|
|
835
1058
|
result.skills.push(...nodeResult.skills);
|
|
@@ -851,11 +1074,13 @@ function topLevelSkills({
|
|
|
851
1074
|
return skills;
|
|
852
1075
|
}
|
|
853
1076
|
const topLevelDeps = getTopLevelDeps(context.projectRoot);
|
|
854
|
-
|
|
1077
|
+
const workspaceTopLevelDeps = context.workspace === null ? null : getWorkspaceTopLevelDeps(context.dependencyFiles);
|
|
1078
|
+
const selectedTopLevelDeps = context.workspace === null ? topLevelDeps : workspaceTopLevelDeps;
|
|
1079
|
+
if (selectedTopLevelDeps === null) {
|
|
855
1080
|
return skills;
|
|
856
1081
|
}
|
|
857
1082
|
return skills.filter(
|
|
858
|
-
(skill) =>
|
|
1083
|
+
(skill) => selectedTopLevelDeps.has(normalizePackageName(skill.packageName))
|
|
859
1084
|
);
|
|
860
1085
|
}
|
|
861
1086
|
function printWarnings(warnings) {
|
|
@@ -867,7 +1092,7 @@ function displayPath(path, projectRoot) {
|
|
|
867
1092
|
if (!path) {
|
|
868
1093
|
return "";
|
|
869
1094
|
}
|
|
870
|
-
const relativePath =
|
|
1095
|
+
const relativePath = relative4(resolve5(projectRoot), resolve5(path));
|
|
871
1096
|
if (relativePath === "") {
|
|
872
1097
|
return ".";
|
|
873
1098
|
}
|
|
@@ -878,6 +1103,12 @@ function displayPath(path, projectRoot) {
|
|
|
878
1103
|
}
|
|
879
1104
|
function printContext(context) {
|
|
880
1105
|
console.log(`Project root: ${context.projectRoot}`);
|
|
1106
|
+
if (context.workspace !== null) {
|
|
1107
|
+
console.log(`Workspace root: ${context.workspace.root}`);
|
|
1108
|
+
if (context.workspace.currentMember !== null) {
|
|
1109
|
+
console.log(`Workspace member: ${context.workspace.currentMember}`);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
881
1112
|
console.log(
|
|
882
1113
|
`Target Python environment: ${context.targetEnvironment ? displayPath(context.targetEnvironment, context.projectRoot) : "not found"}`
|
|
883
1114
|
);
|
|
@@ -917,6 +1148,9 @@ function scanJsonPayload({
|
|
|
917
1148
|
}) {
|
|
918
1149
|
return {
|
|
919
1150
|
project_root: context.projectRoot,
|
|
1151
|
+
workspace_root: context.workspace?.root ?? "",
|
|
1152
|
+
workspace_member: context.workspace?.currentMember ?? "",
|
|
1153
|
+
dependency_files: context.dependencyFiles,
|
|
920
1154
|
target_environment: context.targetEnvironment ?? "",
|
|
921
1155
|
node_modules: context.nodeModulesDir ?? "",
|
|
922
1156
|
skills: skills.map((skill) => ({
|
|
@@ -972,13 +1206,13 @@ function installedStatuses({
|
|
|
972
1206
|
skills
|
|
973
1207
|
}) {
|
|
974
1208
|
const skillsByDir = new Map(
|
|
975
|
-
skills.map((skill) => [
|
|
1209
|
+
skills.map((skill) => [resolve5(skill.skillDir), skill])
|
|
976
1210
|
);
|
|
977
1211
|
const skillsByName = new Map(skills.map((skill) => [skill.name, skill]));
|
|
978
1212
|
const statuses = [];
|
|
979
1213
|
for (const target of targets) {
|
|
980
1214
|
for (const installed of listInstalledSkills(target.path)) {
|
|
981
|
-
const skill = installed.target ? skillsByDir.get(
|
|
1215
|
+
const skill = installed.target ? skillsByDir.get(resolve5(installed.target)) : null;
|
|
982
1216
|
let matchedSkill = skill ?? null;
|
|
983
1217
|
let status = "hand-authored";
|
|
984
1218
|
if (installed.type === "symlink") {
|
|
@@ -1342,13 +1576,13 @@ function collect(value, previous) {
|
|
|
1342
1576
|
}
|
|
1343
1577
|
function exists(path) {
|
|
1344
1578
|
try {
|
|
1345
|
-
|
|
1579
|
+
statSync5(path);
|
|
1346
1580
|
return true;
|
|
1347
1581
|
} catch {
|
|
1348
1582
|
return false;
|
|
1349
1583
|
}
|
|
1350
1584
|
}
|
|
1351
|
-
if (process.argv[1] && realpathSync2(fileURLToPath2(import.meta.url)) === realpathSync2(
|
|
1585
|
+
if (process.argv[1] && realpathSync2(fileURLToPath2(import.meta.url)) === realpathSync2(resolve5(process.argv[1]))) {
|
|
1352
1586
|
main().catch((error) => {
|
|
1353
1587
|
console.error(error);
|
|
1354
1588
|
process.exit(1);
|
package/ts/dist/deps.cjs
CHANGED
|
@@ -22,7 +22,9 @@ var deps_exports = {};
|
|
|
22
22
|
__export(deps_exports, {
|
|
23
23
|
getNodeTopLevelDeps: () => getNodeTopLevelDeps,
|
|
24
24
|
getPythonTopLevelDeps: () => getPythonTopLevelDeps,
|
|
25
|
+
getPythonTopLevelDepsFromFiles: () => getPythonTopLevelDepsFromFiles,
|
|
25
26
|
getTopLevelDeps: () => getTopLevelDeps,
|
|
27
|
+
getWorkspaceTopLevelDeps: () => getWorkspaceTopLevelDeps,
|
|
26
28
|
testing: () => testing
|
|
27
29
|
});
|
|
28
30
|
module.exports = __toCommonJS(deps_exports);
|
|
@@ -45,13 +47,30 @@ function getPythonTopLevelDeps(projectRoot) {
|
|
|
45
47
|
if (!(0, import_node_fs2.existsSync)(pyproject)) {
|
|
46
48
|
return null;
|
|
47
49
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
return getPythonTopLevelDepsFromFiles([pyproject]);
|
|
51
|
+
}
|
|
52
|
+
function getPythonTopLevelDepsFromFiles(pyprojects) {
|
|
53
|
+
if (pyprojects.length === 0) {
|
|
52
54
|
return null;
|
|
53
55
|
}
|
|
54
56
|
const deps = /* @__PURE__ */ new Set();
|
|
57
|
+
let found = false;
|
|
58
|
+
for (const pyproject of pyprojects) {
|
|
59
|
+
if (!(0, import_node_fs2.existsSync)(pyproject)) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
let data;
|
|
63
|
+
try {
|
|
64
|
+
data = (0, import_smol_toml.parse)((0, import_node_fs2.readFileSync)(pyproject, "utf8"));
|
|
65
|
+
} catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
found = true;
|
|
69
|
+
extractPythonTopLevelDeps(data, deps);
|
|
70
|
+
}
|
|
71
|
+
return found ? deps : null;
|
|
72
|
+
}
|
|
73
|
+
function extractPythonTopLevelDeps(data, deps) {
|
|
55
74
|
const project = data["project"];
|
|
56
75
|
if (isRecord(project)) {
|
|
57
76
|
const dependencies = project["dependencies"];
|
|
@@ -73,7 +92,6 @@ function getPythonTopLevelDeps(projectRoot) {
|
|
|
73
92
|
extractDepsFromDependencyGroup(groupName, dependencyGroups, deps, /* @__PURE__ */ new Set());
|
|
74
93
|
}
|
|
75
94
|
}
|
|
76
|
-
return deps;
|
|
77
95
|
}
|
|
78
96
|
function getNodeTopLevelDeps(projectRoot) {
|
|
79
97
|
const packageJson = (0, import_node_path2.join)(projectRoot, "package.json");
|
|
@@ -116,12 +134,15 @@ function getTopLevelDeps(projectRoot) {
|
|
|
116
134
|
}
|
|
117
135
|
return new Set(dependencySets.flatMap((deps) => [...deps]));
|
|
118
136
|
}
|
|
137
|
+
function getWorkspaceTopLevelDeps(pyprojects) {
|
|
138
|
+
return getPythonTopLevelDepsFromFiles(pyprojects);
|
|
139
|
+
}
|
|
119
140
|
function extractDepsFromSpecs(depSpecs, deps) {
|
|
120
141
|
for (const depSpec of depSpecs) {
|
|
121
142
|
if (typeof depSpec !== "string") {
|
|
122
143
|
continue;
|
|
123
144
|
}
|
|
124
|
-
const packageName = depSpec.split(/[
|
|
145
|
+
const packageName = depSpec.split(/[~>=<![\];,\s]/)[0]?.trim();
|
|
125
146
|
if (packageName && !packageName.startsWith("#")) {
|
|
126
147
|
deps.add(normalizePackageName(packageName));
|
|
127
148
|
}
|
|
@@ -164,6 +185,8 @@ var testing = {
|
|
|
164
185
|
0 && (module.exports = {
|
|
165
186
|
getNodeTopLevelDeps,
|
|
166
187
|
getPythonTopLevelDeps,
|
|
188
|
+
getPythonTopLevelDepsFromFiles,
|
|
167
189
|
getTopLevelDeps,
|
|
190
|
+
getWorkspaceTopLevelDeps,
|
|
168
191
|
testing
|
|
169
192
|
});
|
package/ts/dist/deps.d.cts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
declare function getPythonTopLevelDeps(projectRoot: string): Set<string> | null;
|
|
2
|
+
declare function getPythonTopLevelDepsFromFiles(pyprojects: string[]): Set<string> | null;
|
|
2
3
|
declare function getNodeTopLevelDeps(projectRoot: string): Set<string> | null;
|
|
3
4
|
declare function getTopLevelDeps(projectRoot: string): Set<string> | null;
|
|
5
|
+
declare function getWorkspaceTopLevelDeps(pyprojects: string[]): Set<string> | null;
|
|
4
6
|
declare function extractDepsFromSpecs(depSpecs: unknown[], deps: Set<string>): void;
|
|
5
7
|
declare function extractDepsFromDependencyGroup(groupName: unknown, dependencyGroups: Record<string, unknown>, deps: Set<string>, visited: Set<unknown>): void;
|
|
6
8
|
declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
@@ -10,4 +12,4 @@ declare const testing: {
|
|
|
10
12
|
isRecord: typeof isRecord;
|
|
11
13
|
};
|
|
12
14
|
|
|
13
|
-
export { getNodeTopLevelDeps, getPythonTopLevelDeps, getTopLevelDeps, testing };
|
|
15
|
+
export { getNodeTopLevelDeps, getPythonTopLevelDeps, getPythonTopLevelDepsFromFiles, getTopLevelDeps, getWorkspaceTopLevelDeps, testing };
|
package/ts/dist/deps.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
declare function getPythonTopLevelDeps(projectRoot: string): Set<string> | null;
|
|
2
|
+
declare function getPythonTopLevelDepsFromFiles(pyprojects: string[]): Set<string> | null;
|
|
2
3
|
declare function getNodeTopLevelDeps(projectRoot: string): Set<string> | null;
|
|
3
4
|
declare function getTopLevelDeps(projectRoot: string): Set<string> | null;
|
|
5
|
+
declare function getWorkspaceTopLevelDeps(pyprojects: string[]): Set<string> | null;
|
|
4
6
|
declare function extractDepsFromSpecs(depSpecs: unknown[], deps: Set<string>): void;
|
|
5
7
|
declare function extractDepsFromDependencyGroup(groupName: unknown, dependencyGroups: Record<string, unknown>, deps: Set<string>, visited: Set<unknown>): void;
|
|
6
8
|
declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
@@ -10,4 +12,4 @@ declare const testing: {
|
|
|
10
12
|
isRecord: typeof isRecord;
|
|
11
13
|
};
|
|
12
14
|
|
|
13
|
-
export { getNodeTopLevelDeps, getPythonTopLevelDeps, getTopLevelDeps, testing };
|
|
15
|
+
export { getNodeTopLevelDeps, getPythonTopLevelDeps, getPythonTopLevelDepsFromFiles, getTopLevelDeps, getWorkspaceTopLevelDeps, testing };
|
package/ts/dist/deps.js
CHANGED
|
@@ -11,13 +11,30 @@ function getPythonTopLevelDeps(projectRoot) {
|
|
|
11
11
|
if (!existsSync(pyproject)) {
|
|
12
12
|
return null;
|
|
13
13
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
return getPythonTopLevelDepsFromFiles([pyproject]);
|
|
15
|
+
}
|
|
16
|
+
function getPythonTopLevelDepsFromFiles(pyprojects) {
|
|
17
|
+
if (pyprojects.length === 0) {
|
|
18
18
|
return null;
|
|
19
19
|
}
|
|
20
20
|
const deps = /* @__PURE__ */ new Set();
|
|
21
|
+
let found = false;
|
|
22
|
+
for (const pyproject of pyprojects) {
|
|
23
|
+
if (!existsSync(pyproject)) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
let data;
|
|
27
|
+
try {
|
|
28
|
+
data = parse(readFileSync(pyproject, "utf8"));
|
|
29
|
+
} catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
found = true;
|
|
33
|
+
extractPythonTopLevelDeps(data, deps);
|
|
34
|
+
}
|
|
35
|
+
return found ? deps : null;
|
|
36
|
+
}
|
|
37
|
+
function extractPythonTopLevelDeps(data, deps) {
|
|
21
38
|
const project = data["project"];
|
|
22
39
|
if (isRecord(project)) {
|
|
23
40
|
const dependencies = project["dependencies"];
|
|
@@ -39,7 +56,6 @@ function getPythonTopLevelDeps(projectRoot) {
|
|
|
39
56
|
extractDepsFromDependencyGroup(groupName, dependencyGroups, deps, /* @__PURE__ */ new Set());
|
|
40
57
|
}
|
|
41
58
|
}
|
|
42
|
-
return deps;
|
|
43
59
|
}
|
|
44
60
|
function getNodeTopLevelDeps(projectRoot) {
|
|
45
61
|
const packageJson = join(projectRoot, "package.json");
|
|
@@ -82,12 +98,15 @@ function getTopLevelDeps(projectRoot) {
|
|
|
82
98
|
}
|
|
83
99
|
return new Set(dependencySets.flatMap((deps) => [...deps]));
|
|
84
100
|
}
|
|
101
|
+
function getWorkspaceTopLevelDeps(pyprojects) {
|
|
102
|
+
return getPythonTopLevelDepsFromFiles(pyprojects);
|
|
103
|
+
}
|
|
85
104
|
function extractDepsFromSpecs(depSpecs, deps) {
|
|
86
105
|
for (const depSpec of depSpecs) {
|
|
87
106
|
if (typeof depSpec !== "string") {
|
|
88
107
|
continue;
|
|
89
108
|
}
|
|
90
|
-
const packageName = depSpec.split(/[
|
|
109
|
+
const packageName = depSpec.split(/[~>=<![\];,\s]/)[0]?.trim();
|
|
91
110
|
if (packageName && !packageName.startsWith("#")) {
|
|
92
111
|
deps.add(normalizePackageName(packageName));
|
|
93
112
|
}
|
|
@@ -129,6 +148,8 @@ var testing = {
|
|
|
129
148
|
export {
|
|
130
149
|
getNodeTopLevelDeps,
|
|
131
150
|
getPythonTopLevelDeps,
|
|
151
|
+
getPythonTopLevelDepsFromFiles,
|
|
132
152
|
getTopLevelDeps,
|
|
153
|
+
getWorkspaceTopLevelDeps,
|
|
133
154
|
testing
|
|
134
155
|
};
|
package/ts/dist/python-env.cjs
CHANGED
|
@@ -27,54 +27,232 @@ __export(python_env_exports, {
|
|
|
27
27
|
getSitePackagesDir: () => getSitePackagesDir
|
|
28
28
|
});
|
|
29
29
|
module.exports = __toCommonJS(python_env_exports);
|
|
30
|
+
var import_node_fs2 = require("fs");
|
|
31
|
+
var import_node_path2 = require("path");
|
|
32
|
+
|
|
33
|
+
// ts/src/workspace.ts
|
|
30
34
|
var import_node_fs = require("fs");
|
|
31
35
|
var import_node_path = require("path");
|
|
32
|
-
|
|
36
|
+
var import_smol_toml = require("smol-toml");
|
|
37
|
+
function findUvWorkspace(cwd) {
|
|
33
38
|
for (const directory of ancestors(cwd)) {
|
|
34
|
-
|
|
39
|
+
const pyproject = `${directory}/pyproject.toml`;
|
|
40
|
+
if (!(0, import_node_fs.existsSync)(pyproject)) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const data = readPyproject(pyproject);
|
|
44
|
+
if (!hasUvWorkspace(data)) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const members = findWorkspaceMembers(directory, data);
|
|
48
|
+
return {
|
|
49
|
+
root: directory,
|
|
50
|
+
members,
|
|
51
|
+
currentMember: findCurrentMember(cwd, members)
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
function readPyproject(path) {
|
|
57
|
+
try {
|
|
58
|
+
const data = (0, import_smol_toml.parse)((0, import_node_fs.readFileSync)(path, "utf8"));
|
|
59
|
+
return isRecord(data) ? data : {};
|
|
60
|
+
} catch {
|
|
61
|
+
return {};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function hasUvWorkspace(data) {
|
|
65
|
+
const tool = data["tool"];
|
|
66
|
+
if (!isRecord(tool)) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
const uv = tool["uv"];
|
|
70
|
+
if (!isRecord(uv)) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
return isRecord(uv["workspace"]);
|
|
74
|
+
}
|
|
75
|
+
function findWorkspaceMembers(root, data) {
|
|
76
|
+
const workspace = getWorkspaceTable(data);
|
|
77
|
+
if (workspace === null || !Array.isArray(workspace["members"])) {
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
const excludes = Array.isArray(workspace["exclude"]) ? workspace["exclude"].filter(
|
|
81
|
+
(value) => typeof value === "string"
|
|
82
|
+
) : [];
|
|
83
|
+
const members = /* @__PURE__ */ new Set();
|
|
84
|
+
for (const memberGlob of workspace["members"]) {
|
|
85
|
+
if (typeof memberGlob !== "string") {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
for (const member of expandMemberGlob(root, memberGlob)) {
|
|
89
|
+
const relativePath = (0, import_node_path.relative)(root, member).split(import_node_path.sep).join("/");
|
|
90
|
+
if (isExcluded(relativePath, excludes)) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (isFile(`${member}/pyproject.toml`)) {
|
|
94
|
+
members.add((0, import_node_path.resolve)(member));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return [...members].sort();
|
|
99
|
+
}
|
|
100
|
+
function getWorkspaceTable(data) {
|
|
101
|
+
const tool = data["tool"];
|
|
102
|
+
if (!isRecord(tool)) {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
const uv = tool["uv"];
|
|
106
|
+
if (!isRecord(uv)) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
const workspace = uv["workspace"];
|
|
110
|
+
return isRecord(workspace) ? workspace : null;
|
|
111
|
+
}
|
|
112
|
+
function expandMemberGlob(root, pattern) {
|
|
113
|
+
const parts = pattern.split("/");
|
|
114
|
+
const results = [];
|
|
115
|
+
walkGlob(root, parts, results);
|
|
116
|
+
return results;
|
|
117
|
+
}
|
|
118
|
+
function walkGlob(directory, parts, results) {
|
|
119
|
+
if (parts.length === 0) {
|
|
120
|
+
if (isDirectory(directory)) {
|
|
121
|
+
results.push(directory);
|
|
122
|
+
}
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const [part, ...rest] = parts;
|
|
126
|
+
if (part === "*") {
|
|
127
|
+
for (const entry of readDirSafe(directory)) {
|
|
128
|
+
const child = `${directory}/${entry}`;
|
|
129
|
+
if (isDirectory(child)) {
|
|
130
|
+
walkGlob(child, rest, results);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
walkGlob(`${directory}/${part}`, rest, results);
|
|
136
|
+
}
|
|
137
|
+
function isExcluded(relativePath, excludes) {
|
|
138
|
+
return excludes.some(
|
|
139
|
+
(pattern) => globMatches(relativePath, pattern.replace(/\/$/, ""))
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
function globMatches(value, pattern) {
|
|
143
|
+
if (pattern === value) {
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
const regex = new RegExp(`^${pattern.split("*").map(escapeRegex).join(".*")}$`);
|
|
147
|
+
return regex.test(value);
|
|
148
|
+
}
|
|
149
|
+
function findCurrentMember(cwd, members) {
|
|
150
|
+
const resolvedCwd = (0, import_node_path.resolve)(cwd);
|
|
151
|
+
const matches = members.filter((member) => isRelativeTo(resolvedCwd, member));
|
|
152
|
+
if (matches.length === 0) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
return matches.sort((left, right) => right.length - left.length)[0] ?? null;
|
|
156
|
+
}
|
|
157
|
+
function ancestors(start) {
|
|
158
|
+
const result = [];
|
|
159
|
+
let directory = (0, import_node_path.resolve)(start);
|
|
160
|
+
while (true) {
|
|
161
|
+
result.push(directory);
|
|
162
|
+
const parent = (0, import_node_path.resolve)(directory, "..");
|
|
163
|
+
if (parent === directory) {
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
directory = parent;
|
|
167
|
+
}
|
|
168
|
+
return result;
|
|
169
|
+
}
|
|
170
|
+
function isRelativeTo(path, parent) {
|
|
171
|
+
const normalizedPath = (0, import_node_path.resolve)(path);
|
|
172
|
+
const normalizedParent = (0, import_node_path.resolve)(parent);
|
|
173
|
+
return normalizedPath === normalizedParent || normalizedPath.startsWith(`${normalizedParent}${import_node_path.sep}`);
|
|
174
|
+
}
|
|
175
|
+
function isRecord(value) {
|
|
176
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
177
|
+
}
|
|
178
|
+
function isFile(path) {
|
|
179
|
+
try {
|
|
180
|
+
return (0, import_node_fs.statSync)(path).isFile();
|
|
181
|
+
} catch {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function isDirectory(path) {
|
|
186
|
+
try {
|
|
187
|
+
return (0, import_node_fs.statSync)(path).isDirectory();
|
|
188
|
+
} catch {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function readDirSafe(path) {
|
|
193
|
+
try {
|
|
194
|
+
return isDirectory(path) ? (0, import_node_fs.readdirSync)(path) : [];
|
|
195
|
+
} catch {
|
|
196
|
+
return [];
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
var escapeRegex = (value) => value.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
200
|
+
|
|
201
|
+
// ts/src/python-env.ts
|
|
202
|
+
function findProjectRoot(cwd) {
|
|
203
|
+
const workspace = findUvWorkspace(cwd);
|
|
204
|
+
if (workspace !== null) {
|
|
205
|
+
return workspace.root;
|
|
206
|
+
}
|
|
207
|
+
for (const directory of ancestors2(cwd)) {
|
|
208
|
+
if (isFile2((0, import_node_path2.join)(directory, "pyproject.toml")) || isFile2((0, import_node_path2.join)(directory, "uv.lock")) || venvFromDotVenv(directory) !== null || isFile2((0, import_node_path2.join)(directory, "package.json")) || isDirectory2((0, import_node_path2.join)(directory, "node_modules"))) {
|
|
35
209
|
return directory;
|
|
36
210
|
}
|
|
37
211
|
}
|
|
38
212
|
return null;
|
|
39
213
|
}
|
|
40
214
|
function findVenv(cwd = process.cwd()) {
|
|
215
|
+
const workspace = findUvWorkspace(cwd);
|
|
41
216
|
const projectRoot = findProjectRoot(cwd) ?? cwd;
|
|
42
217
|
const uvProjectEnvironment = process.env["UV_PROJECT_ENVIRONMENT"];
|
|
43
218
|
if (uvProjectEnvironment) {
|
|
44
|
-
const path = (0,
|
|
219
|
+
const path = (0, import_node_path2.isAbsolute)(uvProjectEnvironment) ? uvProjectEnvironment : (0, import_node_path2.join)(projectRoot, uvProjectEnvironment);
|
|
45
220
|
if (isVenvDir(path)) {
|
|
46
221
|
return path;
|
|
47
222
|
}
|
|
48
223
|
}
|
|
49
|
-
|
|
224
|
+
if (workspace !== null) {
|
|
225
|
+
return venvFromDotVenv(workspace.root);
|
|
226
|
+
}
|
|
227
|
+
for (const directory of ancestors2(cwd)) {
|
|
50
228
|
const venv = venvFromDotVenv(directory);
|
|
51
229
|
if (venv !== null) {
|
|
52
230
|
return venv;
|
|
53
231
|
}
|
|
54
232
|
}
|
|
55
233
|
const virtualEnv = process.env["VIRTUAL_ENV"];
|
|
56
|
-
if (virtualEnv && isVenvDir(virtualEnv) &&
|
|
234
|
+
if (virtualEnv && isVenvDir(virtualEnv) && isRelativeTo2(virtualEnv, projectRoot)) {
|
|
57
235
|
return virtualEnv;
|
|
58
236
|
}
|
|
59
237
|
const condaPrefix = process.env["CONDA_PREFIX"];
|
|
60
|
-
if (condaPrefix &&
|
|
238
|
+
if (condaPrefix && isDirectory2(condaPrefix)) {
|
|
61
239
|
return condaPrefix;
|
|
62
240
|
}
|
|
63
241
|
return null;
|
|
64
242
|
}
|
|
65
243
|
function getSitePackagesDir(venvPath) {
|
|
66
|
-
const windowsSitePackages = (0,
|
|
67
|
-
if (
|
|
244
|
+
const windowsSitePackages = (0, import_node_path2.join)(venvPath, "Lib", "site-packages");
|
|
245
|
+
if (isDirectory2(windowsSitePackages)) {
|
|
68
246
|
return windowsSitePackages;
|
|
69
247
|
}
|
|
70
248
|
for (const libName of ["lib", "lib64"]) {
|
|
71
|
-
const libDir = (0,
|
|
72
|
-
if (!
|
|
249
|
+
const libDir = (0, import_node_path2.join)(venvPath, libName);
|
|
250
|
+
if (!isDirectory2(libDir)) {
|
|
73
251
|
continue;
|
|
74
252
|
}
|
|
75
|
-
for (const child of (0,
|
|
76
|
-
const sitePackages = (0,
|
|
77
|
-
if (child.startsWith("python") &&
|
|
253
|
+
for (const child of (0, import_node_fs2.readdirSync)(libDir).sort().reverse()) {
|
|
254
|
+
const sitePackages = (0, import_node_path2.join)(libDir, child, "site-packages");
|
|
255
|
+
if (child.startsWith("python") && isDirectory2(sitePackages)) {
|
|
78
256
|
return sitePackages;
|
|
79
257
|
}
|
|
80
258
|
}
|
|
@@ -83,23 +261,23 @@ function getSitePackagesDir(venvPath) {
|
|
|
83
261
|
}
|
|
84
262
|
var getSitePackages = getSitePackagesDir;
|
|
85
263
|
function findNodeModules(cwd = process.cwd()) {
|
|
86
|
-
for (const directory of
|
|
87
|
-
const nodeModules = (0,
|
|
88
|
-
if (
|
|
264
|
+
for (const directory of ancestors2(cwd)) {
|
|
265
|
+
const nodeModules = (0, import_node_path2.join)(directory, "node_modules");
|
|
266
|
+
if (isDirectory2(nodeModules)) {
|
|
89
267
|
return nodeModules;
|
|
90
268
|
}
|
|
91
269
|
}
|
|
92
270
|
return null;
|
|
93
271
|
}
|
|
94
272
|
function isVenvDir(directory) {
|
|
95
|
-
return
|
|
273
|
+
return isFile2((0, import_node_path2.join)(directory, "pyvenv.cfg"));
|
|
96
274
|
}
|
|
97
275
|
function venvFromDotVenv(projectRoot) {
|
|
98
|
-
const dotVenv = (0,
|
|
99
|
-
if (
|
|
276
|
+
const dotVenv = (0, import_node_path2.join)(projectRoot, ".venv");
|
|
277
|
+
if (isDirectory2(dotVenv)) {
|
|
100
278
|
return isVenvDir(dotVenv) ? dotVenv : null;
|
|
101
279
|
}
|
|
102
|
-
if (
|
|
280
|
+
if (isFile2(dotVenv)) {
|
|
103
281
|
return readVenvRedirectFile(dotVenv);
|
|
104
282
|
}
|
|
105
283
|
return null;
|
|
@@ -107,7 +285,7 @@ function venvFromDotVenv(projectRoot) {
|
|
|
107
285
|
function readVenvRedirectFile(path) {
|
|
108
286
|
let content;
|
|
109
287
|
try {
|
|
110
|
-
content = (0,
|
|
288
|
+
content = (0, import_node_fs2.readFileSync)(path, "utf8");
|
|
111
289
|
} catch {
|
|
112
290
|
return null;
|
|
113
291
|
}
|
|
@@ -115,15 +293,15 @@ function readVenvRedirectFile(path) {
|
|
|
115
293
|
if (!redirect) {
|
|
116
294
|
return null;
|
|
117
295
|
}
|
|
118
|
-
const venv = (0,
|
|
296
|
+
const venv = (0, import_node_path2.isAbsolute)(redirect) ? redirect : (0, import_node_path2.join)((0, import_node_path2.dirname)(path), redirect);
|
|
119
297
|
return isVenvDir(venv) ? venv : null;
|
|
120
298
|
}
|
|
121
|
-
function
|
|
299
|
+
function ancestors2(start) {
|
|
122
300
|
const result = [];
|
|
123
|
-
let directory = (0,
|
|
301
|
+
let directory = (0, import_node_path2.resolve)(start);
|
|
124
302
|
while (true) {
|
|
125
303
|
result.push(directory);
|
|
126
|
-
const parent = (0,
|
|
304
|
+
const parent = (0, import_node_path2.dirname)(directory);
|
|
127
305
|
if (parent === directory) {
|
|
128
306
|
break;
|
|
129
307
|
}
|
|
@@ -131,21 +309,21 @@ function ancestors(start) {
|
|
|
131
309
|
}
|
|
132
310
|
return result;
|
|
133
311
|
}
|
|
134
|
-
function
|
|
135
|
-
const normalizedPath = (0,
|
|
136
|
-
const normalizedParent = (0,
|
|
137
|
-
return normalizedPath === normalizedParent || normalizedPath.startsWith(`${normalizedParent}${
|
|
312
|
+
function isRelativeTo2(path, parent) {
|
|
313
|
+
const normalizedPath = (0, import_node_path2.resolve)(path);
|
|
314
|
+
const normalizedParent = (0, import_node_path2.resolve)(parent);
|
|
315
|
+
return normalizedPath === normalizedParent || normalizedPath.startsWith(`${normalizedParent}${import_node_path2.sep}`);
|
|
138
316
|
}
|
|
139
|
-
function
|
|
317
|
+
function isFile2(path) {
|
|
140
318
|
try {
|
|
141
|
-
return (0,
|
|
319
|
+
return (0, import_node_fs2.statSync)(path).isFile();
|
|
142
320
|
} catch {
|
|
143
321
|
return false;
|
|
144
322
|
}
|
|
145
323
|
}
|
|
146
|
-
function
|
|
324
|
+
function isDirectory2(path) {
|
|
147
325
|
try {
|
|
148
|
-
return (0,
|
|
326
|
+
return (0, import_node_fs2.statSync)(path).isDirectory();
|
|
149
327
|
} catch {
|
|
150
328
|
return false;
|
|
151
329
|
}
|
package/ts/dist/python-env.js
CHANGED
|
@@ -1,15 +1,190 @@
|
|
|
1
1
|
// ts/src/python-env.ts
|
|
2
|
-
import { readFileSync, readdirSync, statSync } from "fs";
|
|
3
|
-
import { dirname, isAbsolute, join, resolve, sep } from "path";
|
|
4
|
-
|
|
2
|
+
import { readFileSync as readFileSync2, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
3
|
+
import { dirname, isAbsolute, join, resolve as resolve2, sep as sep2 } from "path";
|
|
4
|
+
|
|
5
|
+
// ts/src/workspace.ts
|
|
6
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "fs";
|
|
7
|
+
import { relative, resolve, sep } from "path";
|
|
8
|
+
import { parse } from "smol-toml";
|
|
9
|
+
function findUvWorkspace(cwd) {
|
|
5
10
|
for (const directory of ancestors(cwd)) {
|
|
6
|
-
|
|
11
|
+
const pyproject = `${directory}/pyproject.toml`;
|
|
12
|
+
if (!existsSync(pyproject)) {
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
const data = readPyproject(pyproject);
|
|
16
|
+
if (!hasUvWorkspace(data)) {
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
const members = findWorkspaceMembers(directory, data);
|
|
20
|
+
return {
|
|
21
|
+
root: directory,
|
|
22
|
+
members,
|
|
23
|
+
currentMember: findCurrentMember(cwd, members)
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
function readPyproject(path) {
|
|
29
|
+
try {
|
|
30
|
+
const data = parse(readFileSync(path, "utf8"));
|
|
31
|
+
return isRecord(data) ? data : {};
|
|
32
|
+
} catch {
|
|
33
|
+
return {};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function hasUvWorkspace(data) {
|
|
37
|
+
const tool = data["tool"];
|
|
38
|
+
if (!isRecord(tool)) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
const uv = tool["uv"];
|
|
42
|
+
if (!isRecord(uv)) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
return isRecord(uv["workspace"]);
|
|
46
|
+
}
|
|
47
|
+
function findWorkspaceMembers(root, data) {
|
|
48
|
+
const workspace = getWorkspaceTable(data);
|
|
49
|
+
if (workspace === null || !Array.isArray(workspace["members"])) {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
const excludes = Array.isArray(workspace["exclude"]) ? workspace["exclude"].filter(
|
|
53
|
+
(value) => typeof value === "string"
|
|
54
|
+
) : [];
|
|
55
|
+
const members = /* @__PURE__ */ new Set();
|
|
56
|
+
for (const memberGlob of workspace["members"]) {
|
|
57
|
+
if (typeof memberGlob !== "string") {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
for (const member of expandMemberGlob(root, memberGlob)) {
|
|
61
|
+
const relativePath = relative(root, member).split(sep).join("/");
|
|
62
|
+
if (isExcluded(relativePath, excludes)) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (isFile(`${member}/pyproject.toml`)) {
|
|
66
|
+
members.add(resolve(member));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return [...members].sort();
|
|
71
|
+
}
|
|
72
|
+
function getWorkspaceTable(data) {
|
|
73
|
+
const tool = data["tool"];
|
|
74
|
+
if (!isRecord(tool)) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
const uv = tool["uv"];
|
|
78
|
+
if (!isRecord(uv)) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
const workspace = uv["workspace"];
|
|
82
|
+
return isRecord(workspace) ? workspace : null;
|
|
83
|
+
}
|
|
84
|
+
function expandMemberGlob(root, pattern) {
|
|
85
|
+
const parts = pattern.split("/");
|
|
86
|
+
const results = [];
|
|
87
|
+
walkGlob(root, parts, results);
|
|
88
|
+
return results;
|
|
89
|
+
}
|
|
90
|
+
function walkGlob(directory, parts, results) {
|
|
91
|
+
if (parts.length === 0) {
|
|
92
|
+
if (isDirectory(directory)) {
|
|
93
|
+
results.push(directory);
|
|
94
|
+
}
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const [part, ...rest] = parts;
|
|
98
|
+
if (part === "*") {
|
|
99
|
+
for (const entry of readDirSafe(directory)) {
|
|
100
|
+
const child = `${directory}/${entry}`;
|
|
101
|
+
if (isDirectory(child)) {
|
|
102
|
+
walkGlob(child, rest, results);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
walkGlob(`${directory}/${part}`, rest, results);
|
|
108
|
+
}
|
|
109
|
+
function isExcluded(relativePath, excludes) {
|
|
110
|
+
return excludes.some(
|
|
111
|
+
(pattern) => globMatches(relativePath, pattern.replace(/\/$/, ""))
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
function globMatches(value, pattern) {
|
|
115
|
+
if (pattern === value) {
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
const regex = new RegExp(`^${pattern.split("*").map(escapeRegex).join(".*")}$`);
|
|
119
|
+
return regex.test(value);
|
|
120
|
+
}
|
|
121
|
+
function findCurrentMember(cwd, members) {
|
|
122
|
+
const resolvedCwd = resolve(cwd);
|
|
123
|
+
const matches = members.filter((member) => isRelativeTo(resolvedCwd, member));
|
|
124
|
+
if (matches.length === 0) {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
return matches.sort((left, right) => right.length - left.length)[0] ?? null;
|
|
128
|
+
}
|
|
129
|
+
function ancestors(start) {
|
|
130
|
+
const result = [];
|
|
131
|
+
let directory = resolve(start);
|
|
132
|
+
while (true) {
|
|
133
|
+
result.push(directory);
|
|
134
|
+
const parent = resolve(directory, "..");
|
|
135
|
+
if (parent === directory) {
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
directory = parent;
|
|
139
|
+
}
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
function isRelativeTo(path, parent) {
|
|
143
|
+
const normalizedPath = resolve(path);
|
|
144
|
+
const normalizedParent = resolve(parent);
|
|
145
|
+
return normalizedPath === normalizedParent || normalizedPath.startsWith(`${normalizedParent}${sep}`);
|
|
146
|
+
}
|
|
147
|
+
function isRecord(value) {
|
|
148
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
149
|
+
}
|
|
150
|
+
function isFile(path) {
|
|
151
|
+
try {
|
|
152
|
+
return statSync(path).isFile();
|
|
153
|
+
} catch {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function isDirectory(path) {
|
|
158
|
+
try {
|
|
159
|
+
return statSync(path).isDirectory();
|
|
160
|
+
} catch {
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
function readDirSafe(path) {
|
|
165
|
+
try {
|
|
166
|
+
return isDirectory(path) ? readdirSync(path) : [];
|
|
167
|
+
} catch {
|
|
168
|
+
return [];
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
var escapeRegex = (value) => value.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
172
|
+
|
|
173
|
+
// ts/src/python-env.ts
|
|
174
|
+
function findProjectRoot(cwd) {
|
|
175
|
+
const workspace = findUvWorkspace(cwd);
|
|
176
|
+
if (workspace !== null) {
|
|
177
|
+
return workspace.root;
|
|
178
|
+
}
|
|
179
|
+
for (const directory of ancestors2(cwd)) {
|
|
180
|
+
if (isFile2(join(directory, "pyproject.toml")) || isFile2(join(directory, "uv.lock")) || venvFromDotVenv(directory) !== null || isFile2(join(directory, "package.json")) || isDirectory2(join(directory, "node_modules"))) {
|
|
7
181
|
return directory;
|
|
8
182
|
}
|
|
9
183
|
}
|
|
10
184
|
return null;
|
|
11
185
|
}
|
|
12
186
|
function findVenv(cwd = process.cwd()) {
|
|
187
|
+
const workspace = findUvWorkspace(cwd);
|
|
13
188
|
const projectRoot = findProjectRoot(cwd) ?? cwd;
|
|
14
189
|
const uvProjectEnvironment = process.env["UV_PROJECT_ENVIRONMENT"];
|
|
15
190
|
if (uvProjectEnvironment) {
|
|
@@ -18,35 +193,38 @@ function findVenv(cwd = process.cwd()) {
|
|
|
18
193
|
return path;
|
|
19
194
|
}
|
|
20
195
|
}
|
|
21
|
-
|
|
196
|
+
if (workspace !== null) {
|
|
197
|
+
return venvFromDotVenv(workspace.root);
|
|
198
|
+
}
|
|
199
|
+
for (const directory of ancestors2(cwd)) {
|
|
22
200
|
const venv = venvFromDotVenv(directory);
|
|
23
201
|
if (venv !== null) {
|
|
24
202
|
return venv;
|
|
25
203
|
}
|
|
26
204
|
}
|
|
27
205
|
const virtualEnv = process.env["VIRTUAL_ENV"];
|
|
28
|
-
if (virtualEnv && isVenvDir(virtualEnv) &&
|
|
206
|
+
if (virtualEnv && isVenvDir(virtualEnv) && isRelativeTo2(virtualEnv, projectRoot)) {
|
|
29
207
|
return virtualEnv;
|
|
30
208
|
}
|
|
31
209
|
const condaPrefix = process.env["CONDA_PREFIX"];
|
|
32
|
-
if (condaPrefix &&
|
|
210
|
+
if (condaPrefix && isDirectory2(condaPrefix)) {
|
|
33
211
|
return condaPrefix;
|
|
34
212
|
}
|
|
35
213
|
return null;
|
|
36
214
|
}
|
|
37
215
|
function getSitePackagesDir(venvPath) {
|
|
38
216
|
const windowsSitePackages = join(venvPath, "Lib", "site-packages");
|
|
39
|
-
if (
|
|
217
|
+
if (isDirectory2(windowsSitePackages)) {
|
|
40
218
|
return windowsSitePackages;
|
|
41
219
|
}
|
|
42
220
|
for (const libName of ["lib", "lib64"]) {
|
|
43
221
|
const libDir = join(venvPath, libName);
|
|
44
|
-
if (!
|
|
222
|
+
if (!isDirectory2(libDir)) {
|
|
45
223
|
continue;
|
|
46
224
|
}
|
|
47
|
-
for (const child of
|
|
225
|
+
for (const child of readdirSync2(libDir).sort().reverse()) {
|
|
48
226
|
const sitePackages = join(libDir, child, "site-packages");
|
|
49
|
-
if (child.startsWith("python") &&
|
|
227
|
+
if (child.startsWith("python") && isDirectory2(sitePackages)) {
|
|
50
228
|
return sitePackages;
|
|
51
229
|
}
|
|
52
230
|
}
|
|
@@ -55,23 +233,23 @@ function getSitePackagesDir(venvPath) {
|
|
|
55
233
|
}
|
|
56
234
|
var getSitePackages = getSitePackagesDir;
|
|
57
235
|
function findNodeModules(cwd = process.cwd()) {
|
|
58
|
-
for (const directory of
|
|
236
|
+
for (const directory of ancestors2(cwd)) {
|
|
59
237
|
const nodeModules = join(directory, "node_modules");
|
|
60
|
-
if (
|
|
238
|
+
if (isDirectory2(nodeModules)) {
|
|
61
239
|
return nodeModules;
|
|
62
240
|
}
|
|
63
241
|
}
|
|
64
242
|
return null;
|
|
65
243
|
}
|
|
66
244
|
function isVenvDir(directory) {
|
|
67
|
-
return
|
|
245
|
+
return isFile2(join(directory, "pyvenv.cfg"));
|
|
68
246
|
}
|
|
69
247
|
function venvFromDotVenv(projectRoot) {
|
|
70
248
|
const dotVenv = join(projectRoot, ".venv");
|
|
71
|
-
if (
|
|
249
|
+
if (isDirectory2(dotVenv)) {
|
|
72
250
|
return isVenvDir(dotVenv) ? dotVenv : null;
|
|
73
251
|
}
|
|
74
|
-
if (
|
|
252
|
+
if (isFile2(dotVenv)) {
|
|
75
253
|
return readVenvRedirectFile(dotVenv);
|
|
76
254
|
}
|
|
77
255
|
return null;
|
|
@@ -79,7 +257,7 @@ function venvFromDotVenv(projectRoot) {
|
|
|
79
257
|
function readVenvRedirectFile(path) {
|
|
80
258
|
let content;
|
|
81
259
|
try {
|
|
82
|
-
content =
|
|
260
|
+
content = readFileSync2(path, "utf8");
|
|
83
261
|
} catch {
|
|
84
262
|
return null;
|
|
85
263
|
}
|
|
@@ -90,9 +268,9 @@ function readVenvRedirectFile(path) {
|
|
|
90
268
|
const venv = isAbsolute(redirect) ? redirect : join(dirname(path), redirect);
|
|
91
269
|
return isVenvDir(venv) ? venv : null;
|
|
92
270
|
}
|
|
93
|
-
function
|
|
271
|
+
function ancestors2(start) {
|
|
94
272
|
const result = [];
|
|
95
|
-
let directory =
|
|
273
|
+
let directory = resolve2(start);
|
|
96
274
|
while (true) {
|
|
97
275
|
result.push(directory);
|
|
98
276
|
const parent = dirname(directory);
|
|
@@ -103,21 +281,21 @@ function ancestors(start) {
|
|
|
103
281
|
}
|
|
104
282
|
return result;
|
|
105
283
|
}
|
|
106
|
-
function
|
|
107
|
-
const normalizedPath =
|
|
108
|
-
const normalizedParent =
|
|
109
|
-
return normalizedPath === normalizedParent || normalizedPath.startsWith(`${normalizedParent}${
|
|
284
|
+
function isRelativeTo2(path, parent) {
|
|
285
|
+
const normalizedPath = resolve2(path);
|
|
286
|
+
const normalizedParent = resolve2(parent);
|
|
287
|
+
return normalizedPath === normalizedParent || normalizedPath.startsWith(`${normalizedParent}${sep2}`);
|
|
110
288
|
}
|
|
111
|
-
function
|
|
289
|
+
function isFile2(path) {
|
|
112
290
|
try {
|
|
113
|
-
return
|
|
291
|
+
return statSync2(path).isFile();
|
|
114
292
|
} catch {
|
|
115
293
|
return false;
|
|
116
294
|
}
|
|
117
295
|
}
|
|
118
|
-
function
|
|
296
|
+
function isDirectory2(path) {
|
|
119
297
|
try {
|
|
120
|
-
return
|
|
298
|
+
return statSync2(path).isDirectory();
|
|
121
299
|
} catch {
|
|
122
300
|
return false;
|
|
123
301
|
}
|