Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 34 additions & 30 deletions exercises/practice/bottle-song/.meta/proof.ci.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,43 @@
const NUMBERS = [
"no",
"One",
"Two",
"Three",
"Four",
"Five",
"Six",
"Seven",
"Eight",
"Nine",
"Ten",
'no',
'One',
'Two',
'Three',
'Four',
'Five',
'Six',
'Seven',
'Eight',
'Nine',
'Ten',
]


export const recite = (initialBottleCount: number, takeDownCount = 1): string[] => {
const out: string[] = []
export const recite = (
initialBottleCount: number,
takeDownCount = 1
): string[] => {
const out: string[] = []

for(let i = initialBottleCount; i > initialBottleCount - takeDownCount; i--) {
const currentBottles = i === 1 ? 'bottle' : 'bottles'
const nextBottles = i-1 === 1 ? 'bottle' : 'bottles'
for (
let i = initialBottleCount;
i > initialBottleCount - takeDownCount;
i--
) {
const currentBottles = i === 1 ? 'bottle' : 'bottles'
const nextBottles = i - 1 === 1 ? 'bottle' : 'bottles'

out.push(...[
...(Array(2).fill(`${NUMBERS[i]} green ${currentBottles} hanging on the wall,`)),
`And if one green bottle should accidentally fall,`,
`There'll be ${NUMBERS[i-1].toLowerCase()} green ${nextBottles} hanging on the wall.`
])

if (initialBottleCount - takeDownCount !== i -1) {
out.push('')
}
const line = `${NUMBERS[i]} green ${currentBottles} hanging on the wall,`
out.push(
line,
line,
`And if one green bottle should accidentally fall,`,
`There'll be ${NUMBERS[i - 1].toLowerCase()} green ${nextBottles} hanging on the wall.`
)

if (initialBottleCount - takeDownCount !== i - 1) {
out.push('')
}
}

return out
return out
}



8 changes: 5 additions & 3 deletions exercises/practice/bottle-song/bottle-song.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@

export const recite = (initialBottleCount: unknown, takeDownCount: unknown): unknown => {
throw new Error('Remove this statement and implement this function')
export const recite = (
initialBottleCount: unknown,
takeDownCount: unknown
): unknown => {
throw new Error('Remove this statement and implement this function')
}
2 changes: 1 addition & 1 deletion exercises/practice/bottle-song/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "@exercism/typescript-practice-bottle-song",
"name": "@exercism/typescript-bottle-song",
"version": "1.0.0",
"description": "Exercism practice exercise on bottle-song",
"private": true,
Expand Down
111 changes: 111 additions & 0 deletions exercises/practice/bottle-song/test-runner.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#!/usr/bin/env node

/**
* 👋🏽 Hello there reader,
*
* It looks like you are working on this solution using the Exercism CLI and
* not the online editor. That's great! The file you are looking at executes
* the various steps the online test-runner also takes.
*
* @see https://github.com/exercism/typescript-test-runner
*
* TypeScript track exercises generally consist of at least two out of three
* types of tests to run.
*
* 1. tsc, the TypeScript compiler. This tests if the TypeScript code is valid
* 2. tstyche, static analysis tests to see if the types used are expected
* 3. jest, runtime implementation tests to see if the solution is correct
*
* If one of these three fails, this script terminates with -1, -2, or -3
* respectively. If it succeeds, it terminates with exit code 0.
*
* @note you need corepack (bundled with node LTS) enabled in order for this
* test runner to work as expected. Follow the installation and test
* instructions if you see errors about corepack or pnp.
*/

import { execSync } from 'node:child_process'
import { existsSync, readFileSync } from 'node:fs'
import { exit } from 'node:process'
import { URL } from 'node:url'

/**
* Before executing any tests, the test runner attempts to find the
* exercise config.json file which has metadata about which types of tests
* to run for this solution.
*/
const metaDirectory = new URL('./.meta/', import.meta.url)
const exercismDirectory = new URL('./.exercism/', import.meta.url)
const configDirectory = existsSync(metaDirectory)
? metaDirectory
: existsSync(exercismDirectory)
? exercismDirectory
: null

if (configDirectory === null) {
throw new Error(
'Expected .meta or .exercism directory to exist, but I cannot find it.'
)
}

const configFile = new URL('./config.json', configDirectory)
if (!existsSync(configFile)) {
throw new Error('Expected config.json to exist at ' + configFile.toString())
}

// Experimental: import config from './config.json' with { type: 'json' }
/** @type {import('./config.json') } */
const config = JSON.parse(readFileSync(configFile))

const jest = !config.custom || config.custom['flag.tests.jest']
const tstyche = config.custom?.['flag.tests.tstyche']
console.log(
`[tests] tsc: ✅, tstyche: ${tstyche ? '✅' : '❌'}, jest: ${jest ? '✅' : '❌'}, `
)

/**
* 1. tsc: the typescript compiler
*/
try {
console.log('[tests] tsc (compile)')
execSync('corepack yarn lint:types', {
stdio: 'inherit',
cwd: process.cwd(),
})
} catch {
exit(-1)
}

/**
* 2. tstyche: type tests
*/
if (tstyche) {
try {
console.log('[tests] tstyche (type tests)')
execSync('corepack yarn test:types', {
stdio: 'inherit',
cwd: process.cwd(),
})
} catch {
exit(-2)
}
}

/**
* 3. jest: implementation tests
*/
if (jest) {
try {
console.log('[tests] tstyche (implementation tests)')
execSync('corepack yarn test:implementation', {
stdio: 'inherit',
cwd: process.cwd(),
})
} catch {
exit(-3)
}
}

/**
* Done! 🥳
*/
Empty file.
Loading