@vercel/python-analysis 0.10.1 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -63,11 +63,12 @@ __export(src_exports, {
63
63
  UvConfigWorkspaceSchema: () => UvConfigWorkspaceSchema,
64
64
  UvIndexEntrySchema: () => UvIndexEntrySchema,
65
65
  classifyPackages: () => classifyPackages,
66
- containsAppOrHandler: () => containsAppOrHandler,
67
66
  containsTopLevelCallable: () => containsTopLevelCallable,
68
67
  createMinimalManifest: () => createMinimalManifest,
69
68
  discoverPythonPackage: () => discoverPythonPackage,
69
+ evaluateMarker: () => evaluateMarker,
70
70
  extendDistRecord: () => extendDistRecord,
71
+ findAppOrHandler: () => findAppOrHandler,
71
72
  getStringConstant: () => getStringConstant,
72
73
  isPrivatePackageSource: () => isPrivatePackageSource,
73
74
  isWheelCompatible: () => isWheelCompatible,
@@ -203,12 +204,12 @@ async function importWasmModule() {
203
204
  }
204
205
 
205
206
  // src/semantic/entrypoints.ts
206
- async function containsAppOrHandler(source) {
207
+ async function findAppOrHandler(source) {
207
208
  if (!source.includes("app") && !source.includes("application") && !source.includes("handler") && !source.includes("Handler")) {
208
- return false;
209
+ return null;
209
210
  }
210
211
  const mod = await importWasmModule();
211
- return mod.containsAppOrHandler(source);
212
+ return mod.findAppOrHandler(source) ?? null;
212
213
  }
213
214
  async function containsTopLevelCallable(source, name) {
214
215
  if (!source.includes(name)) {
@@ -2100,6 +2101,16 @@ async function isWheelCompatible(wheelFilename, pythonMajor, pythonMinor, osName
2100
2101
  osMinor
2101
2102
  );
2102
2103
  }
2104
+ async function evaluateMarker(marker, pythonMajor, pythonMinor, sysPlatform, platformMachine) {
2105
+ const mod = await importWasmModule();
2106
+ return mod.evaluateMarker(
2107
+ marker,
2108
+ pythonMajor,
2109
+ pythonMinor,
2110
+ sysPlatform,
2111
+ platformMachine
2112
+ );
2113
+ }
2103
2114
 
2104
2115
  // src/manifest/python-selector.ts
2105
2116
  function selectPython(constraints, available) {
@@ -2407,11 +2418,12 @@ var HashDigestSchema = hashDigestSchema;
2407
2418
  UvConfigWorkspaceSchema,
2408
2419
  UvIndexEntrySchema,
2409
2420
  classifyPackages,
2410
- containsAppOrHandler,
2411
2421
  containsTopLevelCallable,
2412
2422
  createMinimalManifest,
2413
2423
  discoverPythonPackage,
2424
+ evaluateMarker,
2414
2425
  extendDistRecord,
2426
+ findAppOrHandler,
2415
2427
  getStringConstant,
2416
2428
  isPrivatePackageSource,
2417
2429
  isWheelCompatible,
package/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * @module @vercel/python-analysis
8
8
  */
9
- export { containsAppOrHandler, containsTopLevelCallable, getStringConstant, } from './semantic/entrypoints';
9
+ export { findAppOrHandler, containsTopLevelCallable, getStringConstant, } from './semantic/entrypoints';
10
10
  export type { Distribution, DistributionIndex, PackagePath, DirectUrlInfo, } from './manifest/dist-metadata';
11
11
  export { extendDistRecord, scanDistributions } from './manifest/dist-metadata';
12
12
  export type { PythonConfig, PythonConfigs, PythonLockFile, PythonManifest, PythonManifestOrigin, PythonPackage, PythonVersionConfig, } from './manifest/package';
@@ -14,7 +14,7 @@ export { discoverPythonPackage, PythonConfigKind, PythonLockFileKind, PythonMani
14
14
  export { createMinimalManifest, stringifyManifest, type CreateMinimalManifestOptions, } from './manifest/serialize';
15
15
  export type { ClassifyPackagesOptions, PackageClassification, UvLockFile, UvLockPackage, UvLockPackageSource, UvLockWheel, } from './manifest/uv-lock-parser';
16
16
  export { classifyPackages, isPrivatePackageSource, normalizePackageName, parseUvLock, } from './manifest/uv-lock-parser';
17
- export { isWheelCompatible } from './manifest/wheel-compat';
17
+ export { evaluateMarker, isWheelCompatible, } from './manifest/wheel-compat';
18
18
  export type { PythonSelectionResult, PythonVersionSelectionResult, } from './manifest/python-selector';
19
19
  export { selectPython, selectPythonVersion } from './manifest/python-selector';
20
20
  export { PythonAnalysisError } from './util/error';
package/dist/index.js CHANGED
@@ -120,12 +120,12 @@ async function importWasmModule() {
120
120
  }
121
121
 
122
122
  // src/semantic/entrypoints.ts
123
- async function containsAppOrHandler(source) {
123
+ async function findAppOrHandler(source) {
124
124
  if (!source.includes("app") && !source.includes("application") && !source.includes("handler") && !source.includes("Handler")) {
125
- return false;
125
+ return null;
126
126
  }
127
127
  const mod = await importWasmModule();
128
- return mod.containsAppOrHandler(source);
128
+ return mod.findAppOrHandler(source) ?? null;
129
129
  }
130
130
  async function containsTopLevelCallable(source, name) {
131
131
  if (!source.includes(name)) {
@@ -2020,6 +2020,16 @@ async function isWheelCompatible(wheelFilename, pythonMajor, pythonMinor, osName
2020
2020
  osMinor
2021
2021
  );
2022
2022
  }
2023
+ async function evaluateMarker(marker, pythonMajor, pythonMinor, sysPlatform, platformMachine) {
2024
+ const mod = await importWasmModule();
2025
+ return mod.evaluateMarker(
2026
+ marker,
2027
+ pythonMajor,
2028
+ pythonMinor,
2029
+ sysPlatform,
2030
+ platformMachine
2031
+ );
2032
+ }
2023
2033
 
2024
2034
  // src/manifest/python-selector.ts
2025
2035
  function selectPython(constraints, available) {
@@ -2326,11 +2336,12 @@ export {
2326
2336
  UvConfigWorkspaceSchema,
2327
2337
  UvIndexEntrySchema,
2328
2338
  classifyPackages,
2329
- containsAppOrHandler,
2330
2339
  containsTopLevelCallable,
2331
2340
  createMinimalManifest,
2332
2341
  discoverPythonPackage,
2342
+ evaluateMarker,
2333
2343
  extendDistRecord,
2344
+ findAppOrHandler,
2334
2345
  getStringConstant,
2335
2346
  isPrivatePackageSource,
2336
2347
  isWheelCompatible,
@@ -25,6 +25,7 @@ export interface UvLockPackage {
25
25
  wheels: UvLockWheel[];
26
26
  dependencies?: Array<{
27
27
  name: string;
28
+ marker?: string;
28
29
  }>;
29
30
  }
30
31
  /**
@@ -2,7 +2,7 @@
2
2
  * Check if a wheel filename is compatible with a given platform.
3
3
  *
4
4
  * Uses uv's `WheelFilename::is_compatible()` and `Tags::from_env()` via WASM
5
- * — the same logic uv uses for resolution.
5
+ * -- the same logic uv uses for resolution.
6
6
  *
7
7
  * @param wheelFilename - The wheel filename (e.g. "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.whl")
8
8
  * @param pythonMajor - Python major version (e.g. 3)
@@ -14,3 +14,17 @@
14
14
  * @returns true if the wheel is compatible with the platform
15
15
  */
16
16
  export declare function isWheelCompatible(wheelFilename: string, pythonMajor: number, pythonMinor: number, osName: string, archName: string, osMajor: number, osMinor: number): Promise<boolean>;
17
+ /**
18
+ * Evaluate a PEP 508 environment marker against a target environment.
19
+ *
20
+ * Uses uv's `MarkerTree::evaluate()` via WASM -- the same logic uv uses
21
+ * for dependency resolution.
22
+ *
23
+ * @param marker - PEP 508 marker expression (e.g. "sys_platform == 'win32'")
24
+ * @param pythonMajor - Python major version (e.g. 3)
25
+ * @param pythonMinor - Python minor version (e.g. 12)
26
+ * @param sysPlatform - sys_platform value: "linux", "win32", "darwin"
27
+ * @param platformMachine - platform_machine value: "x86_64", "aarch64", etc.
28
+ * @returns true if the marker is satisfied for the target environment
29
+ */
30
+ export declare function evaluateMarker(marker: string, pythonMajor: number, pythonMinor: number, sysPlatform: string, platformMachine: string): Promise<boolean>;
@@ -12,21 +12,22 @@
12
12
  * accurate AST analysis without requiring a Python runtime.
13
13
  *
14
14
  * @param source - The Python source code to analyze
15
- * @returns Promise that resolves to true if an app or handler is found, false otherwise.
16
- * Returns false for invalid Python syntax.
15
+ * @returns Promise that resolves to the matched variable name (e.g. "app",
16
+ * "application", "handler"), or null if not found.
17
+ * Returns null for invalid Python syntax.
17
18
  *
18
19
  * @example
19
20
  * ```typescript
20
- * import { containsAppOrHandler } from '@vercel/python-analysis';
21
+ * import { findAppOrHandler } from '@vercel/python-analysis';
21
22
  *
22
- * const hasApp = await containsAppOrHandler(`
23
+ * const name = await findAppOrHandler(`
23
24
  * from flask import Flask
24
25
  * app = Flask(__name__)
25
26
  * `);
26
- * console.log(hasApp); // true
27
+ * console.log(name); // "app"
27
28
  * ```
28
29
  */
29
- export declare function containsAppOrHandler(source: string): Promise<boolean>;
30
+ export declare function findAppOrHandler(source: string): Promise<string | null>;
30
31
  /**
31
32
  * Check if a top-level callable with the given name exists in Python source.
32
33
  *
@@ -116,7 +116,7 @@ export interface ImportObject {
116
116
  'wasi:random/insecure-seed@0.2.6': typeof WasiRandomInsecureSeed,
117
117
  }
118
118
  export interface Root {
119
- containsAppOrHandler(source: string): boolean,
119
+ findAppOrHandler(source: string): string | undefined,
120
120
  getStringConstant(source: string, name: string): string | undefined,
121
121
  containsTopLevelCallable(source: string, name: string): boolean,
122
122
  parseDistMetadata(content: Uint8Array): DistMetadata,
@@ -126,6 +126,7 @@ export interface Root {
126
126
  parseRequirementsTxt(content: string, workingDir: string | undefined, filename: string | undefined): ParsedRequirementsTxt,
127
127
  parsePep508(dep: string): ParsedReqEntry,
128
128
  isWheelCompatible(wheelFilename: string, pythonMajor: number, pythonMinor: number, osName: string, archName: string, osMajor: number, osMinor: number): boolean,
129
+ evaluateMarker(marker: string, pythonMajor: number, pythonMinor: number, sysPlatform: string, platformMachine: string): boolean,
129
130
  }
130
131
 
131
132
  /**
@@ -3642,35 +3642,58 @@ let gen = (function* _initGenerator () {
3642
3642
  '9': trampoline22,
3643
3643
  },
3644
3644
  }));
3645
- postReturn0 = exports1['cabi_post_get-string-constant'];
3645
+ postReturn0 = exports1['cabi_post_evaluate-marker'];
3646
3646
  postReturn1 = exports1['cabi_post_parse-dist-metadata'];
3647
3647
  postReturn2 = exports1['cabi_post_parse-record'];
3648
3648
  postReturn3 = exports1['cabi_post_parse-direct-url'];
3649
3649
  postReturn4 = exports1['cabi_post_normalize-package-name'];
3650
3650
  postReturn5 = exports1['cabi_post_parse-requirements-txt'];
3651
3651
  postReturn6 = exports1['cabi_post_parse-pep508'];
3652
- let exports1ContainsAppOrHandler;
3652
+ let exports1FindAppOrHandler;
3653
3653
 
3654
- function containsAppOrHandler(arg0) {
3654
+ function findAppOrHandler(arg0) {
3655
3655
  var ptr0 = utf8Encode(arg0, realloc0, memory0);
3656
3656
  var len0 = utf8EncodedLen;
3657
- _debugLog('[iface="contains-app-or-handler", function="contains-app-or-handler"][Instruction::CallWasm] enter', {
3658
- funcName: 'contains-app-or-handler',
3657
+ _debugLog('[iface="find-app-or-handler", function="find-app-or-handler"][Instruction::CallWasm] enter', {
3658
+ funcName: 'find-app-or-handler',
3659
3659
  paramCount: 2,
3660
3660
  async: false,
3661
- postReturn: false,
3661
+ postReturn: true,
3662
3662
  });
3663
- const _wasm_call_currentTaskID = startCurrentTask(0, false, 'exports1ContainsAppOrHandler');
3664
- const ret = exports1ContainsAppOrHandler(ptr0, len0);
3663
+ const _wasm_call_currentTaskID = startCurrentTask(0, false, 'exports1FindAppOrHandler');
3664
+ const ret = exports1FindAppOrHandler(ptr0, len0);
3665
3665
  endCurrentTask(0);
3666
- var bool1 = ret;
3667
- _debugLog('[iface="contains-app-or-handler", function="contains-app-or-handler"][Instruction::Return]', {
3668
- funcName: 'contains-app-or-handler',
3666
+ let variant2;
3667
+ switch (dataView(memory0).getUint8(ret + 0, true)) {
3668
+ case 0: {
3669
+ variant2 = undefined;
3670
+ break;
3671
+ }
3672
+ case 1: {
3673
+ var ptr1 = dataView(memory0).getUint32(ret + 4, true);
3674
+ var len1 = dataView(memory0).getUint32(ret + 8, true);
3675
+ var result1 = utf8Decoder.decode(new Uint8Array(memory0.buffer, ptr1, len1));
3676
+ variant2 = result1;
3677
+ break;
3678
+ }
3679
+ default: {
3680
+ throw new TypeError('invalid variant discriminant for option');
3681
+ }
3682
+ }
3683
+ _debugLog('[iface="find-app-or-handler", function="find-app-or-handler"][Instruction::Return]', {
3684
+ funcName: 'find-app-or-handler',
3669
3685
  paramCount: 1,
3670
3686
  async: false,
3671
- postReturn: false
3687
+ postReturn: true
3672
3688
  });
3673
- return bool1 == 0 ? false : (bool1 == 1 ? true : throwInvalidBool());
3689
+ const retCopy = variant2;
3690
+
3691
+ let cstate = getOrCreateAsyncState(0);
3692
+ cstate.mayLeave = false;
3693
+ postReturn0(ret);
3694
+ cstate.mayLeave = true;
3695
+ return retCopy;
3696
+
3674
3697
  }
3675
3698
  let exports1GetStringConstant;
3676
3699
 
@@ -5122,7 +5145,70 @@ let gen = (function* _initGenerator () {
5122
5145
  return retCopy.val;
5123
5146
 
5124
5147
  }
5125
- exports1ContainsAppOrHandler = exports1['contains-app-or-handler'];
5148
+ let exports1EvaluateMarker;
5149
+
5150
+ function evaluateMarker(arg0, arg1, arg2, arg3, arg4) {
5151
+ var ptr0 = utf8Encode(arg0, realloc0, memory0);
5152
+ var len0 = utf8EncodedLen;
5153
+ var ptr1 = utf8Encode(arg3, realloc0, memory0);
5154
+ var len1 = utf8EncodedLen;
5155
+ var ptr2 = utf8Encode(arg4, realloc0, memory0);
5156
+ var len2 = utf8EncodedLen;
5157
+ _debugLog('[iface="evaluate-marker", function="evaluate-marker"][Instruction::CallWasm] enter', {
5158
+ funcName: 'evaluate-marker',
5159
+ paramCount: 8,
5160
+ async: false,
5161
+ postReturn: true,
5162
+ });
5163
+ const _wasm_call_currentTaskID = startCurrentTask(0, false, 'exports1EvaluateMarker');
5164
+ const ret = exports1EvaluateMarker(ptr0, len0, toUint8(arg1), toUint8(arg2), ptr1, len1, ptr2, len2);
5165
+ endCurrentTask(0);
5166
+ let variant5;
5167
+ switch (dataView(memory0).getUint8(ret + 0, true)) {
5168
+ case 0: {
5169
+ var bool3 = dataView(memory0).getUint8(ret + 4, true);
5170
+ variant5= {
5171
+ tag: 'ok',
5172
+ val: bool3 == 0 ? false : (bool3 == 1 ? true : throwInvalidBool())
5173
+ };
5174
+ break;
5175
+ }
5176
+ case 1: {
5177
+ var ptr4 = dataView(memory0).getUint32(ret + 4, true);
5178
+ var len4 = dataView(memory0).getUint32(ret + 8, true);
5179
+ var result4 = utf8Decoder.decode(new Uint8Array(memory0.buffer, ptr4, len4));
5180
+ variant5= {
5181
+ tag: 'err',
5182
+ val: result4
5183
+ };
5184
+ break;
5185
+ }
5186
+ default: {
5187
+ throw new TypeError('invalid variant discriminant for expected');
5188
+ }
5189
+ }
5190
+ _debugLog('[iface="evaluate-marker", function="evaluate-marker"][Instruction::Return]', {
5191
+ funcName: 'evaluate-marker',
5192
+ paramCount: 1,
5193
+ async: false,
5194
+ postReturn: true
5195
+ });
5196
+ const retCopy = variant5;
5197
+
5198
+ let cstate = getOrCreateAsyncState(0);
5199
+ cstate.mayLeave = false;
5200
+ postReturn0(ret);
5201
+ cstate.mayLeave = true;
5202
+
5203
+
5204
+
5205
+ if (typeof retCopy === 'object' && retCopy.tag === 'err') {
5206
+ throw new ComponentError(retCopy.val);
5207
+ }
5208
+ return retCopy.val;
5209
+
5210
+ }
5211
+ exports1FindAppOrHandler = exports1['find-app-or-handler'];
5126
5212
  exports1GetStringConstant = exports1['get-string-constant'];
5127
5213
  exports1ContainsTopLevelCallable = exports1['contains-top-level-callable'];
5128
5214
  exports1ParseDistMetadata = exports1['parse-dist-metadata'];
@@ -5132,8 +5218,9 @@ let gen = (function* _initGenerator () {
5132
5218
  exports1ParseRequirementsTxt = exports1['parse-requirements-txt'];
5133
5219
  exports1ParsePep508 = exports1['parse-pep508'];
5134
5220
  exports1IsWheelCompatible = exports1['is-wheel-compatible'];
5221
+ exports1EvaluateMarker = exports1['evaluate-marker'];
5135
5222
 
5136
- return { containsAppOrHandler, containsTopLevelCallable, getStringConstant, isWheelCompatible, normalizePackageName, parseDirectUrl, parseDistMetadata, parsePep508, parseRecord, parseRequirementsTxt, };
5223
+ return { containsTopLevelCallable, evaluateMarker, findAppOrHandler, getStringConstant, isWheelCompatible, normalizePackageName, parseDirectUrl, parseDistMetadata, parsePep508, parseRecord, parseRequirementsTxt, };
5137
5224
  })();
5138
5225
  let promise, resolve, reject;
5139
5226
  function runNext (value) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/python-analysis",
3
- "version": "0.10.1",
3
+ "version": "0.11.0",
4
4
  "main": "./dist/index.cjs",
5
5
  "module": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",