chore: lint-format-docs-tests-bugfixes (#105)
* docs: add jsdoc * feat: change enums to as const objects * chore(test): add themeColors.test.ts * fix: fix tests and bugs with strings.ts util * fix: path alias imports and tsconfig file bug * fix: remove --max-warnings 0
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable jsdoc/require-jsdoc */
|
||||
export default interface BrowserActionMessages {
|
||||
/** make it so that clicking the browser action will open the popup.html */
|
||||
enableBrowserAction: () => void;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable jsdoc/require-jsdoc */
|
||||
export default interface HotReloadingMessages {
|
||||
reloadExtension: () => void;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { Course } from '../types/Course';
|
||||
import type { Course } from '@shared/types/Course';
|
||||
|
||||
/**
|
||||
* Represents a collection of user schedule messages.
|
||||
*/
|
||||
export interface UserScheduleMessages {
|
||||
/**
|
||||
* Add a course to a schedule
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { createMessenger } from 'chrome-extension-toolkit';
|
||||
import BrowserActionMessages from './BrowserActionMessages';
|
||||
import TabManagementMessages from './TabManagementMessages';
|
||||
import TAB_MESSAGES from './TabMessages';
|
||||
import { UserScheduleMessages } from './UserScheduleMessages';
|
||||
|
||||
import type BrowserActionMessages from './BrowserActionMessages';
|
||||
import type TabManagementMessages from './TabManagementMessages';
|
||||
import type TAB_MESSAGES from './TabMessages';
|
||||
import type { UserScheduleMessages } from './UserScheduleMessages';
|
||||
|
||||
/**
|
||||
* This is a type with all the message definitions that can be sent TO the background script
|
||||
|
||||
@@ -15,6 +15,4 @@ export const ExtensionStore = createLocalStore<IExtensionStore>({
|
||||
lastUpdate: Date.now(),
|
||||
});
|
||||
|
||||
|
||||
|
||||
debugStore({ ExtensionStore });
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* eslint-disable max-classes-per-file */
|
||||
import { Serialized } from 'chrome-extension-toolkit';
|
||||
import { CourseMeeting } from './CourseMeeting';
|
||||
import type { Serialized } from 'chrome-extension-toolkit';
|
||||
|
||||
import type { CourseMeeting } from './CourseMeeting';
|
||||
import { CourseSchedule } from './CourseSchedule';
|
||||
import Instructor from './Instructor';
|
||||
|
||||
@@ -12,12 +12,17 @@ export type InstructionMode = 'Online' | 'In Person' | 'Hybrid';
|
||||
/**
|
||||
* The status of a course (e.g. open, closed, waitlisted, cancelled)
|
||||
*/
|
||||
export enum Status {
|
||||
OPEN = 'OPEN',
|
||||
CLOSED = 'CLOSED',
|
||||
WAITLISTED = 'WAITLISTED',
|
||||
CANCELLED = 'CANCELLED',
|
||||
}
|
||||
export const Status = {
|
||||
OPEN: 'OPEN',
|
||||
CLOSED: 'CLOSED',
|
||||
WAITLISTED: 'WAITLISTED',
|
||||
CANCELLED: 'CANCELLED',
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* Represents the type of status for a course.
|
||||
*/
|
||||
export type StatusType = (typeof Status)[keyof typeof Status];
|
||||
|
||||
/**
|
||||
* Represents a semester, with the year and the season for when a course is offered
|
||||
@@ -49,7 +54,7 @@ export class Course {
|
||||
/** The number of credits that a course is worth */
|
||||
creditHours: number;
|
||||
/** Is the course open, closed, waitlisted, or cancelled? */
|
||||
status: Status;
|
||||
status: StatusType;
|
||||
/** all the people that are teaching this course, and some metadata about their names */
|
||||
instructors: Instructor[];
|
||||
/** Some courses at UT are reserved for certain groups of people or people within a certain major, which makes it difficult for people outside of that group to register for the course. */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Serialized } from 'chrome-extension-toolkit';
|
||||
import type { Serialized } from 'chrome-extension-toolkit';
|
||||
|
||||
/**
|
||||
* a map of the days of the week that a class is taught, and the corresponding abbreviation
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Serialized } from 'chrome-extension-toolkit';
|
||||
import { CourseMeeting, Day, DAY_MAP } from './CourseMeeting';
|
||||
import type { Serialized } from 'chrome-extension-toolkit';
|
||||
|
||||
import type { Day } from './CourseMeeting';
|
||||
import { CourseMeeting, DAY_MAP } from './CourseMeeting';
|
||||
|
||||
/**
|
||||
* This represents the schedule for a course, which includes all the meeting times for the course, as well as helper functions for parsing, serializing, and deserializing the schedule
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* eslint-disable max-classes-per-file */
|
||||
import { PointOptionsObject } from 'highcharts';
|
||||
|
||||
import { Semester } from './Course';
|
||||
/**
|
||||
* Each of the possible letter grades that can be given in a course
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Serialized } from 'chrome-extension-toolkit';
|
||||
import type { Serialized } from 'chrome-extension-toolkit';
|
||||
|
||||
import { capitalize } from '../util/string';
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Serialized } from 'chrome-extension-toolkit';
|
||||
import type { Serialized } from 'chrome-extension-toolkit';
|
||||
|
||||
import { Course } from './Course';
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
import { theme } from 'unocss/preset-mini';
|
||||
|
||||
/**
|
||||
* Represents the colors for a course.
|
||||
*/
|
||||
export interface CourseColors {
|
||||
primaryColor: string;
|
||||
secondaryColor: string;
|
||||
}
|
||||
|
||||
// calculates luminance of a hex string
|
||||
/**
|
||||
* Calculates the luminance of a given hexadecimal color.
|
||||
*
|
||||
* @param hex - The hexadecimal color value.
|
||||
* @returns The luminance value between 0 and 1.
|
||||
*/
|
||||
export function getLuminance(hex: string): number {
|
||||
let r = parseInt(hex.substring(1, 3), 16);
|
||||
let g = parseInt(hex.substring(3, 5), 16);
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
import React, { SVGProps } from 'react';
|
||||
import type { StatusType } from '@shared/types/Course';
|
||||
import { Status } from '@shared/types/Course';
|
||||
import type { SVGProps } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import ClosedIcon from '~icons/material-symbols/lock';
|
||||
import WaitlistIcon from '~icons/material-symbols/timelapse';
|
||||
import CancelledIcon from '~icons/material-symbols/warning';
|
||||
import { Status } from '../types/Course';
|
||||
|
||||
/**
|
||||
* Get Icon component based on status
|
||||
* @param props.status status
|
||||
* @returns React.ReactElement - the icon component
|
||||
*/
|
||||
export function StatusIcon(props: SVGProps<SVGSVGElement> & { status: Status }): React.ReactElement {
|
||||
export function StatusIcon(props: SVGProps<SVGSVGElement> & { status: StatusType }): React.ReactElement {
|
||||
const { status, ...rest } = props;
|
||||
|
||||
switch (props.status) {
|
||||
|
||||
@@ -18,6 +18,8 @@ export function capitalize(input: string): string {
|
||||
}
|
||||
capitalized += ' ';
|
||||
}
|
||||
capitalized = capitalized.trim(); // Remove extra space
|
||||
|
||||
return capitalized;
|
||||
}
|
||||
|
||||
@@ -31,7 +33,7 @@ export function capitalizeFirstLetter(input: string): string {
|
||||
}
|
||||
|
||||
/**
|
||||
* Cuts the
|
||||
* Cuts the input string to the specified length and adds an ellipsis if the string is longer than the specified length.
|
||||
* @param input The string to ellipsify.
|
||||
* @param length The length of the string to return.
|
||||
* @returns The ellipsified string.
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { capitalize } from '../string';
|
||||
import { capitalize, capitalizeFirstLetter, ellipsify } from '../string';
|
||||
|
||||
// TODO: Fix `string.ts` and `string.test.ts` to make the tests pass
|
||||
// `capitalize` is adding an extra space at the end of the word.
|
||||
describe('capitalize', () => {
|
||||
it('should capitalize the first letter of each word', () => {
|
||||
// Debug
|
||||
const word = 'hello world';
|
||||
const capitalized = capitalize(word);
|
||||
console.log(capitalize(word));
|
||||
console.log(capitalized.length);
|
||||
console.log(capitalized.split(''));
|
||||
// const word = 'hello world';
|
||||
// const capitalized = capitalize(word);
|
||||
// console.log(capitalize(word));
|
||||
// console.log(capitalized.length);
|
||||
// console.log(capitalized.split(''));
|
||||
|
||||
// Test case 1: Single word
|
||||
expect(capitalize('hello')).toBe('Hello');
|
||||
@@ -25,15 +25,40 @@ describe('capitalize', () => {
|
||||
// Test case 4: Words with hyphens and spaces
|
||||
expect(capitalize('hello-world test')).toBe('Hello-World Test');
|
||||
});
|
||||
});
|
||||
|
||||
it('should not change the capitalization of the remaining letters', () => {
|
||||
// Test case 1: All lowercase
|
||||
expect(capitalize('hello')).toBe('Hello');
|
||||
describe('capitalizeFirstLetter', () => {
|
||||
it('should return a string with the first letter capitalized', () => {
|
||||
// Test case 1: Single word
|
||||
expect(capitalizeFirstLetter('hello')).toBe('Hello');
|
||||
|
||||
// Test case 2: All uppercase
|
||||
expect(capitalize('WORLD')).toBe('WORLD');
|
||||
// Test case 2: Word with all lowercase letters
|
||||
expect(capitalizeFirstLetter('world')).toBe('World');
|
||||
|
||||
// Test case 3: Mixed case
|
||||
expect(capitalize('HeLLo WoRLd')).toBe('Hello World');
|
||||
// Test case 3: Word with all uppercase letters
|
||||
expect(capitalizeFirstLetter('EXAMPLE')).toBe('Example');
|
||||
|
||||
// Test case 4: Word with mixed case letters
|
||||
expect(capitalizeFirstLetter('tEsT')).toBe('Test');
|
||||
});
|
||||
|
||||
it('should handle empty string input', () => {
|
||||
expect(capitalizeFirstLetter('')).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ellipsify', () => {
|
||||
it('should add ellipsis if the input string exceeds the specified character limit', () => {
|
||||
// Test case 1: Input string is shorter than the character limit
|
||||
expect(ellipsify('Hello', 10)).toBe('Hello');
|
||||
|
||||
// Test case 2: Input string is equal to the character limit
|
||||
expect(ellipsify('Hello World', 11)).toBe('Hello World');
|
||||
|
||||
// Test case 3: Input string is longer than the character limit
|
||||
expect(ellipsify('Hello World', 5)).toBe('Hello...');
|
||||
|
||||
// Test case 4: Input string is empty
|
||||
expect(ellipsify('', 5)).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
51
src/shared/util/tests/themeColors.test.ts
Normal file
51
src/shared/util/tests/themeColors.test.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { getThemeColorHexByName, getThemeColorRgbByName, hexToRgb } from '../themeColors';
|
||||
|
||||
describe('hexToRgb', () => {
|
||||
it('should convert hex color to RGB', () => {
|
||||
expect(hexToRgb('#BF5700')).toEqual([191, 87, 0]);
|
||||
expect(hexToRgb('#333F48')).toEqual([51, 63, 72]);
|
||||
expect(hexToRgb('#f8971f')).toEqual([248, 151, 31]);
|
||||
expect(hexToRgb('#ffd600')).toEqual([255, 214, 0]);
|
||||
expect(hexToRgb('#a6cd57')).toEqual([166, 205, 87]);
|
||||
expect(hexToRgb('#579d42')).toEqual([87, 157, 66]);
|
||||
expect(hexToRgb('#00a9b7')).toEqual([0, 169, 183]);
|
||||
expect(hexToRgb('#005f86')).toEqual([0, 95, 134]);
|
||||
expect(hexToRgb('#9cadb7')).toEqual([156, 173, 183]);
|
||||
expect(hexToRgb('#d6d2c4')).toEqual([214, 210, 196]);
|
||||
expect(hexToRgb('#95a5a6')).toEqual([149, 165, 166]);
|
||||
expect(hexToRgb('#B91C1C')).toEqual([185, 28, 28]);
|
||||
expect(hexToRgb('#af2e2d')).toEqual([175, 46, 45]);
|
||||
expect(hexToRgb('#1a2024')).toEqual([26, 32, 36]);
|
||||
expect(hexToRgb('#22c55e')).toEqual([34, 197, 94]);
|
||||
expect(hexToRgb('#a3e635')).toEqual([163, 230, 53]);
|
||||
expect(hexToRgb('#84CC16')).toEqual([132, 204, 22]);
|
||||
expect(hexToRgb('#FDE047')).toEqual([253, 224, 71]);
|
||||
expect(hexToRgb('#FACC15')).toEqual([250, 204, 21]);
|
||||
expect(hexToRgb('#F59E0B')).toEqual([245, 158, 11]);
|
||||
expect(hexToRgb('#FB923C')).toEqual([251, 146, 60]);
|
||||
expect(hexToRgb('#F97316')).toEqual([249, 115, 22]);
|
||||
expect(hexToRgb('#EA580C')).toEqual([234, 88, 12]);
|
||||
expect(hexToRgb('#DC2626')).toEqual([220, 38, 38]);
|
||||
expect(hexToRgb('#B91C1C')).toEqual([185, 28, 28]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getThemeColorHexByName', () => {
|
||||
it('should return the hex color value by name', () => {
|
||||
expect(getThemeColorHexByName('ut-burntorange')).toEqual('#BF5700');
|
||||
expect(getThemeColorHexByName('ut-offwhite')).toEqual('#D6D2C4');
|
||||
expect(getThemeColorHexByName('ut-black')).toEqual('#333F48');
|
||||
// Add more test cases for other theme color names
|
||||
});
|
||||
});
|
||||
|
||||
describe('getThemeColorRgbByName', () => {
|
||||
it('should return the RGB color value by name', () => {
|
||||
expect(getThemeColorRgbByName('ut-burntorange')).toEqual([191, 87, 0]);
|
||||
expect(getThemeColorRgbByName('ut-offwhite')).toEqual([214, 210, 196]);
|
||||
expect(getThemeColorRgbByName('ut-black')).toEqual([51, 63, 72]);
|
||||
// Add more test cases for other theme color names
|
||||
});
|
||||
});
|
||||
@@ -2,24 +2,24 @@ export const colors = {
|
||||
ut: {
|
||||
burntorange: '#BF5700',
|
||||
black: '#333F48',
|
||||
orange: '#f8971f',
|
||||
yellow: '#ffd600',
|
||||
lightgreen: '#a6cd57',
|
||||
green: '#579d42',
|
||||
teal: '#00a9b7',
|
||||
blue: '#005f86',
|
||||
gray: '#9cadb7',
|
||||
offwhite: '#d6d2c4',
|
||||
concrete: '#95a5a6',
|
||||
red: '#B91C1C' // Not sure if this should be here, but it's used for remove course, and add course is ut-green
|
||||
orange: '#F8971F',
|
||||
yellow: '#FFD600',
|
||||
lightgreen: '#A6CD57',
|
||||
green: '#579D42',
|
||||
teal: '#00A9B7',
|
||||
blue: '#005F86',
|
||||
gray: '#9CADB7',
|
||||
offwhite: '#D6D2C4',
|
||||
concrete: '#95A5A6',
|
||||
red: '#B91C1C', // Not sure if this should be here, but it's used for remove course, and add course is ut-green
|
||||
},
|
||||
theme: {
|
||||
red: '#af2e2d',
|
||||
black: '#1a2024',
|
||||
red: '#AF2E2D',
|
||||
black: '#1A2024',
|
||||
},
|
||||
gradeDistribution: {
|
||||
a: '#22c55e',
|
||||
aminus: '#a3e635',
|
||||
a: '#22C55E',
|
||||
aminus: '#A3E635',
|
||||
bplus: '#84CC16',
|
||||
b: '#FDE047',
|
||||
bminus: '#FACC15',
|
||||
@@ -31,7 +31,7 @@ export const colors = {
|
||||
dminus: '#B91C1C',
|
||||
f: '#B91C1C',
|
||||
},
|
||||
} as const;
|
||||
} as const satisfies Record<string, Record<string, string>>;
|
||||
|
||||
type NestedKeys<T> = {
|
||||
[K in keyof T]: T[K] extends Record<string, any> ? `${string & K}-${string & keyof T[K]}` : never;
|
||||
@@ -42,6 +42,10 @@ type NestedKeys<T> = {
|
||||
*/
|
||||
export type ThemeColor = NestedKeys<typeof colors>;
|
||||
|
||||
/**
|
||||
* Flattened colors object.
|
||||
* @type {Record<ThemeColor, string>}
|
||||
*/
|
||||
export const colorsFlattened = Object.entries(colors).reduce(
|
||||
(acc, [prefix, group]) => {
|
||||
for (const [name, hex] of Object.entries(group)) {
|
||||
@@ -52,9 +56,18 @@ export const colorsFlattened = Object.entries(colors).reduce(
|
||||
{} as Record<ThemeColor, string>
|
||||
);
|
||||
|
||||
const hexToRgb = (hex: string) =>
|
||||
/**
|
||||
* Converts a hexadecimal color code to an RGB color array.
|
||||
* @param hex The hexadecimal color code to convert.
|
||||
* @returns An array representing the RGB color values.
|
||||
*/
|
||||
export const hexToRgb = (hex: string) =>
|
||||
hex.match(/[0-9a-f]{2}/gi).map(partialHex => parseInt(partialHex, 16)) as [number, number, number];
|
||||
|
||||
/**
|
||||
* Represents the flattened RGB values of the colors.
|
||||
* @type {Record<ThemeColor, ReturnType<typeof hexToRgb>>}
|
||||
*/
|
||||
const colorsFlattenedRgb = Object.fromEntries(
|
||||
Object.entries(colorsFlattened).map(([name, hex]) => [name, hexToRgb(hex)])
|
||||
) as Record<ThemeColor, ReturnType<typeof hexToRgb>>;
|
||||
|
||||
@@ -5,7 +5,9 @@ export const HOUR = 60 * MINUTE;
|
||||
export const DAY = 24 * HOUR;
|
||||
|
||||
/**
|
||||
*
|
||||
* Pauses the execution for the specified number of milliseconds.
|
||||
* @param milliseconds - The number of milliseconds to sleep.
|
||||
* @returns A promise that resolves after the specified number of milliseconds.
|
||||
*/
|
||||
export const sleep = (milliseconds: number): Promise<void> => new Promise(resolve => setTimeout(resolve, milliseconds));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user