Skip to content

Commit

Permalink
feat: 微信公众号文章发布Form表单探索
Browse files Browse the repository at this point in the history
  • Loading branch information
terwer committed Sep 4, 2023
1 parent 7816ca5 commit 9c6ab1b
Show file tree
Hide file tree
Showing 13 changed files with 1,060 additions and 6 deletions.
9 changes: 9 additions & 0 deletions docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,12 @@ firefox
`pnpm extBuild -t firefox`

或者 `pnpm widgetBuild -t firefox -nb`

## 注意事项

下面的类库需要动态引用,不能直接构建

```
"fetch-blob": "^4.0.0",
"formdata-polyfill": "^4.0.10",
```
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@
"cross-fetch": "^3.1.8",
"crypto-js": "^4.1.1",
"element-plus": "^2.3.12",
"fetch-blob": "^4.0.0",
"formdata-polyfill": "^4.0.10",
"js-base64": "^3.7.5",
"lodash": "^4.17.21",
"pinia": "^2.1.6",
Expand Down
38 changes: 38 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions public/libs/fetch-blob/file.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/** @type {typeof globalThis.File} */ export const File: typeof globalThis.File;
48 changes: 48 additions & 0 deletions public/libs/fetch-blob/file.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Blob } from './index.js'

const _File = class File extends Blob {
#lastModified = 0
#name = ''

/**
* @param {*[]} fileBits
* @param {string} fileName
* @param {{lastModified?: number, type?: string}} options
*/// @ts-ignore
constructor (fileBits, fileName, options = {}) {
if (arguments.length < 2) {
throw new TypeError(`Failed to construct 'File': 2 arguments required, but only ${arguments.length} present.`)
}
super(fileBits, options)

if (options === null) options = {}

// Simulate WebIDL type casting for NaN value in lastModified option.
const lastModified = options.lastModified === undefined ? Date.now() : Number(options.lastModified)
if (!Number.isNaN(lastModified)) {
this.#lastModified = lastModified
}

this.#name = String(fileName)
}

get name () {
return this.#name
}

get lastModified () {
return this.#lastModified
}

get [Symbol.toStringTag] () {
return 'File'
}

static [Symbol.hasInstance] (object) {
return !!object && object instanceof Blob &&
/^(File)$/.test(object[Symbol.toStringTag])
}
}

/** @type {typeof globalThis.File} */// @ts-ignore
export const File = _File
51 changes: 51 additions & 0 deletions public/libs/fetch-blob/from.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
export default blobFromSync;
/**
* @param {string} path filepath on the disk
* @param {string} [type] mimetype to use
*/
export function blobFromSync(path: string, type?: string): Blob;
import { Blob } from "./index.js";
/**
* @param {string} path filepath on the disk
* @param {string} [type] mimetype to use
* @returns {Promise<Blob>}
*/
export function blobFrom(path: string, type?: string): Promise<Blob>;
/**
* Creates a temporary blob backed by the filesystem.
* NOTE: requires node.js v14 or higher to use FinalizationRegistry
*
* @param {*} data Same as fs.writeFile data
* @param {BlobPropertyBag & {signal?: AbortSignal}} options
* @param {AbortSignal} [signal] in case you wish to cancel the write operation
* @returns {Promise<Blob>}
*/
export function createTemporaryBlob(data: any, { signal, type }?: BlobPropertyBag & {
signal?: AbortSignal;
}): Promise<Blob>;
import { File } from "./file.js";
/**
* @param {string} path filepath on the disk
* @param {string} [type] mimetype to use
* @returns {Promise<File>}
*/
export function fileFrom(path: string, type?: string): Promise<File>;
/**
* @param {string} path filepath on the disk
* @param {string} [type] mimetype to use
*/
export function fileFromSync(path: string, type?: string): File;
/**
* Creates a temporary File backed by the filesystem.
* Pretty much the same as constructing a new File(data, name, options)
*
* NOTE: requires node.js v14 or higher to use FinalizationRegistry
* @param {*} data
* @param {string} name
* @param {FilePropertyBag & {signal?: AbortSignal}} opts
* @returns {Promise<File>}
*/
export function createTemporaryFile(data: any, name: string, opts: FilePropertyBag & {
signal?: AbortSignal;
}): Promise<File>;
export { Blob, File };
164 changes: 164 additions & 0 deletions public/libs/fetch-blob/from.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import {
realpathSync,
statSync,
rmdirSync,
createReadStream,
promises as fs
} from 'node:fs'
import { basename, sep, join } from 'node:path'
import { tmpdir } from 'node:os'
import process from 'node:process'
import DOMException from 'node-domexception'

