@netlify/headers-parser 7.2.0 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/all.d.ts CHANGED
@@ -1,9 +1,11 @@
1
+ import type { Header, MinimalHeader } from './types.js';
2
+ export type { Header, MinimalHeader };
1
3
  export declare const parseAllHeaders: ({ headersFiles, netlifyConfigPath, configHeaders, minimal, }: {
2
- headersFiles?: never[] | undefined;
3
- netlifyConfigPath: any;
4
- configHeaders?: never[] | undefined;
5
- minimal?: boolean | undefined;
4
+ headersFiles: undefined | string[];
5
+ netlifyConfigPath?: undefined | string;
6
+ configHeaders: undefined | MinimalHeader[];
7
+ minimal: boolean;
6
8
  }) => Promise<{
7
- headers: import("./types.js").Header[];
9
+ headers: (MinimalHeader | Header)[];
8
10
  errors: Error[];
9
11
  }>;
package/lib/all.js CHANGED
@@ -5,7 +5,7 @@ import { normalizeHeaders } from './normalize.js';
5
5
  import { splitResults, concatResults } from './results.js';
6
6
  // Parse all headers from `netlify.toml` and `_headers` file, then normalize
7
7
  // and validate those.
8
- export const parseAllHeaders = async function ({ headersFiles = [], netlifyConfigPath, configHeaders = [], minimal = false, }) {
8
+ export const parseAllHeaders = async function ({ headersFiles = [], netlifyConfigPath, configHeaders = [], minimal, }) {
9
9
  const [{ headers: fileHeaders, errors: fileParseErrors }, { headers: parsedConfigHeaders, errors: configParseErrors },] = await Promise.all([getFileHeaders(headersFiles), getConfigHeaders(netlifyConfigPath)]);
10
10
  const { headers: normalizedFileHeaders, errors: fileNormalizeErrors } = normalizeHeaders(fileHeaders, minimal);
11
11
  const { headers: normalizedConfigParseHeaders, errors: configParseNormalizeErrors } = normalizeHeaders(parsedConfigHeaders, minimal);
@@ -1 +1 @@
1
- export function getForRegExp(forPath: any): RegExp;
1
+ export declare const getForRegExp: (forPath: string) => RegExp;
package/lib/index.d.ts CHANGED
@@ -1 +1 @@
1
- export { parseAllHeaders } from './all.js';
1
+ export { parseAllHeaders, type Header, type MinimalHeader } from './all.js';
@@ -1,4 +1,6 @@
1
- export declare const parseFileHeaders: (headersFile: string) => Promise<{
2
- headers: any;
3
- errors: any[];
4
- }>;
1
+ import type { MinimalHeader } from './types.js';
2
+ export interface ParseHeadersResult {
3
+ headers: MinimalHeader[];
4
+ errors: Error[];
5
+ }
6
+ export declare const parseFileHeaders: (headersFile: string) => Promise<ParseHeadersResult>;
@@ -1,4 +1,4 @@
1
- import { promises as fs } from 'fs';
1
+ import fs from 'fs/promises';
2
2
  import { pathExists } from 'path-exists';
3
3
  import { splitResults } from './results.js';
4
4
  // Parse `_headers` file to an array of objects following the same syntax as
@@ -18,7 +18,12 @@ const parseHeaders = async function (headersFile) {
18
18
  if (typeof text !== 'string') {
19
19
  return [text];
20
20
  }
21
- return text.split('\n').map(normalizeLine).filter(hasHeader).map(parseLine).filter(Boolean);
21
+ return text
22
+ .split('\n')
23
+ .map(normalizeLine)
24
+ .filter(hasHeader)
25
+ .map(parseLine)
26
+ .filter((line) => line != null);
22
27
  };
23
28
  const readHeadersFile = async function (headersFile) {
24
29
  try {
@@ -41,7 +46,7 @@ const parseLine = function ({ line, index }) {
41
46
  catch (error) {
42
47
  return new Error(`Could not parse header line ${index + 1}:
43
48
  ${line}
44
- ${error.message}`);
49
+ ${error instanceof Error ? error.message : error?.toString()}`);
45
50
  }
46
51
  };
47
52
  // Parse a single header line
@@ -53,7 +58,7 @@ const parseHeaderLine = function (line) {
53
58
  return;
54
59
  }
55
60
  const [rawName, ...rawValue] = line.split(HEADER_SEPARATOR);
56
- const name = rawName.trim();
61
+ const name = rawName?.trim() ?? '';
57
62
  if (name === '') {
58
63
  throw new Error(`Missing header name`);
59
64
  }
@@ -67,16 +72,18 @@ const isPathLine = function (line) {
67
72
  return line.startsWith('/');
68
73
  };
69
74
  const HEADER_SEPARATOR = ':';
70
- const reduceLine = function ({ headers, errors }, { path, name, value }) {
71
- if (path !== undefined) {
75
+ const reduceLine = function ({ headers, errors }, parsedHeader) {
76
+ if ('path' in parsedHeader) {
77
+ const { path } = parsedHeader;
72
78
  return { headers: [...headers, { for: path, values: {} }], errors };
73
79
  }
74
- if (headers.length === 0) {
80
+ const { name, value } = parsedHeader;
81
+ const previousHeaders = headers.slice(0, -1);
82
+ const currentHeader = headers[headers.length - 1];
83
+ if (headers.length === 0 || currentHeader == null) {
75
84
  const error = new Error(`Path should come before header "${name}"`);
76
85
  return { headers, errors: [...errors, error] };
77
86
  }
78
- const previousHeaders = headers.slice(0, -1);
79
- const currentHeader = headers[headers.length - 1];
80
87
  const { values } = currentHeader;
81
88
  const newValue = values[name] === undefined ? value : `${values[name]}, ${value}`;
82
89
  const newHeaders = [...previousHeaders, { ...currentHeader, values: { ...values, [name]: newValue } }];
package/lib/merge.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import type { Header } from './types.js';
1
+ import type { Header, MinimalHeader } from './types.js';
2
2
  export declare const mergeHeaders: ({ fileHeaders, configHeaders, }: {
3
- fileHeaders: (Error | Header)[];
4
- configHeaders: (Error | Header)[];
3
+ fileHeaders: MinimalHeader[] | Header[];
4
+ configHeaders: MinimalHeader[] | Header[];
5
5
  }) => {
6
- headers: Header[];
6
+ headers: (MinimalHeader | Header)[];
7
7
  errors: Error[];
8
8
  };
package/lib/merge.js CHANGED
@@ -28,13 +28,12 @@ export const mergeHeaders = function ({ fileHeaders, configHeaders, }) {
28
28
  const removeDuplicates = function (headers) {
29
29
  const uniqueHeaders = new Set();
30
30
  const result = [];
31
- for (let i = headers.length - 1; i >= 0; i--) {
32
- const h = headers[i];
33
- const key = generateHeaderKey(h);
31
+ for (const header of [...headers].reverse()) {
32
+ const key = generateHeaderKey(header);
34
33
  if (uniqueHeaders.has(key))
35
34
  continue;
36
35
  uniqueHeaders.add(key);
37
- result.push(h);
36
+ result.push(header);
38
37
  }
39
38
  return result.reverse();
40
39
  };
@@ -1,4 +1,5 @@
1
+ import type { MinimalHeader } from './types.js';
1
2
  export declare const parseConfigHeaders: (netlifyConfigPath: string) => Promise<{
2
- headers: any[];
3
+ headers: MinimalHeader[];
3
4
  errors: Error[];
4
5
  }>;
@@ -22,6 +22,7 @@ const parseConfig = async function (configPath) {
22
22
  if (!Array.isArray(headers)) {
23
23
  throw new TypeError(`"headers" must be an array`);
24
24
  }
25
+ // TODO(serhalp) Validate shape instead of assuming and asserting type
25
26
  return headers;
26
27
  }
27
28
  catch (error) {
@@ -1,8 +1,12 @@
1
- import type { Header } from './types.js';
2
- export declare const normalizeHeaders: (headers: any, minimal: boolean) => {
3
- headers: Header[];
1
+ import type { Header, MinimalHeader } from './types.js';
2
+ export interface MinimalNormalizedHeaders {
3
+ headers: MinimalHeader[];
4
4
  errors: Error[];
5
- } | {
6
- headers: TypeError[];
5
+ }
6
+ export interface NormalizedHeaders {
7
+ headers: Header[];
7
8
  errors: Error[];
8
- };
9
+ }
10
+ export declare function normalizeHeaders(headers: MinimalHeader[], minimal: true): MinimalNormalizedHeaders;
11
+ export declare function normalizeHeaders(headers: MinimalHeader[], minimal: false): NormalizedHeaders;
12
+ export declare function normalizeHeaders(headers: MinimalHeader[], minimal: boolean): MinimalNormalizedHeaders | NormalizedHeaders;
package/lib/normalize.js CHANGED
@@ -2,34 +2,34 @@ import isPlainObj from 'is-plain-obj';
2
2
  import mapObj from 'map-obj';
3
3
  import { getForRegExp } from './for_regexp.js';
4
4
  import { splitResults } from './results.js';
5
- // Validate and normalize an array of `headers` objects.
6
- // This step is performed after `headers` have been parsed from either
7
- // `netlify.toml` or `_headers`.
8
- export const normalizeHeaders = function (headers, minimal) {
5
+ export function normalizeHeaders(headers, minimal) {
9
6
  if (!Array.isArray(headers)) {
10
7
  const error = new TypeError(`Headers must be an array not: ${headers}`);
8
+ // This looks odd but it is correct: it takes an array of `T | Error` and returns `{values: T[]: errors: Error[]}`,
9
+ // thus when given a literal array of type `Error[]` it can't infer `T`, so we explicitly pass in `never` as `T`.
11
10
  return splitResults([error]);
12
11
  }
12
+ // TODO(serhalp) Workaround for poor TS type narrowing. Remove once on typescript@5.8.
13
13
  const results = headers
14
- .map((header, index) => parseHeader(header, index, minimal))
15
- .filter(Boolean);
14
+ .map((header, index) => (minimal ? parseHeader(header, index, true) : parseHeader(header, index, false)))
15
+ .filter((header) => header != null);
16
16
  return splitResults(results);
17
- };
18
- const parseHeader = function (header, index, minimal) {
17
+ }
18
+ function parseHeader(header, index, minimal) {
19
19
  if (!isPlainObj(header)) {
20
20
  return new TypeError(`Header must be an object not: ${header}`);
21
21
  }
22
22
  try {
23
- return parseHeaderObject(header, minimal);
23
+ // TODO(serhalp) Workaround for poor TS type narrowing. Remove once on typescript@5.8.
24
+ return minimal ? parseHeaderObject(header, true) : parseHeaderObject(header, false);
24
25
  }
25
26
  catch (error) {
26
27
  return new Error(`Could not parse header number ${index + 1}:
27
28
  ${JSON.stringify(header)}
28
- ${error.message}`);
29
+ ${error instanceof Error ? error.message : error?.toString()}`);
29
30
  }
30
- };
31
- // Parse a single `headers` object
32
- const parseHeaderObject = function ({ for: rawPath, values: rawValues }, minimal) {
31
+ }
32
+ function parseHeaderObject({ for: rawPath, values: rawValues }, minimal) {
33
33
  const forPath = normalizePath(rawPath);
34
34
  if (rawValues === undefined) {
35
35
  return;
@@ -42,11 +42,14 @@ const parseHeaderObject = function ({ for: rawPath, values: rawValues }, minimal
42
42
  for: forPath,
43
43
  values,
44
44
  };
45
- if (!minimal) {
46
- header.forRegExp = getForRegExp(forPath);
45
+ if (minimal) {
46
+ return header;
47
47
  }
48
- return header;
49
- };
48
+ return {
49
+ ...header,
50
+ forRegExp: getForRegExp(forPath),
51
+ };
52
+ }
50
53
  // Normalize and validate the `for` field
51
54
  const normalizePath = function (rawPath) {
52
55
  if (rawPath === undefined) {
package/lib/results.d.ts CHANGED
@@ -1,12 +1,12 @@
1
- import type { Header } from './types.js';
2
- export declare function splitResults<Type>(results: (Error | Type)[]): {
3
- headers: Type[];
1
+ import type { MinimalHeader } from './types.js';
2
+ export declare function splitResults<T>(results: (Error | T)[]): {
3
+ headers: T[];
4
4
  errors: Error[];
5
5
  };
6
6
  export declare const concatResults: (resultsArrays: {
7
- headers: Header[];
7
+ headers: MinimalHeader[];
8
8
  errors: Error[];
9
9
  }[]) => {
10
- headers: Header[];
10
+ headers: MinimalHeader[];
11
11
  errors: Error[];
12
12
  };
package/lib/types.d.ts CHANGED
@@ -1,7 +1,9 @@
1
- export type Header = {
1
+ export interface MinimalHeader {
2
2
  for: string;
3
- forRegExp?: RegExp;
4
3
  values: {
5
4
  [key: string]: string;
6
5
  };
7
- };
6
+ }
7
+ export interface Header extends MinimalHeader {
8
+ forRegExp: RegExp;
9
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/headers-parser",
3
- "version": "7.2.0",
3
+ "version": "8.0.0",
4
4
  "description": "Parses Netlify headers into a JavaScript object representation",
5
5
  "type": "module",
6
6
  "exports": "./lib/index.js",
@@ -47,5 +47,5 @@
47
47
  "url": "https://github.com/netlify/build/issues"
48
48
  },
49
49
  "homepage": "https://github.com/netlify/build#readme",
50
- "gitHead": "131a644bfde5205f730f3369b778d8914c7c0382"
50
+ "gitHead": "65206cf82369d2e0412c707c763590690cc1819a"
51
51
  }