From 0701f308dbdc4ca220c3af5685eec5c80369a3b6 Mon Sep 17 00:00:00 2001 From: mahsashadi <70196035+mahsashadi@users.noreply.github.com> Date: Sun, 29 Aug 2021 09:19:56 +0430 Subject: [PATCH 01/12] Fix unused options in readdir system VFS adapter --- src/adapters/vfs/system.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/adapters/vfs/system.js b/src/adapters/vfs/system.js index ceee251..16dcfd9 100644 --- a/src/adapters/vfs/system.js +++ b/src/adapters/vfs/system.js @@ -59,7 +59,7 @@ const methods = (core, request) => { return { readdir: ({path}, options) => request('readdir', { path, - options: {} + options, }, 'json').then(({body}) => body), readfile: ({path}, type, options) => From 12a3178701ae3e611a5de12371ba497fecab5a28 Mon Sep 17 00:00:00 2001 From: mahsashadi <70196035+mahsashadi@users.noreply.github.com> Date: Sun, 29 Aug 2021 09:26:23 +0430 Subject: [PATCH 02/12] Improve serialization of VFS URL query parameters --- src/utils/fetch.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/utils/fetch.js b/src/utils/fetch.js index 46508e9..343797b 100644 --- a/src/utils/fetch.js +++ b/src/utils/fetch.js @@ -31,10 +31,16 @@ /* * Creates URL request path */ -const encodeQueryData = data => Object.keys(data) - .filter(k => typeof data[k] !== 'object') - .map(k => encodeURIComponent(k) + '=' + encodeURIComponent(data[k])) - .join('&'); +const encodeQueryData = (data, nesting = '') => { + const pairs = Object.entries(data).map(([key, val]) => { + if (typeof val === 'object') { + return encodeQueryData(val, nesting + `${key}.`); + } else { + return encodeURIComponent(nesting + key) + '=' + encodeURIComponent(val); + } + }); + return pairs.join('&'); +}; const bodyTypes = [ window.ArrayBuffer, From 8643d31082fa2e30e7378262ecd5aafd9d551fca Mon Sep 17 00:00:00 2001 From: mahsa shadi Date: Sat, 4 Sep 2021 10:20:01 +0430 Subject: [PATCH 03/12] Export encodeQueryData and add fetch tests --- __tests__/utils/fetch.js | 29 +++++++++++++++++++++++++++++ src/utils/fetch.js | 4 ++-- 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 __tests__/utils/fetch.js diff --git a/__tests__/utils/fetch.js b/__tests__/utils/fetch.js new file mode 100644 index 0000000..67c947e --- /dev/null +++ b/__tests__/utils/fetch.js @@ -0,0 +1,29 @@ +import * as fetch from '../../src/utils/fetch'; + +describe('utils.fetch#encodeQueryData', () => { + test('should create valid query string', () => { + const result1 = fetch.encodeQueryData({ + a: 1, + b: true, + c: null, + d: 'foo' + }); + + const result2 = fetch.encodeQueryData({ + a: { + a: 1, + b: true, + c: null, + d: 'foo' + }, + b: { + c: { + d: 'foo' + } + } + }); + + expect(result1).toEqual('a=1&b=true&c=null&d=foo'); + expect(result2).toEqual('a.a=1&a.b=true&a.c=null&a.d=foo&b.c.d=foo'); + }); +}); \ No newline at end of file diff --git a/src/utils/fetch.js b/src/utils/fetch.js index 343797b..1078483 100644 --- a/src/utils/fetch.js +++ b/src/utils/fetch.js @@ -31,9 +31,9 @@ /* * Creates URL request path */ -const encodeQueryData = (data, nesting = '') => { +export const encodeQueryData = (data, nesting = '') => { const pairs = Object.entries(data).map(([key, val]) => { - if (typeof val === 'object') { + if (typeof val === 'object' && val !== null) { return encodeQueryData(val, nesting + `${key}.`); } else { return encodeURIComponent(nesting + key) + '=' + encodeURIComponent(val); From e89d5f9474d4cf36b5e349cad1cabcae036657bc Mon Sep 17 00:00:00 2001 From: mahsa shadi Date: Mon, 6 Sep 2021 12:09:16 +0430 Subject: [PATCH 04/12] Solve the preservation of types in encodeQueryData --- __tests__/utils/fetch.js | 10 ++++++---- src/utils/fetch.js | 12 +++++++++++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/__tests__/utils/fetch.js b/__tests__/utils/fetch.js index 67c947e..f6d5b16 100644 --- a/__tests__/utils/fetch.js +++ b/__tests__/utils/fetch.js @@ -6,7 +6,8 @@ describe('utils.fetch#encodeQueryData', () => { a: 1, b: true, c: null, - d: 'foo' + d: 'foo', + e: undefined }); const result2 = fetch.encodeQueryData({ @@ -14,7 +15,8 @@ describe('utils.fetch#encodeQueryData', () => { a: 1, b: true, c: null, - d: 'foo' + d: 'foo', + e: undefined }, b: { c: { @@ -23,7 +25,7 @@ describe('utils.fetch#encodeQueryData', () => { } }); - expect(result1).toEqual('a=1&b=true&c=null&d=foo'); - expect(result2).toEqual('a.a=1&a.b=true&a.c=null&a.d=foo&b.c.d=foo'); + expect(result1).toEqual('a.i=1&b.b=true&c.n=null&d.s=foo&e.u=undefined'); + expect(result2).toEqual('a.a.i=1&a.b.b=true&a.c.n=null&a.d.s=foo&a.e.u=undefined&b.c.d.s=foo'); }); }); \ No newline at end of file diff --git a/src/utils/fetch.js b/src/utils/fetch.js index 1078483..1dc2ee9 100644 --- a/src/utils/fetch.js +++ b/src/utils/fetch.js @@ -28,15 +28,25 @@ * @license Simplified BSD License */ +const typesToken = { + string : 's', + number : 'i', + boolean : 'b', + undefined: 'u', + object: 'n' +}; + /* * Creates URL request path */ export const encodeQueryData = (data, nesting = '') => { + let type; const pairs = Object.entries(data).map(([key, val]) => { if (typeof val === 'object' && val !== null) { return encodeQueryData(val, nesting + `${key}.`); } else { - return encodeURIComponent(nesting + key) + '=' + encodeURIComponent(val); + type = typesToken[typeof val]; + return encodeURIComponent(nesting + key + '.' + type) + '=' + encodeURIComponent(val); } }); return pairs.join('&'); From 9f62a30bb27fffbb8e84072cab6f014cab18249b Mon Sep 17 00:00:00 2001 From: mahsa shadi Date: Mon, 6 Sep 2021 16:25:05 +0430 Subject: [PATCH 05/12] Fixes null type in typesToken --- src/utils/fetch.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/utils/fetch.js b/src/utils/fetch.js index 1dc2ee9..a6718af 100644 --- a/src/utils/fetch.js +++ b/src/utils/fetch.js @@ -33,19 +33,19 @@ const typesToken = { number : 'i', boolean : 'b', undefined: 'u', - object: 'n' + null: 'n' }; /* * Creates URL request path */ export const encodeQueryData = (data, nesting = '') => { - let type; const pairs = Object.entries(data).map(([key, val]) => { - if (typeof val === 'object' && val !== null) { + const isNull = val === null; + if (typeof val === 'object' && !isNull) { return encodeQueryData(val, nesting + `${key}.`); } else { - type = typesToken[typeof val]; + const type = typesToken[isNull ? 'null' : typeof val]; return encodeURIComponent(nesting + key + '.' + type) + '=' + encodeURIComponent(val); } }); From 14615e5535ec9544f328a8cf42b50d64136a784c Mon Sep 17 00:00:00 2001 From: mahsa shadi Date: Wed, 8 Sep 2021 14:22:44 +0430 Subject: [PATCH 06/12] Ignore vfs client options from being send to the server --- src/adapters/vfs/system.js | 4 ++-- src/vfs.js | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/adapters/vfs/system.js b/src/adapters/vfs/system.js index 16dcfd9..3c653f4 100644 --- a/src/adapters/vfs/system.js +++ b/src/adapters/vfs/system.js @@ -89,7 +89,7 @@ const methods = (core, request) => { stat: passthrough('stat'), url: ({path}, options) => Promise.resolve( - core.url(`/vfs/readfile?path=${encodeURIComponent(path)}`) + core.url(`/vfs/readfile?path.s=${encodeURIComponent(path)}`) ), search: ({path}, pattern, options) => @@ -102,7 +102,7 @@ const methods = (core, request) => { download: ({path}, options = {}) => { const json = encodeURIComponent(JSON.stringify({download: true})); - return Promise.resolve(`/vfs/readfile?options=${json}&path=` + encodeURIComponent(path)) + return Promise.resolve(`/vfs/readfile?options=${json}&path.s=` + encodeURIComponent(path)) .then(url => { return (options.target || window).open(url); }); diff --git a/src/vfs.js b/src/vfs.js index 505ff14..420bbe3 100644 --- a/src/vfs.js +++ b/src/vfs.js @@ -74,6 +74,12 @@ const handleDirectoryList = (path, options) => result => filter: options.filter })); +// Returns a new "options" object without properties from "ignore" +const filterOptions = (ignore, options) => { + ignore.forEach(item => delete options[item]); + return options; +}; + /** * Read a directory * @@ -82,7 +88,7 @@ const handleDirectoryList = (path, options) => result => * @return {Promise} A list of files */ export const readdir = (adapter, mount) => (path, options = {}) => - adapter.readdir(pathToObject(path), options, mount) + adapter.readdir(pathToObject(path), filterOptions(['showHiddenFiles', 'filter'], options), mount) .then(handleDirectoryList(path, options)); /** From a5e92a19fb3114a3304fd93e12f40ef12cf584a4 Mon Sep 17 00:00:00 2001 From: mahsa shadi Date: Sat, 11 Sep 2021 16:49:38 +0430 Subject: [PATCH 07/12] Preserving the options passed into filterOptions method --- __tests__/vfs.js | 2 +- src/vfs.js | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/__tests__/vfs.js b/__tests__/vfs.js index ca0a76b..4310615 100644 --- a/__tests__/vfs.js +++ b/__tests__/vfs.js @@ -79,7 +79,7 @@ describe('VFS', () => { .toBeInstanceOf(ArrayBuffer); }); - test('writefile - blob', () => { + test('#writefile - blob', () => { return expect(call('writefile', 'null:/filename', new Blob())) .resolves .toBe(-1); diff --git a/src/vfs.js b/src/vfs.js index 420bbe3..5dc80e2 100644 --- a/src/vfs.js +++ b/src/vfs.js @@ -75,10 +75,11 @@ const handleDirectoryList = (path, options) => result => })); // Returns a new "options" object without properties from "ignore" -const filterOptions = (ignore, options) => { - ignore.forEach(item => delete options[item]); - return options; -}; +const filterOptions = (ignore, options) => Object.fromEntries( + Object + .entries(options) + .filter(([k]) => !ignore.includes(k)) +); /** * Read a directory From 98534cb1b9f08e055d916873a0ee36ca50acfb54 Mon Sep 17 00:00:00 2001 From: mahsa shadi Date: Sat, 6 Nov 2021 11:42:04 +0330 Subject: [PATCH 08/12] vfs capabilities method is added --- __tests__/vfs.js | 2 +- src/adapters/vfs/null.js | 1 + src/adapters/vfs/system.js | 15 +++++++++++---- src/filesystem.js | 1 + src/vfs.js | 21 ++++++++++++++++++++- 5 files changed, 34 insertions(+), 6 deletions(-) diff --git a/__tests__/vfs.js b/__tests__/vfs.js index ca0a76b..4310615 100644 --- a/__tests__/vfs.js +++ b/__tests__/vfs.js @@ -79,7 +79,7 @@ describe('VFS', () => { .toBeInstanceOf(ArrayBuffer); }); - test('writefile - blob', () => { + test('#writefile - blob', () => { return expect(call('writefile', 'null:/filename', new Blob())) .resolves .toBe(-1); diff --git a/src/adapters/vfs/null.js b/src/adapters/vfs/null.js index c1528f1..061e592 100644 --- a/src/adapters/vfs/null.js +++ b/src/adapters/vfs/null.js @@ -34,6 +34,7 @@ * @param {object} [options] Adapter options */ const nullAdapter = ({ + capabilities: (path, options) => Promise.resolve({}), readdir: (path, options) => Promise.resolve([]), readfile: (path, type, options) => Promise.resolve({body: new ArrayBuffer(), mime: 'application/octet-stream'}), writefile: (path, data, options) => Promise.resolve(-1), diff --git a/src/adapters/vfs/system.js b/src/adapters/vfs/system.js index ceee251..597a73a 100644 --- a/src/adapters/vfs/system.js +++ b/src/adapters/vfs/system.js @@ -28,7 +28,7 @@ * @license Simplified BSD License */ -const getters = ['exists', 'stat', 'readdir', 'readfile']; +const getters = ['capabilities', 'exists', 'stat', 'readdir', 'readfile']; const requester = core => (fn, body, type, options = {}) => core.request(`/vfs/${fn}`, { @@ -57,9 +57,16 @@ const methods = (core, request) => { .then(({body}) => body); return { + capabilities: ({path}, options) => request('capabilities', { + path, + options + }, 'json').then(({body}) => { + return body; + }), + readdir: ({path}, options) => request('readdir', { path, - options: {} + options, }, 'json').then(({body}) => body), readfile: ({path}, type, options) => @@ -89,7 +96,7 @@ const methods = (core, request) => { stat: passthrough('stat'), url: ({path}, options) => Promise.resolve( - core.url(`/vfs/readfile?path=${encodeURIComponent(path)}`) + core.url(`/vfs/readfile?path.s=${encodeURIComponent(path)}`) ), search: ({path}, pattern, options) => @@ -102,7 +109,7 @@ const methods = (core, request) => { download: ({path}, options = {}) => { const json = encodeURIComponent(JSON.stringify({download: true})); - return Promise.resolve(`/vfs/readfile?options=${json}&path=` + encodeURIComponent(path)) + return Promise.resolve(`/vfs/readfile?options=${json}&path.s=` + encodeURIComponent(path)) .then(url => { return (options.target || window).open(url); }); diff --git a/src/filesystem.js b/src/filesystem.js index 5fd2ee1..812d650 100644 --- a/src/filesystem.js +++ b/src/filesystem.js @@ -63,6 +63,7 @@ import merge from 'deepmerge'; * Filesystem Adapter Methods * TODO: typedef * @typedef {Object} FilesystemAdapterMethods + * @property {Function} capabilities * @property {Function} readdir * @property {Function} readfile * @property {Function} writefile diff --git a/src/vfs.js b/src/vfs.js index 505ff14..3baf226 100644 --- a/src/vfs.js +++ b/src/vfs.js @@ -74,6 +74,25 @@ const handleDirectoryList = (path, options) => result => filter: options.filter })); +const filterOptions = (ignore, options) => Object.fromEntries( + Object + .entries(options) + .filter(([k]) => !ignore.includes(k)) +); + +/** + * Get vfs capabilities + * + * @param {string|VFSFile} path The path of a file + * @param {VFSMethodOptions} [options] Options + * @return {Promise} An object of capabilities + */ +export const capabilities = (adapter, mount) => (path, options = {}) => { + console.log('********************capabilities**************************'); + console.log(options); + return adapter.capabilities(pathToObject(path), options, mount); +}; + /** * Read a directory * @@ -82,7 +101,7 @@ const handleDirectoryList = (path, options) => result => * @return {Promise} A list of files */ export const readdir = (adapter, mount) => (path, options = {}) => - adapter.readdir(pathToObject(path), options, mount) + adapter.readdir(pathToObject(path), filterOptions(['filter'], options), mount) .then(handleDirectoryList(path, options)); /** From 4bd37c91701c00d038b80f63d2d2c6e5fb8141a7 Mon Sep 17 00:00:00 2001 From: mahsa shadi Date: Sun, 7 Nov 2021 14:20:29 +0330 Subject: [PATCH 09/12] remove unnecessary console.log --- src/vfs.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/vfs.js b/src/vfs.js index 3baf226..8216b09 100644 --- a/src/vfs.js +++ b/src/vfs.js @@ -88,8 +88,6 @@ const filterOptions = (ignore, options) => Object.fromEntries( * @return {Promise} An object of capabilities */ export const capabilities = (adapter, mount) => (path, options = {}) => { - console.log('********************capabilities**************************'); - console.log(options); return adapter.capabilities(pathToObject(path), options, mount); }; From 64ff0c3127e633d9aa2f02acd2c21adac159b1ac Mon Sep 17 00:00:00 2001 From: mahsa shadi Date: Mon, 27 Dec 2021 13:25:18 +0330 Subject: [PATCH 10/12] each mountpoint capability is cached in vfs abstraction --- src/utils/fetch.js | 4 +++- src/utils/vfs.js | 46 ++++++++++++++++++++++++---------------------- src/vfs.js | 17 ++++++++++++++--- 3 files changed, 41 insertions(+), 26 deletions(-) diff --git a/src/utils/fetch.js b/src/utils/fetch.js index a6718af..f2180d2 100644 --- a/src/utils/fetch.js +++ b/src/utils/fetch.js @@ -81,7 +81,9 @@ const createFetchOptions = (url, options, type) => { } if (fetchOptions.body && fetchOptions.method.toLowerCase() === 'get') { - url += '?' + encodeQueryData(fetchOptions.body); + if(encodeQueryData(fetchOptions.body) !== '') { + url += '?' + encodeQueryData(fetchOptions.body); + } delete fetchOptions.body; } diff --git a/src/utils/vfs.js b/src/utils/vfs.js index 3eec95c..9658d7a 100644 --- a/src/utils/vfs.js +++ b/src/utils/vfs.js @@ -175,6 +175,7 @@ export const humanFileSize = (bytes, si = false) => { * Transforms a readdir result * @param {object} root The path to the readdir root * @param Object[] files An array of readdir results + * @param Object[] capabilityCache An object of mount point capabilities * @param {object} options Options * @param {Boolean} [options.showHiddenFiles=false] Show hidden files * @param {Function} [options.filter] A filter @@ -182,7 +183,12 @@ export const humanFileSize = (bytes, si = false) => { * @param {string} [options.sortDir='asc'] Sort in this direction * @return {Object[]} */ -export const transformReaddir = ({path}, files, options = {}) => { +export const transformReaddir = ({path}, files, capabilityCache, options = {}) => { + const mountPoint = path => path.split(':/')[0]; + let mountPointSort = false; + if(capabilityCache[mountPoint(path)] !== undefined) { + mountPointSort = capabilityCache[mountPoint(path)].sort; + } options = { showHiddenFiles: false, sortBy: 'filename', @@ -191,48 +197,44 @@ export const transformReaddir = ({path}, files, options = {}) => { }; let {sortDir, sortBy, filter} = options; + if (typeof filter !== 'function') { filter = () => true; } - if (['asc', 'desc'].indexOf(sortDir) === -1) { - sortDir = 'asc'; - } - const filterHidden = options.showHiddenFiles ? () => true : file => file.filename.substr(0, 1) !== '.'; - const sorter = sortMap[sortBy] - ? sortMap[sortBy] - : sortFn('string'); - const modify = (file) => ({ ...file, humanSize: humanFileSize(file.size) }); - // FIXME: Optimize this to one chain! + let sortedSpecial = []; + let sortedFiles = []; - const sortedSpecial = createSpecials(path) - .sort(sorter(sortBy, sortDir)) + sortedSpecial = createSpecials(path) .map(modify); - - const sortedDirectories = files.filter(file => file.isDirectory) - .sort(sorter(sortBy, sortDir)) - .filter(filterHidden) + sortedFiles = files.filter(filterHidden) .filter(filter) .map(modify); - const sortedFiles = files.filter(file => !file.isDirectory) - .sort(sorter(sortBy, sortDir)) - .filter(filterHidden) - .filter(filter) - .map(modify); + if(!mountPointSort) { + if (['asc', 'desc'].indexOf(sortDir) === -1) { + sortDir = 'asc'; + } + const sorter = sortMap[sortBy] + ? sortMap[sortBy] + : sortFn('ascii'); + sortedSpecial = sortedSpecial + .sort(sorter(sortBy, sortDir)); + sortedFiles = sortedFiles + .sort(sorter(sortBy, sortDir)); + } return [ ...sortedSpecial, - ...sortedDirectories, ...sortedFiles ]; }; diff --git a/src/vfs.js b/src/vfs.js index 8216b09..833e06f 100644 --- a/src/vfs.js +++ b/src/vfs.js @@ -60,6 +60,9 @@ import { * @property {object} [stat] */ +// Cache the capability of each mount point +let capabilityCache = {}; + // Makes sure our input paths are object(s) const pathToObject = path => ({ id: null, @@ -69,7 +72,7 @@ const pathToObject = path => ({ // Handles directory listing result(s) const handleDirectoryList = (path, options) => result => Promise.resolve(result.map(stat => createFileIter(stat))) - .then(result => transformReaddir(pathToObject(path), result, { + .then(result => transformReaddir(pathToObject(path), result, capabilityCache, { showHiddenFiles: options.showHiddenFiles !== false, filter: options.filter })); @@ -87,8 +90,16 @@ const filterOptions = (ignore, options) => Object.fromEntries( * @param {VFSMethodOptions} [options] Options * @return {Promise} An object of capabilities */ -export const capabilities = (adapter, mount) => (path, options = {}) => { - return adapter.capabilities(pathToObject(path), options, mount); +export const capabilities = (adapter, mount) => (path, options) => { + const cached = capabilityCache[mount.name]; + if (cached) { + return Promise.resolve(cached); + } + return adapter.capabilities(pathToObject(path), options, mount) + .then(capabilities => { + capabilityCache[mount.name] = capabilities; + return capabilities; + }); }; /** From 68aa1d56b6482be4630440fa243a610d18960db1 Mon Sep 17 00:00:00 2001 From: mahsa shadi Date: Mon, 27 Dec 2021 16:44:29 +0330 Subject: [PATCH 11/12] Ascii based sort function is added, and transformReaddir tests are fixed --- __tests__/utils/vfs.js | 21 ++++++++++++++++----- src/utils/vfs.js | 9 +++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/__tests__/utils/vfs.js b/__tests__/utils/vfs.js index b964afd..5d41a37 100644 --- a/__tests__/utils/vfs.js +++ b/__tests__/utils/vfs.js @@ -67,8 +67,8 @@ describe('utils.vfs#transformReaddir', () => { size: 666 }]; - const check = (options = {}) => vfs.transformReaddir({path: root}, input, options); - const checkMap = (options = {}, key = 'filename') => check(options).map(iter => iter[key]); + const check = (options = {}, capability = {}) => vfs.transformReaddir({path: root}, input, capability, options); + const checkMap = (options = {}, key = 'filename', capability = {}) => check(options, capability).map(iter => iter[key]); test('Should add parent directory', () => { expect(check({ @@ -88,7 +88,7 @@ describe('utils.vfs#transformReaddir', () => { test('Should remove dotfiles', () => { expect(checkMap({ showHiddenFiles: false - })).toEqual(['..', 'directory', 'xdirectory', 'file', 'xfile']); + })).toEqual(['..', 'directory', 'file', 'xdirectory', 'xfile']); }); test('Should sort by descending order', () => { @@ -98,7 +98,7 @@ describe('utils.vfs#transformReaddir', () => { }); return expect(result) - .toEqual(['..', 'xdirectory', 'directory', 'xfile', 'file']); + .toEqual(['..', 'xfile', 'xdirectory', 'file', 'directory']); }); test('Should sort by ascending order', () => { @@ -108,7 +108,7 @@ describe('utils.vfs#transformReaddir', () => { }); return expect(result) - .toEqual(['..', 'directory', 'xdirectory', 'file', 'xfile']); + .toEqual(['..', 'directory', 'file', 'xdirectory', 'xfile']); }); test('Should sort by specified column', () => { @@ -123,6 +123,17 @@ describe('utils.vfs#transformReaddir', () => { expect(every).toEqual(true); }); + + test('Should not sort', () => { + const result = checkMap({}, 'filename', { + foo: { + sort: true + } + }); + + return expect(result) + .toEqual(['..', 'directory', 'xdirectory', 'file', 'xfile']); + }); }); describe('utils.vfs#getFileIcon', () => { diff --git a/src/utils/vfs.js b/src/utils/vfs.js index 9658d7a..a52d738 100644 --- a/src/utils/vfs.js +++ b/src/utils/vfs.js @@ -78,6 +78,13 @@ const sortDefault = (k, d) => (a, b) => ? (d === 'asc' ? 1 : 0) : (d === 'asc' ? 0 : 1)); +/* + * Sort by educated guess + */ +const sortAscii = (k, d) => (a, b) => d === 'asc' + ? (a[k] < b[k]) ? -1 : 1 + : (a[k] < b[k]) ? 1 : -1; + /* * Sorts an array of files */ @@ -86,6 +93,8 @@ const sortFn = t => { return sortString; } else if (t === 'date') { return sortDate; + } else if (t === 'ascii') { + return sortAscii; } return sortDefault; From 12d5b6527d2a658c5308855eb7335e77fca5397f Mon Sep 17 00:00:00 2001 From: mahsa shadi Date: Sun, 24 Jul 2022 10:48:40 +0430 Subject: [PATCH 12/12] Support serialization of URL query parameters --- __tests__/utils/fetch.js | 14 ++++---------- src/utils/fetch.js | 21 +++++++-------------- 2 files changed, 11 insertions(+), 24 deletions(-) diff --git a/__tests__/utils/fetch.js b/__tests__/utils/fetch.js index f6d5b16..964bd0c 100644 --- a/__tests__/utils/fetch.js +++ b/__tests__/utils/fetch.js @@ -11,13 +11,7 @@ describe('utils.fetch#encodeQueryData', () => { }); const result2 = fetch.encodeQueryData({ - a: { - a: 1, - b: true, - c: null, - d: 'foo', - e: undefined - }, + a: 1, b: { c: { d: 'foo' @@ -25,7 +19,7 @@ describe('utils.fetch#encodeQueryData', () => { } }); - expect(result1).toEqual('a.i=1&b.b=true&c.n=null&d.s=foo&e.u=undefined'); - expect(result2).toEqual('a.a.i=1&a.b.b=true&a.c.n=null&a.d.s=foo&a.e.u=undefined&b.c.d.s=foo'); + expect(result1).toEqual('a=1&b=true&c=null&d=foo&e=undefined'); + expect(result2).toEqual('a=1&b=%7B%22c%22%3A%7B%22d%22%3A%22foo%22%7D%7D'); }); -}); \ No newline at end of file +}); diff --git a/src/utils/fetch.js b/src/utils/fetch.js index f2180d2..6b23472 100644 --- a/src/utils/fetch.js +++ b/src/utils/fetch.js @@ -28,25 +28,18 @@ * @license Simplified BSD License */ -const typesToken = { - string : 's', - number : 'i', - boolean : 'b', - undefined: 'u', - null: 'n' -}; -/* - * Creates URL request path - */ -export const encodeQueryData = (data, nesting = '') => { +// /* +// * Creates URL request path +// */ +export const encodeQueryData = (data) => { + const replacer = (k, v)=>(v === undefined ? null : v); const pairs = Object.entries(data).map(([key, val]) => { const isNull = val === null; if (typeof val === 'object' && !isNull) { - return encodeQueryData(val, nesting + `${key}.`); + return `${encodeURIComponent(key)}=${encodeURIComponent(JSON.stringify(val, replacer))}`; } else { - const type = typesToken[isNull ? 'null' : typeof val]; - return encodeURIComponent(nesting + key + '.' + type) + '=' + encodeURIComponent(val); + return `${encodeURIComponent(key)}=${encodeURIComponent(val)}`; } }); return pairs.join('&');