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