generated from nhcarrigan/template
Port in some older solutions I've written just to get the structure established and in place.
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
name: Node.js CI
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint and Test
|
||||
|
||||
steps:
|
||||
- name: Checkout Source Files
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Use Node.js v22
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- name: Install Dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Lint Source Files
|
||||
run: pnpm run lint
|
||||
|
||||
- name: Verify Build
|
||||
run: pnpm run build
|
||||
|
||||
- name: Run Tests
|
||||
run: pnpm run test
|
||||
@@ -0,0 +1 @@
|
||||
node_modules
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit"
|
||||
},
|
||||
"eslint.validate": ["typescript"]
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import NaomisConfig from '@nhcarrigan/eslint-config';
|
||||
|
||||
export default [
|
||||
...NaomisConfig,
|
||||
{
|
||||
rules: {
|
||||
'max-lines-per-function': 'off',
|
||||
'max-statements': 'off',
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['src/**/*.spec.ts'],
|
||||
rules: {
|
||||
'max-nested-callbacks': 'off',
|
||||
}
|
||||
}
|
||||
];
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "dsa",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "prod/index.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"start": "tsx src/index.ts",
|
||||
"lint": "eslint src --max-warnings 0",
|
||||
"test": "vitest run --coverage"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"packageManager": "pnpm@10.22.0",
|
||||
"devDependencies": {
|
||||
"@nhcarrigan/eslint-config": "5.2.0",
|
||||
"@nhcarrigan/typescript-config": "4.0.0",
|
||||
"@types/node": "24.10.1",
|
||||
"@vitest/coverage-v8": "4.0.10",
|
||||
"eslint": "9.39.1",
|
||||
"tsx": "4.20.6",
|
||||
"typescript": "5.9.3",
|
||||
"vitest": "4.0.10"
|
||||
}
|
||||
}
|
||||
Generated
+4256
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @copyright NHCarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { mineColor } from "./main.js";
|
||||
|
||||
describe("mineColor", () => {
|
||||
it("should return white if the square is white", () => {
|
||||
expect(mineColor("a", 8)).toBe("white");
|
||||
expect(mineColor("f", 5)).toBe("white");
|
||||
});
|
||||
|
||||
it("should return black if the square is black", () => {
|
||||
expect(mineColor("b", 2)).toBe("black");
|
||||
});
|
||||
|
||||
it("should handle empty strings", () => {
|
||||
expect(mineColor("", 1)).toBe("white");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* @copyright NHCarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
/**
|
||||
* Determines the color of a square on a chessboard based on its column and row.
|
||||
* @param column - The column of the square, represented as a letter ('a'-'h').
|
||||
* @param row - The row of the square, represented as a number (1-8).
|
||||
* @returns The color of the square, either "white" or "black".
|
||||
* @see https://www.codewars.com/kata/563319974612f4fa3f0000e0
|
||||
*/
|
||||
const mineColor = (column: string, row: number): string => {
|
||||
// Convert column letter ('a'-'h') to a number (1-8)
|
||||
const columnNumber
|
||||
= (column.toLowerCase().codePointAt(0) ?? 0)
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion, stylistic/no-mixed-operators -- "a" clearly has a code point at index 0. We're mixing operators because this is an old solution.
|
||||
- ("a".codePointAt(0)!) + 1;
|
||||
|
||||
// If the sum of column number and row is even, it's white
|
||||
if ((columnNumber + row) % 2 !== 0) {
|
||||
return "white";
|
||||
}
|
||||
return "black";
|
||||
};
|
||||
|
||||
export { mineColor };
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @copyright NHCarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { convert } from "./main.js";
|
||||
|
||||
describe("convert", () => {
|
||||
it("should return the correct heading", () => {
|
||||
expect(convert("# My level 1 heading")).toBe("<h1>My level 1 heading</h1>");
|
||||
expect(convert("My heading")).toBe("Invalid format");
|
||||
expect(convert("##### My level 5 heading")).toBe(
|
||||
"<h5>My level 5 heading</h5>",
|
||||
);
|
||||
expect(convert("#My heading")).toBe("Invalid format");
|
||||
expect(convert(" ### My level 3 heading")).toBe(
|
||||
"<h3>My level 3 heading</h3>",
|
||||
);
|
||||
expect(convert("####### My level 7 heading")).toBe("Invalid format");
|
||||
expect(convert("## My #2 heading")).toBe("<h2>My #2 heading</h2>");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* @copyright NHCarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
/**
|
||||
* Given a string representing a Markdown heading, return the equivalent HTML heading.
|
||||
* @param heading - The Markdown heading to convert.
|
||||
* @returns The equivalent HTML heading.
|
||||
* @see https://www.freecodecamp.org/learn/daily-coding-challenge/2025-11-19
|
||||
*/
|
||||
const convert = (heading: string): string => {
|
||||
if (!/^\s*#{1,6}\s+/.test(heading)) {
|
||||
return "Invalid format";
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- We know the regex will match and the group will be present.
|
||||
const level = /^\s*(?<level>#{1,6})\s+/.exec(heading)!.groups!.level!.length;
|
||||
return `<h${level.toString()}>${heading.replace(/^\s*#{1,6}\s+/, "").trim()}</h${level.toString()}>`;
|
||||
};
|
||||
|
||||
export { convert };
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @copyright NHCarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { backspaceCompare } from "./main.js";
|
||||
|
||||
describe("backspaceCompare", () => {
|
||||
it("should return true if the strings are equal", () => {
|
||||
expect(backspaceCompare("ab#c", "ad#c")).toBe(true);
|
||||
expect(backspaceCompare("ab##", "c#d#")).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false if the strings are not equal", () => {
|
||||
expect(backspaceCompare("ab#c", "b")).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @copyright NHCarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
/**
|
||||
* Compares two strings to see if they are equal when both are typed into empty text editors.
|
||||
* '#' means a backspace character.
|
||||
* @param s - The first string to compare.
|
||||
* @param t - The second string to compare.
|
||||
* @returns True if the strings are equal, false otherwise.
|
||||
* @see https://leetcode.com/problems/backspace-string-compare/description/
|
||||
*/
|
||||
const backspaceCompare = (s: string, t: string): boolean => {
|
||||
let sIndex = s.length - 1;
|
||||
let tIndex = t.length - 1;
|
||||
let sSkips = 0;
|
||||
let tSkips = 0;
|
||||
|
||||
while (sIndex >= 0 || tIndex >= 0) {
|
||||
while (sIndex >= 0) {
|
||||
if (s[sIndex] === "#") {
|
||||
sSkips = sSkips + 1;
|
||||
sIndex = sIndex - 1;
|
||||
} else if (sSkips > 0) {
|
||||
sSkips = sSkips - 1;
|
||||
sIndex = sIndex - 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (tIndex >= 0) {
|
||||
if (t[tIndex] === "#") {
|
||||
tSkips = tSkips + 1;
|
||||
tIndex = tIndex - 1;
|
||||
} else if (tSkips > 0) {
|
||||
tSkips = tSkips - 1;
|
||||
tIndex = tIndex - 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (s[sIndex] !== t[tIndex]) {
|
||||
return false;
|
||||
}
|
||||
sIndex = sIndex - 1;
|
||||
tIndex = tIndex - 1;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
export { backspaceCompare };
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "@nhcarrigan/typescript-config",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"noEmit": true
|
||||
},
|
||||
"exclude": ["vitest.config.ts"]
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { defineConfig } from 'vitest/config'
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
coverage: {
|
||||
provider: 'v8',
|
||||
reporter: ['text'],
|
||||
include: ['src/**/*.ts'],
|
||||
exclude: ['src/**/*.spec.ts'],
|
||||
thresholds: {
|
||||
statements: 100,
|
||||
branches: 100,
|
||||
functions: 100,
|
||||
lines: 100,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
Reference in New Issue
Block a user