Skip to content

Commit 020e405

Browse files
authored
[RNE Rewrite] style(ts): rename opts to options (#1358)
## Description Changes naming from `opts` to `options` across the board in TS API. Follow-up to [comment](https://github.com/software-mansion/react-native-executorch/pull/1317#:~:text=I%27m%20in%20favour%20of%20options%20everywhere.%20Opts%20suffixes%20in%20config%20object%20field%20and%20types%20are%20fine%20I%20guess.%20Also%20when%20we%20add%20PR%20with%20refactor%20we%20should%20add%20note%20in%20core%2Dguidelines/SKILL.md.) from #1317 ### Introduces a breaking change? - [ ] Yes - [x] No ### Type of change - [ ] Bug fix (change which fixes an issue) - [ ] New feature (change which adds functionality) - [ ] Documentation update (improves or adds clarity to existing documentation) - [x] Other (chores, tests, code style improvements etc.) ### Tested on - [ ] iOS - [ ] Android ### Testing instructions N/A ### Screenshots <!-- Add screenshots here, if applicable --> ### Related issues <!-- Link related issues here using #issue-number --> ### Checklist - [ ] I have performed a self-review of my code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have updated the documentation accordingly - [ ] My changes generate no new warnings ### Additional notes <!-- Include any additional information, assumptions, or context that reviewers might need to understand this PR. -->
1 parent 374ca24 commit 020e405

8 files changed

Lines changed: 59 additions & 57 deletions

File tree

.agents/skills/add-task-pipeline/SKILL.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ When implementing task constructors like `create<Task>` (e.g. `createClassifier`
7474
## 🚫 Avoid / Anti-Patterns
7575

7676
- **Do NOT access tensors by index:** Avoid using `tensors[0]` or `tensors[1]` throughout the function body. Always destructure and name them explicitly.
77+
- **Do NOT name options parameters `opts`:** Always name options function parameters `options` (e.g. `options?: { threshold?: number }`). Suffixes like `Opts` for types or properties (e.g. `MyTaskOptions`, `ModelOpts`, `modelOpts`) are acceptable.
7778
- **Do NOT define extra inner helper functions:** You must define **exactly two** inner functions inside the `create<Task>` constructor: the `dispose` function and the task `worklet` executor function. **Push back hard against implementing any other helper closures inside the constructor scope.** Placing other helper functions (especially those that are called from inside the worklet and use the `create<Task>` scope variables) inside `create<Task>` creates implicit dependencies and closures that capture variables, making the code extremely difficult to reason about and debug.
7879
- **Do NOT leak raw Tensors to consumers:** The returned methods must never return raw `Tensor` objects to the API consumer. Always convert output data to standard JavaScript values/objects before returning.
7980
- **Do NOT cross thread boundaries unnecessarily:** Minimize passing heavy objects between JS and the Worklet thread to avoid serialization overhead.

.agents/skills/core-guidelines/SKILL.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ Use the following index to locate the specific procedural guides for your task:
8080
## 💡 Key Coding Conventions
8181

8282
- **Worklets**: Ensure all TypeScript functions directly wrapping native JSI calls start with the `"worklet";` directive so they are compatible with worklet-based libraries (e.g., React Native Reanimated).
83+
- **Options Parameter Naming**: Always name function and method options parameters `options` (not `opts`, `optsObj`, `taskOpts`, or `chunkOpts`). Using `Opts` as a type or property suffix (e.g. `ModelOpts`, `TaskOpts`, `modelOpts`) is acceptable.
8384
- **Memory Management**: When writing native C++ code with JSI, pay close attention to JSI reference management and handle ExecuTorch lifecycle states safely.
8485
- **Keep Core Clean**: Always build on top of core primitives. Do not modify files in `cpp/core/` or `src/core/` unless you are fixing a bug in the foundational runtime.
8586

packages/react-native-executorch/src/extensions/cv/ops/boxes.ts

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -72,23 +72,23 @@ export function decodeBox<F extends BoxFormat>(
7272
* @category Utils
7373
* @typeParam F Bounding box coordinate format.
7474
* @param box The original BoundingBox.
75-
* @param opts Options defining dimensions and resize modes.
76-
* @param opts.from The source bounds (e.g. model input dimensions).
77-
* @param opts.to The destination bounds (e.g. original image dimensions).
78-
* @param opts.resizeMode The mode used to resize the image {@link ResizeMode}
75+
* @param options Options defining dimensions and resize modes.
76+
* @param options.from The source bounds (e.g. model input dimensions).
77+
* @param options.to The destination bounds (e.g. original image dimensions).
78+
* @param options.resizeMode The mode used to resize the image {@link ResizeMode}
7979
* (excluding `'crop'`).
8080
* @returns The scaled BoundingBox object.
8181
*/
8282
export function scaleBox<F extends BoxFormat>(
8383
box: BoundingBox<F>,
84-
opts: {
84+
options: {
8585
readonly from: { readonly width: number; readonly height: number };
8686
readonly to: { readonly width: number; readonly height: number };
8787
readonly resizeMode: Exclude<ResizeMode, 'crop'>;
8888
}
8989
): BoundingBox<F> {
9090
'worklet';
91-
const { from, to, resizeMode } = opts;
91+
const { from, to, resizeMode } = options;
9292

9393
let scaleX: number;
9494
let scaleY: number;
@@ -107,8 +107,8 @@ export function scaleBox<F extends BoxFormat>(
107107

108108
switch (box.format) {
109109
case 'xyxy': {
110-
const pMin = scalePoint({ x: box.xmin, y: box.ymin }, opts);
111-
const pMax = scalePoint({ x: box.xmax, y: box.ymax }, opts);
110+
const pMin = scalePoint({ x: box.xmin, y: box.ymin }, options);
111+
const pMax = scalePoint({ x: box.xmax, y: box.ymax }, options);
112112
return {
113113
format: 'xyxy',
114114
xmin: pMin.x,
@@ -118,7 +118,7 @@ export function scaleBox<F extends BoxFormat>(
118118
} as BoundingBox<F>;
119119
}
120120
case 'xywh': {
121-
const pMin = scalePoint({ x: box.xmin, y: box.ymin }, opts);
121+
const pMin = scalePoint({ x: box.xmin, y: box.ymin }, options);
122122
return {
123123
format: 'xywh',
124124
xmin: pMin.x,
@@ -128,7 +128,7 @@ export function scaleBox<F extends BoxFormat>(
128128
} as BoundingBox<F>;
129129
}
130130
case 'cxcywh': {
131-
const pCenter = scalePoint({ x: box.cx, y: box.cy }, opts);
131+
const pCenter = scalePoint({ x: box.cx, y: box.cy }, options);
132132
return {
133133
format: 'cxcywh',
134134
cx: pCenter.x,
@@ -164,13 +164,13 @@ export type NmsOptions = {
164164
* @category Utils
165165
* @param boxes Bounding boxes coordinate tensor.
166166
* @param scores Bounding boxes confidence scores tensor.
167-
* @param opts Options configuring NMS thresholds and execution mode.
168-
* @param opts.boxFormat The bounding box format {@link BoxFormat}.
169-
* @param opts.iouThreshold Intersection over Union (IoU) threshold for
167+
* @param options Options configuring NMS thresholds and execution mode.
168+
* @param options.boxFormat The bounding box format {@link BoxFormat}.
169+
* @param options.iouThreshold Intersection over Union (IoU) threshold for
170170
* suppression.
171-
* @param opts.confidenceThreshold Minimum confidence score for candidate
171+
* @param options.confidenceThreshold Minimum confidence score for candidate
172172
* selection.
173-
* @param opts.nmsType The NMS algorithm variant {@link NmsOptions.nmsType}.
173+
* @param options.nmsType The NMS algorithm variant {@link NmsOptions.nmsType}.
174174
* @returns The resulting indices of the non-suppressed boxes:
175175
* - For `standard` NMS: A 1D array of indices (`number[]`) representing the
176176
* selected boxes.
@@ -182,16 +182,16 @@ export type NmsOptions = {
182182
export function nms(
183183
boxes: Tensor,
184184
scores: Tensor,
185-
opts: NmsOptions & { readonly nmsType: 'standard' }
185+
options: NmsOptions & { readonly nmsType: 'standard' }
186186
): number[];
187187
export function nms(
188188
boxes: Tensor,
189189
scores: Tensor,
190-
opts: NmsOptions & { readonly nmsType: 'weighted' }
190+
options: NmsOptions & { readonly nmsType: 'weighted' }
191191
): number[][];
192-
export function nms(boxes: Tensor, scores: Tensor, opts: NmsOptions): number[] | number[][] {
192+
export function nms(boxes: Tensor, scores: Tensor, options: NmsOptions): number[] | number[][] {
193193
'worklet';
194-
return rnexecutorchJsi.cv.nms(boxes, scores, opts);
194+
return rnexecutorchJsi.cv.nms(boxes, scores, options);
195195
}
196196

197197
/**

packages/react-native-executorch/src/extensions/cv/ops/image.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -105,20 +105,20 @@ export type NormalizeOptions = {
105105
* @param dst The pre-allocated destination tensor to write the resized image
106106
* to. `dst` must be in HWC layout and its number of channels must match `src`.
107107
* Shape [H',W',C].
108-
* @param opts Configuration options for resizing.
109-
* @param opts.mode The resize algorithm mode {@link ResizeMode}. Defaults to
108+
* @param options Configuration options for resizing.
109+
* @param options.mode The resize algorithm mode {@link ResizeMode}. Defaults to
110110
* `'stretch'`.
111-
* @param opts.interpolation The pixel interpolation method
111+
* @param options.interpolation The pixel interpolation method
112112
* {@link InterpolationMethod}. Defaults to `'lanczos'`.
113-
* @param opts.padValue Fill value for letterboxing. Defaults to `0`.
113+
* @param options.padValue Fill value for letterboxing. Defaults to `0`.
114114
* @returns The destination tensor containing the resized image.
115115
*/
116-
export function resize(src: Tensor, dst: Tensor, opts?: ResizeOptions): Tensor {
116+
export function resize(src: Tensor, dst: Tensor, options?: ResizeOptions): Tensor {
117117
'worklet';
118118
return rnexecutorchJsi.cv.resize(src, dst, {
119-
mode: opts?.mode ?? 'stretch',
120-
interpolation: opts?.interpolation ?? 'lanczos',
121-
padValue: opts?.padValue ?? 0,
119+
mode: options?.mode ?? 'stretch',
120+
interpolation: options?.interpolation ?? 'lanczos',
121+
padValue: options?.padValue ?? 0,
122122
});
123123
}
124124

@@ -184,19 +184,19 @@ export function toChannelsLast(src: Tensor, dst: Tensor): Tensor {
184184
* @param src The source image tensor in CHW layout. Shape [C,H,W].
185185
* @param dst The pre-allocated destination tensor to write the normalized
186186
* values to. `dst` must have the same shape as `src`. Shape [C,H,W].
187-
* @param opts Normalization scaling coefficients.
188-
* @param opts.alpha Multiplicative scaling coefficient(s). Defaults to
187+
* @param options Normalization scaling coefficients.
188+
* @param options.alpha Multiplicative scaling coefficient(s). Defaults to
189189
* `1 / 255.0`.
190-
* @param opts.beta Additive offset coefficient(s). Defaults to `0.0`.
190+
* @param options.beta Additive offset coefficient(s). Defaults to `0.0`.
191191
* @returns The destination tensor containing the normalized image.
192192
*/
193-
export function normalize(src: Tensor, dst: Tensor, opts?: NormalizeOptions): Tensor {
193+
export function normalize(src: Tensor, dst: Tensor, options?: NormalizeOptions): Tensor {
194194
'worklet';
195195
const defaultNormalizeOptions = {
196196
alpha: 1 / 255.0,
197197
beta: 0.0,
198198
} as const;
199-
return rnexecutorchJsi.cv.normalize(src, dst, { ...defaultNormalizeOptions, ...opts });
199+
return rnexecutorchJsi.cv.normalize(src, dst, { ...defaultNormalizeOptions, ...options });
200200
}
201201

202202
/**

packages/react-native-executorch/src/extensions/cv/ops/points.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,23 @@ export type Point = {
1414
* changes.
1515
* @category Utils
1616
* @param point The original coordinate point to scale.
17-
* @param opts Options detailing the scaling factors and resize mode.
18-
* @param opts.from The source bounds (e.g. model input dimensions).
19-
* @param opts.to The destination bounds (e.g. original image dimensions).
20-
* @param opts.resizeMode The mode used to resize the image {@link ResizeMode}
17+
* @param options Options detailing the scaling factors and resize mode.
18+
* @param options.from The source bounds (e.g. model input dimensions).
19+
* @param options.to The destination bounds (e.g. original image dimensions).
20+
* @param options.resizeMode The mode used to resize the image {@link ResizeMode}
2121
* (excluding `'crop'`).
2222
* @returns The scaled coordinate point.
2323
*/
2424
export function scalePoint(
2525
point: Point,
26-
opts: {
26+
options: {
2727
readonly from: { readonly width: number; readonly height: number };
2828
readonly to: { readonly width: number; readonly height: number };
2929
readonly resizeMode: Exclude<ResizeMode, 'crop'>;
3030
}
3131
): Point {
3232
'worklet';
33-
const { from, to, resizeMode } = opts;
33+
const { from, to, resizeMode } = options;
3434
switch (resizeMode) {
3535
case 'letterbox': {
3636
const scale = Math.min(from.width / to.width, from.height / to.height);

packages/react-native-executorch/src/extensions/cv/tasks/keypointDetection.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,14 @@ export type KeypointDetection<F extends BoxFormat, L extends PropertyKey> = {
7777
* @param tBoxes Bounding boxes tensor output from inference.
7878
* @param tScores Scores tensor output from inference.
7979
* @param tKeypoints Keypoints tensor output from inference.
80-
* @param opts Post-processing configuration options.
80+
* @param options Post-processing configuration options.
8181
* @returns Structured keypoint detection results list.
8282
*/
8383
function postprocess<F extends BoxFormat, L extends PropertyKey>(
8484
tBoxes: Tensor,
8585
tScores: Tensor,
8686
tKeypoints: Tensor,
87-
opts: {
87+
options: {
8888
readonly from: { readonly width: number; readonly height: number };
8989
readonly to: { readonly width: number; readonly height: number };
9090
readonly boxFormat: F;
@@ -96,7 +96,7 @@ function postprocess<F extends BoxFormat, L extends PropertyKey>(
9696
): KeypointDetection<F, L>[] {
9797
'worklet';
9898

99-
const nmsGroups = nms(tBoxes, tScores, { ...opts, nmsType: 'weighted' });
99+
const nmsGroups = nms(tBoxes, tScores, { ...options, nmsType: 'weighted' });
100100

101101
const boxes = tBoxes.getData(new Float32Array(tBoxes.numel));
102102
const scores = tScores.getData(new Float32Array(tScores.numel));
@@ -107,15 +107,15 @@ function postprocess<F extends BoxFormat, L extends PropertyKey>(
107107
for (const group of nmsGroups) {
108108
const totalScore = group.reduce((total, idx) => total + (scores[idx] ?? 0), 0);
109109
const weightedBox = new Float32Array(4);
110-
const weightedKpt = new Float32Array(opts.landmarks.length * 3);
110+
const weightedKpt = new Float32Array(options.landmarks.length * 3);
111111

112112
for (const idx of group) {
113113
const score = totalScore === 0 ? 1 / group.length : scores[idx]!;
114114
weightedBox.forEach((v, i) => {
115115
weightedBox[i] = v + score * boxes[idx * 4 + i]!;
116116
});
117117
weightedKpt.forEach((v, i) => {
118-
weightedKpt[i] = v + score * keypoints[idx * opts.landmarks.length * 3 + i]!;
118+
weightedKpt[i] = v + score * keypoints[idx * options.landmarks.length * 3 + i]!;
119119
});
120120
}
121121

@@ -129,11 +129,11 @@ function postprocess<F extends BoxFormat, L extends PropertyKey>(
129129
}
130130

131131
const [a, b, c, d] = weightedBox;
132-
const box = scaleBox(decodeBox([a!, b!, c!, d!], opts.boxFormat), opts);
132+
const box = scaleBox(decodeBox([a!, b!, c!, d!], options.boxFormat), options);
133133
const landmarks = {} as Landmarks<L>;
134134

135-
for (const [i, key] of opts.landmarks.entries()) {
136-
const point = scalePoint({ x: weightedKpt[i * 3]!, y: weightedKpt[i * 3 + 1]! }, opts);
135+
for (const [i, key] of options.landmarks.entries()) {
136+
const point = scalePoint({ x: weightedKpt[i * 3]!, y: weightedKpt[i * 3 + 1]! }, options);
137137
const confidence = weightedKpt[i * 3 + 2]!;
138138
landmarks[key] = { ...point, confidence };
139139
}

packages/react-native-executorch/src/extensions/cv/tasks/preprocessing.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,15 @@ export type ImagePreprocessorOptions = {
3939
* input shapes. All intermediate scratch tensors are pre-allocated and safely
4040
* disposed of when calling `dispose()`.
4141
* @category Typescript API
42-
* @param opts Normalization scaling coefficients, interpolation algorithms, and
42+
* @param options Normalization scaling coefficients, interpolation algorithms, and
4343
* crop/resize modes.
4444
* @param outputShape Expected output shape of the model input tensor (must
4545
* match `[1, 3, H, W]` or `[3, H, W]`).
4646
* @returns An object containing the `process` runner function and a `dispose`
4747
* method.
4848
*/
4949
export function createImagePreprocessor(
50-
opts: ImagePreprocessorOptions,
50+
options: ImagePreprocessorOptions,
5151
outputShape: number[]
5252
): {
5353
/**
@@ -86,7 +86,7 @@ export function createImagePreprocessor(
8686
] as const;
8787

8888
const [tColor, tChanFirst, tNorm, tOutput] = tensors;
89-
const { resizeMode, interpolation, normalizeOpts, padValue } = opts;
89+
const { resizeMode, interpolation, normalizeOpts, padValue } = options;
9090

9191
const dispose = () => tensors.forEach((t) => t.dispose());
9292
const process = (input: ImageBuffer): Tensor => {

packages/react-native-executorch/src/extensions/speech/tasks/fsmnVoiceActivityDetection.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,13 @@ function hannWindow(size: number): Float32Array {
111111
// threshold with hysteresis, pad both ends, then merge near-adjacent regions.
112112
// `scores[i]` holds the non-speech probability of frame `i`, so the speech
113113
// probability is `1 - scores[i]`.
114-
function postprocess(scores: Float32Array, opts: Required<VadOptions>): Segment[] {
114+
function postprocess(scores: Float32Array, options: Required<VadOptions>): Segment[] {
115115
'worklet';
116-
const threshold = opts.speechThreshold;
117-
const minSpeechHops = Math.floor(opts.minSpeechDurationMs / HOP_LENGTH_MS);
118-
const minSilenceHops = Math.floor(opts.minSilenceDurationMs / HOP_LENGTH_MS);
119-
const speechPadHops = Math.floor(opts.speechPadMs / HOP_LENGTH_MS);
120-
const maxMergeGapHops = opts.mergeGapMs / HOP_LENGTH_MS;
116+
const threshold = options.speechThreshold;
117+
const minSpeechHops = Math.floor(options.minSpeechDurationMs / HOP_LENGTH_MS);
118+
const minSilenceHops = Math.floor(options.minSilenceDurationMs / HOP_LENGTH_MS);
119+
const speechPadHops = Math.floor(options.speechPadMs / HOP_LENGTH_MS);
120+
const maxMergeGapHops = options.mergeGapMs / HOP_LENGTH_MS;
121121

122122
// Threshold with hysteresis: a region must stay above the threshold for
123123
// `minSpeechHops` to open a segment, and below it for `minSilenceHops` to
@@ -252,7 +252,7 @@ export async function createFsmnVoiceActivityDetector(
252252

253253
const detectVoiceWorklet = (waveform: Float32Array, options?: VadOptions): Segment[] => {
254254
'worklet';
255-
const opts: Required<VadOptions> = { ...defaultOptions, ...options };
255+
const mergedOpts: Required<VadOptions> = { ...defaultOptions, ...options };
256256
const numFrames = Math.floor((waveform.length - FRAME_LENGTH) / HOP_LENGTH);
257257
if (numFrames <= 0) return [];
258258

@@ -294,7 +294,7 @@ export async function createFsmnVoiceActivityDetector(
294294
offset += realFrames;
295295
}
296296

297-
return postprocess(scores, opts);
297+
return postprocess(scores, mergedOpts);
298298
};
299299

300300
const detectVoice = wrapAsync(detectVoiceWorklet, runtime);

0 commit comments

Comments
 (0)