@oh-my-pi/pi-natives 9.6.4 → 9.8.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/README.md CHANGED
@@ -11,7 +11,7 @@ Native Rust functionality via N-API.
11
11
  ## Usage
12
12
 
13
13
  ```typescript
14
- import { grep, find, PhotonImage, resize, SamplingFilter } from "@oh-my-pi/pi-natives";
14
+ import { grep, find, PhotonImage, SamplingFilter, ImageFormat } from "@oh-my-pi/pi-natives";
15
15
 
16
16
  // Grep for a pattern
17
17
  const results = await grep({
@@ -29,9 +29,9 @@ const files = await find({
29
29
  });
30
30
 
31
31
  // Image processing
32
- using image = await PhotonImage.new_from_byteslice(bytes);
33
- using resized = await resize(image, 800, 600, SamplingFilter.Lanczos3);
34
- const pngBytes = await resized.get_bytes();
32
+ const image = await PhotonImage.parse(bytes);
33
+ const resized = await image.resize(800, 600, SamplingFilter.Lanczos3);
34
+ const pngBytes = await resized.encode(ImageFormat.PNG, 100);
35
35
  ```
36
36
 
37
37
  ## Building
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oh-my-pi/pi-natives",
3
- "version": "9.6.4",
3
+ "version": "9.8.0",
4
4
  "description": "Native Rust functionality via N-API",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -17,6 +17,8 @@
17
17
  ],
18
18
  "scripts": {
19
19
  "build:native": "bun scripts/build-native.ts",
20
+ "dev:native": "bun scripts/build-native.ts --dev",
21
+ "embed:native": "bun scripts/embed-native.ts",
20
22
  "check": "biome check . && tsgo -p tsconfig.json",
21
23
  "fix": "biome check --write --unsafe .",
22
24
  "test": "bun run build:native && bun test",
@@ -30,7 +32,7 @@
30
32
  "directory": "packages/natives"
31
33
  },
32
34
  "dependencies": {
33
- "@oh-my-pi/pi-utils": "9.6.4"
35
+ "@oh-my-pi/pi-utils": "9.8.0"
34
36
  },
