@vercel/python-analysis 0.9.1 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,13 +1,10 @@
1
1
  import type { PyProjectToml } from './pyproject/types';
2
2
  import type { NormalizedRequirement } from './requirement/types';
3
+ import type { ReadFileFn } from '../wasm/host-utils';
3
4
  /**
4
5
  * Parsed pip arguments from requirements file.
5
6
  */
6
7
  export interface PipOptions {
7
- /** Files referenced via -r or --requirement */
8
- requirementFiles: string[];
9
- /** Files referenced via -c or --constraint */
10
- constraintFiles: string[];
11
8
  /** Primary index URL (--index-url or -i) - only the last one is kept */
12
9
  indexUrl?: string;
13
10
  /** Extra index URLs (--extra-index-url) */
@@ -25,35 +22,27 @@ export interface ParsedRequirementsFile {
25
22
  pipOptions: PipOptions;
26
23
  }
27
24
  /**
28
- * Function type for reading referenced requirement files.
25
+ * Options for parsing requirements files.
29
26
  */
30
- export type ReadFileFn = (path: string) => string | null;
27
+ export interface ParseRequirementsOptions {
28
+ /** Function to read referenced requirement files (-r, -c). */
29
+ readFile?: ReadFileFn;
30
+ /** Directory containing the requirements file, used for resolving relative paths. */
31
+ workingDir?: string;
32
+ /**
33
+ * Package root directory (where pyproject.toml lives).
34
+ * When set and different from workingDir, source paths are rebased
35
+ * relative to this directory in convertRequirementsToPyprojectToml.
36
+ */
37
+ packageRoot?: string;
38
+ }
31
39
  /**
32
40
  * Convert a requirements.txt content to a pyproject.toml object suitable for uv.
33
- *
34
- * This creates a minimal pyproject:
35
- *
36
- * [project]
37
- * dependencies = [...]
38
- *
39
- * [tool.uv.sources]
40
- * package = { git = "..." }
41
- *
42
- * Note: Hash information is not included in pyproject.toml output.
43
- *
44
- * @param fileContent - The content of the requirements.txt file
45
- * @param readFile - Optional function to read referenced requirement files (-r, --requirement).
46
- * If provided, referenced files will be recursively processed.
47
41
  */
48
- export declare function convertRequirementsToPyprojectToml(fileContent: string, readFile?: ReadFileFn): PyProjectToml;
42
+ export declare function convertRequirementsToPyprojectToml(fileContent: string, options?: ParseRequirementsOptions): Promise<PyProjectToml>;
49
43
  /**
50
44
  * Parse requirements file content with full pip options support.
51
- * Returns both the normalized requirements and the parsed pip options
52
- * (--requirement, --constraint, --index-url, --extra-index-url, --hash).
53
- *
54
- * @param fileContent - The content of the requirements.txt file
55
- * @param readFile - Optional function to read referenced requirement files (-r, --requirement).
56
- * If provided, referenced files will be recursively processed and their
57
- * requirements merged into the result.
45
+ * The upstream WASM parser handles -r/-c recursion natively via the host-bridge.
58
46
  */
59
- export declare function parseRequirementsFile(fileContent: string, readFile?: ReadFileFn): ParsedRequirementsFile;
47
+ export declare function parseRequirementsFile(fileContent: string, options?: ParseRequirementsOptions): Promise<ParsedRequirementsFile>;
48
+ export type { ReadFileFn };
@@ -9,6 +9,12 @@ export interface UvLockPackageSource {
9
9
  editable?: string;
10
10
  virtual?: string;
11
11
  }
12
+ /**
13
+ * A wheel entry from a uv.lock file.
14
+ */
15
+ export interface UvLockWheel {
16
+ url: string;
17
+ }
12
18
  /**
13
19
  * A package entry from a parsed uv.lock file.
14
20
  */
@@ -16,6 +22,7 @@ export interface UvLockPackage {
16
22
  name: string;
17
23
  version: string;
18
24
  source?: UvLockPackageSource;
25
+ wheels: UvLockWheel[];
19
26
  }
20
27
  /**
21
28
  * Parsed uv.lock file structure.
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Check if a wheel filename is compatible with a given platform.
3
+ *
4
+ * Uses uv's `WheelFilename::is_compatible()` and `Tags::from_env()` via WASM
5
+ * — the same logic uv uses for resolution.
6
+ *
7
+ * @param wheelFilename - The wheel filename (e.g. "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.whl")
8
+ * @param pythonMajor - Python major version (e.g. 3)
9
+ * @param pythonMinor - Python minor version (e.g. 12)
10
+ * @param osName - OS name: "manylinux", "musllinux", "macos", or "windows"
11
+ * @param archName - Architecture: "x86_64", "aarch64", etc.
12
+ * @param osMajor - OS major version (glibc major for Linux, macOS major version)
13
+ * @param osMinor - OS minor version (glibc minor for Linux, macOS minor version)
14
+ * @returns true if the wheel is compatible with the platform
15
+ */
16
+ export declare function isWheelCompatible(wheelFilename: string, pythonMajor: number, pythonMinor: number, osName: string, archName: string, osMajor: number, osMinor: number): Promise<boolean>;
@@ -0,0 +1,23 @@
1
+ /// <reference types="node" />
2
+ /**
3
+ * Host-side implementation of the `vercel:python-analysis/host-utils` WIT interface.
4
+ */
5
+ import { AsyncLocalStorage } from 'node:async_hooks';
6
+ /**
7
+ * Function type for reading referenced requirement files.
8
+ */
9
+ export type ReadFileFn = (path: string) => string | null;
10
+ export interface ReadFileContext {
11
+ readFile: ReadFileFn;
12
+ workingDir?: string;
13
+ }
14
+ export declare const readFileStorage: AsyncLocalStorage<ReadFileContext>;
15
+ export declare function createHostUtils(): {
16
+ readFile(path: string): string;
17
+ domainToAscii(domain: string): string;
18
+ domainToUnicode(domain: string): [string, boolean];
19
+ nfcNormalize(s: string): string;
20
+ nfdNormalize(s: string): string;
21
+ nfkcNormalize(s: string): string;
22
+ nfkdNormalize(s: string): string;
23
+ };
@@ -0,0 +1,4 @@
1
+ /** @module Interface vercel:python-analysis/host-utils **/
2
+ export function domainToAscii(domain: string): string;
3
+ export function nfkcNormalize(s: string): string;
4
+ export function readFile(path: string): string;
@@ -0,0 +1,5 @@
1
+ /** @module Interface wasi:clocks/wall-clock@0.2.6 **/
2
+ export interface Datetime {
3
+ seconds: bigint,
4
+ nanoseconds: number,
5
+ }
@@ -0,0 +1,3 @@
1
+ /** @module Interface wasi:filesystem/preopens@0.2.6 **/
2
+ export function getDirectories(): Array<[Descriptor, string]>;
3
+ export type Descriptor = import('./wasi-filesystem-types.js').Descriptor;
@@ -0,0 +1,142 @@
1
+ /** @module Interface wasi:filesystem/types@0.2.6 **/
2
+ export type Filesize = bigint;
3
+ export type InputStream = import('./wasi-io-streams.js').InputStream;
4
+ /**
5
+ * # Variants
6
+ *
7
+ * ## `"access"`
8
+ *
9
+ * ## `"would-block"`
10
+ *
11
+ * ## `"already"`
12
+ *
13
+ * ## `"bad-descriptor"`
14
+ *
15
+ * ## `"busy"`
16
+ *
17
+ * ## `"deadlock"`
18
+ *
19
+ * ## `"quota"`
20
+ *
21
+ * ## `"exist"`
22
+ *
23
+ * ## `"file-too-large"`
24
+ *
25
+ * ## `"illegal-byte-sequence"`
26
+ *
27
+ * ## `"in-progress"`
28
+ *
29
+ * ## `"interrupted"`
30
+ *
31
+ * ## `"invalid"`
32
+ *
33
+ * ## `"io"`
34
+ *
35
+ * ## `"is-directory"`
36
+ *
37
+ * ## `"loop"`
38
+ *
39
+ * ## `"too-many-links"`
40
+ *
41
+ * ## `"message-size"`
42
+ *
43
+ * ## `"name-too-long"`
44
+ *
45
+ * ## `"no-device"`
46
+ *
47
+ * ## `"no-entry"`
48
+ *
49
+ * ## `"no-lock"`
50
+ *
51
+ * ## `"insufficient-memory"`
52
+ *
53
+ * ## `"insufficient-space"`
54
+ *
55
+ * ## `"not-directory"`
56
+ *
57
+ * ## `"not-empty"`
58
+ *
59
+ * ## `"not-recoverable"`
60
+ *
61
+ * ## `"unsupported"`
62
+ *
63
+ * ## `"no-tty"`
64
+ *
65
+ * ## `"no-such-device"`
66
+ *
67
+ * ## `"overflow"`
68
+ *
69
+ * ## `"not-permitted"`
70
+ *
71
+ * ## `"pipe"`
72
+ *
73
+ * ## `"read-only"`
74
+ *
75
+ * ## `"invalid-seek"`
76
+ *
77
+ * ## `"text-file-busy"`
78
+ *
79
+ * ## `"cross-device"`
80
+ */
81
+ export type ErrorCode = 'access' | 'would-block' | 'already' | 'bad-descriptor' | 'busy' | 'deadlock' | 'quota' | 'exist' | 'file-too-large' | 'illegal-byte-sequence' | 'in-progress' | 'interrupted' | 'invalid' | 'io' | 'is-directory' | 'loop' | 'too-many-links' | 'message-size' | 'name-too-long' | 'no-device' | 'no-entry' | 'no-lock' | 'insufficient-memory' | 'insufficient-space' | 'not-directory' | 'not-empty' | 'not-recoverable' | 'unsupported' | 'no-tty' | 'no-such-device' | 'overflow' | 'not-permitted' | 'pipe' | 'read-only' | 'invalid-seek' | 'text-file-busy' | 'cross-device';
82
+ export type OutputStream = import('./wasi-io-streams.js').OutputStream;
83
+ export interface DescriptorFlags {
84
+ read?: boolean,
85
+ write?: boolean,
86
+ fileIntegritySync?: boolean,
87
+ dataIntegritySync?: boolean,
88
+ requestedWriteSync?: boolean,
89
+ mutateDirectory?: boolean,
90
+ }
91
+ /**
92
+ * # Variants
93
+ *
94
+ * ## `"unknown"`
95
+ *
96
+ * ## `"block-device"`
97
+ *
98
+ * ## `"character-device"`
99
+ *
100
+ * ## `"directory"`
101
+ *
102
+ * ## `"fifo"`
103
+ *
104
+ * ## `"symbolic-link"`
105
+ *
106
+ * ## `"regular-file"`
107
+ *
108
+ * ## `"socket"`
109
+ */
110
+ export type DescriptorType = 'unknown' | 'block-device' | 'character-device' | 'directory' | 'fifo' | 'symbolic-link' | 'regular-file' | 'socket';
111
+ export type LinkCount = bigint;
112
+ export type Datetime = import('./wasi-clocks-wall-clock.js').Datetime;
113
+ export interface DescriptorStat {
114
+ type: DescriptorType,
115
+ linkCount: LinkCount,
116
+ size: Filesize,
117
+ dataAccessTimestamp?: Datetime,
118
+ dataModificationTimestamp?: Datetime,
119
+ statusChangeTimestamp?: Datetime,
120
+ }
121
+ export interface PathFlags {
122
+ symlinkFollow?: boolean,
123
+ }
124
+ export interface MetadataHashValue {
125
+ lower: bigint,
126
+ upper: bigint,
127
+ }
128
+
129
+ export class Descriptor {
130
+ /**
131
+ * This type does not have a public constructor.
132
+ */
133
+ private constructor();
134
+ readViaStream(offset: Filesize): InputStream;
135
+ writeViaStream(offset: Filesize): OutputStream;
136
+ appendViaStream(): OutputStream;
137
+ getFlags(): DescriptorFlags;
138
+ stat(): DescriptorStat;
139
+ statAt(pathFlags: PathFlags, path: string): DescriptorStat;
140
+ metadataHash(): MetadataHashValue;
141
+ metadataHashAt(pathFlags: PathFlags, path: string): MetadataHashValue;
142
+ }
@@ -53,6 +53,31 @@ export interface DirectUrlInfoVcs {
53
53
  tag: 'vcs',
54
54
  val: VcsUrlInfo,
55
55
  }
56
+ export interface ParsedVcsInfo {
57
+ url: string,
58
+ rev?: string,
59
+ }
60
+ export interface ParsedReqEntry {
61
+ name?: string,
62
+ pep508: string,
63
+ extras: Array<string>,
64
+ markers?: string,
65
+ versionSpec?: string,
66
+ url?: string,
67
+ hashes: Array<string>,
68
+ editable: boolean,
69
+ vcs?: ParsedVcsInfo,
70
+ givenUrl?: string,
71
+ }
72
+ export interface ParsedRequirementsTxt {
73
+ requirements: Array<ParsedReqEntry>,
74
+ editables: Array<ParsedReqEntry>,
75
+ indexUrl?: string,
76
+ extraIndexUrls: Array<string>,
77
+ findLinks: Array<string>,
78
+ noIndex: boolean,
79
+ }
80
+ import type * as VercelPythonAnalysisHostUtils from './interfaces/vercel-python-analysis-host-utils.js'; // vercel:python-analysis/host-utils
56
81
  import type * as WasiCliEnvironment from './interfaces/wasi-cli-environment.js'; // wasi:cli/environment@0.2.6
57
82
  import type * as WasiCliExit from './interfaces/wasi-cli-exit.js'; // wasi:cli/exit@0.2.6
58
83
  import type * as WasiCliStderr from './interfaces/wasi-cli-stderr.js'; // wasi:cli/stderr@0.2.6
@@ -63,11 +88,15 @@ import type * as WasiCliTerminalOutput from './interfaces/wasi-cli-terminal-outp
63
88
  import type * as WasiCliTerminalStderr from './interfaces/wasi-cli-terminal-stderr.js'; // wasi:cli/terminal-stderr@0.2.6
64
89
  import type * as WasiCliTerminalStdin from './interfaces/wasi-cli-terminal-stdin.js'; // wasi:cli/terminal-stdin@0.2.6
65
90
  import type * as WasiCliTerminalStdout from './interfaces/wasi-cli-terminal-stdout.js'; // wasi:cli/terminal-stdout@0.2.6
91
+ import type * as WasiClocksWallClock from './interfaces/wasi-clocks-wall-clock.js'; // wasi:clocks/wall-clock@0.2.6
92
+ import type * as WasiFilesystemPreopens from './interfaces/wasi-filesystem-preopens.js'; // wasi:filesystem/preopens@0.2.6
93
+ import type * as WasiFilesystemTypes from './interfaces/wasi-filesystem-types.js'; // wasi:filesystem/types@0.2.6
66
94
  import type * as WasiIoError from './interfaces/wasi-io-error.js'; // wasi:io/error@0.2.6
67
95
  import type * as WasiIoPoll from './interfaces/wasi-io-poll.js'; // wasi:io/poll@0.2.6
68
96
  import type * as WasiIoStreams from './interfaces/wasi-io-streams.js'; // wasi:io/streams@0.2.6
69
97
  import type * as WasiRandomInsecureSeed from './interfaces/wasi-random-insecure-seed.js'; // wasi:random/insecure-seed@0.2.6
70
98
  export interface ImportObject {
99
+ 'vercel:python-analysis/host-utils': typeof VercelPythonAnalysisHostUtils,
71
100
  'wasi:cli/environment@0.2.6': typeof WasiCliEnvironment,
72
101
  'wasi:cli/exit@0.2.6': typeof WasiCliExit,
73
102
  'wasi:cli/stderr@0.2.6': typeof WasiCliStderr,
@@ -78,6 +107,9 @@ export interface ImportObject {
78
107
  'wasi:cli/terminal-stderr@0.2.6': typeof WasiCliTerminalStderr,
79
108
  'wasi:cli/terminal-stdin@0.2.6': typeof WasiCliTerminalStdin,
80
109
  'wasi:cli/terminal-stdout@0.2.6': typeof WasiCliTerminalStdout,
110
+ 'wasi:clocks/wall-clock@0.2.6': typeof WasiClocksWallClock,
111
+ 'wasi:filesystem/preopens@0.2.6': typeof WasiFilesystemPreopens,
112
+ 'wasi:filesystem/types@0.2.6': typeof WasiFilesystemTypes,
81
113
  'wasi:io/error@0.2.6': typeof WasiIoError,
82
114
  'wasi:io/poll@0.2.6': typeof WasiIoPoll,
83
115
  'wasi:io/streams@0.2.6': typeof WasiIoStreams,
@@ -91,6 +123,8 @@ export interface Root {
91
123
  parseRecord(content: string): Array<RecordEntry>,
92
124
  parseDirectUrl(content: string): DirectUrlInfo,
93
125
  normalizePackageName(name: string): string,
126
+ parseRequirementsTxt(content: string, workingDir: string | undefined, filename: string | undefined): ParsedRequirementsTxt,
127
+ isWheelCompatible(wheelFilename: string, pythonMajor: number, pythonMinor: number, osName: string, archName: string, osMajor: number, osMinor: number): boolean,
94
128
  }
95
129
 
96
130
  /**