import { File } from './file.js'
import { Blob } from './index.js'

const { stat, mkdtemp } = fs
let i = 0, tempDir, registry

/**
* @param {string} path filepath on the disk
* @param {string} [type] mimetype to use
*/
const blobFromSync = (path, type) => fromBlob(statSync(path), path, type)

/**
* @param {string} path filepath on the disk
* @param {string} [type] mimetype to use
* @returns {Promise<Blob>}
*/
const blobFrom = (path, type) => stat(path).then(stat => fromBlob(stat, path, type))

/**
* @param {string} path filepath on the disk
* @param {string} [type] mimetype to use
* @returns {Promise<File>}
*/
const fileFrom = (path, type) => stat(path).then(stat => fromFile(stat, path, type))

/**
* @param {string} path filepath on the disk
* @param {string} [type] mimetype to use
*/
const fileFromSync = (path, type) => fromFile(statSync(path), path, type)

// @ts-ignore
const fromBlob = (stat, path, type = '') => new Blob([new BlobDataItem({
path,
size: stat.size,
lastModified: stat.mtimeMs,
start: 0
})], { type })

// @ts-ignore
const fromFile = (stat, path, type = '') => new File([new BlobDataItem({
path,
size: stat.size,
lastModified: stat.mtimeMs,
start: 0
})], basename(path), { type, lastModified: stat.mtimeMs })

/**
* Creates a temporary blob backed by the filesystem.
* NOTE: requires node.js v14 or higher to use FinalizationRegistry
*
* @param {*} data Same as fs.writeFile data
* @param {BlobPropertyBag & {signal?: AbortSignal}} options
* @param {AbortSignal} [signal] in case you wish to cancel the write operation
* @returns {Promise<Blob>}
*/
const createTemporaryBlob = async (data, {signal, type} = {}) => {
registry = registry || new FinalizationRegistry(fs.unlink)
tempDir = tempDir || await mkdtemp(realpathSync(tmpdir()) + sep)
const id = `${i++}`
const destination = join(tempDir, id)
if (data instanceof ArrayBuffer) data = new Uint8Array(data)
await fs.writeFile(destination, data, { signal })
const blob = await blobFrom(destination, type)
registry.register(blob, destination)
return blob
}

/**
* Creates a temporary File backed by the filesystem.
* Pretty much the same as constructing a new File(data, name, options)
*
* NOTE: requires node.js v14 or higher to use FinalizationRegistry
* @param {*} data
* @param {string} name
* @param {FilePropertyBag & {signal?: AbortSignal}} opts
* @returns {Promise<File>}
*/
const createTemporaryFile = async (data, name, opts) => {
const blob = await createTemporaryBlob(data)
return new File([blob], name, opts)
}

/**
* This is a blob backed up by a file on the disk
* with minium requirement. Its wrapped around a Blob as a blobPart
* so you have no direct access to this.
*
* @private
*/
class BlobDataItem {
#path
#start

constructor (options) {
this.#path = options.path
this.#start = options.start
this.size = options.size
this.lastModified = options.lastModified
this.originalSize = options.originalSize === undefined
? options.size
: options.originalSize
}

/**
* Slicing arguments is first validated and formatted
* to not be out of range by Blob.prototype.slice
*/
slice (start, end) {
return new BlobDataItem({
path: this.#path,
lastModified: this.lastModified,
originalSize: this.originalSize,
size: end - start,
start: this.#start + start
})
}

async * stream () {
const { mtimeMs, size } = await stat(this.#path)

if (mtimeMs > this.lastModified || this.originalSize !== size) {
throw new DOMException('The requested file could not be read, typically due to permission problems that have occurred after a reference to a file was acquired.', 'NotReadableError')
}

yield * createReadStream(this.#path, {
start: this.#start,
end: this.#start + this.size - 1
})
}

get [Symbol.toStringTag] () {
return 'Blob'
}
}

process.once('exit', () => {
tempDir && rmdirSync(tempDir, { recursive: true })
})

export default blobFromSync
export {
Blob,
blobFrom,
blobFromSync,
createTemporaryBlob,
File,
fileFrom,
fileFromSync,
createTemporaryFile
}
2 changes: 2 additions & 0 deletions public/libs/fetch-blob/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/** @type {typeof globalThis.Blob} */
export const Blob: typeof globalThis.Blob;
Loading

0 comments on commit 9c6ab1b

Please sign in to comment.