summaryrefslogtreecommitdiff
path: root/date-fns/scripts/build
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2021-08-23 16:46:06 -0300
committerSebastian <sebasjm@gmail.com>2021-08-23 16:48:30 -0300
commit38acabfa6089ab8ac469c12b5f55022fb96935e5 (patch)
tree453dbf70000cc5e338b06201af1eaca8343f8f73 /date-fns/scripts/build
parentf26125e039143b92dc0d84e7775f508ab0cdcaa8 (diff)
downloadnode-vendor-38acabfa6089ab8ac469c12b5f55022fb96935e5.tar.gz
node-vendor-38acabfa6089ab8ac469c12b5f55022fb96935e5.tar.bz2
node-vendor-38acabfa6089ab8ac469c12b5f55022fb96935e5.zip
added web vendorsHEADmaster
Diffstat (limited to 'date-fns/scripts/build')
-rw-r--r--date-fns/scripts/build/_lib/addDenoExtensions.ts79
-rw-r--r--date-fns/scripts/build/_lib/prettier.js6
-rw-r--r--date-fns/scripts/build/_lib/typings/common.js92
-rw-r--r--date-fns/scripts/build/_lib/typings/flow.js190
-rw-r--r--date-fns/scripts/build/_lib/typings/formatBlock.js149
-rw-r--r--date-fns/scripts/build/_lib/typings/typeScript.js460
-rwxr-xr-xdate-fns/scripts/build/build.sh12
-rwxr-xr-xdate-fns/scripts/build/deno.sh7
-rwxr-xr-xdate-fns/scripts/build/docs.js380
-rwxr-xr-xdate-fns/scripts/build/fp.js51
-rwxr-xr-xdate-fns/scripts/build/indices.js61
-rw-r--r--date-fns/scripts/build/localeSnapshots/_lib/distanceDates.js59
-rwxr-xr-xdate-fns/scripts/build/localeSnapshots/index.js69
-rw-r--r--date-fns/scripts/build/localeSnapshots/renderFormatDistance/index.js26
-rw-r--r--date-fns/scripts/build/localeSnapshots/renderFormatDistanceStrict/index.js26
-rw-r--r--date-fns/scripts/build/localeSnapshots/renderFormatParse/formatParseTokens.js218
-rw-r--r--date-fns/scripts/build/localeSnapshots/renderFormatParse/index.js59
-rw-r--r--date-fns/scripts/build/localeSnapshots/renderFormatRelative/index.js23
-rwxr-xr-xdate-fns/scripts/build/package.sh51
-rwxr-xr-xdate-fns/scripts/build/packages.js92
-rwxr-xr-xdate-fns/scripts/build/removeOutdatedLocales.js20
-rwxr-xr-xdate-fns/scripts/build/typings.js31
22 files changed, 2161 insertions, 0 deletions
diff --git a/date-fns/scripts/build/_lib/addDenoExtensions.ts b/date-fns/scripts/build/_lib/addDenoExtensions.ts
new file mode 100644
index 0000000..f0e43d6
--- /dev/null
+++ b/date-fns/scripts/build/_lib/addDenoExtensions.ts
@@ -0,0 +1,79 @@
+import { resolve, dirname } from 'path'
+import fs from 'fs'
+import globby from 'globby'
+import ts, {
+ ExportDeclaration,
+ ImportDeclaration,
+ StringLiteral,
+} from 'typescript'
+
+const { readFile, writeFile, stat } = fs.promises
+
+const pattern = /\.(ts|js)$/
+const ignore = [/\.d\.ts$/]
+
+const resolvedExtensions: Record<string, string> = {}
+
+globby('deno')
+ .then((files) =>
+ files.filter(
+ (file) => pattern.test(file) && !ignore.find((p) => p.test(file))
+ )
+ )
+ .then((files) =>
+ Promise.all(
+ files.map((file) =>
+ readFile(file, 'utf8').then(async (content) => {
+ const source = ts.createSourceFile(
+ file,
+ content,
+ ts.ScriptTarget.Latest
+ )
+ const imports: string[] = []
+
+ source.forEachChild((node) => {
+ if (
+ [
+ ts.SyntaxKind.ImportDeclaration,
+ ts.SyntaxKind.ExportDeclaration,
+ ].includes(node.kind)
+ ) {
+ const importNode = node as ImportDeclaration | ExportDeclaration
+ const specifier = importNode.moduleSpecifier as StringLiteral
+ const importPath = specifier.text
+ const isLocal = /\.\/.+/
+ if (isLocal) imports.push(importPath)
+ }
+ })
+
+ await Promise.all(
+ imports.map(async (importPath) => {
+ if (resolvedExtensions[importPath]) return
+ const fullPath = resolveFullPath(file, importPath)
+ let isTs = false
+ try {
+ await stat(fullPath + '.ts')
+ isTs = true
+ } catch (_) {}
+ resolvedExtensions[fullPath] = isTs ? '.ts' : '.js'
+ })
+ )
+
+ return writeFile(
+ file,
+ imports.reduce((acc, importPath) => {
+ const fullPath = resolveFullPath(file, importPath)
+ return acc.replace(
+ new RegExp(importPath, 'g'),
+ importPath + resolvedExtensions[fullPath]
+ )
+ }, content)
+ )
+ })
+ )
+ )
+ )
+
+function resolveFullPath(file: string, importPath: string) {
+ return resolve(dirname(file), importPath)
+}
diff --git a/date-fns/scripts/build/_lib/prettier.js b/date-fns/scripts/build/_lib/prettier.js
new file mode 100644
index 0000000..a8fb388
--- /dev/null
+++ b/date-fns/scripts/build/_lib/prettier.js
@@ -0,0 +1,6 @@
+const prettier = require('prettier')
+const config = require('../../../.prettierrc')
+
+module.exports = (code, parser = 'babel') => {
+ return prettier.format(code, Object.assign(config, { parser }))
+}
diff --git a/date-fns/scripts/build/_lib/typings/common.js b/date-fns/scripts/build/_lib/typings/common.js
new file mode 100644
index 0000000..cd56267
--- /dev/null
+++ b/date-fns/scripts/build/_lib/typings/common.js
@@ -0,0 +1,92 @@
+const { addSeparator, formatBlock } = require('./formatBlock')
+
+const lowerCaseTypes = ['String', 'Number', 'Boolean']
+
+function correctTypeCase(type) {
+ if (lowerCaseTypes.includes(type)) {
+ return type.toLowerCase()
+ }
+ return type
+}
+
+function getParams(params, { leftBorder = '{', rightBorder = '}' } = {}) {
+ if (!params || params.length === 0) {
+ return leftBorder + rightBorder
+ }
+
+ const formattedParams = addSeparator(
+ params.map(param => {
+ const {
+ name,
+ props,
+ optional,
+ variable,
+ type: { names: typeNames }
+ } = param
+ const type = getType(typeNames, { props, forceArray: variable })
+ return `${variable ? '...' : ''}${name}${optional ? '?' : ''}: ${type}`
+ }),
+ ','
+ )
+
+ return formatBlock`
+ ${leftBorder}
+ ${formattedParams}
+ ${rightBorder}
+ `
+}
+
+function getType(types, { props = [], forceArray = false } = {}) {
+ const typeStrings = types.map(type => {
+ if (type === '*') {
+ return 'any'
+ }
+
+ if (type === 'function') {
+ return '(...args: Array<any>) => any'
+ }
+
+ if (type.startsWith('Array.')) {
+ const [, arrayType] = type.match(/^Array\.<(\w+)>$/i)
+ return `${correctTypeCase(arrayType)}[]`
+ }
+
+ if (type === 'Object' && props.length > 0) {
+ return getParams(props)
+ }
+
+ const caseCorrectedType = correctTypeCase(type)
+ if (forceArray) {
+ return `${caseCorrectedType}[]`
+ }
+
+ return caseCorrectedType
+ })
+
+ const allArrayTypes =
+ typeStrings.length > 1 && typeStrings.every(type => type.endsWith('[]'))
+ if (allArrayTypes) {
+ return `(${typeStrings.map(type => type.replace('[]', '')).join(' | ')})[]`
+ }
+
+ return typeStrings.join(' | ')
+}
+
+function getFPFnType(params, returns) {
+ const fpParamTypes = params.map(param =>
+ getType(param.type.names, { props: param.props })
+ )
+
+ const arity = fpParamTypes.length
+
+ fpParamTypes.push(getType(returns))
+
+ return `CurriedFn${arity}<${fpParamTypes.join(', ')}>`
+}
+
+module.exports = {
+ correctTypeCase,
+ getParams,
+ getType,
+ getFPFnType
+}
diff --git a/date-fns/scripts/build/_lib/typings/flow.js b/date-fns/scripts/build/_lib/typings/flow.js
new file mode 100644
index 0000000..8eca3b7
--- /dev/null
+++ b/date-fns/scripts/build/_lib/typings/flow.js
@@ -0,0 +1,190 @@
+const fs = require('fs')
+const path = require('path')
+const prettier = require('../prettier')
+
+const { getParams, getType, getFPFnType } = require('./common')
+
+const { addSeparator, formatBlock, formatFlowFile } = require('./formatBlock')
+
+/**
+ * Return curried function type aliases for a specific FP function arity.
+ * @param {Number} [arity=4]
+ */
+const getFlowFPTypeAliases = (arity = 4) =>
+ [
+ 'type CurriedFn1<A, R> = <A>(a: A) => R',
+
+ formatBlock`
+ type CurriedFn2<A, B, R> = <A>(a: A) => CurriedFn1<B, R>
+ | <A, B>(a: A, b: B) => R
+ `,
+
+ formatBlock`
+ type CurriedFn3<A, B, C, R> = <A>(a: A) => CurriedFn2<B, C, R>
+ | <A,B>(a: A, b: B) => CurriedFn1<C, R>
+ | <A,B,C>(a: A, b: B, c: C) => R
+ `,
+
+ formatBlock`
+ type CurriedFn4<A, B, C, D, R> = <A>(a: A) => CurriedFn3<B, C, D, R>
+ | <A,B>(a: A, b: B) => CurriedFn2<C, D, R>
+ | <A,B,C>(a: A, b: B, c: C) => CurriedFn1<D, R>
+ | <A,B,C,D>(a: A, b: B, c: C, d: D) => R
+ `,
+ ].slice(0, arity)
+
+function getFlowTypeAlias(type) {
+ const { title, properties, content } = type
+ return `export type ${title} = ${
+ properties ? getParams(properties) : content.type.names.join(' | ')
+ }`
+}
+
+function generateFlowFnTyping(fn, aliasDeclarations) {
+ const { title, args, content } = fn
+
+ const params = getParams(args, { leftBorder: '(', rightBorder: ')' })
+ const returns = getType(content.returns[0].type.names)
+
+ const moduleDeclaration = `declare module.exports: ${params} => ${returns}`
+
+ const typingFile = formatFlowFile`
+ ${addSeparator(aliasDeclarations, '\n')}
+
+ ${moduleDeclaration}
+ `
+
+ writeFile(`src/${title}/index.js.flow`, typingFile)
+}
+
+function generateFlowFnIndexTyping(fns, aliasDeclarations, constants) {
+ const fnsDeclarations = fns.map(({ title, args, content }) => {
+ const params = getParams(args, { leftBorder: '(', rightBorder: ')' })
+ const returns = getType(content.returns[0].type.names)
+ return `${title}: ${params} => ${returns}`
+ })
+
+ const typingFile = formatFlowFile`
+ ${addSeparator(aliasDeclarations, '\n')}
+
+ declare module.exports: {
+ ${addSeparator(
+ fnsDeclarations.concat(generateConstantsDeclarations(constants)),
+ ',\n'
+ )}
+ }
+ `
+
+ writeFile(`src/index.js.flow`, typingFile)
+}
+
+function generateFlowFPFnTyping(fn, aliasDeclarations) {
+ const { title, args, content } = fn
+
+ const type = getFPFnType(args, content.returns[0].type.names)
+
+ const typingFile = formatFlowFile`
+ ${addSeparator(aliasDeclarations, '\n')}
+
+ ${addSeparator(getFlowFPTypeAliases(args.length), '\n')}
+
+ declare module.exports: ${type}
+ `
+
+ writeFile(`src/fp/${title}/index.js.flow`, typingFile)
+}
+
+function generateFlowFPFnIndexTyping(fns, aliasDeclarations, constants) {
+ const fnsDeclarations = fns.map(
+ ({ title, args, content }) =>
+ `${title}: ${getFPFnType(args, content.returns[0].type.names)}`
+ )
+
+ const typingFile = formatFlowFile`
+ ${addSeparator(aliasDeclarations, '\n')}
+
+ ${addSeparator(getFlowFPTypeAliases(), '\n')}
+
+ declare module.exports: {
+ ${addSeparator(
+ fnsDeclarations.concat(generateConstantsDeclarations(constants)),
+ ','
+ )}
+ }
+ `
+
+ writeFile(`src/fp/index.js.flow`, typingFile)
+}
+
+function generateFlowLocaleTyping(locale, localeAliasDeclaration) {
+ const { fullPath } = locale
+
+ const typingFile = formatFlowFile`
+ ${localeAliasDeclaration}
+
+ declare module.exports: Locale
+ `
+
+ writeFile(`${fullPath}.flow`, typingFile)
+}
+
+function generateFlowLocaleIndexTyping(locales, localeAliasDeclaration) {
+ const typingFile = formatFlowFile`
+ ${localeAliasDeclaration}
+
+ declare module.exports: {
+ ${addSeparator(
+ locales.map(({ name }) => `${name}: Locale`),
+ ','
+ )}
+ }
+ `
+
+ writeFile('src/locale/index.js.flow', typingFile)
+}
+
+function generateFlowTypings(fns, aliases, locales, constants) {
+ const aliasDeclarations = aliases.map(getFlowTypeAlias)
+ const localeAliasDeclaration = getFlowTypeAlias(
+ aliases.find((alias) => alias.title === 'Locale')
+ )
+
+ fns.forEach((fn) => {
+ if (fn.isFPFn) {
+ generateFlowFPFnTyping(fn, aliasDeclarations)
+ } else {
+ generateFlowFnTyping(fn, aliasDeclarations)
+ }
+ })
+
+ locales.forEach((locale) => {
+ generateFlowLocaleTyping(locale, localeAliasDeclaration)
+ })
+
+ generateFlowFnIndexTyping(
+ fns.filter(({ isFPFn }) => !isFPFn),
+ aliasDeclarations,
+ constants
+ )
+ generateFlowFPFnIndexTyping(
+ fns.filter(({ isFPFn }) => isFPFn),
+ aliasDeclarations,
+ constants
+ )
+ generateFlowLocaleIndexTyping(locales, localeAliasDeclaration)
+}
+
+function generateConstantsDeclarations(constants) {
+ return constants.map((c) => `${c.name}: ${c.type.names.join(' | ')}`)
+}
+
+function writeFile(relativePath, content) {
+ return fs.writeFileSync(
+ path.resolve(process.cwd(), relativePath),
+ prettier(content, 'flow')
+ )
+}
+
+module.exports = {
+ generateFlowTypings,
+}
diff --git a/date-fns/scripts/build/_lib/typings/formatBlock.js b/date-fns/scripts/build/_lib/typings/formatBlock.js
new file mode 100644
index 0000000..4e1aa32
--- /dev/null
+++ b/date-fns/scripts/build/_lib/typings/formatBlock.js
@@ -0,0 +1,149 @@
+const flowHeader = '// @flow'
+const generatedAutomaticallyMessage = "// This file is generated automatically by `scripts/build/typings.js`. Please, don't change it."
+
+const id = x => x
+
+const trimLeft = string =>
+ string.replace(/^\s*/, '')
+
+const trimRight = string =>
+ string.replace(/\s*$/, '')
+
+const removeIndent = (string, indent) => {
+ return trimLeft(string.slice(0, indent)) + string.slice(indent)
+}
+
+const addIndent = (string, indent) =>
+ string.length > 0
+ ? ' '.repeat(indent) + string
+ : string
+
+const detectIndent = (string) => {
+ const matchResult = string.match(/^\n*(\s+)/)
+ const indent = matchResult
+ ? matchResult[1].length
+ : 0
+ return indent
+}
+
+const addIndentToMultilineString = (string, indent, ignoreFirstLine) =>
+ string
+ .split('\n')
+ .map((line, index) =>
+ (ignoreFirstLine && index === 0)
+ ? line
+ : addIndent(line, indent)
+ )
+ .join('\n')
+
+const addIndentToArray = (array, indent, ignoreFirstElement) =>
+ array
+ .map((element, index) =>
+ addIndentToMultilineString(element, indent, ignoreFirstElement && index === 0)
+ )
+
+const removeIndentFromArray = (array, indent, ignoreFirstElement) =>
+ array
+ .map((element, index) =>
+ (ignoreFirstElement && index === 0)
+ ? element
+ : removeIndent(element, indent)
+ )
+
+/**
+ * Add a specified separator to the end of every string in the array, except the last one
+ * @param {String[]} stringsArray
+ * @returns {String[]} stringsArray with added separators
+ */
+const addSeparator = (stringsArray, separator) =>
+ stringsArray.map((string, index) =>
+ index === stringsArray.length - 1
+ ? string
+ : string + separator
+ )
+
+/**
+ * Tag function that formats a code block by putting correct indentation to it
+ * @param {String[]} rawStrings
+ * @param {...String} substitutions
+ * @returns {String} formatted code block
+ *
+ * @example
+ * const result = formatBlock`
+ * while (true) {
+ * ${addSeparator(
+ * ['Hello', 'world', '!'].map(s => `console.log('${s}')`),
+ * ';'
+ * )}
+ * }
+ * `
+ * console.log(result)
+ * //=>
+ * while (true) {
+ * console.log('Hello');
+ * console.log('world');
+ * console.log('!')
+ * }
+ */
+const formatBlock = (rawStrings, ...substitutions) => {
+ const firstLineIndent = detectIndent(rawStrings[0])
+ let lastLineIndent = 0
+
+ const result = [...substitutions, ''].map((substitution, index) => {
+ const rawString = rawStrings[index]
+
+ // Trim left if it is the first string, and right if it is the last string
+ const maybeTrimLeft = index === 0 ? trimLeft : id
+ const maybeTrimRight = index === substitutions.length ? trimRight : id
+ const string = maybeTrimLeft(maybeTrimRight(rawString))
+
+ const lines = removeIndentFromArray(string.split('\n'), firstLineIndent, true)
+
+ if (lines.length > 1) {
+ const lastLine = lines[lines.length - 1]
+ lastLineIndent = detectIndent(lastLine)
+ }
+
+ const indentedSubstitution =
+ Array.isArray(substitution)
+ ? addIndentToArray(substitution, lastLineIndent, true).join('\n')
+ : addIndentToMultilineString(substitution, lastLineIndent, true)
+
+ return lines.join('\n') + indentedSubstitution
+ }).join('')
+
+ return result
+}
+
+/**
+ * Tag function that formats a Flow file by putting the correct indentation, header and footer to it
+ * @param {String[]} rawStrings
+ * @param {...String} substitutions
+ * @returns {String} formatted file content
+ */
+const formatFlowFile = (...args) =>
+ flowHeader +
+ '\n' +
+ generatedAutomaticallyMessage +
+ '\n\n' +
+ formatBlock(...args) +
+ '\n'
+
+/**
+ * Tag function that formats a TypeScript file by putting the correct indentation, header and footer to it
+ * @param {String[]} rawStrings
+ * @param {...String} substitutions
+ * @returns {String} formatted file content
+ */
+const formatTypeScriptFile = (...args) =>
+ generatedAutomaticallyMessage +
+ '\n\n' +
+ formatBlock(...args) +
+ '\n'
+
+module.exports = {
+ addSeparator,
+ formatBlock,
+ formatFlowFile,
+ formatTypeScriptFile
+}
diff --git a/date-fns/scripts/build/_lib/typings/typeScript.js b/date-fns/scripts/build/_lib/typings/typeScript.js
new file mode 100644
index 0000000..4e93155
--- /dev/null
+++ b/date-fns/scripts/build/_lib/typings/typeScript.js
@@ -0,0 +1,460 @@
+const fs = require('fs')
+const path = require('path')
+const prettier = require('../prettier')
+
+const { getParams, getType, getFPFnType } = require('./common')
+
+const {
+ addSeparator,
+ formatBlock,
+ formatTypeScriptFile,
+} = require('./formatBlock')
+
+/**
+ * Return curried function interfaces for a specific FP function arity.
+ * @param {Number} [arity=4]
+ * @returns {String[arity]} an array of code blocks
+ */
+const getTypeScriptFPInterfaces = (arity = 4) =>
+ [
+ formatBlock`
+ interface CurriedFn1<A, R> {
+ (a: A): R
+ }
+ `,
+
+ formatBlock`
+ interface CurriedFn2<A, B, R> {
+ (a: A): CurriedFn1<B, R>
+ (a: A, b: B): R
+ }
+ `,
+
+ formatBlock`
+ interface CurriedFn3<A, B, C, R> {
+ (a: A): CurriedFn2<B, C, R>
+ (a: A, b: B): CurriedFn1<C, R>
+ (a: A, b: B, c: C): R
+ }
+ `,
+
+ formatBlock`
+ interface CurriedFn4<A, B, C, D, R> {
+ (a: A): CurriedFn3<B, C, D, R>
+ (a: A, b: B): CurriedFn2<C, D, R>
+ (a: A, b: B, c: C): CurriedFn1<D, R>
+ (a: A, b: B, c: C, d: D): R
+ }
+ `,
+ ].slice(0, arity)
+
+function getTypeScriptTypeAlias(type) {
+ const { title, properties, content } = type
+
+ return formatBlock`
+ type ${title} = ${
+ properties ? getParams(properties) : content.type.names.join(' | ')
+ }
+ type ${title}Aliased = ${title}
+ `
+}
+
+function getExportedTypeScriptTypeAlias(type) {
+ const { title } = type
+
+ return formatBlock`
+ export type ${title} = ${title}Aliased
+ `
+}
+
+function getExportedTypeScriptTypeAliases(aliases) {
+ return formatBlock`
+ declare module 'date-fns' {
+ ${addSeparator(aliases.map(getExportedTypeScriptTypeAlias), '\n')}
+ }
+ `
+}
+
+function getTypeScriptDateFnsModuleDefinition(
+ submodule,
+ fns,
+ constantsDefinitions
+) {
+ const moduleName = `date-fns${submodule}`
+
+ const definition = formatBlock`
+ declare module '${moduleName}' {
+ ${addSeparator(
+ fns.map(getTypeScriptFnDefinition).concat(constantsDefinitions),
+ '\n'
+ )}
+ }
+ `
+
+ return {
+ name: moduleName,
+ definition,
+ }
+}
+
+function getTypeScriptDateFnsFPModuleDefinition(
+ submodule,
+ fns,
+ constantsDefinitions
+) {
+ const moduleName = `date-fns${submodule}/fp`
+
+ const fnDefinitions = fns.map(getTypeScriptFPFnDefinition)
+
+ const definition = formatBlock`
+ declare module '${moduleName}' {
+ ${addSeparator(fnDefinitions.concat(constantsDefinitions), '\n')}
+ }
+ `
+
+ return {
+ name: moduleName,
+ definition,
+ }
+}
+
+function getTypeScriptFnModuleDefinition(submodule, fnSuffix, fn) {
+ const name = fn.content.name
+ const moduleName = `date-fns${submodule}/${name}${fnSuffix}`
+
+ const definition = formatBlock`
+ declare module '${moduleName}' {
+ import {${name}} from 'date-fns${submodule}'
+ export default ${name}
+ }
+ `
+
+ return {
+ name: moduleName,
+ definition,
+ }
+}
+
+function getTypeScriptFnDefinition(fn) {
+ const { title, args, content } = fn
+
+ const params = getParams(args, { leftBorder: '(', rightBorder: ')' })
+ const returns = getType(content.returns[0].type.names)
+
+ return formatBlock`
+ function ${title} ${params}: ${returns}
+ namespace ${title} {}
+ `
+}
+
+function getTypeScriptFPFnDefinition(fn) {
+ const { title, args, content } = fn
+
+ const type = getFPFnType(args, content.returns[0].type.names)
+
+ return formatBlock`
+ const ${title}: ${type}
+ namespace ${title} {}
+ `
+}
+
+function getTypeScriptFPFnModuleDefinition(submodule, fnSuffix, isDefault, fn) {
+ const { title } = fn
+ const moduleName = `date-fns${submodule}/fp/${title}${fnSuffix}`
+
+ const definition = formatBlock`
+ declare module '${moduleName}' {
+ import {${title}} from 'date-fns${submodule}/fp'
+ export default ${title}
+ }
+ `
+
+ return {
+ name: moduleName,
+ definition,
+ }
+}
+
+function getTypeScriptLocaleIndexModuleDefinition(submodule, locales) {
+ const moduleName = `date-fns${submodule}/locale`
+
+ const localesDefinitions = locales.map(getTypeScriptLocaleDefinition)
+
+ const definition = formatBlock`
+ declare module '${moduleName}' {
+ ${addSeparator(localesDefinitions, '\n')}
+ }
+ `
+
+ return {
+ name: moduleName,
+ definition,
+ }
+}
+
+function getTypeScriptLocaleDefinition(locale) {
+ const { name } = locale
+
+ return formatBlock`
+ const ${name}: Locale
+ namespace ${name} {}
+ `
+}
+
+function getTypeScriptLocaleModuleDefinition(
+ submodule,
+ localeSuffix,
+ isDefault,
+ locale
+) {
+ const code = locale.code
+ const moduleName = `date-fns${submodule}/locale/${code}${localeSuffix}`
+ const { name } = locale
+
+ const definition = formatBlock`
+ declare module '${moduleName}' {
+ import {${name}} from 'date-fns${submodule}/locale'
+ export default ${name}
+ }
+ `
+
+ return {
+ name: moduleName,
+ definition,
+ }
+}
+
+function getTypeScriptInterfaceDefinition(fn) {
+ const { title, args, content } = fn
+ const params = getParams(args, { leftBorder: '(', rightBorder: ')' })
+ const returns = getType(content.returns[0].type.names)
+
+ return `${title}${params}: ${returns}`
+}
+
+function generateTypescriptFnTyping(fn) {
+ const typingFile = formatTypeScriptFile`
+ import {${fn.title}} from 'date-fns'
+ export default ${fn.title}
+ `
+ writeFile(`./src/${fn.title}/index.d.ts`, typingFile)
+}
+
+function generateTypescriptFPFnTyping(fn) {
+ const typingFile = formatTypeScriptFile`
+ import {${fn.title}} from 'date-fns/fp'
+ export default ${fn.title}
+ `
+ writeFile(`./src/fp/${fn.title}/index.d.ts`, typingFile)
+}
+
+function generateTypescriptLocaleTyping(locale) {
+ const typingFile = formatTypeScriptFile`
+ import {${locale.name}} from 'date-fns/locale'
+ export default ${locale.name}
+ `
+ writeFile(`src/locale/${locale.code}/index.d.ts`, typingFile)
+}
+
+function generateTypeScriptTypings(fns, aliases, locales, constants) {
+ const nonFPFns = fns.filter((fn) => !fn.isFPFn)
+ const fpFns = fns.filter((fn) => fn.isFPFn)
+ const constantsDefinitions = constants.map(
+ (c) => `const ${c.name}: ${c.type.names.join(' | ')}`
+ )
+
+ const moduleDefinitions = [
+ getTypeScriptDateFnsModuleDefinition('', nonFPFns, constantsDefinitions),
+ ]
+ .concat(nonFPFns.map(getTypeScriptFnModuleDefinition.bind(null, '', '')))
+ .concat(
+ nonFPFns.map(getTypeScriptFnModuleDefinition.bind(null, '', '/index'))
+ )
+ .concat(
+ nonFPFns.map(getTypeScriptFnModuleDefinition.bind(null, '', '/index.js'))
+ )
+ .map((module) => module.definition)
+
+ const fpModuleDefinitions = [
+ getTypeScriptDateFnsFPModuleDefinition('', fpFns, constantsDefinitions),
+ ]
+ .concat(
+ fpFns.map(getTypeScriptFPFnModuleDefinition.bind(null, '', '', false))
+ )
+ .concat(
+ fpFns.map(
+ getTypeScriptFPFnModuleDefinition.bind(null, '', '/index', false)
+ )
+ )
+ .concat(
+ fpFns.map(
+ getTypeScriptFPFnModuleDefinition.bind(null, '', '/index.js', false)
+ )
+ )
+ .map((module) => module.definition)
+
+ const esmModuleDefinitions = [
+ getTypeScriptDateFnsModuleDefinition(
+ '/esm',
+ nonFPFns,
+ constantsDefinitions
+ ),
+ ]
+ .concat(
+ nonFPFns.map(getTypeScriptFnModuleDefinition.bind(null, '/esm', ''))
+ )
+ .concat(
+ nonFPFns.map(getTypeScriptFnModuleDefinition.bind(null, '/esm', '/index'))
+ )
+ .concat(
+ nonFPFns.map(
+ getTypeScriptFnModuleDefinition.bind(null, '/esm', '/index.js')
+ )
+ )
+ .map((module) => module.definition)
+
+ const esmFPModuleDefinitions = [
+ getTypeScriptDateFnsFPModuleDefinition('/esm', fpFns, constantsDefinitions),
+ ]
+ .concat(
+ fpFns.map(getTypeScriptFPFnModuleDefinition.bind(null, '/esm', '', true))
+ )
+ .concat(
+ fpFns.map(
+ getTypeScriptFPFnModuleDefinition.bind(null, '/esm', '/index', true)
+ )
+ )
+ .concat(
+ fpFns.map(
+ getTypeScriptFPFnModuleDefinition.bind(null, '/esm', '/index.js', true)
+ )
+ )
+ .map((module) => module.definition)
+
+ const aliasDefinitions = aliases.map(getTypeScriptTypeAlias)
+
+ const exportedAliasDefinitions = [getExportedTypeScriptTypeAliases(aliases)]
+
+ const localeModuleDefinitions = [
+ getTypeScriptLocaleIndexModuleDefinition('', locales),
+ ]
+ .concat(
+ locales.map(getTypeScriptLocaleModuleDefinition.bind(null, '', '', false))
+ )
+ .concat(
+ locales.map(
+ getTypeScriptLocaleModuleDefinition.bind(null, '', '/index', false)
+ )
+ )
+ .concat(
+ locales.map(
+ getTypeScriptLocaleModuleDefinition.bind(null, '', '/index.js', false)
+ )
+ )
+ .map((module) => module.definition)
+
+ const esmLocaleModuleDefinitions = [
+ getTypeScriptLocaleIndexModuleDefinition('/esm', locales),
+ ]
+ .concat(
+ locales.map(
+ getTypeScriptLocaleModuleDefinition.bind(null, '/esm', '', true)
+ )
+ )
+ .concat(
+ locales.map(
+ getTypeScriptLocaleModuleDefinition.bind(null, '/esm', '/index', true)
+ )
+ )
+ .concat(
+ locales.map(
+ getTypeScriptLocaleModuleDefinition.bind(
+ null,
+ '/esm',
+ '/index.js',
+ true
+ )
+ )
+ )
+ .map((module) => module.definition)
+
+ const globalInterfaceDefinition = formatBlock`
+ interface dateFns {
+ ${addSeparator(
+ nonFPFns
+ .map(getTypeScriptInterfaceDefinition)
+ .concat(
+ constants.map((c) => `${c.name}: ${c.type.names.join(' | ')}`)
+ ),
+ '\n'
+ )}
+ }
+ `
+
+ const typingFile = formatTypeScriptFile`
+ // FP Interfaces
+
+ ${addSeparator(getTypeScriptFPInterfaces(), '\n')}
+
+ // Type Aliases
+
+ ${addSeparator(aliasDefinitions, '\n')}
+
+ // Exported Type Aliases
+
+ ${addSeparator(exportedAliasDefinitions, '\n')}
+
+ // Regular Functions
+
+ ${addSeparator(moduleDefinitions, '\n')}
+
+ // FP Functions
+
+ ${addSeparator(fpModuleDefinitions, '\n')}
+
+ // ECMAScript Module Functions
+
+ ${addSeparator(esmModuleDefinitions, '\n')}
+
+ // ECMAScript Module FP Functions
+
+ ${addSeparator(esmFPModuleDefinitions, '\n')}
+
+ // Regular Locales
+
+ ${addSeparator(localeModuleDefinitions, '\n')}
+
+ // ECMAScript Module Locales
+
+ ${addSeparator(esmLocaleModuleDefinitions, '\n')}
+
+ // dateFns Global Interface
+
+ ${globalInterfaceDefinition}
+ `
+
+ writeFile('typings.d.ts', typingFile)
+
+ fns.forEach((fn) => {
+ if (fn.isFPFn) {
+ generateTypescriptFPFnTyping(fn)
+ } else {
+ generateTypescriptFnTyping(fn)
+ }
+ })
+
+ locales.forEach((locale) => {
+ generateTypescriptLocaleTyping(locale)
+ })
+}
+
+function writeFile(relativePath, content) {
+ return fs.writeFileSync(
+ path.resolve(process.cwd(), relativePath),
+ prettier(content, 'typescript')
+ )
+}
+
+module.exports = {
+ generateTypeScriptTypings,
+}
diff --git a/date-fns/scripts/build/build.sh b/date-fns/scripts/build/build.sh
new file mode 100755
index 0000000..d4b3726
--- /dev/null
+++ b/date-fns/scripts/build/build.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# The script unifies the build scripts.
+#
+# It's the entry point for the build process.
+
+set -ex
+
+./scripts/build/docs.js
+./scripts/build/fp.js
+./scripts/build/typings.js
+./scripts/build/indices.js
diff --git a/date-fns/scripts/build/deno.sh b/date-fns/scripts/build/deno.sh
new file mode 100755
index 0000000..f76b52d
--- /dev/null
+++ b/date-fns/scripts/build/deno.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+# The script builds the Deno package.
+
+rsync --archive --prune-empty-dirs --relative --exclude={'*.flow','benchmark.*','test.*','snapshot.md'} src/./ deno
+cp {CHANGELOG.md,LICENSE.md,typings.d.ts} deno
+yarn ts-node scripts/build/_lib/addDenoExtensions.ts \ No newline at end of file
diff --git a/date-fns/scripts/build/docs.js b/date-fns/scripts/build/docs.js
new file mode 100755
index 0000000..85c99eb
--- /dev/null
+++ b/date-fns/scripts/build/docs.js
@@ -0,0 +1,380 @@
+#!/usr/bin/env node
+
+/**
+ * @file
+ * The script generates docs.json used as the source of truth
+ * for the source code generators (FP, typings, etc.).
+ *
+ * It's a part of the build process.
+ */
+
+const os = require('os')
+const pLimit = require('p-limit')
+const fs = require('fs/promises')
+const path = require('path')
+const cloneDeep = require('lodash.clonedeep')
+const jsDocParser = require('jsdoc-to-markdown')
+const listFns = require('../_lib/listFns')
+const docsConfig = require('../../docs/index.js')
+
+const docsPath = path.resolve(process.cwd(), 'tmp/docs.json')
+
+generateDocsFromSource()
+ .then(generatedDocsObj)
+ .then(injectStaticDocsToDocsObj)
+ .then(injectSharedDocsToDocsObj)
+ .then(writeDocsFile)
+ .catch(reportErrors)
+
+/**
+ * Generates docs object from a list of functions using extended JSDoc format.
+ */
+async function generateDocsFromSource() {
+ const fns = await listFns()
+
+ const limit = pLimit(os.cpus().length)
+
+ const configFile = path.resolve(process.cwd(), 'jsdoc2md.json')
+
+ const jobs = fns.map((fn) => {
+ return limit(() =>
+ jsDocParser
+ .getTemplateData({
+ files: fn.fullPath,
+ 'no-cache': true,
+ configure: configFile,
+ })
+ .then((result) => result[0])
+ )
+ })
+
+ const docsResult = await Promise.all(jobs)
+
+ return docsResult
+ .map((doc) => {
+ const pureTag =
+ doc.customTags && doc.customTags.find((t) => t.tag === 'pure')
+ const pure = (pureTag && pureTag.value) !== 'false'
+ return {
+ type: 'jsdoc',
+ kind: 'function',
+ urlId: doc.name,
+ category: doc.category,
+ title: doc.name,
+ description: doc.summary,
+ content: doc,
+ pure,
+ }
+ })
+ .reduce(
+ (array, doc) =>
+ array
+ .concat(generateFnDoc(doc))
+ .concat(
+ doc.pure
+ ? [generateFPFnDoc(doc)].concat(
+ generateFPFnWithOptionsDoc(doc) || []
+ )
+ : []
+ ),
+ []
+ )
+}
+
+/**
+ * Generates docs object.
+ */
+function generatedDocsObj(docs) {
+ return groupDocs(docs, docsConfig.groups)
+}
+
+/**
+ * Injects static docs (markdown documents specified in the config file)
+ * to docs object.
+ */
+function injectStaticDocsToDocsObj(docsFileObj) {
+ return getListOfStaticDocs()
+ .then((staticDocs) => {
+ staticDocs.forEach((staticDoc) => {
+ docsFileObj[staticDoc.category].push(staticDoc)
+ })
+ return docsFileObj
+ })
+ .catch(reportErrors)
+}
+
+/**
+ * Injects shared docs to docs object.
+ */
+function injectSharedDocsToDocsObj(docsFileObj) {
+ return generateSharedDocs()
+ .then((sharedDocs) => {
+ sharedDocs.forEach((sharedDoc) => {
+ docsFileObj[sharedDoc.category].push(sharedDoc)
+ })
+ return docsFileObj
+ })
+ .catch(reportErrors)
+}
+
+/**
+ * Prints an error and exits the process with 1 status code.
+ */
+function reportErrors(err) {
+ console.error(err.stack)
+ process.exit(1)
+}
+
+/**
+ * Writes docs file.
+ */
+function writeDocsFile(docsFileObj) {
+ return fs.writeFile(docsPath, JSON.stringify(docsFileObj))
+}
+
+/**
+ * Groups passed docs list.
+ */
+function groupDocs(docs, groups) {
+ return docs.reduce((acc, doc) => {
+ ;(acc[doc.category] = acc[doc.category] || []).push(doc)
+ return acc
+ }, buildGroupsTemplate(groups))
+}
+
+/**
+ * Builds an object where the key is a group name and the value is
+ * an empty array. Pre-generated docs object allows to preserve the desired
+ * groups order.
+ */
+function buildGroupsTemplate(groups) {
+ return groups.reduce((acc, group) => {
+ acc[group] = []
+ return acc
+ }, {})
+}
+
+/**
+ * Returns promise to list of static docs with its contents.
+ */
+function getListOfStaticDocs() {
+ return Promise.all(
+ docsConfig.staticDocs.map((staticDoc) => {
+ return fs
+ .readFile(staticDoc.path)
+ .then((docContent) => docContent.toString())
+ .then((content) => Object.assign({ content }, staticDoc))
+ .catch(reportErrors)
+ })
+ )
+}
+
+/**
+ * Returns promise to list of shared docs with its contents.
+ */
+function generateSharedDocs() {
+ const docs = docsConfig.sharedDocs
+ .map(
+ (fn) =>
+ jsDocParser.getTemplateDataSync({
+ files: fn.fullPath,
+ 'no-cache': true,
+ })[0]
+ )
+ .map((doc) => ({
+ type: 'jsdoc',
+ kind: 'typedef',
+ urlId: doc.name,
+ category: doc.category,
+ title: doc.name,
+ description: doc.summary,
+ content: doc,
+ properties: paramsToTree(doc.properties),
+ }))
+
+ return Promise.resolve(docs)
+}
+
+function generateFnDoc(dirtyDoc) {
+ const doc = cloneDeep(dirtyDoc)
+
+ const isFPFn = false
+ const { urlId, title } = doc
+ const args = paramsToTree(doc.content.params)
+
+ return Object.assign(doc, {
+ isFPFn,
+ args,
+ relatedDocs: Object.assign(
+ { default: urlId, fp: `fp/${urlId}` },
+ withOptions(args) ? { fpWithOptions: `fp/${urlId}WithOptions` } : {}
+ ),
+ usage: generateUsage(title, isFPFn),
+ usageTabs: generateUsageTabs(isFPFn),
+ syntax: generateSyntaxString(title, args, isFPFn),
+ })
+}
+
+function generateFPFnDoc(dirtyDoc) {
+ const doc = cloneDeep(dirtyDoc)
+
+ const isFPFn = true
+ const { urlId, title } = doc
+ const exceptions = doc.content.exceptions.filter(
+ (exception) => !exception.description.includes('options.')
+ )
+ const params = doc.content.params
+ .filter((param) => !param.name.startsWith('options'))
+ .reverse()
+ const args = paramsToTree(params)
+
+ return Object.assign(doc, {
+ isFPFn,
+ args,
+ generatedFrom: title,
+ urlId: `fp/${urlId}`,
+ relatedDocs: Object.assign(
+ { default: urlId, fp: `fp/${urlId}` },
+ withOptions(args) ? { fpWithOptions: `fp/${urlId}WithOptions` } : {}
+ ),
+ usage: generateUsage(title, isFPFn),
+ usageTabs: generateUsageTabs(isFPFn),
+ syntax: generateSyntaxString(title, args, isFPFn),
+
+ content: Object.assign(doc.content, {
+ exceptions,
+ params,
+ examples:
+ 'See [FP Guide](https://date-fns.org/docs/FP-Guide) for more information',
+ }),
+ })
+}
+
+function generateFPFnWithOptionsDoc(dirtyDoc) {
+ const doc = cloneDeep(dirtyDoc)
+
+ const isFPFn = true
+ const { urlId, title } = doc
+ const params = doc.content.params
+ .map((param) => {
+ if (!param.name.includes('.')) {
+ param.optional = false
+ }
+ return param
+ })
+ .reverse()
+ const args = paramsToTree(params)
+
+ if (!withOptions(args)) return
+
+ return Object.assign(doc, {
+ isFPFn,
+ args,
+ generatedFrom: title,
+ title: `${title}WithOptions`,
+ urlId: `fp/${urlId}WithOptions`,
+ relatedDocs: {
+ default: urlId,
+ fp: `fp/${urlId}`,
+ fpWithOptions: `fp/${urlId}WithOptions`,
+ },
+ usage: generateUsage(title, isFPFn),
+ usageTabs: generateUsageTabs(isFPFn),
+ syntax: generateSyntaxString(title, args, isFPFn),
+
+ content: Object.assign(doc.content, {
+ params,
+ id: `${doc.content.id}WithOptions`,
+ longname: `${doc.content.longname}WithOptions`,
+ name: `${doc.content.name}WithOptions`,
+ examples:
+ 'See [FP Guide](https://date-fns.org/docs/FP-Guide) for more information',
+ }),
+ })
+}
+
+function withOptions(args) {
+ return args && args[0].name === 'options'
+}
+
+function generateUsageTabs(isFPFn) {
+ return isFPFn
+ ? ['commonjs', 'es2015', 'esm']
+ : ['commonjs', 'umd', 'es2015', 'esm']
+}
+
+function generateUsage(name, isFPFn) {
+ const submodule = isFPFn ? '/fp' : ''
+
+ let usage = {
+ commonjs: {
+ title: 'CommonJS',
+ code: `var ${name} = require('date-fns${submodule}/${name}')`,
+ },
+
+ es2015: {
+ title: 'ES 2015',
+ code: `import ${name} from 'date-fns${submodule}/${name}'`,
+ },
+
+ esm: {
+ title: 'ESM',
+ code: `import { ${name} } from 'date-fns${
+ submodule && `/esm/${submodule}`
+ }'`,
+ text:
+ 'See [ECMAScript Modules guide](https://date-fns.org/docs/ECMAScript-Modules) for more information',
+ },
+ }
+
+ return usage
+}
+
+function paramsToTree(dirtyParams) {
+ if (!dirtyParams) {
+ return null
+ }
+
+ const params = cloneDeep(dirtyParams)
+
+ const paramIndices = params.reduce((result, { name }, index) => {
+ result[name] = index
+ return result
+ }, {})
+
+ return params
+ .map((param) => {
+ const { name, isProperty } = param
+
+ const indexOfDot = name.indexOf('.')
+
+ if (indexOfDot >= 0 && !isProperty) {
+ const parentIndex = paramIndices[name.substring(0, indexOfDot)]
+ const parent = params[parentIndex]
+
+ param.name = name.substring(indexOfDot + 1)
+ param.isProperty = true
+ if (!parent.props) {
+ parent.props = [param]
+ } else {
+ parent.props.push(param)
+ }
+ }
+
+ return param
+ })
+ .filter((param) => !param.isProperty)
+}
+
+function generateSyntaxString(name, args, isFPFn) {
+ if (!args) {
+ return undefined
+ } else if (isFPFn) {
+ return args.reduce((acc, arg) => acc.concat(`(${arg.name})`), name)
+ } else {
+ const argsString = args
+ .map((arg) => (arg.optional ? `[${arg.name}]` : arg.name))
+ .join(', ')
+ return `${name}(${argsString})`
+ }
+}
diff --git a/date-fns/scripts/build/fp.js b/date-fns/scripts/build/fp.js
new file mode 100755
index 0000000..f3e5a5a
--- /dev/null
+++ b/date-fns/scripts/build/fp.js
@@ -0,0 +1,51 @@
+#!/usr/bin/env node
+
+/**
+ * @file
+ * The script generates the FP functions using the docs JSON file.
+ *
+ * It's a part of the build process.
+ */
+
+const fs = require('fs')
+const path = require('path')
+const prettier = require('./_lib/prettier')
+const jsDocs = require(path.resolve(process.cwd(), 'tmp/docs.json'))
+
+const generatedAutomaticallyMessage =
+ "// This file is generated automatically by `scripts/build/fp.js`. Please, don't change it."
+const FP_DIR = './src/fp'
+
+const fpFns = Object.keys(jsDocs)
+ .map((category) => jsDocs[category])
+ .reduce((previousValue, newValue) => [...previousValue, ...newValue], [])
+ .filter((doc) => doc.kind === 'function' && doc.isFPFn)
+
+buildFP(fpFns)
+
+function getFPFn(resultFnName, initialFnName, arity) {
+ return [generatedAutomaticallyMessage]
+ .concat('')
+ .concat(`import fn from '../../${initialFnName}/index'`)
+ .concat(`import convertToFP from '../_lib/convertToFP/index'`)
+ .concat('')
+ .concat(`var ${resultFnName} = convertToFP(fn, ${arity})`)
+ .concat('')
+ .concat(`export default ${resultFnName}`)
+ .concat('')
+ .join('\n')
+}
+
+function buildFPFn({ title, generatedFrom, args: { length } }) {
+ const fpFnLines = getFPFn(title, generatedFrom, length)
+ const fpFnDir = `${FP_DIR}/${title}`
+
+ if (!fs.existsSync(fpFnDir)) {
+ fs.mkdirSync(fpFnDir)
+ }
+ fs.writeFileSync(`${fpFnDir}/index.js`, prettier(fpFnLines))
+}
+
+function buildFP(fns) {
+ fns.forEach(buildFPFn)
+}
diff --git a/date-fns/scripts/build/indices.js b/date-fns/scripts/build/indices.js
new file mode 100755
index 0000000..45767fb
--- /dev/null
+++ b/date-fns/scripts/build/indices.js
@@ -0,0 +1,61 @@
+#!/usr/bin/env node
+
+/**
+ * @file
+ * The script generates index files for submodules.
+ *
+ * It's a part of the build process.
+ */
+
+const fs = require('fs')
+const path = require('path')
+const prettier = require('./_lib/prettier')
+const listFns = require('../_lib/listFns')
+const listFPFns = require('../_lib/listFPFns')
+const listLocales = require('../_lib/listLocales')
+
+const outdatedLocales = require('../../outdatedLocales.json')
+
+const generatedAutomaticallyMessage =
+ "// This file is generated automatically by `scripts/build/indices.js`. Please, don't change it."
+
+listFns().then((fns) => {
+ const fpFns = listFPFns()
+ const locales = listLocales().filter(
+ ({ code }) => !outdatedLocales.includes(code)
+ )
+
+ writeFile('src/index.js', generateIndex(fns, false, true))
+ writeFile('src/fp/index.js', generateIndex(fpFns, true, true))
+ writeFile('src/locale/index.js', generateIndex(locales, false, false))
+})
+
+function writeFile(relativePath, content) {
+ return fs.writeFileSync(
+ path.resolve(process.cwd(), relativePath),
+ prettier(content)
+ )
+}
+
+function generateIndex(files, isFP, includeConstants) {
+ const fileLines = files
+ .map(
+ (fn) =>
+ `export { default as ${fn.name} } from '${fn.path.replace(
+ /\.js$/,
+ ''
+ )}/index'`
+ )
+ .concat(
+ includeConstants
+ ? `export * from '${isFP ? '..' : '.'}/constants/index'`
+ : []
+ )
+
+ const indexLines = [generatedAutomaticallyMessage]
+ .concat('')
+ .concat(fileLines)
+ .join('\n')
+
+ return `${indexLines}\n`
+}
diff --git a/date-fns/scripts/build/localeSnapshots/_lib/distanceDates.js b/date-fns/scripts/build/localeSnapshots/_lib/distanceDates.js
new file mode 100644
index 0000000..4f104a0
--- /dev/null
+++ b/date-fns/scripts/build/localeSnapshots/_lib/distanceDates.js
@@ -0,0 +1,59 @@
+export const baseDate = new Date(2000, 0, 1)
+
+export const dates = [
+ new Date(2006, 0, 1),
+ new Date(2005, 0, 1),
+ new Date(2004, 0, 1),
+ new Date(2003, 0, 1),
+ new Date(2002, 0, 1),
+ new Date(2001, 5, 1),
+ new Date(2001, 1, 1),
+ new Date(2001, 0, 1),
+ new Date(2000, 5, 1),
+ new Date(2000, 2, 1),
+ new Date(2000, 1, 1),
+ new Date(2000, 0, 15),
+ new Date(2000, 0, 2),
+ new Date(2000, 0, 1, 6),
+ new Date(2000, 0, 1, 1),
+ new Date(2000, 0, 1, 0, 45),
+ new Date(2000, 0, 1, 0, 30),
+ new Date(2000, 0, 1, 0, 15),
+ new Date(2000, 0, 1, 0, 1),
+ new Date(2000, 0, 1, 0, 0, 25),
+ new Date(2000, 0, 1, 0, 0, 15),
+ new Date(2000, 0, 1, 0, 0, 5),
+ baseDate,
+ new Date(1999, 11, 31, 23, 59, 55),
+ new Date(1999, 11, 31, 23, 59, 45),
+ new Date(1999, 11, 31, 23, 59, 35),
+ new Date(1999, 11, 31, 23, 59),
+ new Date(1999, 11, 31, 23, 45),
+ new Date(1999, 11, 31, 23, 30),
+ new Date(1999, 11, 31, 23, 15),
+ new Date(1999, 11, 31, 23),
+ new Date(1999, 11, 31, 18),
+ new Date(1999, 11, 30),
+ new Date(1999, 11, 15),
+ new Date(1999, 11, 1),
+ new Date(1999, 10, 1),
+ new Date(1999, 5, 1),
+ new Date(1999, 0, 1),
+ new Date(1998, 11, 1),
+ new Date(1998, 5, 1),
+ new Date(1998, 0, 1),
+ new Date(1997, 0, 1),
+ new Date(1996, 0, 1),
+ new Date(1995, 0, 1),
+ new Date(1994, 0, 1)
+]
+
+export const relativeDates = [
+ new Date(2000, 0, 10),
+ new Date(2000, 0, 5),
+ new Date(2000, 0, 2),
+ baseDate,
+ new Date(1999, 11, 31),
+ new Date(1999, 11, 27),
+ new Date(1999, 11, 21)
+]
diff --git a/date-fns/scripts/build/localeSnapshots/index.js b/date-fns/scripts/build/localeSnapshots/index.js
new file mode 100755
index 0000000..7581d95
--- /dev/null
+++ b/date-fns/scripts/build/localeSnapshots/index.js
@@ -0,0 +1,69 @@
+#!/usr/bin/env babel-node
+
+/**
+ * @file
+ * The script generates the locale snapshots.
+ *
+ * It's a part of the build process.
+ */
+
+import { readFile, readFileSync, writeFile } from 'mz/fs'
+import path from 'path'
+import listLocales from '../../_lib/listLocales'
+import prettier from '../_lib/prettier'
+import renderFormatDistance from './renderFormatDistance'
+import renderFormatDistanceStrict from './renderFormatDistanceStrict'
+import renderFormatParse from './renderFormatParse'
+import renderFormatRelative from './renderFormatRelative'
+
+const mode = process.argv[2] || 'generate'
+
+if (process.env.TZ.toLowerCase() !== 'utc')
+ throw new Error('The locale snapshots generation must be run with TZ=utc')
+
+const outdatedLocales = JSON.parse(
+ readFileSync(path.join(process.cwd(), 'outdatedLocales.json'), 'utf8')
+)
+const locales = listLocales().filter(
+ ({ code }) => !outdatedLocales.includes(code)
+)
+
+Promise.all(
+ locales.map(localeObj => {
+ const { code, fullPath } = localeObj
+ const locale = require(`../../../src/locale/${code}`)
+ const source = readFileSync(path.join(process.cwd(), fullPath)).toString()
+ const languageName = source.match(/\* @language (.*)/)[1]
+
+ const snapshot = `# ${languageName} (${code}) locale
+
+${renderFormatParse(locale)}
+
+${renderFormatDistance(locale)}
+
+${renderFormatDistanceStrict(locale)}
+
+${renderFormatRelative(locale)}
+`
+
+ const snapshotPath = path.join(
+ path.resolve(process.cwd(), path.dirname(fullPath)),
+ 'snapshot.md'
+ )
+ const formattedSnapshot = prettier(snapshot, 'markdown')
+
+ if (mode === 'test') {
+ return readFile(snapshotPath, 'utf8').then(snapshotFileContent => {
+ if (snapshotFileContent !== formattedSnapshot)
+ throw new Error(
+ `The snapshot on the disk doesn't match the generated snapshot: ${snapshotPath}. Please run yarn locale-snapshots and commit the results.`
+ )
+ })
+ } else {
+ return writeFile(snapshotPath, formattedSnapshot)
+ }
+ })
+).catch(err => {
+ console.error(err.stack)
+ process.exit(1)
+})
diff --git a/date-fns/scripts/build/localeSnapshots/renderFormatDistance/index.js b/date-fns/scripts/build/localeSnapshots/renderFormatDistance/index.js
new file mode 100644
index 0000000..f59d312
--- /dev/null
+++ b/date-fns/scripts/build/localeSnapshots/renderFormatDistance/index.js
@@ -0,0 +1,26 @@
+import formatDistance from '../../../../src/formatDistance'
+import { baseDate, dates } from '../_lib/distanceDates'
+
+export default function renderFormatDistance(locale) {
+ return `## \`formatDistance\`
+
+If now is January 1st, 2000, 00:00.
+
+| Date | Result | \`includeSeconds: true\` | \`addSuffix: true\` |
+|-|-|-|-|
+${dates
+ .map(date => {
+ const dateString = date.toISOString()
+ const result = formatDistance(date, baseDate, { locale })
+ const resultIncludeSeconds = formatDistance(date, baseDate, {
+ locale,
+ includeSeconds: true
+ })
+ const resultAddSuffix = formatDistance(date, baseDate, {
+ locale,
+ addSuffix: true
+ })
+ return `| ${dateString} | ${result} | ${resultIncludeSeconds} | ${resultAddSuffix} |`
+ })
+ .join('\n')}`
+}
diff --git a/date-fns/scripts/build/localeSnapshots/renderFormatDistanceStrict/index.js b/date-fns/scripts/build/localeSnapshots/renderFormatDistanceStrict/index.js
new file mode 100644
index 0000000..3dc03ab
--- /dev/null
+++ b/date-fns/scripts/build/localeSnapshots/renderFormatDistanceStrict/index.js
@@ -0,0 +1,26 @@
+import formatDistanceStrict from '../../../../src/formatDistanceStrict'
+import { baseDate, dates } from '../_lib/distanceDates'
+
+export default function renderFormatDistanceStrict(locale) {
+ return `## \`formatDistanceStrict\`
+
+If now is January 1st, 2000, 00:00.
+
+| Date | Result | \`addSuffix: true\` | With forced unit (i.e. \`hour\`)
+|-|-|-|-|
+${dates
+ .map(date => {
+ const dateString = date.toISOString()
+ const result = formatDistanceStrict(date, baseDate, { locale })
+ const resultAddSuffix = formatDistanceStrict(date, baseDate, {
+ locale,
+ addSuffix: true
+ })
+ const resultForcedUnit = formatDistanceStrict(date, baseDate, {
+ locale,
+ unit: 'hour'
+ })
+ return `| ${dateString} | ${result} | ${resultAddSuffix} | ${resultForcedUnit} |`
+ })
+ .join('\n')}`
+}
diff --git a/date-fns/scripts/build/localeSnapshots/renderFormatParse/formatParseTokens.js b/date-fns/scripts/build/localeSnapshots/renderFormatParse/formatParseTokens.js
new file mode 100644
index 0000000..5631d95
--- /dev/null
+++ b/date-fns/scripts/build/localeSnapshots/renderFormatParse/formatParseTokens.js
@@ -0,0 +1,218 @@
+const yearDates = [
+ new Date(1987, 1, 11, 12, 13, 14, 15),
+ new Date(0, 0, 1, 12, 13, 14, 15).setFullYear(5, 0, 1)
+]
+
+const quarterDates = [
+ new Date(2019, 0, 1, 12, 13, 14, 15),
+ new Date(2019, 3, 1, 12, 13, 14, 15)
+]
+
+const monthDates = [
+ new Date(2019, 1, 11, 12, 13, 14, 15),
+ new Date(2019, 6, 10, 12, 13, 14, 15)
+]
+
+const weekOfYearDates = [
+ new Date(2019, 0, 1, 12, 13, 14, 15),
+ new Date(2019, 11, 1, 12, 13, 14, 15)
+]
+
+const dayOfMonthDates = [
+ new Date(2019, 1, 11, 12, 13, 14, 15),
+ new Date(2019, 1, 28, 12, 13, 14, 15)
+]
+
+const dayOfYearDates = [
+ new Date(2019, 1, 11, 12, 13, 14, 15),
+ new Date(2019, 11, 31, 12, 13, 14, 15)
+]
+
+const dayOfWeekDates = [
+ new Date(2019, 1, 11, 12, 13, 14, 15),
+ new Date(2019, 1, 15, 12, 13, 14, 15)
+]
+
+const timeOfDayDates = [
+ new Date(2019, 1, 11, 11, 13, 14, 15),
+ new Date(2019, 1, 11, 14, 13, 14, 15),
+ new Date(2019, 1, 11, 19, 13, 14, 15),
+ new Date(2019, 1, 11, 2, 13, 14, 15)
+]
+
+const hourDates = [
+ new Date(2019, 1, 11, 11, 13, 14, 15),
+ new Date(2019, 1, 11, 23, 13, 14, 15)
+]
+
+const localizedDates = [
+ new Date(1987, 1, 11, 12, 13, 14, 15),
+ new Date(1453, 4, 29, 23, 59, 59, 999)
+]
+
+const formatParseTokens = [
+ {
+ title: 'Calendar year',
+ tokens: ['yo'],
+ dates: yearDates
+ },
+
+ {
+ title: 'Local week-numbering year',
+ tokens: ['Yo'],
+ dates: yearDates,
+ options: { useAdditionalWeekYearTokens: true }
+ },
+
+ {
+ title: 'Quarter (formatting)',
+ tokens: ['Qo', 'QQQ', 'QQQQ', 'QQQQQ'],
+ dates: quarterDates
+ },
+
+ {
+ title: 'Quarter (stand-alone)',
+ tokens: ['qo', 'qqq', 'qqqq'],
+ dates: quarterDates
+ },
+
+ {
+ title: 'Month (formatting)',
+ tokens: ['Mo', 'MMM', 'MMMM', 'MMMMM'],
+ dates: monthDates
+ },
+
+ {
+ title: 'Month (stand-alone) ',
+ tokens: ['Lo', 'LLL', 'LLLL', 'LLLLL'],
+ dates: monthDates
+ },
+
+ {
+ title: 'Local week of year',
+ tokens: ['wo'],
+ dates: weekOfYearDates
+ },
+
+ {
+ title: 'ISO week of year',
+ tokens: ['Io'],
+ dates: weekOfYearDates
+ },
+
+ {
+ title: 'Day of month',
+ tokens: ['do'],
+ dates: dayOfMonthDates
+ },
+
+ {
+ title: 'Day of year',
+ tokens: ['Do'],
+ dates: dayOfYearDates,
+ options: { useAdditionalDayOfYearTokens: true }
+ },
+
+ {
+ title: 'Day of week (formatting)',
+ tokens: ['E', 'EE', 'EEE', 'EEEE', 'EEEEE', 'EEEEEE'],
+ dates: dayOfWeekDates
+ },
+
+ {
+ title: 'ISO day of week (formatting)',
+ tokens: ['io', 'iii', 'iiii', 'iiiii', 'iiiiii'],
+ dates: dayOfWeekDates
+ },
+
+ {
+ title: 'Local day of week (formatting)',
+ tokens: ['eo', 'eee', 'eeee', 'eeeee', 'eeeeee'],
+ dates: dayOfWeekDates
+ },
+
+ {
+ title: 'Local day of week (stand-alone)',
+ tokens: ['co', 'ccc', 'cccc', 'ccccc', 'cccccc'],
+ dates: dayOfWeekDates
+ },
+
+ {
+ title: 'AM, PM',
+ tokens: ['a', 'aa', 'aaa', 'aaaa', 'aaaaa'],
+ dates: timeOfDayDates
+ },
+
+ {
+ title: 'AM, PM, noon, midnight',
+ tokens: ['b', 'bb', 'bbb', 'bbbb', 'bbbbb'],
+ dates: timeOfDayDates
+ },
+
+ {
+ title: 'Flexible day period',
+ tokens: ['B', 'BB', 'BBB', 'BBBB', 'BBBBB'],
+ dates: timeOfDayDates
+ },
+
+ {
+ title: 'Hour [1-12]',
+ tokens: ['ho'],
+ dates: hourDates
+ },
+
+ {
+ title: 'Hour [0-23]',
+ tokens: ['Ho'],
+ dates: hourDates
+ },
+
+ {
+ title: 'Hour [0-11]',
+ tokens: ['Ko'],
+ dates: hourDates
+ },
+
+ {
+ title: 'Hour [1-24]',
+ tokens: ['ko'],
+ dates: hourDates
+ },
+
+ {
+ title: 'Minute',
+ tokens: ['mo'],
+ dates: [
+ new Date(2019, 0, 1, 12, 1, 14, 15),
+ new Date(2019, 3, 1, 12, 55, 14, 15)
+ ]
+ },
+
+ {
+ title: 'Second',
+ tokens: ['so'],
+ dates: [
+ new Date(2019, 0, 1, 12, 13, 1, 15),
+ new Date(2019, 3, 1, 12, 13, 55, 15)
+ ]
+ },
+
+ {
+ title: 'Long localized date',
+ tokens: ['P', 'PP', 'PPP', 'PPPP'],
+ dates: localizedDates
+ },
+
+ {
+ title: 'Long localized time',
+ tokens: ['p', 'pp', 'ppp', 'pppp'],
+ dates: localizedDates
+ },
+
+ {
+ title: 'Combination of date and time',
+ tokens: ['Pp', 'PPpp', 'PPPppp', 'PPPPpppp'],
+ dates: localizedDates
+ }
+]
+export default formatParseTokens
diff --git a/date-fns/scripts/build/localeSnapshots/renderFormatParse/index.js b/date-fns/scripts/build/localeSnapshots/renderFormatParse/index.js
new file mode 100644
index 0000000..2ddcb10
--- /dev/null
+++ b/date-fns/scripts/build/localeSnapshots/renderFormatParse/index.js
@@ -0,0 +1,59 @@
+import format from '../../../../src/format'
+import isValid from '../../../../src/isValid'
+import parse from '../../../../src/parse'
+import toDate from '../../../../src/toDate'
+import formatParseTokens from './formatParseTokens'
+
+export default function renderFormatParse(locale) {
+ return `## \`format\` and \`parse\`
+
+| Title | Token string | Date | \`format\` result | \`parse\` result |
+|-|-|-|-|-|
+${formatParseTokens
+ .map(({ title, tokens, dates, options = {}, skipParse }) => {
+ return tokens
+ .map((token, tokenIndex) => {
+ return dates
+ .map((date, dateIndex) => {
+ const dateString = toDate(date).toISOString()
+ const formatResult = format(
+ date,
+ token,
+ Object.assign({ locale }, options)
+ )
+ let parsedDate
+ try {
+ parsedDate =
+ !skipParse &&
+ parse(
+ formatResult,
+ token,
+ date,
+ Object.assign({ locale }, options)
+ )
+ } catch (_err) {
+ parsedDate = 'Errored'
+ }
+
+ const parseResult = skipParse
+ ? 'NA'
+ : parsedDate === 'Errored'
+ ? parsedDate
+ : isValid(parsedDate)
+ ? parsedDate.toISOString()
+ : 'Invalid Date'
+
+ if (dateIndex === 0 && tokenIndex === 0) {
+ return `| ${title} | ${token} | ${dateString} | ${formatResult} | ${parseResult} |`
+ } else if (dateIndex === 0) {
+ return `| | ${token} | ${dateString} | ${formatResult} | ${parseResult} |`
+ } else {
+ return `| | | ${dateString} | ${formatResult} | ${parseResult} |`
+ }
+ })
+ .join('\n')
+ })
+ .join('\n')
+ })
+ .join('\n')}`
+}
diff --git a/date-fns/scripts/build/localeSnapshots/renderFormatRelative/index.js b/date-fns/scripts/build/localeSnapshots/renderFormatRelative/index.js
new file mode 100644
index 0000000..68e558e
--- /dev/null
+++ b/date-fns/scripts/build/localeSnapshots/renderFormatRelative/index.js
@@ -0,0 +1,23 @@
+import formatRelative from '../../../../src/formatRelative'
+import { baseDate, relativeDates } from '../_lib/distanceDates'
+
+export default function renderFormatRelative(locale) {
+ return `## \`formatRelative\`
+
+If now is January 1st, 2000, 00:00.
+
+| Date | Result |
+|-|-|
+${relativeDates
+ .map(date => {
+ const dateString = date.toISOString()
+ let result
+ try {
+ result = formatRelative(date, baseDate, { locale })
+ } catch (_err) {
+ result = 'Errored'
+ }
+ return `| ${dateString} | ${result} |`
+ })
+ .join('\n')}`
+}
diff --git a/date-fns/scripts/build/package.sh b/date-fns/scripts/build/package.sh
new file mode 100755
index 0000000..5f7a831
--- /dev/null
+++ b/date-fns/scripts/build/package.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+
+# The script generates the package in the given directory.
+#
+# It's addition to the build process. The script is used in examples.
+# It also could be used to build date-fns from a git checkout.
+
+set -e
+
+# cd to the root dir
+root="$(pwd)/$(dirname "$0")/../.."
+cd "$root" || exit 1
+
+PATH="$(npm bin):$PATH"
+# XXX: $PACKAGE_OUTPUT_PATH must be an absolute path!
+dir=${PACKAGE_OUTPUT_PATH:-"$root/tmp/package"}
+
+# Clean up output dir
+rm -rf "$dir"
+mkdir -p "$dir"
+
+# Traspile CommonJS versions of files
+env BABEL_ENV='commonjs' babel src --source-root src --out-dir "$dir" --extensions .ts,.js --ignore test.js,benchmark.js,snapshot.md --copy-files --quiet
+
+# Traspile ESM versions of files
+env BABEL_ENV='esm' babel src --source-root src --out-dir "$dir/esm" --extensions .ts,.js --ignore test.js,benchmark.js,snapshot.md,package.json --copy-files --quiet
+
+# Copy basic files
+for pattern in CHANGELOG.md \
+ package.json \
+ docs \
+ LICENSE.md \
+ README.md \
+ typings.d.ts
+do
+ cp -r "$pattern" "$dir"
+done
+
+# Remove clean up code when this issues is resolved:
+# https://github.com/babel/babel/issues/6226
+
+# Clean up dev code
+find "$dir" -type f -name "test.js" -delete
+find "$dir" -type f -name "benchmark.js" -delete
+find "$dir" -type f -name "snapshot.md" -delete
+
+# Clean up package.json pointing to the modules
+find "$dir/esm" -type f -name "package.json" -delete
+
+./scripts/build/packages.js
+./scripts/build/removeOutdatedLocales.js $dir
diff --git a/date-fns/scripts/build/packages.js b/date-fns/scripts/build/packages.js
new file mode 100755
index 0000000..154754c
--- /dev/null
+++ b/date-fns/scripts/build/packages.js
@@ -0,0 +1,92 @@
+#!/usr/bin/env node
+
+/**
+ * @file
+ * The script generates package.json files that points to correct ESM modules
+ * and TypeScript typings.
+ *
+ * It's a part of the build process.
+ */
+
+const { writeFile } = require('mz/fs')
+const path = require('path')
+const listFns = require('../_lib/listFns')
+const listFPFns = require('../_lib/listFPFns')
+const listLocales = require('../_lib/listLocales')
+const rootPath =
+ process.env.PACKAGE_OUTPUT_PATH || path.resolve(process.cwd(), 'tmp/package')
+
+const extraModules = [
+ { fullPath: './src/fp/index.js' },
+ { fullPath: './src/locale/index.js' },
+]
+
+writePackages()
+
+async function writePackages() {
+ const initialPackages = await getInitialPackages()
+ const modules = await listAll()
+ await Promise.all(
+ modules.map(async (module) =>
+ writePackage(module.fullPath, initialPackages[module.fullPath])
+ )
+ )
+ console.log('package.json files are generated')
+}
+
+function writePackage(fullPath, initialPackage) {
+ const dirPath = path.dirname(fullPath)
+ const typingsRelativePath = path.relative(dirPath, `./src/typings.d.ts`)
+ const packagePath = path.resolve(
+ rootPath,
+ `${dirPath.replace('./src/', './')}/package.json`
+ )
+
+ return writeFile(
+ packagePath,
+ JSON.stringify(
+ Object.assign({ sideEffects: false }, initialPackage || {}, {
+ typings: typingsRelativePath,
+ }),
+ null,
+ 2
+ )
+ )
+}
+
+async function getInitialPackages() {
+ const fns = await listFns()
+ return fns
+ .concat(listFPFns())
+ .concat(listLocales())
+ .concat(extraModules)
+ .reduce((acc, module) => {
+ acc[module.fullPath] = getModulePackage(module.fullPath)
+ return acc
+ }, {})
+}
+
+function getModulePackage(fullPath) {
+ const dirPath = path.dirname(fullPath)
+ const subPath = dirPath.match(/^\.\/src\/(.+)$/)[1]
+ const esmRelativePath = path.relative(
+ dirPath,
+ `./src/esm/${subPath}/index.js`
+ )
+ return { module: esmRelativePath }
+}
+
+async function listAll() {
+ const fns = await listFns()
+ return fns
+ .concat(listFPFns())
+ .concat(listLocales())
+ .concat(extraModules)
+ .reduce((acc, module) => {
+ const esmModule = Object.assign({}, module, {
+ fullPath: module.fullPath.replace('./src/', './src/esm/'),
+ })
+ return acc.concat([module, esmModule])
+ }, [])
+ .concat([])
+}
diff --git a/date-fns/scripts/build/removeOutdatedLocales.js b/date-fns/scripts/build/removeOutdatedLocales.js
new file mode 100755
index 0000000..5285f11
--- /dev/null
+++ b/date-fns/scripts/build/removeOutdatedLocales.js
@@ -0,0 +1,20 @@
+#!/usr/bin/env node
+
+/**
+ * @file
+ * The script removes outdated locales from the package.
+ *
+ * It's a part of the build process.
+ */
+
+const path = require('path')
+const rimraf = require('rimraf')
+
+const packageDir = process.argv[2]
+if (!packageDir) throw new Error('Package dir should be passed as an argument')
+
+const locales = require('../../outdatedLocales.json')
+locales.forEach(locale => {
+ rimraf.sync(path.resolve(packageDir, `locale/${locale}`))
+ rimraf.sync(path.resolve(packageDir, `locale/esm/${locale}`))
+})
diff --git a/date-fns/scripts/build/typings.js b/date-fns/scripts/build/typings.js
new file mode 100755
index 0000000..ea0dde5
--- /dev/null
+++ b/date-fns/scripts/build/typings.js
@@ -0,0 +1,31 @@
+#!/usr/bin/env node
+
+/**
+ * @file
+ * The script generates Flow and TypeScript typing files.
+ *
+ * It's a part of the build process.
+ */
+
+const path = require('path')
+const listLocales = require('../_lib/listLocales')
+const getConstants = require('../_lib/getConstants')
+const jsDocs = require(path.resolve(process.cwd(), 'tmp/docs.json'))
+
+const { generateTypeScriptTypings } = require('./_lib/typings/typeScript')
+const { generateFlowTypings } = require('./_lib/typings/flow')
+
+const locales = listLocales()
+
+const fns = Object.keys(jsDocs)
+ .map(category => jsDocs[category])
+ .reduce((previousValue, newValue) => [...previousValue, ...newValue], [])
+ .filter(doc => doc.kind === 'function')
+ .sort((a, b) => a.title.localeCompare(b.title, 'en-US'))
+
+const constants = getConstants()
+
+const aliases = jsDocs['Types']
+
+generateTypeScriptTypings(fns, aliases, locales, constants)
+generateFlowTypings(fns, aliases, locales, constants)