@vercel/python-analysis 0.3.0 → 0.3.2

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