diff --git a/.gitignore b/.gitignore index 2b76d7c..84486cd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +node_modules/ + # System files .DS_Store Thumbs.db diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..2399ab2 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,8 @@ +{ + "semi": true, + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "es5", + "printWidth": 80, + "arrowParens": "always" +} diff --git a/finance-tracker/app.js b/finance-tracker/app.js index 7cfcd07..0dcb0b5 100644 --- a/finance-tracker/app.js +++ b/finance-tracker/app.js @@ -1,3 +1,325 @@ -// This is the entrypoint for your application. -// node app.js +// Import all the functions I need from my finance tracker +import { + printAllTransactions, + printSummary, + addTransaction, + getTransactionsByCategory, + getLargestExpense, + searchByDateRange, + groupTransactionsByMonth, + averageExpensePerCategory, + removeTransactionById, + findConsecutiveExpensiveMonths, + getBalance, + getTotalIncome, + getTotalExpenses, +} from './finance.js'; +import { transactions } from './data.js'; +import { styles } from './style.js'; +import { createInterface } from 'readline'; +// Show a nice header at the top +function displayHeader() { + console.log(styles.bold('\n╔════════════════════════════════════════╗')); + console.log(styles.bold('║ 💰 PERSONAL FINANCE TRACKER 💰 ║')); + console.log(styles.bold('╚════════════════════════════════════════╝\n')); +} + +// Display menu options so I know what each number does +function displayMenu() { + console.log(styles.bold('\n📋 CHOOSE AN OPTION:\n')); + console.log('1. 📊 View All Transactions'); + console.log('2. 📈 View Summary Report'); + console.log('3. ➕ Add New Transaction'); + console.log('4. 🗑️ Remove Transaction by ID'); + console.log('5. 💰 Quick Balance Check'); + console.log('6. 🔍 Search by Category'); + console.log('7. 📅 Search by Date Range'); + console.log('8. 📆 View by Month'); + console.log('9. 💸 View Largest Expense'); + console.log('10. 📊 Average Expense per Category'); + console.log('11. 📈 Consecutive Expensive Months\n'); +} + +// Example 1: Just show me everything +function example1() { + displayHeader(); + console.log(styles.bold('📊 ALL TRANSACTIONS\n')); + printAllTransactions(); +} + +// Example 2: Full summary with all the stats +function example2() { + displayHeader(); + printSummary(); +} + +// Example 3: Add a new transaction +function example3() { + displayHeader(); + console.log(styles.bold('➕ ADD NEW TRANSACTION\n')); + + const newTransaction = { + id: 100, + type: 'expense', + category: 'test', + amount: 50, + description: 'Test transaction', + date: '2025-01-01' + }; + + addTransaction(newTransaction); + console.log(styles.income('✅ Transaction added successfully!')); + console.log('New transaction:', newTransaction); + console.log('\nUpdated transactions:'); + printAllTransactions(); +} + +// Example 4: Remove a transaction by ID +function example4() { + displayHeader(); + console.log(styles.bold('🗑️ REMOVE TRANSACTION BY ID\n')); + + const idToRemove = 1; + const removed = removeTransactionById(idToRemove); + + if (removed) { + console.log(styles.income(`✅ Transaction with ID ${idToRemove} removed successfully!`)); + } else { + console.log(styles.expense(`❌ No transaction found with ID ${idToRemove}`)); + } + + console.log('\nUpdated transactions:'); + printAllTransactions(); +} + +// Example 5: Quick check to see if I'm broke or not +function example5() { + displayHeader(); + const income = getTotalIncome(); + const expenses = getTotalExpenses(); + const balance = getBalance(); + + console.log(styles.bold('💰 QUICK BALANCE CHECK\n')); + console.log(styles.income(`Total Income: €${income.toFixed(2)}`)); + console.log(styles.expense(`Total Expenses: €${expenses.toFixed(2)}`)); + console.log('─────────────────────────────'); + + // Show balance in green if positive, red if negative + const balanceText = + balance >= 0 + ? styles.balancePositive(`€${balance.toFixed(2)}`) + : styles.balanceNegative(`€${balance.toFixed(2)}`); + console.log(styles.bold(`Current Balance: ${balanceText}\n`)); +} + +// Example 6: Find all transactions for a specific category +// Change 'groceries' below to search different categories +function example6() { + displayHeader(); + console.log(styles.bold('🔍 SEARCH BY CATEGORY\n')); + + const category = 'groceries'; // Try: 'rent', 'salary', 'entertainment', etc. + + const results = getTransactionsByCategory(category); + + if (results.length === 0) { + console.log(styles.expense(`❌ No transactions found for category: ${category}`)); + return; + } + + console.log(styles.income(`✅ Found ${results.length} transaction(s) for "${category}":\n`)); + results.forEach((t) => { + const amount = + t.type === 'income' + ? styles.income(`€${t.amount}`) + : styles.expense(`€${t.amount}`); + console.log( + ` ${t.id}. [${t.type.toUpperCase()}] ${t.category} - ${amount} (${t.description || '-'}) - ${t.date}` + ); + }); +} + +// Example 7: Search between two dates +// Useful for checking spending in a specific month +function example7() { + displayHeader(); + console.log(styles.bold('📅 SEARCH BY DATE RANGE\n')); + + const startDate = '2025-01-01'; + const endDate = '2025-01-31'; + + const results = searchByDateRange(startDate, endDate); + + if (results.length === 0) { + console.log(styles.expense('\n❌ No transactions found in this date range')); + return; + } + + console.log(styles.income(`✅ Found ${results.length} transaction(s) from ${startDate} to ${endDate}:\n`)); + results.forEach((t) => { + const amount = + t.type === 'income' + ? styles.income(`€${t.amount}`) + : styles.expense(`€${t.amount}`); + console.log( + ` ${t.date}: [${t.type.toUpperCase()}] ${t.category} - ${amount} (${t.description || '-'})` + ); + }); +} + +// Example 8: See everything organized by month +// Good for comparing different months +function example8() { + displayHeader(); + console.log(styles.bold('📆 TRANSACTIONS BY MONTH\n')); + + const grouped = groupTransactionsByMonth(transactions); + const months = Object.keys(grouped).sort(); + + if (months.length === 0) { + console.log(styles.expense('❌ No transactions found')); + return; + } + + // Loop through each month and show all transactions + months.forEach((month) => { + const monthTransactions = grouped[month]; + // Calculate if the month was good or bad (income - expenses) + const total = monthTransactions.reduce((sum, t) => { + return t.type === 'income' ? sum + t.amount : sum - t.amount; + }, 0); + + const totalText = + total >= 0 + ? styles.income(`+€${total.toFixed(2)}`) + : styles.expense(`-€${Math.abs(total).toFixed(2)}`); + + console.log(styles.bold(`\n${month} (${monthTransactions.length} transactions) - Net: ${totalText}`)); + monthTransactions.forEach((t) => { + const amount = + t.type === 'income' + ? styles.income(`€${t.amount}`) + : styles.expense(`€${t.amount}`); + console.log( + ` ${t.date}: [${t.type.toUpperCase()}] ${t.category} - ${amount} (${t.description || '-'})` + ); + }); + }); +} + +// Example 9: What was my biggest expense? +function example9() { + displayHeader(); + console.log(styles.bold('💸 LARGEST EXPENSE\n')); + + const largest = getLargestExpense(); + if (!largest) { + console.log(styles.expense('❌ No expenses found')); + return; + } + + console.log( + styles.expense( + `💸 €${largest.amount} - ${largest.category} (${largest.description || '-'}) on ${largest.date}` + ) + ); +} + +// Example 10: Average spending per category +// Helps me see where most of my money goes +function example10() { + displayHeader(); + console.log(styles.bold('📊 AVERAGE EXPENSE PER CATEGORY\n')); + + const averages = averageExpensePerCategory(); + const categories = Object.keys(averages); + + if (categories.length === 0) { + console.log(styles.expense('❌ No expenses found')); + return; + } + + categories.forEach((category) => { + console.log(` ${category}: ${styles.expense(`€${averages[category].toFixed(2)}`)}`); + }); +} + +// Example 11: Find months where I spent more and more each month +// This helps spot bad spending habits +function example11() { + displayHeader(); + console.log(styles.bold('📈 CONSECUTIVE EXPENSIVE MONTHS\n')); + + const streaks = findConsecutiveExpensiveMonths(); + + if (streaks.length === 0) { + console.log(styles.income('✅ No consecutive expensive months found')); + return; + } + + streaks.forEach((streak, index) => { + console.log(styles.expense(` Streak ${index + 1}: ${streak.join(' → ')}`)); + }); +} + +// MAIN PROGRAM +displayMenu(); + +const rl = createInterface({ + input: process.stdin, + output: process.stdout +}); + +rl.question('Enter the number of the option you want to run (1-11): ', (input) => { + const exampleToRun = parseInt(input); + + if (isNaN(exampleToRun) || exampleToRun < 1 || exampleToRun > 11) { + console.log(styles.expense('❌ Invalid input! Please enter a number between 1 and 11.')); + rl.close(); + return; + } + + console.log(styles.bold(`\n▶️ Running Example ${exampleToRun}...\n`)); + + // Switch to run the selected example + switch (exampleToRun) { + case 1: + example1(); + break; + case 2: + example2(); + break; + case 3: + example3(); + break; + case 4: + example4(); + break; + case 5: + example5(); + break; + case 6: + example6(); + break; + case 7: + example7(); + break; + case 8: + example8(); + break; + case 9: + example9(); + break; + case 10: + example10(); + break; + case 11: + example11(); + break; + default: + console.log(styles.expense('❌ Invalid example number!')); + } + + rl.close(); +}); \ No newline at end of file diff --git a/finance-tracker/data.js b/finance-tracker/data.js index d7863ff..5d7458b 100644 --- a/finance-tracker/data.js +++ b/finance-tracker/data.js @@ -1,2 +1,162 @@ -// Place here the transaction data array. Use it in your application as needed. -const transactions = []; \ No newline at end of file +export const transactions = [ + { + id: 1, + type: 'income', + category: 'salary', + amount: 2850, + description: 'Software Engineer salary', + date: '2024-12-01', + }, + { + id: 2, + type: 'expense', + category: 'rent', + amount: 1200, + description: 'Apartment rent December', + date: '2024-12-05', + }, + { + id: 3, + type: 'expense', + category: 'groceries', + amount: 87.45, + description: 'Albert Heijn shopping', + date: '2024-12-08', + }, + { + id: 4, + type: 'expense', + category: 'transportation', + amount: 45.50, + description: 'NS train subscription', + date: '2024-12-10', + }, + { + id: 5, + type: 'expense', + category: 'entertainment', + amount: 32.90, + description: 'Netflix & Spotify', + date: '2024-12-12', + }, + { + id: 6, + type: 'income', + category: 'freelance', + amount: 450, + description: 'Website redesign project', + date: '2024-12-15', + }, + { + id: 7, + type: 'expense', + category: 'groceries', + amount: 112.30, + description: 'Jumbo weekly shopping', + date: '2024-12-18', + }, + { + id: 8, + type: 'expense', + category: 'utilities', + amount: 156.20, + description: 'Electricity & water bill', + date: '2024-12-20', + }, + { + id: 9, + type: 'expense', + category: 'entertainment', + amount: 48.75, + description: 'Dinner at restaurant', + date: '2024-12-22', + }, + { + id: 10, + type: 'expense', + category: 'shopping', + amount: 89.99, + description: 'Winter jacket', + date: '2024-12-28', + }, + { + id: 11, + type: 'income', + category: 'salary', + amount: 2850, + description: 'Software Engineer salary', + date: '2025-01-01', + }, + { + id: 12, + type: 'expense', + category: 'rent', + amount: 1200, + description: 'Apartment rent January', + date: '2025-01-05', + }, + { + id: 13, + type: 'expense', + category: 'groceries', + amount: 95.60, + description: 'Aldi shopping', + date: '2025-01-09', + }, + { + id: 14, + type: 'expense', + category: 'healthcare', + amount: 128.50, + description: 'Health insurance premium', + date: '2025-01-12', + }, + { + id: 15, + type: 'income', + category: 'freelance', + amount: 320, + description: 'Logo design work', + date: '2025-01-15', + }, + { + id: 16, + type: 'expense', + category: 'groceries', + amount: 78.20, + description: 'Albert Heijn shopping', + date: '2025-01-18', + }, + { + id: 17, + type: 'expense', + category: 'transportation', + amount: 45.50, + description: 'NS train subscription', + date: '2025-01-20', + }, + { + id: 18, + type: 'expense', + category: 'entertainment', + amount: 65.00, + description: 'Concert tickets', + date: '2025-01-25', + }, + { + id: 19, + type: 'expense', + category: 'utilities', + amount: 142.80, + description: 'Internet & mobile phone', + date: '2025-01-28', + }, + { + id: 20, + type: 'income', + category: 'salary', + amount: 2850, + description: 'Software Engineer salary', + date: '2025-02-01', + }, +]; \ No newline at end of file diff --git a/finance-tracker/finance.js b/finance-tracker/finance.js index ac2118f..f2e3db5 100644 --- a/finance-tracker/finance.js +++ b/finance-tracker/finance.js @@ -1,27 +1,251 @@ -function addTransaction(transaction) { - // TODO: Implement this function +import { transactions } from './data.js'; +import { styles } from './style.js'; + +// Add new transaction using spread operator +export function addTransaction(transaction) { + transactions.push({ ...transaction }); +} + +// Calculate total income using a loop +export function getTotalIncome() { + let total = 0; + for (const transaction of transactions) { + if (transaction.type === 'income') { + total += transaction.amount; + } + } + return total; +} + +// Calculate total expenses using a loop +export function getTotalExpenses() { + let total = 0; + for (const transaction of transactions) { + if (transaction.type === 'expense') { + total += transaction.amount; + } + } + return total; +} + +export function getBalance() { + return getTotalIncome() - getTotalExpenses(); +} + +// Filter transactions by category using loop and demonstrating object destructuring +export function getTransactionsByCategory(category) { + const result = []; + for (const { id, type, category: cat, amount, description, date } of transactions) { + if (cat === category) { + result.push({ id, type, category: cat, amount, description, date }); + } + } + return result; +} + +// Find the largest expense using a for loop +export function getLargestExpense() { + let largest = null; + for (const t of transactions) { + if (t.type === 'expense' && (!largest || t.amount > largest.amount)) { + largest = t; + } + } + return largest; +} + +// Bonus: Search transactions by date range using slice +export function searchByDateRange(startDate, endDate) { + const sorted = [...transactions].sort((a, b) => (a.date > b.date ? 1 : -1)); + + const startIndex = sorted.findIndex((t) => t.date >= startDate); + const endIndex = sorted.findIndex((t) => t.date > endDate); + + return sorted.slice(startIndex, endIndex === -1 ? sorted.length : endIndex); +} + +// Bonus: Group transactions by month using nested objects +export function groupTransactionsByMonth(transactions) { + const grouped = {}; + + for (const t of transactions) { + const month = t.date.slice(0, 7); + if (!grouped[month]) { + grouped[month] = []; + } + grouped[month].push(t); + } + + return grouped; } -function getTotalIncome() { - // TODO: Implement this function +// Bonus: Calculate average expense per category +export function averageExpensePerCategory() { + const categoryTotals = {}; + const categoryCounts = {}; + + for (const t of transactions) { + if (t.type === 'expense') { + if (!categoryTotals[t.category]) { + categoryTotals[t.category] = 0; + categoryCounts[t.category] = 0; + } + categoryTotals[t.category] += t.amount; + categoryCounts[t.category] += 1; + } + } + + const averages = {}; + for (const category in categoryTotals) { + averages[category] = categoryTotals[category] / categoryCounts[category]; + } + + return averages; } -function getTotalExpenses() { - // TODO: Implement this function +// Bonus: Remove transaction by ID +export function removeTransactionById(id) { + const index = transactions.findIndex(t => t.id === id); + if (index !== -1) { + transactions.splice(index, 1); + return true; + } else { + return false; + } } -function getBalance() { - // TODO: Implement this function +// Helper function for consecutive expensive months +function getTotalExpensesByMonth(month) { + const grouped = groupTransactionsByMonth(transactions); + const monthTransactions = grouped[month] || []; + return monthTransactions + .filter(t => t.type === 'expense') + .reduce((sum, t) => sum + t.amount, 0); } -function getTransactionsByCategory(category) { - // TODO: Implement this function +/** + * Finds consecutive months where expenses increase month-over-month. + * This function uses a while loop to iterate through sorted months and identifies + * streaks where each month has higher expenses than the previous month. + * + * Algorithm: + * 1. Get all months from transactions and sort them chronologically + * 2. Use outer while loop to iterate through months + * 3. For each month, use inner while loop to find consecutive increasing expenses + * 4. Track streaks of 2+ months and add to results + * 5. Skip ahead to next non-consecutive month + * + * @returns {Array>} Array of streaks, where each streak is an array of month strings + */ +export function findConsecutiveExpensiveMonths() { + const months = Object.keys(groupTransactionsByMonth(transactions)).sort(); + const result = []; + let i = 0; + + while (i < months.length) { + const streak = [months[i]]; + let prevTotal = getTotalExpensesByMonth(months[i]); + + let j = i + 1; + while (j < months.length) { + const currTotal = getTotalExpensesByMonth(months[j]); + if (currTotal > prevTotal) { + streak.push(months[j]); + prevTotal = currTotal; + j++; + } else { + break; + } + } + + if (streak.length > 1) result.push(streak); + i = j; + } + + return result; } -function getLargestExpense() { - // TODO: Implement this function + +// Display all transactions with color formatting +export function printAllTransactions() { + transactions.forEach((t, index) => { + const values = Object.values(t); + + const typeLabel = `[${values[1].toUpperCase()}]`; + const category = styles.category(values[2]); // Yellow color for category + + const amount = + values[1] === 'income' + ? styles.income(`€${values[3]}`) // Green for income + : styles.expense(`€${values[3]}`); // Red for expense + + console.log( + `${index + 1}. ${typeLabel} ${category} - ${amount} (${values[4] || '-'})` + ); + }); } -function printAllTransactions() { - // TODO: Implement this function +// Print comprehensive summary report with all required information +export function printSummary() { + const totalIncome = getTotalIncome(); + const totalExpenses = getTotalExpenses(); + const balance = getBalance(); + const numTransactions = transactions.length; + const largestExpenseTransaction = getLargestExpense(); + const searchDateRange = searchByDateRange('2025-01-15', '2025-01-18'); + + + console.log(styles.bold('\n--- Summary Report ---')); + console.log(styles.bold(styles.income(`Total Income: €${totalIncome}`))); + console.log(styles.bold(styles.expense(`Total Expenses: €${totalExpenses}`))); + + // Balance in cyan if positive, red if negative + const balanceText = + balance >= 0 + ? styles.balancePositive(`€${balance}`) + : styles.balanceNegative(`€${balance}`); + console.log(styles.bold(`Balance: ${balanceText}`)); + + console.log(styles.bold(`Number of Transactions: ${numTransactions}`)); + + // Display largest expense with description + if (largestExpenseTransaction) { + console.log( + styles.bold( + styles.expense( + `Largest Expense: €${largestExpenseTransaction.amount} (${largestExpenseTransaction.description || '-'})` + ) + ) + ); + } else { + console.log(styles.bold(styles.expense('Largest Expense: -'))); + } + + // Bonus features below + const streaks = findConsecutiveExpensiveMonths(); + if (streaks.length === 0) { + console.log('No consecutive expensive months found.'); + return; + } + + console.log('\n--- Consecutive Expensive Months ---'); + streaks.forEach(streak => { + console.log(streak.join(' → ')); + }); + + console.log('Transactions from 2025-01-15 to 2025-01-18:'); + searchDateRange.forEach((t) => { + console.log( + `- ${t.date}: ${t.type} ${t.category} €${t.amount} (${t.description})` + ); + }); + + const grouped = groupTransactionsByMonth(transactions); + console.log(grouped); + + const averages = averageExpensePerCategory(); + console.log(styles.bold('\n--- Average Expense per Category ---')); + for (const category in averages) { + console.log(`${styles.category(category)}: €${averages[category].toFixed(2)}`); + } } \ No newline at end of file diff --git a/finance-tracker/style.js b/finance-tracker/style.js new file mode 100644 index 0000000..bd371a6 --- /dev/null +++ b/finance-tracker/style.js @@ -0,0 +1,10 @@ +import chalk from 'chalk'; + +export const styles = { + income: chalk.green, + expense: chalk.red, + category: chalk.yellow, + balancePositive: chalk.cyan.bold, + balanceNegative: chalk.red.bold, + bold: chalk.bold +}; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..228d484 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,105 @@ +{ + "name": "c55-core-week-4", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "c55-core-week-4", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "chalk": "^4.1.2" + }, + "devDependencies": { + "prettier": "^3.8.1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/prettier": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..c19f6de --- /dev/null +++ b/package.json @@ -0,0 +1,27 @@ +{ + "name": "c55-core-week-4", + "version": "1.0.0", + "description": "The week 4 assignment for the HackYourFuture Core program can be found at the following link: https://hub.hackyourfuture.nl/core-program-week-4-assignment", + "main": "index.js", + "type": "module", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/shmoonwalker/c55-core-week-4.git" + }, + "keywords": [], + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/shmoonwalker/c55-core-week-4/issues" + }, + "homepage": "https://github.com/shmoonwalker/c55-core-week-4#readme", + "dependencies": { + "chalk": "^4.1.2" + }, + "devDependencies": { + "prettier": "^3.8.1" + } +}