Grade school
This commit is contained in:
13
typescript/grade-school/.eslintignore
Normal file
13
typescript/grade-school/.eslintignore
Normal file
@@ -0,0 +1,13 @@
|
||||
!.meta
|
||||
|
||||
# Protected or generated
|
||||
.git
|
||||
.vscode
|
||||
|
||||
# When using npm
|
||||
node_modules/*
|
||||
|
||||
# Configuration files
|
||||
.eslintrc.cjs
|
||||
babel.config.cjs
|
||||
jest.config.cjs
|
||||
41
typescript/grade-school/.eslintrc.cjs
Normal file
41
typescript/grade-school/.eslintrc.cjs
Normal file
@@ -0,0 +1,41 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ['./tsconfig.json'],
|
||||
},
|
||||
overrides: [
|
||||
// Student provided files
|
||||
{
|
||||
files: ['*.ts'],
|
||||
excludedFiles: ['.meta/proof.ci.ts', '.meta/exemplar.ts', '*.test.ts'],
|
||||
extends: '@exercism/eslint-config-typescript',
|
||||
},
|
||||
// Exercism given tests
|
||||
{
|
||||
files: ['*.test.ts'],
|
||||
excludedFiles: ['custom.test.ts'],
|
||||
env: {
|
||||
jest: true,
|
||||
},
|
||||
extends: '@exercism/eslint-config-typescript/maintainers',
|
||||
},
|
||||
// Student provided tests
|
||||
{
|
||||
files: ['custom.test.ts'],
|
||||
env: {
|
||||
jest: true,
|
||||
},
|
||||
extends: '@exercism/eslint-config-typescript',
|
||||
},
|
||||
// Exercism provided files
|
||||
{
|
||||
files: ['.meta/proof.ci.ts', '.meta/exemplar.ts', '*.test.ts'],
|
||||
excludedFiles: ['custom.test.ts'],
|
||||
extends: '@exercism/eslint-config-typescript/maintainers',
|
||||
rules: {
|
||||
"@typescript-eslint/semi": 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
12
typescript/grade-school/.exercism/config.json
Normal file
12
typescript/grade-school/.exercism/config.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"blurb": "Given students' names along with the grade that they are in, create a roster for the school",
|
||||
"authors": ["masters3d"],
|
||||
"contributors": ["lukaszklis", "pedrorolo", "SleeplessByte"],
|
||||
"files": {
|
||||
"solution": ["grade-school.ts"],
|
||||
"test": ["grade-school.test.ts"],
|
||||
"example": [".meta/proof.ci.ts"]
|
||||
},
|
||||
"source": "A pairing session with Phil Battos at gSchool",
|
||||
"source_url": "http://gschool.it"
|
||||
}
|
||||
1
typescript/grade-school/.exercism/metadata.json
Normal file
1
typescript/grade-school/.exercism/metadata.json
Normal file
@@ -0,0 +1 @@
|
||||
{"track":"typescript","exercise":"grade-school","id":"35dfa4bfea7c4bda8252d9d6099423b9","url":"https://exercism.org/tracks/typescript/exercises/grade-school","handle":"briemens","is_requester":true,"auto_approve":false}
|
||||
44
typescript/grade-school/HELP.md
Normal file
44
typescript/grade-school/HELP.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# Help
|
||||
|
||||
## Running the tests
|
||||
|
||||
Execute the tests with:
|
||||
|
||||
```bash
|
||||
$ yarn test
|
||||
```
|
||||
|
||||
## Skipped tests
|
||||
|
||||
In the test suites all tests but the first have been skipped.
|
||||
|
||||
Once you get a test passing, you can enable the next one by changing `xit` to
|
||||
`it`.
|
||||
|
||||
## Submitting your solution
|
||||
|
||||
You can submit your solution using the `exercism submit grade-school.ts` command.
|
||||
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||
|
||||
It's possible to submit an incomplete solution which allows you to:
|
||||
|
||||
- See how others have completed the exercise
|
||||
- Request help from a mentor
|
||||
|
||||
## Need to get help?
|
||||
|
||||
If you'd like help solving the exercise, check the following pages:
|
||||
|
||||
- The [TypeScript track's documentation](https://exercism.org/docs/tracks/typescript)
|
||||
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
|
||||
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||
|
||||
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||
|
||||
To get help if you're having trouble, you can use one of the following resources:
|
||||
|
||||
- [TypeScript QuickStart](https://www.typescriptlang.org/docs/handbook/release-notes/overview.html)
|
||||
- [ECMAScript 2015 Language Specification](https://www.ecma-international.org/wp-content/uploads/ECMA-262_6th_edition_june_2015.pdf) (pdf)
|
||||
- [Mozilla JavaScript Reference](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference)
|
||||
- [/r/typescript](https://www.reddit.com/r/typescript) is the TypeScript subreddit.
|
||||
- [StackOverflow](https://stackoverflow.com/questions/tagged/typescript) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions.
|
||||
59
typescript/grade-school/README.md
Normal file
59
typescript/grade-school/README.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# Grade School
|
||||
|
||||
Welcome to Grade School on Exercism's TypeScript Track.
|
||||
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||
|
||||
## Instructions
|
||||
|
||||
Given students' names along with the grade that they are in, create a roster
|
||||
for the school.
|
||||
|
||||
In the end, you should be able to:
|
||||
|
||||
- Add a student's name to the roster for a grade
|
||||
- "Add Jim to grade 2."
|
||||
- "OK."
|
||||
- Get a list of all students enrolled in a grade
|
||||
- "Which students are in grade 2?"
|
||||
- "We've only got Jim just now."
|
||||
- Get a sorted list of all students in all grades. Grades should sort
|
||||
as 1, 2, 3, etc., and students within a grade should be sorted
|
||||
alphabetically by name.
|
||||
- "Who all is enrolled in school right now?"
|
||||
- "Let me think. We have
|
||||
Anna, Barb, and Charlie in grade 1,
|
||||
Alex, Peter, and Zoe in grade 2
|
||||
and Jim in grade 5.
|
||||
So the answer is: Anna, Barb, Charlie, Alex, Peter, Zoe and Jim"
|
||||
|
||||
Note that all our students only have one name. (It's a small town, what
|
||||
do you want?)
|
||||
|
||||
## For bonus points
|
||||
|
||||
Did you get the tests passing and the code clean? If you want to, these
|
||||
are some additional things you could try:
|
||||
|
||||
- If you're working in a language with mutable data structures and your
|
||||
implementation allows outside code to mutate the school's internal DB
|
||||
directly, see if you can prevent this. Feel free to introduce additional
|
||||
tests.
|
||||
|
||||
Then please share your thoughts in a comment on the submission. Did this
|
||||
experiment make the code better? Worse? Did you learn anything from it?
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @masters3d
|
||||
|
||||
### Contributed to by
|
||||
|
||||
- @lukaszklis
|
||||
- @pedrorolo
|
||||
- @SleeplessByte
|
||||
|
||||
### Based on
|
||||
|
||||
A pairing session with Phil Battos at gSchool - http://gschool.it
|
||||
4
typescript/grade-school/babel.config.cjs
Normal file
4
typescript/grade-school/babel.config.cjs
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
presets: ['@exercism/babel-preset-typescript'],
|
||||
plugins: [],
|
||||
}
|
||||
86
typescript/grade-school/grade-school.test.ts
Normal file
86
typescript/grade-school/grade-school.test.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import { GradeSchool } from "./grade-school";
|
||||
|
||||
describe("School", () => {
|
||||
let school: GradeSchool;
|
||||
|
||||
beforeEach(() => {
|
||||
school = new GradeSchool();
|
||||
});
|
||||
|
||||
it("a new school has an empty roster", () => {
|
||||
expect(school.roster()).toEqual({});
|
||||
});
|
||||
|
||||
it("adding a student adds them to the roster for the given grade", () => {
|
||||
school.add("Aimee", 2);
|
||||
|
||||
const expectedDb = { 2: ["Aimee"] };
|
||||
expect(school.roster()).toEqual(expectedDb);
|
||||
});
|
||||
|
||||
it("adding more students to the same grade adds them to the roster", () => {
|
||||
school.add("Blair", 2);
|
||||
school.add("James", 2);
|
||||
school.add("Paul", 2);
|
||||
|
||||
const expectedDb = { 2: ["Blair", "James", "Paul"] };
|
||||
expect(school.roster()).toEqual(expectedDb);
|
||||
});
|
||||
|
||||
it("adding students to different grades adds them to the roster", () => {
|
||||
school.add("Chelsea", 3);
|
||||
school.add("Logan", 7);
|
||||
|
||||
const expectedDb = { 3: ["Chelsea"], 7: ["Logan"] };
|
||||
expect(school.roster()).toEqual(expectedDb);
|
||||
});
|
||||
|
||||
it("grade returns the students in that grade in alphabetical order", () => {
|
||||
school.add("Franklin", 5);
|
||||
school.add("Bradley", 5);
|
||||
school.add("Jeff", 1);
|
||||
|
||||
const expectedStudents = ["Bradley", "Franklin"];
|
||||
expect(school.grade(5)).toEqual(expectedStudents);
|
||||
});
|
||||
|
||||
it("grade returns an empty array if there are no students in that grade", () => {
|
||||
expect(school.grade(1)).toEqual([]);
|
||||
});
|
||||
|
||||
it("the students names in each grade in the roster are sorted", () => {
|
||||
school.add("Jennifer", 4);
|
||||
school.add("Kareem", 6);
|
||||
school.add("Christopher", 4);
|
||||
school.add("Kyle", 3);
|
||||
|
||||
const expectedSortedStudents = {
|
||||
3: ["Kyle"],
|
||||
4: ["Christopher", "Jennifer"],
|
||||
6: ["Kareem"],
|
||||
};
|
||||
expect(school.roster()).toEqual(expectedSortedStudents);
|
||||
});
|
||||
|
||||
it("roster cannot be modified outside of module", () => {
|
||||
school.add("Aimee", 2);
|
||||
const roster = school.roster();
|
||||
roster[2].push("Oops.");
|
||||
const expectedDb = { 2: ["Aimee"] };
|
||||
expect(school.roster()).toEqual(expectedDb);
|
||||
});
|
||||
|
||||
it("roster cannot be modified outside of module using grade()", () => {
|
||||
school.add("Aimee", 2);
|
||||
school.grade(2).push("Oops.");
|
||||
const expectedDb = { 2: ["Aimee"] };
|
||||
expect(school.roster()).toEqual(expectedDb);
|
||||
});
|
||||
|
||||
it("a student can't be in two different grades", () => {
|
||||
school.add("Aimee", 2);
|
||||
school.add("Aimee", 1);
|
||||
|
||||
expect(school.grade(2)).toEqual([]);
|
||||
});
|
||||
});
|
||||
35
typescript/grade-school/grade-school.ts
Normal file
35
typescript/grade-school/grade-school.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
export class GradeSchool {
|
||||
private _roster: Record<number, string[]> = {};
|
||||
|
||||
roster(): Record<number, string[]> {
|
||||
return JSON.parse(JSON.stringify(this._roster));
|
||||
}
|
||||
|
||||
get grades(): number[] {
|
||||
return Object.keys(this._roster) as unknown as number[];
|
||||
}
|
||||
|
||||
add(name: string, grade: number): void {
|
||||
const addUniqueValue = <T extends any>(
|
||||
array: T[] | undefined,
|
||||
value: T
|
||||
): T[] => [...new Set<T>([...(array || []), value])];
|
||||
|
||||
const allGrades = addUniqueValue(this.grades, grade);
|
||||
|
||||
this._roster = allGrades.reduce(
|
||||
(newRoster, rosterGrade) => ({
|
||||
...newRoster,
|
||||
[rosterGrade]:
|
||||
rosterGrade === grade
|
||||
? addUniqueValue(newRoster[rosterGrade], name).sort()
|
||||
: newRoster[rosterGrade].filter((n) => n !== name),
|
||||
}),
|
||||
this._roster
|
||||
);
|
||||
}
|
||||
|
||||
grade(grade: number): string[] {
|
||||
return this.roster()[grade] || [];
|
||||
}
|
||||
}
|
||||
19
typescript/grade-school/jest.config.cjs
Normal file
19
typescript/grade-school/jest.config.cjs
Normal file
@@ -0,0 +1,19 @@
|
||||
module.exports = {
|
||||
verbose: true,
|
||||
projects: ['<rootDir>'],
|
||||
testMatch: [
|
||||
'**/__tests__/**/*.[jt]s?(x)',
|
||||
'**/test/**/*.[jt]s?(x)',
|
||||
'**/?(*.)+(spec|test).[jt]s?(x)',
|
||||
],
|
||||
testPathIgnorePatterns: [
|
||||
'/(?:production_)?node_modules/',
|
||||
'.d.ts$',
|
||||
'<rootDir>/test/fixtures',
|
||||
'<rootDir>/test/helpers',
|
||||
'__mocks__',
|
||||
],
|
||||
transform: {
|
||||
'^.+\\.[jt]sx?$': 'babel-jest',
|
||||
},
|
||||
}
|
||||
15996
typescript/grade-school/package-lock.json
generated
Normal file
15996
typescript/grade-school/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
31
typescript/grade-school/package.json
Normal file
31
typescript/grade-school/package.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "@exercism/typescript-grade-school",
|
||||
"version": "1.0.0",
|
||||
"description": "Exercism exercises in Typescript.",
|
||||
"private": true,
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/exercism/typescript"
|
||||
},
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": "^14.13.1 || >=16.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@exercism/babel-preset-typescript": "^0.1.0",
|
||||
"@exercism/eslint-config-typescript": "^0.4.1",
|
||||
"@types/jest": "^27.4.0",
|
||||
"@types/node": "^16.11.24",
|
||||
"babel-jest": "^27.5.1",
|
||||
"core-js": "^3.21.0",
|
||||
"eslint": "^8.9.0",
|
||||
"jest": "^27.5.1",
|
||||
"typescript": "^4.5.4"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "yarn lint:types && jest --no-cache",
|
||||
"lint": "yarn lint:types && yarn lint:ci",
|
||||
"lint:types": "yarn tsc --noEmit -p .",
|
||||
"lint:ci": "eslint . --ext .tsx,.ts"
|
||||
}
|
||||
}
|
||||
28
typescript/grade-school/tsconfig.json
Normal file
28
typescript/grade-school/tsconfig.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"display": "Configuration for Exercism TypeScript Exercises",
|
||||
"compilerOptions": {
|
||||
// Allows you to use the newest syntax, and have access to console.log
|
||||
// https://www.typescriptlang.org/tsconfig#lib
|
||||
"lib": ["ESNEXT", "dom"],
|
||||
// Make sure typescript is configured to output ESM
|
||||
// https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c#how-can-i-make-my-typescript-project-output-esm
|
||||
"module": "ES2020",
|
||||
// Since this project is using babel, TypeScript may target something very
|
||||
// high, and babel will make sure it runs on your local Node version.
|
||||
// https://babeljs.io/docs/en/
|
||||
"target": "ESNext", // ESLint doesn't support this yet: "es2022",
|
||||
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
|
||||
// Because we'll be using babel: ensure that Babel can safely transpile
|
||||
// files in the TypeScript project.
|
||||
//
|
||||
// https://babeljs.io/docs/en/babel-plugin-transform-typescript/#caveats
|
||||
"isolatedModules": true
|
||||
},
|
||||
"include": ["*.ts", "*.tsx", ".meta/*.ts", ".meta/*.tsx"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
Reference in New Issue
Block a user