diff --git a/.gitignore b/.gitignore index 735f4af..c977c85 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .DS_Store +*.d.ts *.log coverage/ node_modules/ diff --git a/cli.js b/cli.js index d13e56a..2df67ad 100755 --- a/cli.js +++ b/cli.js @@ -3,6 +3,7 @@ import fs from 'fs' import {URL} from 'url' import {syllable} from './index.js' +/** @type {Object.} */ var pack = JSON.parse( String(fs.readFileSync(new URL('./package.json', import.meta.url))) ) @@ -23,20 +24,26 @@ if (argv.includes('--help') || argv.includes('-h')) { getSyllables(argv.join(' ')) } +/** + * @param {string} value + */ function getSyllables(value) { - value = value + var values = value .split(/\s+/g) - .map((d) => d.trim()) + .map((/** @type {string} */ d) => d.trim()) .filter(Boolean) - if (value.length === 0) { + if (values.length === 0) { process.stderr.write(help()) process.exit(1) } else { - console.log(syllables(value)) + console.log(syllables(values)) } } +/** + * @param {Array.} values + */ function syllables(values) { var sum = 0 var index = -1 diff --git a/index.js b/index.js index bef999b..581d367 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,5 @@ import pluralize from 'pluralize' +// @ts-ignore remove when typed. import normalize from 'normalize-strings' import {problematic} from './problematic.js' @@ -225,6 +226,12 @@ var EXPRESSION_DOUBLE = new RegExp( var EXPRESSION_TRIPLE = /(creations?|ology|ologist|onomy|onomist)$/g // Wrapper to support multiple word-parts (GH-11). +/** + * Syllable count + * + * @param {string} value + * @returns {number} + */ export function syllable(value) { var values = normalize(String(value)) .toLowerCase() @@ -232,26 +239,34 @@ export function syllable(value) { .replace(/['’]/g, '') // Split on word boundaries. .split(/\b/g) - var length = values.length var index = -1 - var total = 0 + var sum = 0 - while (++index < length) { + while (++index < values.length) { // Remove non-alphabetic characters from a given value. - total += one(values[index].replace(/[^a-z]/g, '')) + sum += one(values[index].replace(/[^a-z]/g, '')) } - return total + return sum } -// Get syllables in a given value. +/** + * Get syllables in a given value. + * + * @param {string} value + * @returns {number} + */ function one(value) { var count = 0 + /** @type {number} */ var index - var length + /** @type {string} */ var singular + /** @type {Array.} */ var parts + /** @type {ReturnType.} */ var addOne + /** @type {ReturnType.} */ var subtractOne if (value.length === 0) { @@ -287,9 +302,8 @@ function one(value) { // Count multiple consonants. parts = value.split(/[^aeiouy]+/) index = -1 - length = parts.length - while (++index < length) { + while (++index < parts.length) { if (parts[index] !== '') { count++ } @@ -312,20 +326,34 @@ function one(value) { // Make sure at least on is returned. return count || 1 - // Define scoped counters, to be used in `String#replace()` calls. - // The scoped counter removes the matched value from the input. + /** + * Define scoped counters, to be used in `String#replace()` calls. + * The scoped counter removes the matched value from the input. + * + * @param {number} addition + */ function countFactory(addition) { return counter + /** + * @returns {string} + */ function counter() { count += addition return '' } } - // Define scoped counters, to be used in `String#replace()` calls. - // The scoped counter does not remove the matched value from the input. + /** + * This scoped counter does not remove the matched value from the input. + * + * @param {number} addition + */ function returnFactory(addition) { return returner + /** + * @param {string} $0 + * @returns {string} + */ function returner($0) { count += addition return $0 diff --git a/package.json b/package.json index 9317e5c..400d8b7 100644 --- a/package.json +++ b/package.json @@ -26,28 +26,37 @@ "type": "module", "bin": "cli.js", "main": "index.js", + "types": "index.d.ts", "files": [ "cli.js", "problematic.js", + "index.d.ts", "index.js" ], "dependencies": { + "@types/pluralize": "^0.0.29", "normalize-strings": "^1.1.0", "pluralize": "^8.0.0" }, "devDependencies": { + "@types/tape": "^4.0.0", "c8": "^7.0.0", "prettier": "^2.0.0", "remark-cli": "^9.0.0", "remark-preset-wooorm": "^8.0.0", + "rimraf": "^3.0.0", "tape": "^5.0.0", + "type-coverage": "^2.0.0", + "typescript": "^4.0.0", "xo": "^0.38.0" }, "scripts": { + "prepack": "npm run build && npm run format", + "build": "rimraf \"*.d.ts\" && tsc && type-coverage", "format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix", "test-api": "node test/index.js", "test-coverage": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 --reporter lcov node test/index.js", - "test": "npm run format && npm run test-coverage" + "test": "npm run build && npm run format && npm run test-coverage" }, "prettier": { "tabWidth": 2, @@ -69,5 +78,10 @@ "plugins": [ "preset-wooorm" ] + }, + "typeCoverage": { + "atLeast": 100, + "detail": true, + "strict": true } } diff --git a/test/index.js b/test/index.js index 3dbd552..c040a74 100644 --- a/test/index.js +++ b/test/index.js @@ -7,10 +7,12 @@ import test from 'tape' var own = {}.hasOwnProperty +/** @type {Object.} */ var pack = JSON.parse( String(fs.readFileSync(new URL('../package.json', import.meta.url))) ) +/** @type {Object.} */ var fixtures = JSON.parse( String(fs.readFileSync(new URL('./fixture.json', import.meta.url))) ) @@ -347,14 +349,16 @@ test('cli', function (t) { // This library focusses on the required Text-Statistics tests (the library // provides both optional and required tests). test('fixtures', function (t) { - var key - var expected var overwrite = { // GH-22: , // Barbed is one syllable as well: // arbed: 1 } + /** @type {string} */ + var key + /** @type {number} */ + var expected for (key in fixtures) { if (own.call(fixtures, key)) { diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..1cb61bf --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,15 @@ +{ + "include": ["*.js", "test/**/*.js"], + "compilerOptions": { + "target": "ES2020", + "lib": ["ES2020"], + "module": "ES2020", + "moduleResolution": "node", + "allowJs": true, + "checkJs": true, + "declaration": true, + "emitDeclarationOnly": true, + "allowSyntheticDefaultImports": true, + "skipLibCheck": true + } +}