Skip to content

Commit 8ccc16b

Browse files
committed
Add ESLint tsconfig and fix formatting
- Add tsconfig.eslint.json for ESLint TypeScript parser - Update eslint.config.js to use project-based linting - Apply Prettier formatting fixes
1 parent faac388 commit 8ccc16b

File tree

60 files changed

+569
-260
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+569
-260
lines changed

epicshop/fix.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,29 +12,29 @@ const VERBOSE = false
1212
const logVerbose = (...args) => (VERBOSE ? console.log(...args) : undefined)
1313

1414
const workshopRoot = here('..')
15-
const examples = (await readDir(here('../examples'))).map(dir =>
15+
const examples = (await readDir(here('../examples'))).map((dir) =>
1616
here(`../examples/${dir}`),
1717
)
1818
const exercises = (await readDir(here('../exercises')))
19-
.map(name => here(`../exercises/${name}`))
20-
.filter(filepath => fs.statSync(filepath).isDirectory())
19+
.map((name) => here(`../exercises/${name}`))
20+
.filter((filepath) => fs.statSync(filepath).isDirectory())
2121
const exerciseApps = (
2222
await Promise.all(
23-
exercises.flatMap(async exercise => {
23+
exercises.flatMap(async (exercise) => {
2424
return (await readDir(exercise))
25-
.filter(dir => {
25+
.filter((dir) => {
2626
return /(problem|solution)/.test(dir)
2727
})
28-
.map(dir => path.join(exercise, dir))
28+
.map((dir) => path.join(exercise, dir))
2929
}),
3030
)
3131
).flat()
32-
const exampleApps = (await readDir(here('../examples'))).map(dir =>
32+
const exampleApps = (await readDir(here('../examples'))).map((dir) =>
3333
here(`../examples/${dir}`),
3434
)
3535
const apps = [...exampleApps, ...exerciseApps]
3636

37-
const appsWithPkgJson = [...examples, ...apps].filter(app => {
37+
const appsWithPkgJson = [...examples, ...apps].filter((app) => {
3838
const pkgjsonPath = path.join(app, 'package.json')
3939
return exists(pkgjsonPath)
4040
})
@@ -70,7 +70,7 @@ async function updateTsconfig() {
7070
const tsconfig = {
7171
files: [],
7272
exclude: ['node_modules'],
73-
references: appsWithPkgJson.map(a => ({
73+
references: appsWithPkgJson.map((a) => ({
7474
path: relativeToWorkshopRoot(a).replace(/\\/g, '/'),
7575
})),
7676
}

epicshop/playwright.config.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { defineConfig } from '@playwright/test'
22
import getPort from 'get-port'
33

4-
const port = process.env.PORT ? Number(process.env.PORT) : await getPort({ port: 5639 })
4+
const port = process.env.PORT
5+
? Number(process.env.PORT)
6+
: await getPort({ port: 5639 })
57

68
process.env.PORT = String(port)
79

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
2-
"status": "passed",
3-
"failedTests": []
4-
}
2+
"status": "passed",
3+
"failedTests": []
4+
}

eslint.config.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@ import defaultConfig from '@epic-web/config/eslint'
33
/** @type {import("eslint").Linter.Config} */
44
export default [
55
...defaultConfig,
6+
{
7+
files: ['**/*.ts?(x)'],
8+
languageOptions: {
9+
parserOptions: {
10+
projectService: false,
11+
project: './tsconfig.eslint.json',
12+
tsconfigRootDir: import.meta.dirname,
13+
},
14+
},
15+
},
616
{
717
rules: {
818
// we leave unused vars around for the exercises
Lines changed: 74 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,88 @@
11
import { testStep, expect } from '@epic-web/workshop-utils/test'
22
import { Product, ShoppingCart } from './index.ts'
33

4-
await testStep('Product class should create instances with name and price', async () => {
5-
const laptop = new Product('Laptop', 999.99)
6-
expect(laptop.name, '🚨 Product.name should be "Laptop" - check your class property definition').toBe('Laptop')
7-
expect(laptop.price, '🚨 Product.price should be 999.99 - check your class property definition').toBe(999.99)
8-
})
4+
await testStep(
5+
'Product class should create instances with name and price',
6+
async () => {
7+
const laptop = new Product('Laptop', 999.99)
8+
expect(
9+
laptop.name,
10+
'🚨 Product.name should be "Laptop" - check your class property definition',
11+
).toBe('Laptop')
12+
expect(
13+
laptop.price,
14+
'🚨 Product.price should be 999.99 - check your class property definition',
15+
).toBe(999.99)
16+
},
17+
)
918

10-
await testStep('Product getDescription should return formatted string', async () => {
11-
const mouse = new Product('Mouse', 29.99)
12-
const description = mouse.getDescription()
13-
expect(description, '🚨 getDescription() should return "Product: Mouse - $29.99" - check your method implementation and formatting').toBe('Product: Mouse - $29.99')
14-
})
19+
await testStep(
20+
'Product getDescription should return formatted string',
21+
async () => {
22+
const mouse = new Product('Mouse', 29.99)
23+
const description = mouse.getDescription()
24+
expect(
25+
description,
26+
'🚨 getDescription() should return "Product: Mouse - $29.99" - check your method implementation and formatting',
27+
).toBe('Product: Mouse - $29.99')
28+
},
29+
)
1530

16-
await testStep('ShoppingCart should initialize with empty items array', async () => {
17-
const cart = new ShoppingCart()
18-
expect(cart.items, '🚨 ShoppingCart.items should be an empty array - check your class property initialization').toEqual([])
19-
expect(cart.items.length, '🚨 ShoppingCart.items.length should be 0 - check your class property initialization').toBe(0)
20-
})
31+
await testStep(
32+
'ShoppingCart should initialize with empty items array',
33+
async () => {
34+
const cart = new ShoppingCart()
35+
expect(
36+
cart.items,
37+
'🚨 ShoppingCart.items should be an empty array - check your class property initialization',
38+
).toEqual([])
39+
expect(
40+
cart.items.length,
41+
'🚨 ShoppingCart.items.length should be 0 - check your class property initialization',
42+
).toBe(0)
43+
},
44+
)
2145

2246
await testStep('ShoppingCart addItem should add products to cart', async () => {
2347
const cart = new ShoppingCart()
2448
const laptop = new Product('Laptop', 999.99)
2549
const mouse = new Product('Mouse', 29.99)
26-
27-
cart.addItem(laptop)
28-
expect(cart.items.length, '🚨 After adding one item, items.length should be 1 - check your addItem method implementation').toBe(1)
29-
expect(cart.items[0], '🚨 items[0] should be the laptop product - check your addItem method implementation').toBe(laptop)
30-
31-
cart.addItem(mouse)
32-
expect(cart.items.length, '🚨 After adding two items, items.length should be 2 - check your addItem method implementation').toBe(2)
33-
expect(cart.items[1], '🚨 items[1] should be the mouse product - check your addItem method implementation').toBe(mouse)
34-
})
3550

36-
await testStep('ShoppingCart getTotal should calculate sum of all item prices', async () => {
37-
const cart = new ShoppingCart()
38-
const laptop = new Product('Laptop', 999.99)
39-
const mouse = new Product('Mouse', 29.99)
40-
4151
cart.addItem(laptop)
52+
expect(
53+
cart.items.length,
54+
'🚨 After adding one item, items.length should be 1 - check your addItem method implementation',
55+
).toBe(1)
56+
expect(
57+
cart.items[0],
58+
'🚨 items[0] should be the laptop product - check your addItem method implementation',
59+
).toBe(laptop)
60+
4261
cart.addItem(mouse)
43-
44-
const total = cart.getTotal()
45-
expect(total, '🚨 getTotal() should return 1029.98 (sum of 999.99 + 29.99) - check your method implementation and price calculation').toBe(1029.98)
62+
expect(
63+
cart.items.length,
64+
'🚨 After adding two items, items.length should be 2 - check your addItem method implementation',
65+
).toBe(2)
66+
expect(
67+
cart.items[1],
68+
'🚨 items[1] should be the mouse product - check your addItem method implementation',
69+
).toBe(mouse)
4670
})
71+
72+
await testStep(
73+
'ShoppingCart getTotal should calculate sum of all item prices',
74+
async () => {
75+
const cart = new ShoppingCart()
76+
const laptop = new Product('Laptop', 999.99)
77+
const mouse = new Product('Mouse', 29.99)
78+
79+
cart.addItem(laptop)
80+
cart.addItem(mouse)
81+
82+
const total = cart.getTotal()
83+
expect(
84+
total,
85+
'🚨 getTotal() should return 1029.98 (sum of 999.99 + 29.99) - check your method implementation and price calculation',
86+
).toBe(1029.98)
87+
},
88+
)
Lines changed: 76 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,98 @@
11
import { testStep, expect } from '@epic-web/workshop-utils/test'
22
import { User, BankAccount, Config } from './index.ts'
33

4-
await testStep('User constructor should set name, email, and default role', async () => {
5-
const user = new User('Alice', '[email protected]')
6-
expect(user.name, '🚨 User.name should be "Alice" - check your constructor parameter assignment').toBe('Alice')
7-
expect(user.email, '🚨 User.email should be "[email protected]" - check your constructor parameter assignment').toBe('[email protected]')
8-
expect(user.role, '🚨 User.role should default to "user" - check your constructor default parameter value').toBe('user')
9-
})
4+
await testStep(
5+
'User constructor should set name, email, and default role',
6+
async () => {
7+
const user = new User('Alice', '[email protected]')
8+
expect(
9+
user.name,
10+
'🚨 User.name should be "Alice" - check your constructor parameter assignment',
11+
).toBe('Alice')
12+
expect(
13+
user.email,
14+
'🚨 User.email should be "[email protected]" - check your constructor parameter assignment',
15+
16+
expect(
17+
user.role,
18+
'🚨 User.role should default to "user" - check your constructor default parameter value',
19+
).toBe('user')
20+
},
21+
)
1022

1123
await testStep('User constructor should accept custom role', async () => {
1224
const admin = new User('Bob', '[email protected]', 'admin')
13-
expect(admin.name, '🚨 User.name should be "Bob" - check your constructor parameter assignment').toBe('Bob')
14-
expect(admin.email, '🚨 User.email should be "[email protected]" - check your constructor parameter assignment').toBe('[email protected]')
15-
expect(admin.role, '🚨 User.role should be "admin" when provided as third parameter - check your constructor parameter handling').toBe('admin')
25+
expect(
26+
admin.name,
27+
'🚨 User.name should be "Bob" - check your constructor parameter assignment',
28+
).toBe('Bob')
29+
expect(
30+
admin.email,
31+
'🚨 User.email should be "[email protected]" - check your constructor parameter assignment',
32+
33+
expect(
34+
admin.role,
35+
'🚨 User.role should be "admin" when provided as third parameter - check your constructor parameter handling',
36+
).toBe('admin')
1637
})
1738

18-
await testStep('BankAccount constructor should set accountNumber and default balance', async () => {
19-
const account = new BankAccount('12345')
20-
expect(account.accountNumber, '🚨 BankAccount.accountNumber should be "12345" - check your constructor parameter assignment').toBe('12345')
21-
expect(account.getBalance(), '🚨 BankAccount.getBalance() should return 0 initially - check your constructor initialization').toBe(0)
22-
})
39+
await testStep(
40+
'BankAccount constructor should set accountNumber and default balance',
41+
async () => {
42+
const account = new BankAccount('12345')
43+
expect(
44+
account.accountNumber,
45+
'🚨 BankAccount.accountNumber should be "12345" - check your constructor parameter assignment',
46+
).toBe('12345')
47+
expect(
48+
account.getBalance(),
49+
'🚨 BankAccount.getBalance() should return 0 initially - check your constructor initialization',
50+
).toBe(0)
51+
},
52+
)
2353

2454
await testStep('BankAccount deposit should increase balance', async () => {
2555
const account = new BankAccount('12345')
2656
account.deposit(100)
27-
expect(account.getBalance(), '🚨 After depositing 100, getBalance() should return 100 - check your deposit method implementation').toBe(100)
57+
expect(
58+
account.getBalance(),
59+
'🚨 After depositing 100, getBalance() should return 100 - check your deposit method implementation',
60+
).toBe(100)
2861
account.deposit(50)
29-
expect(account.getBalance(), '🚨 After depositing another 50, getBalance() should return 150 - check your deposit method accumulates correctly').toBe(150)
62+
expect(
63+
account.getBalance(),
64+
'🚨 After depositing another 50, getBalance() should return 150 - check your deposit method accumulates correctly',
65+
).toBe(150)
3066
})
3167

3268
await testStep('Config constructor should use default values', async () => {
3369
const config = new Config()
34-
expect(config.host, '🚨 Config.host should default to "localhost" - check your constructor default parameter values').toBe('localhost')
35-
expect(config.port, '🚨 Config.port should default to 3000 - check your constructor default parameter values').toBe(3000)
36-
expect(config.debug, '🚨 Config.debug should default to false - check your constructor default parameter values').toBe(false)
70+
expect(
71+
config.host,
72+
'🚨 Config.host should default to "localhost" - check your constructor default parameter values',
73+
).toBe('localhost')
74+
expect(
75+
config.port,
76+
'🚨 Config.port should default to 3000 - check your constructor default parameter values',
77+
).toBe(3000)
78+
expect(
79+
config.debug,
80+
'🚨 Config.debug should default to false - check your constructor default parameter values',
81+
).toBe(false)
3782
})
3883

3984
await testStep('Config constructor should accept custom values', async () => {
4085
const customConfig = new Config('example.com', 8080, true)
41-
expect(customConfig.host, '🚨 Config.host should be "example.com" when provided - check your constructor parameter assignment').toBe('example.com')
42-
expect(customConfig.port, '🚨 Config.port should be 8080 when provided - check your constructor parameter assignment').toBe(8080)
43-
expect(customConfig.debug, '🚨 Config.debug should be true when provided - check your constructor parameter assignment').toBe(true)
86+
expect(
87+
customConfig.host,
88+
'🚨 Config.host should be "example.com" when provided - check your constructor parameter assignment',
89+
).toBe('example.com')
90+
expect(
91+
customConfig.port,
92+
'🚨 Config.port should be 8080 when provided - check your constructor parameter assignment',
93+
).toBe(8080)
94+
expect(
95+
customConfig.debug,
96+
'🚨 Config.debug should be true when provided - check your constructor parameter assignment',
97+
).toBe(true)
4498
})

exercises/01.classes/README.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ class User {
4343
```
4444

4545
<callout-info>
46-
Classes in TypeScript are similar to classes in Java or C#. If you know those
47-
languages, you'll feel right at home.
46+
Classes in TypeScript are similar to classes in Java or C#. If you know those
47+
languages, you'll feel right at home.
4848
</callout-info>
4949

5050
In this exercise, you'll create and use classes.

exercises/02.access-modifiers/01.problem.public-private/README.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@ class User {
2020

2121
💰 Remember: Private members can only be accessed within the class methods.
2222

23-
📜 [TypeScript Handbook - Access Modifiers](https://www.typescriptlang.org/docs/handbook/2/classes.html#member-visibility)
23+
📜 [TypeScript Handbook - Access Modifiers](https://www.typescriptlang.org/docs/handbook/2/classes.html#member-visibility)

exercises/02.access-modifiers/01.problem.public-private/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@
1414
// console.log(user.login('secret123')) // ✅ Should return true
1515
// console.log(user.login('wrong')) // ✅ Should return false
1616

17-
export {}
17+
export {}

exercises/02.access-modifiers/01.solution.public-private/README.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44

55
🦉 Notice how `password` is private—this prevents external code from reading or
66
modifying it directly. The `login()` method provides controlled access to validate
7-
credentials without exposing the actual password value.
7+
credentials without exposing the actual password value.

0 commit comments

Comments
 (0)