Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions __test__/path-constructor.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import test from 'ava'

import { Path2D } from '../index'

test('Path2D constructor should accept another Path2D instance', (t) => {
const originalPath = new Path2D()
originalPath.rect(0, 0, 100, 100)

// This should work - passing a Path2D instance to the constructor
const copiedPath = new Path2D(originalPath)

t.is(copiedPath.toSVGString(), originalPath.toSVGString())
t.is(copiedPath.toSVGString(), 'M0 0L100 0L100 100L0 100L0 0Z')
})

test('Path2D constructor should accept a string', (t) => {
const svgString = 'M0 0L100 0L100 100L0 100L0 0Z'
const path = new Path2D(svgString)

t.is(path.toSVGString(), svgString)
})

test('Path2D constructor should work without arguments', (t) => {
const path = new Path2D()
path.rect(0, 0, 50, 50)

t.is(path.toSVGString(), 'M0 0L50 0L50 50L0 50L0 0Z')
})

test('Path2D constructor with Path instance should create independent copy', (t) => {
const path1 = new Path2D()
path1.rect(0, 0, 100, 100)

const path2 = new Path2D(path1)

// Modify path2
path2.rect(200, 200, 50, 50)

// path1 should be unchanged
t.is(path1.toSVGString(), 'M0 0L100 0L100 100L0 100L0 0Z')
t.is(path2.toSVGString(), 'M0 0L100 0L100 100L0 100L0 0ZM200 200L250 200L250 250L200 250L200 200Z')
})
27 changes: 19 additions & 8 deletions src/path.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use napi::bindgen_prelude::*;
use napi::Env;

use crate::sk::{
FillType as SkFillType, Matrix as SkMatrix, Path as SkPath, PathOp as SkPathOp, SkiaString,
Expand Down Expand Up @@ -122,7 +123,10 @@ pub struct Path {
#[napi]
impl Path {
#[napi(constructor)]
pub fn new(path: Option<Either3<String, &mut Path, Unknown>>) -> Result<Self> {
pub fn new(
env: Env,
path: Option<Either3<String, &mut Path, Unknown>>,
) -> Result<Self> {
let inner = match &path {
Some(Either3::A(path)) => SkPath::from_svg_path(path).ok_or_else(|| {
Error::new(
Expand All @@ -132,13 +136,20 @@ impl Path {
})?,
Some(Either3::B(path)) => path.inner.clone(),
Some(Either3::C(c)) => {
return Err(Error::new(
Status::InvalidArg,
format!(
"Create path from provided unknown value failed {}.",
c.get_type()?
),
));
// Try to unwrap the Unknown value as a Path reference
// This handles the case where webpack or other bundlers wrap the Path instance
// Use FromNapiValue to try to extract the Path from the Unknown
if let Ok(path_ref) = <&Path>::from_napi_value(env.raw(), c.raw()) {
path_ref.inner.clone()
} else {
return Err(Error::new(
Status::InvalidArg,
format!(
"Value is none of these types `String`, `Path`. Got type: {}",
c.get_type().unwrap_or_else(|_| "unknown".to_string())
),
));
}
}
None => SkPath::new(),
};
Expand Down
Loading