Skip to content

Commit

Permalink
Merge pull request #1 from CesarLai/feat/format
Browse files Browse the repository at this point in the history
Feat/format
  • Loading branch information
CesarLai authored Jan 20, 2024
2 parents ec8d433 + fec4f11 commit 81db6bd
Show file tree
Hide file tree
Showing 18 changed files with 279 additions and 14 deletions.
25 changes: 25 additions & 0 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
@@ -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 }}
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# picgo-plugin-image-name-format
# picgo-plugin-filename-format

A picgo plugin to format filename by your setting.
A picgo plugin to format filename by your setting.
10 changes: 6 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -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.",
Expand All @@ -18,7 +18,7 @@
"package.json",
"LICENSE"
],
"repository": "[email protected]:CesarLai/picgo-plugin-image-name-format.git",
"repository": "[email protected]:CesarLai/picgo-plugin-filename-format.git",
"publishConfig": {
"access": "public"
},
Expand All @@ -32,15 +32,17 @@
"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",
"tslib": "2.6.2",
"typescript": "5.0.2",
"typescript-transform-paths": "3.4.6"
}
}
}
23 changes: 19 additions & 4 deletions pnpm-lock.yaml

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

4 changes: 2 additions & 2 deletions src/beforeTransformPlugins.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { IPicGo } from 'picgo'
import fs from 'fs'
import { isUrl } from './util'
import { isUrl } from '@/utils'

/**
* beforeTransformPlugins handle function
Expand All @@ -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)
}

Expand Down
14 changes: 13 additions & 1 deletion src/beforeUploadPlugins.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
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
*/
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
Expand Down
1 change: 1 addition & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const PLUGIN_NAME = 'picgo-plugin-filename-format'
47 changes: 47 additions & 0 deletions src/formatters/hash.ts
Original file line number Diff line number Diff line change
@@ -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
18 changes: 18 additions & 0 deletions src/formatters/index.ts
Original file line number Diff line number Diff line change
@@ -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
}
}, {})
7 changes: 7 additions & 0 deletions src/formatters/origin.ts
Original file line number Diff line number Diff line change
@@ -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
44 changes: 44 additions & 0 deletions src/formatters/time.ts
Original file line number Diff line number Diff line change
@@ -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
18 changes: 18 additions & 0 deletions src/formatters/timestamp.ts
Original file line number Diff line number Diff line change
@@ -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
12 changes: 12 additions & 0 deletions src/formatters/uuid.ts
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { IPicGo } from 'picgo'
import handleBeforeTransformPlugins from './beforeTransformPlugins'
import handleBeforeUploadPlugins from './beforeUploadPlugins'

const PLUGIN_NAME: Readonly<string> = 'image-name-format'
const PLUGIN_NAME: Readonly<string> = 'filename-format'

/**
* picgo image filename format plugin
Expand Down
47 changes: 47 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
export type FormatType = 'timestamp' | 'time' | 'hash' | 'uuid' | 'origin'

export interface TimestampFormatOptions {
length?: 10 | 13
}

export interface TimeFormatOptions {
timeFormat?: string
nameFormat?: Exclude<FormatType, 'time'>
nameOptions?: any
}

export interface HashFormatOptions {
type?: string
length?: number
}

export interface BasePluginSetting<T extends FormatType, O = any> {
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

export type FormatterFunc = (originName: string, config: PluginSetting) => string
export type Formatter = FormatterFunc & {
// (originName: string, config: PluginSetting): string
formatterType: string
}
15 changes: 15 additions & 0 deletions src/utils/helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { PluginSetting } from '@/types'

const DefaultPluginSetting: Readonly<PluginSetting> = {
format: 'origin'
}

export const parsePluginSetting = (
setting: PluginSetting | undefined
): PluginSetting => {
return setting?.format ? setting : DefaultPluginSetting
}

export const getExt = (fileName: string) => {
return /(\.[a-zA-Z]+)?$/.exec(fileName)?.[1] || ''
}
Loading

0 comments on commit 81db6bd

Please sign in to comment.