Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions bundle/lib/plugins/src/_internal/manifest.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { PluginManifest, PluginVersion } from '../types'
import { formatPluginContributor } from '../utils'
import type { InternalPluginManifest } from './types'

/** Manifest schema version internal plugins are written against. */
Expand Down Expand Up @@ -39,6 +40,8 @@ export function completeInternalManifest(
? parseBundleVersion(manifest.version)
: (manifest.version ?? version)
manifest.format ??= ManifestFormat
manifest.author = formatPluginContributor(manifest.author)
manifest.contributors = manifest.contributors?.map(formatPluginContributor)

if (!isReservedDependency(manifest.id)) {
manifest.dependencies ??= {}
Expand Down
6 changes: 5 additions & 1 deletion bundle/lib/plugins/src/_internal/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,20 @@ import type {
PluginOptions,
PluginOptionsFactory,
} from '../types'
import type { PluginContributorInput } from '../utils'
import type { PluginSystemErrorPayload } from './errors'
import type { addPluginFlags, adoptPluginFlags } from './state'

export type AnyPlugin = Plugin<any, any>

export type InternalPluginManifest = Omit<
PluginManifest,
'version' | 'format' | 'dependencies'
'version' | 'format' | 'dependencies' | 'author' | 'contributors'
> &
Partial<Pick<PluginManifest, 'format' | 'dependencies'>> & {
/** Contributor object, or legacy string. Normalized to the string form. */
author: PluginContributorInput | string
contributors?: (PluginContributorInput | string)[]
/**
* Plugin version. Defaults to the bundle version.
* Only stubs (see {@link InternalPluginManifestExtras.defaultSource}) may set it in `manifest.json`, as a string like `1.0.0`.
Expand Down
39 changes: 38 additions & 1 deletion bundle/lib/plugins/src/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { describe, expect, test } from 'vitest'
import { getPluginContributorName, parsePluginContributor } from './utils'
import {
formatPluginContributor,
getPluginContributorName,
parsePluginContributor,
} from './utils'

const Id1 = '123456789012345678'
const Id2 = '876543210987654321'
Expand Down Expand Up @@ -64,3 +68,36 @@ describe('getPluginContributorName', () => {
expect(getPluginContributorName('Jane (Doe)')).toBe('Jane (Doe)')
})
})

describe('formatPluginContributor', () => {
test('passes strings through', () => {
expect(formatPluginContributor(`Jane <${Id1}>`)).toBe(`Jane <${Id1}>`)
})

test('formats objects into a parseable string', () => {
const formatted = formatPluginContributor({
name: 'Jane Doe',
id: Id1,
links: [
{ url: 'https://example.com/jane', title: 'Website' },
{ url: 'mailto:jane@example.com' },
],
})

expect(formatted).toBe(
`Jane Doe <${Id1}> (https://example.com/jane "Website") (mailto:jane@example.com)`,
)
expect(parsePluginContributor(formatted)).toEqual({
name: 'Jane Doe',
ids: [Id1],
links: [
{ url: 'https://example.com/jane', label: 'Website' },
{ url: 'mailto:jane@example.com', label: undefined },
],
})
})

test('formats a name only', () => {
expect(formatPluginContributor({ name: 'Valenced' })).toBe('Valenced')
})
})
25 changes: 25 additions & 0 deletions bundle/lib/plugins/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,31 @@ export interface PluginContributorLink {
label?: string
}

/**
* Contributor as written in `manifest.json`. Preferred over the legacy `Name <DISCORD_ID> (LINK "TITLE")` string,
* which is still accepted.
*/
export interface PluginContributorInput {
name: string
/** Discord user ID. */
id?: string
links?: { url: string; title?: string }[]
}

/** Formats a contributor into the `Name <DISCORD_ID> (LINK "TITLE")` string form. Legacy strings pass through. */
export function formatPluginContributor(
contributor: PluginContributorInput | string,
): string {
if (typeof contributor === 'string') return contributor

const { name, id, links = [] } = contributor
let formatted = name.trim()
if (id !== undefined) formatted += ` <${id}>`
for (const { url, title } of links)
formatted += title === undefined ? ` (${url})` : ` (${url} "${title}")`
return formatted
}

const ContributorEntryRegex =
/^(?:<(\d{17,20})>|\(((?:https?:\/\/|mailto:)[^()\s]+)(?:\s+"([^"()]+)")?\))\s*/i

Expand Down
15 changes: 15 additions & 0 deletions bundle/scripts/manifest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,21 @@ describe('getInternalPluginManifests', () => {
})
})

it('formats stub contributor objects into strings for native', async () => {
await plugin('start', 'settings.themes', {
id: 'valenced.settings.themes',
author: { name: 'Jane', id: '123456789012345678' },
contributors: ['John', { name: 'Bob' }],
defaultSource: { repo: 'https://example.com' },
})

const [stub] = await getInternalPluginManifests(root)
expect(stub).toMatchObject({
author: 'Jane <123456789012345678>',
contributors: ['John', 'Bob'],
})
})

it('rejects a version on a plugin that is not a stub', async () => {
await plugin('start', 'settings', {
id: 'valenced.settings',
Expand Down
19 changes: 15 additions & 4 deletions bundle/scripts/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { readdir, readFile } from 'fs/promises'
import { dirname } from 'path'
import { fileURLToPath } from 'url'
import { ReservedDependencyIds } from '../lib/plugins/src/_internal/manifest'
import { formatPluginContributor } from '../lib/plugins/src/utils'
import { exists, stringEnv } from './_shared'
import type { InternalPluginManifest } from '@valenced/plugins/_'

Expand Down Expand Up @@ -31,8 +32,14 @@ interface BundleManifestPlugin {
}

interface RawBundleManifestPlugin
extends Omit<BundleManifestPlugin, 'enabledByDefault' | 'defaultSource'>,
Pick<InternalPluginManifest, 'enabledByDefault' | 'defaultSource'> {
extends Omit<
BundleManifestPlugin,
'enabledByDefault' | 'defaultSource' | 'author' | 'contributors'
>,
Pick<
InternalPluginManifest,
'enabledByDefault' | 'defaultSource' | 'author' | 'contributors'
> {
build?: {
devOnly?: boolean
}
Expand Down Expand Up @@ -114,8 +121,12 @@ export async function getInternalPluginManifests(
...(defaultSource && {
name: manifest.name,
description: manifest.description,
author: manifest.author,
contributors: manifest.contributors,
author:
manifest.author &&
formatPluginContributor(manifest.author),
contributors: manifest.contributors?.map(
formatPluginContributor,
),
icon: manifest.icon,
}),
...(manifest.essential && { essential: true }),
Expand Down
5 changes: 4 additions & 1 deletion bundle/src/plugins/preinit/api.hidden/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
"id": "valenced.api.hidden",
"name": "Developer Mode",
"description": "Exposes internal Valenced APIs for debugging.",
"author": "Valenced",
"author": {
"name": "Valenced",
"links": [{ "url": "https://discord.com/invite/dtBTQHYSx4", "title": "Support Server" }]
},
"icon": "WrenchIcon",
"enabledByDefault": "dev"
}
5 changes: 4 additions & 1 deletion bundle/src/plugins/preinit/api.themes/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
"id": "valenced.api.themes",
"name": "Themes API",
"description": "This feature requires an update to be installed.",
"author": "Valenced",
"author": {
"name": "Valenced",
"links": [{ "url": "https://discord.com/invite/dtBTQHYSx4", "title": "Support Server" }]
},
"icon": "PaintPaletteIcon",
"version": "0.0.0",
"enabledByDefault": true,
Expand Down
5 changes: 4 additions & 1 deletion bundle/src/plugins/preinit/api/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
"id": "valenced.api",
"name": "Plugin API",
"description": "Provides the Valenced plugin API.",
"author": "Valenced",
"author": {
"name": "Valenced",
"links": [{ "url": "https://discord.com/invite/dtBTQHYSx4", "title": "Support Server" }]
},
"icon": "PollsIcon",
"essential": true,
"api": true
Expand Down
5 changes: 4 additions & 1 deletion bundle/src/plugins/preinit/logging/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
"id": "valenced.logging",
"name": "Logging",
"description": "Logs assisting Valenced developers.",
"author": "Valenced",
"author": {
"name": "Valenced",
"links": [{ "url": "https://discord.com/invite/dtBTQHYSx4", "title": "Support Server" }]
},
"icon": "PaperIcon",
"enabledByDefault": true,
"build": {
Expand Down
5 changes: 4 additions & 1 deletion bundle/src/plugins/preinit/no-track/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
"id": "valenced.no-track",
"name": "No Track",
"description": "Disables Discord and Sentry analytics.",
"author": "Valenced",
"author": {
"name": "Valenced",
"links": [{ "url": "https://discord.com/invite/dtBTQHYSx4", "title": "Support Server" }]
},
"icon": "AnalyticsIcon",
"enabledByDefault": true
}
5 changes: 4 additions & 1 deletion bundle/src/plugins/preinit/recovery/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
"id": "valenced.recovery",
"name": "Recovery",
"description": "Handles errors and provides troubleshooting options for Valenced.",
"author": "Valenced",
"author": {
"name": "Valenced",
"links": [{ "url": "https://discord.com/invite/dtBTQHYSx4", "title": "Support Server" }]
},
"icon": "ShieldIcon",
"essential": true,
"dependencies": {
Expand Down
5 changes: 4 additions & 1 deletion bundle/src/plugins/start/settings.plugins/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
"id": "valenced.settings.plugins",
"name": "Plugin Settings",
"description": "Plugin management UI for Valenced.",
"author": "Valenced",
"author": {
"name": "Valenced",
"links": [{ "url": "https://discord.com/invite/dtBTQHYSx4", "title": "Support Server" }]
},
"icon": "PuzzlePieceIcon",
"essential": true,
"dependencies": {
Expand Down
5 changes: 4 additions & 1 deletion bundle/src/plugins/start/settings.themes/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
"id": "valenced.settings.themes",
"name": "Themes",
"description": "This feature requires an update to be installed.",
"author": "Valenced",
"author": {
"name": "Valenced",
"links": [{ "url": "https://discord.com/invite/dtBTQHYSx4", "title": "Support Server" }]
},
"icon": "PaintPaletteIcon",
"version": "0.0.0",
"enabledByDefault": true,
Expand Down
5 changes: 4 additions & 1 deletion bundle/src/plugins/start/settings/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
"id": "valenced.settings",
"name": "Settings",
"description": "Settings UI for Valenced.",
"author": "Valenced",
"author": {
"name": "Valenced",
"links": [{ "url": "https://discord.com/invite/dtBTQHYSx4", "title": "Support Server" }]
},
"icon": "SettingsIcon",
"essential": true
}
5 changes: 4 additions & 1 deletion bundle/src/plugins/start/staff-settings/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
"id": "valenced.staff-settings",
"name": "Staff Settings",
"description": "Allows accessing Discord's Staff Settings.",
"author": "Valenced",
"author": {
"name": "Valenced",
"links": [{ "url": "https://discord.com/invite/dtBTQHYSx4", "title": "Support Server" }]
},
"icon": "StaffBadgeIcon",
"enabledByDefault": true
}
5 changes: 4 additions & 1 deletion bundle/src/plugins/start/user-badges/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
"id": "valenced.user-badges",
"name": "User Badges",
"description": "Badges for Valenced contributors and sponsors.",
"author": "Valenced",
"author": {
"name": "Valenced",
"links": [{ "url": "https://discord.com/invite/dtBTQHYSx4", "title": "Support Server" }]
},
"icon": "ShieldUserIcon",
"essential": true
}
Loading