Skip to content

Commit

Permalink
Merge pull request #8856 from weseek/support/add-theme-plugin-validator
Browse files Browse the repository at this point in the history
support: Add theme plugin validator
  • Loading branch information
yuki-takei authored May 29, 2024
2 parents 96e3edf + ea12546 commit c411367
Show file tree
Hide file tree
Showing 10 changed files with 165 additions and 2 deletions.
6 changes: 6 additions & 0 deletions .changeset/nine-keys-hide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@growi/pluginkit': minor
'@growi/core': minor
---

Add vaidator for GROWI theme plugins
18 changes: 18 additions & 0 deletions packages/core/src/interfaces/growi-theme-metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,21 @@ export type GrowiThemeMetadata = {
createBtn: string,
isPresetTheme?: boolean,
};

export const isGrowiThemeMetadata = (obj: unknown): obj is GrowiThemeMetadata => {
const objAny = obj as any;

return objAny != null
&& typeof objAny === 'object'
&& Array.isArray(objAny) === false
&& 'name' in objAny && typeof objAny.name === 'string'
&& 'manifestKey' in objAny && typeof objAny.manifestKey === 'string'
&& 'schemeType' in objAny && typeof objAny.schemeType === 'string'
&& 'lightBg' in objAny && typeof objAny.lightBg === 'string'
&& 'darkBg' in objAny && typeof objAny.darkBg === 'string'
&& 'lightSidebar' in objAny && typeof objAny.lightSidebar === 'string'
&& 'darkSidebar' in objAny && typeof objAny.darkSidebar === 'string'
&& 'lightIcon' in objAny && typeof objAny.lightIcon === 'string'
&& 'darkIcon' in objAny && typeof objAny.darkIcon === 'string'
&& 'createBtn' in objAny && typeof objAny.createBtn === 'string';
};
8 changes: 6 additions & 2 deletions packages/pluginkit/src/model/growi-plugin-validation-data.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { GrowiPluginType } from '@growi/core';
import type { GrowiPluginType, GrowiThemeMetadata } from '@growi/core';

import { GrowiPluginDirective } from './growi-plugin-package-data';
import type { GrowiPluginDirective } from './growi-plugin-package-data';

export type GrowiPluginValidationData = {
projectDirRoot: string,
Expand All @@ -13,3 +13,7 @@ export type GrowiPluginValidationData = {
export type GrowiTemplatePluginValidationData = GrowiPluginValidationData & {
supportingLocales: string[],
}

export type GrowiThemePluginValidationData = GrowiPluginValidationData & {
themes: GrowiThemeMetadata[],
}
1 change: 1 addition & 0 deletions packages/pluginkit/src/v4/server/utils/theme/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './validate-growi-plugin-directive';
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import path from 'path';

import { isGrowiThemeMetadata } from '@growi/core';

import { validateThemePluginGrowiDirective } from './validate-growi-plugin-directive';


describe('validateThemePluginGrowiDirective()', () => {

it('returns a data object', async() => {
// setup
const projectDirRoot = path.resolve(__dirname, '../../../../../test/fixtures/example-package/theme1');

// when
const data = validateThemePluginGrowiDirective(projectDirRoot);

// then
expect(data).not.toBeNull();
expect(data.growiPlugin).not.toBeNull();
expect(data.themes).not.toBeNull();
expect(isGrowiThemeMetadata(data.themes[0])).toBeTruthy();
});

describe('should throw an GrowiPluginValidationError', () => {

it("when the pkg does not have 'growiPlugin.themes' directive", () => {
// setup
const projectDirRoot = path.resolve(__dirname, '../../../../../test/fixtures/example-package/invalid-theme1');

// when
const caller = () => { validateThemePluginGrowiDirective(projectDirRoot) };

// then
expect(caller).toThrow("Theme plugin must have 'themes' array and that must have one or more theme metadata");
});

it("when the pkg does not have 'growiPlugin.locale' directive", () => {
// setup
const projectDirRoot = path.resolve(__dirname, '../../../../../test/fixtures/example-package/invalid-theme2');

// when
const caller = () => { validateThemePluginGrowiDirective(projectDirRoot) };

// then
expect(caller).toThrow(/^Some of theme metadata are invalid:/);
});

});

});
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import type { GrowiThemeMetadata } from '@growi/core';
import { GrowiPluginType, isGrowiThemeMetadata } from '@growi/core';

import type { GrowiPluginValidationData, GrowiThemePluginValidationData } from '../../../../model';
import { GrowiPluginValidationError } from '../../../../model';
import { validateGrowiDirective } from '../common';


/**
* An utility for theme plugin which wrap 'validateGrowiDirective' of './common' module
* @param projectDirRoot
*/
export const validateThemePluginGrowiDirective = (projectDirRoot: string): GrowiThemePluginValidationData => {
const data = validateGrowiDirective(projectDirRoot, GrowiPluginType.Theme);

const { growiPlugin } = data;

// check themes
if (growiPlugin.themes == null || !Array.isArray(growiPlugin.themes) || growiPlugin.themes.length === 0) {
throw new GrowiPluginValidationError<GrowiPluginValidationData>(
"Theme plugin must have 'themes' array and that must have one or more theme metadata",
);
}

const validMetadatas: GrowiThemeMetadata[] = [];
const invalidObjects: unknown[] = [];
growiPlugin.themes.forEach((theme: unknown) => {
if (isGrowiThemeMetadata(theme)) {
validMetadatas.push(theme);
}
else {
invalidObjects.push(theme);
}
});

if (invalidObjects.length > 0) {
throw new GrowiPluginValidationError<GrowiPluginValidationData>(
`Some of theme metadata are invalid: ${invalidObjects.toString()}`,
);
}

return {
...data,
themes: validMetadatas,
};
};
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "example-package-invalid-theme1",
"version": "1.0.0",
"main": "index.js",
"growiPlugin": {
"schemaVersion": "4",
"types": ["theme"]
}
}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "example-package-invalid-theme2",
"version": "1.0.0",
"main": "index.js",
"growiPlugin": {
"schemaVersion": "4",
"types": ["theme"],
"themes": [
{
"name": "theme2-1",
"manifestKey": "src/styles/style.scss",
"schemeType": "light",
"lightBg": "#ff0000",
"darkBg": "#0000ff",
"lightSidebar": "#ffff00",
"darkSidebar": "#ff8800",
"lightIcon": "#ff0000",
"darkIcon": "#000000",
"createBtn": "#00ff00"
},
{
"name": "theme2-2",
"manifestKey": "src/styles/style.scss",
"schemeType": "light",
"// missing some attributes": ""
}
]
}
}

0 comments on commit c411367

Please sign in to comment.