@digitalwalletcorp/utils 0.13.1 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/file-util-8dZPFn1f.cjs +2 -0
- package/lib/file-util-8dZPFn1f.cjs.map +1 -0
- package/lib/{file-util-CO5vjmkO.js → file-util-DrU0xUXt.js} +50 -44
- package/lib/file-util-DrU0xUXt.js.map +1 -0
- package/lib/file-util.cjs +1 -1
- package/lib/file-util.d.cts +9 -0
- package/lib/file-util.d.ts +9 -0
- package/lib/file-util.js +14 -13
- package/lib/index.cjs +1 -1
- package/lib/index.js +1 -1
- package/lib/zoned-date-time.cjs +1 -1
- package/lib/zoned-date-time.cjs.map +1 -1
- package/lib/zoned-date-time.d.cts +14 -0
- package/lib/zoned-date-time.d.ts +14 -0
- package/lib/zoned-date-time.js +25 -7
- package/lib/zoned-date-time.js.map +1 -1
- package/package.json +1 -1
- package/src/file-util.ts +13 -0
- package/src/zoned-date-time.ts +20 -0
- package/lib/file-util-CO5vjmkO.js.map +0 -1
- package/lib/file-util-Dqiw5tBQ.cjs +0 -2
- package/lib/file-util-Dqiw5tBQ.cjs.map +0 -1
|
@@ -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
|
|
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
|
-
},
|
|
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
|
|
37
|
+
function m(e, t) {
|
|
38
38
|
return `data:${t || g};base64,${e}`;
|
|
39
39
|
}
|
|
40
|
-
function
|
|
41
|
-
const t =
|
|
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
|
|
44
|
+
async function F(e) {
|
|
45
45
|
if (typeof e == "string")
|
|
46
|
-
return
|
|
46
|
+
return u.test(e) ? e : y(e);
|
|
47
47
|
if (e instanceof Blob) {
|
|
48
48
|
const t = await e.arrayBuffer();
|
|
49
|
-
return
|
|
49
|
+
return a(t, e.type || f(t)?.mime);
|
|
50
50
|
}
|
|
51
|
-
return
|
|
51
|
+
return a(e, f(e)?.mime);
|
|
52
52
|
}
|
|
53
|
-
async function
|
|
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 &&
|
|
57
|
+
return e && m(e, t || f(e)?.mime);
|
|
58
58
|
}
|
|
59
|
-
function
|
|
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
|
|
66
|
-
|
|
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(
|
|
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
|
|
79
|
-
return
|
|
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 =
|
|
104
|
+
const n = l(e).slice(0, 16384);
|
|
101
105
|
try {
|
|
102
|
-
t = c(
|
|
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
|
|
112
|
+
return b(t);
|
|
109
113
|
}
|
|
110
|
-
function
|
|
114
|
+
function L(e) {
|
|
111
115
|
return e.replace(/[\\/:*?"<>|]/g, "");
|
|
112
116
|
}
|
|
113
|
-
const
|
|
117
|
+
const R = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
114
118
|
__proto__: null,
|
|
115
119
|
analyzeFileType: f,
|
|
116
120
|
arrayBufferToBase64: h,
|
|
117
|
-
arrayBufferToDataURL:
|
|
118
|
-
base64ToArrayBuffer:
|
|
121
|
+
arrayBufferToDataURL: a,
|
|
122
|
+
base64ToArrayBuffer: s,
|
|
123
|
+
base64ToBlob: _,
|
|
119
124
|
base64ToDataURL: y,
|
|
120
125
|
calcSize: v,
|
|
121
126
|
convertUTF16withBOM: D,
|
|
122
|
-
createDataURL:
|
|
127
|
+
createDataURL: m,
|
|
123
128
|
dataURLToArrayBuffer: p,
|
|
124
|
-
dataURLToBase64:
|
|
125
|
-
parseDataURL:
|
|
126
|
-
readAsArrayBuffer:
|
|
127
|
-
readAsDataURL:
|
|
128
|
-
sanitizeFileName:
|
|
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
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
F as
|
|
144
|
-
|
|
145
|
-
|
|
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-
|
|
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-
|
|
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
|
package/lib/file-util.d.cts
CHANGED
|
@@ -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.d.ts
CHANGED
|
@@ -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
|
|
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
|
-
|
|
4
|
-
|
|
3
|
+
s as analyzeFileType,
|
|
4
|
+
r as arrayBufferToBase64,
|
|
5
5
|
t as arrayBufferToDataURL,
|
|
6
6
|
f as base64ToArrayBuffer,
|
|
7
|
-
o as
|
|
8
|
-
B as
|
|
9
|
-
T as
|
|
10
|
-
U as
|
|
11
|
-
i as
|
|
12
|
-
y as
|
|
13
|
-
L as
|
|
14
|
-
R as
|
|
15
|
-
|
|
16
|
-
|
|
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
|
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-
|
|
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,7 +2,7 @@ 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-
|
|
5
|
+
import { f as s } from "./file-util-DrU0xUXt.js";
|
|
6
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";
|
package/lib/zoned-date-time.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("luxon"),d="UTC",h="en-US",m=s=>{if(!s.isValid&&s.invalidReason==="unsupported zone")throw new RangeError(s.invalidExplanation??s.invalidReason)},o=(s,t,e,i)=>{if(t!==void 0&&(!Number.isInteger(t)||t<e||i<t))throw new RangeError(`${s} must be an integer from ${e} to ${i}: ${t}`)};class n{dateTime;constructor(t){this.dateTime=t}static now(t=d){const e=a.DateTime.now().setZone(t);return m(e),new n(e)}static parse(t,e){if(t==null||t==="")return null;const i=e?.inputTimezone??d;let r=null;if(t instanceof n)r=e?.inputTimezone?t.dateTime.setZone(e.inputTimezone):t.dateTime;else if(t instanceof Date)r=a.DateTime.fromJSDate(t,{zone:i});else if(typeof t=="number")r=Number.isFinite(t)?a.DateTime.fromMillis(t,{zone:i}):null;else{const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("luxon"),d="UTC",h="en-US",m=s=>{if(!s.isValid&&s.invalidReason==="unsupported zone")throw new RangeError(s.invalidExplanation??s.invalidReason)},o=(s,t,e,i)=>{if(t!==void 0&&(!Number.isInteger(t)||t<e||i<t))throw new RangeError(`${s} must be an integer from ${e} to ${i}: ${t}`)};class n{dateTime;constructor(t){this.dateTime=t}static now(t=d){const e=a.DateTime.now().setZone(t);return m(e),new n(e)}static parse(t,e){if(t==null||t==="")return null;const i=e?.inputTimezone??d;let r=null;if(t instanceof n)r=e?.inputTimezone?t.dateTime.setZone(e.inputTimezone):t.dateTime;else if(t instanceof Date)r=a.DateTime.fromJSDate(t,{zone:i});else if(typeof t=="number")r=Number.isFinite(t)?a.DateTime.fromMillis(t,{zone:i}):null;else{const l=e?.locale??h,c=e?.inputFormat?[e.inputFormat].flat():[];for(const T of c){const u=a.DateTime.fromFormat(t,T,{zone:i,locale:l});if(m(u),u.isValid){r=u;break}}r==null&&(r=a.DateTime.fromISO(t,{zone:i}))}return r==null||(m(r),!r.isValid)?null:(e?.duration&&(r=r.plus(e.duration)),e?.startOf&&(r=r.startOf(e.startOf)),e?.endOf&&(r=r.endOf(e.endOf)),new n(r))}get year(){return this.dateTime.year}get month(){return this.dateTime.month}get day(){return this.dateTime.day}get hour(){return this.dateTime.hour}get minute(){return this.dateTime.minute}get second(){return this.dateTime.second}get millisecond(){return this.dateTime.millisecond}get weekday(){return this.dateTime.weekday}get daysInMonth(){return this.dateTime.daysInMonth}get isInDST(){return this.dateTime.isInDST}get timezone(){return this.dateTime.zoneName}plus(t){return new n(this.dateTime.plus(t))}minus(t){return new n(this.dateTime.minus(t))}startOf(t){return new n(this.dateTime.startOf(t))}endOf(t){return new n(this.dateTime.endOf(t))}set(t){o("month",t.month,1,12),o("hour",t.hour,0,23),o("minute",t.minute,0,59),o("second",t.second,0,59),o("millisecond",t.millisecond,0,999);const e=this.dateTime.set({year:t.year??this.year,month:t.month??this.month,day:1}).daysInMonth;return o("day",t.day,1,e),new n(this.dateTime.set(t))}setZone(t){const e=this.dateTime.setZone(t);return m(e),new n(e)}diff(t,e){const i=e.slice(0,-1),r=t.dateTime.setZone(this.dateTime.zone);return this.dateTime.startOf(i).diff(r.startOf(i),e).get(e)}compareTo(t){return Math.sign(this.toMillis()-t.toMillis())}eq(t){return this.compareTo(t)===0}lt(t){return this.compareTo(t)<0}lte(t){return this.compareTo(t)<=0}gt(t){return 0<this.compareTo(t)}gte(t){return 0<=this.compareTo(t)}format(t,e){return this.dateTime.toFormat(t,{locale:e?.locale??h})}toISO(){return this.dateTime.toISO()}toDate(){return this.dateTime.toJSDate()}toMillis(){return this.dateTime.toMillis()}toString(){return this.toISO()}valueOf(){return this.toMillis()}[Symbol.toPrimitive](t){return t==="number"?this.toMillis():this.toISO()}}exports.ZonedDateTime=n;
|
|
2
2
|
//# sourceMappingURL=zoned-date-time.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zoned-date-time.cjs","sources":["../src/zoned-date-time.ts"],"sourcesContent":["/**\n * このクラス ZonedDateTime の役割は、日時演算の実体としての luxon を内部に閉じ込め、利用者側に露出させないことにある\n */\nimport { DateTime } from 'luxon';\nimport type { DateInput, DateUnit, Duration, ParseDateOptions, TimeUnit } from './date-util';\n\n/** set で変更する日時の要素。month は1〜12 */\nexport interface ZonedDateTimeFields {\n year?: number;\n month?: number;\n day?: number;\n hour?: number;\n minute?: number;\n second?: number;\n millisecond?: number;\n}\n\n/**\n * 日時を文字列にするときのオプション\n */\nexport interface ZonedDateTimeFormatOptions {\n /** 月名・曜日名に使うロケール。既定は 'en-US' */\n locale?: string;\n}\n\nconst DEFAULT_TIMEZONE = 'UTC';\n\nconst DEFAULT_LOCALE = 'en-US';\n\n/**\n * タイムゾーンの指定が不正な場合は、日時の不正とは区別して例外にする\n */\nconst assertZone = (d: DateTime): void => {\n if (!d.isValid && d.invalidReason === 'unsupported zone') {\n throw new RangeError(d.invalidExplanation ?? d.invalidReason);\n }\n};\n\n/**\n * set に渡された要素が min〜max の整数であることを確かめる\n */\nconst assertField = (name: keyof ZonedDateTimeFields, value: number | undefined, min: number, max: number): void => {\n if (value === undefined) {\n return;\n }\n if (!Number.isInteger(value) || value < min || max < value) {\n throw new RangeError(`${name} must be an integer from ${min} to ${max}: ${value}`);\n }\n};\n\n/**\n * 日時を表す不変オブジェクト\n * 演算メソッドは自身を変更せず、結果を新しいインスタンスで返す\n * インスタンスごとにタイムゾーンを持ち、startOf / endOf / set や各要素の参照はそのタイムゾーンで計算する\n */\nexport class ZonedDateTime {\n /**\n * 日時演算インスタンス\n */\n private dateTime: DateTime;\n\n private constructor(dateTime: DateTime) {\n this.dateTime = dateTime;\n }\n\n /**\n * 現在時刻を返す\n * タイムゾーンの指定が不正な場合は RangeError をスローする\n *\n * @param {string} [timezone] IANA名。既定は 'UTC'\n * @returns {ZonedDateTime}\n */\n public static now(timezone: string = DEFAULT_TIMEZONE): ZonedDateTime {\n const d = DateTime.now().setZone(timezone);\n assertZone(d);\n return new ZonedDateTime(d);\n }\n\n /**\n * 値を日時として解釈する\n * 生成したインスタンスは inputTimezone のタイムゾーンを持つ\n * ZonedDateTime を渡した場合、inputTimezone を省略すると渡した ZonedDateTime のタイムゾーンを引き継ぐ\n * duration / startOf / endOf はそのタイムゾーンで計算する\n * 解釈できない値、null / undefined / 空文字は null を返す。タイムゾーンの指定が不正な場合は RangeError をスローする\n *\n * @param {DateInput} value\n * @param {ParseDateOptions} [options]\n * @returns {ZonedDateTime | null}\n */\n public static parse(value: DateInput, options?: ParseDateOptions): ZonedDateTime | null {\n if (value == null || value === '') {\n return null;\n }\n const zone = options?.inputTimezone ?? DEFAULT_TIMEZONE;\n let d: DateTime | null = null;\n if (value instanceof ZonedDateTime) {\n d = options?.inputTimezone ? value.dateTime.setZone(options.inputTimezone) : value.dateTime;\n } else if (value instanceof Date) {\n d = DateTime.fromJSDate(value, { zone: zone });\n } else if (typeof value === 'number') {\n d = Number.isFinite(value) ? DateTime.fromMillis(value, { zone: zone }) : null;\n } else {\n const locale = options?.locale ?? DEFAULT_LOCALE;\n const formats = options?.inputFormat ? [options.inputFormat].flat() : [];\n for (const format of formats) {\n const parsed = DateTime.fromFormat(value, format, {\n zone: zone,\n locale: locale\n });\n assertZone(parsed);\n if (parsed.isValid) {\n d = parsed;\n break;\n }\n }\n if (d == null) {\n d = DateTime.fromISO(value, { zone: zone });\n }\n }\n if (d == null) {\n return null;\n }\n assertZone(d);\n if (!d.isValid) {\n return null;\n }\n if (options?.duration) {\n d = d.plus(options.duration);\n }\n if (options?.startOf) {\n d = d.startOf(options.startOf);\n }\n if (options?.endOf) {\n d = d.endOf(options.endOf);\n }\n return new ZonedDateTime(d);\n }\n\n /** 年 */\n public get year(): number {\n return this.dateTime.year;\n }\n\n /** 月(1〜12) */\n public get month(): number {\n return this.dateTime.month;\n }\n\n /** 日 */\n public get day(): number {\n return this.dateTime.day;\n }\n\n /** 時 */\n public get hour(): number {\n return this.dateTime.hour;\n }\n\n /** 分 */\n public get minute(): number {\n return this.dateTime.minute;\n }\n\n /** 秒 */\n public get second(): number {\n return this.dateTime.second;\n }\n\n /** ミリ秒 */\n public get millisecond(): number {\n return this.dateTime.millisecond;\n }\n\n /** 曜日。月曜が1、日曜が7 */\n public get weekday(): number {\n return this.dateTime.weekday;\n }\n\n /** その月の日数 */\n public get daysInMonth(): number {\n return this.dateTime.daysInMonth as number;\n }\n\n /** 夏時間の期間中か */\n public get isInDST(): boolean {\n return this.dateTime.isInDST;\n }\n\n /** タイムゾーン(IANA名) */\n public get timezone(): string {\n return this.dateTime.zoneName as string;\n }\n\n /**\n * 期間を加算した結果を返す\n * 負の値を指定すると減算になる\n *\n * @param {Duration} duration\n * @returns {ZonedDateTime}\n */\n public plus(duration: Duration): ZonedDateTime {\n return new ZonedDateTime(this.dateTime.plus(duration));\n }\n\n /**\n * 期間を減算した結果を返す\n *\n * @param {Duration} duration\n * @returns {ZonedDateTime}\n */\n public minus(duration: Duration): ZonedDateTime {\n return new ZonedDateTime(this.dateTime.minus(duration));\n }\n\n /**\n * 指定した単位の最初の時点に切り捨てた結果を返す(month なら月初の00:00:00.000)\n * week は月曜始まりで切り捨てる\n *\n * @param {DateUnit} unit\n * @returns {ZonedDateTime}\n */\n public startOf(unit: DateUnit): ZonedDateTime {\n return new ZonedDateTime(this.dateTime.startOf(unit));\n }\n\n /**\n * 指定した単位の最後の時点に切り上げた結果を返す(month なら月末の23:59:59.999)\n * week は日曜終わりで切り上げる\n *\n * @param {DateUnit} unit\n * @returns {ZonedDateTime}\n */\n public endOf(unit: DateUnit): ZonedDateTime {\n return new ZonedDateTime(this.dateTime.endOf(unit));\n }\n\n /**\n * 指定した要素を変更した結果を返す\n * 範囲外の値や整数でない値を指定した場合は RangeError をスローする\n * day を指定せずに year / month を変更し、日がその月に無い場合は月末日にする(1月31日に { month: 2 } なら2月末日)\n *\n * @param {ZonedDateTimeFields} fields\n * @returns {ZonedDateTime}\n */\n public set(fields: ZonedDateTimeFields): ZonedDateTime {\n assertField('month', fields.month, 1, 12);\n assertField('hour', fields.hour, 0, 23);\n assertField('minute', fields.minute, 0, 59);\n assertField('second', fields.second, 0, 59);\n assertField('millisecond', fields.millisecond, 0, 999);\n // day の上限は変更後の年月で決まる\n const daysInMonth = this.dateTime.set({\n year: fields.year ?? this.year,\n month: fields.month ?? this.month,\n day: 1\n }).daysInMonth as number;\n assertField('day', fields.day, 1, daysInMonth);\n return new ZonedDateTime(this.dateTime.set(fields));\n }\n\n /**\n * 同じ時刻を別のタイムゾーンで表した結果を返す\n * タイムゾーンの指定が不正な場合は RangeError をスローする\n *\n * @param {string} timezone IANA名\n * @returns {ZonedDateTime}\n */\n public setZone(timezone: string): ZonedDateTime {\n const d = this.dateTime.setZone(timezone);\n assertZone(d);\n return new ZonedDateTime(d);\n }\n\n /**\n * 自身 − other を unit の単位で返す\n * 両方を自身のタイムゾーンで unit の始まりに切り捨ててから差を取るため、暦の上での差になる(23:00 と翌 01:00 の days は 1)\n *\n * @param {ZonedDateTime} other\n * @param {TimeUnit} unit\n * @returns {number}\n */\n public diff(other: ZonedDateTime, unit: TimeUnit): number {\n // 'days' → 'day' のように切り捨ての単位にする\n const dateUnit = unit.slice(0, -1) as DateUnit;\n const target = other.dateTime.setZone(this.dateTime.zone);\n return this.dateTime.startOf(dateUnit).diff(target.startOf(dateUnit), unit).get(unit);\n }\n\n /**\n * 時刻を比較する。タイムゾーンが異なっていても同じ時刻なら等しい\n *\n * @param {ZonedDateTime} other\n * @returns {-1 | 0 | 1} 自身が前なら-1、等しければ0、後なら1\n */\n public compareTo(other: ZonedDateTime): -1 | 0 | 1 {\n return Math.sign(this.toMillis() - other.toMillis()) as -1 | 0 | 1;\n }\n\n /**\n * 同じ時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public eq(other: ZonedDateTime): boolean {\n return this.compareTo(other) === 0;\n }\n\n /**\n * 自身が前の時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public lt(other: ZonedDateTime): boolean {\n return this.compareTo(other) < 0;\n }\n\n /**\n * 自身が前か同じ時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public lte(other: ZonedDateTime): boolean {\n return this.compareTo(other) <= 0;\n }\n\n /**\n * 自身が後の時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public gt(other: ZonedDateTime): boolean {\n return 0 < this.compareTo(other);\n }\n\n /**\n * 自身が後か同じ時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public gte(other: ZonedDateTime): boolean {\n return 0 <= this.compareTo(other);\n }\n\n /**\n * 自身のタイムゾーンで、指定した書式の文字列にする\n *\n * @param {string} outputFormat\n * @param {ZonedDateTimeFormatOptions} [options]\n * @returns {string}\n */\n public format(outputFormat: string, options?: ZonedDateTimeFormatOptions): string {\n return this.dateTime.toFormat(outputFormat, { locale: options?.locale ?? DEFAULT_LOCALE });\n }\n\n /**\n * 自身のタイムゾーンで、ISO形式の文字列にする\n *\n * @returns {string}\n */\n public toISO(): string {\n return this.dateTime.toISO() as string;\n }\n\n /**\n * Date に変換する\n *\n * @returns {Date}\n */\n public toDate(): Date {\n return this.dateTime.toJSDate();\n }\n\n /**\n * epoch ミリ秒に変換する\n *\n * @returns {number}\n */\n public toMillis(): number {\n return this.dateTime.toMillis();\n }\n\n /**\n * 自身のタイムゾーンで、ISO形式の文字列にする\n *\n * @returns {string}\n */\n public toString(): string {\n return this.toISO();\n }\n}\n"],"names":["DEFAULT_TIMEZONE","DEFAULT_LOCALE","assertZone","d","assertField","name","value","min","max","ZonedDateTime","dateTime","timezone","DateTime","options","zone","locale","formats","format","parsed","duration","unit","fields","daysInMonth","other","dateUnit","target","outputFormat"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"zoned-date-time.cjs","sources":["../src/zoned-date-time.ts"],"sourcesContent":["/**\n * このクラス ZonedDateTime の役割は、日時演算の実体としての luxon を内部に閉じ込め、利用者側に露出させないことにある\n */\nimport { DateTime } from 'luxon';\nimport type { DateInput, DateUnit, Duration, ParseDateOptions, TimeUnit } from './date-util';\n\n/** set で変更する日時の要素。month は1〜12 */\nexport interface ZonedDateTimeFields {\n year?: number;\n month?: number;\n day?: number;\n hour?: number;\n minute?: number;\n second?: number;\n millisecond?: number;\n}\n\n/**\n * 日時を文字列にするときのオプション\n */\nexport interface ZonedDateTimeFormatOptions {\n /** 月名・曜日名に使うロケール。既定は 'en-US' */\n locale?: string;\n}\n\nconst DEFAULT_TIMEZONE = 'UTC';\n\nconst DEFAULT_LOCALE = 'en-US';\n\n/**\n * タイムゾーンの指定が不正な場合は、日時の不正とは区別して例外にする\n */\nconst assertZone = (d: DateTime): void => {\n if (!d.isValid && d.invalidReason === 'unsupported zone') {\n throw new RangeError(d.invalidExplanation ?? d.invalidReason);\n }\n};\n\n/**\n * set に渡された要素が min〜max の整数であることを確かめる\n */\nconst assertField = (name: keyof ZonedDateTimeFields, value: number | undefined, min: number, max: number): void => {\n if (value === undefined) {\n return;\n }\n if (!Number.isInteger(value) || value < min || max < value) {\n throw new RangeError(`${name} must be an integer from ${min} to ${max}: ${value}`);\n }\n};\n\n/**\n * 日時を表す不変オブジェクト\n * 演算メソッドは自身を変更せず、結果を新しいインスタンスで返す\n * インスタンスごとにタイムゾーンを持ち、startOf / endOf / set や各要素の参照はそのタイムゾーンで計算する\n */\nexport class ZonedDateTime {\n /**\n * 日時演算インスタンス\n */\n private dateTime: DateTime;\n\n private constructor(dateTime: DateTime) {\n this.dateTime = dateTime;\n }\n\n /**\n * 現在時刻を返す\n * タイムゾーンの指定が不正な場合は RangeError をスローする\n *\n * @param {string} [timezone] IANA名。既定は 'UTC'\n * @returns {ZonedDateTime}\n */\n public static now(timezone: string = DEFAULT_TIMEZONE): ZonedDateTime {\n const d = DateTime.now().setZone(timezone);\n assertZone(d);\n return new ZonedDateTime(d);\n }\n\n /**\n * 値を日時として解釈する\n * 生成したインスタンスは inputTimezone のタイムゾーンを持つ\n * ZonedDateTime を渡した場合、inputTimezone を省略すると渡した ZonedDateTime のタイムゾーンを引き継ぐ\n * duration / startOf / endOf はそのタイムゾーンで計算する\n * 解釈できない値、null / undefined / 空文字は null を返す。タイムゾーンの指定が不正な場合は RangeError をスローする\n *\n * @param {DateInput} value\n * @param {ParseDateOptions} [options]\n * @returns {ZonedDateTime | null}\n */\n public static parse(value: DateInput, options?: ParseDateOptions): ZonedDateTime | null {\n if (value == null || value === '') {\n return null;\n }\n const zone = options?.inputTimezone ?? DEFAULT_TIMEZONE;\n let d: DateTime | null = null;\n if (value instanceof ZonedDateTime) {\n d = options?.inputTimezone ? value.dateTime.setZone(options.inputTimezone) : value.dateTime;\n } else if (value instanceof Date) {\n d = DateTime.fromJSDate(value, { zone: zone });\n } else if (typeof value === 'number') {\n d = Number.isFinite(value) ? DateTime.fromMillis(value, { zone: zone }) : null;\n } else {\n const locale = options?.locale ?? DEFAULT_LOCALE;\n const formats = options?.inputFormat ? [options.inputFormat].flat() : [];\n for (const format of formats) {\n const parsed = DateTime.fromFormat(value, format, {\n zone: zone,\n locale: locale\n });\n assertZone(parsed);\n if (parsed.isValid) {\n d = parsed;\n break;\n }\n }\n if (d == null) {\n d = DateTime.fromISO(value, { zone: zone });\n }\n }\n if (d == null) {\n return null;\n }\n assertZone(d);\n if (!d.isValid) {\n return null;\n }\n if (options?.duration) {\n d = d.plus(options.duration);\n }\n if (options?.startOf) {\n d = d.startOf(options.startOf);\n }\n if (options?.endOf) {\n d = d.endOf(options.endOf);\n }\n return new ZonedDateTime(d);\n }\n\n /** 年 */\n public get year(): number {\n return this.dateTime.year;\n }\n\n /** 月(1〜12) */\n public get month(): number {\n return this.dateTime.month;\n }\n\n /** 日 */\n public get day(): number {\n return this.dateTime.day;\n }\n\n /** 時 */\n public get hour(): number {\n return this.dateTime.hour;\n }\n\n /** 分 */\n public get minute(): number {\n return this.dateTime.minute;\n }\n\n /** 秒 */\n public get second(): number {\n return this.dateTime.second;\n }\n\n /** ミリ秒 */\n public get millisecond(): number {\n return this.dateTime.millisecond;\n }\n\n /** 曜日。月曜が1、日曜が7 */\n public get weekday(): number {\n return this.dateTime.weekday;\n }\n\n /** その月の日数 */\n public get daysInMonth(): number {\n return this.dateTime.daysInMonth as number;\n }\n\n /** 夏時間の期間中か */\n public get isInDST(): boolean {\n return this.dateTime.isInDST;\n }\n\n /** タイムゾーン(IANA名) */\n public get timezone(): string {\n return this.dateTime.zoneName as string;\n }\n\n /**\n * 期間を加算した結果を返す\n * 負の値を指定すると減算になる\n *\n * @param {Duration} duration\n * @returns {ZonedDateTime}\n */\n public plus(duration: Duration): ZonedDateTime {\n return new ZonedDateTime(this.dateTime.plus(duration));\n }\n\n /**\n * 期間を減算した結果を返す\n *\n * @param {Duration} duration\n * @returns {ZonedDateTime}\n */\n public minus(duration: Duration): ZonedDateTime {\n return new ZonedDateTime(this.dateTime.minus(duration));\n }\n\n /**\n * 指定した単位の最初の時点に切り捨てた結果を返す(month なら月初の00:00:00.000)\n * week は月曜始まりで切り捨てる\n *\n * @param {DateUnit} unit\n * @returns {ZonedDateTime}\n */\n public startOf(unit: DateUnit): ZonedDateTime {\n return new ZonedDateTime(this.dateTime.startOf(unit));\n }\n\n /**\n * 指定した単位の最後の時点に切り上げた結果を返す(month なら月末の23:59:59.999)\n * week は日曜終わりで切り上げる\n *\n * @param {DateUnit} unit\n * @returns {ZonedDateTime}\n */\n public endOf(unit: DateUnit): ZonedDateTime {\n return new ZonedDateTime(this.dateTime.endOf(unit));\n }\n\n /**\n * 指定した要素を変更した結果を返す\n * 範囲外の値や整数でない値を指定した場合は RangeError をスローする\n * day を指定せずに year / month を変更し、日がその月に無い場合は月末日にする(1月31日に { month: 2 } なら2月末日)\n *\n * @param {ZonedDateTimeFields} fields\n * @returns {ZonedDateTime}\n */\n public set(fields: ZonedDateTimeFields): ZonedDateTime {\n assertField('month', fields.month, 1, 12);\n assertField('hour', fields.hour, 0, 23);\n assertField('minute', fields.minute, 0, 59);\n assertField('second', fields.second, 0, 59);\n assertField('millisecond', fields.millisecond, 0, 999);\n // day の上限は変更後の年月で決まる\n const daysInMonth = this.dateTime.set({\n year: fields.year ?? this.year,\n month: fields.month ?? this.month,\n day: 1\n }).daysInMonth as number;\n assertField('day', fields.day, 1, daysInMonth);\n return new ZonedDateTime(this.dateTime.set(fields));\n }\n\n /**\n * 同じ時刻を別のタイムゾーンで表した結果を返す\n * タイムゾーンの指定が不正な場合は RangeError をスローする\n *\n * @param {string} timezone IANA名\n * @returns {ZonedDateTime}\n */\n public setZone(timezone: string): ZonedDateTime {\n const d = this.dateTime.setZone(timezone);\n assertZone(d);\n return new ZonedDateTime(d);\n }\n\n /**\n * 自身 − other を unit の単位で返す\n * 両方を自身のタイムゾーンで unit の始まりに切り捨ててから差を取るため、暦の上での差になる(23:00 と翌 01:00 の days は 1)\n *\n * @param {ZonedDateTime} other\n * @param {TimeUnit} unit\n * @returns {number}\n */\n public diff(other: ZonedDateTime, unit: TimeUnit): number {\n // 'days' → 'day' のように切り捨ての単位にする\n const dateUnit = unit.slice(0, -1) as DateUnit;\n const target = other.dateTime.setZone(this.dateTime.zone);\n return this.dateTime.startOf(dateUnit).diff(target.startOf(dateUnit), unit).get(unit);\n }\n\n /**\n * 時刻を比較する。タイムゾーンが異なっていても同じ時刻なら等しい\n *\n * @param {ZonedDateTime} other\n * @returns {-1 | 0 | 1} 自身が前なら-1、等しければ0、後なら1\n */\n public compareTo(other: ZonedDateTime): -1 | 0 | 1 {\n return Math.sign(this.toMillis() - other.toMillis()) as -1 | 0 | 1;\n }\n\n /**\n * 同じ時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public eq(other: ZonedDateTime): boolean {\n return this.compareTo(other) === 0;\n }\n\n /**\n * 自身が前の時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public lt(other: ZonedDateTime): boolean {\n return this.compareTo(other) < 0;\n }\n\n /**\n * 自身が前か同じ時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public lte(other: ZonedDateTime): boolean {\n return this.compareTo(other) <= 0;\n }\n\n /**\n * 自身が後の時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public gt(other: ZonedDateTime): boolean {\n return 0 < this.compareTo(other);\n }\n\n /**\n * 自身が後か同じ時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public gte(other: ZonedDateTime): boolean {\n return 0 <= this.compareTo(other);\n }\n\n /**\n * 自身のタイムゾーンで、指定した書式の文字列にする\n *\n * @param {string} outputFormat\n * @param {ZonedDateTimeFormatOptions} [options]\n * @returns {string}\n */\n public format(outputFormat: string, options?: ZonedDateTimeFormatOptions): string {\n return this.dateTime.toFormat(outputFormat, { locale: options?.locale ?? DEFAULT_LOCALE });\n }\n\n /**\n * 自身のタイムゾーンで、ISO形式の文字列にする\n *\n * @returns {string}\n */\n public toISO(): string {\n return this.dateTime.toISO() as string;\n }\n\n /**\n * Date に変換する\n *\n * @returns {Date}\n */\n public toDate(): Date {\n return this.dateTime.toJSDate();\n }\n\n /**\n * epoch ミリ秒に変換する\n *\n * @returns {number}\n */\n public toMillis(): number {\n return this.dateTime.toMillis();\n }\n\n /**\n * 自身のタイムゾーンで、ISO形式の文字列にする\n *\n * @returns {string}\n */\n public toString(): string {\n return this.toISO();\n }\n\n /**\n * epoch ミリ秒を返す。< や > で時刻の前後を比較できるようにするため\n *\n * @returns {number}\n */\n public valueOf(): number {\n return this.toMillis();\n }\n\n /**\n * プリミティブ値への変換\n * 数値が必要な場面(< や > による比較)では epoch ミリ秒、それ以外(+ による文字列の連結など)ではISO形式の文字列にする\n *\n * @param {string} hint\n * @returns {number | string}\n */\n public [Symbol.toPrimitive](hint: 'number' | 'string' | 'default'): number | string {\n return hint === 'number' ? this.toMillis() : this.toISO();\n }\n}\n"],"names":["DEFAULT_TIMEZONE","DEFAULT_LOCALE","assertZone","d","assertField","name","value","min","max","ZonedDateTime","dateTime","timezone","DateTime","options","zone","locale","formats","format","parsed","duration","unit","fields","daysInMonth","other","dateUnit","target","outputFormat","hint"],"mappings":"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"}
|
|
@@ -200,4 +200,18 @@ export declare class ZonedDateTime {
|
|
|
200
200
|
* @returns {string}
|
|
201
201
|
*/
|
|
202
202
|
toString(): string;
|
|
203
|
+
/**
|
|
204
|
+
* epoch ミリ秒を返す。< や > で時刻の前後を比較できるようにするため
|
|
205
|
+
*
|
|
206
|
+
* @returns {number}
|
|
207
|
+
*/
|
|
208
|
+
valueOf(): number;
|
|
209
|
+
/**
|
|
210
|
+
* プリミティブ値への変換
|
|
211
|
+
* 数値が必要な場面(< や > による比較)では epoch ミリ秒、それ以外(+ による文字列の連結など)ではISO形式の文字列にする
|
|
212
|
+
*
|
|
213
|
+
* @param {string} hint
|
|
214
|
+
* @returns {number | string}
|
|
215
|
+
*/
|
|
216
|
+
[Symbol.toPrimitive](hint: 'number' | 'string' | 'default'): number | string;
|
|
203
217
|
}
|
package/lib/zoned-date-time.d.ts
CHANGED
|
@@ -200,4 +200,18 @@ export declare class ZonedDateTime {
|
|
|
200
200
|
* @returns {string}
|
|
201
201
|
*/
|
|
202
202
|
toString(): string;
|
|
203
|
+
/**
|
|
204
|
+
* epoch ミリ秒を返す。< や > で時刻の前後を比較できるようにするため
|
|
205
|
+
*
|
|
206
|
+
* @returns {number}
|
|
207
|
+
*/
|
|
208
|
+
valueOf(): number;
|
|
209
|
+
/**
|
|
210
|
+
* プリミティブ値への変換
|
|
211
|
+
* 数値が必要な場面(< や > による比較)では epoch ミリ秒、それ以外(+ による文字列の連結など)ではISO形式の文字列にする
|
|
212
|
+
*
|
|
213
|
+
* @param {string} hint
|
|
214
|
+
* @returns {number | string}
|
|
215
|
+
*/
|
|
216
|
+
[Symbol.toPrimitive](hint: 'number' | 'string' | 'default'): number | string;
|
|
203
217
|
}
|
package/lib/zoned-date-time.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DateTime as a } from "luxon";
|
|
2
|
-
const
|
|
2
|
+
const h = "UTC", d = "en-US", m = (s) => {
|
|
3
3
|
if (!s.isValid && s.invalidReason === "unsupported zone")
|
|
4
4
|
throw new RangeError(s.invalidExplanation ?? s.invalidReason);
|
|
5
5
|
}, o = (s, t, e, n) => {
|
|
@@ -21,7 +21,7 @@ class i {
|
|
|
21
21
|
* @param {string} [timezone] IANA名。既定は 'UTC'
|
|
22
22
|
* @returns {ZonedDateTime}
|
|
23
23
|
*/
|
|
24
|
-
static now(t =
|
|
24
|
+
static now(t = h) {
|
|
25
25
|
const e = a.now().setZone(t);
|
|
26
26
|
return m(e), new i(e);
|
|
27
27
|
}
|
|
@@ -39,7 +39,7 @@ class i {
|
|
|
39
39
|
static parse(t, e) {
|
|
40
40
|
if (t == null || t === "")
|
|
41
41
|
return null;
|
|
42
|
-
const n = e?.inputTimezone ??
|
|
42
|
+
const n = e?.inputTimezone ?? h;
|
|
43
43
|
let r = null;
|
|
44
44
|
if (t instanceof i)
|
|
45
45
|
r = e?.inputTimezone ? t.dateTime.setZone(e.inputTimezone) : t.dateTime;
|
|
@@ -48,11 +48,11 @@ class i {
|
|
|
48
48
|
else if (typeof t == "number")
|
|
49
49
|
r = Number.isFinite(t) ? a.fromMillis(t, { zone: n }) : null;
|
|
50
50
|
else {
|
|
51
|
-
const
|
|
52
|
-
for (const f of
|
|
51
|
+
const l = e?.locale ?? d, c = e?.inputFormat ? [e.inputFormat].flat() : [];
|
|
52
|
+
for (const f of c) {
|
|
53
53
|
const u = a.fromFormat(t, f, {
|
|
54
54
|
zone: n,
|
|
55
|
-
locale:
|
|
55
|
+
locale: l
|
|
56
56
|
});
|
|
57
57
|
if (m(u), u.isValid) {
|
|
58
58
|
r = u;
|
|
@@ -248,7 +248,7 @@ class i {
|
|
|
248
248
|
* @returns {string}
|
|
249
249
|
*/
|
|
250
250
|
format(t, e) {
|
|
251
|
-
return this.dateTime.toFormat(t, { locale: e?.locale ??
|
|
251
|
+
return this.dateTime.toFormat(t, { locale: e?.locale ?? d });
|
|
252
252
|
}
|
|
253
253
|
/**
|
|
254
254
|
* 自身のタイムゾーンで、ISO形式の文字列にする
|
|
@@ -282,6 +282,24 @@ class i {
|
|
|
282
282
|
toString() {
|
|
283
283
|
return this.toISO();
|
|
284
284
|
}
|
|
285
|
+
/**
|
|
286
|
+
* epoch ミリ秒を返す。< や > で時刻の前後を比較できるようにするため
|
|
287
|
+
*
|
|
288
|
+
* @returns {number}
|
|
289
|
+
*/
|
|
290
|
+
valueOf() {
|
|
291
|
+
return this.toMillis();
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* プリミティブ値への変換
|
|
295
|
+
* 数値が必要な場面(< や > による比較)では epoch ミリ秒、それ以外(+ による文字列の連結など)ではISO形式の文字列にする
|
|
296
|
+
*
|
|
297
|
+
* @param {string} hint
|
|
298
|
+
* @returns {number | string}
|
|
299
|
+
*/
|
|
300
|
+
[Symbol.toPrimitive](t) {
|
|
301
|
+
return t === "number" ? this.toMillis() : this.toISO();
|
|
302
|
+
}
|
|
285
303
|
}
|
|
286
304
|
export {
|
|
287
305
|
i as ZonedDateTime
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zoned-date-time.js","sources":["../src/zoned-date-time.ts"],"sourcesContent":["/**\n * このクラス ZonedDateTime の役割は、日時演算の実体としての luxon を内部に閉じ込め、利用者側に露出させないことにある\n */\nimport { DateTime } from 'luxon';\nimport type { DateInput, DateUnit, Duration, ParseDateOptions, TimeUnit } from './date-util';\n\n/** set で変更する日時の要素。month は1〜12 */\nexport interface ZonedDateTimeFields {\n year?: number;\n month?: number;\n day?: number;\n hour?: number;\n minute?: number;\n second?: number;\n millisecond?: number;\n}\n\n/**\n * 日時を文字列にするときのオプション\n */\nexport interface ZonedDateTimeFormatOptions {\n /** 月名・曜日名に使うロケール。既定は 'en-US' */\n locale?: string;\n}\n\nconst DEFAULT_TIMEZONE = 'UTC';\n\nconst DEFAULT_LOCALE = 'en-US';\n\n/**\n * タイムゾーンの指定が不正な場合は、日時の不正とは区別して例外にする\n */\nconst assertZone = (d: DateTime): void => {\n if (!d.isValid && d.invalidReason === 'unsupported zone') {\n throw new RangeError(d.invalidExplanation ?? d.invalidReason);\n }\n};\n\n/**\n * set に渡された要素が min〜max の整数であることを確かめる\n */\nconst assertField = (name: keyof ZonedDateTimeFields, value: number | undefined, min: number, max: number): void => {\n if (value === undefined) {\n return;\n }\n if (!Number.isInteger(value) || value < min || max < value) {\n throw new RangeError(`${name} must be an integer from ${min} to ${max}: ${value}`);\n }\n};\n\n/**\n * 日時を表す不変オブジェクト\n * 演算メソッドは自身を変更せず、結果を新しいインスタンスで返す\n * インスタンスごとにタイムゾーンを持ち、startOf / endOf / set や各要素の参照はそのタイムゾーンで計算する\n */\nexport class ZonedDateTime {\n /**\n * 日時演算インスタンス\n */\n private dateTime: DateTime;\n\n private constructor(dateTime: DateTime) {\n this.dateTime = dateTime;\n }\n\n /**\n * 現在時刻を返す\n * タイムゾーンの指定が不正な場合は RangeError をスローする\n *\n * @param {string} [timezone] IANA名。既定は 'UTC'\n * @returns {ZonedDateTime}\n */\n public static now(timezone: string = DEFAULT_TIMEZONE): ZonedDateTime {\n const d = DateTime.now().setZone(timezone);\n assertZone(d);\n return new ZonedDateTime(d);\n }\n\n /**\n * 値を日時として解釈する\n * 生成したインスタンスは inputTimezone のタイムゾーンを持つ\n * ZonedDateTime を渡した場合、inputTimezone を省略すると渡した ZonedDateTime のタイムゾーンを引き継ぐ\n * duration / startOf / endOf はそのタイムゾーンで計算する\n * 解釈できない値、null / undefined / 空文字は null を返す。タイムゾーンの指定が不正な場合は RangeError をスローする\n *\n * @param {DateInput} value\n * @param {ParseDateOptions} [options]\n * @returns {ZonedDateTime | null}\n */\n public static parse(value: DateInput, options?: ParseDateOptions): ZonedDateTime | null {\n if (value == null || value === '') {\n return null;\n }\n const zone = options?.inputTimezone ?? DEFAULT_TIMEZONE;\n let d: DateTime | null = null;\n if (value instanceof ZonedDateTime) {\n d = options?.inputTimezone ? value.dateTime.setZone(options.inputTimezone) : value.dateTime;\n } else if (value instanceof Date) {\n d = DateTime.fromJSDate(value, { zone: zone });\n } else if (typeof value === 'number') {\n d = Number.isFinite(value) ? DateTime.fromMillis(value, { zone: zone }) : null;\n } else {\n const locale = options?.locale ?? DEFAULT_LOCALE;\n const formats = options?.inputFormat ? [options.inputFormat].flat() : [];\n for (const format of formats) {\n const parsed = DateTime.fromFormat(value, format, {\n zone: zone,\n locale: locale\n });\n assertZone(parsed);\n if (parsed.isValid) {\n d = parsed;\n break;\n }\n }\n if (d == null) {\n d = DateTime.fromISO(value, { zone: zone });\n }\n }\n if (d == null) {\n return null;\n }\n assertZone(d);\n if (!d.isValid) {\n return null;\n }\n if (options?.duration) {\n d = d.plus(options.duration);\n }\n if (options?.startOf) {\n d = d.startOf(options.startOf);\n }\n if (options?.endOf) {\n d = d.endOf(options.endOf);\n }\n return new ZonedDateTime(d);\n }\n\n /** 年 */\n public get year(): number {\n return this.dateTime.year;\n }\n\n /** 月(1〜12) */\n public get month(): number {\n return this.dateTime.month;\n }\n\n /** 日 */\n public get day(): number {\n return this.dateTime.day;\n }\n\n /** 時 */\n public get hour(): number {\n return this.dateTime.hour;\n }\n\n /** 分 */\n public get minute(): number {\n return this.dateTime.minute;\n }\n\n /** 秒 */\n public get second(): number {\n return this.dateTime.second;\n }\n\n /** ミリ秒 */\n public get millisecond(): number {\n return this.dateTime.millisecond;\n }\n\n /** 曜日。月曜が1、日曜が7 */\n public get weekday(): number {\n return this.dateTime.weekday;\n }\n\n /** その月の日数 */\n public get daysInMonth(): number {\n return this.dateTime.daysInMonth as number;\n }\n\n /** 夏時間の期間中か */\n public get isInDST(): boolean {\n return this.dateTime.isInDST;\n }\n\n /** タイムゾーン(IANA名) */\n public get timezone(): string {\n return this.dateTime.zoneName as string;\n }\n\n /**\n * 期間を加算した結果を返す\n * 負の値を指定すると減算になる\n *\n * @param {Duration} duration\n * @returns {ZonedDateTime}\n */\n public plus(duration: Duration): ZonedDateTime {\n return new ZonedDateTime(this.dateTime.plus(duration));\n }\n\n /**\n * 期間を減算した結果を返す\n *\n * @param {Duration} duration\n * @returns {ZonedDateTime}\n */\n public minus(duration: Duration): ZonedDateTime {\n return new ZonedDateTime(this.dateTime.minus(duration));\n }\n\n /**\n * 指定した単位の最初の時点に切り捨てた結果を返す(month なら月初の00:00:00.000)\n * week は月曜始まりで切り捨てる\n *\n * @param {DateUnit} unit\n * @returns {ZonedDateTime}\n */\n public startOf(unit: DateUnit): ZonedDateTime {\n return new ZonedDateTime(this.dateTime.startOf(unit));\n }\n\n /**\n * 指定した単位の最後の時点に切り上げた結果を返す(month なら月末の23:59:59.999)\n * week は日曜終わりで切り上げる\n *\n * @param {DateUnit} unit\n * @returns {ZonedDateTime}\n */\n public endOf(unit: DateUnit): ZonedDateTime {\n return new ZonedDateTime(this.dateTime.endOf(unit));\n }\n\n /**\n * 指定した要素を変更した結果を返す\n * 範囲外の値や整数でない値を指定した場合は RangeError をスローする\n * day を指定せずに year / month を変更し、日がその月に無い場合は月末日にする(1月31日に { month: 2 } なら2月末日)\n *\n * @param {ZonedDateTimeFields} fields\n * @returns {ZonedDateTime}\n */\n public set(fields: ZonedDateTimeFields): ZonedDateTime {\n assertField('month', fields.month, 1, 12);\n assertField('hour', fields.hour, 0, 23);\n assertField('minute', fields.minute, 0, 59);\n assertField('second', fields.second, 0, 59);\n assertField('millisecond', fields.millisecond, 0, 999);\n // day の上限は変更後の年月で決まる\n const daysInMonth = this.dateTime.set({\n year: fields.year ?? this.year,\n month: fields.month ?? this.month,\n day: 1\n }).daysInMonth as number;\n assertField('day', fields.day, 1, daysInMonth);\n return new ZonedDateTime(this.dateTime.set(fields));\n }\n\n /**\n * 同じ時刻を別のタイムゾーンで表した結果を返す\n * タイムゾーンの指定が不正な場合は RangeError をスローする\n *\n * @param {string} timezone IANA名\n * @returns {ZonedDateTime}\n */\n public setZone(timezone: string): ZonedDateTime {\n const d = this.dateTime.setZone(timezone);\n assertZone(d);\n return new ZonedDateTime(d);\n }\n\n /**\n * 自身 − other を unit の単位で返す\n * 両方を自身のタイムゾーンで unit の始まりに切り捨ててから差を取るため、暦の上での差になる(23:00 と翌 01:00 の days は 1)\n *\n * @param {ZonedDateTime} other\n * @param {TimeUnit} unit\n * @returns {number}\n */\n public diff(other: ZonedDateTime, unit: TimeUnit): number {\n // 'days' → 'day' のように切り捨ての単位にする\n const dateUnit = unit.slice(0, -1) as DateUnit;\n const target = other.dateTime.setZone(this.dateTime.zone);\n return this.dateTime.startOf(dateUnit).diff(target.startOf(dateUnit), unit).get(unit);\n }\n\n /**\n * 時刻を比較する。タイムゾーンが異なっていても同じ時刻なら等しい\n *\n * @param {ZonedDateTime} other\n * @returns {-1 | 0 | 1} 自身が前なら-1、等しければ0、後なら1\n */\n public compareTo(other: ZonedDateTime): -1 | 0 | 1 {\n return Math.sign(this.toMillis() - other.toMillis()) as -1 | 0 | 1;\n }\n\n /**\n * 同じ時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public eq(other: ZonedDateTime): boolean {\n return this.compareTo(other) === 0;\n }\n\n /**\n * 自身が前の時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public lt(other: ZonedDateTime): boolean {\n return this.compareTo(other) < 0;\n }\n\n /**\n * 自身が前か同じ時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public lte(other: ZonedDateTime): boolean {\n return this.compareTo(other) <= 0;\n }\n\n /**\n * 自身が後の時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public gt(other: ZonedDateTime): boolean {\n return 0 < this.compareTo(other);\n }\n\n /**\n * 自身が後か同じ時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public gte(other: ZonedDateTime): boolean {\n return 0 <= this.compareTo(other);\n }\n\n /**\n * 自身のタイムゾーンで、指定した書式の文字列にする\n *\n * @param {string} outputFormat\n * @param {ZonedDateTimeFormatOptions} [options]\n * @returns {string}\n */\n public format(outputFormat: string, options?: ZonedDateTimeFormatOptions): string {\n return this.dateTime.toFormat(outputFormat, { locale: options?.locale ?? DEFAULT_LOCALE });\n }\n\n /**\n * 自身のタイムゾーンで、ISO形式の文字列にする\n *\n * @returns {string}\n */\n public toISO(): string {\n return this.dateTime.toISO() as string;\n }\n\n /**\n * Date に変換する\n *\n * @returns {Date}\n */\n public toDate(): Date {\n return this.dateTime.toJSDate();\n }\n\n /**\n * epoch ミリ秒に変換する\n *\n * @returns {number}\n */\n public toMillis(): number {\n return this.dateTime.toMillis();\n }\n\n /**\n * 自身のタイムゾーンで、ISO形式の文字列にする\n *\n * @returns {string}\n */\n public toString(): string {\n return this.toISO();\n }\n}\n"],"names":["DEFAULT_TIMEZONE","DEFAULT_LOCALE","assertZone","d","assertField","name","value","min","max","ZonedDateTime","dateTime","timezone","DateTime","options","zone","locale","formats","format","parsed","duration","unit","fields","daysInMonth","other","dateUnit","target","outputFormat"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"zoned-date-time.js","sources":["../src/zoned-date-time.ts"],"sourcesContent":["/**\n * このクラス ZonedDateTime の役割は、日時演算の実体としての luxon を内部に閉じ込め、利用者側に露出させないことにある\n */\nimport { DateTime } from 'luxon';\nimport type { DateInput, DateUnit, Duration, ParseDateOptions, TimeUnit } from './date-util';\n\n/** set で変更する日時の要素。month は1〜12 */\nexport interface ZonedDateTimeFields {\n year?: number;\n month?: number;\n day?: number;\n hour?: number;\n minute?: number;\n second?: number;\n millisecond?: number;\n}\n\n/**\n * 日時を文字列にするときのオプション\n */\nexport interface ZonedDateTimeFormatOptions {\n /** 月名・曜日名に使うロケール。既定は 'en-US' */\n locale?: string;\n}\n\nconst DEFAULT_TIMEZONE = 'UTC';\n\nconst DEFAULT_LOCALE = 'en-US';\n\n/**\n * タイムゾーンの指定が不正な場合は、日時の不正とは区別して例外にする\n */\nconst assertZone = (d: DateTime): void => {\n if (!d.isValid && d.invalidReason === 'unsupported zone') {\n throw new RangeError(d.invalidExplanation ?? d.invalidReason);\n }\n};\n\n/**\n * set に渡された要素が min〜max の整数であることを確かめる\n */\nconst assertField = (name: keyof ZonedDateTimeFields, value: number | undefined, min: number, max: number): void => {\n if (value === undefined) {\n return;\n }\n if (!Number.isInteger(value) || value < min || max < value) {\n throw new RangeError(`${name} must be an integer from ${min} to ${max}: ${value}`);\n }\n};\n\n/**\n * 日時を表す不変オブジェクト\n * 演算メソッドは自身を変更せず、結果を新しいインスタンスで返す\n * インスタンスごとにタイムゾーンを持ち、startOf / endOf / set や各要素の参照はそのタイムゾーンで計算する\n */\nexport class ZonedDateTime {\n /**\n * 日時演算インスタンス\n */\n private dateTime: DateTime;\n\n private constructor(dateTime: DateTime) {\n this.dateTime = dateTime;\n }\n\n /**\n * 現在時刻を返す\n * タイムゾーンの指定が不正な場合は RangeError をスローする\n *\n * @param {string} [timezone] IANA名。既定は 'UTC'\n * @returns {ZonedDateTime}\n */\n public static now(timezone: string = DEFAULT_TIMEZONE): ZonedDateTime {\n const d = DateTime.now().setZone(timezone);\n assertZone(d);\n return new ZonedDateTime(d);\n }\n\n /**\n * 値を日時として解釈する\n * 生成したインスタンスは inputTimezone のタイムゾーンを持つ\n * ZonedDateTime を渡した場合、inputTimezone を省略すると渡した ZonedDateTime のタイムゾーンを引き継ぐ\n * duration / startOf / endOf はそのタイムゾーンで計算する\n * 解釈できない値、null / undefined / 空文字は null を返す。タイムゾーンの指定が不正な場合は RangeError をスローする\n *\n * @param {DateInput} value\n * @param {ParseDateOptions} [options]\n * @returns {ZonedDateTime | null}\n */\n public static parse(value: DateInput, options?: ParseDateOptions): ZonedDateTime | null {\n if (value == null || value === '') {\n return null;\n }\n const zone = options?.inputTimezone ?? DEFAULT_TIMEZONE;\n let d: DateTime | null = null;\n if (value instanceof ZonedDateTime) {\n d = options?.inputTimezone ? value.dateTime.setZone(options.inputTimezone) : value.dateTime;\n } else if (value instanceof Date) {\n d = DateTime.fromJSDate(value, { zone: zone });\n } else if (typeof value === 'number') {\n d = Number.isFinite(value) ? DateTime.fromMillis(value, { zone: zone }) : null;\n } else {\n const locale = options?.locale ?? DEFAULT_LOCALE;\n const formats = options?.inputFormat ? [options.inputFormat].flat() : [];\n for (const format of formats) {\n const parsed = DateTime.fromFormat(value, format, {\n zone: zone,\n locale: locale\n });\n assertZone(parsed);\n if (parsed.isValid) {\n d = parsed;\n break;\n }\n }\n if (d == null) {\n d = DateTime.fromISO(value, { zone: zone });\n }\n }\n if (d == null) {\n return null;\n }\n assertZone(d);\n if (!d.isValid) {\n return null;\n }\n if (options?.duration) {\n d = d.plus(options.duration);\n }\n if (options?.startOf) {\n d = d.startOf(options.startOf);\n }\n if (options?.endOf) {\n d = d.endOf(options.endOf);\n }\n return new ZonedDateTime(d);\n }\n\n /** 年 */\n public get year(): number {\n return this.dateTime.year;\n }\n\n /** 月(1〜12) */\n public get month(): number {\n return this.dateTime.month;\n }\n\n /** 日 */\n public get day(): number {\n return this.dateTime.day;\n }\n\n /** 時 */\n public get hour(): number {\n return this.dateTime.hour;\n }\n\n /** 分 */\n public get minute(): number {\n return this.dateTime.minute;\n }\n\n /** 秒 */\n public get second(): number {\n return this.dateTime.second;\n }\n\n /** ミリ秒 */\n public get millisecond(): number {\n return this.dateTime.millisecond;\n }\n\n /** 曜日。月曜が1、日曜が7 */\n public get weekday(): number {\n return this.dateTime.weekday;\n }\n\n /** その月の日数 */\n public get daysInMonth(): number {\n return this.dateTime.daysInMonth as number;\n }\n\n /** 夏時間の期間中か */\n public get isInDST(): boolean {\n return this.dateTime.isInDST;\n }\n\n /** タイムゾーン(IANA名) */\n public get timezone(): string {\n return this.dateTime.zoneName as string;\n }\n\n /**\n * 期間を加算した結果を返す\n * 負の値を指定すると減算になる\n *\n * @param {Duration} duration\n * @returns {ZonedDateTime}\n */\n public plus(duration: Duration): ZonedDateTime {\n return new ZonedDateTime(this.dateTime.plus(duration));\n }\n\n /**\n * 期間を減算した結果を返す\n *\n * @param {Duration} duration\n * @returns {ZonedDateTime}\n */\n public minus(duration: Duration): ZonedDateTime {\n return new ZonedDateTime(this.dateTime.minus(duration));\n }\n\n /**\n * 指定した単位の最初の時点に切り捨てた結果を返す(month なら月初の00:00:00.000)\n * week は月曜始まりで切り捨てる\n *\n * @param {DateUnit} unit\n * @returns {ZonedDateTime}\n */\n public startOf(unit: DateUnit): ZonedDateTime {\n return new ZonedDateTime(this.dateTime.startOf(unit));\n }\n\n /**\n * 指定した単位の最後の時点に切り上げた結果を返す(month なら月末の23:59:59.999)\n * week は日曜終わりで切り上げる\n *\n * @param {DateUnit} unit\n * @returns {ZonedDateTime}\n */\n public endOf(unit: DateUnit): ZonedDateTime {\n return new ZonedDateTime(this.dateTime.endOf(unit));\n }\n\n /**\n * 指定した要素を変更した結果を返す\n * 範囲外の値や整数でない値を指定した場合は RangeError をスローする\n * day を指定せずに year / month を変更し、日がその月に無い場合は月末日にする(1月31日に { month: 2 } なら2月末日)\n *\n * @param {ZonedDateTimeFields} fields\n * @returns {ZonedDateTime}\n */\n public set(fields: ZonedDateTimeFields): ZonedDateTime {\n assertField('month', fields.month, 1, 12);\n assertField('hour', fields.hour, 0, 23);\n assertField('minute', fields.minute, 0, 59);\n assertField('second', fields.second, 0, 59);\n assertField('millisecond', fields.millisecond, 0, 999);\n // day の上限は変更後の年月で決まる\n const daysInMonth = this.dateTime.set({\n year: fields.year ?? this.year,\n month: fields.month ?? this.month,\n day: 1\n }).daysInMonth as number;\n assertField('day', fields.day, 1, daysInMonth);\n return new ZonedDateTime(this.dateTime.set(fields));\n }\n\n /**\n * 同じ時刻を別のタイムゾーンで表した結果を返す\n * タイムゾーンの指定が不正な場合は RangeError をスローする\n *\n * @param {string} timezone IANA名\n * @returns {ZonedDateTime}\n */\n public setZone(timezone: string): ZonedDateTime {\n const d = this.dateTime.setZone(timezone);\n assertZone(d);\n return new ZonedDateTime(d);\n }\n\n /**\n * 自身 − other を unit の単位で返す\n * 両方を自身のタイムゾーンで unit の始まりに切り捨ててから差を取るため、暦の上での差になる(23:00 と翌 01:00 の days は 1)\n *\n * @param {ZonedDateTime} other\n * @param {TimeUnit} unit\n * @returns {number}\n */\n public diff(other: ZonedDateTime, unit: TimeUnit): number {\n // 'days' → 'day' のように切り捨ての単位にする\n const dateUnit = unit.slice(0, -1) as DateUnit;\n const target = other.dateTime.setZone(this.dateTime.zone);\n return this.dateTime.startOf(dateUnit).diff(target.startOf(dateUnit), unit).get(unit);\n }\n\n /**\n * 時刻を比較する。タイムゾーンが異なっていても同じ時刻なら等しい\n *\n * @param {ZonedDateTime} other\n * @returns {-1 | 0 | 1} 自身が前なら-1、等しければ0、後なら1\n */\n public compareTo(other: ZonedDateTime): -1 | 0 | 1 {\n return Math.sign(this.toMillis() - other.toMillis()) as -1 | 0 | 1;\n }\n\n /**\n * 同じ時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public eq(other: ZonedDateTime): boolean {\n return this.compareTo(other) === 0;\n }\n\n /**\n * 自身が前の時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public lt(other: ZonedDateTime): boolean {\n return this.compareTo(other) < 0;\n }\n\n /**\n * 自身が前か同じ時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public lte(other: ZonedDateTime): boolean {\n return this.compareTo(other) <= 0;\n }\n\n /**\n * 自身が後の時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public gt(other: ZonedDateTime): boolean {\n return 0 < this.compareTo(other);\n }\n\n /**\n * 自身が後か同じ時刻か判定する\n *\n * @param {ZonedDateTime} other\n * @returns {boolean}\n */\n public gte(other: ZonedDateTime): boolean {\n return 0 <= this.compareTo(other);\n }\n\n /**\n * 自身のタイムゾーンで、指定した書式の文字列にする\n *\n * @param {string} outputFormat\n * @param {ZonedDateTimeFormatOptions} [options]\n * @returns {string}\n */\n public format(outputFormat: string, options?: ZonedDateTimeFormatOptions): string {\n return this.dateTime.toFormat(outputFormat, { locale: options?.locale ?? DEFAULT_LOCALE });\n }\n\n /**\n * 自身のタイムゾーンで、ISO形式の文字列にする\n *\n * @returns {string}\n */\n public toISO(): string {\n return this.dateTime.toISO() as string;\n }\n\n /**\n * Date に変換する\n *\n * @returns {Date}\n */\n public toDate(): Date {\n return this.dateTime.toJSDate();\n }\n\n /**\n * epoch ミリ秒に変換する\n *\n * @returns {number}\n */\n public toMillis(): number {\n return this.dateTime.toMillis();\n }\n\n /**\n * 自身のタイムゾーンで、ISO形式の文字列にする\n *\n * @returns {string}\n */\n public toString(): string {\n return this.toISO();\n }\n\n /**\n * epoch ミリ秒を返す。< や > で時刻の前後を比較できるようにするため\n *\n * @returns {number}\n */\n public valueOf(): number {\n return this.toMillis();\n }\n\n /**\n * プリミティブ値への変換\n * 数値が必要な場面(< や > による比較)では epoch ミリ秒、それ以外(+ による文字列の連結など)ではISO形式の文字列にする\n *\n * @param {string} hint\n * @returns {number | string}\n */\n public [Symbol.toPrimitive](hint: 'number' | 'string' | 'default'): number | string {\n return hint === 'number' ? this.toMillis() : this.toISO();\n }\n}\n"],"names":["DEFAULT_TIMEZONE","DEFAULT_LOCALE","assertZone","d","assertField","name","value","min","max","ZonedDateTime","dateTime","timezone","DateTime","options","zone","locale","formats","format","parsed","duration","unit","fields","daysInMonth","other","dateUnit","target","outputFormat","hint"],"mappings":"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"}
|
package/package.json
CHANGED
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/zoned-date-time.ts
CHANGED
|
@@ -392,4 +392,24 @@ export class ZonedDateTime {
|
|
|
392
392
|
public toString(): string {
|
|
393
393
|
return this.toISO();
|
|
394
394
|
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* epoch ミリ秒を返す。< や > で時刻の前後を比較できるようにするため
|
|
398
|
+
*
|
|
399
|
+
* @returns {number}
|
|
400
|
+
*/
|
|
401
|
+
public valueOf(): number {
|
|
402
|
+
return this.toMillis();
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* プリミティブ値への変換
|
|
407
|
+
* 数値が必要な場面(< や > による比較)では epoch ミリ秒、それ以外(+ による文字列の連結など)ではISO形式の文字列にする
|
|
408
|
+
*
|
|
409
|
+
* @param {string} hint
|
|
410
|
+
* @returns {number | string}
|
|
411
|
+
*/
|
|
412
|
+
public [Symbol.toPrimitive](hint: 'number' | 'string' | 'default'): number | string {
|
|
413
|
+
return hint === 'number' ? this.toMillis() : this.toISO();
|
|
414
|
+
}
|
|
395
415
|
}
|
|
@@ -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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"}
|