35
37
  "devDependencies": {
36
38
  "@types/node": "^25.0.10"
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Base types for native bindings.
3
+ * Modules extend this interface via declaration merging.
4
+ */
5
+
6
+ /** Callback type for threadsafe functions from N-API. */
7
+ export type TsFunc<T> = (error: Error | null, value: T) => void;
8
+
9
+ /**
10
+ * Native bindings interface.
11
+ * Extended by each module via declaration merging.
12
+ */
13
+ export interface NativeBindings {}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Clipboard helpers backed by native arboard bindings.
3
+ */
4
+
5
+ import { native } from "../native";
6
+
7
+ export type { ClipboardImage } from "./types";
8
+
9
+ export const { copyToClipboard, readImageFromClipboard } = native;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Types for clipboard operations.
3
+ */
4
+
5
+ /** PNG-encoded clipboard image payload. */
6
+ export interface ClipboardImage {
7
+ /** PNG image bytes. */
8
+ data: Uint8Array;
9
+ /** MIME type for the PNG payload. */
10
+ mimeType: string;
11
+ }
12
+
13
+ declare module "../bindings" {
14
+ /** Native clipboard operations exposed by the bindings layer. */
15
+ interface NativeBindings {
16
+ /**
17
+ * Copy text to the system clipboard.
18
+ * @param text - UTF-8 text to place on the clipboard.
19
+ */
20
+ copyToClipboard(text: string): Promise<void>;
21
+ /**
22
+ * Read an image from the clipboard.
23
+ * @returns PNG payload or null when no image is available.
24
+ */
25
+ readImageFromClipboard(): Promise<ClipboardImage | null>;
26
+ }
27
+ }
@@ -0,0 +1,7 @@
1
+ export interface EmbeddedAddon {
2
+ platform: string;
3
+ version: string;
4
+ filePath: string;
5
+ }
6
+
7
+ export const embeddedAddon: EmbeddedAddon | null = null;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * File discovery API powered by globset + ignore crate.
3
+ */
4
+
5
+ import * as path from "node:path";
6
+ import { native } from "../native";
7
+ import type { FindMatch, FindOptions, FindResult } from "./types";
8
+
9
+ export type { FindMatch, FindOptions, FindResult } from "./types";
10
+
11
+ /**
12
+ * Find files matching a glob pattern.
13
+ * Respects .gitignore by default.
14
+ */
15
+ export async function find(options: FindOptions, onMatch?: (match: FindMatch) => void): Promise<FindResult> {
16
+ const searchPath = path.resolve(options.path);
17
+ const pattern = options.pattern || "*";
18
+
19
+ // Convert simple patterns to recursive globs if needed
20
+ const globPattern = pattern.includes("/") || pattern.startsWith("**") ? pattern : `**/${pattern}`;
21
+
22
+ // napi-rs ThreadsafeFunction passes (error, value) - skip callback on error
23
+ const cb = onMatch ? (err: Error | null, m: FindMatch) => !err && onMatch(m) : undefined;
24
+
25
+ return native.find(
26
+ {
27
+ ...options,
28
+ path: searchPath,
29
+ pattern: globPattern,
30
+ hidden: options.hidden ?? false,
31
+ gitignore: options.gitignore ?? true,
32
+ },
33
+ cb,
34
+ );
35
+ }
package/src/find/types.ts CHANGED
@@ -2,30 +2,51 @@
2
2
  * Types for native find API.
3
3
  */
4
4
 
5
+ import type { TsFunc } from "../bindings";
6
+
7
+ /** Options for discovering files and directories. */
5
8
  export interface FindOptions {
6
- /** Glob pattern to match (e.g., `*.ts`) */
9
+ /** Glob pattern to match (e.g., `*.ts`). */
7
10
  pattern: string;
8
- /** Directory to search */
11
+ /** Directory to search. */
9
12
  path: string;
10
- /** Filter by file type: "file", "dir", or "symlink" */
13
+ /** Filter by file type: "file", "dir", or "symlink". */
11
14
  fileType?: "file" | "dir" | "symlink";
12
- /** Include hidden files (default: false) */
15
+ /** Include hidden files (default: false). */
13
16
  hidden?: boolean;
14
- /** Maximum number of results */
17
+ /** Maximum number of results to return. */
15
18
  maxResults?: number;
16
- /** Respect .gitignore files (default: true) */
19
+ /** Respect .gitignore files (default: true). */
17
20
  gitignore?: boolean;
18
- /** Sort results by mtime (most recent first) before applying limit */
21
+ /** Sort results by mtime (most recent first) before applying limit. */
19
22
  sortByMtime?: boolean;
20
23
  }
21
24
 
25
+ /** A single filesystem match. */
22
26
  export interface FindMatch {
27
+ /** Relative path from the search root. */
23
28
  path: string;
29
+ /** Resolved filesystem type for the match. */
24
30
  fileType: "file" | "dir" | "symlink";
31
+ /** Modification time in milliseconds since epoch, if available. */
25
32
  mtime?: number;
26
33
  }
27
34
 
35
+ /** Result of a find operation. */
28
36
  export interface FindResult {
37
+ /** Matched filesystem entries. */
29
38
  matches: FindMatch[];
39
+ /** Number of matches returned after limits are applied. */
30
40
  totalMatches: number;
31
41
  }
42
+
43
+ declare module "../bindings" {
44
+ interface NativeBindings {
45
+ /**
46
+ * Find filesystem entries matching a glob pattern.
47
+ * @param options Search options that control globbing and filters.
48
+ * @param onMatch Optional callback for streaming matches as they are found.
49
+ */
50
+ find(options: FindOptions, onMatch?: TsFunc<FindMatch>): Promise<FindResult>;
51
+ }
52
+ }
package/src/grep/types.ts CHANGED
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Types for grep/search operations.
3
+ */
4
+
5
+ import type { TsFunc } from "../bindings";
1
6
  import type { RequestOptions } from "../request-options";
2
7
 
3
8
  /** Options for searching files. */
@@ -28,32 +33,51 @@ export interface GrepOptions extends RequestOptions {
28
33
  mode?: "content" | "filesWithMatches" | "count";
29
34
  }
30
35
 
36
+ /** A context line returned around a match. */
31
37
  export interface ContextLine {
38
+ /** 1-indexed line number. */
32
39
  lineNumber: number;
40
+ /** Line content (trimmed line ending). */
33
41
  line: string;
34
42
  }
35
43
 
44
+ /** A single grep match or per-file count entry. */
36
45
  export interface GrepMatch {
46
+ /** File path for the match (relative for directory searches). */
37
47
  path: string;
48
+ /** 1-indexed line number (0 for count-only entries). */
38
49
  lineNumber: number;
50
+ /** Matched line content (empty for count-only entries). */
39
51
  line: string;
52
+ /** Context lines before the match. */
40
53
  contextBefore?: ContextLine[];
54
+ /** Context lines after the match. */
41
55
  contextAfter?: ContextLine[];
56
+ /** Whether the line was truncated. */
42
57
  truncated?: boolean;
58
+ /** Per-file match count (count mode only). */
43
59
  matchCount?: number;
44
60
  }
45
61
 
62
+ /** Summary stats for a grep run. */
46
63
  export interface GrepSummary {
64
+ /** Total matches across all files. */
47
65
  totalMatches: number;
66
+ /** Number of files with at least one match. */
48
67
  filesWithMatches: number;
68
+ /** Number of files searched. */
49
69
  filesSearched: number;
70
+ /** Whether the limit/offset stopped the search early. */
50
71
  limitReached?: boolean;
51
72
  }
52
73
 
74
+ /** Full grep result including matches and summary counts. */
53
75
  export interface GrepResult extends GrepSummary {
76
+ /** Matches or per-file counts, depending on mode. */
54
77
  matches: GrepMatch[];
55
78
  }
56
79
 
80
+ /** Options for searching in-memory content. */
57
81
  export interface SearchOptions {
58
82
  /** Regex pattern to search for */
59
83
  pattern: string;
@@ -73,22 +97,35 @@ export interface SearchOptions {
73
97
  mode?: "content" | "count";
74
98
  }
75
99
 
100
+ /** A single content match. */
76
101
  export interface SearchMatch {
102
+ /** 1-indexed line number. */
77
103
  lineNumber: number;
104
+ /** Matched line content. */
78
105
  line: string;
106
+ /** Context lines before the match. */
79
107
  contextBefore?: ContextLine[];
108
+ /** Context lines after the match. */
80
109
  contextAfter?: ContextLine[];
110
+ /** Whether the line was truncated. */
81
111
  truncated?: boolean;
82
112
  }
83
113
 
114
+ /** Result of searching in-memory content. */
84
115
  export interface SearchResult {
116
+ /** All matches found. */
85
117
  matches: SearchMatch[];
118
+ /** Total number of matches (may exceed `matches.length`). */
86
119
  matchCount: number;
120
+ /** Whether the limit was reached. */
87
121
  limitReached: boolean;
122
+ /** Error message, if any. */
88
123
  error?: string;
89
124
  }
90
125
 
126
+ /** Legacy alias for WASM match output. */
91
127
  export type WasmMatch = SearchMatch;
128
+ /** Legacy alias for WASM search output. */
92
129
  export type WasmSearchResult = SearchResult;
93
130
 
94
131
  /** Options for fuzzy file path search. */
@@ -120,3 +157,21 @@ export interface FuzzyFindResult {
120
157
  /** Total number of matches found (may exceed `matches.length`). */
121
158
  totalMatches: number;
122
159
  }
160
+
161
+ declare module "../bindings" {
162
+ interface NativeBindings {
163
+ /** Fuzzy file path search for autocomplete. */
164
+ fuzzyFind(options: FuzzyFindOptions): Promise<FuzzyFindResult>;
165
+ /** Search files for a regex pattern. */
166
+ grep(options: GrepOptions, onMatch?: TsFunc<GrepMatch>): Promise<GrepResult>;
167
+ /** Search in-memory content for a regex pattern. */
168
+ search(content: string | Uint8Array, options: SearchOptions): SearchResult;
169
+ /** Quick check if content matches a pattern. */
170
+ hasMatch(
171
+ content: string | Uint8Array,
172
+ pattern: string | Uint8Array,
173
+ ignoreCase: boolean,
174
+ multiline: boolean,
175
+ ): boolean;
176
+ }
177
+ }
@@ -4,48 +4,6 @@
4
4
 
5
5
  import { native } from "../native";
6
6
 
7
- /**
8
- * Theme colors for syntax highlighting.
9
- * Each color should be an ANSI escape sequence (e.g., "\x1b[38;2;255;0;0m").
10
- */
11
- export interface HighlightColors {
12
- comment: string;
13
- keyword: string;
14
- function: string;
15
- variable: string;
16
- string: string;
17
- number: string;
18
- type: string;
19
- operator: string;
20
- punctuation: string;
21
- /** Color for diff inserted lines (+). Optional, defaults to no coloring. */
22
- inserted?: string;
23
- /** Color for diff deleted lines (-). Optional, defaults to no coloring. */
24
- deleted?: string;
25
- }
26
-
27
- /**
28
- * Highlight code with syntax coloring.
29
- *
30
- * @param code - The source code to highlight
31
- * @param lang - Optional language identifier (e.g., "rust", "typescript", "python")
32
- * @param colors - Theme colors as ANSI escape sequences
33
- * @returns Highlighted code as a single string with ANSI color codes
34
- */
35
- export function highlightCode(code: string, lang: string | undefined, colors: HighlightColors): string {
36
- return native.highlightCode(code, lang, colors);
37
- }
7
+ export type { HighlightColors } from "./types";
38
8
 
39
- /**
40
- * Check if a language is supported for highlighting.
41
- */
42
- export function supportsLanguage(lang: string): boolean {
43
- return native.supportsLanguage(lang);
44
- }
45
-
46
- /**
47
- * Get list of all supported languages.
48
- */
49
- export function getSupportedLanguages(): string[] {
50
- return native.getSupportedLanguages();
51
- }
9
+ export const { highlightCode, supportsLanguage, getSupportedLanguages } = native;
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Types for syntax highlighting.
3
+ */
4
+
5
+ /**
6
+ * Theme colors for syntax highlighting.
7
+ * Each color should be an ANSI escape sequence (e.g., "\x1b[38;2;255;0;0m").
8
+ */
9
+ export interface HighlightColors {
10
+ /** ANSI color for comments. */
11
+ comment: string;
12
+ /** ANSI color for keywords. */
13
+ keyword: string;
14
+ /** ANSI color for function names. */
15
+ function: string;
16
+ /** ANSI color for variables and identifiers. */
17
+ variable: string;
18
+ /** ANSI color for string literals. */
19
+ string: string;
20
+ /** ANSI color for numeric literals. */
21
+ number: string;
22
+ /** ANSI color for type identifiers. */
23
+ type: string;
24
+ /** ANSI color for operators. */
25
+ operator: string;
26
+ /** ANSI color for punctuation tokens. */
27
+ punctuation: string;
28
+ /** Color for diff inserted lines (+). */
29
+ inserted?: string;
30
+ /** Color for diff deleted lines (-). */
31
+ deleted?: string;
32
+ }
33
+
34
+ declare module "../bindings" {
35
+ interface NativeBindings {
36
+ /**
37
+ * Highlight code with syntax coloring.
38
+ * @param code Source code to highlight.
39
+ * @param lang Language name, extension, or null for plain text.
40
+ * @param colors ANSI color palette for semantic scopes.
41
+ * @returns Highlighted code with ANSI color codes.
42
+ */
43
+ highlightCode(code: string, lang: string | null | undefined, colors: HighlightColors): string;
44
+ /**
45
+ * Check if a language is supported for highlighting.
46
+ * @param lang Language name or extension to test.
47
+ * @returns True when highlighting is available.
48
+ */
49
+ supportsLanguage(lang: string): boolean;
50
+ /**
51
+ * Get list of all supported languages.
52
+ * @returns Syntect language names supported by the native highlighter.
53
+ */
54
+ getSupportedLanguages(): string[];
55
+ }
56
+ }
package/src/html/types.ts CHANGED
@@ -2,9 +2,23 @@
2
2
  * Types for HTML to Markdown conversion.
3
3
  */
4
4
 
5
+ /** Options controlling HTML preprocessing and output. */
5
6
  export interface HtmlToMarkdownOptions {
6
- /** Remove navigation elements, forms, headers, footers */
7
+ /** Remove navigation elements, forms, headers, and footers. */
7
8
  cleanContent?: boolean;
8
- /** Skip images during conversion */
9
+ /** Skip images during conversion. */
9
10
  skipImages?: boolean;
10
11
  }
12
+
13
+ declare module "../bindings" {
14
+ /** Native HTML utilities exposed by the Rust bindings. */
15
+ interface NativeBindings {
16
+ /**
17
+ * Convert HTML to Markdown.
18
+ * @param html HTML source to convert.
19
+ * @param options Optional conversion settings.
20
+ * @returns Markdown output.
21
+ */
22
+ htmlToMarkdown(html: string, options?: HtmlToMarkdownOptions | null): Promise<string>;
23
+ }
24
+ }
@@ -2,112 +2,12 @@
2
2
  * Image processing via native bindings.
3
3
  */
4
4
 
5
- import { type NativePhotonImage, native } from "../native";
5
+ import { native } from "../native";
6
6
 
7
- const images = new Map<number, NativePhotonImage>();
8
- let nextHandle = 1;
7
+ export { ImageFormat, type PhotonImageConstructor, SamplingFilter } from "./types";
9
8
 
10
- function registerImage(image: NativePhotonImage): number {
11
- const handle = nextHandle++;
12
- images.set(handle, image);
13
- return handle;
14
- }
9
+ /** PhotonImage class for image manipulation. Use PhotonImage.parse() to create instances. */
10
+ export const PhotonImage = native.PhotonImage;
15
11
 
16
- function getImage(handle: number): NativePhotonImage {
17
- const image = images.get(handle);
18
- if (!image) {
19
- throw new Error("Image already freed");
20
- }
21
- return image;
22
- }
23
-
24
- export const SamplingFilter = native.SamplingFilter;
25
- export type SamplingFilter = (typeof SamplingFilter)[keyof typeof SamplingFilter];
26
-
27
- /**
28
- * Image handle for async operations.
29
- */
30
- export class PhotonImage {
31
- #handle: number;
32
- #freed = false;
33
-
34
- private constructor(handle: number) {
35
- this.#handle = handle;
36
- }
37
-
38
- /** @internal */
39
- static _create(handle: number): PhotonImage {
40
- if (!images.has(handle)) {
41
- throw new Error("Invalid image handle");
42
- }
43
- return new PhotonImage(handle);
44
- }
45
-
46
- /**
47
- * Load an image from encoded bytes (PNG, JPEG, WebP, GIF).
48
- */
49
- static async new_from_byteslice(bytes: Uint8Array): Promise<PhotonImage> {
50
- const image = await native.PhotonImage.newFromByteslice(bytes);
51
- const handle = registerImage(image);
52
- return new PhotonImage(handle);
53
- }
54
-
55
- /** @internal */
56
- _getHandle(): number {
57
- if (this.#freed) throw new Error("Image already freed");
58
- return this.#handle;
59
- }
60
-
61
- #native(): NativePhotonImage {
62
- if (this.#freed) throw new Error("Image already freed");
63
- return getImage(this.#handle);
64
- }
65
-
66
- /** Get image width in pixels. */
67
- get_width(): number {
68
- return this.#native().getWidth();
69
- }
70
-
71
- /** Get image height in pixels. */
72
- get_height(): number {
73
- return this.#native().getHeight();
74
- }
75
-
76
- /** Export as PNG bytes. */
77
- async get_bytes(): Promise<Uint8Array> {
78
- return this.#native().getBytes();
79
- }
80
-
81
- /** Export as JPEG bytes with specified quality (0-100). */
82
- async get_bytes_jpeg(quality: number): Promise<Uint8Array> {
83
- return this.#native().getBytesJpeg(quality);
84
- }
85
-
86
- /** Release native resources. */
87
- free() {
88
- if (this.#freed) return;
89
- this.#freed = true;
90
- images.delete(this.#handle);
91
- }
92
-
93
- /** Alias for free() to support using-declarations. */
94
- [Symbol.dispose](): void {
95
- this.free();
96
- }
97
- }
98
-
99
- /**
100
- * Resize an image to the specified dimensions.
101
- * Returns a new PhotonImage (original is not modified).
102
- */
103
- export async function resize(image: PhotonImage, width: number, height: number, filter: number): Promise<PhotonImage> {
104
- const nativeImage = getImage(image._getHandle());
105
- const resized = await nativeImage.resize(width, height, filter);
106
- const handle = registerImage(resized);
107
- return PhotonImage._create(handle);
108
- }
109
-
110
- /**
111
- * Terminate image resources (no-op for native bindings).
112
- */
113
- export function terminate(): void {}
12
+ /** PhotonImage instance type. */
13
+ export type PhotonImage = import("./types").PhotonImage;
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Types for image processing.
3
+ */
4
+
5
+ /** Output format for image encoding. */
6
+ export const enum ImageFormat {
7
+ /** PNG encoded bytes. */
8
+ PNG = 0,
9
+ /** JPEG encoded bytes. */
10
+ JPEG = 1,
11
+ /** WebP encoded bytes. */
12
+ WEBP = 2,
13
+ /** GIF encoded bytes. */
14
+ GIF = 3,
15
+ }
16
+
17
+ /** Sampling filter for resize operations. */
18
+ export const enum SamplingFilter {
19
+ /** Nearest-neighbor sampling (fast, low quality). */
20
+ Nearest = 1,
21
+ /** Triangle filter (linear interpolation). */
22
+ Triangle = 2,
23
+ /** Catmull-Rom filter with sharper edges. */
24
+ CatmullRom = 3,
25
+ /** Gaussian filter for smoother results. */
26
+ Gaussian = 4,
27
+ /** Lanczos3 filter for high-quality downscaling. */
28
+ Lanczos3 = 5,
29
+ }
30
+
31
+ /** Image container for native image operations. */
32
+ export interface PhotonImage {
33
+ /** Image width in pixels. */
34
+ get width(): number;
35
+ /** Image height in pixels. */
36
+ get height(): number;
37
+ /**
38
+ * Encode the image using the requested format and quality.
39
+ * Returns the encoded image bytes.
40
+ */
41
+ encode(format: ImageFormat, quality: number): Promise<Uint8Array>;
42
+ /**
43
+ * Resize the image to the requested dimensions with the filter.
44
+ * Returns a new image instance.
45
+ */
46
+ resize(width: number, height: number, filter: SamplingFilter): Promise<PhotonImage>;
47
+ }
48
+
49
+ /** Static entrypoints for creating `PhotonImage` instances. */
50
+ export interface PhotonImageConstructor {
51
+ /** Parse image bytes (PNG, JPEG, WebP, GIF) into a native image. */
52
+ parse(bytes: Uint8Array): Promise<PhotonImage>;
53
+ /** Instance prototype reference. */
54
+ prototype: PhotonImage;
55
+ }
56
+
57
+ declare module "../bindings" {
58
+ /** Native bindings for image operations. */
59
+ interface NativeBindings {
60
+ /** Sampling filters exposed by the native module. */
61
+ SamplingFilter: typeof SamplingFilter;
62
+ /** Photon image constructor exposed by the native module. */
63
+ PhotonImage: PhotonImageConstructor;
64
+ }
65
+ }