diff --git a/CHANGELOG.md b/CHANGELOG.md index ecb691b..acb659b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## 0.7.3 +- Fix folder creation for certain operating system + - Create 0-length "files" for each directory specified with "object" syntax" + - Support empty folders + - Add options for folders +- Fix minification in SWC + - Remove instanceof, no-whitespace assumptions in async functions ## 0.7.2 - Fixed TypeScript typing for errors when using `strictNullChecks` - Fixed failure to compress files above 64kB with `{ level: 0 }` diff --git a/README.md b/README.md index 73ed3e5..8507145 100644 --- a/README.md +++ b/README.md @@ -243,26 +243,38 @@ const zipped = fflate.zipSync({ 'dir1': { 'nested': { // You can use Unicode in filenames - '你好.txt': strToU8('Hey there!') + '你好.txt': fflate.strToU8('Hey there!') }, // You can also manually write out a directory path 'other/tmp.txt': new Uint8Array([97, 98, 99, 100]) }, + // You can also provide compression options 'massiveImage.bmp': [aMassiveFile, { level: 9, - mem: 12, - // ZIP-specific: mtime works here too, defaults to current time - mtime: new Date('10/20/2020') + mem: 12 }], // PNG is pre-compressed; no need to waste time - 'superTinyFile.png': [aPNGFile, { level: 0 }] + 'superTinyFile.png': [aPNGFile, { level: 0 }], + + // Directories take options too + 'exec': [{ + 'hello.sh': [fflate.strToU8('echo hello world'), { + // ZIP only: Set the operating system to Unix + os: 3, + // ZIP only: Make this file executable on Unix + attrs: 0o755 << 16 + }] + }, { + // ZIP and GZIP support mtime (defaults to current time) + mtime: new Date('10/20/2020') + }] }, { // These options are the defaults for all files, but file-specific // options take precedence. level: 1, - // Obfuscate mtime by default - mtime: 0 + // Obfuscate last modified time by default + mtime: new Date('1/1/1980') }); // If you write the zipped data to myzip.zip and unzip, the folder @@ -442,8 +454,7 @@ gzs.terminate(); zip({ f1: aMassiveFile, 'f2.txt': anotherMassiveFile }, { // The options object is still optional, you can still do just // zip(archive, callback) - level: 6, - mtime: 0 + level: 6 }, (err, data) => { // Save the ZIP file }); diff --git a/docs/README.md b/docs/README.md index 1c90039..77338b9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -113,7 +113,7 @@ ___ ### AsyncZippableFile -Ƭ **AsyncZippableFile**: Uint8Array \| [] +Ƭ **AsyncZippableFile**: Uint8Array \| [AsyncZippable](interfaces/asynczippable.md) \| [] A file that can be used to asynchronously create a ZIP archive @@ -191,7 +191,7 @@ ___ ### ZippableFile -Ƭ **ZippableFile**: Uint8Array \| [] +Ƭ **ZippableFile**: Uint8Array \| [Zippable](interfaces/zippable.md) \| [] A file that can be used to create a ZIP archive diff --git a/docs/interfaces/asynczipoptions.md b/docs/interfaces/asynczipoptions.md index c17a66d..92234c7 100644 --- a/docs/interfaces/asynczipoptions.md +++ b/docs/interfaces/asynczipoptions.md @@ -47,7 +47,9 @@ rwx = user permissions, rwx = group permissions, rwx = other permissions A = archive, D = directory, V = volume label, S = system file, H = hidden, R = read-only -If you want to set the Unix permissions, for instance, just bit shift by 16, e.g. 0644 << 16 +If you want to set the Unix permissions, for instance, just bit shift by 16, e.g. 0o644 << 16. +Note that attributes usually only work in conjunction with the `os` setting: you must use +`os` = 3 (Unix) if you want to set Unix permissions ___ @@ -145,4 +147,4 @@ ___ The operating system of origin for this file. The value is defined by PKZIP's APPNOTE.txt, section 4.4.2.2. For example, 0 (the default) -is MS/DOS, 3 is UNIX, 19 is macOS. +is MS/DOS, 3 is Unix, 19 is macOS. diff --git a/docs/interfaces/asynczippable.md b/docs/interfaces/asynczippable.md index a90147d..0ba2443 100644 --- a/docs/interfaces/asynczippable.md +++ b/docs/interfaces/asynczippable.md @@ -8,6 +8,6 @@ The complete directory structure of an asynchronously ZIPpable archive ## Indexable -▪ [path: string]: [AsyncZippable](asynczippable.md) \| [AsyncZippableFile](../README.md#asynczippablefile) +▪ [path: string]: [AsyncZippableFile](../README.md#asynczippablefile) The complete directory structure of an asynchronously ZIPpable archive diff --git a/docs/interfaces/zipattributes.md b/docs/interfaces/zipattributes.md index adf55bc..6170bd0 100644 --- a/docs/interfaces/zipattributes.md +++ b/docs/interfaces/zipattributes.md @@ -44,7 +44,9 @@ rwx = user permissions, rwx = group permissions, rwx = other permissions A = archive, D = directory, V = volume label, S = system file, H = hidden, R = read-only -If you want to set the Unix permissions, for instance, just bit shift by 16, e.g. 0644 << 16 +If you want to set the Unix permissions, for instance, just bit shift by 16, e.g. 0o644 << 16. +Note that attributes usually only work in conjunction with the `os` setting: you must use +`os` = 3 (Unix) if you want to set Unix permissions ___ @@ -85,4 +87,4 @@ ___ The operating system of origin for this file. The value is defined by PKZIP's APPNOTE.txt, section 4.4.2.2. For example, 0 (the default) -is MS/DOS, 3 is UNIX, 19 is macOS. +is MS/DOS, 3 is Unix, 19 is macOS. diff --git a/docs/interfaces/zipinputfile.md b/docs/interfaces/zipinputfile.md index 44bf3a9..3d0e649 100644 --- a/docs/interfaces/zipinputfile.md +++ b/docs/interfaces/zipinputfile.md @@ -55,7 +55,9 @@ rwx = user permissions, rwx = group permissions, rwx = other permissions A = archive, D = directory, V = volume label, S = system file, H = hidden, R = read-only -If you want to set the Unix permissions, for instance, just bit shift by 16, e.g. 0644 << 16 +If you want to set the Unix permissions, for instance, just bit shift by 16, e.g. 0o644 << 16. +Note that attributes usually only work in conjunction with the `os` setting: you must use +`os` = 3 (Unix) if you want to set Unix permissions ___ @@ -166,7 +168,7 @@ ___ The operating system of origin for this file. The value is defined by PKZIP's APPNOTE.txt, section 4.4.2.2. For example, 0 (the default) -is MS/DOS, 3 is UNIX, 19 is macOS. +is MS/DOS, 3 is Unix, 19 is macOS. ___ diff --git a/docs/interfaces/zipoptions.md b/docs/interfaces/zipoptions.md index 4f7aceb..8e4262a 100644 --- a/docs/interfaces/zipoptions.md +++ b/docs/interfaces/zipoptions.md @@ -46,7 +46,9 @@ rwx = user permissions, rwx = group permissions, rwx = other permissions A = archive, D = directory, V = volume label, S = system file, H = hidden, R = read-only -If you want to set the Unix permissions, for instance, just bit shift by 16, e.g. 0644 << 16 +If you want to set the Unix permissions, for instance, just bit shift by 16, e.g. 0o644 << 16. +Note that attributes usually only work in conjunction with the `os` setting: you must use +`os` = 3 (Unix) if you want to set Unix permissions ___ @@ -133,4 +135,4 @@ ___ The operating system of origin for this file. The value is defined by PKZIP's APPNOTE.txt, section 4.4.2.2. For example, 0 (the default) -is MS/DOS, 3 is UNIX, 19 is macOS. +is MS/DOS, 3 is Unix, 19 is macOS. diff --git a/docs/interfaces/zippable.md b/docs/interfaces/zippable.md index feecac1..63aadf1 100644 --- a/docs/interfaces/zippable.md +++ b/docs/interfaces/zippable.md @@ -8,6 +8,6 @@ The complete directory structure of a ZIPpable archive ## Indexable -▪ [path: string]: [Zippable](zippable.md) \| [ZippableFile](../README.md#zippablefile) +▪ [path: string]: [ZippableFile](../README.md#zippablefile) The complete directory structure of a ZIPpable archive diff --git a/package.json b/package.json index 40e552c..51bf514 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fflate", - "version": "0.7.2", + "version": "0.7.3", "description": "High performance (de)compression in an 8kB package", "main": "./lib/index.cjs", "module": "./esm/browser.js", diff --git a/src/index.ts b/src/index.ts index cf86e02..651d91d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -151,7 +151,7 @@ const slc = (v: T, s: number, if (s == null || s < 0) s = 0; if (e == null || e > v.length) e = v.length; // can't use .constructor in case user-supplied - const n = new (v instanceof u16 ? u16 : v instanceof u32 ? u32 : u8)(e - s) as T; + const n = new (v.BYTES_PER_ELEMENT == 2 ? u16 : v.BYTES_PER_ELEMENT == 4 ? u32 : u8)(e - s) as T; n.set(v.subarray(s, e)); return n; } @@ -930,7 +930,7 @@ const mrg = (a: A, b: B) => { const wcln = (fn: () => unknown[], fnStr: string, td: Record) => { const dt = fn(); const st = fn.toString(); - const ks = st.slice(st.indexOf('[') + 1, st.lastIndexOf(']')).replace(/ /g, '').split(','); + const ks = st.slice(st.indexOf('[') + 1, st.lastIndexOf(']')).replace(/\s+/g, '').split(','); for (let i = 0; i < dt.length; ++i) { let v = dt[i], k = ks[i]; if (typeof v == 'function') { @@ -958,7 +958,9 @@ const ch: CachedWorker[] = []; const cbfs = (v: Record) => { const tl: ArrayBuffer[] = []; for (const k in v) { - if (v[k] instanceof u8 || v[k] instanceof u16 || v[k] instanceof u32) tl.push((v[k] = new (v[k].constructor as typeof u8)(v[k] as Uint8Array)).buffer); + if ((v[k] as Uint8Array).buffer) { + tl.push((v[k] = new (v[k].constructor as typeof u8)(v[k] as Uint8Array)).buffer); + } } return tl; } @@ -977,7 +979,7 @@ const wrkr = (fns: (() => unknown[])[], init: (ev: MessageEvent) => voi // base async inflate fn const bInflt = () => [u8, u16, u32, fleb, fdeb, clim, fl, fd, flrm, fdrm, rev, ec, hMap, max, bits, bits16, shft, slc, err, inflt, inflateSync, pbf, gu8]; -const bDflt = () => [u8, u16, u32, fleb, fdeb, clim, revfl, revfd, flm, flt, fdm, fdt, rev, deo, et, hMap, wbits, wbits16, hTree, ln, lc, clen, wfblk, wblk, shft, slc, dflt, dopt, deflateSync, pbf] +const bDflt = () => [u8, u16, u32, fleb, fdeb, clim, revfl, revfd, flm, flt, fdm, fdt, rev, deo, et, hMap, wbits, wbits16, hTree, ln, lc, clen, wfblk, wblk, shft, slc, dflt, dopt, deflateSync, pbf]; // gzip extra const gze = () => [gzh, gzhl, wbytes, crc, crct]; @@ -1967,7 +1969,7 @@ export interface ZipAttributes { /** * The operating system of origin for this file. The value is defined * by PKZIP's APPNOTE.txt, section 4.4.2.2. For example, 0 (the default) - * is MS/DOS, 3 is UNIX, 19 is macOS. + * is MS/DOS, 3 is Unix, 19 is macOS. */ os?: number; @@ -1988,7 +1990,9 @@ export interface ZipAttributes { * * A = archive, D = directory, V = volume label, S = system file, H = hidden, R = read-only * - * If you want to set the Unix permissions, for instance, just bit shift by 16, e.g. 0644 << 16 + * If you want to set the Unix permissions, for instance, just bit shift by 16, e.g. 0o644 << 16. + * Note that attributes usually only work in conjunction with the `os` setting: you must use + * `os` = 3 (Unix) if you want to set Unix permissions */ attrs?: number; @@ -2043,25 +2047,25 @@ export interface AsyncUnzipOptions extends UnzipOptions {} /** * A file that can be used to create a ZIP archive */ -export type ZippableFile = Uint8Array | [Uint8Array, ZipOptions]; +export type ZippableFile = Uint8Array | Zippable | [Uint8Array | Zippable, ZipOptions]; /** * A file that can be used to asynchronously create a ZIP archive */ -export type AsyncZippableFile = Uint8Array | [Uint8Array, AsyncZipOptions]; +export type AsyncZippableFile = Uint8Array | AsyncZippable | [Uint8Array | AsyncZippable, AsyncZipOptions] /** * The complete directory structure of a ZIPpable archive */ export interface Zippable { - [path: string]: Zippable | ZippableFile; + [path: string]: ZippableFile; } /** * The complete directory structure of an asynchronously ZIPpable archive */ export interface AsyncZippable { - [path: string]: AsyncZippable | AsyncZippableFile; + [path: string]: AsyncZippableFile; } /** @@ -2096,12 +2100,15 @@ export type UnzipFileHandler = (file: UnzipFile) => void; type FlatZippable = Record; // flatten a directory structure -const fltn = (d: A extends true ? AsyncZippable : Zippable, p: string, t: FlatZippable, o: ZipOptions) => { +const fltn = (d: D, p: string, t: FlatZippable, o: ZipOptions) => { for (const k in d) { - const val = d[k], n = p + k; - if (val instanceof u8) t[n] = [val, o] as unknown as FlatZippable[string]; - else if (Array.isArray(val)) t[n] = [val[0], mrg(o, val[1])] as FlatZippable[string]; - else fltn(val as unknown as (A extends true ? AsyncZippable : Zippable), n + '/', t, o); + let val = d[k], n = p + k, op = o; + if (Array.isArray(val)) op = mrg(o, val[1]), val = val[0] as unknown as D[Extract]; + if (val instanceof u8) t[n] = [val, op] as unknown as FlatZippable[string]; + else { + t[n += '/'] = [new u8(0), op] as unknown as FlatZippable[string]; + fltn(val as unknown as (A extends true ? AsyncZippable : Zippable), n, t, o); + } } }