diff --git a/tools/helper/src/client/index.ts b/tools/helper/src/client/index.ts index b7c5040daf..d3864faf91 100644 --- a/tools/helper/src/client/index.ts +++ b/tools/helper/src/client/index.ts @@ -1,2 +1,3 @@ export * from './composables/index.js' +export * from './utils/index.js' export * from '../shared/index.js' diff --git a/tools/helper/src/client/utils/data.ts b/tools/helper/src/client/utils/data.ts new file mode 100644 index 0000000000..3601e8737d --- /dev/null +++ b/tools/helper/src/client/utils/data.ts @@ -0,0 +1,28 @@ +import type { DeflateOptions } from 'fflate' +import { strFromU8, strToU8, unzlibSync, zlibSync } from 'fflate/browser' + +declare const __VUEPRESS_SSR__: boolean + +export const encodeData = ( + data: string, + level: DeflateOptions['level'] = 6, +): string => { + const buffer = strToU8(data) + // zlib headers can be found at https://stackoverflow.com/a/54915442 + const zipped = zlibSync(buffer, { level }) + const binary = strFromU8(zipped, true) + + return __VUEPRESS_SSR__ + ? Buffer.from(binary, 'binary').toString('base64') + : btoa(binary) +} + +export const decodeData = (base64: string): string => { + console.log(base64) + + const binary = __VUEPRESS_SSR__ + ? Buffer.from(base64, 'base64').toString('binary') + : atob(base64) + + return strFromU8(unzlibSync(strToU8(binary, true))) +} diff --git a/tools/helper/src/client/utils/index.ts b/tools/helper/src/client/utils/index.ts new file mode 100644 index 0000000000..b14b7762e1 --- /dev/null +++ b/tools/helper/src/client/utils/index.ts @@ -0,0 +1 @@ +export * from './data.js' diff --git a/tools/helper/src/node/utils/data.ts b/tools/helper/src/node/utils/data.ts new file mode 100644 index 0000000000..a97879d0de --- /dev/null +++ b/tools/helper/src/node/utils/data.ts @@ -0,0 +1,26 @@ +import type { DeflateOptions } from 'fflate' +import { strFromU8, strToU8, unzlibSync, zlibSync } from 'fflate/node' + +/** + * Encode and compress data + */ +export const encodeData = ( + data: string, + level: DeflateOptions['level'] = 6, +): string => { + const buffer = strToU8(data) + // zlib headers can be found at https://stackoverflow.com/a/54915442 + const zipped = zlibSync(buffer, { level }) + const binary = strFromU8(zipped, true) + + return Buffer.from(binary, 'binary').toString('base64') +} + +/** + * Decode and unzip data + */ +export const decodeData = (base64: string): string => { + const binary = Buffer.from(base64, 'base64').toString('binary') + + return strFromU8(unzlibSync(strToU8(binary, true))) +} diff --git a/tools/helper/src/node/utils/index.ts b/tools/helper/src/node/utils/index.ts index a0bcba79cc..b5f0b2ece4 100644 --- a/tools/helper/src/node/utils/index.ts +++ b/tools/helper/src/node/utils/index.ts @@ -1,3 +1,4 @@ +export * from './data.js' export * from './getInstalledStatus.js' export * from './getRealPath.js' export * from './logger.js' diff --git a/tools/helper/tests/data.spec.ts b/tools/helper/tests/data.spec.ts new file mode 100644 index 0000000000..2c3fbd021a --- /dev/null +++ b/tools/helper/tests/data.spec.ts @@ -0,0 +1,49 @@ +import { describe, expect, it, vi } from 'vitest' +import { + encodeData as clientDecodeData, + decodeData as clientEncodeData, +} from '../src/client/utils/data.js' +import { + encodeData as nodeDecodeData, + decodeData as nodeEncodeData, +} from '../src/node/utils/data.js' + +// mock define value +vi.stubGlobal('__VUEPRESS_SSR__', false) + +const words = [ + 'Hello world.', + 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolores quasi consequatur sed accusamus repellendus mollitia dolore facilis perferendis provident, sint a tempora quos eveniet temporibus? Ipsum quasi adipisci voluptatibus fuga?', + '中国制造', + '昔人已乘黄鹤去⑵,此地空余黄鹤楼。黄鹤一去不复返,白云千载空悠悠⑶。晴川历历汉阳树⑷,芳草萋萋鹦鹉洲⑸。日暮乡关何处是⑹?烟波江上使人愁⑺', +] + +const compressed = [ + 'eNrzSM3JyVcozy/KSdEDAB0WBGs=', + 'eNoljkGOAyEMBL/SD1jtF3LJJVI+4UBPZAkwwWbeHybcSlZZXU8brNDusyJbsQHXgFQGkjVnCsYckKxdXZO2N1g0/nG/ZDo+U1y3u/BynRmS0nSp0zHYWQpbXlytrF+VvUQckrSoo3McHMu5eNipmS3+VklbKQjWbkPWkjl4sumK20d9Tb/h8avfITs0KU4rs4fEpeCYb7l9ATPWWYk=', + 'eNp7smPt09l7n3Zse9mwAAA6rwiz', + 'eNolj9sKgkAURX+9iwVWRgNFGoUVFvTQVUtndPBfpnOOM0/+QieE9bBh7/WwKVyCUpi/QIau9JxMcF4a8W6rGV0T3D6aiwIddRWdqm9v0GUoeryEIsAksPWS902kQQkMhlZrtmiwZ4z4sEJRhvkO52OGnr4LU9oLI3K27CS1gW8XU8bJs5M+ZS8jir+1PtHmBvKAoxT0ChOPwrsRsq3iZhhTeqRnDMUEdM0XyOsboX7tYJUm', +] + +const browserUtoaResults = words.map((word) => clientDecodeData(word)) +const browserAtouResults = compressed.map((data) => clientEncodeData(data)) + +const nodeUtoaResults = words.map((word) => nodeDecodeData(word)) +const nodeAutoResults = compressed.map((data) => nodeEncodeData(data)) + +describe('props', () => { + it('utoa should return same result', () => { + expect(browserUtoaResults).toEqual(nodeUtoaResults) + }) + + it('atou should return same result', () => { + expect(browserAtouResults).toEqual(nodeAutoResults) + }) + + it('transform should return itself', () => { + expect(browserUtoaResults.map((word) => nodeEncodeData(word))).toEqual( + words, + ) + expect(nodeUtoaResults.map((word) => nodeEncodeData(word))).toEqual(words) + }) +})