From 1c1eeed8cd605bc623ba3b30b8d7c7b8784050a2 Mon Sep 17 00:00:00 2001 From: Cesar Lai Date: Thu, 4 Jan 2024 08:23:44 +0800 Subject: [PATCH 1/4] feat: update plugin name --- README.md | 4 ++-- package.json | 6 +++--- src/index.ts | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index bef95c5..8e16f8a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ -# picgo-plugin-image-name-format +# picgo-plugin-filename-format -A picgo plugin to format filename by your setting. \ No newline at end of file +A picgo plugin to format filename by your setting. diff --git a/package.json b/package.json index 287d9ee..086123a 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "picgo-plugin-image-name-format", + "name": "picgo-plugin-filename-format", "version": "0.1.0", "author": "Cesar Lai", "description": "A picgo plugin to format filename by your setting.", @@ -18,7 +18,7 @@ "package.json", "LICENSE" ], - "repository": "git@github.com:CesarLai/picgo-plugin-image-name-format.git", + "repository": "git@github.com:CesarLai/picgo-plugin-filename-format.git", "publishConfig": { "access": "public" }, @@ -43,4 +43,4 @@ "typescript": "5.0.2", "typescript-transform-paths": "3.4.6" } -} +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index d88ff00..d44103e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,7 +2,7 @@ import type { IPicGo } from 'picgo' import handleBeforeTransformPlugins from './beforeTransformPlugins' import handleBeforeUploadPlugins from './beforeUploadPlugins' -const PLUGIN_NAME: Readonly = 'image-name-format' +const PLUGIN_NAME: Readonly = 'filename-format' /** * picgo image filename format plugin From c1c763bc8a2385a2bce5cd05d05c5130cf4b6b1e Mon Sep 17 00:00:00 2001 From: Cesar Lai Date: Thu, 4 Jan 2024 08:24:41 +0800 Subject: [PATCH 2/4] feat: change utils structure --- src/beforeTransformPlugins.ts | 2 +- src/types.ts | 39 +++++++++++++++++++++++++++++++++++ src/utils/helper.ts | 22 ++++++++++++++++++++ src/utils/index.ts | 2 ++ src/{util.ts => utils/url.ts} | 0 5 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 src/types.ts create mode 100644 src/utils/helper.ts create mode 100644 src/utils/index.ts rename src/{util.ts => utils/url.ts} (100%) diff --git a/src/beforeTransformPlugins.ts b/src/beforeTransformPlugins.ts index 65ad528..2fd7354 100644 --- a/src/beforeTransformPlugins.ts +++ b/src/beforeTransformPlugins.ts @@ -1,6 +1,6 @@ import type { IPicGo } from 'picgo' import fs from 'fs' -import { isUrl } from './util' +import { isUrl } from '@/utils' /** * beforeTransformPlugins handle function diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..9a53752 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,39 @@ +export type FormatType = 'timestamp' | 'time' | 'hash' | 'uuid' | 'origin' + +export interface TimestampFormatOptions { + length?: 10 | 13 | '10' | '13' +} + +export interface TimeFormatOptions { + timeFormat?: string +} + +export interface HashFormatOptions { + type?: string + length?: number | string +} + +export interface BasePluginSetting { + format?: T + options?: O +} + +export type TimestampPluginSetting = BasePluginSetting< + 'timestamp', + TimestampFormatOptions +> + +export type TimePluginSetting = BasePluginSetting<'time', TimeFormatOptions> + +export type HashPluginSetting = BasePluginSetting<'hash', HashFormatOptions> + +export type UuidPluginSetting = BasePluginSetting<'uuid', undefined> + +export type OriginPluginSetting = BasePluginSetting<'origin', undefined> + +export type PluginSetting = + | TimestampPluginSetting + | TimePluginSetting + | HashPluginSetting + | UuidPluginSetting + | OriginPluginSetting diff --git a/src/utils/helper.ts b/src/utils/helper.ts new file mode 100644 index 0000000..d147289 --- /dev/null +++ b/src/utils/helper.ts @@ -0,0 +1,22 @@ +import { HashFormatOptions, PluginSetting, TimeFormatOptions, TimestampFormatOptions } from "@/types"; + +const DefaultPluginSetting: Readonly = { + format: 'origin' +} + +const DefaultTimestampFormatOptions: Readonly = { + length: 13 +} + +const DefaultTimeFormatOptions: Readonly = { + timeFormat: 'YYYYMMDDHHmmss' +} + +const DefaultHashFormatOptions: Readonly = { + type: '', + length: 32 +} + +export const parsePluginSetting = (setting: PluginSetting | undefined) => { + +} \ No newline at end of file diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 0000000..95d3cf7 --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,2 @@ +export * from './helper' +export * from './url' diff --git a/src/util.ts b/src/utils/url.ts similarity index 100% rename from src/util.ts rename to src/utils/url.ts From 5c881b92f43cf8fe5ede151f54ecebf1ccafa534 Mon Sep 17 00:00:00 2001 From: Cesar Lai Date: Sun, 21 Jan 2024 01:28:38 +0800 Subject: [PATCH 3/4] feat: add formatters --- package.json | 4 ++- pnpm-lock.yaml | 23 ++++++++++++++--- src/beforeTransformPlugins.ts | 2 +- src/beforeUploadPlugins.ts | 14 ++++++++++- src/constants.ts | 1 + src/formatters/hash.ts | 47 +++++++++++++++++++++++++++++++++++ src/formatters/index.ts | 18 ++++++++++++++ src/formatters/origin.ts | 7 ++++++ src/formatters/time.ts | 44 ++++++++++++++++++++++++++++++++ src/formatters/timestamp.ts | 18 ++++++++++++++ src/formatters/uuid.ts | 12 +++++++++ src/types.ts | 14 ++++++++--- src/utils/helper.ts | 21 ++++++---------- 13 files changed, 201 insertions(+), 24 deletions(-) create mode 100644 src/constants.ts create mode 100644 src/formatters/hash.ts create mode 100644 src/formatters/index.ts create mode 100644 src/formatters/origin.ts create mode 100644 src/formatters/time.ts create mode 100644 src/formatters/timestamp.ts create mode 100644 src/formatters/uuid.ts diff --git a/package.json b/package.json index 086123a..4ed3ab9 100644 --- a/package.json +++ b/package.json @@ -32,10 +32,12 @@ "build": "rimraf dist && tspc" }, "dependencies": { - "dayjs": "1.11.10" + "dayjs": "1.11.10", + "uuid": "9.0.1" }, "devDependencies": { "@types/node": "16.9.1", + "@types/uuid": "9.0.7", "picgo": "1.5.0-alpha.13", "rimraf": "5.0.5", "ts-patch": "3.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3a2e875..ff975c3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,18 +1,20 @@ lockfileVersion: '6.0' -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - dependencies: dayjs: specifier: 1.11.10 version: 1.11.10 + uuid: + specifier: ^9.0.1 + version: 9.0.1 devDependencies: '@types/node': specifier: 16.9.1 version: 16.9.1 + '@types/uuid': + specifier: ^9.0.7 + version: 9.0.7 picgo: specifier: 1.5.0-alpha.13 version: 1.5.0-alpha.13 @@ -146,6 +148,10 @@ packages: '@types/node': 16.9.1 dev: true + /@types/uuid@9.0.7: + resolution: {integrity: sha512-WUtIVRUZ9i5dYXefDEAI7sh9/O7jGvHg7Df/5O/gtH3Yabe5odI3UWopVR1qbPXQtvOxWu3mM4XxlYeZtMWF4g==} + dev: true + /agentkeepalive@4.5.0: resolution: {integrity: sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==} engines: {node: '>= 8.0.0'} @@ -2145,6 +2151,11 @@ packages: unescape: 1.0.1 dev: true + /uuid@9.0.1: + resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + hasBin: true + dev: false + /which@1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} hasBin: true @@ -2212,3 +2223,7 @@ packages: buffer-crc32: 0.2.13 fd-slicer: 1.1.0 dev: true + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false diff --git a/src/beforeTransformPlugins.ts b/src/beforeTransformPlugins.ts index 2fd7354..32fc906 100644 --- a/src/beforeTransformPlugins.ts +++ b/src/beforeTransformPlugins.ts @@ -9,7 +9,7 @@ const handleBeforeTransformPlugins = (ctx: IPicGo) => { ctx.input = ctx.input.map((item) => { if (Buffer.isBuffer(item)) { return item - } else if (typeof item === 'string' && !isUrl(item)) { + } else if (typeof item === 'string' && fs.existsSync(item)) { return fs.readFileSync(item) } diff --git a/src/beforeUploadPlugins.ts b/src/beforeUploadPlugins.ts index 170cde9..03c5716 100644 --- a/src/beforeUploadPlugins.ts +++ b/src/beforeUploadPlugins.ts @@ -1,4 +1,8 @@ import type { IPicGo } from 'picgo' +import { PLUGIN_NAME } from '@/constants' +import { parsePluginSetting } from '@/utils' +import { formatterMap } from '@/formatters' +import { PluginSetting } from '@/types' /** * beforeUploadPlugins handle function @@ -6,9 +10,17 @@ import type { IPicGo } from 'picgo' const handleBeforeUploadPlugins = (ctx: IPicGo) => { ctx.output = ctx.output.map((item) => { if (typeof item === 'object' && item.fileName) { + const fixedFileName = item.fileName.replace(/}$/, '') + const config = ctx.getConfig(PLUGIN_NAME) as PluginSetting + const fullConfig = parsePluginSetting(config) + const formatedFileName = + typeof formatterMap[fullConfig.format] === 'function' + ? formatterMap[fullConfig.format](fixedFileName, fullConfig) + : fixedFileName + return { ...item, - fileName: item.fileName.replace(/}$/, '') + fileName: formatedFileName } } return item diff --git a/src/constants.ts b/src/constants.ts new file mode 100644 index 0000000..ff658f1 --- /dev/null +++ b/src/constants.ts @@ -0,0 +1 @@ +export const PLUGIN_NAME = 'picgo-plugin-filename-format' diff --git a/src/formatters/hash.ts b/src/formatters/hash.ts new file mode 100644 index 0000000..310777f --- /dev/null +++ b/src/formatters/hash.ts @@ -0,0 +1,47 @@ +import { createHash } from 'crypto' +import { getExt } from '@/utils' +import { Formatter, FormatterFunc, HashFormatOptions } from '@/types' + +const getRandomString = (length = 8) => { + if (length <= 0) { + return '' + } + + const charPool = 'abcdefghijklmnopqrstuvwxyz0123456789' + const randomChars: string[] = [] + let i = length + while (i > 0) { + const randomIndex = (Math.floor(Math.random() * 100) % charPool.length) - 1 + randomChars.push(charPool[randomIndex]) + i-- + } + + return randomChars.join('') +} + +const generateHashFileName = ( + originName: string, + type: string, + length: number +) => { + const ext = getExt(originName) + const randomString = getRandomString(8) + const timestamp = new Date().getTime() + const hash = createHash(type) + .update(`${timestamp}_${originName}_${randomString}`) + .digest() + .toString('hex') + .substring(0, length) + return `${hash}${ext}` +} + +export const hashFormatter: FormatterFunc = (originName, config) => { + const { type, length } = config.options as HashFormatOptions + const hashType = type || 'sha256' + const hashLength = typeof length === 'number' && length > 0 ? length : 32 + return generateHashFileName(originName, hashType, hashLength) +} + +Reflect.defineProperty(hashFormatter, 'formatterType', { value: 'hash' }) + +export default hashFormatter as Formatter diff --git a/src/formatters/index.ts b/src/formatters/index.ts new file mode 100644 index 0000000..e3f90a8 --- /dev/null +++ b/src/formatters/index.ts @@ -0,0 +1,18 @@ +import originFormatter from './origin' +import hashFormatter from './hash' +import uuidFormatter from './uuid' +import timeFormatter from './time' +import timestampFormatter from './timestamp' + +export const formatterMap = [ + originFormatter, + hashFormatter, + uuidFormatter, + timeFormatter, + timestampFormatter +].reduce((map, formatter) => { + return { + ...map, + [formatter.formatterType]: formatter + } +}, {}) diff --git a/src/formatters/origin.ts b/src/formatters/origin.ts new file mode 100644 index 0000000..2452b8e --- /dev/null +++ b/src/formatters/origin.ts @@ -0,0 +1,7 @@ +import { Formatter, FormatterFunc } from '@/types' + +const originFormatter: FormatterFunc = (originName) => originName + +Reflect.defineProperty(originFormatter, 'formatterType', { value: 'origin' }) + +export default originFormatter as Formatter diff --git a/src/formatters/time.ts b/src/formatters/time.ts new file mode 100644 index 0000000..bffdd9e --- /dev/null +++ b/src/formatters/time.ts @@ -0,0 +1,44 @@ +import dayjs from 'dayjs' +import { + Formatter, + FormatterFunc, + PluginSetting, + TimeFormatOptions +} from '@/types' +import originFormatter from './origin' +import hashFormatter from './hash' +import timestampFormatter from './timestamp' +import uuidFormatter from './uuid' + +const generalFileName = ( + format: TimeFormatOptions['nameFormat'], + originName: string, + config: PluginSetting +) => { + switch (format) { + case 'hash': + return hashFormatter(originName, config) + case 'uuid': + return uuidFormatter(originName, config) + case 'timestamp': + return timestampFormatter(originName, config) + default: + return originFormatter(originName, config) + } +} + +export const timeFormatter: FormatterFunc = (originName, config) => { + const { timeFormat, nameFormat, nameOptions } = (config.options || {}) as TimeFormatOptions + const parsedTimeFormat = timeFormat || 'YYYY-MM-DD' + const parsedNameFormat = nameFormat || 'origin' + const fileName = generalFileName(parsedNameFormat, originName, { + ...config, + format: parsedNameFormat, + options: nameOptions + }) + return `${dayjs().format(parsedTimeFormat)}/${fileName}` +} + +Reflect.defineProperty(timeFormatter, 'formatterType', { value: 'time' }) + +export default timeFormatter as Formatter diff --git a/src/formatters/timestamp.ts b/src/formatters/timestamp.ts new file mode 100644 index 0000000..0e61061 --- /dev/null +++ b/src/formatters/timestamp.ts @@ -0,0 +1,18 @@ +import { getExt } from '@/utils' +import { Formatter, FormatterFunc, TimestampFormatOptions } from '@/types' + +const timestampFormatter: FormatterFunc = (originName, config) => { + const ext = getExt(originName) + const { length } = (config.options || {}) as TimestampFormatOptions + let timestamp = new Date().getTime() + if (length === 10) { + timestamp = Math.ceil(timestamp / 1000) + } + return `${timestamp}${ext}` +} + +Reflect.defineProperty(timestampFormatter, 'formatterType', { + value: 'timestamp' +}) + +export default timestampFormatter as Formatter diff --git a/src/formatters/uuid.ts b/src/formatters/uuid.ts new file mode 100644 index 0000000..f8fe7e4 --- /dev/null +++ b/src/formatters/uuid.ts @@ -0,0 +1,12 @@ +import { v4 as uuidv4 } from 'uuid' +import { getExt } from '@/utils' +import { Formatter, FormatterFunc } from '@/types' + +export const uuidFormatter: FormatterFunc = (originName) => { + const ext = getExt(originName) + return `${uuidv4()}${ext}` +} + +Reflect.defineProperty(uuidFormatter, 'formatterType', { value: 'uuid' }) + +export default uuidFormatter as Formatter diff --git a/src/types.ts b/src/types.ts index 9a53752..5dd08be 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,20 +1,22 @@ export type FormatType = 'timestamp' | 'time' | 'hash' | 'uuid' | 'origin' export interface TimestampFormatOptions { - length?: 10 | 13 | '10' | '13' + length?: 10 | 13 } export interface TimeFormatOptions { timeFormat?: string + nameFormat?: Exclude + nameOptions?: any } export interface HashFormatOptions { type?: string - length?: number | string + length?: number } export interface BasePluginSetting { - format?: T + format: T options?: O } @@ -37,3 +39,9 @@ export type PluginSetting = | HashPluginSetting | UuidPluginSetting | OriginPluginSetting + +export type FormatterFunc = (originName: string, config: PluginSetting) => string +export type Formatter = FormatterFunc & { + // (originName: string, config: PluginSetting): string + formatterType: string +} diff --git a/src/utils/helper.ts b/src/utils/helper.ts index d147289..663fc4e 100644 --- a/src/utils/helper.ts +++ b/src/utils/helper.ts @@ -1,22 +1,15 @@ -import { HashFormatOptions, PluginSetting, TimeFormatOptions, TimestampFormatOptions } from "@/types"; +import { PluginSetting } from '@/types' const DefaultPluginSetting: Readonly = { format: 'origin' } -const DefaultTimestampFormatOptions: Readonly = { - length: 13 +export const parsePluginSetting = ( + setting: PluginSetting | undefined +): PluginSetting => { + return setting?.format ? setting : DefaultPluginSetting } -const DefaultTimeFormatOptions: Readonly = { - timeFormat: 'YYYYMMDDHHmmss' +export const getExt = (fileName: string) => { + return /(\.[a-zA-Z]+)?$/.exec(fileName)?.[1] || '' } - -const DefaultHashFormatOptions: Readonly = { - type: '', - length: 32 -} - -export const parsePluginSetting = (setting: PluginSetting | undefined) => { - -} \ No newline at end of file From fec4f11c15a7e9da4b5983ef738d7ee0fef84afb Mon Sep 17 00:00:00 2001 From: Cesar Lai Date: Sun, 21 Jan 2024 01:28:51 +0800 Subject: [PATCH 4/4] feat: add workflows --- .github/workflows/publish.yaml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/publish.yaml diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml new file mode 100644 index 0000000..bcbf612 --- /dev/null +++ b/.github/workflows/publish.yaml @@ -0,0 +1,25 @@ +name: Publish Package to npmjs + +on: + push: + branches: ["main"] +env: + PNPM_VERSION: 7.2.0 + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + # Setup .npmrc file to publish to npm + - uses: actions/setup-node@v3 + with: + node-version: "16.x" + registry-url: "https://registry.npmjs.org" + scope: "@cesarlai" + - run: npm i -g pnpm@${PNPM_VERSION} + - run: pnpm install + - run: pnpm build + - run: pnpm run publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}