diff --git a/package.json b/package.json index 6b6cdd67..45e2469f 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "wasm": "ts-node bin/build_wasm.ts", "clean": "rm -rf lib && rm -rf test/tmp", "prepare": "npm run clean && npm run build-ts", - "test": "node -r ts-node/register/type-check -r ./test/md-test.ts", + "test": "node -r ts-node/register/type-check ./test/md-test.ts", "lint": "eslint -c eslint.json bin/*.ts src/*.ts src/**/*.ts test/*.ts test/**/*.ts", "lint-fix": "eslint --fix -c eslint.json bin/*.ts src/*.ts src/**/*.ts test/*.ts test/**/*.ts", "postversion": "RELEASE=`node -e \"process.stdout.write(require('./package').version)\"` make -B postversion", diff --git a/src/llhttp/c-headers.ts b/src/llhttp/c-headers.ts index dec75c5e..6b7fe20b 100644 --- a/src/llhttp/c-headers.ts +++ b/src/llhttp/c-headers.ts @@ -1,5 +1,5 @@ import * as constants from './constants'; -import { enumToMap, IEnumMap } from './utils'; +import { enumToMap } from './utils'; type Encoding = 'none' | 'hex'; @@ -64,7 +64,7 @@ export class CHeaders { return res; } - private buildEnum(name: string, prefix: string, map: IEnumMap, + private buildEnum(name: string, prefix: string, map: constants.IntDict, encoding: Encoding = 'none'): string { let res = ''; @@ -92,7 +92,7 @@ export class CHeaders { return res; } - private buildMap(name: string, map: IEnumMap): string { + private buildMap(name: string, map: constants.IntDict): string { let res = ''; res += `#define ${name}_MAP(XX) \\\n`; diff --git a/src/llhttp/constants.ts b/src/llhttp/constants.ts index f52cd6c9..226342e1 100644 --- a/src/llhttp/constants.ts +++ b/src/llhttp/constants.ts @@ -1,144 +1,267 @@ -import { enumToMap, IEnumMap } from './utils'; - -// C headers - -export enum ERROR { - OK = 0, - INTERNAL = 1, - STRICT = 2, - CR_EXPECTED = 25, - LF_EXPECTED = 3, - UNEXPECTED_CONTENT_LENGTH = 4, - UNEXPECTED_SPACE = 30, - CLOSED_CONNECTION = 5, - INVALID_METHOD = 6, - INVALID_URL = 7, - INVALID_CONSTANT = 8, - INVALID_VERSION = 9, - INVALID_HEADER_TOKEN = 10, - INVALID_CONTENT_LENGTH = 11, - INVALID_CHUNK_SIZE = 12, - INVALID_STATUS = 13, - INVALID_EOF_STATE = 14, - INVALID_TRANSFER_ENCODING = 15, - - CB_MESSAGE_BEGIN = 16, - CB_HEADERS_COMPLETE = 17, - CB_MESSAGE_COMPLETE = 18, - CB_CHUNK_HEADER = 19, - CB_CHUNK_COMPLETE = 20, - - PAUSED = 21, - PAUSED_UPGRADE = 22, - PAUSED_H2_UPGRADE = 23, - - USER = 24, - - CB_URL_COMPLETE = 26, - CB_STATUS_COMPLETE = 27, - CB_METHOD_COMPLETE = 32, - CB_VERSION_COMPLETE = 33, - CB_HEADER_FIELD_COMPLETE = 28, - CB_HEADER_VALUE_COMPLETE = 29, - CB_CHUNK_EXTENSION_NAME_COMPLETE = 34, - CB_CHUNK_EXTENSION_VALUE_COMPLETE = 35, - CB_RESET = 31, -} +import { enumToMap } from './utils'; + +export type IntDict = Record; + +// Emums + +export const ERROR: IntDict = { + OK: 0, + INTERNAL: 1, + STRICT: 2, + CR_EXPECTED: 25, + LF_EXPECTED: 3, + UNEXPECTED_CONTENT_LENGTH: 4, + UNEXPECTED_SPACE: 30, + CLOSED_CONNECTION: 5, + INVALID_METHOD: 6, + INVALID_URL: 7, + INVALID_CONSTANT: 8, + INVALID_VERSION: 9, + INVALID_HEADER_TOKEN: 10, + INVALID_CONTENT_LENGTH: 11, + INVALID_CHUNK_SIZE: 12, + INVALID_STATUS: 13, + INVALID_EOF_STATE: 14, + INVALID_TRANSFER_ENCODING: 15, + + CB_MESSAGE_BEGIN: 16, + CB_HEADERS_COMPLETE: 17, + CB_MESSAGE_COMPLETE: 18, + CB_CHUNK_HEADER: 19, + CB_CHUNK_COMPLETE: 20, + + PAUSED: 21, + PAUSED_UPGRADE: 22, + PAUSED_H2_UPGRADE: 23, + + USER: 24, + + CB_URL_COMPLETE: 26, + CB_STATUS_COMPLETE: 27, + CB_METHOD_COMPLETE: 32, + CB_VERSION_COMPLETE: 33, + CB_HEADER_FIELD_COMPLETE: 28, + CB_HEADER_VALUE_COMPLETE: 29, + CB_CHUNK_EXTENSION_NAME_COMPLETE: 34, + CB_CHUNK_EXTENSION_VALUE_COMPLETE: 35, + CB_RESET: 31, +}; -export enum TYPE { - BOTH = 0, // default - REQUEST = 1, - RESPONSE = 2, -} +export const TYPE: IntDict = { + BOTH: 0, // default + REQUEST: 1, + RESPONSE: 2, +}; -export enum FLAGS { - CONNECTION_KEEP_ALIVE = 1 << 0, - CONNECTION_CLOSE = 1 << 1, - CONNECTION_UPGRADE = 1 << 2, - CHUNKED = 1 << 3, - UPGRADE = 1 << 4, - CONTENT_LENGTH = 1 << 5, - SKIPBODY = 1 << 6, - TRAILING = 1 << 7, +export const FLAGS: IntDict = { + CONNECTION_KEEP_ALIVE: 1 << 0, + CONNECTION_CLOSE: 1 << 1, + CONNECTION_UPGRADE: 1 << 2, + CHUNKED: 1 << 3, + UPGRADE: 1 << 4, + CONTENT_LENGTH: 1 << 5, + SKIPBODY: 1 << 6, + TRAILING: 1 << 7, // 1 << 8 is unused - TRANSFER_ENCODING = 1 << 9, -} + TRANSFER_ENCODING: 1 << 9, +}; -export enum LENIENT_FLAGS { - HEADERS = 1 << 0, - CHUNKED_LENGTH = 1 << 1, - KEEP_ALIVE = 1 << 2, - TRANSFER_ENCODING = 1 << 3, - VERSION = 1 << 4, - DATA_AFTER_CLOSE = 1 << 5, - OPTIONAL_LF_AFTER_CR = 1 << 6, - OPTIONAL_CRLF_AFTER_CHUNK = 1 << 7, - OPTIONAL_CR_BEFORE_LF = 1 << 8, - SPACES_AFTER_CHUNK_SIZE = 1 << 9, -} +export const LENIENT_FLAGS: IntDict = { + HEADERS: 1 << 0, + CHUNKED_LENGTH: 1 << 1, + KEEP_ALIVE: 1 << 2, + TRANSFER_ENCODING: 1 << 3, + VERSION: 1 << 4, + DATA_AFTER_CLOSE: 1 << 5, + OPTIONAL_LF_AFTER_CR: 1 << 6, + OPTIONAL_CRLF_AFTER_CHUNK: 1 << 7, + OPTIONAL_CR_BEFORE_LF: 1 << 8, + SPACES_AFTER_CHUNK_SIZE: 1 << 9, +}; -export enum METHODS { - DELETE = 0, - GET = 1, - HEAD = 2, - POST = 3, - PUT = 4, +export const METHODS: IntDict = { + 'DELETE': 0, + 'GET': 1, + 'HEAD': 2, + 'POST': 3, + 'PUT': 4, /* pathological */ - CONNECT = 5, - OPTIONS = 6, - TRACE = 7, + 'CONNECT': 5, + 'OPTIONS': 6, + 'TRACE': 7, /* WebDAV */ - COPY = 8, - LOCK = 9, - MKCOL = 10, - MOVE = 11, - PROPFIND = 12, - PROPPATCH = 13, - SEARCH = 14, - UNLOCK = 15, - BIND = 16, - REBIND = 17, - UNBIND = 18, - ACL = 19, + 'COPY': 8, + 'LOCK': 9, + 'MKCOL': 10, + 'MOVE': 11, + 'PROPFIND': 12, + 'PROPPATCH': 13, + 'SEARCH': 14, + 'UNLOCK': 15, + 'BIND': 16, + 'REBIND': 17, + 'UNBIND': 18, + 'ACL': 19, /* subversion */ - REPORT = 20, - MKACTIVITY = 21, - CHECKOUT = 22, - MERGE = 23, + 'REPORT': 20, + 'MKACTIVITY': 21, + 'CHECKOUT': 22, + 'MERGE': 23, /* upnp */ - 'M-SEARCH' = 24, - NOTIFY = 25, - SUBSCRIBE = 26, - UNSUBSCRIBE = 27, + 'M-SEARCH': 24, + 'NOTIFY': 25, + 'SUBSCRIBE': 26, + 'UNSUBSCRIBE': 27, /* RFC-5789 */ - PATCH = 28, - PURGE = 29, + 'PATCH': 28, + 'PURGE': 29, /* CalDAV */ - MKCALENDAR = 30, + 'MKCALENDAR': 30, /* RFC-2068, section 19.6.1.2 */ - LINK = 31, - UNLINK = 32, + 'LINK': 31, + 'UNLINK': 32, /* icecast */ - SOURCE = 33, + 'SOURCE': 33, /* RFC-7540, section 11.6 */ - PRI = 34, + 'PRI': 34, /* RFC-2326 RTSP */ - DESCRIBE = 35, - ANNOUNCE = 36, - SETUP = 37, - PLAY = 38, - PAUSE = 39, - TEARDOWN = 40, - GET_PARAMETER = 41, - SET_PARAMETER = 42, - REDIRECT = 43, - RECORD = 44, + 'DESCRIBE': 35, + 'ANNOUNCE': 36, + 'SETUP': 37, + 'PLAY': 38, + 'PAUSE': 39, + 'TEARDOWN': 40, + 'GET_PARAMETER': 41, + 'SET_PARAMETER': 42, + 'REDIRECT': 43, + 'RECORD': 44, /* RAOP */ - FLUSH = 45, + 'FLUSH': 45, /* DRAFT https://www.ietf.org/archive/id/draft-ietf-httpbis-safe-method-w-body-02.html */ - QUERY = 46, -} + 'QUERY': 46, +}; + +export const STATUSES: IntDict = { + CONTINUE: 100, + SWITCHING_PROTOCOLS: 101, + PROCESSING: 102, + EARLY_HINTS: 103, + RESPONSE_IS_STALE: 110, // Unofficial + REVALIDATION_FAILED: 111, // Unofficial + DISCONNECTED_OPERATION: 112, // Unofficial + HEURISTIC_EXPIRATION: 113, // Unofficial + MISCELLANEOUS_WARNING: 199, // Unofficial + OK: 200, + CREATED: 201, + ACCEPTED: 202, + NON_AUTHORITATIVE_INFORMATION: 203, + NO_CONTENT: 204, + RESET_CONTENT: 205, + PARTIAL_CONTENT: 206, + MULTI_STATUS: 207, + ALREADY_REPORTED: 208, + TRANSFORMATION_APPLIED: 214, // Unofficial + IM_USED: 226, + MISCELLANEOUS_PERSISTENT_WARNING: 299, // Unofficial + MULTIPLE_CHOICES: 300, + MOVED_PERMANENTLY: 301, + FOUND: 302, + SEE_OTHER: 303, + NOT_MODIFIED: 304, + USE_PROXY: 305, + SWITCH_PROXY: 306, // No longer used + TEMPORARY_REDIRECT: 307, + PERMANENT_REDIRECT: 308, + BAD_REQUEST: 400, + UNAUTHORIZED: 401, + PAYMENT_REQUIRED: 402, + FORBIDDEN: 403, + NOT_FOUND: 404, + METHOD_NOT_ALLOWED: 405, + NOT_ACCEPTABLE: 406, + PROXY_AUTHENTICATION_REQUIRED: 407, + REQUEST_TIMEOUT: 408, + CONFLICT: 409, + GONE: 410, + LENGTH_REQUIRED: 411, + PRECONDITION_FAILED: 412, + PAYLOAD_TOO_LARGE: 413, + URI_TOO_LONG: 414, + UNSUPPORTED_MEDIA_TYPE: 415, + RANGE_NOT_SATISFIABLE: 416, + EXPECTATION_FAILED: 417, + IM_A_TEAPOT: 418, + PAGE_EXPIRED: 419, // Unofficial + ENHANCE_YOUR_CALM: 420, // Unofficial + MISDIRECTED_REQUEST: 421, + UNPROCESSABLE_ENTITY: 422, + LOCKED: 423, + FAILED_DEPENDENCY: 424, + TOO_EARLY: 425, + UPGRADE_REQUIRED: 426, + PRECONDITION_REQUIRED: 428, + TOO_MANY_REQUESTS: 429, + REQUEST_HEADER_FIELDS_TOO_LARGE_UNOFFICIAL: 430, // Unofficial + REQUEST_HEADER_FIELDS_TOO_LARGE: 431, + LOGIN_TIMEOUT: 440, // Unofficial + NO_RESPONSE: 444, // Unofficial + RETRY_WITH: 449, // Unofficial + BLOCKED_BY_PARENTAL_CONTROL: 450, // Unofficial + UNAVAILABLE_FOR_LEGAL_REASONS: 451, + CLIENT_CLOSED_LOAD_BALANCED_REQUEST: 460, // Unofficial + INVALID_X_FORWARDED_FOR: 463, // Unofficial + REQUEST_HEADER_TOO_LARGE: 494, // Unofficial + SSL_CERTIFICATE_ERROR: 495, // Unofficial + SSL_CERTIFICATE_REQUIRED: 496, // Unofficial + HTTP_REQUEST_SENT_TO_HTTPS_PORT: 497, // Unofficial + INVALID_TOKEN: 498, // Unofficial + CLIENT_CLOSED_REQUEST: 499, // Unofficial + INTERNAL_SERVER_ERROR: 500, + NOT_IMPLEMENTED: 501, + BAD_GATEWAY: 502, + SERVICE_UNAVAILABLE: 503, + GATEWAY_TIMEOUT: 504, + HTTP_VERSION_NOT_SUPPORTED: 505, + VARIANT_ALSO_NEGOTIATES: 506, + INSUFFICIENT_STORAGE: 507, + LOOP_DETECTED: 508, + BANDWIDTH_LIMIT_EXCEEDED: 509, + NOT_EXTENDED: 510, + NETWORK_AUTHENTICATION_REQUIRED: 511, + WEB_SERVER_UNKNOWN_ERROR: 520, // Unofficial + WEB_SERVER_IS_DOWN: 521, // Unofficial + CONNECTION_TIMEOUT: 522, // Unofficial + ORIGIN_IS_UNREACHABLE: 523, // Unofficial + TIMEOUT_OCCURED: 524, // Unofficial + SSL_HANDSHAKE_FAILED: 525, // Unofficial + INVALID_SSL_CERTIFICATE: 526, // Unofficial + RAILGUN_ERROR: 527, // Unofficial + SITE_IS_OVERLOADED: 529, // Unofficial + SITE_IS_FROZEN: 530, // Unofficial + IDENTITY_PROVIDER_AUTHENTICATION_ERROR: 561, // Unofficial + NETWORK_READ_TIMEOUT: 598, // Unofficial + NETWORK_CONNECT_TIMEOUT: 599, // Unofficial +}; + +export const FINISH: IntDict = { + SAFE: 0, + SAFE_WITH_CB: 1, + UNSAFE: 2, +}; +export const HEADER_STATE: IntDict = { + GENERAL: 0, + CONNECTION: 1, + CONTENT_LENGTH: 2, + TRANSFER_ENCODING: 3, + UPGRADE: 4, + CONNECTION_KEEP_ALIVE: 5, + CONNECTION_CLOSE: 6, + CONNECTION_UPGRADE: 7, + TRANSFER_ENCODING_CHUNKED: 8, +}; + +// C headers export const METHODS_HTTP = [ METHODS.DELETE, METHODS.GET, @@ -204,115 +327,10 @@ export const METHODS_RTSP = [ ]; export const METHOD_MAP = enumToMap(METHODS); -export const H_METHOD_MAP: IEnumMap = {}; - -for (const key of Object.keys(METHOD_MAP)) { - if (key[0] === 'H') { - H_METHOD_MAP[key] = METHOD_MAP[key as keyof typeof METHOD_MAP]; - } -} -export enum STATUSES { - CONTINUE = 100, - SWITCHING_PROTOCOLS = 101, - PROCESSING = 102, - EARLY_HINTS = 103, - RESPONSE_IS_STALE = 110, // Unofficial - REVALIDATION_FAILED = 111, // Unofficial - DISCONNECTED_OPERATION = 112, // Unofficial - HEURISTIC_EXPIRATION = 113, // Unofficial - MISCELLANEOUS_WARNING = 199, // Unofficial - OK = 200, - CREATED = 201, - ACCEPTED = 202, - NON_AUTHORITATIVE_INFORMATION = 203, - NO_CONTENT = 204, - RESET_CONTENT = 205, - PARTIAL_CONTENT = 206, - MULTI_STATUS = 207, - ALREADY_REPORTED = 208, - TRANSFORMATION_APPLIED = 214, // Unofficial - IM_USED = 226, - MISCELLANEOUS_PERSISTENT_WARNING = 299, // Unofficial - MULTIPLE_CHOICES = 300, - MOVED_PERMANENTLY = 301, - FOUND = 302, - SEE_OTHER = 303, - NOT_MODIFIED = 304, - USE_PROXY = 305, - SWITCH_PROXY = 306, // No longer used - TEMPORARY_REDIRECT = 307, - PERMANENT_REDIRECT = 308, - BAD_REQUEST = 400, - UNAUTHORIZED = 401, - PAYMENT_REQUIRED = 402, - FORBIDDEN = 403, - NOT_FOUND = 404, - METHOD_NOT_ALLOWED = 405, - NOT_ACCEPTABLE = 406, - PROXY_AUTHENTICATION_REQUIRED = 407, - REQUEST_TIMEOUT = 408, - CONFLICT = 409, - GONE = 410, - LENGTH_REQUIRED = 411, - PRECONDITION_FAILED = 412, - PAYLOAD_TOO_LARGE = 413, - URI_TOO_LONG = 414, - UNSUPPORTED_MEDIA_TYPE = 415, - RANGE_NOT_SATISFIABLE = 416, - EXPECTATION_FAILED = 417, - IM_A_TEAPOT = 418, - PAGE_EXPIRED = 419, // Unofficial - ENHANCE_YOUR_CALM = 420, // Unofficial - MISDIRECTED_REQUEST = 421, - UNPROCESSABLE_ENTITY = 422, - LOCKED = 423, - FAILED_DEPENDENCY = 424, - TOO_EARLY = 425, - UPGRADE_REQUIRED = 426, - PRECONDITION_REQUIRED = 428, - TOO_MANY_REQUESTS = 429, - REQUEST_HEADER_FIELDS_TOO_LARGE_UNOFFICIAL = 430, // Unofficial - REQUEST_HEADER_FIELDS_TOO_LARGE = 431, - LOGIN_TIMEOUT = 440, // Unofficial - NO_RESPONSE = 444, // Unofficial - RETRY_WITH = 449, // Unofficial - BLOCKED_BY_PARENTAL_CONTROL = 450, // Unofficial - UNAVAILABLE_FOR_LEGAL_REASONS = 451, - CLIENT_CLOSED_LOAD_BALANCED_REQUEST = 460, // Unofficial - INVALID_X_FORWARDED_FOR = 463, // Unofficial - REQUEST_HEADER_TOO_LARGE = 494, // Unofficial - SSL_CERTIFICATE_ERROR = 495, // Unofficial - SSL_CERTIFICATE_REQUIRED = 496, // Unofficial - HTTP_REQUEST_SENT_TO_HTTPS_PORT = 497, // Unofficial - INVALID_TOKEN = 498, // Unofficial - CLIENT_CLOSED_REQUEST = 499, // Unofficial - INTERNAL_SERVER_ERROR = 500, - NOT_IMPLEMENTED = 501, - BAD_GATEWAY = 502, - SERVICE_UNAVAILABLE = 503, - GATEWAY_TIMEOUT = 504, - HTTP_VERSION_NOT_SUPPORTED = 505, - VARIANT_ALSO_NEGOTIATES = 506, - INSUFFICIENT_STORAGE = 507, - LOOP_DETECTED = 508, - BANDWIDTH_LIMIT_EXCEEDED = 509, - NOT_EXTENDED = 510, - NETWORK_AUTHENTICATION_REQUIRED = 511, - WEB_SERVER_UNKNOWN_ERROR = 520, // Unofficial - WEB_SERVER_IS_DOWN = 521, // Unofficial - CONNECTION_TIMEOUT = 522, // Unofficial - ORIGIN_IS_UNREACHABLE = 523, // Unofficial - TIMEOUT_OCCURED = 524, // Unofficial - SSL_HANDSHAKE_FAILED = 525, // Unofficial - INVALID_SSL_CERTIFICATE = 526, // Unofficial - RAILGUN_ERROR = 527, // Unofficial - SITE_IS_OVERLOADED = 529, // Unofficial - SITE_IS_FROZEN = 530, // Unofficial - IDENTITY_PROVIDER_AUTHENTICATION_ERROR = 561, // Unofficial - NETWORK_READ_TIMEOUT = 598, // Unofficial - NETWORK_CONNECT_TIMEOUT = 599, // Unofficial -} +export const H_METHOD_MAP = Object.fromEntries( + Object.entries(METHODS).filter(([ k ]) => k.startsWith('H')) +); export const STATUSES_HTTP = [ STATUSES.CONTINUE, @@ -416,12 +434,6 @@ export const STATUSES_HTTP = [ STATUSES.NETWORK_CONNECT_TIMEOUT, ]; -export enum FINISH { - SAFE = 0, - SAFE_WITH_CB = 1, - UNSAFE = 2, -} - // Internal export type CharList = Array; @@ -521,19 +533,6 @@ for (let i = 0x80; i <= 0xff; i++) { export const MAJOR = NUM_MAP; export const MINOR = MAJOR; -export enum HEADER_STATE { - GENERAL = 0, - CONNECTION = 1, - CONTENT_LENGTH = 2, - TRANSFER_ENCODING = 3, - UPGRADE = 4, - - CONNECTION_KEEP_ALIVE = 5, - CONNECTION_CLOSE = 6, - CONNECTION_UPGRADE = 7, - TRANSFER_ENCODING_CHUNKED = 8, -} - export const SPECIAL_HEADERS = { 'connection': HEADER_STATE.CONNECTION, 'content-length': HEADER_STATE.CONTENT_LENGTH, diff --git a/src/llhttp/http.ts b/src/llhttp/http.ts index 46c002da..f80bf067 100644 --- a/src/llhttp/http.ts +++ b/src/llhttp/http.ts @@ -437,7 +437,7 @@ export class HTTP { this.update('http_minor', 9, onUrlCompleteHTTP09)), ); - const checkMethod = (methods: METHODS[], error: string): Node => { + const checkMethod = (methods: number[], error: string): Node => { const success = n('req_http_version'); const failure = p.error(ERROR.INVALID_CONSTANT, error); @@ -1169,17 +1169,17 @@ export class HTTP { return span.start(span.end(this.node(next))); } - private unsetFlag(flag: FLAGS, next: string | Node): Node { + private unsetFlag(flag: number, next: string | Node): Node { const p = this.llparse; return p.invoke(p.code.and('flags', ~flag), this.node(next)); } - private setFlag(flag: FLAGS, next: string | Node): Node { + private setFlag(flag: number, next: string | Node): Node { const p = this.llparse; return p.invoke(p.code.or('flags', flag), this.node(next)); } - private testFlags(flag: FLAGS, map: { [key: number]: Node }, + private testFlags(flag: number, map: { [key: number]: Node }, next?: string | Node): Node { const p = this.llparse; const res = p.invoke(p.code.test('flags', flag), map); @@ -1189,7 +1189,7 @@ export class HTTP { return res; } - private testLenientFlags(flag: LENIENT_FLAGS, map: { [key: number]: Node }, + private testLenientFlags(flag: number, map: { [key: number]: Node }, next?: string | Node): Node { const p = this.llparse; const res = p.invoke(p.code.test('lenient_flags', flag), map); @@ -1240,7 +1240,7 @@ export class HTTP { return res; } - private invokePausable(name: string, errorCode: ERROR, next: string | Node): Node { + private invokePausable(name: string, errorCode: number, next: string | Node): Node { let cb; switch (name) { diff --git a/src/llhttp/utils.ts b/src/llhttp/utils.ts index d9802374..22511255 100644 --- a/src/llhttp/utils.ts +++ b/src/llhttp/utils.ts @@ -1,34 +1,18 @@ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -type AnyObject = Record; +import { IntDict } from './constants'; -type NumericKeys = { - [K in keyof T]: T[K] extends number ? K : never -}[keyof T]; +export function enumToMap( + obj: IntDict, + filter: ReadonlyArray = [], + exceptions: ReadonlyArray = [], +): IntDict { + const emptyFilter = (filter?.length ?? 0) === 0; + const emptyExceptions = (exceptions?.length ?? 0) === 0; -export type IEnumMap = { - [K in NumericKeys]: T[K] -}; - -export function enumToMap( - obj: T, - filter?: ReadonlyArray, - exceptions?: ReadonlyArray, -): IEnumMap { - const res: Record = {}; - - for (const key of Object.keys(obj)) { - const value = obj[key]; - if (typeof value !== 'number') { - continue; - } - if (filter && !filter.includes(value)) { - continue; - } - if (exceptions && exceptions.includes(value)) { - continue; - } - res[key] = value; - } - - return res as IEnumMap; + return Object.fromEntries(Object.entries(obj).filter(([ , value ]) => { + return ( + typeof value === 'number' && + (emptyFilter || filter.includes(value)) && + (emptyExceptions || !exceptions.includes(value)) + ); + })); }