diff --git a/README.md b/README.md index 0458221..6140be1 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,16 @@ response | 507 | INSUFFICIENT_STORAGE | Insufficient Storage | | 511 | NETWORK_AUTHENTICATION_REQUIRED | Network Authentication Required | +## Classes + +| Constant | Range | +| ------------- | --------- | +| Informational | 100 - 199 | +| Successful | 200 - 299 | +| Redirection | 300 - 399 | +| ClientError | 400 - 499 | +| ServerError | 500 - 599 | + ## Migrating from v1.x.x http-status-codes v2 is mostly backwards compatible with v1. There is a single breaking change and two recommended changes. diff --git a/classes.json b/classes.json new file mode 100644 index 0000000..c2aff65 --- /dev/null +++ b/classes.json @@ -0,0 +1,57 @@ +[ + { + "name": "Informational", + "constant": "Informational", + "range": { + "min": 100, + "max": 199 + }, + "comment": { + "doc": "Official Documentation @ https://tools.ietf.org/html/rfc7231#section-6.2" + } + }, + { + "name": "Successful", + "constant": "Successful", + "range": { + "min": 200, + "max": 299 + }, + "comment": { + "doc": "Official Documentation @ https://tools.ietf.org/html/rfc7231#section-6.3" + } + }, + { + "name": "Redirection", + "constant": "Redirection", + "range": { + "min": 300, + "max": 399 + }, + "comment": { + "doc": "Official Documentation @ https://tools.ietf.org/html/rfc7231#section-6.4" + } + }, + { + "name": "ClientError", + "constant": "ClientError", + "range": { + "min": 400, + "max": 499 + }, + "comment": { + "doc": "Official Documentation @ https://tools.ietf.org/html/rfc7231#section-6.5" + } + }, + { + "name": "ServerError", + "constant": "ServerError", + "range": { + "min": 500, + "max": 599 + }, + "comment": { + "doc": "Official Documentation @ https://tools.ietf.org/html/rfc7231#section-6.6" + } + } +] \ No newline at end of file diff --git a/package.json b/package.json index efdf662..831ff20 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "http-status-codes", "sideEffects": false, - "version": "2.2.0", + "version": "3.1.0", "description": "Constants enumerating the HTTP status codes. Based on the Java Apache HttpStatus API.", "scripts": { "update-codes": "ts-node --project ./scripts/tsconfig.json ./scripts/update-codes", diff --git a/scripts/update-codes.ts b/scripts/update-codes.ts index 51f3800..9eaf0e9 100644 --- a/scripts/update-codes.ts +++ b/scripts/update-codes.ts @@ -8,12 +8,19 @@ import fs from 'fs-extra'; import { - Writers, VariableDeclarationKind, Project, StructureKind, EnumMemberStructure, OptionalKind, + Writers, + VariableDeclarationKind, + Project, + StructureKind, + EnumMemberStructure, + OptionalKind, + StatementStructures, } from 'ts-morph'; import markdownTable from 'markdown-table'; import Codes from '../codes.json'; +import Classes from '../classes.json'; interface JsonCodeComment { doc: string; @@ -59,7 +66,62 @@ const run = async () => { value: code, docs: [`${deprecatedString}${doc}\n\n${description}`], }; - }).sort(({value: aValue}, {value : bValue}) => aValue - bValue); + }).sort(({ value: aValue }, { value: bValue }) => aValue - bValue); + + const statusClassStatements: StatementStructures[] = Classes + .map(({ + constant, range, comment, + }) => { + const codesInRange = Codes.filter( + (code) => code.code >= range.min && code.code <= range.max, + ); + + const codesAsTypeString = codesInRange.map((code) => `StatusCodes.${code.constant}`); + const rangeDescriptorString = `Union of all status codes between ${range.min} and ${range.max}:`; + const comprehensiveListOfTypes = '- '.concat(codesAsTypeString.join('\n- ')); + + return { + docs: [`${comment.doc}\n\n${rangeDescriptorString}\n${comprehensiveListOfTypes}`], + kind: StructureKind.TypeAlias, + name: constant, + type: '\n| '.concat(codesAsTypeString.join('\n| ')), + isExported: true, + }; + }); + + const statusClassNamespaces: StatementStructures[] = Classes + .map(({ + constant, range, comment, + }) => { + const codesInRange = Codes.filter( + (code) => code.code >= range.min && code.code <= range.max, + ); + + const codesAsTypeString = codesInRange.map((code) => `StatusCodes.${code.constant}`); + const rangeDescriptorString = `Union of all status codes between ${range.min} and ${range.max}:`; + const comprehensiveListOfTypes = '- '.concat(codesAsTypeString.join('\n- ')); + + const temp: StatementStructures = { + docs: [`${comment.doc}\n\n${rangeDescriptorString}\n${comprehensiveListOfTypes}`], + kind: StructureKind.Namespace, + name: constant, + isExported: true, + statements: [ + { + docs: ['List of all codes'], + kind: StructureKind.VariableStatement, + isExported: true, + declarationKind: VariableDeclarationKind.Const, + declarations: [{ + name: 'LIST', + type: 'Number[]', + initializer: `[\n${(codesInRange.map((code) => `StatusCodes.${code.constant}`)).join(',\n')}\n]`, + }], + }, + ], + }; + return temp; + }); const statusCodeToReasonPhrase = Codes .reduce((acc: Record, { code, phrase }) => { @@ -85,6 +147,27 @@ const run = async () => { overwrite: true, }); + const statusClassFile = project.createSourceFile('src/status-classes.ts', { + statements: [ + { + kind: StructureKind.Namespace, + name: 'StatusClasses', + isExported: true, + statements: [...statusClassStatements, ...statusClassNamespaces], + }, + ], + }, { + overwrite: true, + }); + statusClassFile.addImportDeclaration({ + namedImports: [ + { + name: 'StatusCodes', + }, + ], + moduleSpecifier: './status-codes', + }); + const reasonPhraseFile = project.createSourceFile('src/reason-phrases.ts', { statements: [ { @@ -126,7 +209,7 @@ const run = async () => { overwrite: true, }); - [statusCodeFile, reasonPhraseFile, utilsFile].forEach((sf) => { + [statusCodeFile, statusClassFile, reasonPhraseFile, utilsFile].forEach((sf) => { sf.insertStatements(0, '// Generated file. Do not edit\n'); }); @@ -145,6 +228,15 @@ const run = async () => { const readmeRegex = /## Codes\n\n([^#]*)##/g; readmeFile = readmeFile.replace(readmeRegex, `## Codes\n\n${table}\n\n##`); + const sortedClasses = Classes.sort((a, b) => (a.range.min - b.range.min)); + const classTable = markdownTable([ + ['Constant', 'Range'], + ...sortedClasses.map(({ constant, range }) => [constant, `${range.min} - ${range.max}`]), + ]); + + const readmeClassRegex = /## Classes\n\n([^#]*)##/g; + readmeFile = readmeFile.replace(readmeClassRegex, `## Classes\n\n${classTable}\n\n##`); + fs.writeFile('./README.md', readmeFile); console.log('Successfully updated README.md table'); }; diff --git a/src/index.ts b/src/index.ts index d688d56..3ddf22d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,6 +15,10 @@ export { StatusCodes, } from './status-codes'; +export { + StatusClasses, +} from './status-classes'; + export { ReasonPhrases, } from './reason-phrases'; diff --git a/src/status-classes.ts b/src/status-classes.ts new file mode 100644 index 0000000..adf5e70 --- /dev/null +++ b/src/status-classes.ts @@ -0,0 +1,314 @@ +// Generated file. Do not edit +import { StatusCodes } from "./status-codes"; + +export namespace StatusClasses { + /** + * Official Documentation @ https://tools.ietf.org/html/rfc7231#section-6.2 + * + * Union of all status codes between 100 and 199: + * - StatusCodes.CONTINUE + * - StatusCodes.PROCESSING + * - StatusCodes.SWITCHING_PROTOCOLS + */ + export type Informational = + | StatusCodes.CONTINUE + | StatusCodes.PROCESSING + | StatusCodes.SWITCHING_PROTOCOLS; + /** + * Official Documentation @ https://tools.ietf.org/html/rfc7231#section-6.3 + * + * Union of all status codes between 200 and 299: + * - StatusCodes.ACCEPTED + * - StatusCodes.CREATED + * - StatusCodes.MULTI_STATUS + * - StatusCodes.NO_CONTENT + * - StatusCodes.NON_AUTHORITATIVE_INFORMATION + * - StatusCodes.OK + * - StatusCodes.PARTIAL_CONTENT + * - StatusCodes.RESET_CONTENT + */ + export type Successful = + | StatusCodes.ACCEPTED + | StatusCodes.CREATED + | StatusCodes.MULTI_STATUS + | StatusCodes.NO_CONTENT + | StatusCodes.NON_AUTHORITATIVE_INFORMATION + | StatusCodes.OK + | StatusCodes.PARTIAL_CONTENT + | StatusCodes.RESET_CONTENT; + /** + * Official Documentation @ https://tools.ietf.org/html/rfc7231#section-6.4 + * + * Union of all status codes between 300 and 399: + * - StatusCodes.MOVED_PERMANENTLY + * - StatusCodes.MOVED_TEMPORARILY + * - StatusCodes.MULTIPLE_CHOICES + * - StatusCodes.NOT_MODIFIED + * - StatusCodes.PERMANENT_REDIRECT + * - StatusCodes.SEE_OTHER + * - StatusCodes.TEMPORARY_REDIRECT + * - StatusCodes.USE_PROXY + */ + export type Redirection = + | StatusCodes.MOVED_PERMANENTLY + | StatusCodes.MOVED_TEMPORARILY + | StatusCodes.MULTIPLE_CHOICES + | StatusCodes.NOT_MODIFIED + | StatusCodes.PERMANENT_REDIRECT + | StatusCodes.SEE_OTHER + | StatusCodes.TEMPORARY_REDIRECT + | StatusCodes.USE_PROXY; + /** + * Official Documentation @ https://tools.ietf.org/html/rfc7231#section-6.5 + * + * Union of all status codes between 400 and 499: + * - StatusCodes.BAD_REQUEST + * - StatusCodes.CONFLICT + * - StatusCodes.EXPECTATION_FAILED + * - StatusCodes.FAILED_DEPENDENCY + * - StatusCodes.FORBIDDEN + * - StatusCodes.GONE + * - StatusCodes.IM_A_TEAPOT + * - StatusCodes.INSUFFICIENT_SPACE_ON_RESOURCE + * - StatusCodes.LENGTH_REQUIRED + * - StatusCodes.LOCKED + * - StatusCodes.METHOD_FAILURE + * - StatusCodes.METHOD_NOT_ALLOWED + * - StatusCodes.NOT_ACCEPTABLE + * - StatusCodes.NOT_FOUND + * - StatusCodes.PAYMENT_REQUIRED + * - StatusCodes.PRECONDITION_FAILED + * - StatusCodes.PRECONDITION_REQUIRED + * - StatusCodes.PROXY_AUTHENTICATION_REQUIRED + * - StatusCodes.REQUEST_HEADER_FIELDS_TOO_LARGE + * - StatusCodes.REQUEST_TIMEOUT + * - StatusCodes.REQUEST_TOO_LONG + * - StatusCodes.REQUEST_URI_TOO_LONG + * - StatusCodes.REQUESTED_RANGE_NOT_SATISFIABLE + * - StatusCodes.TOO_MANY_REQUESTS + * - StatusCodes.UNAUTHORIZED + * - StatusCodes.UNAVAILABLE_FOR_LEGAL_REASONS + * - StatusCodes.UNPROCESSABLE_ENTITY + * - StatusCodes.UNSUPPORTED_MEDIA_TYPE + * - StatusCodes.MISDIRECTED_REQUEST + */ + export type ClientError = + | StatusCodes.BAD_REQUEST + | StatusCodes.CONFLICT + | StatusCodes.EXPECTATION_FAILED + | StatusCodes.FAILED_DEPENDENCY + | StatusCodes.FORBIDDEN + | StatusCodes.GONE + | StatusCodes.IM_A_TEAPOT + | StatusCodes.INSUFFICIENT_SPACE_ON_RESOURCE + | StatusCodes.LENGTH_REQUIRED + | StatusCodes.LOCKED + | StatusCodes.METHOD_FAILURE + | StatusCodes.METHOD_NOT_ALLOWED + | StatusCodes.NOT_ACCEPTABLE + | StatusCodes.NOT_FOUND + | StatusCodes.PAYMENT_REQUIRED + | StatusCodes.PRECONDITION_FAILED + | StatusCodes.PRECONDITION_REQUIRED + | StatusCodes.PROXY_AUTHENTICATION_REQUIRED + | StatusCodes.REQUEST_HEADER_FIELDS_TOO_LARGE + | StatusCodes.REQUEST_TIMEOUT + | StatusCodes.REQUEST_TOO_LONG + | StatusCodes.REQUEST_URI_TOO_LONG + | StatusCodes.REQUESTED_RANGE_NOT_SATISFIABLE + | StatusCodes.TOO_MANY_REQUESTS + | StatusCodes.UNAUTHORIZED + | StatusCodes.UNAVAILABLE_FOR_LEGAL_REASONS + | StatusCodes.UNPROCESSABLE_ENTITY + | StatusCodes.UNSUPPORTED_MEDIA_TYPE + | StatusCodes.MISDIRECTED_REQUEST; + /** + * Official Documentation @ https://tools.ietf.org/html/rfc7231#section-6.6 + * + * Union of all status codes between 500 and 599: + * - StatusCodes.BAD_GATEWAY + * - StatusCodes.GATEWAY_TIMEOUT + * - StatusCodes.HTTP_VERSION_NOT_SUPPORTED + * - StatusCodes.INSUFFICIENT_STORAGE + * - StatusCodes.INTERNAL_SERVER_ERROR + * - StatusCodes.NETWORK_AUTHENTICATION_REQUIRED + * - StatusCodes.NOT_IMPLEMENTED + * - StatusCodes.SERVICE_UNAVAILABLE + */ + export type ServerError = + | StatusCodes.BAD_GATEWAY + | StatusCodes.GATEWAY_TIMEOUT + | StatusCodes.HTTP_VERSION_NOT_SUPPORTED + | StatusCodes.INSUFFICIENT_STORAGE + | StatusCodes.INTERNAL_SERVER_ERROR + | StatusCodes.NETWORK_AUTHENTICATION_REQUIRED + | StatusCodes.NOT_IMPLEMENTED + | StatusCodes.SERVICE_UNAVAILABLE; + + /** + * Official Documentation @ https://tools.ietf.org/html/rfc7231#section-6.2 + * + * Union of all status codes between 100 and 199: + * - StatusCodes.CONTINUE + * - StatusCodes.PROCESSING + * - StatusCodes.SWITCHING_PROTOCOLS + */ + export namespace Informational { + /** List of all codes */ + export const LIST: Number[] = [ + StatusCodes.CONTINUE, + StatusCodes.PROCESSING, + StatusCodes.SWITCHING_PROTOCOLS + ]; + } + + /** + * Official Documentation @ https://tools.ietf.org/html/rfc7231#section-6.3 + * + * Union of all status codes between 200 and 299: + * - StatusCodes.ACCEPTED + * - StatusCodes.CREATED + * - StatusCodes.MULTI_STATUS + * - StatusCodes.NO_CONTENT + * - StatusCodes.NON_AUTHORITATIVE_INFORMATION + * - StatusCodes.OK + * - StatusCodes.PARTIAL_CONTENT + * - StatusCodes.RESET_CONTENT + */ + export namespace Successful { + /** List of all codes */ + export const LIST: Number[] = [ + StatusCodes.ACCEPTED, + StatusCodes.CREATED, + StatusCodes.MULTI_STATUS, + StatusCodes.NO_CONTENT, + StatusCodes.NON_AUTHORITATIVE_INFORMATION, + StatusCodes.OK, + StatusCodes.PARTIAL_CONTENT, + StatusCodes.RESET_CONTENT + ]; + } + + /** + * Official Documentation @ https://tools.ietf.org/html/rfc7231#section-6.4 + * + * Union of all status codes between 300 and 399: + * - StatusCodes.MOVED_PERMANENTLY + * - StatusCodes.MOVED_TEMPORARILY + * - StatusCodes.MULTIPLE_CHOICES + * - StatusCodes.NOT_MODIFIED + * - StatusCodes.PERMANENT_REDIRECT + * - StatusCodes.SEE_OTHER + * - StatusCodes.TEMPORARY_REDIRECT + * - StatusCodes.USE_PROXY + */ + export namespace Redirection { + /** List of all codes */ + export const LIST: Number[] = [ + StatusCodes.MOVED_PERMANENTLY, + StatusCodes.MOVED_TEMPORARILY, + StatusCodes.MULTIPLE_CHOICES, + StatusCodes.NOT_MODIFIED, + StatusCodes.PERMANENT_REDIRECT, + StatusCodes.SEE_OTHER, + StatusCodes.TEMPORARY_REDIRECT, + StatusCodes.USE_PROXY + ]; + } + + /** + * Official Documentation @ https://tools.ietf.org/html/rfc7231#section-6.5 + * + * Union of all status codes between 400 and 499: + * - StatusCodes.BAD_REQUEST + * - StatusCodes.CONFLICT + * - StatusCodes.EXPECTATION_FAILED + * - StatusCodes.FAILED_DEPENDENCY + * - StatusCodes.FORBIDDEN + * - StatusCodes.GONE + * - StatusCodes.IM_A_TEAPOT + * - StatusCodes.INSUFFICIENT_SPACE_ON_RESOURCE + * - StatusCodes.LENGTH_REQUIRED + * - StatusCodes.LOCKED + * - StatusCodes.METHOD_FAILURE + * - StatusCodes.METHOD_NOT_ALLOWED + * - StatusCodes.NOT_ACCEPTABLE + * - StatusCodes.NOT_FOUND + * - StatusCodes.PAYMENT_REQUIRED + * - StatusCodes.PRECONDITION_FAILED + * - StatusCodes.PRECONDITION_REQUIRED + * - StatusCodes.PROXY_AUTHENTICATION_REQUIRED + * - StatusCodes.REQUEST_HEADER_FIELDS_TOO_LARGE + * - StatusCodes.REQUEST_TIMEOUT + * - StatusCodes.REQUEST_TOO_LONG + * - StatusCodes.REQUEST_URI_TOO_LONG + * - StatusCodes.REQUESTED_RANGE_NOT_SATISFIABLE + * - StatusCodes.TOO_MANY_REQUESTS + * - StatusCodes.UNAUTHORIZED + * - StatusCodes.UNAVAILABLE_FOR_LEGAL_REASONS + * - StatusCodes.UNPROCESSABLE_ENTITY + * - StatusCodes.UNSUPPORTED_MEDIA_TYPE + * - StatusCodes.MISDIRECTED_REQUEST + */ + export namespace ClientError { + /** List of all codes */ + export const LIST: Number[] = [ + StatusCodes.BAD_REQUEST, + StatusCodes.CONFLICT, + StatusCodes.EXPECTATION_FAILED, + StatusCodes.FAILED_DEPENDENCY, + StatusCodes.FORBIDDEN, + StatusCodes.GONE, + StatusCodes.IM_A_TEAPOT, + StatusCodes.INSUFFICIENT_SPACE_ON_RESOURCE, + StatusCodes.LENGTH_REQUIRED, + StatusCodes.LOCKED, + StatusCodes.METHOD_FAILURE, + StatusCodes.METHOD_NOT_ALLOWED, + StatusCodes.NOT_ACCEPTABLE, + StatusCodes.NOT_FOUND, + StatusCodes.PAYMENT_REQUIRED, + StatusCodes.PRECONDITION_FAILED, + StatusCodes.PRECONDITION_REQUIRED, + StatusCodes.PROXY_AUTHENTICATION_REQUIRED, + StatusCodes.REQUEST_HEADER_FIELDS_TOO_LARGE, + StatusCodes.REQUEST_TIMEOUT, + StatusCodes.REQUEST_TOO_LONG, + StatusCodes.REQUEST_URI_TOO_LONG, + StatusCodes.REQUESTED_RANGE_NOT_SATISFIABLE, + StatusCodes.TOO_MANY_REQUESTS, + StatusCodes.UNAUTHORIZED, + StatusCodes.UNAVAILABLE_FOR_LEGAL_REASONS, + StatusCodes.UNPROCESSABLE_ENTITY, + StatusCodes.UNSUPPORTED_MEDIA_TYPE, + StatusCodes.MISDIRECTED_REQUEST + ]; + } + + /** + * Official Documentation @ https://tools.ietf.org/html/rfc7231#section-6.6 + * + * Union of all status codes between 500 and 599: + * - StatusCodes.BAD_GATEWAY + * - StatusCodes.GATEWAY_TIMEOUT + * - StatusCodes.HTTP_VERSION_NOT_SUPPORTED + * - StatusCodes.INSUFFICIENT_STORAGE + * - StatusCodes.INTERNAL_SERVER_ERROR + * - StatusCodes.NETWORK_AUTHENTICATION_REQUIRED + * - StatusCodes.NOT_IMPLEMENTED + * - StatusCodes.SERVICE_UNAVAILABLE + */ + export namespace ServerError { + /** List of all codes */ + export const LIST: Number[] = [ + StatusCodes.BAD_GATEWAY, + StatusCodes.GATEWAY_TIMEOUT, + StatusCodes.HTTP_VERSION_NOT_SUPPORTED, + StatusCodes.INSUFFICIENT_STORAGE, + StatusCodes.INTERNAL_SERVER_ERROR, + StatusCodes.NETWORK_AUTHENTICATION_REQUIRED, + StatusCodes.NOT_IMPLEMENTED, + StatusCodes.SERVICE_UNAVAILABLE + ]; + } +}