chore: enable svelte-check (#992)

chore: enable svelte check on the repository on each PR
allows to check if code is valid

For now threshold is at error but it should be turned to hints

Change-Id: Id1af31a438775f38c8cf37ad75552fea9f21fe3e
Signed-off-by: Florent Benoit <fbenoit@redhat.com>

Signed-off-by: Florent Benoit <fbenoit@redhat.com>
This commit is contained in:
Florent BENOIT 2022-12-08 17:06:45 +01:00 committed by GitHub
parent f71dd4b0be
commit acbbfd0905
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 100 additions and 63 deletions

View file

@ -202,3 +202,9 @@ jobs:
- name: Run unit tests
run: yarn test
- name: Run generate-types (required to run svelte check)
run: yarn generate-types
- name: Run svelte check
run: yarn svelte:check

View file

@ -43,10 +43,12 @@
"test:renderer": "vitest run -r packages/renderer --passWithNoTests",
"test:watch": "vitest watch",
"watch": "node scripts/watch.js",
"generate-types": "node scripts/watch.js --types-only",
"format:check": "prettier --check '{extensions,packages,tests,types}/**/*.{ts,svelte}' 'extensions/*/scripts/build.js' 'website/*.js' 'website/src/**/*.{css,tsx}'",
"format:fix": "prettier --write '{extensions,packages,tests,types}/**/*.{ts,svelte}' 'extensions/*/scripts/build.js' 'website/src/**/*.{css,tsx}'",
"lint:check": "eslint . --ext js,ts,tsx",
"lint:fix": "eslint . --fix --ext js,ts,tsx",
"svelte:check": "svelte-check",
"typecheck:main": "tsc --noEmit -p packages/main/tsconfig.json",
"typecheck:preload": "tsc --noEmit -p packages/preload/tsconfig.json",
"typecheck:renderer": "npm run build:preload:types",

View file

@ -305,7 +305,7 @@ const processPasswordElement = (node: HTMLInputElement, registry: Registry) => {
<DropdownMenuItem
title="Login"
onClick="{() => markRegistryAsModified(registry)}"
hidden="{registry.username && registry.secret}"
hidden="{!!registry.username && !!registry.secret}"
icon="{faUser}" />
<DropdownMenuItem
title="Edit password"

View file

@ -25,15 +25,15 @@ beforeEach(() => {
test('Should expect invalid domain', async () => {
const result = urlValidator()('my_invalid_domain');
expect(result).toBe('Please enter a valid URL');
expect(result[1]).toBe('Please enter a valid URL');
});
test('Should expect valid domain', async () => {
const result = urlValidator()('valid.com');
expect(result).toBe(true);
expect(result[0]).toBe(true);
});
test('Should expect valid TLD domain with more than 3 char domains', async () => {
const result = urlValidator()('foobar.mydomain.science');
expect(result).toBe(true);
expect(result[0]).toBe(true);
});

View file

@ -25,52 +25,73 @@ interface Validation {
message?: string;
}
export function createFieldValidator(...validators) {
const { subscribe, set } = writable({ dirty: false, valid: false, message: null } as Validation);
export type UpdateAction = {
update(value: string): void;
};
export type ActivateFunction = {
(_node: unknown, binding: unknown): UpdateAction;
};
export function createFieldValidator(...validators): [SvelteStore<Validation>, ActivateFunction] {
const validation: Validation = { dirty: false, valid: false, message: null };
const writableObject = writable<Validation>(validation);
const validator = buildValidator(validators);
function action(node, binding) {
function validate(value, dirty) {
function action(_node, binding): UpdateAction {
function validate(value: string, dirty: boolean) {
const result = validator(value, dirty);
set(result);
writableObject.set(result);
}
validate(binding, false);
return {
update(value) {
update(value: string): void {
validate(value, value !== undefined);
},
};
}
return [{ subscribe }, action];
const store: SvelteStore<Validation> = writableObject;
const tuple: [SvelteStore<Validation>, ActivateFunction] = [store, action];
return tuple;
}
function buildValidator(validators) {
return function validate(value, dirty) {
function buildValidator(
validators: ((value: string) => [boolean, string])[],
): (value: string, dirty: boolean) => Validation {
return function validate(value: string, dirty: boolean): Validation {
if (!validators || validators.length === 0) {
return { dirty, valid: true };
}
const failing = validators.find(v => v(value) !== true);
const failing = validators.map(v => v(value)).find(value => value[0] !== true);
return {
dirty,
valid: !failing,
message: failing && failing(value),
} as Validation;
if (!failing) {
return { dirty, valid: true, message: '' };
} else {
return {
dirty,
valid: false,
message: failing[1],
};
}
};
}
export function requiredValidator() {
return function required(value) {
return (value !== undefined && value !== '') || 'Field is required';
export function requiredValidator(): (value: string) => [boolean, string] {
return function required(value: string): [boolean, string] {
const valid = value !== undefined && value !== '';
const message = valid ? '' : 'Field is required';
return [valid, message];
};
}
export function urlValidator() {
return function url(value) {
return validator.isURL(value) || 'Please enter a valid URL';
export function urlValidator(): (value: string) => [boolean, string] {
return function url(value: string): [boolean, string] {
const valid = validator.isURL(value);
const message = valid ? '' : 'Please enter a valid URL';
return [valid, message];
};
}

View file

@ -1,19 +1,17 @@
#!/usr/bin/env node
const {createServer, build, createLogger} = require('vite');
const { createServer, build, createLogger } = require('vite');
const electronPath = require('electron');
const {spawn} = require('child_process');
const {generateAsync} = require('dts-for-context-bridge');
const { spawn } = require('child_process');
const { generateAsync } = require('dts-for-context-bridge');
const path = require('path');
/** @type 'production' | 'development'' */
const mode = process.env.MODE = process.env.MODE || 'development';
const mode = (process.env.MODE = process.env.MODE || 'development');
/** @type {import('vite').LogLevel} */
const LOG_LEVEL = 'info';
/** @type {import('vite').InlineConfig} */
const sharedConfig = {
mode,
@ -34,20 +32,19 @@ const stderrFilterPatterns = [
/**
* @param {{name: string; configFile: string; writeBundle: import('rollup').OutputPlugin['writeBundle'] }} param0
*/
const getWatcher = ({name, configFile, writeBundle}) => {
const getWatcher = ({ name, configFile, writeBundle }) => {
return build({
...sharedConfig,
configFile,
plugins: [{name, writeBundle}],
plugins: [{ name, writeBundle }],
});
};
/**
* Start or restart App when source files are changed
* @param {{config: {server: import('vite').ResolvedServerOptions}}} ResolvedServerOptions
*/
const setupMainPackageWatcher = ({config: {server}}) => {
const setupMainPackageWatcher = ({ config: { server } }) => {
// Create VITE_DEV_SERVER_URL environment variable to pass it to the main process.
{
const protocol = server.https ? 'https:' : 'http:';
@ -74,13 +71,13 @@ const setupMainPackageWatcher = ({config: {server}}) => {
spawnProcess = null;
}
spawnProcess = spawn(String(electronPath), ['.'], { env: {...process.env, ELECTRON_IS_DEV: 1} });
spawnProcess = spawn(String(electronPath), ['.'], { env: { ...process.env, ELECTRON_IS_DEV: 1 } });
spawnProcess.stdout.on('data', d => d.toString().trim() && logger.warn(d.toString(), {timestamp: true}));
spawnProcess.stdout.on('data', d => d.toString().trim() && logger.warn(d.toString(), { timestamp: true }));
spawnProcess.stderr.on('data', d => {
const data = d.toString().trim();
if (!data) return;
const mayIgnore = stderrFilterPatterns.some((r) => r.test(data));
const mayIgnore = stderrFilterPatterns.some(r => r.test(data));
if (mayIgnore) return;
logger.error(data, { timestamp: true });
});
@ -91,12 +88,11 @@ const setupMainPackageWatcher = ({config: {server}}) => {
});
};
/**
* Start or restart App when source files are changed
* @param {{ws: import('vite').WebSocketServer}} WebSocketServer
*/
const setupPreloadPackageWatcher = ({ws}) =>
const setupPreloadPackageWatcher = ({ ws }) =>
getWatcher({
name: 'reload-page-on-preload-package-change',
configFile: 'packages/preload/vite.config.js',
@ -106,14 +102,15 @@ const setupPreloadPackageWatcher = ({ws}) =>
input: 'packages/preload/tsconfig.json',
output: 'packages/preload/exposedInMainWorld.d.ts',
});
ws.send({
type: 'full-reload',
});
if (ws) {
ws.send({
type: 'full-reload',
});
}
},
});
const setupPreloadDockerExtensionPackageWatcher = ({ws}) =>
const setupPreloadDockerExtensionPackageWatcher = ({ ws }) =>
getWatcher({
name: 'reload-page-on-preload-docker-extension-package-change',
configFile: 'packages/preload-docker-extension/vite.config.js',
@ -124,37 +121,48 @@ const setupPreloadDockerExtensionPackageWatcher = ({ws}) =>
output: 'packages/preload-docker-extension/exposedInDockerExtension.d.ts',
});
ws.send({
type: 'full-reload',
});
if (ws) {
ws.send({
type: 'full-reload',
});
}
},
});
/**
* Start or restart App when source files are changed
* @param {{ws: import('vite').WebSocketServer}} WebSocketServer
*/
const setupExtensionApiWatcher = (name) =>{
let spawnProcess;
const folderName = path.resolve(__dirname, '../extensions/' + name);
const setupExtensionApiWatcher = name => {
let spawnProcess;
const folderName = path.resolve(__dirname, '../extensions/' + name);
console.log('dirname is', folderName);
spawnProcess = spawn('yarn', ['--cwd', folderName, 'watch'], { shell: process.platform === 'win32'} );
spawnProcess = spawn('yarn', ['--cwd', folderName, 'watch'], { shell: process.platform === 'win32' });
spawnProcess.stdout.on('data', d => d.toString().trim() && console.warn(d.toString(), {timestamp: true}));
spawnProcess.stderr.on('data', d => {
const data = d.toString().trim();
if (!data) return;
console.error(data, { timestamp: true });
});
spawnProcess.stdout.on('data', d => d.toString().trim() && console.warn(d.toString(), { timestamp: true }));
spawnProcess.stderr.on('data', d => {
const data = d.toString().trim();
if (!data) return;
console.error(data, { timestamp: true });
});
// Stops the watch script when the application has been quit
spawnProcess.on('exit', process.exit);
};
// Stops the watch script when the application has been quit
spawnProcess.on('exit', process.exit);
};
(async () => {
// grab arguments
const args = process.argv.slice(2);
const generateTypesOnly = args.includes('--types-only');
// If types-only is passed, we don't watch for changes but only do generation
if (generateTypesOnly) {
delete sharedConfig.build.watch;
await setupPreloadPackageWatcher({ ws: undefined });
await setupPreloadDockerExtensionPackageWatcher({ ws: undefined });
return;
}
try {
const viteDevServer = await createServer({
...sharedConfig,