@vercel/python-analysis 0.4.1 → 0.5.0
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/dist/index.cjs +235 -44
- package/dist/index.d.ts +4 -0
- package/dist/index.js +197 -12
- package/dist/manifest/dist-metadata.d.ts +103 -0
- package/dist/manifest/uv-lock-parser.d.ts +77 -0
- package/dist/wasm/interfaces/wasi-random-insecure-seed.d.ts +2 -0
- package/dist/wasm/vercel_python_analysis.core.wasm +0 -0
- package/dist/wasm/vercel_python_analysis.core2.wasm +0 -0
- package/dist/wasm/vercel_python_analysis.core3.wasm +0 -0
- package/dist/wasm/vercel_python_analysis.core4.wasm +0 -0
- package/dist/wasm/vercel_python_analysis.d.ts +60 -0
- package/dist/wasm/vercel_python_analysis.js +734 -20
- package/package.json +1 -1
- /package/dist/{semantic → wasm}/load.d.ts +0 -0
package/dist/index.cjs
CHANGED
|
@@ -62,15 +62,21 @@ __export(src_exports, {
|
|
|
62
62
|
UvConfigSchema: () => UvConfigSchema,
|
|
63
63
|
UvConfigWorkspaceSchema: () => UvConfigWorkspaceSchema,
|
|
64
64
|
UvIndexEntrySchema: () => UvIndexEntrySchema,
|
|
65
|
+
classifyPackages: () => classifyPackages,
|
|
65
66
|
containsAppOrHandler: () => containsAppOrHandler,
|
|
66
67
|
createMinimalManifest: () => createMinimalManifest,
|
|
67
68
|
discoverPythonPackage: () => discoverPythonPackage,
|
|
69
|
+
generateRuntimeRequirements: () => generateRuntimeRequirements,
|
|
70
|
+
isPrivatePackageSource: () => isPrivatePackageSource,
|
|
71
|
+
normalizePackageName: () => normalizePackageName,
|
|
72
|
+
parseUvLock: () => parseUvLock,
|
|
73
|
+
scanDistributions: () => scanDistributions,
|
|
68
74
|
selectPython: () => selectPython,
|
|
69
75
|
stringifyManifest: () => stringifyManifest
|
|
70
76
|
});
|
|
71
77
|
module.exports = __toCommonJS(src_exports);
|
|
72
78
|
|
|
73
|
-
// src/
|
|
79
|
+
// src/wasm/load.ts
|
|
74
80
|
var import_promises = require("fs/promises");
|
|
75
81
|
var import_node_module = require("module");
|
|
76
82
|
var import_node_path = require("path");
|
|
@@ -89,7 +95,7 @@ function getWasmDir() {
|
|
|
89
95
|
}
|
|
90
96
|
async function getCoreModule(path4) {
|
|
91
97
|
const wasmPath = (0, import_node_path.join)(getWasmDir(), path4);
|
|
92
|
-
const wasmBytes = await (0, import_promises.readFile)(wasmPath);
|
|
98
|
+
const wasmBytes = new Uint8Array(await (0, import_promises.readFile)(wasmPath));
|
|
93
99
|
return WebAssembly.compile(wasmBytes);
|
|
94
100
|
}
|
|
95
101
|
async function importWasmModule() {
|
|
@@ -119,17 +125,107 @@ async function containsAppOrHandler(source) {
|
|
|
119
125
|
return mod.containsAppOrHandler(source);
|
|
120
126
|
}
|
|
121
127
|
|
|
128
|
+
// src/manifest/dist-metadata.ts
|
|
129
|
+
var import_promises2 = require("fs/promises");
|
|
130
|
+
var import_node_path2 = require("path");
|
|
131
|
+
async function readDistInfoFile(distInfoDir, filename) {
|
|
132
|
+
try {
|
|
133
|
+
return await (0, import_promises2.readFile)((0, import_node_path2.join)(distInfoDir, filename), "utf-8");
|
|
134
|
+
} catch {
|
|
135
|
+
return void 0;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
async function scanDistributions(sitePackagesDir) {
|
|
139
|
+
const mod = await importWasmModule();
|
|
140
|
+
const index = /* @__PURE__ */ new Map();
|
|
141
|
+
let entries;
|
|
142
|
+
try {
|
|
143
|
+
entries = await (0, import_promises2.readdir)(sitePackagesDir);
|
|
144
|
+
} catch {
|
|
145
|
+
return index;
|
|
146
|
+
}
|
|
147
|
+
const distInfoDirs = entries.filter((e) => e.endsWith(".dist-info"));
|
|
148
|
+
for (const dirName of distInfoDirs) {
|
|
149
|
+
const distInfoPath = (0, import_node_path2.join)(sitePackagesDir, dirName);
|
|
150
|
+
const metadataContent = await readDistInfoFile(distInfoPath, "METADATA");
|
|
151
|
+
if (!metadataContent) {
|
|
152
|
+
console.debug(`Missing METADATA in ${dirName}`);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
let metadata;
|
|
156
|
+
try {
|
|
157
|
+
metadata = mod.parseDistMetadata(
|
|
158
|
+
new TextEncoder().encode(metadataContent)
|
|
159
|
+
);
|
|
160
|
+
} catch (e) {
|
|
161
|
+
console.debug(`Failed to parse METADATA for ${dirName}: ${e}`);
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
const normalizedName = mod.normalizePackageName(metadata.name);
|
|
165
|
+
let files = [];
|
|
166
|
+
const recordContent = await readDistInfoFile(distInfoPath, "RECORD");
|
|
167
|
+
if (recordContent) {
|
|
168
|
+
try {
|
|
169
|
+
files = mod.parseRecord(recordContent);
|
|
170
|
+
} catch (e) {
|
|
171
|
+
console.warn(`Failed to parse RECORD for ${dirName}: ${e}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
let origin;
|
|
175
|
+
const directUrlContent = await readDistInfoFile(
|
|
176
|
+
distInfoPath,
|
|
177
|
+
"direct_url.json"
|
|
178
|
+
);
|
|
179
|
+
if (directUrlContent) {
|
|
180
|
+
try {
|
|
181
|
+
origin = mod.parseDirectUrl(directUrlContent);
|
|
182
|
+
} catch (e) {
|
|
183
|
+
console.debug(`Failed to parse direct_url.json for ${dirName}: ${e}`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
const installerContent = await readDistInfoFile(distInfoPath, "INSTALLER");
|
|
187
|
+
const installer = installerContent?.trim() || void 0;
|
|
188
|
+
const dist = {
|
|
189
|
+
name: normalizedName,
|
|
190
|
+
version: metadata.version,
|
|
191
|
+
metadataVersion: metadata.metadataVersion,
|
|
192
|
+
summary: metadata.summary,
|
|
193
|
+
description: metadata.description,
|
|
194
|
+
descriptionContentType: metadata.descriptionContentType,
|
|
195
|
+
requiresDist: metadata.requiresDist,
|
|
196
|
+
requiresPython: metadata.requiresPython,
|
|
197
|
+
providesExtra: metadata.providesExtra,
|
|
198
|
+
author: metadata.author,
|
|
199
|
+
authorEmail: metadata.authorEmail,
|
|
200
|
+
maintainer: metadata.maintainer,
|
|
201
|
+
maintainerEmail: metadata.maintainerEmail,
|
|
202
|
+
license: metadata.license,
|
|
203
|
+
licenseExpression: metadata.licenseExpression,
|
|
204
|
+
classifiers: metadata.classifiers,
|
|
205
|
+
homePage: metadata.homePage,
|
|
206
|
+
projectUrls: metadata.projectUrls,
|
|
207
|
+
platforms: metadata.platforms,
|
|
208
|
+
dynamic: metadata.dynamic,
|
|
209
|
+
files,
|
|
210
|
+
origin,
|
|
211
|
+
installer
|
|
212
|
+
};
|
|
213
|
+
index.set(normalizedName, dist);
|
|
214
|
+
}
|
|
215
|
+
return index;
|
|
216
|
+
}
|
|
217
|
+
|
|
122
218
|
// src/manifest/package.ts
|
|
123
|
-
var
|
|
219
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
124
220
|
var import_minimatch = require("minimatch");
|
|
125
221
|
|
|
126
222
|
// src/util/config.ts
|
|
127
|
-
var
|
|
223
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
128
224
|
var import_js_yaml = __toESM(require("js-yaml"), 1);
|
|
129
225
|
var import_smol_toml = __toESM(require("smol-toml"), 1);
|
|
130
226
|
|
|
131
227
|
// src/util/fs.ts
|
|
132
|
-
var
|
|
228
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
133
229
|
var import_fs_extra = require("fs-extra");
|
|
134
230
|
|
|
135
231
|
// src/util/error.ts
|
|
@@ -177,21 +273,21 @@ async function readFileTextIfExists(file, encoding = "utf8") {
|
|
|
177
273
|
}
|
|
178
274
|
}
|
|
179
275
|
function normalizePath(p) {
|
|
180
|
-
let np =
|
|
181
|
-
if (np.endsWith(
|
|
276
|
+
let np = import_node_path3.default.normalize(p);
|
|
277
|
+
if (np.endsWith(import_node_path3.default.sep)) {
|
|
182
278
|
np = np.slice(0, -1);
|
|
183
279
|
}
|
|
184
280
|
return np;
|
|
185
281
|
}
|
|
186
282
|
function isSubpath(somePath, parentPath) {
|
|
187
|
-
const rel =
|
|
188
|
-
return rel === "" || !rel.startsWith("..") && !
|
|
283
|
+
const rel = import_node_path3.default.relative(parentPath, somePath);
|
|
284
|
+
return rel === "" || !rel.startsWith("..") && !import_node_path3.default.isAbsolute(rel);
|
|
189
285
|
}
|
|
190
286
|
|
|
191
287
|
// src/util/config.ts
|
|
192
288
|
function parseRawConfig(content, filename, filetype = void 0) {
|
|
193
289
|
if (filetype === void 0) {
|
|
194
|
-
filetype =
|
|
290
|
+
filetype = import_node_path4.default.extname(filename.toLowerCase());
|
|
195
291
|
}
|
|
196
292
|
try {
|
|
197
293
|
if (filetype === ".json") {
|
|
@@ -722,7 +818,7 @@ var PyProjectToolSectionSchema = pyProjectToolSectionSchema.passthrough();
|
|
|
722
818
|
var PyProjectTomlSchema = pyProjectTomlSchema.passthrough();
|
|
723
819
|
|
|
724
820
|
// src/manifest/requirements-txt-parser.ts
|
|
725
|
-
var
|
|
821
|
+
var import_node_path5 = require("path");
|
|
726
822
|
var import_pip_requirements_js = require("pip-requirements-js");
|
|
727
823
|
var PRIMARY_INDEX_NAME = "primary";
|
|
728
824
|
var EXTRA_INDEX_PREFIX = "extra-";
|
|
@@ -1060,9 +1156,9 @@ function normalizePathRequirement(rawLine) {
|
|
|
1060
1156
|
}
|
|
1061
1157
|
return req;
|
|
1062
1158
|
}
|
|
1063
|
-
function convertRequirementsToPyprojectToml(fileContent,
|
|
1159
|
+
function convertRequirementsToPyprojectToml(fileContent, readFile4) {
|
|
1064
1160
|
const pyproject = {};
|
|
1065
|
-
const parsed = parseRequirementsFile(fileContent,
|
|
1161
|
+
const parsed = parseRequirementsFile(fileContent, readFile4);
|
|
1066
1162
|
const deps = [];
|
|
1067
1163
|
const sources = {};
|
|
1068
1164
|
for (const req of parsed.requirements) {
|
|
@@ -1121,11 +1217,11 @@ function buildIndexEntries(pipOptions) {
|
|
|
1121
1217
|
}
|
|
1122
1218
|
return indexes;
|
|
1123
1219
|
}
|
|
1124
|
-
function parseRequirementsFile(fileContent,
|
|
1220
|
+
function parseRequirementsFile(fileContent, readFile4) {
|
|
1125
1221
|
const visited = /* @__PURE__ */ new Set();
|
|
1126
|
-
return parseRequirementsFileInternal(fileContent,
|
|
1222
|
+
return parseRequirementsFileInternal(fileContent, readFile4, visited);
|
|
1127
1223
|
}
|
|
1128
|
-
function parseRequirementsFileInternal(fileContent,
|
|
1224
|
+
function parseRequirementsFileInternal(fileContent, readFile4, visited) {
|
|
1129
1225
|
const { cleanedContent, options, pathRequirements, editableRequirements } = extractPipArguments(fileContent);
|
|
1130
1226
|
const hashMap = buildHashMap(fileContent);
|
|
1131
1227
|
const requirements = (0, import_pip_requirements_js.parsePipRequirementsFile)(cleanedContent);
|
|
@@ -1173,18 +1269,18 @@ function parseRequirementsFileInternal(fileContent, readFile3, visited) {
|
|
|
1173
1269
|
normalized.push(norm);
|
|
1174
1270
|
}
|
|
1175
1271
|
}
|
|
1176
|
-
if (
|
|
1272
|
+
if (readFile4) {
|
|
1177
1273
|
for (const refPath of mergedOptions.requirementFiles) {
|
|
1178
|
-
const refPathKey = (0,
|
|
1274
|
+
const refPathKey = (0, import_node_path5.normalize)(refPath);
|
|
1179
1275
|
if (visited.has(refPathKey)) {
|
|
1180
1276
|
continue;
|
|
1181
1277
|
}
|
|
1182
1278
|
visited.add(refPathKey);
|
|
1183
|
-
const refContent =
|
|
1279
|
+
const refContent = readFile4(refPath);
|
|
1184
1280
|
if (refContent != null) {
|
|
1185
1281
|
const refParsed = parseRequirementsFileInternal(
|
|
1186
1282
|
refContent,
|
|
1187
|
-
|
|
1283
|
+
readFile4,
|
|
1188
1284
|
visited
|
|
1189
1285
|
);
|
|
1190
1286
|
const existingNames = new Set(
|
|
@@ -1727,7 +1823,7 @@ async function discoverPythonPackage({
|
|
|
1727
1823
|
}) {
|
|
1728
1824
|
const entrypointPath = normalizePath(entrypointDir);
|
|
1729
1825
|
const rootPath = normalizePath(rootDir);
|
|
1730
|
-
let prefix =
|
|
1826
|
+
let prefix = import_node_path6.default.relative(rootPath, entrypointPath);
|
|
1731
1827
|
if (prefix.startsWith("..")) {
|
|
1732
1828
|
throw new PythonAnalysisError({
|
|
1733
1829
|
message: "Entrypoint directory outside of repository root",
|
|
@@ -1751,7 +1847,7 @@ async function discoverPythonPackage({
|
|
|
1751
1847
|
if (prefix === "" || prefix === ".") {
|
|
1752
1848
|
break;
|
|
1753
1849
|
}
|
|
1754
|
-
prefix =
|
|
1850
|
+
prefix = import_node_path6.default.dirname(prefix);
|
|
1755
1851
|
}
|
|
1756
1852
|
let entrypointManifest;
|
|
1757
1853
|
let workspaceManifest;
|
|
@@ -1771,8 +1867,8 @@ async function discoverPythonPackage({
|
|
|
1771
1867
|
configs = configs.filter(
|
|
1772
1868
|
(config) => Object.values(config).some(
|
|
1773
1869
|
(cfg) => cfg !== void 0 && isSubpath(
|
|
1774
|
-
|
|
1775
|
-
|
|
1870
|
+
import_node_path6.default.dirname(cfg.path),
|
|
1871
|
+
import_node_path6.default.dirname(entrypointWorkspaceManifest.path)
|
|
1776
1872
|
)
|
|
1777
1873
|
)
|
|
1778
1874
|
);
|
|
@@ -1845,9 +1941,9 @@ function findWorkspaceManifestFor(manifest, manifestStack) {
|
|
|
1845
1941
|
if (!Array.isArray(exclude)) {
|
|
1846
1942
|
exclude = [];
|
|
1847
1943
|
}
|
|
1848
|
-
const entrypointRelPath =
|
|
1849
|
-
|
|
1850
|
-
|
|
1944
|
+
const entrypointRelPath = import_node_path6.default.relative(
|
|
1945
|
+
import_node_path6.default.dirname(parentManifest.path),
|
|
1946
|
+
import_node_path6.default.dirname(manifest.path)
|
|
1851
1947
|
);
|
|
1852
1948
|
if (members.length > 0 && members.some(
|
|
1853
1949
|
(pat) => (0, import_minimatch.match)([entrypointRelPath], pat).length > 0
|
|
@@ -1882,7 +1978,7 @@ async function loadPythonManifest(root, prefix) {
|
|
|
1882
1978
|
"requirements-frozen.txt",
|
|
1883
1979
|
"requirements.txt",
|
|
1884
1980
|
"requirements.in",
|
|
1885
|
-
|
|
1981
|
+
import_node_path6.default.join("requirements", "prod.txt")
|
|
1886
1982
|
]) {
|
|
1887
1983
|
const requirementsTxtManifest = await maybeLoadRequirementsTxt(
|
|
1888
1984
|
root,
|
|
@@ -1901,14 +1997,14 @@ async function loadPythonManifest(root, prefix) {
|
|
|
1901
1997
|
return manifest;
|
|
1902
1998
|
}
|
|
1903
1999
|
async function maybeLoadLockFile(root, subdir) {
|
|
1904
|
-
const uvLockRelPath =
|
|
1905
|
-
const uvLockPath =
|
|
2000
|
+
const uvLockRelPath = import_node_path6.default.join(subdir, "uv.lock");
|
|
2001
|
+
const uvLockPath = import_node_path6.default.join(root, uvLockRelPath);
|
|
1906
2002
|
const uvLockContent = await readFileTextIfExists(uvLockPath);
|
|
1907
2003
|
if (uvLockContent != null) {
|
|
1908
2004
|
return { path: uvLockRelPath, kind: "uv.lock" /* UvLock */ };
|
|
1909
2005
|
}
|
|
1910
|
-
const pylockRelPath =
|
|
1911
|
-
const pylockPath =
|
|
2006
|
+
const pylockRelPath = import_node_path6.default.join(subdir, "pylock.toml");
|
|
2007
|
+
const pylockPath = import_node_path6.default.join(root, pylockRelPath);
|
|
1912
2008
|
const pylockContent = await readFileTextIfExists(pylockPath);
|
|
1913
2009
|
if (pylockContent != null) {
|
|
1914
2010
|
return { path: pylockRelPath, kind: "pylock.toml" /* PylockToml */ };
|
|
@@ -1916,8 +2012,8 @@ async function maybeLoadLockFile(root, subdir) {
|
|
|
1916
2012
|
return void 0;
|
|
1917
2013
|
}
|
|
1918
2014
|
async function maybeLoadPyProjectToml(root, subdir) {
|
|
1919
|
-
const pyprojectTomlRelPath =
|
|
1920
|
-
const pyprojectTomlPath =
|
|
2015
|
+
const pyprojectTomlRelPath = import_node_path6.default.join(subdir, "pyproject.toml");
|
|
2016
|
+
const pyprojectTomlPath = import_node_path6.default.join(root, pyprojectTomlRelPath);
|
|
1921
2017
|
let pyproject;
|
|
1922
2018
|
try {
|
|
1923
2019
|
pyproject = await readConfigIfExists(
|
|
@@ -1938,8 +2034,8 @@ async function maybeLoadPyProjectToml(root, subdir) {
|
|
|
1938
2034
|
if (pyproject == null) {
|
|
1939
2035
|
return null;
|
|
1940
2036
|
}
|
|
1941
|
-
const uvTomlRelPath =
|
|
1942
|
-
const uvTomlPath =
|
|
2037
|
+
const uvTomlRelPath = import_node_path6.default.join(subdir, "uv.toml");
|
|
2038
|
+
const uvTomlPath = import_node_path6.default.join(root, uvTomlRelPath);
|
|
1943
2039
|
let uvToml;
|
|
1944
2040
|
try {
|
|
1945
2041
|
uvToml = await readConfigIfExists(uvTomlPath, UvConfigSchema);
|
|
@@ -1969,8 +2065,8 @@ async function maybeLoadPyProjectToml(root, subdir) {
|
|
|
1969
2065
|
};
|
|
1970
2066
|
}
|
|
1971
2067
|
async function maybeLoadPipfile(root, subdir) {
|
|
1972
|
-
const pipfileRelPath =
|
|
1973
|
-
const pipfilePath =
|
|
2068
|
+
const pipfileRelPath = import_node_path6.default.join(subdir, "Pipfile");
|
|
2069
|
+
const pipfilePath = import_node_path6.default.join(root, pipfileRelPath);
|
|
1974
2070
|
let pipfile;
|
|
1975
2071
|
try {
|
|
1976
2072
|
pipfile = await readConfigIfExists(pipfilePath, PipfileLikeSchema, ".toml");
|
|
@@ -1999,8 +2095,8 @@ async function maybeLoadPipfile(root, subdir) {
|
|
|
1999
2095
|
};
|
|
2000
2096
|
}
|
|
2001
2097
|
async function maybeLoadPipfileLock(root, subdir) {
|
|
2002
|
-
const pipfileLockRelPath =
|
|
2003
|
-
const pipfileLockPath =
|
|
2098
|
+
const pipfileLockRelPath = import_node_path6.default.join(subdir, "Pipfile.lock");
|
|
2099
|
+
const pipfileLockPath = import_node_path6.default.join(root, pipfileLockRelPath);
|
|
2004
2100
|
let pipfileLock;
|
|
2005
2101
|
try {
|
|
2006
2102
|
pipfileLock = await readConfigIfExists(
|
|
@@ -2033,8 +2129,8 @@ async function maybeLoadPipfileLock(root, subdir) {
|
|
|
2033
2129
|
};
|
|
2034
2130
|
}
|
|
2035
2131
|
async function maybeLoadRequirementsTxt(root, subdir, fileName) {
|
|
2036
|
-
const requirementsTxtRelPath =
|
|
2037
|
-
const requirementsTxtPath =
|
|
2132
|
+
const requirementsTxtRelPath = import_node_path6.default.join(subdir, fileName);
|
|
2133
|
+
const requirementsTxtPath = import_node_path6.default.join(root, requirementsTxtRelPath);
|
|
2038
2134
|
const requirementsContent = await readFileTextIfExists(requirementsTxtPath);
|
|
2039
2135
|
if (requirementsContent == null) {
|
|
2040
2136
|
return null;
|
|
@@ -2074,8 +2170,8 @@ async function loadPythonConfigs(root, prefix) {
|
|
|
2074
2170
|
return configs;
|
|
2075
2171
|
}
|
|
2076
2172
|
async function maybeLoadPythonRequest(root, subdir) {
|
|
2077
|
-
const dotPythonVersionRelPath =
|
|
2078
|
-
const dotPythonVersionPath =
|
|
2173
|
+
const dotPythonVersionRelPath = import_node_path6.default.join(subdir, ".python-version");
|
|
2174
|
+
const dotPythonVersionPath = import_node_path6.default.join(
|
|
2079
2175
|
root,
|
|
2080
2176
|
dotPythonVersionRelPath
|
|
2081
2177
|
);
|
|
@@ -2121,6 +2217,95 @@ function createMinimalManifest(options = {}) {
|
|
|
2121
2217
|
};
|
|
2122
2218
|
}
|
|
2123
2219
|
|
|
2220
|
+
// src/manifest/uv-lock-parser.ts
|
|
2221
|
+
var import_smol_toml3 = __toESM(require("smol-toml"), 1);
|
|
2222
|
+
function parseUvLock(content, path4) {
|
|
2223
|
+
let parsed;
|
|
2224
|
+
try {
|
|
2225
|
+
parsed = import_smol_toml3.default.parse(content);
|
|
2226
|
+
} catch (error) {
|
|
2227
|
+
throw new PythonAnalysisError({
|
|
2228
|
+
message: `Could not parse uv.lock: ${error instanceof Error ? error.message : String(error)}`,
|
|
2229
|
+
code: "PYTHON_UV_LOCK_PARSE_ERROR",
|
|
2230
|
+
path: path4,
|
|
2231
|
+
fileContent: content
|
|
2232
|
+
});
|
|
2233
|
+
}
|
|
2234
|
+
const packages = (parsed.package ?? []).filter((pkg) => pkg.name && pkg.version).map((pkg) => ({
|
|
2235
|
+
name: pkg.name,
|
|
2236
|
+
version: pkg.version,
|
|
2237
|
+
source: pkg.source
|
|
2238
|
+
}));
|
|
2239
|
+
return { version: parsed.version, packages };
|
|
2240
|
+
}
|
|
2241
|
+
var PUBLIC_PYPI_PATTERNS = [
|
|
2242
|
+
"https://pypi.org",
|
|
2243
|
+
"https://files.pythonhosted.org",
|
|
2244
|
+
"pypi.org"
|
|
2245
|
+
];
|
|
2246
|
+
function isPublicPyPIRegistry(registryUrl) {
|
|
2247
|
+
if (!registryUrl)
|
|
2248
|
+
return true;
|
|
2249
|
+
const normalized = registryUrl.toLowerCase();
|
|
2250
|
+
return PUBLIC_PYPI_PATTERNS.some((pattern) => normalized.includes(pattern));
|
|
2251
|
+
}
|
|
2252
|
+
function isPrivatePackageSource(source) {
|
|
2253
|
+
if (!source)
|
|
2254
|
+
return false;
|
|
2255
|
+
if (source.git)
|
|
2256
|
+
return true;
|
|
2257
|
+
if (source.path)
|
|
2258
|
+
return true;
|
|
2259
|
+
if (source.editable)
|
|
2260
|
+
return true;
|
|
2261
|
+
if (source.url)
|
|
2262
|
+
return true;
|
|
2263
|
+
if (source.virtual)
|
|
2264
|
+
return true;
|
|
2265
|
+
if (source.registry && !isPublicPyPIRegistry(source.registry)) {
|
|
2266
|
+
return true;
|
|
2267
|
+
}
|
|
2268
|
+
return false;
|
|
2269
|
+
}
|
|
2270
|
+
function normalizePackageName(name) {
|
|
2271
|
+
return name.toLowerCase().replace(/[-_.]+/g, "-");
|
|
2272
|
+
}
|
|
2273
|
+
function classifyPackages(options) {
|
|
2274
|
+
const { lockFile, excludePackages = [] } = options;
|
|
2275
|
+
const privatePackages = [];
|
|
2276
|
+
const publicPackages = [];
|
|
2277
|
+
const packageVersions = {};
|
|
2278
|
+
const excludeSet = new Set(excludePackages.map(normalizePackageName));
|
|
2279
|
+
for (const pkg of lockFile.packages) {
|
|
2280
|
+
if (excludeSet.has(normalizePackageName(pkg.name))) {
|
|
2281
|
+
continue;
|
|
2282
|
+
}
|
|
2283
|
+
packageVersions[pkg.name] = pkg.version;
|
|
2284
|
+
if (isPrivatePackageSource(pkg.source)) {
|
|
2285
|
+
privatePackages.push(pkg.name);
|
|
2286
|
+
} else {
|
|
2287
|
+
publicPackages.push(pkg.name);
|
|
2288
|
+
}
|
|
2289
|
+
}
|
|
2290
|
+
return { privatePackages, publicPackages, packageVersions };
|
|
2291
|
+
}
|
|
2292
|
+
function generateRuntimeRequirements(classification) {
|
|
2293
|
+
const lines = [
|
|
2294
|
+
"# Auto-generated requirements for runtime installation",
|
|
2295
|
+
"# Private packages are bundled separately and not listed here.",
|
|
2296
|
+
""
|
|
2297
|
+
];
|
|
2298
|
+
for (const pkgName of classification.publicPackages) {
|
|
2299
|
+
const version = classification.packageVersions[pkgName];
|
|
2300
|
+
if (version) {
|
|
2301
|
+
lines.push(`${pkgName}==${version}`);
|
|
2302
|
+
} else {
|
|
2303
|
+
lines.push(pkgName);
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
2306
|
+
return lines.join("\n");
|
|
2307
|
+
}
|
|
2308
|
+
|
|
2124
2309
|
// src/manifest/python-selector.ts
|
|
2125
2310
|
function selectPython(constraints, available) {
|
|
2126
2311
|
const warnings = [];
|
|
@@ -2304,9 +2489,15 @@ var HashDigestSchema = hashDigestSchema;
|
|
|
2304
2489
|
UvConfigSchema,
|
|
2305
2490
|
UvConfigWorkspaceSchema,
|
|
2306
2491
|
UvIndexEntrySchema,
|
|
2492
|
+
classifyPackages,
|
|
2307
2493
|
containsAppOrHandler,
|
|
2308
2494
|
createMinimalManifest,
|
|
2309
2495
|
discoverPythonPackage,
|
|
2496
|
+
generateRuntimeRequirements,
|
|
2497
|
+
isPrivatePackageSource,
|
|
2498
|
+
normalizePackageName,
|
|
2499
|
+
parseUvLock,
|
|
2500
|
+
scanDistributions,
|
|
2310
2501
|
selectPython,
|
|
2311
2502
|
stringifyManifest
|
|
2312
2503
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -7,9 +7,13 @@
|
|
|
7
7
|
* @module @vercel/python-analysis
|
|
8
8
|
*/
|
|
9
9
|
export { containsAppOrHandler } from './semantic/entrypoints';
|
|
10
|
+
export type { Distribution, DistributionIndex, PackagePath, DirectUrlInfo, } from './manifest/dist-metadata';
|
|
11
|
+
export { scanDistributions } from './manifest/dist-metadata';
|
|
10
12
|
export type { PythonConfig, PythonConfigs, PythonLockFile, PythonManifest, PythonManifestOrigin, PythonPackage, PythonVersionConfig, } from './manifest/package';
|
|
11
13
|
export { discoverPythonPackage, PythonConfigKind, PythonLockFileKind, PythonManifestConvertedKind, PythonManifestKind, } from './manifest/package';
|
|
12
14
|
export { createMinimalManifest, stringifyManifest, type CreateMinimalManifestOptions, } from './manifest/serialize';
|
|
15
|
+
export type { ClassifyPackagesOptions, PackageClassification, UvLockFile, UvLockPackage, UvLockPackageSource, } from './manifest/uv-lock-parser';
|
|
16
|
+
export { classifyPackages, generateRuntimeRequirements, isPrivatePackageSource, normalizePackageName, parseUvLock, } from './manifest/uv-lock-parser';
|
|
13
17
|
export type { PythonSelectionResult } from './manifest/python-selector';
|
|
14
18
|
export { selectPython } from './manifest/python-selector';
|
|
15
19
|
export { PythonAnalysisError } from './util/error';
|