├── .editorconfig ├── .gitignore ├── .travis.yml ├── license.md ├── package.json ├── readme.md ├── src └── index.ts ├── tasks ├── babel │ └── config.ts ├── index.ts └── karma │ └── config.ts ├── test └── index.ts ├── tsconfig.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | tmp/ 3 | build/ 4 | coverage/ 5 | .npmrc 6 | *.log 7 | .DS_Store 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # https://docs.travis-ci.com/user/customizing-the-build/ 2 | 3 | sudo: false 4 | language: node_js 5 | node_js: lts/carbon 6 | env: 7 | global: 8 | - PATH=$HOME/.yarn/bin:$PATH 9 | before_install: 10 | - curl -o- -L https://yarnpkg.com/install.sh | bash 11 | addons: 12 | chrome: stable 13 | firefox: latest 14 | cache: 15 | yarn: true 16 | directories: 17 | - node_modules 18 | branches: 19 | only: 20 | - master 21 | matrix: 22 | fast_finish: true 23 | script: yarn start ci 24 | -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) 2018–present Kir Belevich 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mnth", 3 | "version": "0.1.2", 4 | "description": "Framework-agnostic base block to build calendars, datepickers, etc by rendering 2d array of Dates", 5 | "keywords": "date, month, calendar", 6 | "homepage": "https://github.com/deepsweet/mnth", 7 | "repository": "deepsweet/mnth", 8 | "author": "Kir Belevich (https://twitter.com/deepsweet)", 9 | "license": "MIT", 10 | "files": [ 11 | "build/" 12 | ], 13 | "main": "build/node/index.js", 14 | "browser": "build/browser/index.js", 15 | "types": "build/index.d.ts", 16 | "engines": { 17 | "node": ">=8.6.0" 18 | }, 19 | "peerDependencies": { 20 | "date-fns": "^2.0.0-0" 21 | }, 22 | "dependencies": { 23 | "@babel/runtime": "^7.0.0" 24 | }, 25 | "devDependencies": { 26 | "@babel/core": "^7.0.0", 27 | "@babel/plugin-syntax-dynamic-import": "^7.0.0", 28 | "@babel/plugin-transform-runtime": "^7.0.0", 29 | "@babel/preset-env": "^7.0.0", 30 | "@babel/preset-typescript": "^7.0.0", 31 | "@babel/register": "^7.0.0", 32 | "@deepsweet/browserslist-preset": "^0.1.0", 33 | "@start/cli": "^0.3.1", 34 | "@start/plugin-find": "^0.2.0", 35 | "@start/plugin-lib-babel": "^0.2.1", 36 | "@start/plugin-lib-codecov": "^0.2.0", 37 | "@start/plugin-lib-eslint": "^0.3.0", 38 | "@start/plugin-lib-istanbul": "^0.3.0", 39 | "@start/plugin-lib-karma": "^0.2.0", 40 | "@start/plugin-lib-tape": "^0.2.0", 41 | "@start/plugin-lib-typescript-check": "^0.2.1", 42 | "@start/plugin-lib-typescript-generate": "^0.2.2", 43 | "@start/plugin-overwrite": "^0.2.0", 44 | "@start/plugin-parallel": "^0.2.0", 45 | "@start/plugin-read": "^0.2.0", 46 | "@start/plugin-remove": "^0.2.1", 47 | "@start/plugin-rename": "^0.2.0", 48 | "@start/plugin-sequence": "^0.2.0", 49 | "@start/plugin-watch": "^0.2.0", 50 | "@start/plugin-write": "^0.2.0", 51 | "@start/reporter-verbose": "^0.1.0-2", 52 | "@types/node": "^10.9.4", 53 | "@types/tape": "^4.2.32", 54 | "babel-loader": "^8.0.0", 55 | "date-fns": "^2.0.0-0", 56 | "eslint": "^5.5.0", 57 | "eslint-config-standard": "^12.0.0", 58 | "eslint-plugin-import": "^2.14.0", 59 | "eslint-plugin-node": "^7.0.1", 60 | "eslint-plugin-promise": "^4.0.0", 61 | "eslint-plugin-standard": "^4.0.0", 62 | "karma": "^3.0.0", 63 | "karma-chrome-launcher": "^2.2.0", 64 | "karma-firefox-launcher": "^1.1.0", 65 | "karma-tap": "^4.1.4", 66 | "karma-tap-pretty-reporter": "^4.1.0", 67 | "karma-webpack": "^4.0.0-0", 68 | "tap-diff": "^0.1.1", 69 | "typescript": "^3.0.3", 70 | "typescript-eslint-parser": "^18.0.0", 71 | "webpack": "^4.17.1" 72 | }, 73 | "start": { 74 | "require": [ 75 | [ 76 | "@babel/register", 77 | { 78 | "presets": [ 79 | [ 80 | "@babel/preset-env", 81 | { 82 | "targets": { 83 | "node": "current" 84 | }, 85 | "modules": false 86 | } 87 | ], 88 | "@babel/preset-typescript" 89 | ], 90 | "plugins": [ 91 | "@babel/plugin-syntax-dynamic-import" 92 | ], 93 | "extensions": [ 94 | ".ts", 95 | ".js" 96 | ] 97 | } 98 | ] 99 | ], 100 | "reporter": "@start/reporter-verbose" 101 | }, 102 | "eslintConfig": { 103 | "parser": "typescript-eslint-parser", 104 | "plugins": [ 105 | "standard", 106 | "node", 107 | "promise" 108 | ], 109 | "extends": [ 110 | "standard", 111 | "plugin:node/recommended", 112 | "plugin:promise/recommended" 113 | ], 114 | "env": { 115 | "node": true 116 | }, 117 | "rules": { 118 | "no-undef": "off", 119 | "no-unused-vars": "off", 120 | "prefer-promise-reject-errors": "off", 121 | "promise/avoid-new": "off", 122 | "node/no-unsupported-features/es-syntax": [ 123 | "error", 124 | { 125 | "ignores": [ 126 | "asyncFunctions", 127 | "modules" 128 | ] 129 | } 130 | ] 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # mnth 2 | 3 | **:warning: Project has been transferred to [NexTools metarepo](https://github.com/nextools/metarepo/tree/master/packages/mnth)** 4 | 5 | [![npm](https://img.shields.io/npm/v/mnth.svg?style=flat-square)](https://www.npmjs.com/package/mnth) [![tests](https://img.shields.io/travis/deepsweet/mnth/master.svg?label=tests&style=flat-square)](https://travis-ci.org/deepsweet/mnth) [![coverage](https://img.shields.io/codecov/c/github/deepsweet/mnth.svg?style=flat-square)](https://codecov.io/github/deepsweet/mnth) 6 | 7 | Framework-agnostic base block to build calendars, datepickers, etc by rendering 2d array of Dates. 8 | 9 | ## Requirements 10 | 11 | * [`date-fns@next`](https://github.com/date-fns/date-fns) dependency 12 | 13 | ### Node 14 | 15 | * Node.js >= 6 16 | * [`esm` loader](https://github.com/standard-things/esm) 17 | 18 | ### Browser 19 | 20 | * Browser from the [supported list](https://github.com/deepsweet/_/blob/master/packages/browserslist-preset/index.js) 21 | * Bundler with ESM support like [webpack](https://webpack.js.org/) 22 | 23 | ## Install 24 | 25 | ```sh 26 | $ yarn add date-fns@next mnth 27 | ``` 28 | 29 | ## Usage 30 | 31 | ```js 32 | mnth(date, options) 33 | ``` 34 | 35 | * `date` – Date object 36 | * `options` 37 | * `firstDay` – first day of the week, [from 0 to 6](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getDay), `1` by default 38 | 39 | ```js 40 | import { format, parse } from 'date-fns/esm' 41 | import mnth from 'mnth' 42 | 43 | const date = parse('2018-04-01', 'yyyy-MM-dd', new Date()) 44 | const month = mnth(date).map((week) => 45 | week.map((day) => format(day, 'yyyy-MM-dd')) 46 | ) 47 | 48 | console.log(month) 49 | /* 50 | [ 51 | [ '2018-03-26', '2018-03-27', '2018-03-28', '2018-03-29', '2018-03-30', '2018-03-31', '2018-04-01' ], 52 | [ '2018-04-02', '2018-04-03', '2018-04-04', '2018-04-05', '2018-04-06', '2018-04-07', '2018-04-08' ], 53 | [ '2018-04-09', '2018-04-10', '2018-04-11', '2018-04-12', '2018-04-13', '2018-04-14', '2018-04-15' ], 54 | [ '2018-04-16', '2018-04-17', '2018-04-18', '2018-04-19', '2018-04-20', '2018-04-21', '2018-04-22' ], 55 | [ '2018-04-23', '2018-04-24', '2018-04-25', '2018-04-26', '2018-04-27', '2018-04-28', '2018-04-29' ], 56 | [ '2018-04-30', '2018-05-01', '2018-05-02', '2018-05-03', '2018-05-04', '2018-05-05', '2018-05-06' ] 57 | ] 58 | */ 59 | ``` 60 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | addDays, 3 | endOfMonth, 4 | getDay, 5 | getDaysInMonth, 6 | setDate, 7 | startOfMonth 8 | } from 'date-fns' 9 | 10 | const DAYS_IN_WEEK = 7 11 | 12 | type Options = { 13 | firstDay: 0 | 1 | 2 | 3 | 4 | 5 | 6 14 | } 15 | 16 | const mnth = (date: Date, options?: Options): Date[][] => { 17 | const { firstDay } = { 18 | firstDay: 1, 19 | ...options 20 | } 21 | const daysInMonth = getDaysInMonth(date) 22 | const firstDateOfMonth = startOfMonth(date) 23 | const lastDateOfMonth = endOfMonth(date) 24 | const firstDayOfMonth = getDay(firstDateOfMonth) 25 | const lastDayOfMonth = getDay(lastDateOfMonth) 26 | const daysToPrepend = (firstDayOfMonth - firstDay + DAYS_IN_WEEK) % DAYS_IN_WEEK 27 | const daysToAppend = (DAYS_IN_WEEK - 1 - lastDayOfMonth + firstDay) % DAYS_IN_WEEK 28 | const month: Date[][] = [] 29 | let week: Date[] = [] 30 | 31 | for (let i = 1 - daysToPrepend; i <= daysInMonth + daysToAppend + 1; i++) { 32 | /* istanbul ignore else */ 33 | if (week.length <= 7) { 34 | if (i <= 0) { 35 | week.push( 36 | addDays(firstDateOfMonth, i - 1) 37 | ) 38 | } else if (i > daysInMonth) { 39 | week.push( 40 | addDays(lastDateOfMonth, i - daysInMonth) 41 | ) 42 | } else { 43 | week.push( 44 | setDate(date, i) 45 | ) 46 | } 47 | } 48 | 49 | if (week.length === 7) { 50 | month.push(week) 51 | week = [] 52 | } 53 | } 54 | 55 | return month 56 | } 57 | 58 | export default mnth 59 | -------------------------------------------------------------------------------- /tasks/babel/config.ts: -------------------------------------------------------------------------------- 1 | import browsersList from '@deepsweet/browserslist-preset' 2 | 3 | export const babelConfigNode = { 4 | babelrc: false, 5 | presets: [ 6 | '@babel/preset-typescript', 7 | [ 8 | '@babel/preset-env', 9 | { 10 | targets: { 11 | node: '8.6.0' 12 | } 13 | } 14 | ] 15 | ] 16 | } 17 | 18 | export const babelConfigBrowser = { 19 | babelrc: false, 20 | presets: [ 21 | '@babel/preset-typescript', 22 | [ 23 | '@babel/preset-env', 24 | { 25 | targets: { 26 | browsers: browsersList 27 | }, 28 | modules: false 29 | } 30 | ] 31 | ], 32 | plugins: [ 33 | '@babel/plugin-transform-runtime' 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /tasks/index.ts: -------------------------------------------------------------------------------- 1 | import sequence from '@start/plugin-sequence' 2 | import parallel from '@start/plugin-parallel' 3 | import find from '@start/plugin-find' 4 | import remove from '@start/plugin-remove' 5 | import read from '@start/plugin-read' 6 | import rename from '@start/plugin-rename' 7 | import write from '@start/plugin-write' 8 | import overwrite from '@start/plugin-overwrite' 9 | import babel from '@start/plugin-lib-babel' 10 | import typescriptGenerate from '@start/plugin-lib-typescript-generate' 11 | import typescriptCheck from '@start/plugin-lib-typescript-check' 12 | import watch from '@start/plugin-watch' 13 | import eslint from '@start/plugin-lib-eslint' 14 | import { 15 | istanbulInstrument, 16 | istanbulReport, 17 | istanbulThresholds 18 | } from '@start/plugin-lib-istanbul' 19 | import karma from '@start/plugin-lib-karma' 20 | import tape from '@start/plugin-lib-tape' 21 | import tapDiff from 'tap-diff' 22 | import codecov from '@start/plugin-lib-codecov' 23 | 24 | export const buildNode = async () => { 25 | const { babelConfigNode } = await import('./babel/config') 26 | 27 | return sequence( 28 | find('src/*.ts'), 29 | read, 30 | babel(babelConfigNode), 31 | rename((file) => file.replace(/\.ts$/, '.js')), 32 | write('build/node/') 33 | ) 34 | } 35 | 36 | export const buildBrowser = async () => { 37 | const { babelConfigBrowser } = await import('./babel/config') 38 | 39 | return sequence( 40 | find('src/*.ts'), 41 | read, 42 | babel(babelConfigBrowser), 43 | rename((file) => file.replace(/\.ts$/, '.js')), 44 | write('build/browser/') 45 | ) 46 | } 47 | 48 | export const build = parallel(['buildNode', 'buildBrowser']) 49 | 50 | export const dts = () => 51 | sequence( 52 | find('src/*.ts'), 53 | typescriptGenerate('build/') 54 | ) 55 | 56 | export const pack = () => 57 | sequence( 58 | find('build/'), 59 | remove, 60 | parallel(['build', 'dts'])() 61 | ) 62 | 63 | export const dev = () => watch('src/*.ts')(pack()) 64 | 65 | export const lint = () => 66 | sequence( 67 | find('{src,test,tasks}/*.ts'), 68 | read, 69 | eslint(), 70 | typescriptCheck() 71 | ) 72 | 73 | export const fix = () => 74 | sequence( 75 | find('{src,test,tasks}/*.ts'), 76 | read, 77 | eslint({ fix: true }), 78 | overwrite 79 | ) 80 | 81 | export const test = async () => { 82 | const { default: karmaConfig } = await import('./karma/config') 83 | 84 | return sequence( 85 | find(`coverage/`), 86 | remove, 87 | find('src/*.ts'), 88 | istanbulInstrument({ esModules: true, extensions: ['.ts'] }), 89 | find('test/*.ts'), 90 | tape(tapDiff), 91 | istanbulReport(['lcovonly', 'html', 'text-summary']), 92 | istanbulThresholds({ 93 | branches: 100, 94 | functions: 100, 95 | lines: 100, 96 | statements: 100 97 | }), 98 | karma(karmaConfig) 99 | ) 100 | } 101 | 102 | export const ci = () => 103 | sequence( 104 | lint(), 105 | test(), 106 | find('coverage/lcov.info'), 107 | read, 108 | codecov 109 | ) 110 | -------------------------------------------------------------------------------- /tasks/karma/config.ts: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import { LOG_ERROR } from 'karma/lib/constants' 3 | 4 | import { babelConfigBrowser } from '../babel/config' 5 | 6 | export default { 7 | plugins: [ 8 | 'karma-chrome-launcher', 9 | 'karma-firefox-launcher', 10 | 'karma-tap', 11 | 'karma-tap-pretty-reporter', 12 | 'karma-webpack' 13 | ], 14 | colors: true, 15 | files: [ 16 | 'test/index.ts' 17 | ], 18 | preprocessors: { 19 | 'test/index.ts': 'webpack' 20 | }, 21 | webpack: { 22 | mode: 'development', 23 | output: { 24 | filename: '[name]' 25 | }, 26 | node: { 27 | fs: 'empty' 28 | }, 29 | resolve: { 30 | extensions: ['.ts', '.js', '.json'] 31 | }, 32 | module: { 33 | rules: [ 34 | { 35 | test: /\.ts$/, 36 | exclude: path.resolve('node_modules/'), 37 | use: [ 38 | { 39 | loader: 'babel-loader', 40 | options: { 41 | ...babelConfigBrowser, 42 | cacheDirectory: true 43 | } 44 | } 45 | ] 46 | } 47 | ] 48 | } 49 | }, 50 | webpackMiddleware: { 51 | noInfo: true, 52 | quiet: true 53 | }, 54 | mime: { 55 | 'text/x-typescript': ['ts'] 56 | }, 57 | basePath: './', 58 | frameworks: ['tap'], 59 | customLaunchers: { 60 | Chrome_Travis: { 61 | base: 'ChromeHeadless', 62 | flags: ['--no-sandbox', '--disable-gpu'] 63 | }, 64 | Firefox_Travis: { 65 | base: 'Firefox', 66 | flags: ['-headless'] 67 | } 68 | }, 69 | // browsers: ['Chrome', 'Firefox'], 70 | browsers: ['Chrome_Travis', 'Firefox_Travis'], 71 | reporters: ['tap-pretty'], 72 | tapReporter: { 73 | prettify: require('tap-diff') 74 | }, 75 | logLevel: LOG_ERROR, 76 | singleRun: true, 77 | browserNoActivityTimeout: 60 * 1000, // default 10 * 1000 78 | browserDisconnectTimeout: 10 * 1000, // default 2 * 1000 79 | browserDisconnectTolerance: 2, // default 0 80 | captureTimeout: 2 * 60 * 1000 // default 1 * 60 * 1000 81 | } 82 | -------------------------------------------------------------------------------- /test/index.ts: -------------------------------------------------------------------------------- 1 | import test from 'tape' 2 | import { format, parse } from 'date-fns/esm' 3 | 4 | import mnth from '../src' 5 | 6 | const parseDate = (date: string) => parse(date, 'yyyy-MM-dd', new Date()) 7 | const formatMonth = (month: Date[][]) => month.map((week) => 8 | week.map((day) => format(day, 'yyyy-MM-dd')) 9 | ) 10 | 11 | test('first day of week is Monday, month starts on Monday', (t) => { 12 | const date = parseDate('2018-01-01') 13 | const month = formatMonth(mnth(date)) 14 | 15 | t.deepEqual( 16 | month, 17 | [ 18 | [ '2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04', '2018-01-05', '2018-01-06', '2018-01-07' ], 19 | [ '2018-01-08', '2018-01-09', '2018-01-10', '2018-01-11', '2018-01-12', '2018-01-13', '2018-01-14' ], 20 | [ '2018-01-15', '2018-01-16', '2018-01-17', '2018-01-18', '2018-01-19', '2018-01-20', '2018-01-21' ], 21 | [ '2018-01-22', '2018-01-23', '2018-01-24', '2018-01-25', '2018-01-26', '2018-01-27', '2018-01-28' ], 22 | [ '2018-01-29', '2018-01-30', '2018-01-31', '2018-02-01', '2018-02-02', '2018-02-03', '2018-02-04' ] 23 | ] 24 | ) 25 | t.end() 26 | }) 27 | 28 | test('first day of week is Monday, month starts on Sunday', (t) => { 29 | const date = parseDate('2018-04-01') 30 | const month = formatMonth(mnth(date)) 31 | 32 | t.deepEqual( 33 | month, 34 | [ 35 | [ '2018-03-26', '2018-03-27', '2018-03-28', '2018-03-29', '2018-03-30', '2018-03-31', '2018-04-01' ], 36 | [ '2018-04-02', '2018-04-03', '2018-04-04', '2018-04-05', '2018-04-06', '2018-04-07', '2018-04-08' ], 37 | [ '2018-04-09', '2018-04-10', '2018-04-11', '2018-04-12', '2018-04-13', '2018-04-14', '2018-04-15' ], 38 | [ '2018-04-16', '2018-04-17', '2018-04-18', '2018-04-19', '2018-04-20', '2018-04-21', '2018-04-22' ], 39 | [ '2018-04-23', '2018-04-24', '2018-04-25', '2018-04-26', '2018-04-27', '2018-04-28', '2018-04-29' ], 40 | [ '2018-04-30', '2018-05-01', '2018-05-02', '2018-05-03', '2018-05-04', '2018-05-05', '2018-05-06' ] 41 | ] 42 | ) 43 | t.end() 44 | }) 45 | 46 | test('first day of week is Monday, month ends on Sunday', (t) => { 47 | const date = parseDate('2017-04-01') 48 | const month = formatMonth(mnth(date)) 49 | 50 | t.deepEqual( 51 | month, 52 | [ 53 | [ '2017-03-27', '2017-03-28', '2017-03-29', '2017-03-30', '2017-03-31', '2017-04-01', '2017-04-02' ], 54 | [ '2017-04-03', '2017-04-04', '2017-04-05', '2017-04-06', '2017-04-07', '2017-04-08', '2017-04-09' ], 55 | [ '2017-04-10', '2017-04-11', '2017-04-12', '2017-04-13', '2017-04-14', '2017-04-15', '2017-04-16' ], 56 | [ '2017-04-17', '2017-04-18', '2017-04-19', '2017-04-20', '2017-04-21', '2017-04-22', '2017-04-23' ], 57 | [ '2017-04-24', '2017-04-25', '2017-04-26', '2017-04-27', '2017-04-28', '2017-04-29', '2017-04-30' ] 58 | ] 59 | ) 60 | t.end() 61 | }) 62 | 63 | test('first day of week is Monday, February, leap year', (t) => { 64 | const date = parseDate('2016-02-01') 65 | const month = formatMonth(mnth(date)) 66 | 67 | t.deepEqual( 68 | month, 69 | [ 70 | [ '2016-02-01', '2016-02-02', '2016-02-03', '2016-02-04', '2016-02-05', '2016-02-06', '2016-02-07' ], 71 | [ '2016-02-08', '2016-02-09', '2016-02-10', '2016-02-11', '2016-02-12', '2016-02-13', '2016-02-14' ], 72 | [ '2016-02-15', '2016-02-16', '2016-02-17', '2016-02-18', '2016-02-19', '2016-02-20', '2016-02-21' ], 73 | [ '2016-02-22', '2016-02-23', '2016-02-24', '2016-02-25', '2016-02-26', '2016-02-27', '2016-02-28' ], 74 | [ '2016-02-29', '2016-03-01', '2016-03-02', '2016-03-03', '2016-03-04', '2016-03-05', '2016-03-06' ] 75 | ] 76 | ) 77 | t.end() 78 | }) 79 | 80 | test('first day of week is Tuesday, month starts on Tuesday', (t) => { 81 | const date = parseDate('2018-05-01') 82 | const month = formatMonth( 83 | mnth(date, { firstDay: 2 }) 84 | ) 85 | 86 | t.deepEqual( 87 | month, 88 | [ 89 | [ '2018-05-01', '2018-05-02', '2018-05-03', '2018-05-04', '2018-05-05', '2018-05-06', '2018-05-07' ], 90 | [ '2018-05-08', '2018-05-09', '2018-05-10', '2018-05-11', '2018-05-12', '2018-05-13', '2018-05-14' ], 91 | [ '2018-05-15', '2018-05-16', '2018-05-17', '2018-05-18', '2018-05-19', '2018-05-20', '2018-05-21' ], 92 | [ '2018-05-22', '2018-05-23', '2018-05-24', '2018-05-25', '2018-05-26', '2018-05-27', '2018-05-28' ], 93 | [ '2018-05-29', '2018-05-30', '2018-05-31', '2018-06-01', '2018-06-02', '2018-06-03', '2018-06-04' ] 94 | ] 95 | ) 96 | t.end() 97 | }) 98 | 99 | test('first day of week is Tuesday, month starts on Monday, 6 weeks', (t) => { 100 | const date = parseDate('2018-10-01') 101 | const month = formatMonth( 102 | mnth(date, { firstDay: 2 }) 103 | ) 104 | 105 | t.deepEqual( 106 | month, 107 | [ 108 | [ '2018-09-25', '2018-09-26', '2018-09-27', '2018-09-28', '2018-09-29', '2018-09-30', '2018-10-01' ], 109 | [ '2018-10-02', '2018-10-03', '2018-10-04', '2018-10-05', '2018-10-06', '2018-10-07', '2018-10-08' ], 110 | [ '2018-10-09', '2018-10-10', '2018-10-11', '2018-10-12', '2018-10-13', '2018-10-14', '2018-10-15' ], 111 | [ '2018-10-16', '2018-10-17', '2018-10-18', '2018-10-19', '2018-10-20', '2018-10-21', '2018-10-22' ], 112 | [ '2018-10-23', '2018-10-24', '2018-10-25', '2018-10-26', '2018-10-27', '2018-10-28', '2018-10-29' ], 113 | [ '2018-10-30', '2018-10-31', '2018-11-01', '2018-11-02', '2018-11-03', '2018-11-04', '2018-11-05' ] 114 | ] 115 | ) 116 | t.end() 117 | }) 118 | 119 | test('first day of week is Tuesday, month ends on Monday', (t) => { 120 | const date = parseDate('2018-12-01') 121 | const month = formatMonth( 122 | mnth(date, { firstDay: 2 }) 123 | ) 124 | 125 | t.deepEqual( 126 | month, 127 | [ 128 | [ '2018-11-27', '2018-11-28', '2018-11-29', '2018-11-30', '2018-12-01', '2018-12-02', '2018-12-03' ], 129 | [ '2018-12-04', '2018-12-05', '2018-12-06', '2018-12-07', '2018-12-08', '2018-12-09', '2018-12-10' ], 130 | [ '2018-12-11', '2018-12-12', '2018-12-13', '2018-12-14', '2018-12-15', '2018-12-16', '2018-12-17' ], 131 | [ '2018-12-18', '2018-12-19', '2018-12-20', '2018-12-21', '2018-12-22', '2018-12-23', '2018-12-24' ], 132 | [ '2018-12-25', '2018-12-26', '2018-12-27', '2018-12-28', '2018-12-29', '2018-12-30', '2018-12-31' ] 133 | ] 134 | ) 135 | t.end() 136 | }) 137 | 138 | test('first day of week is Tuesday, February, leap year', (t) => { 139 | const date = parseDate('2016-02-01') 140 | const month = formatMonth( 141 | mnth(date, { firstDay: 2 }) 142 | ) 143 | 144 | t.deepEqual( 145 | month, 146 | [ 147 | [ '2016-01-26', '2016-01-27', '2016-01-28', '2016-01-29', '2016-01-30', '2016-01-31', '2016-02-01' ], 148 | [ '2016-02-02', '2016-02-03', '2016-02-04', '2016-02-05', '2016-02-06', '2016-02-07', '2016-02-08' ], 149 | [ '2016-02-09', '2016-02-10', '2016-02-11', '2016-02-12', '2016-02-13', '2016-02-14', '2016-02-15' ], 150 | [ '2016-02-16', '2016-02-17', '2016-02-18', '2016-02-19', '2016-02-20', '2016-02-21', '2016-02-22' ], 151 | [ '2016-02-23', '2016-02-24', '2016-02-25', '2016-02-26', '2016-02-27', '2016-02-28', '2016-02-29' ] 152 | ] 153 | ) 154 | t.end() 155 | }) 156 | 157 | test('first day of week is Wednesday, month starts on Wednesday', (t) => { 158 | const date = parseDate('2018-08-01') 159 | const month = formatMonth( 160 | mnth(date, { firstDay: 3 }) 161 | ) 162 | 163 | t.deepEqual( 164 | month, 165 | [ 166 | [ '2018-08-01', '2018-08-02', '2018-08-03', '2018-08-04', '2018-08-05', '2018-08-06', '2018-08-07' ], 167 | [ '2018-08-08', '2018-08-09', '2018-08-10', '2018-08-11', '2018-08-12', '2018-08-13', '2018-08-14' ], 168 | [ '2018-08-15', '2018-08-16', '2018-08-17', '2018-08-18', '2018-08-19', '2018-08-20', '2018-08-21' ], 169 | [ '2018-08-22', '2018-08-23', '2018-08-24', '2018-08-25', '2018-08-26', '2018-08-27', '2018-08-28' ], 170 | [ '2018-08-29', '2018-08-30', '2018-08-31', '2018-09-01', '2018-09-02', '2018-09-03', '2018-09-04' ] 171 | ] 172 | ) 173 | t.end() 174 | }) 175 | 176 | test('first day of week is Wednesday, month starts on Tuesday', (t) => { 177 | const date = parseDate('2018-05-01') 178 | const month = formatMonth( 179 | mnth(date, { firstDay: 3 }) 180 | ) 181 | 182 | t.deepEqual( 183 | month, 184 | [ 185 | [ '2018-04-25', '2018-04-26', '2018-04-27', '2018-04-28', '2018-04-29', '2018-04-30', '2018-05-01' ], 186 | [ '2018-05-02', '2018-05-03', '2018-05-04', '2018-05-05', '2018-05-06', '2018-05-07', '2018-05-08' ], 187 | [ '2018-05-09', '2018-05-10', '2018-05-11', '2018-05-12', '2018-05-13', '2018-05-14', '2018-05-15' ], 188 | [ '2018-05-16', '2018-05-17', '2018-05-18', '2018-05-19', '2018-05-20', '2018-05-21', '2018-05-22' ], 189 | [ '2018-05-23', '2018-05-24', '2018-05-25', '2018-05-26', '2018-05-27', '2018-05-28', '2018-05-29' ], 190 | [ '2018-05-30', '2018-05-31', '2018-06-01', '2018-06-02', '2018-06-03', '2018-06-04', '2018-06-05' ] 191 | ] 192 | ) 193 | t.end() 194 | }) 195 | 196 | test('first day of week is Wednesday, month ends on Tuesday', (t) => { 197 | const date = parseDate('2018-07-01') 198 | const month = formatMonth( 199 | mnth(date, { firstDay: 3 }) 200 | ) 201 | 202 | t.deepEqual( 203 | month, 204 | [ 205 | [ '2018-06-27', '2018-06-28', '2018-06-29', '2018-06-30', '2018-07-01', '2018-07-02', '2018-07-03' ], 206 | [ '2018-07-04', '2018-07-05', '2018-07-06', '2018-07-07', '2018-07-08', '2018-07-09', '2018-07-10' ], 207 | [ '2018-07-11', '2018-07-12', '2018-07-13', '2018-07-14', '2018-07-15', '2018-07-16', '2018-07-17' ], 208 | [ '2018-07-18', '2018-07-19', '2018-07-20', '2018-07-21', '2018-07-22', '2018-07-23', '2018-07-24' ], 209 | [ '2018-07-25', '2018-07-26', '2018-07-27', '2018-07-28', '2018-07-29', '2018-07-30', '2018-07-31' ] 210 | ] 211 | ) 212 | t.end() 213 | }) 214 | 215 | test('first day of week is Wednesday, February, leap year', (t) => { 216 | const date = parseDate('2016-02-01') 217 | const month = formatMonth( 218 | mnth(date, { firstDay: 3 }) 219 | ) 220 | 221 | t.deepEqual( 222 | month, 223 | [ 224 | [ '2016-01-27', '2016-01-28', '2016-01-29', '2016-01-30', '2016-01-31', '2016-02-01', '2016-02-02' ], 225 | [ '2016-02-03', '2016-02-04', '2016-02-05', '2016-02-06', '2016-02-07', '2016-02-08', '2016-02-09' ], 226 | [ '2016-02-10', '2016-02-11', '2016-02-12', '2016-02-13', '2016-02-14', '2016-02-15', '2016-02-16' ], 227 | [ '2016-02-17', '2016-02-18', '2016-02-19', '2016-02-20', '2016-02-21', '2016-02-22', '2016-02-23' ], 228 | [ '2016-02-24', '2016-02-25', '2016-02-26', '2016-02-27', '2016-02-28', '2016-02-29', '2016-03-01' ] 229 | ] 230 | ) 231 | t.end() 232 | }) 233 | 234 | test('first day of week is Thursday, month starts on Thursday, 4 weeks', (t) => { 235 | const date = parseDate('2018-02-01') 236 | const month = formatMonth( 237 | mnth(date, { firstDay: 4 }) 238 | ) 239 | 240 | t.deepEqual( 241 | month, 242 | [ 243 | [ '2018-02-01', '2018-02-02', '2018-02-03', '2018-02-04', '2018-02-05', '2018-02-06', '2018-02-07' ], 244 | [ '2018-02-08', '2018-02-09', '2018-02-10', '2018-02-11', '2018-02-12', '2018-02-13', '2018-02-14' ], 245 | [ '2018-02-15', '2018-02-16', '2018-02-17', '2018-02-18', '2018-02-19', '2018-02-20', '2018-02-21' ], 246 | [ '2018-02-22', '2018-02-23', '2018-02-24', '2018-02-25', '2018-02-26', '2018-02-27', '2018-02-28' ] 247 | ] 248 | ) 249 | t.end() 250 | }) 251 | 252 | test('first day of week is Thursday, month starts on Wednesday, 6 weeks', (t) => { 253 | const date = parseDate('2018-08-01') 254 | const month = formatMonth( 255 | mnth(date, { firstDay: 4 }) 256 | ) 257 | 258 | t.deepEqual( 259 | month, 260 | [ 261 | [ '2018-07-26', '2018-07-27', '2018-07-28', '2018-07-29', '2018-07-30', '2018-07-31', '2018-08-01' ], 262 | [ '2018-08-02', '2018-08-03', '2018-08-04', '2018-08-05', '2018-08-06', '2018-08-07', '2018-08-08' ], 263 | [ '2018-08-09', '2018-08-10', '2018-08-11', '2018-08-12', '2018-08-13', '2018-08-14', '2018-08-15' ], 264 | [ '2018-08-16', '2018-08-17', '2018-08-18', '2018-08-19', '2018-08-20', '2018-08-21', '2018-08-22' ], 265 | [ '2018-08-23', '2018-08-24', '2018-08-25', '2018-08-26', '2018-08-27', '2018-08-28', '2018-08-29' ], 266 | [ '2018-08-30', '2018-08-31', '2018-09-01', '2018-09-02', '2018-09-03', '2018-09-04', '2018-09-05' ] 267 | ] 268 | ) 269 | t.end() 270 | }) 271 | 272 | test('first day of week is Thursday, month ends on Wednesday', (t) => { 273 | const date = parseDate('2018-10-01') 274 | const month = formatMonth( 275 | mnth(date, { firstDay: 4 }) 276 | ) 277 | 278 | t.deepEqual( 279 | month, 280 | [ 281 | [ '2018-09-27', '2018-09-28', '2018-09-29', '2018-09-30', '2018-10-01', '2018-10-02', '2018-10-03' ], 282 | [ '2018-10-04', '2018-10-05', '2018-10-06', '2018-10-07', '2018-10-08', '2018-10-09', '2018-10-10' ], 283 | [ '2018-10-11', '2018-10-12', '2018-10-13', '2018-10-14', '2018-10-15', '2018-10-16', '2018-10-17' ], 284 | [ '2018-10-18', '2018-10-19', '2018-10-20', '2018-10-21', '2018-10-22', '2018-10-23', '2018-10-24' ], 285 | [ '2018-10-25', '2018-10-26', '2018-10-27', '2018-10-28', '2018-10-29', '2018-10-30', '2018-10-31' ] 286 | ] 287 | ) 288 | t.end() 289 | }) 290 | 291 | test('first day of week is Thursday, February, leap year', (t) => { 292 | const date = parseDate('2016-02-01') 293 | const month = formatMonth( 294 | mnth(date, { firstDay: 4 }) 295 | ) 296 | 297 | t.deepEqual( 298 | month, 299 | [ 300 | [ '2016-01-28', '2016-01-29', '2016-01-30', '2016-01-31', '2016-02-01', '2016-02-02', '2016-02-03' ], 301 | [ '2016-02-04', '2016-02-05', '2016-02-06', '2016-02-07', '2016-02-08', '2016-02-09', '2016-02-10' ], 302 | [ '2016-02-11', '2016-02-12', '2016-02-13', '2016-02-14', '2016-02-15', '2016-02-16', '2016-02-17' ], 303 | [ '2016-02-18', '2016-02-19', '2016-02-20', '2016-02-21', '2016-02-22', '2016-02-23', '2016-02-24' ], 304 | [ '2016-02-25', '2016-02-26', '2016-02-27', '2016-02-28', '2016-02-29', '2016-03-01', '2016-03-02' ] 305 | ] 306 | ) 307 | t.end() 308 | }) 309 | 310 | test('first day of week is Friday, month starts on Friday', (t) => { 311 | const date = parseDate('2018-06-01') 312 | const month = formatMonth( 313 | mnth(date, { firstDay: 5 }) 314 | ) 315 | 316 | t.deepEqual( 317 | month, 318 | [ 319 | [ '2018-06-01', '2018-06-02', '2018-06-03', '2018-06-04', '2018-06-05', '2018-06-06', '2018-06-07' ], 320 | [ '2018-06-08', '2018-06-09', '2018-06-10', '2018-06-11', '2018-06-12', '2018-06-13', '2018-06-14' ], 321 | [ '2018-06-15', '2018-06-16', '2018-06-17', '2018-06-18', '2018-06-19', '2018-06-20', '2018-06-21' ], 322 | [ '2018-06-22', '2018-06-23', '2018-06-24', '2018-06-25', '2018-06-26', '2018-06-27', '2018-06-28' ], 323 | [ '2018-06-29', '2018-06-30', '2018-07-01', '2018-07-02', '2018-07-03', '2018-07-04', '2018-07-05' ] 324 | ] 325 | ) 326 | t.end() 327 | }) 328 | 329 | test('first day of week is Friday, month starts on Thursday, 6 weeks', (t) => { 330 | const date = parseDate('2018-03-01') 331 | const month = formatMonth( 332 | mnth(date, { firstDay: 5 }) 333 | ) 334 | 335 | t.deepEqual( 336 | month, 337 | [ 338 | [ '2018-02-23', '2018-02-24', '2018-02-25', '2018-02-26', '2018-02-27', '2018-02-28', '2018-03-01' ], 339 | [ '2018-03-02', '2018-03-03', '2018-03-04', '2018-03-05', '2018-03-06', '2018-03-07', '2018-03-08' ], 340 | [ '2018-03-09', '2018-03-10', '2018-03-11', '2018-03-12', '2018-03-13', '2018-03-14', '2018-03-15' ], 341 | [ '2018-03-16', '2018-03-17', '2018-03-18', '2018-03-19', '2018-03-20', '2018-03-21', '2018-03-22' ], 342 | [ '2018-03-23', '2018-03-24', '2018-03-25', '2018-03-26', '2018-03-27', '2018-03-28', '2018-03-29' ], 343 | [ '2018-03-30', '2018-03-31', '2018-04-01', '2018-04-02', '2018-04-03', '2018-04-04', '2018-04-05' ] 344 | ] 345 | ) 346 | t.end() 347 | }) 348 | 349 | test('first day of week is Friday, month ends on Thursday', (t) => { 350 | const date = parseDate('2018-05-01') 351 | const month = formatMonth( 352 | mnth(date, { firstDay: 5 }) 353 | ) 354 | 355 | t.deepEqual( 356 | month, 357 | [ 358 | [ '2018-04-27', '2018-04-28', '2018-04-29', '2018-04-30', '2018-05-01', '2018-05-02', '2018-05-03' ], 359 | [ '2018-05-04', '2018-05-05', '2018-05-06', '2018-05-07', '2018-05-08', '2018-05-09', '2018-05-10' ], 360 | [ '2018-05-11', '2018-05-12', '2018-05-13', '2018-05-14', '2018-05-15', '2018-05-16', '2018-05-17' ], 361 | [ '2018-05-18', '2018-05-19', '2018-05-20', '2018-05-21', '2018-05-22', '2018-05-23', '2018-05-24' ], 362 | [ '2018-05-25', '2018-05-26', '2018-05-27', '2018-05-28', '2018-05-29', '2018-05-30', '2018-05-31' ] 363 | ] 364 | ) 365 | t.end() 366 | }) 367 | 368 | test('first day of week is Friday, February, leap year', (t) => { 369 | const date = parseDate('2016-02-01') 370 | const month = formatMonth( 371 | mnth(date, { firstDay: 5 }) 372 | ) 373 | 374 | t.deepEqual( 375 | month, 376 | [ 377 | [ '2016-01-29', '2016-01-30', '2016-01-31', '2016-02-01', '2016-02-02', '2016-02-03', '2016-02-04' ], 378 | [ '2016-02-05', '2016-02-06', '2016-02-07', '2016-02-08', '2016-02-09', '2016-02-10', '2016-02-11' ], 379 | [ '2016-02-12', '2016-02-13', '2016-02-14', '2016-02-15', '2016-02-16', '2016-02-17', '2016-02-18' ], 380 | [ '2016-02-19', '2016-02-20', '2016-02-21', '2016-02-22', '2016-02-23', '2016-02-24', '2016-02-25' ], 381 | [ '2016-02-26', '2016-02-27', '2016-02-28', '2016-02-29', '2016-03-01', '2016-03-02', '2016-03-03' ] 382 | ] 383 | ) 384 | t.end() 385 | }) 386 | 387 | test('first day of week is Saturday, month starts on Saturday', (t) => { 388 | const date = parseDate('2018-09-01') 389 | const month = formatMonth( 390 | mnth(date, { firstDay: 6 }) 391 | ) 392 | 393 | t.deepEqual( 394 | month, 395 | [ 396 | [ '2018-09-01', '2018-09-02', '2018-09-03', '2018-09-04', '2018-09-05', '2018-09-06', '2018-09-07' ], 397 | [ '2018-09-08', '2018-09-09', '2018-09-10', '2018-09-11', '2018-09-12', '2018-09-13', '2018-09-14' ], 398 | [ '2018-09-15', '2018-09-16', '2018-09-17', '2018-09-18', '2018-09-19', '2018-09-20', '2018-09-21' ], 399 | [ '2018-09-22', '2018-09-23', '2018-09-24', '2018-09-25', '2018-09-26', '2018-09-27', '2018-09-28' ], 400 | [ '2018-09-29', '2018-09-30', '2018-10-01', '2018-10-02', '2018-10-03', '2018-10-04', '2018-10-05' ] 401 | ] 402 | ) 403 | t.end() 404 | }) 405 | 406 | test('first day of week is Saturday, month starts on Friday, 6 weeks', (t) => { 407 | const date = parseDate('2018-06-01') 408 | const month = formatMonth( 409 | mnth(date, { firstDay: 6 }) 410 | ) 411 | 412 | t.deepEqual( 413 | month, 414 | [ 415 | [ '2018-05-26', '2018-05-27', '2018-05-28', '2018-05-29', '2018-05-30', '2018-05-31', '2018-06-01' ], 416 | [ '2018-06-02', '2018-06-03', '2018-06-04', '2018-06-05', '2018-06-06', '2018-06-07', '2018-06-08' ], 417 | [ '2018-06-09', '2018-06-10', '2018-06-11', '2018-06-12', '2018-06-13', '2018-06-14', '2018-06-15' ], 418 | [ '2018-06-16', '2018-06-17', '2018-06-18', '2018-06-19', '2018-06-20', '2018-06-21', '2018-06-22' ], 419 | [ '2018-06-23', '2018-06-24', '2018-06-25', '2018-06-26', '2018-06-27', '2018-06-28', '2018-06-29' ], 420 | [ '2018-06-30', '2018-07-01', '2018-07-02', '2018-07-03', '2018-07-04', '2018-07-05', '2018-07-06' ] 421 | ] 422 | ) 423 | t.end() 424 | }) 425 | 426 | test('first day of week is Saturday, month ends on Friday', (t) => { 427 | const date = parseDate('2018-08-01') 428 | const month = formatMonth( 429 | mnth(date, { firstDay: 6 }) 430 | ) 431 | 432 | t.deepEqual( 433 | month, 434 | [ 435 | [ '2018-07-28', '2018-07-29', '2018-07-30', '2018-07-31', '2018-08-01', '2018-08-02', '2018-08-03' ], 436 | [ '2018-08-04', '2018-08-05', '2018-08-06', '2018-08-07', '2018-08-08', '2018-08-09', '2018-08-10' ], 437 | [ '2018-08-11', '2018-08-12', '2018-08-13', '2018-08-14', '2018-08-15', '2018-08-16', '2018-08-17' ], 438 | [ '2018-08-18', '2018-08-19', '2018-08-20', '2018-08-21', '2018-08-22', '2018-08-23', '2018-08-24' ], 439 | [ '2018-08-25', '2018-08-26', '2018-08-27', '2018-08-28', '2018-08-29', '2018-08-30', '2018-08-31' ] 440 | ] 441 | ) 442 | t.end() 443 | }) 444 | 445 | test('first day of week is Saturday, February, leap year', (t) => { 446 | const date = parseDate('2016-02-01') 447 | const month = formatMonth( 448 | mnth(date, { firstDay: 6 }) 449 | ) 450 | 451 | t.deepEqual( 452 | month, 453 | [ 454 | [ '2016-01-30', '2016-01-31', '2016-02-01', '2016-02-02', '2016-02-03', '2016-02-04', '2016-02-05' ], 455 | [ '2016-02-06', '2016-02-07', '2016-02-08', '2016-02-09', '2016-02-10', '2016-02-11', '2016-02-12' ], 456 | [ '2016-02-13', '2016-02-14', '2016-02-15', '2016-02-16', '2016-02-17', '2016-02-18', '2016-02-19' ], 457 | [ '2016-02-20', '2016-02-21', '2016-02-22', '2016-02-23', '2016-02-24', '2016-02-25', '2016-02-26' ], 458 | [ '2016-02-27', '2016-02-28', '2016-02-29', '2016-03-01', '2016-03-02', '2016-03-03', '2016-03-04' ] 459 | ] 460 | ) 461 | t.end() 462 | }) 463 | 464 | test('first day of week is Sunday, month starts on Sunday', (t) => { 465 | const date = parseDate('2018-07-01') 466 | const month = formatMonth( 467 | mnth(date, { firstDay: 0 }) 468 | ) 469 | 470 | t.deepEqual( 471 | month, 472 | [ 473 | [ '2018-07-01', '2018-07-02', '2018-07-03', '2018-07-04', '2018-07-05', '2018-07-06', '2018-07-07' ], 474 | [ '2018-07-08', '2018-07-09', '2018-07-10', '2018-07-11', '2018-07-12', '2018-07-13', '2018-07-14' ], 475 | [ '2018-07-15', '2018-07-16', '2018-07-17', '2018-07-18', '2018-07-19', '2018-07-20', '2018-07-21' ], 476 | [ '2018-07-22', '2018-07-23', '2018-07-24', '2018-07-25', '2018-07-26', '2018-07-27', '2018-07-28' ], 477 | [ '2018-07-29', '2018-07-30', '2018-07-31', '2018-08-01', '2018-08-02', '2018-08-03', '2018-08-04' ] 478 | ] 479 | ) 480 | t.end() 481 | }) 482 | 483 | test('first day of week is Sunday, month starts on Saturday, 6 weeks', (t) => { 484 | const date = parseDate('2018-12-01') 485 | const month = formatMonth( 486 | mnth(date, { firstDay: 0 }) 487 | ) 488 | 489 | t.deepEqual( 490 | month, 491 | [ 492 | [ '2018-11-25', '2018-11-26', '2018-11-27', '2018-11-28', '2018-11-29', '2018-11-30', '2018-12-01' ], 493 | [ '2018-12-02', '2018-12-03', '2018-12-04', '2018-12-05', '2018-12-06', '2018-12-07', '2018-12-08' ], 494 | [ '2018-12-09', '2018-12-10', '2018-12-11', '2018-12-12', '2018-12-13', '2018-12-14', '2018-12-15' ], 495 | [ '2018-12-16', '2018-12-17', '2018-12-18', '2018-12-19', '2018-12-20', '2018-12-21', '2018-12-22' ], 496 | [ '2018-12-23', '2018-12-24', '2018-12-25', '2018-12-26', '2018-12-27', '2018-12-28', '2018-12-29' ], 497 | [ '2018-12-30', '2018-12-31', '2019-01-01', '2019-01-02', '2019-01-03', '2019-01-04', '2019-01-05' ] ] 498 | ) 499 | t.end() 500 | }) 501 | 502 | test('first day of week is Sunday, month ends on Saturday', (t) => { 503 | const date = parseDate('2018-03-01') 504 | const month = formatMonth( 505 | mnth(date, { firstDay: 0 }) 506 | ) 507 | 508 | t.deepEqual( 509 | month, 510 | [ 511 | [ '2018-02-25', '2018-02-26', '2018-02-27', '2018-02-28', '2018-03-01', '2018-03-02', '2018-03-03' ], 512 | [ '2018-03-04', '2018-03-05', '2018-03-06', '2018-03-07', '2018-03-08', '2018-03-09', '2018-03-10' ], 513 | [ '2018-03-11', '2018-03-12', '2018-03-13', '2018-03-14', '2018-03-15', '2018-03-16', '2018-03-17' ], 514 | [ '2018-03-18', '2018-03-19', '2018-03-20', '2018-03-21', '2018-03-22', '2018-03-23', '2018-03-24' ], 515 | [ '2018-03-25', '2018-03-26', '2018-03-27', '2018-03-28', '2018-03-29', '2018-03-30', '2018-03-31' ] 516 | ] 517 | ) 518 | t.end() 519 | }) 520 | 521 | test('first day of week is Sunday, February, leap year', (t) => { 522 | const date = parseDate('2016-02-01') 523 | const month = formatMonth( 524 | mnth(date, { firstDay: 0 }) 525 | ) 526 | 527 | t.deepEqual( 528 | month, 529 | [ 530 | [ '2016-01-31', '2016-02-01', '2016-02-02', '2016-02-03', '2016-02-04', '2016-02-05', '2016-02-06' ], 531 | [ '2016-02-07', '2016-02-08', '2016-02-09', '2016-02-10', '2016-02-11', '2016-02-12', '2016-02-13' ], 532 | [ '2016-02-14', '2016-02-15', '2016-02-16', '2016-02-17', '2016-02-18', '2016-02-19', '2016-02-20' ], 533 | [ '2016-02-21', '2016-02-22', '2016-02-23', '2016-02-24', '2016-02-25', '2016-02-26', '2016-02-27' ], 534 | [ '2016-02-28', '2016-02-29', '2016-03-01', '2016-03-02', '2016-03-03', '2016-03-04', '2016-03-05' ] 535 | ] 536 | ) 537 | t.end() 538 | }) 539 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "noEmit": true, 5 | "pretty": true, 6 | "lib": ["esnext"], 7 | "moduleResolution": "node" 8 | }, 9 | "exclude": ["node_modules/", "coverage/", "build/"] 10 | } 11 | --------------------------------------------------------------------------------