@vercel/python-analysis 0.3.0 → 0.3.1

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 ADDED
@@ -0,0 +1,1999 @@
1
+ var __import_meta_url__ = require("url").pathToFileURL(__filename).href;
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // src/index.ts
32
+ var src_exports = {};
33
+ __export(src_exports, {
34
+ DependencySourceSchema: () => DependencySourceSchema,
35
+ HashDigestSchema: () => HashDigestSchema,
36
+ LicenseObjectSchema: () => LicenseObjectSchema,
37
+ LicenseSchema: () => LicenseSchema,
38
+ NormalizedRequirementSchema: () => NormalizedRequirementSchema,
39
+ PersonSchema: () => PersonSchema,
40
+ PipfileDependencyDetailSchema: () => PipfileDependencyDetailSchema,
41
+ PipfileDependencySchema: () => PipfileDependencySchema,
42
+ PipfileLikeSchema: () => PipfileLikeSchema,
43
+ PipfileLockLikeSchema: () => PipfileLockLikeSchema,
44
+ PipfileLockMetaSchema: () => PipfileLockMetaSchema,
45
+ PipfileSourceSchema: () => PipfileSourceSchema,
46
+ PyProjectBuildSystemSchema: () => PyProjectBuildSystemSchema,
47
+ PyProjectDependencyGroupsSchema: () => PyProjectDependencyGroupsSchema,
48
+ PyProjectProjectSchema: () => PyProjectProjectSchema,
49
+ PyProjectTomlSchema: () => PyProjectTomlSchema,
50
+ PyProjectToolSectionSchema: () => PyProjectToolSectionSchema,
51
+ PythonAnalysisError: () => PythonAnalysisError,
52
+ PythonBuild: () => PythonBuild,
53
+ PythonConfigKind: () => PythonConfigKind,
54
+ PythonImplementation: () => PythonImplementation,
55
+ PythonManifestConvertedKind: () => PythonManifestConvertedKind,
56
+ PythonManifestKind: () => PythonManifestKind,
57
+ PythonVariant: () => PythonVariant,
58
+ PythonVersion: () => PythonVersion,
59
+ ReadmeObjectSchema: () => ReadmeObjectSchema,
60
+ ReadmeSchema: () => ReadmeSchema,
61
+ UvConfigSchema: () => UvConfigSchema,
62
+ UvConfigWorkspaceSchema: () => UvConfigWorkspaceSchema,
63
+ UvIndexEntrySchema: () => UvIndexEntrySchema,
64
+ containsAppOrHandler: () => containsAppOrHandler,
65
+ discoverPythonPackage: () => discoverPythonPackage,
66
+ selectPython: () => selectPython
67
+ });
68
+ module.exports = __toCommonJS(src_exports);
69
+
70
+ // src/semantic/load.ts
71
+ var import_promises = require("fs/promises");
72
+ var import_node_module = require("module");
73
+ var import_node_path = require("path");
74
+ var WASI_SHIM_PATH = "@bytecodealliance/preview2-shim/instantiation";
75
+ var WASM_MODULE_PATH = "#wasm/vercel_python_analysis.js";
76
+ var wasmInstance = null;
77
+ var wasmLoadPromise = null;
78
+ var wasmDir = null;
79
+ function getWasmDir() {
80
+ if (wasmDir === null) {
81
+ const require2 = (0, import_node_module.createRequire)(__import_meta_url__);
82
+ const wasmModulePath = require2.resolve(WASM_MODULE_PATH);
83
+ wasmDir = (0, import_node_path.dirname)(wasmModulePath);
84
+ }
85
+ return wasmDir;
86
+ }
87
+ async function getCoreModule(path4) {
88
+ const wasmPath = (0, import_node_path.join)(getWasmDir(), path4);
89
+ const wasmBytes = await (0, import_promises.readFile)(wasmPath);
90
+ return WebAssembly.compile(wasmBytes);
91
+ }
92
+ async function importWasmModule() {
93
+ if (wasmInstance) {
94
+ return wasmInstance;
95
+ }
96
+ if (!wasmLoadPromise) {
97
+ wasmLoadPromise = (async () => {
98
+ const wasiShimModule = await import(WASI_SHIM_PATH);
99
+ const WASIShim = wasiShimModule.WASIShim;
100
+ const wasmModule = await import(WASM_MODULE_PATH);
101
+ const imports = new WASIShim().getImportObject();
102
+ const instance = await wasmModule.instantiate(getCoreModule, imports);
103
+ wasmInstance = instance;
104
+ return instance;
105
+ })();
106
+ }
107
+ return wasmLoadPromise;
108
+ }
109
+
110
+ // src/semantic/entrypoints.ts
111
+ async function containsAppOrHandler(source) {
112
+ if (!source.includes("app") && !source.includes("handler") && !source.includes("Handler")) {
113
+ return false;
114
+ }
115
+ const mod = await importWasmModule();
116
+ return mod.containsAppOrHandler(source);
117
+ }
118
+
119
+ // src/manifest/package.ts
120
+ var import_node_path5 = __toESM(require("path"), 1);
121
+ var import_minimatch = require("minimatch");
122
+
123
+ // src/util/config.ts
124
+ var import_node_path3 = __toESM(require("path"), 1);
125
+ var import_js_yaml = __toESM(require("js-yaml"), 1);
126
+ var import_smol_toml = __toESM(require("smol-toml"), 1);
127
+
128
+ // src/util/fs.ts
129
+ var import_node_path2 = __toESM(require("path"), 1);
130
+ var import_fs_extra = require("fs-extra");
131
+
132
+ // src/util/error.ts
133
+ var import_node_util = __toESM(require("util"), 1);
134
+ var isErrnoException = (error, code = void 0) => {
135
+ return import_node_util.default.types.isNativeError(error) && "code" in error && (code === void 0 || error.code === code);
136
+ };
137
+ var PythonAnalysisError = class extends Error {
138
+ constructor({ message, code, path: path4, link, action }) {
139
+ super(message);
140
+ this.hideStackTrace = true;
141
+ this.name = "PythonAnalysisError";
142
+ this.code = code;
143
+ this.path = path4;
144
+ this.link = link;
145
+ this.action = action;
146
+ }
147
+ };
148
+
149
+ // src/util/fs.ts
150
+ async function readFileIfExists(file) {
151
+ try {
152
+ return await (0, import_fs_extra.readFile)(file);
153
+ } catch (error) {
154
+ if (!isErrnoException(error, "ENOENT")) {
155
+ throw error;
156
+ }
157
+ }
158
+ return null;
159
+ }
160
+ async function readFileTextIfExists(file, encoding = "utf8") {
161
+ const data = await readFileIfExists(file);
162
+ if (data == null) {
163
+ return null;
164
+ } else {
165
+ return data.toString(encoding);
166
+ }
167
+ }
168
+ function normalizePath(p) {
169
+ let np = import_node_path2.default.normalize(p);
170
+ if (np.endsWith(import_node_path2.default.sep)) {
171
+ np = np.slice(0, -1);
172
+ }
173
+ return np;
174
+ }
175
+ function isSubpath(somePath, parentPath) {
176
+ const rel = import_node_path2.default.relative(parentPath, somePath);
177
+ return rel === "" || !rel.startsWith("..") && !import_node_path2.default.isAbsolute(rel);
178
+ }
179
+
180
+ // src/util/config.ts
181
+ function parseRawConfig(content, filename, filetype = void 0) {
182
+ if (filetype === void 0) {
183
+ filetype = import_node_path3.default.extname(filename.toLowerCase());
184
+ }
185
+ try {
186
+ if (filetype === ".json") {
187
+ return JSON.parse(content);
188
+ } else if (filetype === ".toml") {
189
+ return import_smol_toml.default.parse(content);
190
+ } else if (filetype === ".yaml" || filetype === ".yml") {
191
+ return import_js_yaml.default.load(content, { filename });
192
+ } else {
193
+ throw new PythonAnalysisError({
194
+ message: `Could not parse config file "${filename}": unrecognized config format`,
195
+ code: "PYTHON_CONFIG_UNKNOWN_FORMAT",
196
+ path: filename
197
+ });
198
+ }
199
+ } catch (error) {
200
+ if (error instanceof PythonAnalysisError) {
201
+ throw error;
202
+ }
203
+ if (error instanceof Error) {
204
+ throw new PythonAnalysisError({
205
+ message: `Could not parse config file "${filename}": ${error.message}`,
206
+ code: "PYTHON_CONFIG_PARSE_ERROR",
207
+ path: filename
208
+ });
209
+ }
210
+ throw error;
211
+ }
212
+ }
213
+ function parseConfig(content, filename, schema, filetype = void 0) {
214
+ const raw = parseRawConfig(content, filename, filetype);
215
+ const result = schema.safeParse(raw);
216
+ if (!result.success) {
217
+ const issues = result.error.issues.map((issue) => {
218
+ const path4 = issue.path.length > 0 ? issue.path.join(".") : "(root)";
219
+ return ` - ${path4}: ${issue.message}`;
220
+ }).join("\n");
221
+ throw new PythonAnalysisError({
222
+ message: `Invalid config in "${filename}":
223
+ ${issues}`,
224
+ code: "PYTHON_CONFIG_VALIDATION_ERROR",
225
+ path: filename
226
+ });
227
+ }
228
+ return result.data;
229
+ }
230
+ async function readConfigIfExists(filename, schema, filetype = void 0) {
231
+ const content = await readFileTextIfExists(filename);
232
+ if (content == null) {
233
+ return null;
234
+ }
235
+ return parseConfig(content, filename, schema, filetype);
236
+ }
237
+
238
+ // src/manifest/pep440.ts
239
+ var import_node_assert = __toESM(require("assert"), 1);
240
+ var import_version = require("@renovatebot/pep440/lib/version");
241
+ var import_pep440 = require("@renovatebot/pep440");
242
+ var import_specifier = require("@renovatebot/pep440/lib/specifier");
243
+ function pep440ConstraintFromVersion(v) {
244
+ return [
245
+ {
246
+ operator: "==",
247
+ version: unparsePep440Version(v),
248
+ prefix: ""
249
+ }
250
+ ];
251
+ }
252
+ function unparsePep440Version(v) {
253
+ const verstr = (0, import_version.stringify)(v);
254
+ (0, import_node_assert.default)(verstr != null, "pep440/lib/version:stringify returned null");
255
+ return verstr;
256
+ }
257
+
258
+ // src/manifest/pipfile/schema.zod.ts
259
+ var import_zod = require("zod");
260
+ var pipfileDependencyDetailSchema = import_zod.z.object({
261
+ version: import_zod.z.string().optional(),
262
+ hashes: import_zod.z.array(import_zod.z.string()).optional(),
263
+ extras: import_zod.z.union([import_zod.z.array(import_zod.z.string()), import_zod.z.string()]).optional(),
264
+ markers: import_zod.z.string().optional(),
265
+ index: import_zod.z.string().optional(),
266
+ git: import_zod.z.string().optional(),
267
+ ref: import_zod.z.string().optional(),
268
+ editable: import_zod.z.boolean().optional(),
269
+ path: import_zod.z.string().optional()
270
+ });
271
+ var pipfileDependencySchema = import_zod.z.union([
272
+ import_zod.z.string(),
273
+ pipfileDependencyDetailSchema
274
+ ]);
275
+ var pipfileSourceSchema = import_zod.z.object({
276
+ name: import_zod.z.string(),
277
+ url: import_zod.z.string(),
278
+ verify_ssl: import_zod.z.boolean().optional()
279
+ });
280
+ var pipfileLikeSchema = import_zod.z.record(
281
+ import_zod.z.union([
282
+ import_zod.z.record(pipfileDependencySchema),
283
+ import_zod.z.array(pipfileSourceSchema),
284
+ import_zod.z.record(import_zod.z.string()),
285
+ import_zod.z.undefined()
286
+ ])
287
+ ).and(
288
+ import_zod.z.object({
289
+ packages: import_zod.z.record(pipfileDependencySchema).optional(),
290
+ "dev-packages": import_zod.z.record(pipfileDependencySchema).optional(),
291
+ source: import_zod.z.array(pipfileSourceSchema).optional(),
292
+ scripts: import_zod.z.record(import_zod.z.string()).optional()
293
+ })
294
+ );
295
+ var pipfileLockMetaSchema = import_zod.z.object({
296
+ hash: import_zod.z.object({
297
+ sha256: import_zod.z.string().optional()
298
+ }).optional(),
299
+ "pipfile-spec": import_zod.z.number().optional(),
300
+ requires: import_zod.z.object({
301
+ python_version: import_zod.z.string().optional(),
302
+ python_full_version: import_zod.z.string().optional()
303
+ }).optional(),
304
+ sources: import_zod.z.array(pipfileSourceSchema).optional()
305
+ });
306
+ var pipfileLockLikeSchema = import_zod.z.record(
307
+ import_zod.z.union([
308
+ pipfileLockMetaSchema,
309
+ import_zod.z.record(pipfileDependencyDetailSchema),
310
+ import_zod.z.undefined()
311
+ ])
312
+ ).and(
313
+ import_zod.z.object({
314
+ _meta: pipfileLockMetaSchema.optional(),
315
+ default: import_zod.z.record(pipfileDependencyDetailSchema).optional(),
316
+ develop: import_zod.z.record(pipfileDependencyDetailSchema).optional()
317
+ })
318
+ );
319
+
320
+ // src/manifest/pipfile/schema.ts
321
+ var PipfileDependencyDetailSchema = pipfileDependencyDetailSchema.passthrough();
322
+ var PipfileDependencySchema = pipfileDependencySchema;
323
+ var PipfileSourceSchema = pipfileSourceSchema.passthrough();
324
+ var PipfileLikeSchema = pipfileLikeSchema;
325
+ var PipfileLockMetaSchema = pipfileLockMetaSchema.passthrough();
326
+ var PipfileLockLikeSchema = pipfileLockLikeSchema;
327
+
328
+ // src/manifest/pep508.ts
329
+ var EXTRAS_REGEX = /^(.+)\[([^\]]+)\]$/;
330
+ function splitExtras(spec) {
331
+ const match = EXTRAS_REGEX.exec(spec);
332
+ if (!match) {
333
+ return [spec, void 0];
334
+ }
335
+ const extras = match[2].split(",").map((e) => e.trim());
336
+ return [match[1], extras];
337
+ }
338
+ function formatPep508(req) {
339
+ let result = req.name;
340
+ if (req.extras && req.extras.length > 0) {
341
+ result += `[${req.extras.join(",")}]`;
342
+ }
343
+ if (req.url) {
344
+ result += ` @ ${req.url}`;
345
+ } else if (req.version && req.version !== "*") {
346
+ result += req.version;
347
+ }
348
+ if (req.markers) {
349
+ result += ` ; ${req.markers}`;
350
+ }
351
+ return result;
352
+ }
353
+ function mergeExtras(existing, additional) {
354
+ const result = new Set(existing || []);
355
+ if (additional) {
356
+ const additionalArray = Array.isArray(additional) ? additional : [additional];
357
+ for (const extra of additionalArray) {
358
+ result.add(extra);
359
+ }
360
+ }
361
+ return result.size > 0 ? Array.from(result) : void 0;
362
+ }
363
+
364
+ // src/util/type.ts
365
+ function isPlainObject(value) {
366
+ return value != null && typeof value === "object" && !Array.isArray(value);
367
+ }
368
+
369
+ // src/manifest/pipfile-parser.ts
370
+ var PYPI_INDEX_NAME = "pypi";
371
+ function addDepSource(sources, dep) {
372
+ if (!dep.source) {
373
+ return;
374
+ }
375
+ if (Object.prototype.hasOwnProperty.call(sources, dep.name)) {
376
+ sources[dep.name].push(dep.source);
377
+ } else {
378
+ sources[dep.name] = [dep.source];
379
+ }
380
+ }
381
+ function isPypiSource(source) {
382
+ return typeof source?.name === "string" && source.name === PYPI_INDEX_NAME;
383
+ }
384
+ function processIndexSources(sources) {
385
+ const hasPypi = sources.some(isPypiSource);
386
+ const setExplicit = sources.length > 1 && hasPypi;
387
+ const indexes = [];
388
+ for (const source of sources) {
389
+ if (isPypiSource(source)) {
390
+ continue;
391
+ }
392
+ const entry = {
393
+ name: source.name,
394
+ url: source.url
395
+ };
396
+ if (setExplicit) {
397
+ entry.explicit = true;
398
+ }
399
+ indexes.push(entry);
400
+ }
401
+ return indexes;
402
+ }
403
+ function buildUvToolSection(sources, indexes) {
404
+ const uv = {};
405
+ if (indexes.length > 0) {
406
+ uv.index = indexes;
407
+ }
408
+ if (Object.keys(sources).length > 0) {
409
+ uv.sources = sources;
410
+ }
411
+ return Object.keys(uv).length > 0 ? uv : null;
412
+ }
413
+ function pipfileDepsToRequirements(entries) {
414
+ const deps = [];
415
+ for (const [name, properties] of Object.entries(entries)) {
416
+ const dep = pipfileDepToRequirement(name, properties);
417
+ deps.push(dep);
418
+ }
419
+ return deps;
420
+ }
421
+ function pipfileDepToRequirement(spec, properties) {
422
+ const [name, extrasFromName] = splitExtras(spec);
423
+ const dep = { name };
424
+ if (extrasFromName && extrasFromName.length > 0) {
425
+ dep.extras = extrasFromName;
426
+ }
427
+ if (typeof properties === "string") {
428
+ dep.version = properties;
429
+ } else if (properties && typeof properties === "object") {
430
+ if (properties.version) {
431
+ dep.version = properties.version;
432
+ }
433
+ if (properties.extras) {
434
+ dep.extras = mergeExtras(dep.extras, properties.extras);
435
+ }
436
+ if (properties.markers) {
437
+ dep.markers = properties.markers;
438
+ }
439
+ const source = buildDependencySource(properties);
440
+ if (source) {
441
+ dep.source = source;
442
+ }
443
+ }
444
+ return dep;
445
+ }
446
+ function pipfileLockDepsToRequirements(entries) {
447
+ const deps = [];
448
+ for (const [name, properties] of Object.entries(entries)) {
449
+ const dep = pipfileLockDepToRequirement(name, properties);
450
+ deps.push(dep);
451
+ }
452
+ return deps;
453
+ }
454
+ function pipfileLockDepToRequirement(spec, properties) {
455
+ const [name, extrasFromName] = splitExtras(spec);
456
+ const dep = { name };
457
+ if (extrasFromName && extrasFromName.length > 0) {
458
+ dep.extras = extrasFromName;
459
+ }
460
+ if (properties.version) {
461
+ dep.version = properties.version;
462
+ }
463
+ if (properties.extras) {
464
+ dep.extras = mergeExtras(dep.extras, properties.extras);
465
+ }
466
+ if (properties.markers) {
467
+ dep.markers = properties.markers;
468
+ }
469
+ const source = buildDependencySource(properties);
470
+ if (source) {
471
+ dep.source = source;
472
+ }
473
+ return dep;
474
+ }
475
+ function buildDependencySource(properties) {
476
+ const source = {};
477
+ if (properties.index && properties.index !== PYPI_INDEX_NAME) {
478
+ source.index = properties.index;
479
+ }
480
+ if (properties.git) {
481
+ source.git = properties.git;
482
+ if (properties.ref) {
483
+ source.rev = properties.ref;
484
+ }
485
+ }
486
+ if (properties.path) {
487
+ source.path = properties.path;
488
+ if (properties.editable) {
489
+ source.editable = true;
490
+ }
491
+ }
492
+ return Object.keys(source).length > 0 ? source : null;
493
+ }
494
+ function convertPipfileToPyprojectToml(pipfile) {
495
+ const sources = {};
496
+ const pyproject = {};
497
+ const deps = [];
498
+ for (const dep of pipfileDepsToRequirements(pipfile.packages || {})) {
499
+ deps.push(formatPep508(dep));
500
+ addDepSource(sources, dep);
501
+ }
502
+ if (deps.length > 0) {
503
+ pyproject.project = {
504
+ dependencies: deps
505
+ };
506
+ }
507
+ const devDeps = [];
508
+ for (const dep of pipfileDepsToRequirements(pipfile["dev-packages"] || {})) {
509
+ devDeps.push(formatPep508(dep));
510
+ addDepSource(sources, dep);
511
+ }
512
+ if (devDeps.length > 0) {
513
+ pyproject["dependency-groups"] = {
514
+ dev: devDeps
515
+ };
516
+ }
517
+ const RESERVED_KEYS = /* @__PURE__ */ new Set([
518
+ "packages",
519
+ "dev-packages",
520
+ "source",
521
+ "scripts",
522
+ "requires",
523
+ "pipenv"
524
+ ]);
525
+ for (const [sectionName, value] of Object.entries(pipfile)) {
526
+ if (RESERVED_KEYS.has(sectionName))
527
+ continue;
528
+ if (!isPlainObject(value))
529
+ continue;
530
+ const groupDeps = [];
531
+ for (const dep of pipfileDepsToRequirements(
532
+ value
533
+ )) {
534
+ groupDeps.push(formatPep508(dep));
535
+ addDepSource(sources, dep);
536
+ }
537
+ if (groupDeps.length > 0) {
538
+ pyproject["dependency-groups"] = {
539
+ ...pyproject["dependency-groups"] || {},
540
+ [sectionName]: groupDeps
541
+ };
542
+ }
543
+ }
544
+ const indexes = processIndexSources(pipfile.source ?? []);
545
+ const uv = buildUvToolSection(sources, indexes);
546
+ if (uv) {
547
+ pyproject.tool = { uv };
548
+ }
549
+ return pyproject;
550
+ }
551
+ function convertPipfileLockToPyprojectToml(pipfileLock) {
552
+ const sources = {};
553
+ const pyproject = {};
554
+ const deps = [];
555
+ for (const dep of pipfileLockDepsToRequirements(pipfileLock.default || {})) {
556
+ deps.push(formatPep508(dep));
557
+ addDepSource(sources, dep);
558
+ }
559
+ if (deps.length > 0) {
560
+ pyproject.project = {
561
+ dependencies: deps
562
+ };
563
+ }
564
+ const devDeps = [];
565
+ for (const dep of pipfileLockDepsToRequirements(pipfileLock.develop || {})) {
566
+ devDeps.push(formatPep508(dep));
567
+ addDepSource(sources, dep);
568
+ }
569
+ if (devDeps.length > 0) {
570
+ pyproject["dependency-groups"] = {
571
+ dev: devDeps
572
+ };
573
+ }
574
+ const RESERVED_KEYS = /* @__PURE__ */ new Set(["_meta", "default", "develop"]);
575
+ for (const [sectionName, value] of Object.entries(pipfileLock)) {
576
+ if (RESERVED_KEYS.has(sectionName))
577
+ continue;
578
+ if (!isPlainObject(value))
579
+ continue;
580
+ const groupDeps = [];
581
+ for (const dep of pipfileLockDepsToRequirements(
582
+ value
583
+ )) {
584
+ groupDeps.push(formatPep508(dep));
585
+ addDepSource(sources, dep);
586
+ }
587
+ if (groupDeps.length > 0) {
588
+ pyproject["dependency-groups"] = {
589
+ ...pyproject["dependency-groups"] || {},
590
+ [sectionName]: groupDeps
591
+ };
592
+ }
593
+ }
594
+ const indexes = processIndexSources(pipfileLock._meta?.sources ?? []);
595
+ const uv = buildUvToolSection(sources, indexes);
596
+ if (uv) {
597
+ pyproject.tool = { uv };
598
+ }
599
+ return pyproject;
600
+ }
601
+
602
+ // src/manifest/pyproject/schema.zod.ts
603
+ var import_zod4 = require("zod");
604
+
605
+ // src/manifest/uv-config/schema.zod.ts
606
+ var import_zod3 = require("zod");
607
+
608
+ // src/manifest/requirement/schema.zod.ts
609
+ var import_zod2 = require("zod");
610
+ var dependencySourceSchema = import_zod2.z.object({
611
+ index: import_zod2.z.string().optional(),
612
+ git: import_zod2.z.string().optional(),
613
+ rev: import_zod2.z.string().optional(),
614
+ path: import_zod2.z.string().optional(),
615
+ editable: import_zod2.z.boolean().optional()
616
+ });
617
+ var normalizedRequirementSchema = import_zod2.z.object({
618
+ name: import_zod2.z.string(),
619
+ version: import_zod2.z.string().optional(),
620
+ extras: import_zod2.z.array(import_zod2.z.string()).optional(),
621
+ markers: import_zod2.z.string().optional(),
622
+ url: import_zod2.z.string().optional(),
623
+ hashes: import_zod2.z.array(import_zod2.z.string()).optional(),
624
+ source: dependencySourceSchema.optional()
625
+ });
626
+ var hashDigestSchema = import_zod2.z.string();
627
+
628
+ // src/manifest/uv-config/schema.zod.ts
629
+ var uvConfigWorkspaceSchema = import_zod3.z.object({
630
+ members: import_zod3.z.array(import_zod3.z.string()).optional(),
631
+ exclude: import_zod3.z.array(import_zod3.z.string()).optional()
632
+ });
633
+ var uvIndexEntrySchema = import_zod3.z.object({
634
+ name: import_zod3.z.string(),
635
+ url: import_zod3.z.string(),
636
+ default: import_zod3.z.boolean().optional(),
637
+ explicit: import_zod3.z.boolean().optional()
638
+ });
639
+ var uvConfigSchema = import_zod3.z.object({
640
+ sources: import_zod3.z.record(import_zod3.z.union([dependencySourceSchema, import_zod3.z.array(dependencySourceSchema)])).optional(),
641
+ index: import_zod3.z.array(uvIndexEntrySchema).optional(),
642
+ workspace: uvConfigWorkspaceSchema.optional()
643
+ });
644
+
645
+ // src/manifest/pyproject/schema.zod.ts
646
+ var pyProjectBuildSystemSchema = import_zod4.z.object({
647
+ requires: import_zod4.z.array(import_zod4.z.string()),
648
+ "build-backend": import_zod4.z.string().optional(),
649
+ "backend-path": import_zod4.z.array(import_zod4.z.string()).optional()
650
+ });
651
+ var personSchema = import_zod4.z.object({
652
+ name: import_zod4.z.string().optional(),
653
+ email: import_zod4.z.string().optional()
654
+ });
655
+ var readmeObjectSchema = import_zod4.z.object({
656
+ file: import_zod4.z.union([import_zod4.z.string(), import_zod4.z.array(import_zod4.z.string())]),
657
+ content_type: import_zod4.z.string().optional()
658
+ });
659
+ var readmeSchema = import_zod4.z.union([import_zod4.z.string(), readmeObjectSchema]);
660
+ var licenseObjectSchema = import_zod4.z.object({
661
+ text: import_zod4.z.string().optional(),
662
+ file: import_zod4.z.string().optional()
663
+ });
664
+ var licenseSchema = import_zod4.z.union([import_zod4.z.string(), licenseObjectSchema]);
665
+ var pyProjectProjectSchema = import_zod4.z.object({
666
+ name: import_zod4.z.string().optional(),
667
+ version: import_zod4.z.string().optional(),
668
+ description: import_zod4.z.string().optional(),
669
+ readme: readmeSchema.optional(),
670
+ keywords: import_zod4.z.array(import_zod4.z.string()).optional(),
671
+ authors: import_zod4.z.array(personSchema).optional(),
672
+ maintainers: import_zod4.z.array(personSchema).optional(),
673
+ license: licenseSchema.optional(),
674
+ classifiers: import_zod4.z.array(import_zod4.z.string()).optional(),
675
+ urls: import_zod4.z.record(import_zod4.z.string()).optional(),
676
+ dependencies: import_zod4.z.array(import_zod4.z.string()).optional(),
677
+ "optional-dependencies": import_zod4.z.record(import_zod4.z.array(import_zod4.z.string())).optional(),
678
+ dynamic: import_zod4.z.array(import_zod4.z.string()).optional(),
679
+ "requires-python": import_zod4.z.string().optional(),
680
+ scripts: import_zod4.z.record(import_zod4.z.string()).optional(),
681
+ entry_points: import_zod4.z.record(import_zod4.z.record(import_zod4.z.string())).optional()
682
+ });
683
+ var pyProjectDependencyGroupsSchema = import_zod4.z.record(import_zod4.z.array(import_zod4.z.string()));
684
+ var pyProjectToolSectionSchema = import_zod4.z.object({
685
+ uv: uvConfigSchema.optional()
686
+ });
687
+ var pyProjectTomlSchema = import_zod4.z.object({
688
+ project: pyProjectProjectSchema.optional(),
689
+ "build-system": pyProjectBuildSystemSchema.optional(),
690
+ "dependency-groups": pyProjectDependencyGroupsSchema.optional(),
691
+ tool: pyProjectToolSectionSchema.optional()
692
+ });
693
+
694
+ // src/manifest/pyproject/schema.ts
695
+ var PyProjectBuildSystemSchema = pyProjectBuildSystemSchema.passthrough();
696
+ var PersonSchema = personSchema.passthrough();
697
+ var ReadmeObjectSchema = readmeObjectSchema.passthrough();
698
+ var ReadmeSchema = readmeSchema;
699
+ var LicenseObjectSchema = licenseObjectSchema.passthrough();
700
+ var LicenseSchema = licenseSchema;
701
+ var PyProjectProjectSchema = pyProjectProjectSchema.passthrough();
702
+ var PyProjectDependencyGroupsSchema = pyProjectDependencyGroupsSchema;
703
+ var PyProjectToolSectionSchema = pyProjectToolSectionSchema.passthrough();
704
+ var PyProjectTomlSchema = pyProjectTomlSchema.passthrough();
705
+
706
+ // src/manifest/requirements-txt-parser.ts
707
+ var import_node_path4 = require("path");
708
+ var import_pip_requirements_js = require("pip-requirements-js");
709
+ var PRIMARY_INDEX_NAME = "primary";
710
+ var EXTRA_INDEX_PREFIX = "extra-";
711
+ function parseGitUrl(url) {
712
+ if (!url.startsWith("git+")) {
713
+ return null;
714
+ }
715
+ let remaining = url.slice(4);
716
+ let egg;
717
+ const fragmentIdx = remaining.indexOf("#");
718
+ if (fragmentIdx !== -1) {
719
+ const fragment = remaining.slice(fragmentIdx + 1);
720
+ remaining = remaining.slice(0, fragmentIdx);
721
+ for (const part of fragment.split("&")) {
722
+ const [key, value] = part.split("=");
723
+ if (key === "egg" && value) {
724
+ egg = value;
725
+ }
726
+ }
727
+ }
728
+ let ref;
729
+ const lastSlashIdx = remaining.lastIndexOf("/");
730
+ const atIdx = remaining.indexOf("@", lastSlashIdx > 0 ? lastSlashIdx : 0);
731
+ if (atIdx !== -1 && atIdx > remaining.indexOf("://")) {
732
+ ref = remaining.slice(atIdx + 1);
733
+ remaining = remaining.slice(0, atIdx);
734
+ }
735
+ return {
736
+ url: remaining,
737
+ ref,
738
+ egg
739
+ };
740
+ }
741
+ function isGitUrl(url) {
742
+ return url.startsWith("git+");
743
+ }
744
+ function extractPipArguments(fileContent) {
745
+ const options = {
746
+ requirementFiles: [],
747
+ constraintFiles: [],
748
+ extraIndexUrls: []
749
+ };
750
+ const lines = fileContent.split(/\r?\n/);
751
+ const cleanedLines = [];
752
+ for (let i = 0; i < lines.length; i++) {
753
+ const line = lines[i];
754
+ const trimmed = line.trim();
755
+ if (trimmed === "" || trimmed.startsWith("#")) {
756
+ cleanedLines.push(line);
757
+ continue;
758
+ }
759
+ let fullLine = trimmed;
760
+ let linesConsumed = 0;
761
+ while (fullLine.endsWith("\\") && i + linesConsumed + 1 < lines.length) {
762
+ linesConsumed++;
763
+ fullLine = fullLine.slice(0, -1) + lines[i + linesConsumed].trim();
764
+ }
765
+ const extracted = tryExtractPipArgument(fullLine, options);
766
+ if (extracted) {
767
+ i += linesConsumed;
768
+ } else {
769
+ const strippedLine = stripInlineHashes(fullLine);
770
+ if (strippedLine !== fullLine) {
771
+ cleanedLines.push(strippedLine);
772
+ } else {
773
+ cleanedLines.push(line);
774
+ for (let j = 1; j <= linesConsumed; j++) {
775
+ cleanedLines.push(lines[i + j]);
776
+ }
777
+ }
778
+ i += linesConsumed;
779
+ }
780
+ }
781
+ return {
782
+ cleanedContent: cleanedLines.join("\n"),
783
+ options
784
+ };
785
+ }
786
+ function tryExtractPipArgument(line, options) {
787
+ if (line.startsWith("--requirement")) {
788
+ const path4 = extractArgValue(line, "--requirement");
789
+ if (path4) {
790
+ options.requirementFiles.push(path4);
791
+ return true;
792
+ }
793
+ }
794
+ if (line.startsWith("--constraint")) {
795
+ const path4 = extractArgValue(line, "--constraint");
796
+ if (path4) {
797
+ options.constraintFiles.push(path4);
798
+ return true;
799
+ }
800
+ }
801
+ if (line.startsWith("--index-url")) {
802
+ const url = extractArgValue(line, "--index-url");
803
+ if (url) {
804
+ options.indexUrl = url;
805
+ return true;
806
+ }
807
+ }
808
+ if (line.startsWith("-i ") || line === "-i") {
809
+ const match = line.match(/^-i\s+(\S+)/);
810
+ if (match) {
811
+ options.indexUrl = match[1];
812
+ return true;
813
+ }
814
+ }
815
+ if (line.startsWith("--extra-index-url")) {
816
+ const url = extractArgValue(line, "--extra-index-url");
817
+ if (url) {
818
+ options.extraIndexUrls.push(url);
819
+ return true;
820
+ }
821
+ }
822
+ return false;
823
+ }
824
+ function stripInlineHashes(line) {
825
+ return line.replace(/\s+--hash=\S+/g, "").trim();
826
+ }
827
+ function extractInlineHashes(line) {
828
+ const hashes = [];
829
+ const hashRegex = /--hash=(\S+)/g;
830
+ let match;
831
+ while ((match = hashRegex.exec(line)) != null) {
832
+ hashes.push(match[1]);
833
+ }
834
+ return hashes;
835
+ }
836
+ function extractArgValue(line, option) {
837
+ if (line.startsWith(`${option}=`)) {
838
+ const value = line.slice(option.length + 1).trim();
839
+ return value || null;
840
+ }
841
+ if (line.startsWith(`${option} `) || line.startsWith(`${option} `)) {
842
+ const value = line.slice(option.length).trim();
843
+ return value || null;
844
+ }
845
+ return null;
846
+ }
847
+ function convertRequirementsToPyprojectToml(fileContent, readFile3) {
848
+ const pyproject = {};
849
+ const parsed = parseRequirementsFile(fileContent, readFile3);
850
+ const deps = [];
851
+ const sources = {};
852
+ for (const req of parsed.requirements) {
853
+ deps.push(formatPep508(req));
854
+ if (req.source) {
855
+ if (Object.prototype.hasOwnProperty.call(sources, req.name)) {
856
+ sources[req.name].push(req.source);
857
+ } else {
858
+ sources[req.name] = [req.source];
859
+ }
860
+ }
861
+ }
862
+ if (deps.length > 0) {
863
+ pyproject.project = {
864
+ dependencies: deps
865
+ };
866
+ }
867
+ const uv = {};
868
+ const indexes = buildIndexEntries(parsed.pipOptions);
869
+ if (indexes.length > 0) {
870
+ uv.index = indexes;
871
+ }
872
+ if (Object.keys(sources).length > 0) {
873
+ uv.sources = sources;
874
+ }
875
+ if (Object.keys(uv).length > 0) {
876
+ pyproject.tool = { uv };
877
+ }
878
+ return pyproject;
879
+ }
880
+ function buildIndexEntries(pipOptions) {
881
+ const indexes = [];
882
+ if (pipOptions.indexUrl) {
883
+ indexes.push({
884
+ name: PRIMARY_INDEX_NAME,
885
+ url: pipOptions.indexUrl,
886
+ default: true
887
+ });
888
+ }
889
+ for (let i = 0; i < pipOptions.extraIndexUrls.length; i++) {
890
+ indexes.push({
891
+ name: `${EXTRA_INDEX_PREFIX}${i + 1}`,
892
+ url: pipOptions.extraIndexUrls[i]
893
+ });
894
+ }
895
+ return indexes;
896
+ }
897
+ function parseRequirementsFile(fileContent, readFile3) {
898
+ const visited = /* @__PURE__ */ new Set();
899
+ return parseRequirementsFileInternal(fileContent, readFile3, visited);
900
+ }
901
+ function parseRequirementsFileInternal(fileContent, readFile3, visited) {
902
+ const { cleanedContent, options } = extractPipArguments(fileContent);
903
+ const hashMap = buildHashMap(fileContent);
904
+ const requirements = (0, import_pip_requirements_js.parsePipRequirementsFile)(cleanedContent);
905
+ const normalized = [];
906
+ const mergedOptions = {
907
+ requirementFiles: [...options.requirementFiles],
908
+ constraintFiles: [...options.constraintFiles],
909
+ indexUrl: options.indexUrl,
910
+ extraIndexUrls: [...options.extraIndexUrls]
911
+ };
912
+ for (const req of requirements) {
913
+ if (req.type === "RequirementsFile") {
914
+ mergedOptions.requirementFiles.push(req.path);
915
+ continue;
916
+ }
917
+ if (req.type === "ConstraintsFile") {
918
+ mergedOptions.constraintFiles.push(req.path);
919
+ continue;
920
+ }
921
+ const norm = normalizeRequirement(req);
922
+ if (norm != null) {
923
+ const hashes = hashMap.get(norm.name.toLowerCase());
924
+ if (hashes && hashes.length > 0) {
925
+ norm.hashes = hashes;
926
+ }
927
+ normalized.push(norm);
928
+ }
929
+ }
930
+ if (readFile3) {
931
+ for (const refPath of mergedOptions.requirementFiles) {
932
+ const refPathKey = (0, import_node_path4.normalize)(refPath);
933
+ if (visited.has(refPathKey)) {
934
+ continue;
935
+ }
936
+ visited.add(refPathKey);
937
+ const refContent = readFile3(refPath);
938
+ if (refContent != null) {
939
+ const refParsed = parseRequirementsFileInternal(
940
+ refContent,
941
+ readFile3,
942
+ visited
943
+ );
944
+ const existingNames = new Set(
945
+ normalized.map((r) => r.name.toLowerCase())
946
+ );
947
+ for (const req of refParsed.requirements) {
948
+ if (!existingNames.has(req.name.toLowerCase())) {
949
+ normalized.push(req);
950
+ existingNames.add(req.name.toLowerCase());
951
+ }
952
+ }
953
+ if (refParsed.pipOptions.indexUrl) {
954
+ mergedOptions.indexUrl = refParsed.pipOptions.indexUrl;
955
+ }
956
+ for (const url of refParsed.pipOptions.extraIndexUrls) {
957
+ if (!mergedOptions.extraIndexUrls.includes(url)) {
958
+ mergedOptions.extraIndexUrls.push(url);
959
+ }
960
+ }
961
+ for (const constraintPath of refParsed.pipOptions.constraintFiles) {
962
+ if (!mergedOptions.constraintFiles.includes(constraintPath)) {
963
+ mergedOptions.constraintFiles.push(constraintPath);
964
+ }
965
+ }
966
+ }
967
+ }
968
+ }
969
+ return {
970
+ requirements: normalized,
971
+ pipOptions: mergedOptions
972
+ };
973
+ }
974
+ function buildHashMap(fileContent) {
975
+ const hashMap = /* @__PURE__ */ new Map();
976
+ const lines = fileContent.split(/\r?\n/);
977
+ for (let i = 0; i < lines.length; i++) {
978
+ let line = lines[i].trim();
979
+ if (line === "" || line.startsWith("#") || line.startsWith("-")) {
980
+ continue;
981
+ }
982
+ while (line.endsWith("\\") && i + 1 < lines.length) {
983
+ i++;
984
+ line = line.slice(0, -1) + lines[i].trim();
985
+ }
986
+ const hashes = extractInlineHashes(line);
987
+ if (hashes.length === 0) {
988
+ continue;
989
+ }
990
+ const packageMatch = line.match(/^([a-zA-Z0-9][-a-zA-Z0-9._]*)/);
991
+ if (packageMatch) {
992
+ const packageName = packageMatch[1].toLowerCase();
993
+ hashMap.set(packageName, hashes);
994
+ }
995
+ }
996
+ return hashMap;
997
+ }
998
+ function normalizeRequirement(req) {
999
+ if (req.type === "RequirementsFile" || req.type === "ConstraintsFile") {
1000
+ return null;
1001
+ }
1002
+ if (req.type === "ProjectURL") {
1003
+ return normalizeProjectURLRequirement(req);
1004
+ }
1005
+ if (req.type === "ProjectName") {
1006
+ return normalizeProjectNameRequirement(req);
1007
+ }
1008
+ return null;
1009
+ }
1010
+ function normalizeProjectNameRequirement(req) {
1011
+ const normalized = {
1012
+ name: req.name
1013
+ };
1014
+ if (req.extras && req.extras.length > 0) {
1015
+ normalized.extras = req.extras;
1016
+ }
1017
+ if (req.versionSpec && req.versionSpec.length > 0) {
1018
+ normalized.version = req.versionSpec.map((spec) => `${spec.operator}${spec.version}`).join(",");
1019
+ }
1020
+ if (req.environmentMarkerTree) {
1021
+ normalized.markers = formatEnvironmentMarkers(req.environmentMarkerTree);
1022
+ }
1023
+ return normalized;
1024
+ }
1025
+ function normalizeProjectURLRequirement(req) {
1026
+ const normalized = {
1027
+ name: req.name
1028
+ };
1029
+ if (req.extras && req.extras.length > 0) {
1030
+ normalized.extras = req.extras;
1031
+ }
1032
+ if (req.environmentMarkerTree) {
1033
+ normalized.markers = formatEnvironmentMarkers(req.environmentMarkerTree);
1034
+ }
1035
+ if (isGitUrl(req.url)) {
1036
+ const parsed = parseGitUrl(req.url);
1037
+ if (parsed) {
1038
+ const source = {
1039
+ git: parsed.url
1040
+ };
1041
+ if (parsed.ref) {
1042
+ source.rev = parsed.ref;
1043
+ }
1044
+ if (parsed.editable) {
1045
+ source.editable = true;
1046
+ }
1047
+ normalized.source = source;
1048
+ }
1049
+ }
1050
+ normalized.url = req.url;
1051
+ return normalized;
1052
+ }
1053
+ function formatEnvironmentMarkers(marker) {
1054
+ if (isEnvironmentMarkerNode(marker)) {
1055
+ const left = formatEnvironmentMarkers(marker.left);
1056
+ const right = formatEnvironmentMarkers(marker.right);
1057
+ return `(${left}) ${marker.operator} (${right})`;
1058
+ }
1059
+ const leaf = marker;
1060
+ const leftStr = formatMarkerValue(leaf.left);
1061
+ const rightStr = formatMarkerValue(leaf.right);
1062
+ return `${leftStr} ${leaf.operator} ${rightStr}`;
1063
+ }
1064
+ function isEnvironmentMarkerNode(marker) {
1065
+ if (typeof marker !== "object" || marker == null) {
1066
+ return false;
1067
+ }
1068
+ const op = marker.operator;
1069
+ return op === "and" || op === "or";
1070
+ }
1071
+ function formatMarkerValue(value) {
1072
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
1073
+ return value;
1074
+ }
1075
+ return value;
1076
+ }
1077
+
1078
+ // src/manifest/uv-config/schema.ts
1079
+ var UvConfigWorkspaceSchema = uvConfigWorkspaceSchema.passthrough();
1080
+ var UvIndexEntrySchema = uvIndexEntrySchema.passthrough();
1081
+ var UvConfigSchema = uvConfigSchema.passthrough();
1082
+
1083
+ // src/manifest/python-specifiers.ts
1084
+ var PythonImplementation = {
1085
+ knownLongNames() {
1086
+ return {
1087
+ python: "cpython",
1088
+ cpython: "cpython",
1089
+ pypy: "pypy",
1090
+ pyodide: "pyodide",
1091
+ graalpy: "graalpy"
1092
+ };
1093
+ },
1094
+ knownShortNames() {
1095
+ return { cp: "cpython", pp: "pypy", gp: "graalpy" };
1096
+ },
1097
+ knownNames() {
1098
+ return { ...this.knownLongNames(), ...this.knownShortNames() };
1099
+ },
1100
+ parse(s) {
1101
+ const impl = this.knownNames()[s];
1102
+ if (impl !== void 0) {
1103
+ return impl;
1104
+ } else {
1105
+ return { implementation: s };
1106
+ }
1107
+ },
1108
+ isUnknown(impl) {
1109
+ return impl.implementation !== void 0;
1110
+ },
1111
+ toString(impl) {
1112
+ switch (impl) {
1113
+ case "cpython":
1114
+ return "cpython";
1115
+ case "pypy":
1116
+ return "pypy";
1117
+ case "pyodide":
1118
+ return "pyodide";
1119
+ case "graalpy":
1120
+ return "graalpy";
1121
+ default:
1122
+ return impl.implementation;
1123
+ }
1124
+ },
1125
+ toStringPretty(impl) {
1126
+ switch (impl) {
1127
+ case "cpython":
1128
+ return "CPython";
1129
+ case "pypy":
1130
+ return "PyPy";
1131
+ case "pyodide":
1132
+ return "PyOdide";
1133
+ case "graalpy":
1134
+ return "GraalPy";
1135
+ default:
1136
+ return impl.implementation;
1137
+ }
1138
+ }
1139
+ };
1140
+ var PythonVariant = {
1141
+ parse(s) {
1142
+ switch (s) {
1143
+ case "default":
1144
+ return "default";
1145
+ case "d":
1146
+ case "debug":
1147
+ return "debug";
1148
+ case "freethreaded":
1149
+ return "freethreaded";
1150
+ case "t":
1151
+ return "freethreaded";
1152
+ case "gil":
1153
+ return "gil";
1154
+ case "freethreaded+debug":
1155
+ return "freethreaded+debug";
1156
+ case "td":
1157
+ return "freethreaded+debug";
1158
+ case "gil+debug":
1159
+ return "gil+debug";
1160
+ default:
1161
+ return { type: "unknown", variant: s };
1162
+ }
1163
+ },
1164
+ toString(v) {
1165
+ switch (v) {
1166
+ case "default":
1167
+ return "default";
1168
+ case "debug":
1169
+ return "debug";
1170
+ case "freethreaded":
1171
+ return "freethreaded";
1172
+ case "gil":
1173
+ return "gil";
1174
+ case "freethreaded+debug":
1175
+ return "freethreaded+debug";
1176
+ case "gil+debug":
1177
+ return "gil+debug";
1178
+ default:
1179
+ return v.variant;
1180
+ }
1181
+ }
1182
+ };
1183
+ var PythonVersion = {
1184
+ toString(version) {
1185
+ let verstr = `${version.major}.${version.minor}`;
1186
+ if (version.patch !== void 0) {
1187
+ verstr = `${verstr}.${version.patch}`;
1188
+ }
1189
+ if (version.prerelease !== void 0) {
1190
+ verstr = `${verstr}${version.prerelease}`;
1191
+ }
1192
+ return verstr;
1193
+ }
1194
+ };
1195
+ var PythonBuild = {
1196
+ toString(build) {
1197
+ const parts = [
1198
+ PythonImplementation.toString(build.implementation),
1199
+ `${PythonVersion.toString(build.version)}+${PythonVariant.toString(build.variant)}`,
1200
+ build.os,
1201
+ build.architecture,
1202
+ build.libc
1203
+ ];
1204
+ return parts.join("-");
1205
+ }
1206
+ };
1207
+
1208
+ // src/manifest/uv-python-version-parser.ts
1209
+ function pythonRequestFromConstraint(constraint) {
1210
+ return {
1211
+ implementation: "cpython",
1212
+ version: {
1213
+ constraint,
1214
+ variant: "default"
1215
+ }
1216
+ };
1217
+ }
1218
+ function parsePythonVersionFile(content) {
1219
+ const lines = content.split(/\r?\n/);
1220
+ const requests = [];
1221
+ for (let i = 0; i < lines.length; i++) {
1222
+ const raw = lines[i] ?? "";
1223
+ const trimmed = raw.trim();
1224
+ if (!trimmed)
1225
+ continue;
1226
+ if (trimmed.startsWith("#"))
1227
+ continue;
1228
+ const parsed = parseUvPythonRequest(trimmed);
1229
+ if (parsed != null) {
1230
+ requests.push(parsed);
1231
+ }
1232
+ }
1233
+ if (requests.length === 0) {
1234
+ return null;
1235
+ } else {
1236
+ return requests;
1237
+ }
1238
+ }
1239
+ function parseUvPythonRequest(input) {
1240
+ const raw = input.trim();
1241
+ if (!raw) {
1242
+ return null;
1243
+ }
1244
+ const lowercase = raw.toLowerCase();
1245
+ if (lowercase === "any" || lowercase === "default") {
1246
+ return {};
1247
+ }
1248
+ for (const [implName, implementation] of Object.entries(
1249
+ PythonImplementation.knownNames()
1250
+ )) {
1251
+ if (lowercase.startsWith(implName)) {
1252
+ let rest = lowercase.substring(implName.length);
1253
+ if (rest.length === 0) {
1254
+ return {
1255
+ implementation
1256
+ };
1257
+ }
1258
+ if (rest[0] === "@") {
1259
+ rest = rest.substring(1);
1260
+ }
1261
+ const version2 = parseVersionRequest(rest);
1262
+ if (version2 != null) {
1263
+ return {
1264
+ implementation,
1265
+ version: version2
1266
+ };
1267
+ }
1268
+ }
1269
+ }
1270
+ const version = parseVersionRequest(lowercase);
1271
+ if (version != null) {
1272
+ return {
1273
+ implementation: "cpython",
1274
+ version
1275
+ };
1276
+ }
1277
+ return tryParsePlatformRequest(lowercase);
1278
+ }
1279
+ function parseVersionRequest(input) {
1280
+ const [version, variant] = parseVariantSuffix(input);
1281
+ let parsedVer = (0, import_pep440.parse)(version);
1282
+ if (parsedVer != null) {
1283
+ if (parsedVer.release.length === 1) {
1284
+ const converted = splitWheelTagVersion(version);
1285
+ if (converted != null) {
1286
+ const convertedVer = (0, import_pep440.parse)(converted);
1287
+ if (convertedVer != null) {
1288
+ parsedVer = convertedVer;
1289
+ }
1290
+ }
1291
+ }
1292
+ return {
1293
+ constraint: pep440ConstraintFromVersion(parsedVer),
1294
+ variant
1295
+ };
1296
+ }
1297
+ const parsedConstr = (0, import_specifier.parse)(version);
1298
+ if (parsedConstr?.length) {
1299
+ return {
1300
+ constraint: parsedConstr,
1301
+ variant
1302
+ };
1303
+ }
1304
+ return null;
1305
+ }
1306
+ function splitWheelTagVersion(version) {
1307
+ if (!/^\d+$/.test(version)) {
1308
+ return null;
1309
+ }
1310
+ if (version.length < 2) {
1311
+ return null;
1312
+ }
1313
+ const major = version[0];
1314
+ const minorStr = version.substring(1);
1315
+ const minor = parseInt(minorStr, 10);
1316
+ if (isNaN(minor) || minor > 255) {
1317
+ return null;
1318
+ }
1319
+ return `${major}.${minor}`;
1320
+ }
1321
+ function rfindNumericChar(s) {
1322
+ for (let i = s.length - 1; i >= 0; i--) {
1323
+ const code = s.charCodeAt(i);
1324
+ if (code >= 48 && code <= 57)
1325
+ return i;
1326
+ }
1327
+ return -1;
1328
+ }
1329
+ function parseVariantSuffix(vrs) {
1330
+ let pos = rfindNumericChar(vrs);
1331
+ if (pos < 0) {
1332
+ return [vrs, "default"];
1333
+ }
1334
+ pos += 1;
1335
+ if (pos + 1 > vrs.length) {
1336
+ return [vrs, "default"];
1337
+ }
1338
+ let variant = vrs.substring(pos);
1339
+ if (variant[0] === "+") {
1340
+ variant = variant.substring(1);
1341
+ }
1342
+ const prefix = vrs.substring(0, pos);
1343
+ return [prefix, PythonVariant.parse(variant)];
1344
+ }
1345
+ function tryParsePlatformRequest(raw) {
1346
+ const parts = raw.split("-");
1347
+ let partIdx = 0;
1348
+ const state = ["implementation", "version", "os", "arch", "libc", "end"];
1349
+ let stateIdx = 0;
1350
+ let implementation;
1351
+ let version;
1352
+ let os;
1353
+ let arch;
1354
+ let libc;
1355
+ let implOrVersionFailed = false;
1356
+ for (; ; ) {
1357
+ if (partIdx >= parts.length || state[stateIdx] === "end") {
1358
+ break;
1359
+ }
1360
+ const part = parts[partIdx].toLowerCase();
1361
+ if (part.length === 0) {
1362
+ break;
1363
+ }
1364
+ switch (state[stateIdx]) {
1365
+ case "implementation":
1366
+ if (part === "any") {
1367
+ partIdx += 1;
1368
+ stateIdx += 1;
1369
+ continue;
1370
+ }
1371
+ implementation = PythonImplementation.parse(part);
1372
+ if (PythonImplementation.isUnknown(implementation)) {
1373
+ implementation = void 0;
1374
+ stateIdx += 1;
1375
+ implOrVersionFailed = true;
1376
+ continue;
1377
+ }
1378
+ stateIdx += 1;
1379
+ partIdx += 1;
1380
+ break;
1381
+ case "version":
1382
+ if (part === "any") {
1383
+ partIdx += 1;
1384
+ stateIdx += 1;
1385
+ continue;
1386
+ }
1387
+ version = parseVersionRequest(part);
1388
+ if (version == null) {
1389
+ version = void 0;
1390
+ stateIdx += 1;
1391
+ implOrVersionFailed = true;
1392
+ continue;
1393
+ }
1394
+ stateIdx += 1;
1395
+ partIdx += 1;
1396
+ break;
1397
+ case "os":
1398
+ if (part === "any") {
1399
+ partIdx += 1;
1400
+ stateIdx += 1;
1401
+ continue;
1402
+ }
1403
+ os = part;
1404
+ stateIdx += 1;
1405
+ partIdx += 1;
1406
+ break;
1407
+ case "arch":
1408
+ if (part === "any") {
1409
+ partIdx += 1;
1410
+ stateIdx += 1;
1411
+ continue;
1412
+ }
1413
+ arch = part;
1414
+ stateIdx += 1;
1415
+ partIdx += 1;
1416
+ break;
1417
+ case "libc":
1418
+ if (part === "any") {
1419
+ partIdx += 1;
1420
+ stateIdx += 1;
1421
+ continue;
1422
+ }
1423
+ libc = part;
1424
+ stateIdx += 1;
1425
+ partIdx += 1;
1426
+ break;
1427
+ default:
1428
+ break;
1429
+ }
1430
+ }
1431
+ if (implOrVersionFailed && implementation === void 0 && version === void 0) {
1432
+ return null;
1433
+ }
1434
+ let platform;
1435
+ if (os !== void 0 || arch !== void 0 || libc !== void 0) {
1436
+ platform = {
1437
+ os,
1438
+ arch,
1439
+ libc
1440
+ };
1441
+ }
1442
+ return { implementation, version, platform };
1443
+ }
1444
+
1445
+ // src/manifest/package.ts
1446
+ var PythonConfigKind = /* @__PURE__ */ ((PythonConfigKind2) => {
1447
+ PythonConfigKind2["PythonVersion"] = ".python-version";
1448
+ return PythonConfigKind2;
1449
+ })(PythonConfigKind || {});
1450
+ var PythonManifestKind = /* @__PURE__ */ ((PythonManifestKind2) => {
1451
+ PythonManifestKind2["PyProjectToml"] = "pyproject.toml";
1452
+ return PythonManifestKind2;
1453
+ })(PythonManifestKind || {});
1454
+ var PythonManifestConvertedKind = /* @__PURE__ */ ((PythonManifestConvertedKind2) => {
1455
+ PythonManifestConvertedKind2["Pipfile"] = "Pipfile";
1456
+ PythonManifestConvertedKind2["PipfileLock"] = "Pipfile.lock";
1457
+ PythonManifestConvertedKind2["RequirementsIn"] = "requirements.in";
1458
+ PythonManifestConvertedKind2["RequirementsTxt"] = "requirements.txt";
1459
+ return PythonManifestConvertedKind2;
1460
+ })(PythonManifestConvertedKind || {});
1461
+ async function discoverPythonPackage({
1462
+ entrypointDir,
1463
+ rootDir
1464
+ }) {
1465
+ const entrypointPath = normalizePath(entrypointDir);
1466
+ const rootPath = normalizePath(rootDir);
1467
+ let prefix = import_node_path5.default.relative(rootPath, entrypointPath);
1468
+ if (prefix.startsWith("..")) {
1469
+ throw new PythonAnalysisError({
1470
+ message: "Entrypoint directory outside of repository root",
1471
+ code: "PYTHON_INVALID_ENTRYPOINT_PATH"
1472
+ });
1473
+ }
1474
+ const manifests = [];
1475
+ let configs = [];
1476
+ for (; ; ) {
1477
+ const prefixConfigs = await loadPythonConfigs(rootPath, prefix);
1478
+ if (Object.keys(prefixConfigs).length !== 0) {
1479
+ configs.push(prefixConfigs);
1480
+ }
1481
+ const prefixManifest = await loadPythonManifest(rootPath, prefix);
1482
+ if (prefixManifest != null) {
1483
+ manifests.push(prefixManifest);
1484
+ if (prefixManifest.isRoot) {
1485
+ break;
1486
+ }
1487
+ }
1488
+ if (prefix === "" || prefix === ".") {
1489
+ break;
1490
+ }
1491
+ prefix = import_node_path5.default.dirname(prefix);
1492
+ }
1493
+ let entrypointManifest;
1494
+ let workspaceManifest;
1495
+ if (manifests.length === 0) {
1496
+ return {
1497
+ configs
1498
+ };
1499
+ } else {
1500
+ entrypointManifest = manifests[0];
1501
+ const entrypointWorkspaceManifest = findWorkspaceManifestFor(
1502
+ entrypointManifest,
1503
+ manifests
1504
+ );
1505
+ workspaceManifest = entrypointWorkspaceManifest;
1506
+ configs = configs.filter(
1507
+ (config) => Object.values(config).some(
1508
+ (cfg) => cfg !== void 0 && isSubpath(
1509
+ import_node_path5.default.dirname(cfg.path),
1510
+ import_node_path5.default.dirname(entrypointWorkspaceManifest.path)
1511
+ )
1512
+ )
1513
+ );
1514
+ }
1515
+ const requiresPython = computeRequiresPython(
1516
+ entrypointManifest,
1517
+ workspaceManifest,
1518
+ configs
1519
+ );
1520
+ return {
1521
+ manifest: entrypointManifest,
1522
+ workspaceManifest,
1523
+ configs,
1524
+ requiresPython
1525
+ };
1526
+ }
1527
+ function computeRequiresPython(manifest, workspaceManifest, configs) {
1528
+ const constraints = [];
1529
+ for (const configSet of configs) {
1530
+ const pythonVersionConfig = configSet[".python-version" /* PythonVersion */];
1531
+ if (pythonVersionConfig !== void 0) {
1532
+ constraints.push({
1533
+ request: pythonVersionConfig.data,
1534
+ source: `${pythonVersionConfig.path}`
1535
+ });
1536
+ break;
1537
+ }
1538
+ }
1539
+ const manifestRequiresPython = manifest?.data.project?.["requires-python"];
1540
+ if (manifestRequiresPython) {
1541
+ const parsed = (0, import_specifier.parse)(manifestRequiresPython);
1542
+ if (parsed?.length) {
1543
+ const request = pythonRequestFromConstraint(parsed);
1544
+ constraints.push({
1545
+ request: [request],
1546
+ source: `"requires-python" key in ${manifest.path}`
1547
+ });
1548
+ }
1549
+ } else {
1550
+ const workspaceRequiresPython = workspaceManifest?.data.project?.["requires-python"];
1551
+ if (workspaceRequiresPython) {
1552
+ const parsed = (0, import_specifier.parse)(workspaceRequiresPython);
1553
+ if (parsed?.length) {
1554
+ const request = pythonRequestFromConstraint(parsed);
1555
+ constraints.push({
1556
+ request: [request],
1557
+ source: `"requires-python" key in ${workspaceManifest.path}`
1558
+ });
1559
+ }
1560
+ }
1561
+ }
1562
+ return constraints;
1563
+ }
1564
+ function findWorkspaceManifestFor(manifest, manifestStack) {
1565
+ if (manifest.isRoot) {
1566
+ return manifest;
1567
+ }
1568
+ for (const parentManifest of manifestStack) {
1569
+ if (parentManifest.path === manifest.path) {
1570
+ continue;
1571
+ }
1572
+ const workspace = parentManifest.data.tool?.uv?.workspace;
1573
+ if (workspace !== void 0) {
1574
+ let members = workspace.members ?? [];
1575
+ if (!Array.isArray(members)) {
1576
+ members = [];
1577
+ }
1578
+ let exclude = workspace.exclude ?? [];
1579
+ if (!Array.isArray(exclude)) {
1580
+ exclude = [];
1581
+ }
1582
+ const entrypointRelPath = import_node_path5.default.relative(
1583
+ import_node_path5.default.dirname(parentManifest.path),
1584
+ import_node_path5.default.dirname(manifest.path)
1585
+ );
1586
+ if (members.length > 0 && members.some(
1587
+ (pat) => (0, import_minimatch.match)([entrypointRelPath], pat).length > 0
1588
+ ) && !exclude.some(
1589
+ (pat) => (0, import_minimatch.match)([entrypointRelPath], pat).length > 0
1590
+ )) {
1591
+ return parentManifest;
1592
+ }
1593
+ }
1594
+ }
1595
+ return manifest;
1596
+ }
1597
+ async function loadPythonManifest(root, prefix) {
1598
+ let manifest = null;
1599
+ const pyproject = await maybeLoadPyProjectToml(root, prefix);
1600
+ if (pyproject != null) {
1601
+ manifest = pyproject;
1602
+ manifest.isRoot = pyproject.data.tool?.uv?.workspace !== void 0;
1603
+ } else {
1604
+ const pipfileLockPyProject = await maybeLoadPipfileLock(root, prefix);
1605
+ if (pipfileLockPyProject != null) {
1606
+ manifest = pipfileLockPyProject;
1607
+ manifest.isRoot = true;
1608
+ } else {
1609
+ const pipfilePyProject = await maybeLoadPipfile(root, prefix);
1610
+ if (pipfilePyProject != null) {
1611
+ manifest = pipfilePyProject;
1612
+ manifest.isRoot = true;
1613
+ } else {
1614
+ for (const fileName of [
1615
+ "requirements.frozen.txt",
1616
+ "requirements-frozen.txt",
1617
+ "requirements.txt",
1618
+ "requirements.in",
1619
+ import_node_path5.default.join("requirements", "prod.txt")
1620
+ ]) {
1621
+ const requirementsTxtManifest = await maybeLoadRequirementsTxt(
1622
+ root,
1623
+ prefix,
1624
+ fileName
1625
+ );
1626
+ if (requirementsTxtManifest != null) {
1627
+ manifest = requirementsTxtManifest;
1628
+ manifest.isRoot = true;
1629
+ break;
1630
+ }
1631
+ }
1632
+ }
1633
+ }
1634
+ }
1635
+ return manifest;
1636
+ }
1637
+ async function maybeLoadPyProjectToml(root, subdir) {
1638
+ const pyprojectTomlRelPath = import_node_path5.default.join(subdir, "pyproject.toml");
1639
+ const pyprojectTomlPath = import_node_path5.default.join(root, pyprojectTomlRelPath);
1640
+ let pyproject;
1641
+ try {
1642
+ pyproject = await readConfigIfExists(
1643
+ pyprojectTomlPath,
1644
+ PyProjectTomlSchema
1645
+ );
1646
+ } catch (error) {
1647
+ if (error instanceof PythonAnalysisError) {
1648
+ error.path = pyprojectTomlRelPath;
1649
+ throw error;
1650
+ }
1651
+ throw new PythonAnalysisError({
1652
+ message: `could not parse pyproject.toml: ${error instanceof Error ? error.message : String(error)}`,
1653
+ code: "PYTHON_PYPROJECT_PARSE_ERROR",
1654
+ path: pyprojectTomlRelPath
1655
+ });
1656
+ }
1657
+ if (pyproject == null) {
1658
+ return null;
1659
+ }
1660
+ const uvTomlRelPath = import_node_path5.default.join(subdir, "uv.toml");
1661
+ const uvTomlPath = import_node_path5.default.join(root, uvTomlRelPath);
1662
+ let uvToml;
1663
+ try {
1664
+ uvToml = await readConfigIfExists(uvTomlPath, UvConfigSchema);
1665
+ } catch (error) {
1666
+ if (error instanceof PythonAnalysisError) {
1667
+ error.path = uvTomlRelPath;
1668
+ throw error;
1669
+ }
1670
+ throw new PythonAnalysisError({
1671
+ message: `could not parse uv.toml: ${error instanceof Error ? error.message : String(error)}`,
1672
+ code: "PYTHON_UV_CONFIG_PARSE_ERROR",
1673
+ path: uvTomlRelPath
1674
+ });
1675
+ }
1676
+ if (uvToml != null) {
1677
+ if (pyproject.tool == null) {
1678
+ pyproject.tool = { uv: uvToml };
1679
+ } else {
1680
+ pyproject.tool.uv = uvToml;
1681
+ }
1682
+ }
1683
+ return {
1684
+ path: pyprojectTomlRelPath,
1685
+ data: pyproject
1686
+ };
1687
+ }
1688
+ async function maybeLoadPipfile(root, subdir) {
1689
+ const pipfileRelPath = import_node_path5.default.join(subdir, "Pipfile");
1690
+ const pipfilePath = import_node_path5.default.join(root, pipfileRelPath);
1691
+ let pipfile;
1692
+ try {
1693
+ pipfile = await readConfigIfExists(pipfilePath, PipfileLikeSchema, ".toml");
1694
+ } catch (error) {
1695
+ if (error instanceof PythonAnalysisError) {
1696
+ error.path = pipfileRelPath;
1697
+ throw error;
1698
+ }
1699
+ throw new PythonAnalysisError({
1700
+ message: `could not parse Pipfile: ${error instanceof Error ? error.message : String(error)}`,
1701
+ code: "PYTHON_PIPFILE_PARSE_ERROR",
1702
+ path: pipfileRelPath
1703
+ });
1704
+ }
1705
+ if (pipfile == null) {
1706
+ return null;
1707
+ }
1708
+ const pyproject = convertPipfileToPyprojectToml(pipfile);
1709
+ return {
1710
+ path: pipfileRelPath,
1711
+ data: pyproject,
1712
+ origin: {
1713
+ kind: "Pipfile" /* Pipfile */,
1714
+ path: pipfileRelPath
1715
+ }
1716
+ };
1717
+ }
1718
+ async function maybeLoadPipfileLock(root, subdir) {
1719
+ const pipfileLockRelPath = import_node_path5.default.join(subdir, "Pipfile.lock");
1720
+ const pipfileLockPath = import_node_path5.default.join(root, pipfileLockRelPath);
1721
+ let pipfileLock;
1722
+ try {
1723
+ pipfileLock = await readConfigIfExists(
1724
+ pipfileLockPath,
1725
+ PipfileLockLikeSchema,
1726
+ ".json"
1727
+ );
1728
+ } catch (error) {
1729
+ if (error instanceof PythonAnalysisError) {
1730
+ error.path = pipfileLockRelPath;
1731
+ throw error;
1732
+ }
1733
+ throw new PythonAnalysisError({
1734
+ message: `could not parse Pipfile.lock: ${error instanceof Error ? error.message : String(error)}`,
1735
+ code: "PYTHON_PIPFILE_LOCK_PARSE_ERROR",
1736
+ path: pipfileLockRelPath
1737
+ });
1738
+ }
1739
+ if (pipfileLock == null) {
1740
+ return null;
1741
+ }
1742
+ const pyproject = convertPipfileLockToPyprojectToml(pipfileLock);
1743
+ return {
1744
+ path: pipfileLockRelPath,
1745
+ data: pyproject,
1746
+ origin: {
1747
+ kind: "Pipfile.lock" /* PipfileLock */,
1748
+ path: pipfileLockRelPath
1749
+ }
1750
+ };
1751
+ }
1752
+ async function maybeLoadRequirementsTxt(root, subdir, fileName) {
1753
+ const requirementsTxtRelPath = import_node_path5.default.join(subdir, fileName);
1754
+ const requirementsTxtPath = import_node_path5.default.join(root, requirementsTxtRelPath);
1755
+ const requirementsContent = await readFileTextIfExists(requirementsTxtPath);
1756
+ if (requirementsContent == null) {
1757
+ return null;
1758
+ }
1759
+ try {
1760
+ const pyproject = convertRequirementsToPyprojectToml(requirementsContent);
1761
+ return {
1762
+ path: requirementsTxtRelPath,
1763
+ data: pyproject,
1764
+ origin: {
1765
+ kind: "requirements.txt" /* RequirementsTxt */,
1766
+ path: requirementsTxtRelPath
1767
+ }
1768
+ };
1769
+ } catch (error) {
1770
+ if (error instanceof PythonAnalysisError) {
1771
+ error.path = requirementsTxtRelPath;
1772
+ throw error;
1773
+ }
1774
+ throw new PythonAnalysisError({
1775
+ message: `could not parse ${fileName}: ${error instanceof Error ? error.message : String(error)}`,
1776
+ code: "PYTHON_REQUIREMENTS_PARSE_ERROR",
1777
+ path: requirementsTxtRelPath
1778
+ });
1779
+ }
1780
+ }
1781
+ async function loadPythonConfigs(root, prefix) {
1782
+ const configs = {};
1783
+ const pythonRequest = await maybeLoadPythonRequest(root, prefix);
1784
+ if (pythonRequest != null) {
1785
+ configs[".python-version" /* PythonVersion */] = pythonRequest;
1786
+ }
1787
+ return configs;
1788
+ }
1789
+ async function maybeLoadPythonRequest(root, subdir) {
1790
+ const dotPythonVersionRelPath = import_node_path5.default.join(subdir, ".python-version");
1791
+ const dotPythonVersionPath = import_node_path5.default.join(
1792
+ root,
1793
+ dotPythonVersionRelPath
1794
+ );
1795
+ const data = await readFileTextIfExists(dotPythonVersionPath);
1796
+ if (data == null) {
1797
+ return null;
1798
+ }
1799
+ const pyreq = parsePythonVersionFile(data);
1800
+ if (pyreq == null) {
1801
+ throw new PythonAnalysisError({
1802
+ message: `could not parse .python-version file: no valid Python version requests found`,
1803
+ code: "PYTHON_VERSION_FILE_PARSE_ERROR",
1804
+ path: dotPythonVersionRelPath
1805
+ });
1806
+ }
1807
+ return {
1808
+ kind: ".python-version" /* PythonVersion */,
1809
+ path: dotPythonVersionRelPath,
1810
+ data: pyreq
1811
+ };
1812
+ }
1813
+
1814
+ // src/manifest/python-selector.ts
1815
+ function selectPython(constraints, available) {
1816
+ const warnings = [];
1817
+ const errors = [];
1818
+ if (constraints.length === 0) {
1819
+ return {
1820
+ build: available.length > 0 ? available[0] : null,
1821
+ errors: available.length === 0 ? ["No Python builds available"] : void 0
1822
+ };
1823
+ }
1824
+ const constraintMatches = /* @__PURE__ */ new Map();
1825
+ for (let i = 0; i < constraints.length; i++) {
1826
+ constraintMatches.set(i, []);
1827
+ }
1828
+ for (const build of available) {
1829
+ let matchesAll = true;
1830
+ for (let i = 0; i < constraints.length; i++) {
1831
+ const constraint = constraints[i];
1832
+ if (buildMatchesConstraint(build, constraint)) {
1833
+ constraintMatches.get(i)?.push(build);
1834
+ } else {
1835
+ matchesAll = false;
1836
+ }
1837
+ }
1838
+ if (matchesAll) {
1839
+ return {
1840
+ build,
1841
+ warnings: warnings.length > 0 ? warnings : void 0
1842
+ };
1843
+ }
1844
+ }
1845
+ if (constraints.length > 1) {
1846
+ const constraintsWithMatches = [];
1847
+ for (let i = 0; i < constraints.length; i++) {
1848
+ const matches = constraintMatches.get(i) ?? [];
1849
+ if (matches.length > 0) {
1850
+ constraintsWithMatches.push(i);
1851
+ }
1852
+ }
1853
+ if (constraintsWithMatches.length > 1) {
1854
+ const sources = constraintsWithMatches.map((i) => constraints[i].source);
1855
+ warnings.push(
1856
+ `Python version constraints may not overlap: ${sources.join(", ")}`
1857
+ );
1858
+ }
1859
+ }
1860
+ const constraintDescriptions = constraints.map((c) => c.source).join(", ");
1861
+ errors.push(
1862
+ `No Python build satisfies all constraints: ${constraintDescriptions}`
1863
+ );
1864
+ return {
1865
+ build: null,
1866
+ errors,
1867
+ warnings: warnings.length > 0 ? warnings : void 0
1868
+ };
1869
+ }
1870
+ function pythonVersionToString(version) {
1871
+ let str = `${version.major}.${version.minor}`;
1872
+ if (version.patch !== void 0) {
1873
+ str += `.${version.patch}`;
1874
+ }
1875
+ if (version.prerelease) {
1876
+ str += version.prerelease;
1877
+ }
1878
+ return str;
1879
+ }
1880
+ function pep440ConstraintsToString(constraints) {
1881
+ return constraints.map((c) => `${c.operator}${c.prefix}${c.version}`).join(",");
1882
+ }
1883
+ function implementationsMatch(buildImpl, requestImpl) {
1884
+ if (PythonImplementation.isUnknown(buildImpl)) {
1885
+ if (PythonImplementation.isUnknown(requestImpl)) {
1886
+ return buildImpl.implementation === requestImpl.implementation;
1887
+ }
1888
+ return false;
1889
+ }
1890
+ if (PythonImplementation.isUnknown(requestImpl)) {
1891
+ return false;
1892
+ }
1893
+ return buildImpl === requestImpl;
1894
+ }
1895
+ function variantsMatch(buildVariant, requestVariant) {
1896
+ if (typeof buildVariant === "object" && "type" in buildVariant) {
1897
+ if (typeof requestVariant === "object" && "type" in requestVariant) {
1898
+ return buildVariant.variant === requestVariant.variant;
1899
+ }
1900
+ return false;
1901
+ }
1902
+ if (typeof requestVariant === "object" && "type" in requestVariant) {
1903
+ return false;
1904
+ }
1905
+ return buildVariant === requestVariant;
1906
+ }
1907
+ function buildMatchesRequest(build, request) {
1908
+ if (request.implementation !== void 0) {
1909
+ if (!implementationsMatch(build.implementation, request.implementation)) {
1910
+ return false;
1911
+ }
1912
+ }
1913
+ if (request.version !== void 0) {
1914
+ const versionConstraints = request.version.constraint;
1915
+ if (versionConstraints.length > 0) {
1916
+ const buildVersionStr = pythonVersionToString(build.version);
1917
+ const specifier = pep440ConstraintsToString(versionConstraints);
1918
+ if (!(0, import_specifier.satisfies)(buildVersionStr, specifier)) {
1919
+ return false;
1920
+ }
1921
+ }
1922
+ if (request.version.variant !== void 0) {
1923
+ if (!variantsMatch(build.variant, request.version.variant)) {
1924
+ return false;
1925
+ }
1926
+ }
1927
+ }
1928
+ if (request.platform !== void 0) {
1929
+ const platform = request.platform;
1930
+ if (platform.os !== void 0) {
1931
+ if (build.os.toLowerCase() !== platform.os.toLowerCase()) {
1932
+ return false;
1933
+ }
1934
+ }
1935
+ if (platform.arch !== void 0) {
1936
+ if (build.architecture.toLowerCase() !== platform.arch.toLowerCase()) {
1937
+ return false;
1938
+ }
1939
+ }
1940
+ if (platform.libc !== void 0) {
1941
+ if (build.libc.toLowerCase() !== platform.libc.toLowerCase()) {
1942
+ return false;
1943
+ }
1944
+ }
1945
+ }
1946
+ return true;
1947
+ }
1948
+ function buildMatchesConstraint(build, constraint) {
1949
+ if (constraint.request.length === 0) {
1950
+ return true;
1951
+ }
1952
+ for (const request of constraint.request) {
1953
+ if (buildMatchesRequest(build, request)) {
1954
+ return true;
1955
+ }
1956
+ }
1957
+ return false;
1958
+ }
1959
+
1960
+ // src/manifest/requirement/schema.ts
1961
+ var DependencySourceSchema = dependencySourceSchema.passthrough();
1962
+ var NormalizedRequirementSchema = normalizedRequirementSchema;
1963
+ var HashDigestSchema = hashDigestSchema;
1964
+ // Annotate the CommonJS export names for ESM import in node:
1965
+ 0 && (module.exports = {
1966
+ DependencySourceSchema,
1967
+ HashDigestSchema,
1968
+ LicenseObjectSchema,
1969
+ LicenseSchema,
1970
+ NormalizedRequirementSchema,
1971
+ PersonSchema,
1972
+ PipfileDependencyDetailSchema,
1973
+ PipfileDependencySchema,
1974
+ PipfileLikeSchema,
1975
+ PipfileLockLikeSchema,
1976
+ PipfileLockMetaSchema,
1977
+ PipfileSourceSchema,
1978
+ PyProjectBuildSystemSchema,
1979
+ PyProjectDependencyGroupsSchema,
1980
+ PyProjectProjectSchema,
1981
+ PyProjectTomlSchema,
1982
+ PyProjectToolSectionSchema,
1983
+ PythonAnalysisError,
1984
+ PythonBuild,
1985
+ PythonConfigKind,
1986
+ PythonImplementation,
1987
+ PythonManifestConvertedKind,
1988
+ PythonManifestKind,
1989
+ PythonVariant,
1990
+ PythonVersion,
1991
+ ReadmeObjectSchema,
1992
+ ReadmeSchema,
1993
+ UvConfigSchema,
1994
+ UvConfigWorkspaceSchema,
1995
+ UvIndexEntrySchema,
1996
+ containsAppOrHandler,
1997
+ discoverPythonPackage,
1998
+ selectPython
1999
+ });