Fix comment structure (#216)
* fix: Add comment children * feat: Update snaps * fix: specs * spec: Add spec * fix: js ifmain
parent
e45e0431e9
commit
2e5a22fc53
|
@ -10,7 +10,7 @@ pub fn main() -> Result<(), DocxError> {
|
||||||
Comment::new(1)
|
Comment::new(1)
|
||||||
.author("bokuweb")
|
.author("bokuweb")
|
||||||
.date("2019-01-01T00:00:00Z")
|
.date("2019-01-01T00:00:00Z")
|
||||||
.paragraph(Paragraph::new().add_run(Run::new().add_text("Hello"))),
|
.add_paragraph(Paragraph::new().add_run(Run::new().add_text("Hello"))),
|
||||||
)
|
)
|
||||||
.add_comment_end(1),
|
.add_comment_end(1),
|
||||||
)
|
)
|
||||||
|
|
|
@ -10,7 +10,8 @@ pub fn main() -> Result<(), DocxError> {
|
||||||
Comment::new(1)
|
Comment::new(1)
|
||||||
.author("bokuweb")
|
.author("bokuweb")
|
||||||
.date("2019-01-01T00:00:00Z")
|
.date("2019-01-01T00:00:00Z")
|
||||||
.paragraph(Paragraph::new().add_run(Run::new().add_text("Hello"))),
|
.add_paragraph(Paragraph::new().add_run(Run::new().add_text("Hello")))
|
||||||
|
.add_paragraph(Paragraph::new().add_run(Run::new().add_text("World"))),
|
||||||
)
|
)
|
||||||
.add_comment_end(1)
|
.add_comment_end(1)
|
||||||
.add_comment_start(
|
.add_comment_start(
|
||||||
|
@ -18,7 +19,7 @@ pub fn main() -> Result<(), DocxError> {
|
||||||
.author("bokuweb")
|
.author("bokuweb")
|
||||||
.date("2019-01-02T00:00:00Z")
|
.date("2019-01-02T00:00:00Z")
|
||||||
.parent_comment_id(1)
|
.parent_comment_id(1)
|
||||||
.paragraph(Paragraph::new().add_run(Run::new().add_text("World"))),
|
.add_paragraph(Paragraph::new().add_run(Run::new().add_text("World"))),
|
||||||
)
|
)
|
||||||
.add_comment_end(2)
|
.add_comment_end(2)
|
||||||
.add_comment_start(
|
.add_comment_start(
|
||||||
|
@ -26,7 +27,8 @@ pub fn main() -> Result<(), DocxError> {
|
||||||
.author("bokuweb")
|
.author("bokuweb")
|
||||||
.date("2019-01-02T00:00:00Z")
|
.date("2019-01-02T00:00:00Z")
|
||||||
.parent_comment_id(1)
|
.parent_comment_id(1)
|
||||||
.paragraph(Paragraph::new().add_run(Run::new().add_text("!!!!!"))),
|
.add_paragraph(Paragraph::new().add_run(Run::new().add_text("!!!!!")))
|
||||||
|
.add_paragraph(Paragraph::new().add_run(Run::new().add_text("!!!!!"))),
|
||||||
)
|
)
|
||||||
.add_comment_end(3),
|
.add_comment_end(3),
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
use serde::ser::{SerializeStruct, Serializer};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::documents::{BuildXML, Paragraph};
|
use crate::documents::*;
|
||||||
use crate::xml_builder::*;
|
use crate::xml_builder::*;
|
||||||
|
|
||||||
#[derive(Serialize, Debug, Clone, PartialEq)]
|
#[derive(Serialize, Debug, Clone, PartialEq)]
|
||||||
|
@ -9,17 +10,45 @@ pub struct Comment {
|
||||||
pub id: usize,
|
pub id: usize,
|
||||||
pub author: String,
|
pub author: String,
|
||||||
pub date: String,
|
pub date: String,
|
||||||
pub paragraph: Paragraph,
|
pub children: Vec<CommentChild>,
|
||||||
pub parent_comment_id: Option<usize>,
|
pub parent_comment_id: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum CommentChild {
|
||||||
|
Paragraph(Paragraph),
|
||||||
|
Table(Table),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for CommentChild {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
match *self {
|
||||||
|
CommentChild::Paragraph(ref p) => {
|
||||||
|
let mut t = serializer.serialize_struct("Paragraph", 2)?;
|
||||||
|
t.serialize_field("type", "paragraph")?;
|
||||||
|
t.serialize_field("data", p)?;
|
||||||
|
t.end()
|
||||||
|
}
|
||||||
|
CommentChild::Table(ref c) => {
|
||||||
|
let mut t = serializer.serialize_struct("Table", 2)?;
|
||||||
|
t.serialize_field("type", "table")?;
|
||||||
|
t.serialize_field("data", c)?;
|
||||||
|
t.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for Comment {
|
impl Default for Comment {
|
||||||
fn default() -> Comment {
|
fn default() -> Comment {
|
||||||
Comment {
|
Comment {
|
||||||
id: 1,
|
id: 1,
|
||||||
author: "unnamed".to_owned(),
|
author: "unnamed".to_owned(),
|
||||||
date: "1970-01-01T00:00:00Z".to_owned(),
|
date: "1970-01-01T00:00:00Z".to_owned(),
|
||||||
paragraph: Paragraph::new(),
|
children: vec![],
|
||||||
parent_comment_id: None,
|
parent_comment_id: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,8 +72,13 @@ impl Comment {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn paragraph(mut self, p: Paragraph) -> Comment {
|
pub fn add_paragraph(mut self, p: Paragraph) -> Self {
|
||||||
self.paragraph = p;
|
self.children.push(CommentChild::Paragraph(p));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_table(mut self, t: Table) -> Self {
|
||||||
|
self.children.push(CommentChild::Table(t));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,11 +92,20 @@ impl Comment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl BuildXML for CommentChild {
|
||||||
|
fn build(&self) -> Vec<u8> {
|
||||||
|
match self {
|
||||||
|
CommentChild::Paragraph(v) => v.build(),
|
||||||
|
CommentChild::Table(v) => v.build(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl BuildXML for Comment {
|
impl BuildXML for Comment {
|
||||||
fn build(&self) -> Vec<u8> {
|
fn build(&self) -> Vec<u8> {
|
||||||
XMLBuilder::new()
|
XMLBuilder::new()
|
||||||
.open_comment(&format!("{}", self.id), &self.author, &self.date, "")
|
.open_comment(&format!("{}", self.id), &self.author, &self.date, "")
|
||||||
.add_child(&self.paragraph)
|
.add_children(&self.children)
|
||||||
.close()
|
.close()
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
@ -77,8 +120,17 @@ mod tests {
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ins_default() {
|
fn test_comment_default() {
|
||||||
let b = Comment::new(1).build();
|
let b = Comment::new(1).build();
|
||||||
|
assert_eq!(
|
||||||
|
str::from_utf8(&b).unwrap(),
|
||||||
|
r#"<w:comment w:id="1" w:author="unnamed" w:date="1970-01-01T00:00:00Z" w:initials="" />"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_comment_with_default_paragraph() {
|
||||||
|
let b = Comment::new(1).add_paragraph(Paragraph::new()).build();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
str::from_utf8(&b).unwrap(),
|
str::from_utf8(&b).unwrap(),
|
||||||
r#"<w:comment w:id="1" w:author="unnamed" w:date="1970-01-01T00:00:00Z" w:initials=""><w:p w14:paraId="12345678"><w:pPr><w:rPr /></w:pPr></w:p></w:comment>"#
|
r#"<w:comment w:id="1" w:author="unnamed" w:date="1970-01-01T00:00:00Z" w:initials=""><w:p w14:paraId="12345678"><w:pPr><w:rPr /></w:pPr></w:p></w:comment>"#
|
||||||
|
|
|
@ -278,8 +278,14 @@ impl Docx {
|
||||||
for child in ¶graph.children {
|
for child in ¶graph.children {
|
||||||
if let ParagraphChild::CommentStart(c) = child {
|
if let ParagraphChild::CommentStart(c) = child {
|
||||||
let comment = c.get_comment();
|
let comment = c.get_comment();
|
||||||
let para_id = comment.paragraph.id.clone();
|
let comment_id = comment.id();
|
||||||
comment_map.insert(comment.id(), para_id.clone());
|
for child in comment.children {
|
||||||
|
if let CommentChild::Paragraph(child) = child {
|
||||||
|
let para_id = child.id.clone();
|
||||||
|
comment_map.insert(comment_id, para_id.clone());
|
||||||
|
}
|
||||||
|
// TODO: Support table
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -292,8 +298,15 @@ impl Docx {
|
||||||
for child in ¶graph.children {
|
for child in ¶graph.children {
|
||||||
if let ParagraphChild::CommentStart(c) = child {
|
if let ParagraphChild::CommentStart(c) = child {
|
||||||
let comment = c.get_comment();
|
let comment = c.get_comment();
|
||||||
let para_id = comment.paragraph.id.clone();
|
let comment_id = comment.id();
|
||||||
comment_map.insert(comment.id(), para_id.clone());
|
for child in comment.children {
|
||||||
|
if let CommentChild::Paragraph(child) = child {
|
||||||
|
let para_id = child.id.clone();
|
||||||
|
comment_map
|
||||||
|
.insert(comment_id, para_id.clone());
|
||||||
|
}
|
||||||
|
// TODO: Support table
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -312,18 +325,24 @@ impl Docx {
|
||||||
for child in ¶graph.children {
|
for child in ¶graph.children {
|
||||||
if let ParagraphChild::CommentStart(c) = child {
|
if let ParagraphChild::CommentStart(c) = child {
|
||||||
let comment = c.get_comment();
|
let comment = c.get_comment();
|
||||||
let para_id = comment.paragraph.id.clone();
|
for child in comment.children {
|
||||||
|
if let CommentChild::Paragraph(child) = child {
|
||||||
|
let para_id = child.id.clone();
|
||||||
comments.push(c.get_comment());
|
comments.push(c.get_comment());
|
||||||
let comment_extended = CommentExtended::new(para_id);
|
let comment_extended = CommentExtended::new(para_id);
|
||||||
if let Some(parent_comment_id) = comment.parent_comment_id {
|
if let Some(parent_comment_id) = comment.parent_comment_id {
|
||||||
let parent_para_id =
|
let parent_para_id =
|
||||||
comment_map.get(&parent_comment_id).unwrap().clone();
|
comment_map.get(&parent_comment_id).unwrap().clone();
|
||||||
comments_extended
|
comments_extended.push(
|
||||||
.push(comment_extended.parent_paragraph_id(parent_para_id));
|
comment_extended.parent_paragraph_id(parent_para_id),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
comments_extended.push(comment_extended);
|
comments_extended.push(comment_extended);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO: Support table
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DocumentChild::Table(table) => {
|
DocumentChild::Table(table) => {
|
||||||
|
@ -335,7 +354,9 @@ impl Docx {
|
||||||
for child in ¶graph.children {
|
for child in ¶graph.children {
|
||||||
if let ParagraphChild::CommentStart(c) = child {
|
if let ParagraphChild::CommentStart(c) = child {
|
||||||
let comment = c.get_comment();
|
let comment = c.get_comment();
|
||||||
let para_id = comment.paragraph.id.clone();
|
for child in comment.children {
|
||||||
|
if let CommentChild::Paragraph(child) = child {
|
||||||
|
let para_id = child.id.clone();
|
||||||
comments.push(c.get_comment());
|
comments.push(c.get_comment());
|
||||||
let comment_extended =
|
let comment_extended =
|
||||||
CommentExtended::new(para_id);
|
CommentExtended::new(para_id);
|
||||||
|
@ -348,10 +369,15 @@ impl Docx {
|
||||||
.clone();
|
.clone();
|
||||||
comments_extended.push(
|
comments_extended.push(
|
||||||
comment_extended
|
comment_extended
|
||||||
.parent_paragraph_id(parent_para_id),
|
.parent_paragraph_id(
|
||||||
|
parent_para_id,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
comments_extended.push(comment_extended);
|
comments_extended
|
||||||
|
.push(comment_extended);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ impl ElementReader for Comment {
|
||||||
.expect("should convert to XMLElement");
|
.expect("should convert to XMLElement");
|
||||||
if let XMLElement::Paragraph = e {
|
if let XMLElement::Paragraph = e {
|
||||||
let p = Paragraph::read(r, &attributes)?;
|
let p = Paragraph::read(r, &attributes)?;
|
||||||
comment = comment.paragraph(p);
|
comment = comment.add_paragraph(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(XmlEvent::EndElement { name, .. }) => {
|
Ok(XmlEvent::EndElement { name, .. }) => {
|
||||||
|
|
|
@ -126,19 +126,31 @@ pub fn read_docx(buf: &[u8]) -> Result<Docx, ReaderError> {
|
||||||
let mut comments = Comments::from_xml(&data[..])?.into_inner();
|
let mut comments = Comments::from_xml(&data[..])?.into_inner();
|
||||||
for i in 0..comments.len() {
|
for i in 0..comments.len() {
|
||||||
let c = &comments[i];
|
let c = &comments[i];
|
||||||
let extended = comments_extended
|
let extended = comments_extended.children.iter().find(|ex| {
|
||||||
.children
|
for child in &c.children {
|
||||||
.iter()
|
if let CommentChild::Paragraph(p) = child {
|
||||||
.find(|ex| ex.paragraph_id == c.paragraph.id);
|
if ex.paragraph_id == p.id {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
});
|
||||||
if let Some(CommentExtended {
|
if let Some(CommentExtended {
|
||||||
parent_paragraph_id: Some(parent_paragraph_id),
|
parent_paragraph_id: Some(parent_paragraph_id),
|
||||||
..
|
..
|
||||||
}) = extended
|
}) = extended
|
||||||
{
|
{
|
||||||
if let Some(parent_comment) = comments
|
if let Some(parent_comment) = comments.iter().find(|c| {
|
||||||
.iter()
|
for child in &c.children {
|
||||||
.find(|c| &c.paragraph.id == parent_paragraph_id)
|
if let CommentChild::Paragraph(p) = child {
|
||||||
{
|
if &p.id == parent_paragraph_id {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}) {
|
||||||
comments[i].parent_comment_id = Some(parent_comment.id);
|
comments[i].parent_comment_id = Some(parent_comment.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -262,7 +262,7 @@ pub fn comments() -> Result<(), DocxError> {
|
||||||
Comment::new(1)
|
Comment::new(1)
|
||||||
.author("bokuweb")
|
.author("bokuweb")
|
||||||
.date("2019-01-01T00:00:00Z")
|
.date("2019-01-01T00:00:00Z")
|
||||||
.paragraph(Paragraph::new().add_run(Run::new().add_text("Hello"))),
|
.add_paragraph(Paragraph::new().add_run(Run::new().add_text("Hello"))),
|
||||||
)
|
)
|
||||||
.add_run(Run::new().add_text("Hello").highlight("cyan"))
|
.add_run(Run::new().add_text("Hello").highlight("cyan"))
|
||||||
.add_run(Run::new().add_text(" World!").highlight("yellow"))
|
.add_run(Run::new().add_text(" World!").highlight("yellow"))
|
||||||
|
@ -284,7 +284,7 @@ pub fn comments_to_table() -> Result<(), DocxError> {
|
||||||
Comment::new(1)
|
Comment::new(1)
|
||||||
.author("bokuweb")
|
.author("bokuweb")
|
||||||
.date("2019-01-01T00:00:00Z")
|
.date("2019-01-01T00:00:00Z")
|
||||||
.paragraph(Paragraph::new().add_run(Run::new().add_text("Hello"))),
|
.add_paragraph(Paragraph::new().add_run(Run::new().add_text("Hello"))),
|
||||||
)
|
)
|
||||||
.add_run(Run::new().add_text("Hello"))
|
.add_run(Run::new().add_text("Hello"))
|
||||||
.add_comment_end(1),
|
.add_comment_end(1),
|
||||||
|
@ -298,7 +298,7 @@ pub fn comments_to_table() -> Result<(), DocxError> {
|
||||||
Comment::new(1)
|
Comment::new(1)
|
||||||
.author("bokuweb")
|
.author("bokuweb")
|
||||||
.date("2019-01-01T00:00:00Z")
|
.date("2019-01-01T00:00:00Z")
|
||||||
.paragraph(Paragraph::new().add_run(Run::new().add_text("Comment!!"))),
|
.add_paragraph(Paragraph::new().add_run(Run::new().add_text("Comment!!"))),
|
||||||
)
|
)
|
||||||
.add_run(Run::new().add_text("Hello").highlight("cyan"))
|
.add_run(Run::new().add_text("Hello").highlight("cyan"))
|
||||||
.add_comment_end(1),
|
.add_comment_end(1),
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,10 +1,11 @@
|
||||||
import { Paragraph } from "./paragraph";
|
import { Paragraph } from "./paragraph";
|
||||||
|
import { Table } from "./table";
|
||||||
|
|
||||||
export class Comment {
|
export class Comment {
|
||||||
id: number;
|
id: number;
|
||||||
_author: string;
|
_author: string;
|
||||||
_date: string;
|
_date: string;
|
||||||
_paragraph: Paragraph;
|
children: (Paragraph | Table)[] = [];
|
||||||
_parentCommentId: number;
|
_parentCommentId: number;
|
||||||
|
|
||||||
constructor(id: number) {
|
constructor(id: number) {
|
||||||
|
@ -21,8 +22,8 @@ export class Comment {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
paragraph(p: Paragraph) {
|
addParagraph(p: Paragraph) {
|
||||||
this._paragraph = p;
|
this.children.push(p);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -231,9 +231,13 @@ export class Docx {
|
||||||
|
|
||||||
buildComment(c: Comment) {
|
buildComment(c: Comment) {
|
||||||
let comment = wasm.createComment(c.id);
|
let comment = wasm.createComment(c.id);
|
||||||
if (c._paragraph) {
|
c.children.forEach((child) => {
|
||||||
comment = comment.paragraph(this.buildParagraph(c._paragraph));
|
if (child instanceof Paragraph) {
|
||||||
|
comment = comment.add_paragraph(this.buildParagraph(child));
|
||||||
|
} else if (child instanceof Table) {
|
||||||
|
// TODO:
|
||||||
}
|
}
|
||||||
|
});
|
||||||
if (c._author) {
|
if (c._author) {
|
||||||
comment = comment.author(c._author);
|
comment = comment.author(c._author);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import { ParagraphJSON } from "../";
|
import { ParagraphJSON, TableJSON } from "../";
|
||||||
|
|
||||||
|
export type CommentChildJSON = ParagraphJSON | TableJSON;
|
||||||
|
|
||||||
export type CommentJSON = {
|
export type CommentJSON = {
|
||||||
id: number;
|
id: number;
|
||||||
author: string;
|
author: string;
|
||||||
date: string;
|
date: string;
|
||||||
paragraph: ParagraphJSON;
|
children: CommentChildJSON[];
|
||||||
parentCommentId: number | null;
|
parentCommentId: number | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -28,8 +28,8 @@ impl Comment {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn paragraph(mut self, p: Paragraph) -> Comment {
|
pub fn add_paragraph(mut self, p: Paragraph) -> Comment {
|
||||||
self.0.paragraph = p.take();
|
self.0 = self.0.add_paragraph(p.take());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -28,6 +28,14 @@ describe("reader", () => {
|
||||||
const json = w.readDocx(buf);
|
const json = w.readDocx(buf);
|
||||||
expect(json).toMatchSnapshot();
|
expect(json).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("should read multi paragraph comments docx", () => {
|
||||||
|
const buf = readFileSync(
|
||||||
|
"../fixtures/multi_paragraph_comment/multi_paragraph_comment.docx"
|
||||||
|
);
|
||||||
|
const json = w.readDocx(buf);
|
||||||
|
expect(json).toMatchSnapshot();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("writer", () => {
|
describe("writer", () => {
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue