@digitalwalletcorp/utils 0.13.0 → 0.14.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.
@@ -0,0 +1,2 @@
1
+ "use strict";const p=/^data:([^;,]+)?(?:;[^,]*)?;base64,(.*)$/s,T="application/octet-stream";const L=/^\ufeff?\s*(?:<\?xml[^>]*>\s*)?(?:<!--[\s\S]*?-->\s*)*(?:<!DOCTYPE[^>]*>\s*)?<svg[\s>]/i,D=[{entry:"word/",type:{ext:"docx",mime:"application/vnd.openxmlformats-officedocument.wordprocessingml.document"}},{entry:"xl/",type:{ext:"xlsx",mime:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}},{entry:"ppt/",type:{ext:"pptx",mime:"application/vnd.openxmlformats-officedocument.presentationml.presentation"}}],R=["avif","avis"],c=e=>e instanceof ArrayBuffer?new Uint8Array(e):new Uint8Array(e.buffer,e.byteOffset,e.byteLength),B=e=>c(e).slice().buffer,i=(e,t,r=0)=>{const n=typeof t=="string"?Array.from(t,o=>o.charCodeAt(0)):t;return e.length<r+n.length?!1:n.every((o,F)=>e[r+F]===o)},E=e=>{const t=Math.min(new DataView(e.buffer,e.byteOffset,e.byteLength).getUint32(0),e.length),r=new TextDecoder("latin1").decode(e.subarray(0,t)),n=[r.slice(8,12)];for(let o=16;o+4<=t;o+=4)n.push(r.slice(o,o+4));return n},_=e=>{if(i(e,[137,80,78,71,13,10,26,10]))return{ext:"png",mime:"image/png"};if(i(e,[255,216,255]))return{ext:"jpg",mime:"image/jpeg"};if(i(e,"GIF87a")||i(e,"GIF89a"))return{ext:"gif",mime:"image/gif"};if(i(e,"RIFF")&&i(e,"WEBP",8))return{ext:"webp",mime:"image/webp"};if(i(e,"BM"))return{ext:"bmp",mime:"image/bmp"};if(i(e,[73,73,42,0])||i(e,[77,77,0,42]))return{ext:"tif",mime:"image/tiff"};if(i(e,"ftyp",4)&&E(e).some(t=>R.includes(t)))return{ext:"avif",mime:"image/avif"};if(i(e,"%PDF-"))return{ext:"pdf",mime:"application/pdf"};if(i(e,[80,75,3,4])||i(e,[80,75,5,6])||i(e,[80,75,7,8])){const t=new TextDecoder("latin1").decode(e),r=D.find(n=>t.includes(n.entry));return r?r.type:{ext:"zip",mime:"application/zip"}}return L.test(new TextDecoder().decode(e))?{ext:"svg",mime:"image/svg+xml"}:null};function u(e,t){return`data:${t||T};base64,${e}`}function x(e){const t=p.exec(e),r=t?t[2]:e;return[r,f(r)?.mime??t?.[1]??T]}async function A(e){if(typeof e=="string")return p.test(e)?e:g(e);if(e instanceof Blob){const t=await e.arrayBuffer();return s(t,e.type||f(t)?.mime)}return s(e,f(e)?.mime)}async function h(e){return typeof e=="string"?m(e):e instanceof Blob?e.arrayBuffer():B(e)}function g(e,t){return e&&u(e,t||f(e)?.mime)}function a(e){const t=atob(e),r=new Uint8Array(t.length);for(let n=0;n<t.length;n++)r[n]=t.charCodeAt(n);return r.buffer}function U(e,t){const r=a(e);return new Blob([r],{type:t||f(r)?.mime||""})}function l(e){return p.exec(e)?.[2]??e}function m(e){return a(l(e))}function y(e){const t=c(e);let r="";for(let n=0;n<t.length;n++)r+=String.fromCharCode(t[n]);return btoa(r)}function s(e,t){return u(y(e),t)}function d(e){return m(e).byteLength}function b(e){if(!e)return new Blob([]);let t;if(typeof e=="string"){const r=`\uFEFF${e}`,n=new Uint16Array(r.length);for(let o=0;o<r.length;o++)n[o]=r.charCodeAt(o);t=[n]}else t=[new Uint8Array([255,254]),B(e)];return new Blob(t,{type:"text/csv;charset=utf-16;"})}function f(e){let t;if(typeof e=="string"){const r=l(e).slice(0,16384);try{t=c(a(r.slice(0,r.length-r.length%4)))}catch{return null}}else t=c(e);return _(t)}function w(e){return e.replace(/[\\/:*?"<>|]/g,"")}const v=Object.freeze(Object.defineProperty({__proto__:null,analyzeFileType:f,arrayBufferToBase64:y,arrayBufferToDataURL:s,base64ToArrayBuffer:a,base64ToBlob:U,base64ToDataURL:g,calcSize:d,convertUTF16withBOM:b,createDataURL:u,dataURLToArrayBuffer:m,dataURLToBase64:l,parseDataURL:x,readAsArrayBuffer:h,readAsDataURL:A,sanitizeFileName:w},Symbol.toStringTag,{value:"Module"}));exports.analyzeFileType=f;exports.arrayBufferToBase64=y;exports.arrayBufferToDataURL=s;exports.base64ToArrayBuffer=a;exports.base64ToBlob=U;exports.base64ToDataURL=g;exports.calcSize=d;exports.convertUTF16withBOM=b;exports.createDataURL=u;exports.dataURLToArrayBuffer=m;exports.dataURLToBase64=l;exports.fileUtil=v;exports.parseDataURL=x;exports.readAsArrayBuffer=h;exports.readAsDataURL=A;exports.sanitizeFileName=w;
2
+ //# sourceMappingURL=file-util-8dZPFn1f.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-util-8dZPFn1f.cjs","sources":["../src/file-util.ts"],"sourcesContent":["/** 先頭バイトの署名から判定したファイルの種類 */\nexport interface FileType {\n /** 拡張子(ドットなし) */\n ext: string;\n /** MIMEタイプ */\n mime: string;\n}\n\n/** バイナリとして受け付ける値。Node.js の Buffer も ArrayBufferView として渡せる */\nexport type BinaryInput = ArrayBuffer | ArrayBufferView;\n\nconst DATA_URL_PATTERN = /^data:([^;,]+)?(?:;[^,]*)?;base64,(.*)$/s;\n\nconst DEFAULT_MIME_TYPE = 'application/octet-stream';\n\n/** 種類の判定に使う先頭の base64 の文字数。ZIP の中のエントリ名を探すため数KB分を見る */\nconst SIGNATURE_BASE64_LENGTH = 16384;\n\nconst SVG_PATTERN = /^\\ufeff?\\s*(?:<\\?xml[^>]*>\\s*)?(?:<!--[\\s\\S]*?-->\\s*)*(?:<!DOCTYPE[^>]*>\\s*)?<svg[\\s>]/i;\n\nconst OFFICE_FILE_TYPES: { entry: string; type: FileType; }[] = [\n { entry: 'word/', type: { ext: 'docx', mime: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' } },\n { entry: 'xl/', type: { ext: 'xlsx', mime: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' } },\n { entry: 'ppt/', type: { ext: 'pptx', mime: 'application/vnd.openxmlformats-officedocument.presentationml.presentation' } }\n];\n\n/** ftyp ボックスのブランドのうち、AVIF を表すもの */\nconst AVIF_BRANDS = ['avif', 'avis'];\n\nconst toBytes = (data: BinaryInput): Uint8Array => {\n return data instanceof ArrayBuffer ? new Uint8Array(data) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);\n};\n\nconst toArrayBuffer = (data: BinaryInput): ArrayBuffer => toBytes(data).slice().buffer as ArrayBuffer;\n\nconst startsWith = (bytes: Uint8Array, signature: number[] | string, offset: number = 0): boolean => {\n const expected = typeof signature === 'string' ? Array.from(signature, c => c.charCodeAt(0)) : signature;\n if (bytes.length < offset + expected.length) {\n return false;\n }\n return expected.every((value, i) => bytes[offset + i] === value);\n};\n\n/**\n * ISOBMFF の ftyp ボックスに並ぶブランドを返す\n * 8バイト目からメジャーブランド、16バイト目から互換ブランドが4文字ずつ並ぶ\n *\n * @param {Uint8Array} bytes\n * @returns {string[]}\n */\nconst readBrands = (bytes: Uint8Array): string[] => {\n const end = Math.min(new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(0), bytes.length);\n const text = new TextDecoder('latin1').decode(bytes.subarray(0, end));\n const brands = [text.slice(8, 12)];\n for (let i = 16; i + 4 <= end; i += 4) {\n brands.push(text.slice(i, i + 4));\n }\n return brands;\n};\n\nconst detectFileType = (bytes: Uint8Array): FileType | null => {\n if (startsWith(bytes, [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A])) {\n return { ext: 'png', mime: 'image/png' };\n }\n if (startsWith(bytes, [0xFF, 0xD8, 0xFF])) {\n return { ext: 'jpg', mime: 'image/jpeg' };\n }\n if (startsWith(bytes, 'GIF87a') || startsWith(bytes, 'GIF89a')) {\n return { ext: 'gif', mime: 'image/gif' };\n }\n if (startsWith(bytes, 'RIFF') && startsWith(bytes, 'WEBP', 8)) {\n return { ext: 'webp', mime: 'image/webp' };\n }\n if (startsWith(bytes, 'BM')) {\n return { ext: 'bmp', mime: 'image/bmp' };\n }\n if (startsWith(bytes, [0x49, 0x49, 0x2A, 0x00]) || startsWith(bytes, [0x4D, 0x4D, 0x00, 0x2A])) {\n return { ext: 'tif', mime: 'image/tiff' };\n }\n if (startsWith(bytes, 'ftyp', 4) && readBrands(bytes).some(a => AVIF_BRANDS.includes(a))) {\n return { ext: 'avif', mime: 'image/avif' };\n }\n if (startsWith(bytes, '%PDF-')) {\n return { ext: 'pdf', mime: 'application/pdf' };\n }\n if (startsWith(bytes, [0x50, 0x4B, 0x03, 0x04]) || startsWith(bytes, [0x50, 0x4B, 0x05, 0x06]) || startsWith(bytes, [0x50, 0x4B, 0x07, 0x08])) {\n // Office Open XML も ZIP なので、ZIP に含まれるエントリ名で見分ける\n const text = new TextDecoder('latin1').decode(bytes);\n const office = OFFICE_FILE_TYPES.find(a => text.includes(a.entry));\n return office ? office.type : { ext: 'zip', mime: 'application/zip' };\n }\n if (SVG_PATTERN.test(new TextDecoder().decode(bytes))) {\n return { ext: 'svg', mime: 'image/svg+xml' };\n }\n return null;\n};\n\n/**\n * base64 データと MIME タイプから DataURL を生成する\n *\n * @param {string} base64\n * @param {string} [mimeType] 省略時は 'application/octet-stream'\n * @returns {string}\n */\nexport function createDataURL(base64: string, mimeType?: string): string {\n return `data:${mimeType || DEFAULT_MIME_TYPE};base64,${base64}`;\n}\n\n/**\n * DataURL を base64 データと MIME タイプに分解する\n * MIME タイプは DataURL に書かれた値ではなく、データの先頭バイトから判定した値を返す。判定できない場合は DataURL に書かれた値、それもなければ 'application/octet-stream'\n * DataURL 形式でない文字列は base64 データとみなす\n *\n * @param {string} dataURL\n * @returns {[string, string]} [base64, mimeType]\n */\nexport function parseDataURL(dataURL: string): [string, string] {\n const matcher = DATA_URL_PATTERN.exec(dataURL);\n const base64 = matcher ? matcher[2] : dataURL;\n return [base64, analyzeFileType(base64)?.mime ?? matcher?.[1] ?? DEFAULT_MIME_TYPE];\n}\n\n/**\n * データを読み込み DataURL を返す\n * 文字列は、DataURL 形式ならそのまま、そうでなければ base64 データとみなす\n * Blob は Blob の type を、それがなければ先頭バイトから判定した MIME タイプを使う\n *\n * @param {string | Blob | BinaryInput} data\n * @returns {Promise<string>}\n */\nexport async function readAsDataURL(data: string | Blob | BinaryInput): Promise<string> {\n if (typeof data === 'string') {\n return DATA_URL_PATTERN.test(data) ? data : base64ToDataURL(data);\n }\n if (data instanceof Blob) {\n const buffer = await data.arrayBuffer();\n return arrayBufferToDataURL(buffer, data.type || analyzeFileType(buffer)?.mime);\n }\n return arrayBufferToDataURL(data, analyzeFileType(data)?.mime);\n}\n\n/**\n * データを読み込み ArrayBuffer を返す\n * 文字列は、DataURL 形式ならその base64 部分を、そうでなければ base64 データとみなして変換する\n *\n * @param {string | Blob | BinaryInput} data\n * @returns {Promise<ArrayBuffer>}\n */\nexport async function readAsArrayBuffer(data: string | Blob | BinaryInput): Promise<ArrayBuffer> {\n if (typeof data === 'string') {\n return dataURLToArrayBuffer(data);\n }\n if (data instanceof Blob) {\n return data.arrayBuffer();\n }\n return toArrayBuffer(data);\n}\n\n/**\n * base64 データを DataURL に変換する\n * MIME タイプを省略した場合はデータの先頭バイトから判定する\n *\n * @param {string} base64\n * @param {string} [mimeType]\n * @returns {string} base64 が空の場合はそのまま返す\n */\nexport function base64ToDataURL(base64: string, mimeType?: string): string {\n if (!base64) {\n return base64;\n }\n return createDataURL(base64, mimeType || analyzeFileType(base64)?.mime);\n}\n\n/**\n * base64 データを ArrayBuffer に変換する\n *\n * @param {string} base64\n * @returns {ArrayBuffer}\n */\nexport function base64ToArrayBuffer(base64: string): ArrayBuffer {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes.buffer;\n}\n\n/**\n * base64 データを Blob に変換する\n * MIME タイプを省略した場合はデータの先頭バイトから判定する。判定できない場合は type が空の Blob になる\n *\n * @param {string} base64\n * @param {string} [mimeType]\n * @returns {Blob}\n */\nexport function base64ToBlob(base64: string, mimeType?: string): Blob {\n const buffer = base64ToArrayBuffer(base64);\n return new Blob([buffer], { type: mimeType || analyzeFileType(buffer)?.mime || '' });\n}\n\n/**\n * DataURL から base64 データを取り出す\n *\n * @param {string} dataURL\n * @returns {string} DataURL 形式でない場合はそのまま返す\n */\nexport function dataURLToBase64(dataURL: string): string {\n return DATA_URL_PATTERN.exec(dataURL)?.[2] ?? dataURL;\n}\n\n/**\n * DataURL を ArrayBuffer に変換する\n *\n * @param {string} dataURL\n * @returns {ArrayBuffer}\n */\nexport function dataURLToArrayBuffer(dataURL: string): ArrayBuffer {\n return base64ToArrayBuffer(dataURLToBase64(dataURL));\n}\n\n/**\n * バイナリを base64 データに変換する\n *\n * @param {BinaryInput} data\n * @returns {string}\n */\nexport function arrayBufferToBase64(data: BinaryInput): string {\n const bytes = toBytes(data);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n\n/**\n * バイナリを DataURL に変換する\n *\n * @param {BinaryInput} data\n * @param {string} [mimeType] 省略時は 'application/octet-stream'\n * @returns {string}\n */\nexport function arrayBufferToDataURL(data: BinaryInput, mimeType?: string): string {\n return createDataURL(arrayBufferToBase64(data), mimeType);\n}\n\n/**\n * base64 データまたは DataURL が表すデータのバイト数を返す\n *\n * @param {string} data\n * @returns {number}\n */\nexport function calcSize(data: string): number {\n return dataURLToArrayBuffer(data).byteLength;\n}\n\n/**\n * 文字列またはバイナリを、BOM 付き UTF-16 の CSV の Blob にする\n * バイナリはすでに UTF-16LE で符号化されているものとして BOM だけを付ける\n *\n * @param {string | BinaryInput} data\n * @returns {Blob}\n */\nexport function convertUTF16withBOM(data: string | BinaryInput): Blob {\n if (!data) {\n return new Blob([]);\n }\n let parts: BlobPart[];\n if (typeof data === 'string') {\n const text = `\\ufeff${data}`;\n const codes = new Uint16Array(text.length);\n for (let i = 0; i < text.length; i++) {\n codes[i] = text.charCodeAt(i);\n }\n parts = [codes];\n } else {\n // 文字列で BOM を渡すと Blob が UTF-8 で符号化してしまうため、UTF-16LE の BOM をバイト列で付ける\n parts = [new Uint8Array([0xFF, 0xFE]), toArrayBuffer(data)];\n }\n return new Blob(parts, { type: 'text/csv;charset=utf-16;' });\n}\n\n/**\n * データの先頭バイトの署名からファイルの種類を判定する\n * 判定できる種類: PNG / JPEG / GIF / WebP / BMP / TIFF / SVG / PDF / ZIP / XLSX / DOCX / PPTX\n * 文字列は、DataURL 形式ならその base64 部分を、そうでなければ base64 データとみなす\n *\n * @param {string | BinaryInput} data\n * @returns {FileType | null} 判定できない場合は null\n */\nexport function analyzeFileType(data: string | BinaryInput): FileType | null {\n let bytes: Uint8Array;\n if (typeof data === 'string') {\n const base64 = dataURLToBase64(data).slice(0, SIGNATURE_BASE64_LENGTH);\n try {\n // 判定に必要な先頭だけを復号する。4文字単位で切らないと末尾がパディング不正になる\n bytes = toBytes(base64ToArrayBuffer(base64.slice(0, base64.length - base64.length % 4)));\n } catch (error) {\n // base64 として復号できない文字列は判定できない\n return null;\n }\n } else {\n bytes = toBytes(data);\n }\n return detectFileType(bytes);\n}\n\n/**\n * ファイル名に使えない文字(\\ / : * ? \" < > |)を取り除く\n *\n * @param {string} name\n * @returns {string}\n */\nexport function sanitizeFileName(name: string): string {\n return name.replace(/[\\\\/:*?\"<>|]/g, '');\n}\n"],"names":["DATA_URL_PATTERN","DEFAULT_MIME_TYPE","SVG_PATTERN","OFFICE_FILE_TYPES","AVIF_BRANDS","toBytes","data","toArrayBuffer","startsWith","bytes","signature","offset","expected","c","value","i","readBrands","end","text","brands","detectFileType","a","office","createDataURL","base64","mimeType","parseDataURL","dataURL","matcher","analyzeFileType","readAsDataURL","base64ToDataURL","buffer","arrayBufferToDataURL","readAsArrayBuffer","dataURLToArrayBuffer","base64ToArrayBuffer","binary","base64ToBlob","dataURLToBase64","arrayBufferToBase64","calcSize","convertUTF16withBOM","parts","codes","sanitizeFileName","name"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- const a = /^data:([^;,]+)?(?:;[^,]*)?;base64,(.*)$/s, g = "application/octet-stream";
1
+ const u = /^data:([^;,]+)?(?:;[^,]*)?;base64,(.*)$/s, g = "application/octet-stream";
2
2
  const T = /^\ufeff?\s*(?:<\?xml[^>]*>\s*)?(?:<!--[\s\S]*?-->\s*)*(?:<!DOCTYPE[^>]*>\s*)?<svg[\s>]/i, B = [
3
3
  { entry: "word/", type: { ext: "docx", mime: "application/vnd.openxmlformats-officedocument.wordprocessingml.document" } },
4
4
  { entry: "xl/", type: { ext: "xlsx", mime: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" } },
@@ -11,7 +11,7 @@ const T = /^\ufeff?\s*(?:<\?xml[^>]*>\s*)?(?:<!--[\s\S]*?-->\s*)*(?:<!DOCTYPE[^>
11
11
  for (let o = 16; o + 4 <= t; o += 4)
12
12
  r.push(n.slice(o, o + 4));
13
13
  return r;
14
- }, E = (e) => {
14
+ }, b = (e) => {
15
15
  if (i(e, [137, 80, 78, 71, 13, 10, 26, 10]))
16
16
  return { ext: "png", mime: "image/png" };
17
17
  if (i(e, [255, 216, 255]))
@@ -34,39 +34,43 @@ const T = /^\ufeff?\s*(?:<\?xml[^>]*>\s*)?(?:<!--[\s\S]*?-->\s*)*(?:<!DOCTYPE[^>
34
34
  }
35
35
  return T.test(new TextDecoder().decode(e)) ? { ext: "svg", mime: "image/svg+xml" } : null;
36
36
  };
37
- function u(e, t) {
37
+ function m(e, t) {
38
38
  return `data:${t || g};base64,${e}`;
39
39
  }
40
- function F(e) {
41
- const t = a.exec(e), n = t ? t[2] : e;
40
+ function E(e) {
41
+ const t = u.exec(e), n = t ? t[2] : e;
42
42
  return [n, f(n)?.mime ?? t?.[1] ?? g];
43
43
  }
44
- async function U(e) {
44
+ async function F(e) {
45
45
  if (typeof e == "string")
46
- return a.test(e) ? e : y(e);
46
+ return u.test(e) ? e : y(e);
47
47
  if (e instanceof Blob) {
48
48
  const t = await e.arrayBuffer();
49
- return s(t, e.type || f(t)?.mime);
49
+ return a(t, e.type || f(t)?.mime);
50
50
  }
51
- return s(e, f(e)?.mime);
51
+ return a(e, f(e)?.mime);
52
52
  }
53
- async function _(e) {
53
+ async function U(e) {
54
54
  return typeof e == "string" ? p(e) : e instanceof Blob ? e.arrayBuffer() : x(e);
55
55
  }
56
56
  function y(e, t) {
57
- return e && u(e, t || f(e)?.mime);
57
+ return e && m(e, t || f(e)?.mime);
58
58
  }
59
- function l(e) {
59
+ function s(e) {
60
60
  const t = atob(e), n = new Uint8Array(t.length);
61
61
  for (let r = 0; r < t.length; r++)
62
62
  n[r] = t.charCodeAt(r);
63
63
  return n.buffer;
64
64
  }
65
- function m(e) {
66
- return a.exec(e)?.[2] ?? e;
65
+ function _(e, t) {
66
+ const n = s(e);
67
+ return new Blob([n], { type: t || f(n)?.mime || "" });
68
+ }
69
+ function l(e) {
70
+ return u.exec(e)?.[2] ?? e;
67
71
  }
68
72
  function p(e) {
69
- return l(m(e));
73
+ return s(l(e));
70
74
  }
71
75
  function h(e) {
72
76
  const t = c(e);
@@ -75,8 +79,8 @@ function h(e) {
75
79
  n += String.fromCharCode(t[r]);
76
80
  return btoa(n);
77
81
  }
78
- function s(e, t) {
79
- return u(h(e), t);
82
+ function a(e, t) {
83
+ return m(h(e), t);
80
84
  }
81
85
  function v(e) {
82
86
  return p(e).byteLength;
@@ -97,51 +101,53 @@ function D(e) {
97
101
  function f(e) {
98
102
  let t;
99
103
  if (typeof e == "string") {
100
- const n = m(e).slice(0, 16384);
104
+ const n = l(e).slice(0, 16384);
101
105
  try {
102
- t = c(l(n.slice(0, n.length - n.length % 4)));
106
+ t = c(s(n.slice(0, n.length - n.length % 4)));
103
107
  } catch {
104
108
  return null;
105
109
  }
106
110
  } else
107
111
  t = c(e);
108
- return E(t);
112
+ return b(t);
109
113
  }
110
- function b(e) {
114
+ function L(e) {
111
115
  return e.replace(/[\\/:*?"<>|]/g, "");
112
116
  }
113
- const L = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
117
+ const R = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
114
118
  __proto__: null,
115
119
  analyzeFileType: f,
116
120
  arrayBufferToBase64: h,
117
- arrayBufferToDataURL: s,
118
- base64ToArrayBuffer: l,
121
+ arrayBufferToDataURL: a,
122
+ base64ToArrayBuffer: s,
123
+ base64ToBlob: _,
119
124
  base64ToDataURL: y,
120
125
  calcSize: v,
121
126
  convertUTF16withBOM: D,
122
- createDataURL: u,
127
+ createDataURL: m,
123
128
  dataURLToArrayBuffer: p,
124
- dataURLToBase64: m,
125
- parseDataURL: F,
126
- readAsArrayBuffer: _,
127
- readAsDataURL: U,
128
- sanitizeFileName: b
129
+ dataURLToBase64: l,
130
+ parseDataURL: E,
131
+ readAsArrayBuffer: U,
132
+ readAsDataURL: F,
133
+ sanitizeFileName: L
129
134
  }, Symbol.toStringTag, { value: "Module" }));
130
135
  export {
131
136
  f as a,
132
137
  h as b,
133
- s as c,
134
- l as d,
135
- y as e,
136
- L as f,
137
- v as g,
138
- D as h,
139
- u as i,
140
- p as j,
141
- m as k,
142
- U as l,
143
- F as p,
144
- _ as r,
145
- b as s
138
+ a as c,
139
+ s as d,
140
+ _ as e,
141
+ R as f,
142
+ y as g,
143
+ v as h,
144
+ D as i,
145
+ m as j,
146
+ p as k,
147
+ l,
148
+ F as m,
149
+ E as p,
150
+ U as r,
151
+ L as s
146
152
  };
147
- //# sourceMappingURL=file-util-CO5vjmkO.js.map
153
+ //# sourceMappingURL=file-util-DrU0xUXt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-util-DrU0xUXt.js","sources":["../src/file-util.ts"],"sourcesContent":["/** 先頭バイトの署名から判定したファイルの種類 */\nexport interface FileType {\n /** 拡張子(ドットなし) */\n ext: string;\n /** MIMEタイプ */\n mime: string;\n}\n\n/** バイナリとして受け付ける値。Node.js の Buffer も ArrayBufferView として渡せる */\nexport type BinaryInput = ArrayBuffer | ArrayBufferView;\n\nconst DATA_URL_PATTERN = /^data:([^;,]+)?(?:;[^,]*)?;base64,(.*)$/s;\n\nconst DEFAULT_MIME_TYPE = 'application/octet-stream';\n\n/** 種類の判定に使う先頭の base64 の文字数。ZIP の中のエントリ名を探すため数KB分を見る */\nconst SIGNATURE_BASE64_LENGTH = 16384;\n\nconst SVG_PATTERN = /^\\ufeff?\\s*(?:<\\?xml[^>]*>\\s*)?(?:<!--[\\s\\S]*?-->\\s*)*(?:<!DOCTYPE[^>]*>\\s*)?<svg[\\s>]/i;\n\nconst OFFICE_FILE_TYPES: { entry: string; type: FileType; }[] = [\n { entry: 'word/', type: { ext: 'docx', mime: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' } },\n { entry: 'xl/', type: { ext: 'xlsx', mime: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' } },\n { entry: 'ppt/', type: { ext: 'pptx', mime: 'application/vnd.openxmlformats-officedocument.presentationml.presentation' } }\n];\n\n/** ftyp ボックスのブランドのうち、AVIF を表すもの */\nconst AVIF_BRANDS = ['avif', 'avis'];\n\nconst toBytes = (data: BinaryInput): Uint8Array => {\n return data instanceof ArrayBuffer ? new Uint8Array(data) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);\n};\n\nconst toArrayBuffer = (data: BinaryInput): ArrayBuffer => toBytes(data).slice().buffer as ArrayBuffer;\n\nconst startsWith = (bytes: Uint8Array, signature: number[] | string, offset: number = 0): boolean => {\n const expected = typeof signature === 'string' ? Array.from(signature, c => c.charCodeAt(0)) : signature;\n if (bytes.length < offset + expected.length) {\n return false;\n }\n return expected.every((value, i) => bytes[offset + i] === value);\n};\n\n/**\n * ISOBMFF の ftyp ボックスに並ぶブランドを返す\n * 8バイト目からメジャーブランド、16バイト目から互換ブランドが4文字ずつ並ぶ\n *\n * @param {Uint8Array} bytes\n * @returns {string[]}\n */\nconst readBrands = (bytes: Uint8Array): string[] => {\n const end = Math.min(new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(0), bytes.length);\n const text = new TextDecoder('latin1').decode(bytes.subarray(0, end));\n const brands = [text.slice(8, 12)];\n for (let i = 16; i + 4 <= end; i += 4) {\n brands.push(text.slice(i, i + 4));\n }\n return brands;\n};\n\nconst detectFileType = (bytes: Uint8Array): FileType | null => {\n if (startsWith(bytes, [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A])) {\n return { ext: 'png', mime: 'image/png' };\n }\n if (startsWith(bytes, [0xFF, 0xD8, 0xFF])) {\n return { ext: 'jpg', mime: 'image/jpeg' };\n }\n if (startsWith(bytes, 'GIF87a') || startsWith(bytes, 'GIF89a')) {\n return { ext: 'gif', mime: 'image/gif' };\n }\n if (startsWith(bytes, 'RIFF') && startsWith(bytes, 'WEBP', 8)) {\n return { ext: 'webp', mime: 'image/webp' };\n }\n if (startsWith(bytes, 'BM')) {\n return { ext: 'bmp', mime: 'image/bmp' };\n }\n if (startsWith(bytes, [0x49, 0x49, 0x2A, 0x00]) || startsWith(bytes, [0x4D, 0x4D, 0x00, 0x2A])) {\n return { ext: 'tif', mime: 'image/tiff' };\n }\n if (startsWith(bytes, 'ftyp', 4) && readBrands(bytes).some(a => AVIF_BRANDS.includes(a))) {\n return { ext: 'avif', mime: 'image/avif' };\n }\n if (startsWith(bytes, '%PDF-')) {\n return { ext: 'pdf', mime: 'application/pdf' };\n }\n if (startsWith(bytes, [0x50, 0x4B, 0x03, 0x04]) || startsWith(bytes, [0x50, 0x4B, 0x05, 0x06]) || startsWith(bytes, [0x50, 0x4B, 0x07, 0x08])) {\n // Office Open XML も ZIP なので、ZIP に含まれるエントリ名で見分ける\n const text = new TextDecoder('latin1').decode(bytes);\n const office = OFFICE_FILE_TYPES.find(a => text.includes(a.entry));\n return office ? office.type : { ext: 'zip', mime: 'application/zip' };\n }\n if (SVG_PATTERN.test(new TextDecoder().decode(bytes))) {\n return { ext: 'svg', mime: 'image/svg+xml' };\n }\n return null;\n};\n\n/**\n * base64 データと MIME タイプから DataURL を生成する\n *\n * @param {string} base64\n * @param {string} [mimeType] 省略時は 'application/octet-stream'\n * @returns {string}\n */\nexport function createDataURL(base64: string, mimeType?: string): string {\n return `data:${mimeType || DEFAULT_MIME_TYPE};base64,${base64}`;\n}\n\n/**\n * DataURL を base64 データと MIME タイプに分解する\n * MIME タイプは DataURL に書かれた値ではなく、データの先頭バイトから判定した値を返す。判定できない場合は DataURL に書かれた値、それもなければ 'application/octet-stream'\n * DataURL 形式でない文字列は base64 データとみなす\n *\n * @param {string} dataURL\n * @returns {[string, string]} [base64, mimeType]\n */\nexport function parseDataURL(dataURL: string): [string, string] {\n const matcher = DATA_URL_PATTERN.exec(dataURL);\n const base64 = matcher ? matcher[2] : dataURL;\n return [base64, analyzeFileType(base64)?.mime ?? matcher?.[1] ?? DEFAULT_MIME_TYPE];\n}\n\n/**\n * データを読み込み DataURL を返す\n * 文字列は、DataURL 形式ならそのまま、そうでなければ base64 データとみなす\n * Blob は Blob の type を、それがなければ先頭バイトから判定した MIME タイプを使う\n *\n * @param {string | Blob | BinaryInput} data\n * @returns {Promise<string>}\n */\nexport async function readAsDataURL(data: string | Blob | BinaryInput): Promise<string> {\n if (typeof data === 'string') {\n return DATA_URL_PATTERN.test(data) ? data : base64ToDataURL(data);\n }\n if (data instanceof Blob) {\n const buffer = await data.arrayBuffer();\n return arrayBufferToDataURL(buffer, data.type || analyzeFileType(buffer)?.mime);\n }\n return arrayBufferToDataURL(data, analyzeFileType(data)?.mime);\n}\n\n/**\n * データを読み込み ArrayBuffer を返す\n * 文字列は、DataURL 形式ならその base64 部分を、そうでなければ base64 データとみなして変換する\n *\n * @param {string | Blob | BinaryInput} data\n * @returns {Promise<ArrayBuffer>}\n */\nexport async function readAsArrayBuffer(data: string | Blob | BinaryInput): Promise<ArrayBuffer> {\n if (typeof data === 'string') {\n return dataURLToArrayBuffer(data);\n }\n if (data instanceof Blob) {\n return data.arrayBuffer();\n }\n return toArrayBuffer(data);\n}\n\n/**\n * base64 データを DataURL に変換する\n * MIME タイプを省略した場合はデータの先頭バイトから判定する\n *\n * @param {string} base64\n * @param {string} [mimeType]\n * @returns {string} base64 が空の場合はそのまま返す\n */\nexport function base64ToDataURL(base64: string, mimeType?: string): string {\n if (!base64) {\n return base64;\n }\n return createDataURL(base64, mimeType || analyzeFileType(base64)?.mime);\n}\n\n/**\n * base64 データを ArrayBuffer に変換する\n *\n * @param {string} base64\n * @returns {ArrayBuffer}\n */\nexport function base64ToArrayBuffer(base64: string): ArrayBuffer {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes.buffer;\n}\n\n/**\n * base64 データを Blob に変換する\n * MIME タイプを省略した場合はデータの先頭バイトから判定する。判定できない場合は type が空の Blob になる\n *\n * @param {string} base64\n * @param {string} [mimeType]\n * @returns {Blob}\n */\nexport function base64ToBlob(base64: string, mimeType?: string): Blob {\n const buffer = base64ToArrayBuffer(base64);\n return new Blob([buffer], { type: mimeType || analyzeFileType(buffer)?.mime || '' });\n}\n\n/**\n * DataURL から base64 データを取り出す\n *\n * @param {string} dataURL\n * @returns {string} DataURL 形式でない場合はそのまま返す\n */\nexport function dataURLToBase64(dataURL: string): string {\n return DATA_URL_PATTERN.exec(dataURL)?.[2] ?? dataURL;\n}\n\n/**\n * DataURL を ArrayBuffer に変換する\n *\n * @param {string} dataURL\n * @returns {ArrayBuffer}\n */\nexport function dataURLToArrayBuffer(dataURL: string): ArrayBuffer {\n return base64ToArrayBuffer(dataURLToBase64(dataURL));\n}\n\n/**\n * バイナリを base64 データに変換する\n *\n * @param {BinaryInput} data\n * @returns {string}\n */\nexport function arrayBufferToBase64(data: BinaryInput): string {\n const bytes = toBytes(data);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n\n/**\n * バイナリを DataURL に変換する\n *\n * @param {BinaryInput} data\n * @param {string} [mimeType] 省略時は 'application/octet-stream'\n * @returns {string}\n */\nexport function arrayBufferToDataURL(data: BinaryInput, mimeType?: string): string {\n return createDataURL(arrayBufferToBase64(data), mimeType);\n}\n\n/**\n * base64 データまたは DataURL が表すデータのバイト数を返す\n *\n * @param {string} data\n * @returns {number}\n */\nexport function calcSize(data: string): number {\n return dataURLToArrayBuffer(data).byteLength;\n}\n\n/**\n * 文字列またはバイナリを、BOM 付き UTF-16 の CSV の Blob にする\n * バイナリはすでに UTF-16LE で符号化されているものとして BOM だけを付ける\n *\n * @param {string | BinaryInput} data\n * @returns {Blob}\n */\nexport function convertUTF16withBOM(data: string | BinaryInput): Blob {\n if (!data) {\n return new Blob([]);\n }\n let parts: BlobPart[];\n if (typeof data === 'string') {\n const text = `\\ufeff${data}`;\n const codes = new Uint16Array(text.length);\n for (let i = 0; i < text.length; i++) {\n codes[i] = text.charCodeAt(i);\n }\n parts = [codes];\n } else {\n // 文字列で BOM を渡すと Blob が UTF-8 で符号化してしまうため、UTF-16LE の BOM をバイト列で付ける\n parts = [new Uint8Array([0xFF, 0xFE]), toArrayBuffer(data)];\n }\n return new Blob(parts, { type: 'text/csv;charset=utf-16;' });\n}\n\n/**\n * データの先頭バイトの署名からファイルの種類を判定する\n * 判定できる種類: PNG / JPEG / GIF / WebP / BMP / TIFF / SVG / PDF / ZIP / XLSX / DOCX / PPTX\n * 文字列は、DataURL 形式ならその base64 部分を、そうでなければ base64 データとみなす\n *\n * @param {string | BinaryInput} data\n * @returns {FileType | null} 判定できない場合は null\n */\nexport function analyzeFileType(data: string | BinaryInput): FileType | null {\n let bytes: Uint8Array;\n if (typeof data === 'string') {\n const base64 = dataURLToBase64(data).slice(0, SIGNATURE_BASE64_LENGTH);\n try {\n // 判定に必要な先頭だけを復号する。4文字単位で切らないと末尾がパディング不正になる\n bytes = toBytes(base64ToArrayBuffer(base64.slice(0, base64.length - base64.length % 4)));\n } catch (error) {\n // base64 として復号できない文字列は判定できない\n return null;\n }\n } else {\n bytes = toBytes(data);\n }\n return detectFileType(bytes);\n}\n\n/**\n * ファイル名に使えない文字(\\ / : * ? \" < > |)を取り除く\n *\n * @param {string} name\n * @returns {string}\n */\nexport function sanitizeFileName(name: string): string {\n return name.replace(/[\\\\/:*?\"<>|]/g, '');\n}\n"],"names":["DATA_URL_PATTERN","DEFAULT_MIME_TYPE","SVG_PATTERN","OFFICE_FILE_TYPES","AVIF_BRANDS","toBytes","data","toArrayBuffer","startsWith","bytes","signature","offset","expected","c","value","i","readBrands","end","text","brands","detectFileType","a","office","createDataURL","base64","mimeType","parseDataURL","dataURL","matcher","analyzeFileType","readAsDataURL","base64ToDataURL","buffer","arrayBufferToDataURL","readAsArrayBuffer","dataURLToArrayBuffer","base64ToArrayBuffer","binary","base64ToBlob","dataURLToBase64","arrayBufferToBase64","calcSize","convertUTF16withBOM","parts","codes","sanitizeFileName","name"],"mappings":"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"}
package/lib/file-util.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("./file-util-Dqiw5tBQ.cjs");exports.analyzeFileType=a.analyzeFileType;exports.arrayBufferToBase64=a.arrayBufferToBase64;exports.arrayBufferToDataURL=a.arrayBufferToDataURL;exports.base64ToArrayBuffer=a.base64ToArrayBuffer;exports.base64ToDataURL=a.base64ToDataURL;exports.calcSize=a.calcSize;exports.convertUTF16withBOM=a.convertUTF16withBOM;exports.createDataURL=a.createDataURL;exports.dataURLToArrayBuffer=a.dataURLToArrayBuffer;exports.dataURLToBase64=a.dataURLToBase64;exports.parseDataURL=a.parseDataURL;exports.readAsArrayBuffer=a.readAsArrayBuffer;exports.readAsDataURL=a.readAsDataURL;exports.sanitizeFileName=a.sanitizeFileName;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("./file-util-8dZPFn1f.cjs");exports.analyzeFileType=a.analyzeFileType;exports.arrayBufferToBase64=a.arrayBufferToBase64;exports.arrayBufferToDataURL=a.arrayBufferToDataURL;exports.base64ToArrayBuffer=a.base64ToArrayBuffer;exports.base64ToBlob=a.base64ToBlob;exports.base64ToDataURL=a.base64ToDataURL;exports.calcSize=a.calcSize;exports.convertUTF16withBOM=a.convertUTF16withBOM;exports.createDataURL=a.createDataURL;exports.dataURLToArrayBuffer=a.dataURLToArrayBuffer;exports.dataURLToBase64=a.dataURLToBase64;exports.parseDataURL=a.parseDataURL;exports.readAsArrayBuffer=a.readAsArrayBuffer;exports.readAsDataURL=a.readAsDataURL;exports.sanitizeFileName=a.sanitizeFileName;
2
2
  //# sourceMappingURL=file-util.cjs.map
@@ -57,6 +57,15 @@ export declare function base64ToDataURL(base64: string, mimeType?: string): stri
57
57
  * @returns {ArrayBuffer}
58
58
  */
59
59
  export declare function base64ToArrayBuffer(base64: string): ArrayBuffer;
60
+ /**
61
+ * base64 データを Blob に変換する
62
+ * MIME タイプを省略した場合はデータの先頭バイトから判定する。判定できない場合は type が空の Blob になる
63
+ *
64
+ * @param {string} base64
65
+ * @param {string} [mimeType]
66
+ * @returns {Blob}
67
+ */
68
+ export declare function base64ToBlob(base64: string, mimeType?: string): Blob;
60
69
  /**
61
70
  * DataURL から base64 データを取り出す
62
71
  *
@@ -57,6 +57,15 @@ export declare function base64ToDataURL(base64: string, mimeType?: string): stri
57
57
  * @returns {ArrayBuffer}
58
58
  */
59
59
  export declare function base64ToArrayBuffer(base64: string): ArrayBuffer;
60
+ /**
61
+ * base64 データを Blob に変換する
62
+ * MIME タイプを省略した場合はデータの先頭バイトから判定する。判定できない場合は type が空の Blob になる
63
+ *
64
+ * @param {string} base64
65
+ * @param {string} [mimeType]
66
+ * @returns {Blob}
67
+ */
68
+ export declare function base64ToBlob(base64: string, mimeType?: string): Blob;
60
69
  /**
61
70
  * DataURL から base64 データを取り出す
62
71
  *
package/lib/file-util.js CHANGED
@@ -1,18 +1,19 @@
1
- import { a as r, b as s, c as t, d as f, e as o, g as B, h as T, i as U, j as i, k as y, p as L, r as R, l as c, s as d } from "./file-util-CO5vjmkO.js";
1
+ import { a as s, b as r, c as t, d as f, e as o, g as B, h as T, i as U, j as i, k as y, l as L, p as R, r as l, m as b, s as c } from "./file-util-DrU0xUXt.js";
2
2
  export {
3
- r as analyzeFileType,
4
- s as arrayBufferToBase64,
3
+ s as analyzeFileType,
4
+ r as arrayBufferToBase64,
5
5
  t as arrayBufferToDataURL,
6
6
  f as base64ToArrayBuffer,
7
- o as base64ToDataURL,
8
- B as calcSize,
9
- T as convertUTF16withBOM,
10
- U as createDataURL,
11
- i as dataURLToArrayBuffer,
12
- y as dataURLToBase64,
13
- L as parseDataURL,
14
- R as readAsArrayBuffer,
15
- c as readAsDataURL,
16
- d as sanitizeFileName
7
+ o as base64ToBlob,
8
+ B as base64ToDataURL,
9
+ T as calcSize,
10
+ U as convertUTF16withBOM,
11
+ i as createDataURL,
12
+ y as dataURLToArrayBuffer,
13
+ L as dataURLToBase64,
14
+ R as parseDataURL,
15
+ l as readAsArrayBuffer,
16
+ b as readAsDataURL,
17
+ c as sanitizeFileName
17
18
  };
18
19
  //# sourceMappingURL=file-util.js.map
@@ -0,0 +1,2 @@
1
+ "use strict";const s=require("./json-util-CKnsxu1e.cjs"),c=/(<!--[\s\S]*?-->|<[^>]*>|&(?:#\d+|#x[\da-f]+|\w+);)/i,a={'"':"&quot;","&":"&amp;","'":"&#39;","<":"&lt;",">":"&gt;"},f=t=>t.replace(/["&'<>]/g,n=>a[n]);function i(t,n){if(!t)return"";const o=r=>r.replace(/\r\n|\r|\n/g,"<br>").replace(/\t/g,"&nbsp;&nbsp;").replace(/ /g,"&nbsp;");return n?.html?t.split(c).map((r,e)=>e%2===1?r:o(r)).join(""):o(f(t))}function l(t,n){const{html:o,...r}=n??{},e=s.formatJsonString(t,r);return e==null?"":i(String(e),{html:o})}const m=Object.freeze(Object.defineProperty({__proto__:null,formatJsonStringForWeb:l,formatStringForWeb:i},Symbol.toStringTag,{value:"Module"}));exports.formatJsonStringForWeb=l;exports.formatStringForWeb=i;exports.htmlUtil=m;
2
+ //# sourceMappingURL=html-util-DAqLW2ol.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-util-DAqLW2ol.cjs","sources":["../src/html-util.ts"],"sourcesContent":["import { formatJsonString } from './json-util';\nimport type { FormatJsonStringOptions } from './json-util';\n\nconst HTML_TOKEN = /(<!--[\\s\\S]*?-->|<[^>]*>|&(?:#\\d+|#x[\\da-f]+|\\w+);)/i;\n\nconst HTML_ESCAPE_CHARS: Record<string, string> = {\n '\"': '&quot;',\n '&': '&amp;',\n '\\'': '&#39;',\n '<': '&lt;',\n '>': '&gt;'\n};\n\nconst escapeHtml = (str: string): string => str.replace(/[\"&'<>]/g, (c) => HTML_ESCAPE_CHARS[c]);\n\n/**\n * 文字列をWEB表示用にフォーマットする\n * オプションのhtmlにより、入力文字列がHTMLなのかプレーンテキストなのかを指定可能\n *\n * @param {string | null | undefined} str\n * @param {*} [options]\n * ├ html boolean trueを指定した場合、入力された文字列をHTMLとして扱う\n * @returns {string}\n */\nexport function formatStringForWeb(str: string | null | undefined, options?: {\n html?: boolean;\n}): string {\n if (!str) {\n return '';\n }\n\n const formatText = (text: string): string => text\n .replace(/\\r\\n|\\r|\\n/g, '<br>')\n .replace(/\\t/g, '&nbsp;&nbsp;')\n .replace(/ /g, '&nbsp;');\n\n if (options?.html) {\n // 奇数番目がタグ・コメント・文字参照。偶数番目のテキスト部分だけをフォーマットする\n return str\n .split(HTML_TOKEN)\n .map((segment, i) => i % 2 === 1 ? segment : formatText(segment))\n .join('');\n }\n\n return formatText(escapeHtml(str));\n}\n\n/**\n * 値を整形したJSON文字列にしてWEB表示用にフォーマットする\n * formatJsonStringで整形した文字列をformatStringForWebで変換する\n *\n * @param {any} value\n * @param {*} [options] formatJsonStringのオプションに以下を加えたもの\n * ├ html boolean trueを指定した場合、文字列をHTMLとして扱う\n * @returns {string}\n */\nexport function formatJsonStringForWeb(value: any, options?: FormatJsonStringOptions & {\n html?: boolean;\n}): string {\n const { html, ...formatOptions } = options ?? {};\n const json = formatJsonString(value, formatOptions);\n return json == null ? '' : formatStringForWeb(String(json), { html });\n}\n"],"names":["HTML_TOKEN","HTML_ESCAPE_CHARS","escapeHtml","str","c","formatStringForWeb","options","formatText","text","segment","i","formatJsonStringForWeb","value","html","formatOptions","json","formatJsonString"],"mappings":"yDAGMA,EAAa,uDAEbC,EAA4C,CAChD,IAAK,SACL,IAAK,QACL,IAAM,QACN,IAAK,OACL,IAAK,MACP,EAEMC,EAAcC,GAAwBA,EAAI,QAAQ,WAAaC,GAAMH,EAAkBG,CAAC,CAAC,EAWxF,SAASC,EAAmBF,EAAgCG,EAExD,CACT,GAAI,CAACH,EACH,MAAO,GAGT,MAAMI,EAAcC,GAAyBA,EAC1C,QAAQ,cAAe,MAAM,EAC7B,QAAQ,MAAO,cAAc,EAC7B,QAAQ,KAAM,QAAQ,EAEzB,OAAIF,GAAS,KAEJH,EACJ,MAAMH,CAAU,EAChB,IAAI,CAACS,EAASC,IAAMA,EAAI,IAAM,EAAID,EAAUF,EAAWE,CAAO,CAAC,EAC/D,KAAK,EAAE,EAGLF,EAAWL,EAAWC,CAAG,CAAC,CACnC,CAWO,SAASQ,EAAuBC,EAAYN,EAExC,CACT,KAAM,CAAE,KAAAO,EAAM,GAAGC,CAAA,EAAkBR,GAAW,CAAA,EACxCS,EAAOC,EAAAA,iBAAiBJ,EAAOE,CAAa,EAClD,OAAOC,GAAQ,KAAO,GAAKV,EAAmB,OAAOU,CAAI,EAAG,CAAE,KAAAF,EAAM,CACtE"}
@@ -0,0 +1,29 @@
1
+ import { f as l } from "./json-util-C_Pm1BpJ.js";
2
+ const s = /(<!--[\s\S]*?-->|<[^>]*>|&(?:#\d+|#x[\da-f]+|\w+);)/i, c = {
3
+ '"': "&quot;",
4
+ "&": "&amp;",
5
+ "'": "&#39;",
6
+ "<": "&lt;",
7
+ ">": "&gt;"
8
+ }, i = (t) => t.replace(/["&'<>]/g, (r) => c[r]);
9
+ function a(t, r) {
10
+ if (!t)
11
+ return "";
12
+ const o = (n) => n.replace(/\r\n|\r|\n/g, "<br>").replace(/\t/g, "&nbsp;&nbsp;").replace(/ /g, "&nbsp;");
13
+ return r?.html ? t.split(s).map((n, e) => e % 2 === 1 ? n : o(n)).join("") : o(i(t));
14
+ }
15
+ function p(t, r) {
16
+ const { html: o, ...n } = r ?? {}, e = l(t, n);
17
+ return e == null ? "" : a(String(e), { html: o });
18
+ }
19
+ const m = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
20
+ __proto__: null,
21
+ formatJsonStringForWeb: p,
22
+ formatStringForWeb: a
23
+ }, Symbol.toStringTag, { value: "Module" }));
24
+ export {
25
+ a,
26
+ p as f,
27
+ m as h
28
+ };
29
+ //# sourceMappingURL=html-util-EI6f5f8f.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-util-EI6f5f8f.js","sources":["../src/html-util.ts"],"sourcesContent":["import { formatJsonString } from './json-util';\nimport type { FormatJsonStringOptions } from './json-util';\n\nconst HTML_TOKEN = /(<!--[\\s\\S]*?-->|<[^>]*>|&(?:#\\d+|#x[\\da-f]+|\\w+);)/i;\n\nconst HTML_ESCAPE_CHARS: Record<string, string> = {\n '\"': '&quot;',\n '&': '&amp;',\n '\\'': '&#39;',\n '<': '&lt;',\n '>': '&gt;'\n};\n\nconst escapeHtml = (str: string): string => str.replace(/[\"&'<>]/g, (c) => HTML_ESCAPE_CHARS[c]);\n\n/**\n * 文字列をWEB表示用にフォーマットする\n * オプションのhtmlにより、入力文字列がHTMLなのかプレーンテキストなのかを指定可能\n *\n * @param {string | null | undefined} str\n * @param {*} [options]\n * ├ html boolean trueを指定した場合、入力された文字列をHTMLとして扱う\n * @returns {string}\n */\nexport function formatStringForWeb(str: string | null | undefined, options?: {\n html?: boolean;\n}): string {\n if (!str) {\n return '';\n }\n\n const formatText = (text: string): string => text\n .replace(/\\r\\n|\\r|\\n/g, '<br>')\n .replace(/\\t/g, '&nbsp;&nbsp;')\n .replace(/ /g, '&nbsp;');\n\n if (options?.html) {\n // 奇数番目がタグ・コメント・文字参照。偶数番目のテキスト部分だけをフォーマットする\n return str\n .split(HTML_TOKEN)\n .map((segment, i) => i % 2 === 1 ? segment : formatText(segment))\n .join('');\n }\n\n return formatText(escapeHtml(str));\n}\n\n/**\n * 値を整形したJSON文字列にしてWEB表示用にフォーマットする\n * formatJsonStringで整形した文字列をformatStringForWebで変換する\n *\n * @param {any} value\n * @param {*} [options] formatJsonStringのオプションに以下を加えたもの\n * ├ html boolean trueを指定した場合、文字列をHTMLとして扱う\n * @returns {string}\n */\nexport function formatJsonStringForWeb(value: any, options?: FormatJsonStringOptions & {\n html?: boolean;\n}): string {\n const { html, ...formatOptions } = options ?? {};\n const json = formatJsonString(value, formatOptions);\n return json == null ? '' : formatStringForWeb(String(json), { html });\n}\n"],"names":["HTML_TOKEN","HTML_ESCAPE_CHARS","escapeHtml","str","c","formatStringForWeb","options","formatText","text","segment","i","formatJsonStringForWeb","value","html","formatOptions","json","formatJsonString"],"mappings":";AAGA,MAAMA,IAAa,wDAEbC,IAA4C;AAAA,EAChD,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AACP,GAEMC,IAAa,CAACC,MAAwBA,EAAI,QAAQ,YAAY,CAACC,MAAMH,EAAkBG,CAAC,CAAC;AAWxF,SAASC,EAAmBF,GAAgCG,GAExD;AACT,MAAI,CAACH;AACH,WAAO;AAGT,QAAMI,IAAa,CAACC,MAAyBA,EAC1C,QAAQ,eAAe,MAAM,EAC7B,QAAQ,OAAO,cAAc,EAC7B,QAAQ,MAAM,QAAQ;AAEzB,SAAIF,GAAS,OAEJH,EACJ,MAAMH,CAAU,EAChB,IAAI,CAACS,GAASC,MAAMA,IAAI,MAAM,IAAID,IAAUF,EAAWE,CAAO,CAAC,EAC/D,KAAK,EAAE,IAGLF,EAAWL,EAAWC,CAAG,CAAC;AACnC;AAWO,SAASQ,EAAuBC,GAAYN,GAExC;AACT,QAAM,EAAE,MAAAO,GAAM,GAAGC,EAAA,IAAkBR,KAAW,CAAA,GACxCS,IAAOC,EAAiBJ,GAAOE,CAAa;AAClD,SAAOC,KAAQ,OAAO,KAAKV,EAAmB,OAAOU,CAAI,GAAG,EAAE,MAAAF,GAAM;AACtE;;;;;;"}
package/lib/html-util.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});require("diff");require("./json-util-CKnsxu1e.cjs");const r=require("./html-util--mpzaYuJ.cjs");exports.diffForWeb=r.diffForWeb;exports.formatJsonStringForWeb=r.formatJsonStringForWeb;exports.formatStringForWeb=r.formatStringForWeb;exports.highlightWord=r.highlightWord;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});require("./json-util-CKnsxu1e.cjs");const r=require("./html-util-DAqLW2ol.cjs");exports.formatJsonStringForWeb=r.formatJsonStringForWeb;exports.formatStringForWeb=r.formatStringForWeb;
2
2
  //# sourceMappingURL=html-util.cjs.map
@@ -1,21 +1,4 @@
1
1
  import { FormatJsonStringOptions } from './json-util.cjs';
2
- /**
3
- * class属性に指定する値
4
- * 配列は要素を空白区切りで連結し、Recordは値がtrueのキーだけを連結する
5
- */
6
- export type HtmlClassValue = string | string[] | Record<string, boolean>;
7
- /**
8
- * style属性に指定する値
9
- * Recordのキーはキャメルケースをケバブケースに変換する。数値には単位を付けない
10
- */
11
- export type HtmlStyleValue = string | Record<string, string | number>;
12
- /**
13
- * 生成するタグに付与する属性
14
- */
15
- export interface HtmlTagOptions {
16
- class?: HtmlClassValue;
17
- style?: HtmlStyleValue;
18
- }
19
2
  /**
20
3
  * 文字列をWEB表示用にフォーマットする
21
4
  * オプションのhtmlにより、入力文字列がHTMLなのかプレーンテキストなのかを指定可能
@@ -40,48 +23,3 @@ export declare function formatStringForWeb(str: string | null | undefined, optio
40
23
  export declare function formatJsonStringForWeb(value: any, options?: FormatJsonStringOptions & {
41
24
  html?: boolean;
42
25
  }): string;
43
- /**
44
- * 文字列の中で一致したワードをmarkタグで囲んだHTML文字列を返す
45
- * markタグは既定の背景色・文字色を持つ。色はCSS変数(--dwui-background-highlight / --dwui-color-text-highlight)で変更できる
46
- * styleは既定の背景色・文字色より後に出力する
47
- * オプションのhtmlにより、入力文字列がHTMLなのかプレーンテキストなのかを指定可能
48
- *
49
- * 例)
50
- * HtmlUtil.highlightWord('This is a test message', 'test', { class: 'highlight' });
51
- * → 'This is a <mark class="highlight" style="background: var(--dwui-background-highlight, Mark); color: var(--dwui-color-text-highlight, MarkText)">test</mark> message'
52
- *
53
- * @param {string | null | undefined} value
54
- * @param {string | null | undefined} word
55
- * @param {*} [options] markタグに付与するclass, styleのほか、以下を指定できる
56
- * ├ class string | string[] | Record<string, boolean>
57
- * ├ style string | Record<string, string | number>
58
- * ├ caseInsensitive boolean trueを指定した場合、大文字小文字を区別しない
59
- * ├ html boolean trueを指定した場合、入力された文字列をHTMLとして扱う
60
- * @returns {string}
61
- */
62
- export declare function highlightWord(value: string | null | undefined, word: string | null | undefined, options?: HtmlTagOptions & {
63
- caseInsensitive?: boolean;
64
- html?: boolean;
65
- }): string;
66
- /**
67
- * 文字列を1文字ずつ比較し、差分をspanタグで囲んだHTML文字列を返す
68
- * 追加・削除・一致の部分ごとに既定の文字色を持つ。文字色はCSS変数(--dwui-color-text-diff-added / --dwui-color-text-diff-removed / --dwui-color-text-diff-same)で変更できる
69
- * 追加・削除・一致の部分ごとに、spanタグに付与するclass, styleを指定できる。styleは既定の文字色より後に出力する
70
- * 入力文字列はプレーンなテキストであるとみなす
71
- * 出力される文字列は、diffで埋め込まれるHTMLタグ以外はHTMLエスケープされ、HTMLセーフな文字列となる
72
- *
73
- * @param {string | null | undefined} text1 比較元の文字列
74
- * @param {string | null | undefined} text2 比較される文字列(通常、入力値はこちらに渡す)
75
- * @param {*} [options]
76
- * ├ ignoreCase boolean trueを指定した場合、大文字小文字を区別しない
77
- * ├ added HtmlTagOptions text2で追加された部分のspanタグに付与する属性
78
- * ├ removed HtmlTagOptions text2で削除された部分のspanタグに付与する属性
79
- * ├ same HtmlTagOptions 一致した部分のspanタグに付与する属性
80
- * @returns {string}
81
- */
82
- export declare function diffForWeb(text1: string | null | undefined, text2: string | null | undefined, options?: {
83
- ignoreCase?: boolean;
84
- added?: HtmlTagOptions;
85
- removed?: HtmlTagOptions;
86
- same?: HtmlTagOptions;
87
- }): string;
@@ -1,21 +1,4 @@
1
1
  import { FormatJsonStringOptions } from './json-util';
2
- /**
3
- * class属性に指定する値
4
- * 配列は要素を空白区切りで連結し、Recordは値がtrueのキーだけを連結する
5
- */
6
- export type HtmlClassValue = string | string[] | Record<string, boolean>;
7
- /**
8
- * style属性に指定する値
9
- * Recordのキーはキャメルケースをケバブケースに変換する。数値には単位を付けない
10
- */
11
- export type HtmlStyleValue = string | Record<string, string | number>;
12
- /**
13
- * 生成するタグに付与する属性
14
- */
15
- export interface HtmlTagOptions {
16
- class?: HtmlClassValue;
17
- style?: HtmlStyleValue;
18
- }
19
2
  /**
20
3
  * 文字列をWEB表示用にフォーマットする
21
4
  * オプションのhtmlにより、入力文字列がHTMLなのかプレーンテキストなのかを指定可能
@@ -40,48 +23,3 @@ export declare function formatStringForWeb(str: string | null | undefined, optio
40
23
  export declare function formatJsonStringForWeb(value: any, options?: FormatJsonStringOptions & {
41
24
  html?: boolean;
42
25
  }): string;
43
- /**
44
- * 文字列の中で一致したワードをmarkタグで囲んだHTML文字列を返す
45
- * markタグは既定の背景色・文字色を持つ。色はCSS変数(--dwui-background-highlight / --dwui-color-text-highlight)で変更できる
46
- * styleは既定の背景色・文字色より後に出力する
47
- * オプションのhtmlにより、入力文字列がHTMLなのかプレーンテキストなのかを指定可能
48
- *
49
- * 例)
50
- * HtmlUtil.highlightWord('This is a test message', 'test', { class: 'highlight' });
51
- * → 'This is a <mark class="highlight" style="background: var(--dwui-background-highlight, Mark); color: var(--dwui-color-text-highlight, MarkText)">test</mark> message'
52
- *
53
- * @param {string | null | undefined} value
54
- * @param {string | null | undefined} word
55
- * @param {*} [options] markタグに付与するclass, styleのほか、以下を指定できる
56
- * ├ class string | string[] | Record<string, boolean>
57
- * ├ style string | Record<string, string | number>
58
- * ├ caseInsensitive boolean trueを指定した場合、大文字小文字を区別しない
59
- * ├ html boolean trueを指定した場合、入力された文字列をHTMLとして扱う
60
- * @returns {string}
61
- */
62
- export declare function highlightWord(value: string | null | undefined, word: string | null | undefined, options?: HtmlTagOptions & {
63
- caseInsensitive?: boolean;
64
- html?: boolean;
65
- }): string;
66
- /**
67
- * 文字列を1文字ずつ比較し、差分をspanタグで囲んだHTML文字列を返す
68
- * 追加・削除・一致の部分ごとに既定の文字色を持つ。文字色はCSS変数(--dwui-color-text-diff-added / --dwui-color-text-diff-removed / --dwui-color-text-diff-same)で変更できる
69
- * 追加・削除・一致の部分ごとに、spanタグに付与するclass, styleを指定できる。styleは既定の文字色より後に出力する
70
- * 入力文字列はプレーンなテキストであるとみなす
71
- * 出力される文字列は、diffで埋め込まれるHTMLタグ以外はHTMLエスケープされ、HTMLセーフな文字列となる
72
- *
73
- * @param {string | null | undefined} text1 比較元の文字列
74
- * @param {string | null | undefined} text2 比較される文字列(通常、入力値はこちらに渡す)
75
- * @param {*} [options]
76
- * ├ ignoreCase boolean trueを指定した場合、大文字小文字を区別しない
77
- * ├ added HtmlTagOptions text2で追加された部分のspanタグに付与する属性
78
- * ├ removed HtmlTagOptions text2で削除された部分のspanタグに付与する属性
79
- * ├ same HtmlTagOptions 一致した部分のspanタグに付与する属性
80
- * @returns {string}
81
- */
82
- export declare function diffForWeb(text1: string | null | undefined, text2: string | null | undefined, options?: {
83
- ignoreCase?: boolean;
84
- added?: HtmlTagOptions;
85
- removed?: HtmlTagOptions;
86
- same?: HtmlTagOptions;
87
- }): string;
package/lib/html-util.js CHANGED
@@ -1,10 +1,7 @@
1
- import "diff";
2
1
  import "./json-util-C_Pm1BpJ.js";
3
- import { d as i, f, a as m, b as s } from "./html-util-B8sdLw9I.js";
2
+ import { f as a, a as f } from "./html-util-EI6f5f8f.js";
4
3
  export {
5
- i as diffForWeb,
6
- f as formatJsonStringForWeb,
7
- m as formatStringForWeb,
8
- s as highlightWord
4
+ a as formatJsonStringForWeb,
5
+ f as formatStringForWeb
9
6
  };
10
7
  //# sourceMappingURL=html-util.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"html-util.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}
1
+ {"version":3,"file":"html-util.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
package/lib/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("./crypto-util-BcHurtbE.cjs"),e=require("./zoned-date-time.cjs"),i=require("./date-util-CZmiQEYH.cjs"),l=require("./decimal.cjs"),r=require("./file-util-Dqiw5tBQ.cjs"),o=require("./html-util--mpzaYuJ.cjs"),U=require("./json-util-CKnsxu1e.cjs"),n=require("./number-util-BrDEKYJo.cjs"),c=require("./object-util-BHg61ifG.cjs"),s=require("./string-util-w2I5EYuY.cjs");exports.CryptoUtil=t.cryptoUtil;exports.ZonedDateTime=e.ZonedDateTime;exports.DateUtil=i.dateUtil;exports.Decimal=l.Decimal;exports.FileUtil=r.fileUtil;exports.HtmlUtil=o.htmlUtil;exports.JsonUtil=U.jsonUtil;exports.NumberUtil=n.numberUtil;exports.ObjectUtil=c.objectUtil;exports.StringUtil=s.stringUtil;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("./crypto-util-BcHurtbE.cjs"),e=require("./zoned-date-time.cjs"),i=require("./date-util-CZmiQEYH.cjs"),l=require("./decimal.cjs"),r=require("./file-util-8dZPFn1f.cjs"),o=require("./html-util-DAqLW2ol.cjs"),U=require("./json-util-CKnsxu1e.cjs"),n=require("./number-util-BrDEKYJo.cjs"),c=require("./object-util-BHg61ifG.cjs"),s=require("./string-util-w2I5EYuY.cjs");exports.CryptoUtil=t.cryptoUtil;exports.ZonedDateTime=e.ZonedDateTime;exports.DateUtil=i.dateUtil;exports.Decimal=l.Decimal;exports.FileUtil=r.fileUtil;exports.HtmlUtil=o.htmlUtil;exports.JsonUtil=U.jsonUtil;exports.NumberUtil=n.numberUtil;exports.ObjectUtil=c.objectUtil;exports.StringUtil=s.stringUtil;
2
2
  //# sourceMappingURL=index.cjs.map
package/lib/index.js CHANGED
@@ -2,8 +2,8 @@ import { c as r } from "./crypto-util-B5K2CmE2.js";
2
2
  import { ZonedDateTime as m } from "./zoned-date-time.js";
3
3
  import { d as a } from "./date-util-BNe2E-tA.js";
4
4
  import { Decimal as l } from "./decimal.js";
5
- import { f as s } from "./file-util-CO5vjmkO.js";
6
- import { h as U } from "./html-util-B8sdLw9I.js";
5
+ import { f as s } from "./file-util-DrU0xUXt.js";
6
+ import { h as U } from "./html-util-EI6f5f8f.js";
7
7
  import { j as c } from "./json-util-C_Pm1BpJ.js";
8
8
  import { n as b } from "./number-util-Wpubbqr4.js";
9
9
  import { o as j } from "./object-util-wOMJtGK3.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@digitalwalletcorp/utils",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "description": "A javascript utility.",
5
5
  "type": "module",
6
6
  "main": "lib/index.cjs",
@@ -66,7 +66,6 @@
66
66
  "dependencies": {
67
67
  "big.js": "7.0.1",
68
68
  "crypto-js": "4.2.0",
69
- "diff": "8.0.2",
70
69
  "luxon": "3.7.2"
71
70
  },
72
71
  "devDependencies": {
package/src/file-util.ts CHANGED
@@ -186,6 +186,19 @@ export function base64ToArrayBuffer(base64: string): ArrayBuffer {
186
186
  return bytes.buffer;
187
187
  }
188
188
 
189
+ /**
190
+ * base64 データを Blob に変換する
191
+ * MIME タイプを省略した場合はデータの先頭バイトから判定する。判定できない場合は type が空の Blob になる
192
+ *
193
+ * @param {string} base64
194
+ * @param {string} [mimeType]
195
+ * @returns {Blob}
196
+ */
197
+ export function base64ToBlob(base64: string, mimeType?: string): Blob {
198
+ const buffer = base64ToArrayBuffer(base64);
199
+ return new Blob([buffer], { type: mimeType || analyzeFileType(buffer)?.mime || '' });
200
+ }
201
+
189
202
  /**
190
203
  * DataURL から base64 データを取り出す
191
204
  *
package/src/html-util.ts CHANGED
@@ -1,27 +1,6 @@
1
- import { diffChars } from 'diff';
2
1
  import { formatJsonString } from './json-util';
3
2
  import type { FormatJsonStringOptions } from './json-util';
4
3
 
5
- /**
6
- * class属性に指定する値
7
- * 配列は要素を空白区切りで連結し、Recordは値がtrueのキーだけを連結する
8
- */
9
- export type HtmlClassValue = string | string[] | Record<string, boolean>;
10
-
11
- /**
12
- * style属性に指定する値
13
- * Recordのキーはキャメルケースをケバブケースに変換する。数値には単位を付けない
14
- */
15
- export type HtmlStyleValue = string | Record<string, string | number>;
16
-
17
- /**
18
- * 生成するタグに付与する属性
19
- */
20
- export interface HtmlTagOptions {
21
- class?: HtmlClassValue;
22
- style?: HtmlStyleValue;
23
- }
24
-
25
4
  const HTML_TOKEN = /(<!--[\s\S]*?-->|<[^>]*>|&(?:#\d+|#x[\da-f]+|\w+);)/i;
26
5
 
27
6
  const HTML_ESCAPE_CHARS: Record<string, string> = {
@@ -34,61 +13,6 @@ const HTML_ESCAPE_CHARS: Record<string, string> = {
34
13
 
35
14
  const escapeHtml = (str: string): string => str.replace(/["&'<>]/g, (c) => HTML_ESCAPE_CHARS[c]);
36
15
 
37
- const toClassString = (value: HtmlClassValue): string => {
38
- if (typeof value === 'string') {
39
- return value;
40
- }
41
- if (Array.isArray(value)) {
42
- return value.filter(Boolean).join(' ');
43
- }
44
- return Object.keys(value).filter(key => value[key]).join(' ');
45
- };
46
-
47
- const toStyleString = (value: HtmlStyleValue): string => {
48
- if (typeof value === 'string') {
49
- return value;
50
- }
51
- return Object.entries(value)
52
- .map(([key, v]) => {
53
- // カスタムプロパティ(--xxx)は大文字小文字を区別するため変換しない
54
- const property = key.startsWith('--') ? key : key.replace(/[A-Z]/g, c => `-${c.toLowerCase()}`);
55
- return `${property}: ${v}`;
56
- })
57
- .join('; ');
58
- };
59
-
60
- /** diffForWebの既定の文字色 */
61
- const DIFF_STYLES = {
62
- added: 'color: var(--dwui-color-text-diff-added, light-dark(#006400, rgb(121, 227, 121)))',
63
- removed: 'color: var(--dwui-color-text-diff-removed, light-dark(#ff0000, rgb(222, 109, 109)))',
64
- same: 'color: var(--dwui-color-text-diff-same, light-dark(#838383, #808080))'
65
- };
66
-
67
- /** highlightWordの既定の背景色・文字色。markタグのブラウザ標準の色をフォールバックにする */
68
- const HIGHLIGHT_STYLE = 'background: var(--dwui-background-highlight, Mark); color: var(--dwui-color-text-highlight, MarkText)';
69
-
70
- /**
71
- * 値をエスケープしたタグを返す
72
- *
73
- * @param {string} tagName
74
- * @param {string} value
75
- * @param {HtmlTagOptions} [options]
76
- * @param {string} [defaultStyle] optionsのstyleより前に出力するstyle
77
- * @returns {string}
78
- */
79
- const toElement = (tagName: string, value: string, options?: HtmlTagOptions, defaultStyle?: string): string => {
80
- let attributes = '';
81
- const className = options?.class == null ? '' : toClassString(options.class);
82
- if (className) {
83
- attributes += ` class="${escapeHtml(className)}"`;
84
- }
85
- const style = [defaultStyle, options?.style == null ? '' : toStyleString(options.style)].filter(Boolean).join('; ');
86
- if (style) {
87
- attributes += ` style="${escapeHtml(style)}"`;
88
- }
89
- return `<${tagName}${attributes}>${escapeHtml(value)}</${tagName}>`;
90
- };
91
-
92
16
  /**
93
17
  * 文字列をWEB表示用にフォーマットする
94
18
  * オプションのhtmlにより、入力文字列がHTMLなのかプレーンテキストなのかを指定可能
@@ -137,94 +61,3 @@ export function formatJsonStringForWeb(value: any, options?: FormatJsonStringOpt
137
61
  const json = formatJsonString(value, formatOptions);
138
62
  return json == null ? '' : formatStringForWeb(String(json), { html });
139
63
  }
140
-
141
- /**
142
- * 文字列の中で一致したワードをmarkタグで囲んだHTML文字列を返す
143
- * markタグは既定の背景色・文字色を持つ。色はCSS変数(--dwui-background-highlight / --dwui-color-text-highlight)で変更できる
144
- * styleは既定の背景色・文字色より後に出力する
145
- * オプションのhtmlにより、入力文字列がHTMLなのかプレーンテキストなのかを指定可能
146
- *
147
- * 例)
148
- * HtmlUtil.highlightWord('This is a test message', 'test', { class: 'highlight' });
149
- * → 'This is a <mark class="highlight" style="background: var(--dwui-background-highlight, Mark); color: var(--dwui-color-text-highlight, MarkText)">test</mark> message'
150
- *
151
- * @param {string | null | undefined} value
152
- * @param {string | null | undefined} word
153
- * @param {*} [options] markタグに付与するclass, styleのほか、以下を指定できる
154
- * ├ class string | string[] | Record<string, boolean>
155
- * ├ style string | Record<string, string | number>
156
- * ├ caseInsensitive boolean trueを指定した場合、大文字小文字を区別しない
157
- * ├ html boolean trueを指定した場合、入力された文字列をHTMLとして扱う
158
- * @returns {string}
159
- */
160
- export function highlightWord(
161
- value: string | null | undefined,
162
- word: string | null | undefined,
163
- options?: HtmlTagOptions & {
164
- caseInsensitive?: boolean;
165
- html?: boolean;
166
- }
167
- ): string {
168
- if (!value) {
169
- return '';
170
- }
171
-
172
- const toHtml = (text: string): string => options?.html ? text : escapeHtml(text);
173
- if (!word) {
174
- return toHtml(value);
175
- }
176
-
177
- const pattern = word.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d');
178
- const regex = new RegExp(`(${pattern})`, options?.caseInsensitive ? 'i' : '');
179
- // キャプチャグループで分割すると、奇数番目の要素が一致した部分になる
180
- const highlight = (text: string): string => text
181
- .split(regex)
182
- .map((part, i) => i % 2 === 0 ? toHtml(part) : toElement('mark', part, options, HIGHLIGHT_STYLE))
183
- .join('');
184
-
185
- if (!options?.html) {
186
- return highlight(value);
187
- }
188
-
189
- // 奇数番目がタグ・コメント・文字参照。偶数番目のテキスト部分だけをハイライトする
190
- return value
191
- .split(HTML_TOKEN)
192
- .map((segment, i) => i % 2 === 1 ? segment : highlight(segment))
193
- .join('');
194
- }
195
-
196
- /**
197
- * 文字列を1文字ずつ比較し、差分をspanタグで囲んだHTML文字列を返す
198
- * 追加・削除・一致の部分ごとに既定の文字色を持つ。文字色はCSS変数(--dwui-color-text-diff-added / --dwui-color-text-diff-removed / --dwui-color-text-diff-same)で変更できる
199
- * 追加・削除・一致の部分ごとに、spanタグに付与するclass, styleを指定できる。styleは既定の文字色より後に出力する
200
- * 入力文字列はプレーンなテキストであるとみなす
201
- * 出力される文字列は、diffで埋め込まれるHTMLタグ以外はHTMLエスケープされ、HTMLセーフな文字列となる
202
- *
203
- * @param {string | null | undefined} text1 比較元の文字列
204
- * @param {string | null | undefined} text2 比較される文字列(通常、入力値はこちらに渡す)
205
- * @param {*} [options]
206
- * ├ ignoreCase boolean trueを指定した場合、大文字小文字を区別しない
207
- * ├ added HtmlTagOptions text2で追加された部分のspanタグに付与する属性
208
- * ├ removed HtmlTagOptions text2で削除された部分のspanタグに付与する属性
209
- * ├ same HtmlTagOptions 一致した部分のspanタグに付与する属性
210
- * @returns {string}
211
- */
212
- export function diffForWeb(text1: string | null | undefined, text2: string | null | undefined, options?: {
213
- ignoreCase?: boolean;
214
- added?: HtmlTagOptions;
215
- removed?: HtmlTagOptions;
216
- same?: HtmlTagOptions;
217
- }): string {
218
- const changes = diffChars(text1 ?? '', text2 ?? '', { ignoreCase: options?.ignoreCase });
219
- let html = '';
220
- for (const change of changes) {
221
- if (change.added) {
222
- html += toElement('span', change.value, options?.added, DIFF_STYLES.added);
223
- } else if (change.removed) {
224
- html += toElement('span', change.value, options?.removed, DIFF_STYLES.removed);
225
- } else {
226
- html += toElement('span', change.value, options?.same, DIFF_STYLES.same);
227
- }
228
- }
229
- return html;
230
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"file-util-CO5vjmkO.js","sources":["../src/file-util.ts"],"sourcesContent":["/** 先頭バイトの署名から判定したファイルの種類 */\nexport interface FileType {\n /** 拡張子(ドットなし) */\n ext: string;\n /** MIMEタイプ */\n mime: string;\n}\n\n/** バイナリとして受け付ける値。Node.js の Buffer も ArrayBufferView として渡せる */\nexport type BinaryInput = ArrayBuffer | ArrayBufferView;\n\nconst DATA_URL_PATTERN = /^data:([^;,]+)?(?:;[^,]*)?;base64,(.*)$/s;\n\nconst DEFAULT_MIME_TYPE = 'application/octet-stream';\n\n/** 種類の判定に使う先頭の base64 の文字数。ZIP の中のエントリ名を探すため数KB分を見る */\nconst SIGNATURE_BASE64_LENGTH = 16384;\n\nconst SVG_PATTERN = /^\\ufeff?\\s*(?:<\\?xml[^>]*>\\s*)?(?:<!--[\\s\\S]*?-->\\s*)*(?:<!DOCTYPE[^>]*>\\s*)?<svg[\\s>]/i;\n\nconst OFFICE_FILE_TYPES: { entry: string; type: FileType; }[] = [\n { entry: 'word/', type: { ext: 'docx', mime: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' } },\n { entry: 'xl/', type: { ext: 'xlsx', mime: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' } },\n { entry: 'ppt/', type: { ext: 'pptx', mime: 'application/vnd.openxmlformats-officedocument.presentationml.presentation' } }\n];\n\n/** ftyp ボックスのブランドのうち、AVIF を表すもの */\nconst AVIF_BRANDS = ['avif', 'avis'];\n\nconst toBytes = (data: BinaryInput): Uint8Array => {\n return data instanceof ArrayBuffer ? new Uint8Array(data) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);\n};\n\nconst toArrayBuffer = (data: BinaryInput): ArrayBuffer => toBytes(data).slice().buffer as ArrayBuffer;\n\nconst startsWith = (bytes: Uint8Array, signature: number[] | string, offset: number = 0): boolean => {\n const expected = typeof signature === 'string' ? Array.from(signature, c => c.charCodeAt(0)) : signature;\n if (bytes.length < offset + expected.length) {\n return false;\n }\n return expected.every((value, i) => bytes[offset + i] === value);\n};\n\n/**\n * ISOBMFF の ftyp ボックスに並ぶブランドを返す\n * 8バイト目からメジャーブランド、16バイト目から互換ブランドが4文字ずつ並ぶ\n *\n * @param {Uint8Array} bytes\n * @returns {string[]}\n */\nconst readBrands = (bytes: Uint8Array): string[] => {\n const end = Math.min(new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(0), bytes.length);\n const text = new TextDecoder('latin1').decode(bytes.subarray(0, end));\n const brands = [text.slice(8, 12)];\n for (let i = 16; i + 4 <= end; i += 4) {\n brands.push(text.slice(i, i + 4));\n }\n return brands;\n};\n\nconst detectFileType = (bytes: Uint8Array): FileType | null => {\n if (startsWith(bytes, [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A])) {\n return { ext: 'png', mime: 'image/png' };\n }\n if (startsWith(bytes, [0xFF, 0xD8, 0xFF])) {\n return { ext: 'jpg', mime: 'image/jpeg' };\n }\n if (startsWith(bytes, 'GIF87a') || startsWith(bytes, 'GIF89a')) {\n return { ext: 'gif', mime: 'image/gif' };\n }\n if (startsWith(bytes, 'RIFF') && startsWith(bytes, 'WEBP', 8)) {\n return { ext: 'webp', mime: 'image/webp' };\n }\n if (startsWith(bytes, 'BM')) {\n return { ext: 'bmp', mime: 'image/bmp' };\n }\n if (startsWith(bytes, [0x49, 0x49, 0x2A, 0x00]) || startsWith(bytes, [0x4D, 0x4D, 0x00, 0x2A])) {\n return { ext: 'tif', mime: 'image/tiff' };\n }\n if (startsWith(bytes, 'ftyp', 4) && readBrands(bytes).some(a => AVIF_BRANDS.includes(a))) {\n return { ext: 'avif', mime: 'image/avif' };\n }\n if (startsWith(bytes, '%PDF-')) {\n return { ext: 'pdf', mime: 'application/pdf' };\n }\n if (startsWith(bytes, [0x50, 0x4B, 0x03, 0x04]) || startsWith(bytes, [0x50, 0x4B, 0x05, 0x06]) || startsWith(bytes, [0x50, 0x4B, 0x07, 0x08])) {\n // Office Open XML も ZIP なので、ZIP に含まれるエントリ名で見分ける\n const text = new TextDecoder('latin1').decode(bytes);\n const office = OFFICE_FILE_TYPES.find(a => text.includes(a.entry));\n return office ? office.type : { ext: 'zip', mime: 'application/zip' };\n }\n if (SVG_PATTERN.test(new TextDecoder().decode(bytes))) {\n return { ext: 'svg', mime: 'image/svg+xml' };\n }\n return null;\n};\n\n/**\n * base64 データと MIME タイプから DataURL を生成する\n *\n * @param {string} base64\n * @param {string} [mimeType] 省略時は 'application/octet-stream'\n * @returns {string}\n */\nexport function createDataURL(base64: string, mimeType?: string): string {\n return `data:${mimeType || DEFAULT_MIME_TYPE};base64,${base64}`;\n}\n\n/**\n * DataURL を base64 データと MIME タイプに分解する\n * MIME タイプは DataURL に書かれた値ではなく、データの先頭バイトから判定した値を返す。判定できない場合は DataURL に書かれた値、それもなければ 'application/octet-stream'\n * DataURL 形式でない文字列は base64 データとみなす\n *\n * @param {string} dataURL\n * @returns {[string, string]} [base64, mimeType]\n */\nexport function parseDataURL(dataURL: string): [string, string] {\n const matcher = DATA_URL_PATTERN.exec(dataURL);\n const base64 = matcher ? matcher[2] : dataURL;\n return [base64, analyzeFileType(base64)?.mime ?? matcher?.[1] ?? DEFAULT_MIME_TYPE];\n}\n\n/**\n * データを読み込み DataURL を返す\n * 文字列は、DataURL 形式ならそのまま、そうでなければ base64 データとみなす\n * Blob は Blob の type を、それがなければ先頭バイトから判定した MIME タイプを使う\n *\n * @param {string | Blob | BinaryInput} data\n * @returns {Promise<string>}\n */\nexport async function readAsDataURL(data: string | Blob | BinaryInput): Promise<string> {\n if (typeof data === 'string') {\n return DATA_URL_PATTERN.test(data) ? data : base64ToDataURL(data);\n }\n if (data instanceof Blob) {\n const buffer = await data.arrayBuffer();\n return arrayBufferToDataURL(buffer, data.type || analyzeFileType(buffer)?.mime);\n }\n return arrayBufferToDataURL(data, analyzeFileType(data)?.mime);\n}\n\n/**\n * データを読み込み ArrayBuffer を返す\n * 文字列は、DataURL 形式ならその base64 部分を、そうでなければ base64 データとみなして変換する\n *\n * @param {string | Blob | BinaryInput} data\n * @returns {Promise<ArrayBuffer>}\n */\nexport async function readAsArrayBuffer(data: string | Blob | BinaryInput): Promise<ArrayBuffer> {\n if (typeof data === 'string') {\n return dataURLToArrayBuffer(data);\n }\n if (data instanceof Blob) {\n return data.arrayBuffer();\n }\n return toArrayBuffer(data);\n}\n\n/**\n * base64 データを DataURL に変換する\n * MIME タイプを省略した場合はデータの先頭バイトから判定する\n *\n * @param {string} base64\n * @param {string} [mimeType]\n * @returns {string} base64 が空の場合はそのまま返す\n */\nexport function base64ToDataURL(base64: string, mimeType?: string): string {\n if (!base64) {\n return base64;\n }\n return createDataURL(base64, mimeType || analyzeFileType(base64)?.mime);\n}\n\n/**\n * base64 データを ArrayBuffer に変換する\n *\n * @param {string} base64\n * @returns {ArrayBuffer}\n */\nexport function base64ToArrayBuffer(base64: string): ArrayBuffer {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes.buffer;\n}\n\n/**\n * DataURL から base64 データを取り出す\n *\n * @param {string} dataURL\n * @returns {string} DataURL 形式でない場合はそのまま返す\n */\nexport function dataURLToBase64(dataURL: string): string {\n return DATA_URL_PATTERN.exec(dataURL)?.[2] ?? dataURL;\n}\n\n/**\n * DataURL を ArrayBuffer に変換する\n *\n * @param {string} dataURL\n * @returns {ArrayBuffer}\n */\nexport function dataURLToArrayBuffer(dataURL: string): ArrayBuffer {\n return base64ToArrayBuffer(dataURLToBase64(dataURL));\n}\n\n/**\n * バイナリを base64 データに変換する\n *\n * @param {BinaryInput} data\n * @returns {string}\n */\nexport function arrayBufferToBase64(data: BinaryInput): string {\n const bytes = toBytes(data);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n\n/**\n * バイナリを DataURL に変換する\n *\n * @param {BinaryInput} data\n * @param {string} [mimeType] 省略時は 'application/octet-stream'\n * @returns {string}\n */\nexport function arrayBufferToDataURL(data: BinaryInput, mimeType?: string): string {\n return createDataURL(arrayBufferToBase64(data), mimeType);\n}\n\n/**\n * base64 データまたは DataURL が表すデータのバイト数を返す\n *\n * @param {string} data\n * @returns {number}\n */\nexport function calcSize(data: string): number {\n return dataURLToArrayBuffer(data).byteLength;\n}\n\n/**\n * 文字列またはバイナリを、BOM 付き UTF-16 の CSV の Blob にする\n * バイナリはすでに UTF-16LE で符号化されているものとして BOM だけを付ける\n *\n * @param {string | BinaryInput} data\n * @returns {Blob}\n */\nexport function convertUTF16withBOM(data: string | BinaryInput): Blob {\n if (!data) {\n return new Blob([]);\n }\n let parts: BlobPart[];\n if (typeof data === 'string') {\n const text = `\\ufeff${data}`;\n const codes = new Uint16Array(text.length);\n for (let i = 0; i < text.length; i++) {\n codes[i] = text.charCodeAt(i);\n }\n parts = [codes];\n } else {\n // 文字列で BOM を渡すと Blob が UTF-8 で符号化してしまうため、UTF-16LE の BOM をバイト列で付ける\n parts = [new Uint8Array([0xFF, 0xFE]), toArrayBuffer(data)];\n }\n return new Blob(parts, { type: 'text/csv;charset=utf-16;' });\n}\n\n/**\n * データの先頭バイトの署名からファイルの種類を判定する\n * 判定できる種類: PNG / JPEG / GIF / WebP / BMP / TIFF / SVG / PDF / ZIP / XLSX / DOCX / PPTX\n * 文字列は、DataURL 形式ならその base64 部分を、そうでなければ base64 データとみなす\n *\n * @param {string | BinaryInput} data\n * @returns {FileType | null} 判定できない場合は null\n */\nexport function analyzeFileType(data: string | BinaryInput): FileType | null {\n let bytes: Uint8Array;\n if (typeof data === 'string') {\n const base64 = dataURLToBase64(data).slice(0, SIGNATURE_BASE64_LENGTH);\n try {\n // 判定に必要な先頭だけを復号する。4文字単位で切らないと末尾がパディング不正になる\n bytes = toBytes(base64ToArrayBuffer(base64.slice(0, base64.length - base64.length % 4)));\n } catch (error) {\n // base64 として復号できない文字列は判定できない\n return null;\n }\n } else {\n bytes = toBytes(data);\n }\n return detectFileType(bytes);\n}\n\n/**\n * ファイル名に使えない文字(\\ / : * ? \" < > |)を取り除く\n *\n * @param {string} name\n * @returns {string}\n */\nexport function sanitizeFileName(name: string): string {\n return name.replace(/[\\\\/:*?\"<>|]/g, '');\n}\n"],"names":["DATA_URL_PATTERN","DEFAULT_MIME_TYPE","SVG_PATTERN","OFFICE_FILE_TYPES","AVIF_BRANDS","toBytes","data","toArrayBuffer","startsWith","bytes","signature","offset","expected","c","value","i","readBrands","end","text","brands","detectFileType","a","office","createDataURL","base64","mimeType","parseDataURL","dataURL","matcher","analyzeFileType","readAsDataURL","base64ToDataURL","buffer","arrayBufferToDataURL","readAsArrayBuffer","dataURLToArrayBuffer","base64ToArrayBuffer","binary","dataURLToBase64","arrayBufferToBase64","calcSize","convertUTF16withBOM","parts","codes","sanitizeFileName","name"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- "use strict";const p=/^data:([^;,]+)?(?:;[^,]*)?;base64,(.*)$/s,T="application/octet-stream";const w=/^\ufeff?\s*(?:<\?xml[^>]*>\s*)?(?:<!--[\s\S]*?-->\s*)*(?:<!DOCTYPE[^>]*>\s*)?<svg[\s>]/i,D=[{entry:"word/",type:{ext:"docx",mime:"application/vnd.openxmlformats-officedocument.wordprocessingml.document"}},{entry:"xl/",type:{ext:"xlsx",mime:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}},{entry:"ppt/",type:{ext:"pptx",mime:"application/vnd.openxmlformats-officedocument.presentationml.presentation"}}],R=["avif","avis"],a=e=>e instanceof ArrayBuffer?new Uint8Array(e):new Uint8Array(e.buffer,e.byteOffset,e.byteLength),x=e=>a(e).slice().buffer,i=(e,t,r=0)=>{const n=typeof t=="string"?Array.from(t,o=>o.charCodeAt(0)):t;return e.length<r+n.length?!1:n.every((o,L)=>e[r+L]===o)},E=e=>{const t=Math.min(new DataView(e.buffer,e.byteOffset,e.byteLength).getUint32(0),e.length),r=new TextDecoder("latin1").decode(e.subarray(0,t)),n=[r.slice(8,12)];for(let o=16;o+4<=t;o+=4)n.push(r.slice(o,o+4));return n},_=e=>{if(i(e,[137,80,78,71,13,10,26,10]))return{ext:"png",mime:"image/png"};if(i(e,[255,216,255]))return{ext:"jpg",mime:"image/jpeg"};if(i(e,"GIF87a")||i(e,"GIF89a"))return{ext:"gif",mime:"image/gif"};if(i(e,"RIFF")&&i(e,"WEBP",8))return{ext:"webp",mime:"image/webp"};if(i(e,"BM"))return{ext:"bmp",mime:"image/bmp"};if(i(e,[73,73,42,0])||i(e,[77,77,0,42]))return{ext:"tif",mime:"image/tiff"};if(i(e,"ftyp",4)&&E(e).some(t=>R.includes(t)))return{ext:"avif",mime:"image/avif"};if(i(e,"%PDF-"))return{ext:"pdf",mime:"application/pdf"};if(i(e,[80,75,3,4])||i(e,[80,75,5,6])||i(e,[80,75,7,8])){const t=new TextDecoder("latin1").decode(e),r=D.find(n=>t.includes(n.entry));return r?r.type:{ext:"zip",mime:"application/zip"}}return w.test(new TextDecoder().decode(e))?{ext:"svg",mime:"image/svg+xml"}:null};function s(e,t){return`data:${t||T};base64,${e}`}function A(e){const t=p.exec(e),r=t?t[2]:e;return[r,f(r)?.mime??t?.[1]??T]}async function B(e){if(typeof e=="string")return p.test(e)?e:g(e);if(e instanceof Blob){const t=await e.arrayBuffer();return c(t,e.type||f(t)?.mime)}return c(e,f(e)?.mime)}async function h(e){return typeof e=="string"?m(e):e instanceof Blob?e.arrayBuffer():x(e)}function g(e,t){return e&&s(e,t||f(e)?.mime)}function u(e){const t=atob(e),r=new Uint8Array(t.length);for(let n=0;n<t.length;n++)r[n]=t.charCodeAt(n);return r.buffer}function l(e){return p.exec(e)?.[2]??e}function m(e){return u(l(e))}function y(e){const t=a(e);let r="";for(let n=0;n<t.length;n++)r+=String.fromCharCode(t[n]);return btoa(r)}function c(e,t){return s(y(e),t)}function U(e){return m(e).byteLength}function d(e){if(!e)return new Blob([]);let t;if(typeof e=="string"){const r=`\uFEFF${e}`,n=new Uint16Array(r.length);for(let o=0;o<r.length;o++)n[o]=r.charCodeAt(o);t=[n]}else t=[new Uint8Array([255,254]),x(e)];return new Blob(t,{type:"text/csv;charset=utf-16;"})}function f(e){let t;if(typeof e=="string"){const r=l(e).slice(0,16384);try{t=a(u(r.slice(0,r.length-r.length%4)))}catch{return null}}else t=a(e);return _(t)}function F(e){return e.replace(/[\\/:*?"<>|]/g,"")}const v=Object.freeze(Object.defineProperty({__proto__:null,analyzeFileType:f,arrayBufferToBase64:y,arrayBufferToDataURL:c,base64ToArrayBuffer:u,base64ToDataURL:g,calcSize:U,convertUTF16withBOM:d,createDataURL:s,dataURLToArrayBuffer:m,dataURLToBase64:l,parseDataURL:A,readAsArrayBuffer:h,readAsDataURL:B,sanitizeFileName:F},Symbol.toStringTag,{value:"Module"}));exports.analyzeFileType=f;exports.arrayBufferToBase64=y;exports.arrayBufferToDataURL=c;exports.base64ToArrayBuffer=u;exports.base64ToDataURL=g;exports.calcSize=U;exports.convertUTF16withBOM=d;exports.createDataURL=s;exports.dataURLToArrayBuffer=m;exports.dataURLToBase64=l;exports.fileUtil=v;exports.parseDataURL=A;exports.readAsArrayBuffer=h;exports.readAsDataURL=B;exports.sanitizeFileName=F;
2
- //# sourceMappingURL=file-util-Dqiw5tBQ.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"file-util-Dqiw5tBQ.cjs","sources":["../src/file-util.ts"],"sourcesContent":["/** 先頭バイトの署名から判定したファイルの種類 */\nexport interface FileType {\n /** 拡張子(ドットなし) */\n ext: string;\n /** MIMEタイプ */\n mime: string;\n}\n\n/** バイナリとして受け付ける値。Node.js の Buffer も ArrayBufferView として渡せる */\nexport type BinaryInput = ArrayBuffer | ArrayBufferView;\n\nconst DATA_URL_PATTERN = /^data:([^;,]+)?(?:;[^,]*)?;base64,(.*)$/s;\n\nconst DEFAULT_MIME_TYPE = 'application/octet-stream';\n\n/** 種類の判定に使う先頭の base64 の文字数。ZIP の中のエントリ名を探すため数KB分を見る */\nconst SIGNATURE_BASE64_LENGTH = 16384;\n\nconst SVG_PATTERN = /^\\ufeff?\\s*(?:<\\?xml[^>]*>\\s*)?(?:<!--[\\s\\S]*?-->\\s*)*(?:<!DOCTYPE[^>]*>\\s*)?<svg[\\s>]/i;\n\nconst OFFICE_FILE_TYPES: { entry: string; type: FileType; }[] = [\n { entry: 'word/', type: { ext: 'docx', mime: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' } },\n { entry: 'xl/', type: { ext: 'xlsx', mime: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' } },\n { entry: 'ppt/', type: { ext: 'pptx', mime: 'application/vnd.openxmlformats-officedocument.presentationml.presentation' } }\n];\n\n/** ftyp ボックスのブランドのうち、AVIF を表すもの */\nconst AVIF_BRANDS = ['avif', 'avis'];\n\nconst toBytes = (data: BinaryInput): Uint8Array => {\n return data instanceof ArrayBuffer ? new Uint8Array(data) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);\n};\n\nconst toArrayBuffer = (data: BinaryInput): ArrayBuffer => toBytes(data).slice().buffer as ArrayBuffer;\n\nconst startsWith = (bytes: Uint8Array, signature: number[] | string, offset: number = 0): boolean => {\n const expected = typeof signature === 'string' ? Array.from(signature, c => c.charCodeAt(0)) : signature;\n if (bytes.length < offset + expected.length) {\n return false;\n }\n return expected.every((value, i) => bytes[offset + i] === value);\n};\n\n/**\n * ISOBMFF の ftyp ボックスに並ぶブランドを返す\n * 8バイト目からメジャーブランド、16バイト目から互換ブランドが4文字ずつ並ぶ\n *\n * @param {Uint8Array} bytes\n * @returns {string[]}\n */\nconst readBrands = (bytes: Uint8Array): string[] => {\n const end = Math.min(new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(0), bytes.length);\n const text = new TextDecoder('latin1').decode(bytes.subarray(0, end));\n const brands = [text.slice(8, 12)];\n for (let i = 16; i + 4 <= end; i += 4) {\n brands.push(text.slice(i, i + 4));\n }\n return brands;\n};\n\nconst detectFileType = (bytes: Uint8Array): FileType | null => {\n if (startsWith(bytes, [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A])) {\n return { ext: 'png', mime: 'image/png' };\n }\n if (startsWith(bytes, [0xFF, 0xD8, 0xFF])) {\n return { ext: 'jpg', mime: 'image/jpeg' };\n }\n if (startsWith(bytes, 'GIF87a') || startsWith(bytes, 'GIF89a')) {\n return { ext: 'gif', mime: 'image/gif' };\n }\n if (startsWith(bytes, 'RIFF') && startsWith(bytes, 'WEBP', 8)) {\n return { ext: 'webp', mime: 'image/webp' };\n }\n if (startsWith(bytes, 'BM')) {\n return { ext: 'bmp', mime: 'image/bmp' };\n }\n if (startsWith(bytes, [0x49, 0x49, 0x2A, 0x00]) || startsWith(bytes, [0x4D, 0x4D, 0x00, 0x2A])) {\n return { ext: 'tif', mime: 'image/tiff' };\n }\n if (startsWith(bytes, 'ftyp', 4) && readBrands(bytes).some(a => AVIF_BRANDS.includes(a))) {\n return { ext: 'avif', mime: 'image/avif' };\n }\n if (startsWith(bytes, '%PDF-')) {\n return { ext: 'pdf', mime: 'application/pdf' };\n }\n if (startsWith(bytes, [0x50, 0x4B, 0x03, 0x04]) || startsWith(bytes, [0x50, 0x4B, 0x05, 0x06]) || startsWith(bytes, [0x50, 0x4B, 0x07, 0x08])) {\n // Office Open XML も ZIP なので、ZIP に含まれるエントリ名で見分ける\n const text = new TextDecoder('latin1').decode(bytes);\n const office = OFFICE_FILE_TYPES.find(a => text.includes(a.entry));\n return office ? office.type : { ext: 'zip', mime: 'application/zip' };\n }\n if (SVG_PATTERN.test(new TextDecoder().decode(bytes))) {\n return { ext: 'svg', mime: 'image/svg+xml' };\n }\n return null;\n};\n\n/**\n * base64 データと MIME タイプから DataURL を生成する\n *\n * @param {string} base64\n * @param {string} [mimeType] 省略時は 'application/octet-stream'\n * @returns {string}\n */\nexport function createDataURL(base64: string, mimeType?: string): string {\n return `data:${mimeType || DEFAULT_MIME_TYPE};base64,${base64}`;\n}\n\n/**\n * DataURL を base64 データと MIME タイプに分解する\n * MIME タイプは DataURL に書かれた値ではなく、データの先頭バイトから判定した値を返す。判定できない場合は DataURL に書かれた値、それもなければ 'application/octet-stream'\n * DataURL 形式でない文字列は base64 データとみなす\n *\n * @param {string} dataURL\n * @returns {[string, string]} [base64, mimeType]\n */\nexport function parseDataURL(dataURL: string): [string, string] {\n const matcher = DATA_URL_PATTERN.exec(dataURL);\n const base64 = matcher ? matcher[2] : dataURL;\n return [base64, analyzeFileType(base64)?.mime ?? matcher?.[1] ?? DEFAULT_MIME_TYPE];\n}\n\n/**\n * データを読み込み DataURL を返す\n * 文字列は、DataURL 形式ならそのまま、そうでなければ base64 データとみなす\n * Blob は Blob の type を、それがなければ先頭バイトから判定した MIME タイプを使う\n *\n * @param {string | Blob | BinaryInput} data\n * @returns {Promise<string>}\n */\nexport async function readAsDataURL(data: string | Blob | BinaryInput): Promise<string> {\n if (typeof data === 'string') {\n return DATA_URL_PATTERN.test(data) ? data : base64ToDataURL(data);\n }\n if (data instanceof Blob) {\n const buffer = await data.arrayBuffer();\n return arrayBufferToDataURL(buffer, data.type || analyzeFileType(buffer)?.mime);\n }\n return arrayBufferToDataURL(data, analyzeFileType(data)?.mime);\n}\n\n/**\n * データを読み込み ArrayBuffer を返す\n * 文字列は、DataURL 形式ならその base64 部分を、そうでなければ base64 データとみなして変換する\n *\n * @param {string | Blob | BinaryInput} data\n * @returns {Promise<ArrayBuffer>}\n */\nexport async function readAsArrayBuffer(data: string | Blob | BinaryInput): Promise<ArrayBuffer> {\n if (typeof data === 'string') {\n return dataURLToArrayBuffer(data);\n }\n if (data instanceof Blob) {\n return data.arrayBuffer();\n }\n return toArrayBuffer(data);\n}\n\n/**\n * base64 データを DataURL に変換する\n * MIME タイプを省略した場合はデータの先頭バイトから判定する\n *\n * @param {string} base64\n * @param {string} [mimeType]\n * @returns {string} base64 が空の場合はそのまま返す\n */\nexport function base64ToDataURL(base64: string, mimeType?: string): string {\n if (!base64) {\n return base64;\n }\n return createDataURL(base64, mimeType || analyzeFileType(base64)?.mime);\n}\n\n/**\n * base64 データを ArrayBuffer に変換する\n *\n * @param {string} base64\n * @returns {ArrayBuffer}\n */\nexport function base64ToArrayBuffer(base64: string): ArrayBuffer {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes.buffer;\n}\n\n/**\n * DataURL から base64 データを取り出す\n *\n * @param {string} dataURL\n * @returns {string} DataURL 形式でない場合はそのまま返す\n */\nexport function dataURLToBase64(dataURL: string): string {\n return DATA_URL_PATTERN.exec(dataURL)?.[2] ?? dataURL;\n}\n\n/**\n * DataURL を ArrayBuffer に変換する\n *\n * @param {string} dataURL\n * @returns {ArrayBuffer}\n */\nexport function dataURLToArrayBuffer(dataURL: string): ArrayBuffer {\n return base64ToArrayBuffer(dataURLToBase64(dataURL));\n}\n\n/**\n * バイナリを base64 データに変換する\n *\n * @param {BinaryInput} data\n * @returns {string}\n */\nexport function arrayBufferToBase64(data: BinaryInput): string {\n const bytes = toBytes(data);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n\n/**\n * バイナリを DataURL に変換する\n *\n * @param {BinaryInput} data\n * @param {string} [mimeType] 省略時は 'application/octet-stream'\n * @returns {string}\n */\nexport function arrayBufferToDataURL(data: BinaryInput, mimeType?: string): string {\n return createDataURL(arrayBufferToBase64(data), mimeType);\n}\n\n/**\n * base64 データまたは DataURL が表すデータのバイト数を返す\n *\n * @param {string} data\n * @returns {number}\n */\nexport function calcSize(data: string): number {\n return dataURLToArrayBuffer(data).byteLength;\n}\n\n/**\n * 文字列またはバイナリを、BOM 付き UTF-16 の CSV の Blob にする\n * バイナリはすでに UTF-16LE で符号化されているものとして BOM だけを付ける\n *\n * @param {string | BinaryInput} data\n * @returns {Blob}\n */\nexport function convertUTF16withBOM(data: string | BinaryInput): Blob {\n if (!data) {\n return new Blob([]);\n }\n let parts: BlobPart[];\n if (typeof data === 'string') {\n const text = `\\ufeff${data}`;\n const codes = new Uint16Array(text.length);\n for (let i = 0; i < text.length; i++) {\n codes[i] = text.charCodeAt(i);\n }\n parts = [codes];\n } else {\n // 文字列で BOM を渡すと Blob が UTF-8 で符号化してしまうため、UTF-16LE の BOM をバイト列で付ける\n parts = [new Uint8Array([0xFF, 0xFE]), toArrayBuffer(data)];\n }\n return new Blob(parts, { type: 'text/csv;charset=utf-16;' });\n}\n\n/**\n * データの先頭バイトの署名からファイルの種類を判定する\n * 判定できる種類: PNG / JPEG / GIF / WebP / BMP / TIFF / SVG / PDF / ZIP / XLSX / DOCX / PPTX\n * 文字列は、DataURL 形式ならその base64 部分を、そうでなければ base64 データとみなす\n *\n * @param {string | BinaryInput} data\n * @returns {FileType | null} 判定できない場合は null\n */\nexport function analyzeFileType(data: string | BinaryInput): FileType | null {\n let bytes: Uint8Array;\n if (typeof data === 'string') {\n const base64 = dataURLToBase64(data).slice(0, SIGNATURE_BASE64_LENGTH);\n try {\n // 判定に必要な先頭だけを復号する。4文字単位で切らないと末尾がパディング不正になる\n bytes = toBytes(base64ToArrayBuffer(base64.slice(0, base64.length - base64.length % 4)));\n } catch (error) {\n // base64 として復号できない文字列は判定できない\n return null;\n }\n } else {\n bytes = toBytes(data);\n }\n return detectFileType(bytes);\n}\n\n/**\n * ファイル名に使えない文字(\\ / : * ? \" < > |)を取り除く\n *\n * @param {string} name\n * @returns {string}\n */\nexport function sanitizeFileName(name: string): string {\n return name.replace(/[\\\\/:*?\"<>|]/g, '');\n}\n"],"names":["DATA_URL_PATTERN","DEFAULT_MIME_TYPE","SVG_PATTERN","OFFICE_FILE_TYPES","AVIF_BRANDS","toBytes","data","toArrayBuffer","startsWith","bytes","signature","offset","expected","c","value","i","readBrands","end","text","brands","detectFileType","a","office","createDataURL","base64","mimeType","parseDataURL","dataURL","matcher","analyzeFileType","readAsDataURL","base64ToDataURL","buffer","arrayBufferToDataURL","readAsArrayBuffer","dataURLToArrayBuffer","base64ToArrayBuffer","binary","dataURLToBase64","arrayBufferToBase64","calcSize","convertUTF16withBOM","parts","codes","sanitizeFileName","name"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- "use strict";const S=require("diff"),j=require("./json-util-CKnsxu1e.cjs"),m=/(<!--[\s\S]*?-->|<[^>]*>|&(?:#\d+|#x[\da-f]+|\w+);)/i,y={'"':"&quot;","&":"&amp;","'":"&#39;","<":"&lt;",">":"&gt;"},a=r=>r.replace(/["&'<>]/g,e=>y[e]),$=r=>typeof r=="string"?r:Array.isArray(r)?r.filter(Boolean).join(" "):Object.keys(r).filter(e=>r[e]).join(" "),x=r=>typeof r=="string"?r:Object.entries(r).map(([e,t])=>`${e.startsWith("--")?e:e.replace(/[A-Z]/g,n=>`-${n.toLowerCase()}`)}: ${t}`).join("; "),d={added:"color: var(--dwui-color-text-diff-added, light-dark(#006400, rgb(121, 227, 121)))",removed:"color: var(--dwui-color-text-diff-removed, light-dark(#ff0000, rgb(222, 109, 109)))",same:"color: var(--dwui-color-text-diff-same, light-dark(#838383, #808080))"},T="background: var(--dwui-background-highlight, Mark); color: var(--dwui-color-text-highlight, MarkText)",f=(r,e,t,o)=>{let n="";const i=t?.class==null?"":$(t.class);i&&(n+=` class="${a(i)}"`);const l=[o,t?.style==null?"":x(t.style)].filter(Boolean).join("; ");return l&&(n+=` style="${a(l)}"`),`<${r}${n}>${a(e)}</${r}>`};function g(r,e){if(!r)return"";const t=o=>o.replace(/\r\n|\r|\n/g,"<br>").replace(/\t/g,"&nbsp;&nbsp;").replace(/ /g,"&nbsp;");return e?.html?r.split(m).map((o,n)=>n%2===1?o:t(o)).join(""):t(a(r))}function u(r,e){const{html:t,...o}=e??{},n=j.formatJsonString(r,o);return n==null?"":g(String(n),{html:t})}function h(r,e,t){if(!r)return"";const o=s=>t?.html?s:a(s);if(!e)return o(r);const n=e.replace(/[|\\{}()[\]^$+*?.]/g,"\\$&").replace(/-/g,"\\x2d"),i=new RegExp(`(${n})`,t?.caseInsensitive?"i":""),l=s=>s.split(i).map((c,b)=>b%2===0?o(c):f("mark",c,t,T)).join("");return t?.html?r.split(m).map((s,c)=>c%2===1?s:l(s)).join(""):l(r)}function p(r,e,t){const o=S.diffChars(r??"",e??"",{ignoreCase:t?.ignoreCase});let n="";for(const i of o)i.added?n+=f("span",i.value,t?.added,d.added):i.removed?n+=f("span",i.value,t?.removed,d.removed):n+=f("span",i.value,t?.same,d.same);return n}const W=Object.freeze(Object.defineProperty({__proto__:null,diffForWeb:p,formatJsonStringForWeb:u,formatStringForWeb:g,highlightWord:h},Symbol.toStringTag,{value:"Module"}));exports.diffForWeb=p;exports.formatJsonStringForWeb=u;exports.formatStringForWeb=g;exports.highlightWord=h;exports.htmlUtil=W;
2
- //# sourceMappingURL=html-util--mpzaYuJ.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"html-util--mpzaYuJ.cjs","sources":["../src/html-util.ts"],"sourcesContent":["import { diffChars } from 'diff';\nimport { formatJsonString } from './json-util';\nimport type { FormatJsonStringOptions } from './json-util';\n\n/**\n * class属性に指定する値\n * 配列は要素を空白区切りで連結し、Recordは値がtrueのキーだけを連結する\n */\nexport type HtmlClassValue = string | string[] | Record<string, boolean>;\n\n/**\n * style属性に指定する値\n * Recordのキーはキャメルケースをケバブケースに変換する。数値には単位を付けない\n */\nexport type HtmlStyleValue = string | Record<string, string | number>;\n\n/**\n * 生成するタグに付与する属性\n */\nexport interface HtmlTagOptions {\n class?: HtmlClassValue;\n style?: HtmlStyleValue;\n}\n\nconst HTML_TOKEN = /(<!--[\\s\\S]*?-->|<[^>]*>|&(?:#\\d+|#x[\\da-f]+|\\w+);)/i;\n\nconst HTML_ESCAPE_CHARS: Record<string, string> = {\n '\"': '&quot;',\n '&': '&amp;',\n '\\'': '&#39;',\n '<': '&lt;',\n '>': '&gt;'\n};\n\nconst escapeHtml = (str: string): string => str.replace(/[\"&'<>]/g, (c) => HTML_ESCAPE_CHARS[c]);\n\nconst toClassString = (value: HtmlClassValue): string => {\n if (typeof value === 'string') {\n return value;\n }\n if (Array.isArray(value)) {\n return value.filter(Boolean).join(' ');\n }\n return Object.keys(value).filter(key => value[key]).join(' ');\n};\n\nconst toStyleString = (value: HtmlStyleValue): string => {\n if (typeof value === 'string') {\n return value;\n }\n return Object.entries(value)\n .map(([key, v]) => {\n // カスタムプロパティ(--xxx)は大文字小文字を区別するため変換しない\n const property = key.startsWith('--') ? key : key.replace(/[A-Z]/g, c => `-${c.toLowerCase()}`);\n return `${property}: ${v}`;\n })\n .join('; ');\n};\n\n/** diffForWebの既定の文字色 */\nconst DIFF_STYLES = {\n added: 'color: var(--dwui-color-text-diff-added, light-dark(#006400, rgb(121, 227, 121)))',\n removed: 'color: var(--dwui-color-text-diff-removed, light-dark(#ff0000, rgb(222, 109, 109)))',\n same: 'color: var(--dwui-color-text-diff-same, light-dark(#838383, #808080))'\n};\n\n/** highlightWordの既定の背景色・文字色。markタグのブラウザ標準の色をフォールバックにする */\nconst HIGHLIGHT_STYLE = 'background: var(--dwui-background-highlight, Mark); color: var(--dwui-color-text-highlight, MarkText)';\n\n/**\n * 値をエスケープしたタグを返す\n *\n * @param {string} tagName\n * @param {string} value\n * @param {HtmlTagOptions} [options]\n * @param {string} [defaultStyle] optionsのstyleより前に出力するstyle\n * @returns {string}\n */\nconst toElement = (tagName: string, value: string, options?: HtmlTagOptions, defaultStyle?: string): string => {\n let attributes = '';\n const className = options?.class == null ? '' : toClassString(options.class);\n if (className) {\n attributes += ` class=\"${escapeHtml(className)}\"`;\n }\n const style = [defaultStyle, options?.style == null ? '' : toStyleString(options.style)].filter(Boolean).join('; ');\n if (style) {\n attributes += ` style=\"${escapeHtml(style)}\"`;\n }\n return `<${tagName}${attributes}>${escapeHtml(value)}</${tagName}>`;\n};\n\n/**\n * 文字列をWEB表示用にフォーマットする\n * オプションのhtmlにより、入力文字列がHTMLなのかプレーンテキストなのかを指定可能\n *\n * @param {string | null | undefined} str\n * @param {*} [options]\n * ├ html boolean trueを指定した場合、入力された文字列をHTMLとして扱う\n * @returns {string}\n */\nexport function formatStringForWeb(str: string | null | undefined, options?: {\n html?: boolean;\n}): string {\n if (!str) {\n return '';\n }\n\n const formatText = (text: string): string => text\n .replace(/\\r\\n|\\r|\\n/g, '<br>')\n .replace(/\\t/g, '&nbsp;&nbsp;')\n .replace(/ /g, '&nbsp;');\n\n if (options?.html) {\n // 奇数番目がタグ・コメント・文字参照。偶数番目のテキスト部分だけをフォーマットする\n return str\n .split(HTML_TOKEN)\n .map((segment, i) => i % 2 === 1 ? segment : formatText(segment))\n .join('');\n }\n\n return formatText(escapeHtml(str));\n}\n\n/**\n * 値を整形したJSON文字列にしてWEB表示用にフォーマットする\n * formatJsonStringで整形した文字列をformatStringForWebで変換する\n *\n * @param {any} value\n * @param {*} [options] formatJsonStringのオプションに以下を加えたもの\n * ├ html boolean trueを指定した場合、文字列をHTMLとして扱う\n * @returns {string}\n */\nexport function formatJsonStringForWeb(value: any, options?: FormatJsonStringOptions & {\n html?: boolean;\n}): string {\n const { html, ...formatOptions } = options ?? {};\n const json = formatJsonString(value, formatOptions);\n return json == null ? '' : formatStringForWeb(String(json), { html });\n}\n\n/**\n * 文字列の中で一致したワードをmarkタグで囲んだHTML文字列を返す\n * markタグは既定の背景色・文字色を持つ。色はCSS変数(--dwui-background-highlight / --dwui-color-text-highlight)で変更できる\n * styleは既定の背景色・文字色より後に出力する\n * オプションのhtmlにより、入力文字列がHTMLなのかプレーンテキストなのかを指定可能\n *\n * 例)\n * HtmlUtil.highlightWord('This is a test message', 'test', { class: 'highlight' });\n * → 'This is a <mark class=\"highlight\" style=\"background: var(--dwui-background-highlight, Mark); color: var(--dwui-color-text-highlight, MarkText)\">test</mark> message'\n *\n * @param {string | null | undefined} value\n * @param {string | null | undefined} word\n * @param {*} [options] markタグに付与するclass, styleのほか、以下を指定できる\n * ├ class string | string[] | Record<string, boolean>\n * ├ style string | Record<string, string | number>\n * ├ caseInsensitive boolean trueを指定した場合、大文字小文字を区別しない\n * ├ html boolean trueを指定した場合、入力された文字列をHTMLとして扱う\n * @returns {string}\n */\nexport function highlightWord(\n value: string | null | undefined,\n word: string | null | undefined,\n options?: HtmlTagOptions & {\n caseInsensitive?: boolean;\n html?: boolean;\n }\n): string {\n if (!value) {\n return '';\n }\n\n const toHtml = (text: string): string => options?.html ? text : escapeHtml(text);\n if (!word) {\n return toHtml(value);\n }\n\n const pattern = word.replace(/[|\\\\{}()[\\]^$+*?.]/g, '\\\\$&').replace(/-/g, '\\\\x2d');\n const regex = new RegExp(`(${pattern})`, options?.caseInsensitive ? 'i' : '');\n // キャプチャグループで分割すると、奇数番目の要素が一致した部分になる\n const highlight = (text: string): string => text\n .split(regex)\n .map((part, i) => i % 2 === 0 ? toHtml(part) : toElement('mark', part, options, HIGHLIGHT_STYLE))\n .join('');\n\n if (!options?.html) {\n return highlight(value);\n }\n\n // 奇数番目がタグ・コメント・文字参照。偶数番目のテキスト部分だけをハイライトする\n return value\n .split(HTML_TOKEN)\n .map((segment, i) => i % 2 === 1 ? segment : highlight(segment))\n .join('');\n}\n\n/**\n * 文字列を1文字ずつ比較し、差分をspanタグで囲んだHTML文字列を返す\n * 追加・削除・一致の部分ごとに既定の文字色を持つ。文字色はCSS変数(--dwui-color-text-diff-added / --dwui-color-text-diff-removed / --dwui-color-text-diff-same)で変更できる\n * 追加・削除・一致の部分ごとに、spanタグに付与するclass, styleを指定できる。styleは既定の文字色より後に出力する\n * 入力文字列はプレーンなテキストであるとみなす\n * 出力される文字列は、diffで埋め込まれるHTMLタグ以外はHTMLエスケープされ、HTMLセーフな文字列となる\n *\n * @param {string | null | undefined} text1 比較元の文字列\n * @param {string | null | undefined} text2 比較される文字列(通常、入力値はこちらに渡す)\n * @param {*} [options]\n * ├ ignoreCase boolean trueを指定した場合、大文字小文字を区別しない\n * ├ added HtmlTagOptions text2で追加された部分のspanタグに付与する属性\n * ├ removed HtmlTagOptions text2で削除された部分のspanタグに付与する属性\n * ├ same HtmlTagOptions 一致した部分のspanタグに付与する属性\n * @returns {string}\n */\nexport function diffForWeb(text1: string | null | undefined, text2: string | null | undefined, options?: {\n ignoreCase?: boolean;\n added?: HtmlTagOptions;\n removed?: HtmlTagOptions;\n same?: HtmlTagOptions;\n}): string {\n const changes = diffChars(text1 ?? '', text2 ?? '', { ignoreCase: options?.ignoreCase });\n let html = '';\n for (const change of changes) {\n if (change.added) {\n html += toElement('span', change.value, options?.added, DIFF_STYLES.added);\n } else if (change.removed) {\n html += toElement('span', change.value, options?.removed, DIFF_STYLES.removed);\n } else {\n html += toElement('span', change.value, options?.same, DIFF_STYLES.same);\n }\n }\n return html;\n}\n"],"names":["HTML_TOKEN","HTML_ESCAPE_CHARS","escapeHtml","str","c","toClassString","value","key","toStyleString","v","DIFF_STYLES","HIGHLIGHT_STYLE","toElement","tagName","options","defaultStyle","attributes","className","style","formatStringForWeb","formatText","text","segment","i","formatJsonStringForWeb","html","formatOptions","json","formatJsonString","highlightWord","word","toHtml","pattern","regex","highlight","part","diffForWeb","text1","text2","changes","diffChars","change"],"mappings":"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"}
@@ -1,60 +0,0 @@
1
- import { diffChars as h } from "diff";
2
- import { f as p } from "./json-util-C_Pm1BpJ.js";
3
- const g = /(<!--[\s\S]*?-->|<[^>]*>|&(?:#\d+|#x[\da-f]+|\w+);)/i, b = {
4
- '"': "&quot;",
5
- "&": "&amp;",
6
- "'": "&#39;",
7
- "<": "&lt;",
8
- ">": "&gt;"
9
- }, l = (r) => r.replace(/["&'<>]/g, (e) => b[e]), S = (r) => typeof r == "string" ? r : Array.isArray(r) ? r.filter(Boolean).join(" ") : Object.keys(r).filter((e) => r[e]).join(" "), j = (r) => typeof r == "string" ? r : Object.entries(r).map(([e, t]) => `${e.startsWith("--") ? e : e.replace(/[A-Z]/g, (n) => `-${n.toLowerCase()}`)}: ${t}`).join("; "), d = {
10
- added: "color: var(--dwui-color-text-diff-added, light-dark(#006400, rgb(121, 227, 121)))",
11
- removed: "color: var(--dwui-color-text-diff-removed, light-dark(#ff0000, rgb(222, 109, 109)))",
12
- same: "color: var(--dwui-color-text-diff-same, light-dark(#838383, #808080))"
13
- }, y = "background: var(--dwui-background-highlight, Mark); color: var(--dwui-color-text-highlight, MarkText)", f = (r, e, t, o) => {
14
- let n = "";
15
- const i = t?.class == null ? "" : S(t.class);
16
- i && (n += ` class="${l(i)}"`);
17
- const a = [o, t?.style == null ? "" : j(t.style)].filter(Boolean).join("; ");
18
- return a && (n += ` style="${l(a)}"`), `<${r}${n}>${l(e)}</${r}>`;
19
- };
20
- function m(r, e) {
21
- if (!r)
22
- return "";
23
- const t = (o) => o.replace(/\r\n|\r|\n/g, "<br>").replace(/\t/g, "&nbsp;&nbsp;").replace(/ /g, "&nbsp;");
24
- return e?.html ? r.split(g).map((o, n) => n % 2 === 1 ? o : t(o)).join("") : t(l(r));
25
- }
26
- function $(r, e) {
27
- const { html: t, ...o } = e ?? {}, n = p(r, o);
28
- return n == null ? "" : m(String(n), { html: t });
29
- }
30
- function x(r, e, t) {
31
- if (!r)
32
- return "";
33
- const o = (s) => t?.html ? s : l(s);
34
- if (!e)
35
- return o(r);
36
- const n = e.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d"), i = new RegExp(`(${n})`, t?.caseInsensitive ? "i" : ""), a = (s) => s.split(i).map((c, u) => u % 2 === 0 ? o(c) : f("mark", c, t, y)).join("");
37
- return t?.html ? r.split(g).map((s, c) => c % 2 === 1 ? s : a(s)).join("") : a(r);
38
- }
39
- function T(r, e, t) {
40
- const o = h(r ?? "", e ?? "", { ignoreCase: t?.ignoreCase });
41
- let n = "";
42
- for (const i of o)
43
- i.added ? n += f("span", i.value, t?.added, d.added) : i.removed ? n += f("span", i.value, t?.removed, d.removed) : n += f("span", i.value, t?.same, d.same);
44
- return n;
45
- }
46
- const k = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
47
- __proto__: null,
48
- diffForWeb: T,
49
- formatJsonStringForWeb: $,
50
- formatStringForWeb: m,
51
- highlightWord: x
52
- }, Symbol.toStringTag, { value: "Module" }));
53
- export {
54
- m as a,
55
- x as b,
56
- T as d,
57
- $ as f,
58
- k as h
59
- };
60
- //# sourceMappingURL=html-util-B8sdLw9I.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"html-util-B8sdLw9I.js","sources":["../src/html-util.ts"],"sourcesContent":["import { diffChars } from 'diff';\nimport { formatJsonString } from './json-util';\nimport type { FormatJsonStringOptions } from './json-util';\n\n/**\n * class属性に指定する値\n * 配列は要素を空白区切りで連結し、Recordは値がtrueのキーだけを連結する\n */\nexport type HtmlClassValue = string | string[] | Record<string, boolean>;\n\n/**\n * style属性に指定する値\n * Recordのキーはキャメルケースをケバブケースに変換する。数値には単位を付けない\n */\nexport type HtmlStyleValue = string | Record<string, string | number>;\n\n/**\n * 生成するタグに付与する属性\n */\nexport interface HtmlTagOptions {\n class?: HtmlClassValue;\n style?: HtmlStyleValue;\n}\n\nconst HTML_TOKEN = /(<!--[\\s\\S]*?-->|<[^>]*>|&(?:#\\d+|#x[\\da-f]+|\\w+);)/i;\n\nconst HTML_ESCAPE_CHARS: Record<string, string> = {\n '\"': '&quot;',\n '&': '&amp;',\n '\\'': '&#39;',\n '<': '&lt;',\n '>': '&gt;'\n};\n\nconst escapeHtml = (str: string): string => str.replace(/[\"&'<>]/g, (c) => HTML_ESCAPE_CHARS[c]);\n\nconst toClassString = (value: HtmlClassValue): string => {\n if (typeof value === 'string') {\n return value;\n }\n if (Array.isArray(value)) {\n return value.filter(Boolean).join(' ');\n }\n return Object.keys(value).filter(key => value[key]).join(' ');\n};\n\nconst toStyleString = (value: HtmlStyleValue): string => {\n if (typeof value === 'string') {\n return value;\n }\n return Object.entries(value)\n .map(([key, v]) => {\n // カスタムプロパティ(--xxx)は大文字小文字を区別するため変換しない\n const property = key.startsWith('--') ? key : key.replace(/[A-Z]/g, c => `-${c.toLowerCase()}`);\n return `${property}: ${v}`;\n })\n .join('; ');\n};\n\n/** diffForWebの既定の文字色 */\nconst DIFF_STYLES = {\n added: 'color: var(--dwui-color-text-diff-added, light-dark(#006400, rgb(121, 227, 121)))',\n removed: 'color: var(--dwui-color-text-diff-removed, light-dark(#ff0000, rgb(222, 109, 109)))',\n same: 'color: var(--dwui-color-text-diff-same, light-dark(#838383, #808080))'\n};\n\n/** highlightWordの既定の背景色・文字色。markタグのブラウザ標準の色をフォールバックにする */\nconst HIGHLIGHT_STYLE = 'background: var(--dwui-background-highlight, Mark); color: var(--dwui-color-text-highlight, MarkText)';\n\n/**\n * 値をエスケープしたタグを返す\n *\n * @param {string} tagName\n * @param {string} value\n * @param {HtmlTagOptions} [options]\n * @param {string} [defaultStyle] optionsのstyleより前に出力するstyle\n * @returns {string}\n */\nconst toElement = (tagName: string, value: string, options?: HtmlTagOptions, defaultStyle?: string): string => {\n let attributes = '';\n const className = options?.class == null ? '' : toClassString(options.class);\n if (className) {\n attributes += ` class=\"${escapeHtml(className)}\"`;\n }\n const style = [defaultStyle, options?.style == null ? '' : toStyleString(options.style)].filter(Boolean).join('; ');\n if (style) {\n attributes += ` style=\"${escapeHtml(style)}\"`;\n }\n return `<${tagName}${attributes}>${escapeHtml(value)}</${tagName}>`;\n};\n\n/**\n * 文字列をWEB表示用にフォーマットする\n * オプションのhtmlにより、入力文字列がHTMLなのかプレーンテキストなのかを指定可能\n *\n * @param {string | null | undefined} str\n * @param {*} [options]\n * ├ html boolean trueを指定した場合、入力された文字列をHTMLとして扱う\n * @returns {string}\n */\nexport function formatStringForWeb(str: string | null | undefined, options?: {\n html?: boolean;\n}): string {\n if (!str) {\n return '';\n }\n\n const formatText = (text: string): string => text\n .replace(/\\r\\n|\\r|\\n/g, '<br>')\n .replace(/\\t/g, '&nbsp;&nbsp;')\n .replace(/ /g, '&nbsp;');\n\n if (options?.html) {\n // 奇数番目がタグ・コメント・文字参照。偶数番目のテキスト部分だけをフォーマットする\n return str\n .split(HTML_TOKEN)\n .map((segment, i) => i % 2 === 1 ? segment : formatText(segment))\n .join('');\n }\n\n return formatText(escapeHtml(str));\n}\n\n/**\n * 値を整形したJSON文字列にしてWEB表示用にフォーマットする\n * formatJsonStringで整形した文字列をformatStringForWebで変換する\n *\n * @param {any} value\n * @param {*} [options] formatJsonStringのオプションに以下を加えたもの\n * ├ html boolean trueを指定した場合、文字列をHTMLとして扱う\n * @returns {string}\n */\nexport function formatJsonStringForWeb(value: any, options?: FormatJsonStringOptions & {\n html?: boolean;\n}): string {\n const { html, ...formatOptions } = options ?? {};\n const json = formatJsonString(value, formatOptions);\n return json == null ? '' : formatStringForWeb(String(json), { html });\n}\n\n/**\n * 文字列の中で一致したワードをmarkタグで囲んだHTML文字列を返す\n * markタグは既定の背景色・文字色を持つ。色はCSS変数(--dwui-background-highlight / --dwui-color-text-highlight)で変更できる\n * styleは既定の背景色・文字色より後に出力する\n * オプションのhtmlにより、入力文字列がHTMLなのかプレーンテキストなのかを指定可能\n *\n * 例)\n * HtmlUtil.highlightWord('This is a test message', 'test', { class: 'highlight' });\n * → 'This is a <mark class=\"highlight\" style=\"background: var(--dwui-background-highlight, Mark); color: var(--dwui-color-text-highlight, MarkText)\">test</mark> message'\n *\n * @param {string | null | undefined} value\n * @param {string | null | undefined} word\n * @param {*} [options] markタグに付与するclass, styleのほか、以下を指定できる\n * ├ class string | string[] | Record<string, boolean>\n * ├ style string | Record<string, string | number>\n * ├ caseInsensitive boolean trueを指定した場合、大文字小文字を区別しない\n * ├ html boolean trueを指定した場合、入力された文字列をHTMLとして扱う\n * @returns {string}\n */\nexport function highlightWord(\n value: string | null | undefined,\n word: string | null | undefined,\n options?: HtmlTagOptions & {\n caseInsensitive?: boolean;\n html?: boolean;\n }\n): string {\n if (!value) {\n return '';\n }\n\n const toHtml = (text: string): string => options?.html ? text : escapeHtml(text);\n if (!word) {\n return toHtml(value);\n }\n\n const pattern = word.replace(/[|\\\\{}()[\\]^$+*?.]/g, '\\\\$&').replace(/-/g, '\\\\x2d');\n const regex = new RegExp(`(${pattern})`, options?.caseInsensitive ? 'i' : '');\n // キャプチャグループで分割すると、奇数番目の要素が一致した部分になる\n const highlight = (text: string): string => text\n .split(regex)\n .map((part, i) => i % 2 === 0 ? toHtml(part) : toElement('mark', part, options, HIGHLIGHT_STYLE))\n .join('');\n\n if (!options?.html) {\n return highlight(value);\n }\n\n // 奇数番目がタグ・コメント・文字参照。偶数番目のテキスト部分だけをハイライトする\n return value\n .split(HTML_TOKEN)\n .map((segment, i) => i % 2 === 1 ? segment : highlight(segment))\n .join('');\n}\n\n/**\n * 文字列を1文字ずつ比較し、差分をspanタグで囲んだHTML文字列を返す\n * 追加・削除・一致の部分ごとに既定の文字色を持つ。文字色はCSS変数(--dwui-color-text-diff-added / --dwui-color-text-diff-removed / --dwui-color-text-diff-same)で変更できる\n * 追加・削除・一致の部分ごとに、spanタグに付与するclass, styleを指定できる。styleは既定の文字色より後に出力する\n * 入力文字列はプレーンなテキストであるとみなす\n * 出力される文字列は、diffで埋め込まれるHTMLタグ以外はHTMLエスケープされ、HTMLセーフな文字列となる\n *\n * @param {string | null | undefined} text1 比較元の文字列\n * @param {string | null | undefined} text2 比較される文字列(通常、入力値はこちらに渡す)\n * @param {*} [options]\n * ├ ignoreCase boolean trueを指定した場合、大文字小文字を区別しない\n * ├ added HtmlTagOptions text2で追加された部分のspanタグに付与する属性\n * ├ removed HtmlTagOptions text2で削除された部分のspanタグに付与する属性\n * ├ same HtmlTagOptions 一致した部分のspanタグに付与する属性\n * @returns {string}\n */\nexport function diffForWeb(text1: string | null | undefined, text2: string | null | undefined, options?: {\n ignoreCase?: boolean;\n added?: HtmlTagOptions;\n removed?: HtmlTagOptions;\n same?: HtmlTagOptions;\n}): string {\n const changes = diffChars(text1 ?? '', text2 ?? '', { ignoreCase: options?.ignoreCase });\n let html = '';\n for (const change of changes) {\n if (change.added) {\n html += toElement('span', change.value, options?.added, DIFF_STYLES.added);\n } else if (change.removed) {\n html += toElement('span', change.value, options?.removed, DIFF_STYLES.removed);\n } else {\n html += toElement('span', change.value, options?.same, DIFF_STYLES.same);\n }\n }\n return html;\n}\n"],"names":["HTML_TOKEN","HTML_ESCAPE_CHARS","escapeHtml","str","c","toClassString","value","key","toStyleString","v","DIFF_STYLES","HIGHLIGHT_STYLE","toElement","tagName","options","defaultStyle","attributes","className","style","formatStringForWeb","formatText","text","segment","i","formatJsonStringForWeb","html","formatOptions","json","formatJsonString","highlightWord","word","toHtml","pattern","regex","highlight","part","diffForWeb","text1","text2","changes","diffChars","change"],"mappings":"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"}