@carecard/validate 3.1.16 → 3.1.18
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/.github/workflows/auto-draft-pr.yml +114 -0
- package/.github/workflows/ci.yml +15 -15
- package/.github/workflows/publish.yml +24 -24
- package/.prettierrc.js +11 -10
- package/eslint.config.mjs +8 -8
- package/index.d.ts +76 -30
- package/index.js +6 -4
- package/lib/validate.js +131 -131
- package/lib/validateProperties.js +218 -218
- package/lib/validateWhitelistProperties.js +285 -0
- package/package.json +41 -38
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
name: Auto Draft PR
|
|
2
|
+
|
|
3
|
+
# Creates a draft Pull Request automatically when a feature/fix/hotfix/etc.
|
|
4
|
+
# branch is pushed.
|
|
5
|
+
#
|
|
6
|
+
# Why not `workflow_run`?
|
|
7
|
+
# GitHub only dispatches `workflow_run` events for workflow files that
|
|
8
|
+
# exist on the repository's DEFAULT branch. Until this file is merged
|
|
9
|
+
# into the default branch, a `workflow_run`-based trigger silently does
|
|
10
|
+
# nothing. Triggering directly on `push` (with the same branch filters
|
|
11
|
+
# as CI) is more reliable and works from the branch itself.
|
|
12
|
+
#
|
|
13
|
+
# Routing rules:
|
|
14
|
+
# - If the branch name starts with "main-" (e.g. main-hotfix-x), open a
|
|
15
|
+
# draft PR targeting `main`.
|
|
16
|
+
# - For any other branch (except protected base branches), open a draft
|
|
17
|
+
# PR targeting `development`.
|
|
18
|
+
#
|
|
19
|
+
# Branch patterns mirror `.github/workflows/ci.yml` and support nested
|
|
20
|
+
# names such as `feature/foo/bar`, `fix/bug-1`, `hotfix/...`, etc.
|
|
21
|
+
|
|
22
|
+
on:
|
|
23
|
+
push:
|
|
24
|
+
branches:
|
|
25
|
+
- 'feature/**'
|
|
26
|
+
- 'releases/**'
|
|
27
|
+
- 'release*'
|
|
28
|
+
- 'hotfix/**'
|
|
29
|
+
- 'iss/**'
|
|
30
|
+
- 'fix/**'
|
|
31
|
+
- 'main-*'
|
|
32
|
+
- 'main-**'
|
|
33
|
+
paths-ignore:
|
|
34
|
+
- '**.md'
|
|
35
|
+
workflow_dispatch:
|
|
36
|
+
|
|
37
|
+
permissions:
|
|
38
|
+
contents: read
|
|
39
|
+
pull-requests: write
|
|
40
|
+
|
|
41
|
+
jobs:
|
|
42
|
+
open-draft-pr:
|
|
43
|
+
runs-on: ubuntu-latest
|
|
44
|
+
|
|
45
|
+
steps:
|
|
46
|
+
- name: Determine target base branch
|
|
47
|
+
id: target
|
|
48
|
+
env:
|
|
49
|
+
HEAD_BRANCH: ${{ github.ref_name }}
|
|
50
|
+
run: |
|
|
51
|
+
set -euo pipefail
|
|
52
|
+
echo "Head branch: $HEAD_BRANCH"
|
|
53
|
+
|
|
54
|
+
# Skip protected/base branches – we never open a PR from them to themselves.
|
|
55
|
+
case "$HEAD_BRANCH" in
|
|
56
|
+
main|master|development|develop)
|
|
57
|
+
echo "Branch '$HEAD_BRANCH' is a base branch – skipping PR creation."
|
|
58
|
+
echo "skip=true" >> "$GITHUB_OUTPUT"
|
|
59
|
+
exit 0
|
|
60
|
+
;;
|
|
61
|
+
esac
|
|
62
|
+
|
|
63
|
+
if [[ "$HEAD_BRANCH" == main-* ]]; then
|
|
64
|
+
BASE="main"
|
|
65
|
+
else
|
|
66
|
+
BASE="development"
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
echo "Target base branch: $BASE"
|
|
70
|
+
echo "base=$BASE" >> "$GITHUB_OUTPUT"
|
|
71
|
+
echo "head=$HEAD_BRANCH" >> "$GITHUB_OUTPUT"
|
|
72
|
+
echo "skip=false" >> "$GITHUB_OUTPUT"
|
|
73
|
+
|
|
74
|
+
- name: Checkout repository
|
|
75
|
+
if: steps.target.outputs.skip == 'false'
|
|
76
|
+
uses: actions/checkout@v4
|
|
77
|
+
with:
|
|
78
|
+
fetch-depth: 0
|
|
79
|
+
|
|
80
|
+
- name: Create draft Pull Request (if missing)
|
|
81
|
+
if: steps.target.outputs.skip == 'false'
|
|
82
|
+
env:
|
|
83
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
84
|
+
HEAD: ${{ steps.target.outputs.head }}
|
|
85
|
+
BASE: ${{ steps.target.outputs.base }}
|
|
86
|
+
REPO: ${{ github.repository }}
|
|
87
|
+
run: |
|
|
88
|
+
set -euo pipefail
|
|
89
|
+
|
|
90
|
+
# Avoid creating duplicates: check for an existing open PR for this head -> base.
|
|
91
|
+
# `gh pr list --head` expects the branch name (without owner prefix) for same-repo PRs.
|
|
92
|
+
EXISTING=$(gh pr list \
|
|
93
|
+
--repo "$REPO" \
|
|
94
|
+
--state open \
|
|
95
|
+
--head "$HEAD" \
|
|
96
|
+
--base "$BASE" \
|
|
97
|
+
--json number \
|
|
98
|
+
--jq '.[0].number' || true)
|
|
99
|
+
|
|
100
|
+
if [[ -n "${EXISTING:-}" ]]; then
|
|
101
|
+
echo "An open PR already exists for $HEAD -> $BASE (#$EXISTING). Nothing to do."
|
|
102
|
+
exit 0
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
TITLE="Draft: merge \`$HEAD\` into \`$BASE\`"
|
|
106
|
+
BODY=$'Auto-created draft PR for branch `'"$HEAD"$'`.\n\nTarget base: `'"$BASE"$'`\n\nMark this PR as ready for review when you want it to be reviewed/merged.'
|
|
107
|
+
|
|
108
|
+
gh pr create \
|
|
109
|
+
--repo "$REPO" \
|
|
110
|
+
--draft \
|
|
111
|
+
--base "$BASE" \
|
|
112
|
+
--head "$HEAD" \
|
|
113
|
+
--title "$TITLE" \
|
|
114
|
+
--body "$BODY"
|
package/.github/workflows/ci.yml
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
name: CI
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
6
|
|
|
7
7
|
jobs:
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
test:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
- name: Use Node.js
|
|
15
|
+
uses: actions/setup-node@v4
|
|
16
|
+
with:
|
|
17
|
+
node-version: '25'
|
|
18
|
+
cache: 'npm'
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
- name: Install dependencies
|
|
21
|
+
run: npm ci
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
- name: Run tests and coverage
|
|
24
|
+
run: npm run test:All
|
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
name: Publish to npm
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
7
|
|
|
8
8
|
permissions:
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
id-token: write
|
|
10
|
+
contents: read
|
|
11
11
|
|
|
12
12
|
jobs:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
publish:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- name: Checkout code
|
|
17
|
+
uses: actions/checkout@v4
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
- name: Setup Node.js
|
|
20
|
+
uses: actions/setup-node@v4
|
|
21
|
+
with:
|
|
22
|
+
node-version: '25'
|
|
23
|
+
registry-url: 'https://registry.npmjs.org'
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
- name: Install dependencies
|
|
26
|
+
# Added HUSKY=0 to prevent the husky error in logs
|
|
27
|
+
run: npm ci
|
|
28
|
+
env:
|
|
29
|
+
HUSKY: 0
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
- name: Publish to npm
|
|
32
|
+
run: npm publish --provenance --access public
|
|
33
|
+
env:
|
|
34
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/.prettierrc.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
module.exports = {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
arrowParens: 'avoid',
|
|
3
|
+
bracketSameLine: true,
|
|
4
|
+
bracketSpacing: true,
|
|
5
|
+
singleQuote: true,
|
|
6
|
+
trailingComma: 'all',
|
|
7
|
+
printWidth: 140,
|
|
8
|
+
tabWidth: 4,
|
|
9
|
+
useTabs: false,
|
|
10
|
+
endOfLine: 'auto',
|
|
11
|
+
importOrderSeparation: true,
|
|
12
|
+
importOrderSortSpecifiers: true,
|
|
12
13
|
};
|
package/eslint.config.mjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { defineConfig, globalIgnores } from 'eslint/config';
|
|
2
2
|
|
|
3
3
|
const eslintConfig = defineConfig([
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
4
|
+
globalIgnores([
|
|
5
|
+
// Default ignores of eslint-config-next:
|
|
6
|
+
'.next/**',
|
|
7
|
+
'out/**',
|
|
8
|
+
'build/**',
|
|
9
|
+
'next-env.d.ts',
|
|
10
|
+
'node_modules/**',
|
|
11
|
+
]),
|
|
12
12
|
]);
|
|
13
13
|
|
|
14
14
|
export default eslintConfig;
|
package/index.d.ts
CHANGED
|
@@ -3,6 +3,52 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export function validateProperties(obj?: Record<string, any>): Record<string, any>;
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Options for {@link validateWhitelistProperties}.
|
|
8
|
+
*/
|
|
9
|
+
export interface ValidateWhitelistPropertiesOptions {
|
|
10
|
+
/** Properties allowed in the input but not required. */
|
|
11
|
+
optionalProperties?: string[];
|
|
12
|
+
/** When true, the returned object's keys are converted to snake_case. */
|
|
13
|
+
convertToSnakeCase?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* When true, the returned object is flattened so that every validated leaf
|
|
16
|
+
* becomes a top-level key, joined by `.` (e.g. `{ 'user.first_name': 'Jane' }`).
|
|
17
|
+
* No nested objects remain in the output. Applied after snake_case conversion.
|
|
18
|
+
*/
|
|
19
|
+
flattenOutput?: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Validates and transforms whitelisted properties from an input object.
|
|
24
|
+
*
|
|
25
|
+
* - Supports nested objects via dot-notation paths (e.g. `"address.city"`),
|
|
26
|
+
* up to 5 levels deep. The function checks that each path resolves to an
|
|
27
|
+
* existing leaf property and validates the leaf value by its leaf segment.
|
|
28
|
+
* - Extracts only the whitelisted (required + optional) leaf properties and
|
|
29
|
+
* rebuilds the same nested shape in the result.
|
|
30
|
+
* - Validates values via {@link validateProperties}.
|
|
31
|
+
* - Throws a "Bad_Input" error when any required property is missing/invalid,
|
|
32
|
+
* when a provided optional property has an invalid value, when a path
|
|
33
|
+
* exceeds 5 levels of nesting, or when the combined count of
|
|
34
|
+
* `requiredProperties` and `options.optionalProperties` exceeds 5000.
|
|
35
|
+
* - Array values are supported: if a leaf value is an array, the per-leaf
|
|
36
|
+
* validator is applied to each element. The leaf is accepted only when every
|
|
37
|
+
* element passes validation, and the returned value is an array of the
|
|
38
|
+
* validated elements (e.g. `{ name: ["First", "Other"] }` is validated like
|
|
39
|
+
* `{ name: "First" }` and `{ name: "Other" }` individually).
|
|
40
|
+
* - Optionally converts the resulting keys (including nested keys) to snake_case.
|
|
41
|
+
*
|
|
42
|
+
* @param inputObject The input object (e.g. `req.body` or `req.params`).
|
|
43
|
+
* @param requiredProperties Leaf paths that must be present and valid. Dot-notation supported.
|
|
44
|
+
* @param options Optional list of additional allowed leaf paths and case-conversion flag.
|
|
45
|
+
*/
|
|
46
|
+
export function validateWhitelistProperties(
|
|
47
|
+
inputObject: Record<string, any>,
|
|
48
|
+
requiredProperties?: string[],
|
|
49
|
+
options?: ValidateWhitelistPropertiesOptions,
|
|
50
|
+
): Promise<Record<string, any>>;
|
|
51
|
+
|
|
6
52
|
/** Checks if the string is a valid image URL format. */
|
|
7
53
|
export function isImageUrl(imageUrl: any): boolean;
|
|
8
54
|
/** Checks if the value is an integer. */
|
|
@@ -70,34 +116,34 @@ export function isValidArrayOfStrings(arr: any): boolean;
|
|
|
70
116
|
* @deprecated Use direct imports instead.
|
|
71
117
|
*/
|
|
72
118
|
export const validate: {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
119
|
+
isImageUrl: typeof isImageUrl;
|
|
120
|
+
isInteger: typeof isInteger;
|
|
121
|
+
isValidJsonString: typeof isValidJsonString;
|
|
122
|
+
isValidIntegerString: typeof isValidIntegerString;
|
|
123
|
+
isValidUuidString: typeof isValidUuidString;
|
|
124
|
+
isCharactersString: typeof isCharactersString;
|
|
125
|
+
isNameString: typeof isNameString;
|
|
126
|
+
isSafeSearchString: typeof isSafeSearchString;
|
|
127
|
+
isEmailString: typeof isEmailString;
|
|
128
|
+
isJwtString: typeof isJwtString;
|
|
129
|
+
isPasswordString: typeof isPasswordString;
|
|
130
|
+
isSimplePasswordString: typeof isSimplePasswordString;
|
|
131
|
+
isPasswordStringFailureMessage: typeof isPasswordStringFailureMessage;
|
|
132
|
+
isSimplePasswordStringFailureMessage: typeof isSimplePasswordStringFailureMessage;
|
|
133
|
+
isUsernameString: typeof isUsernameString;
|
|
134
|
+
isPhoneNumber: typeof isPhoneNumber;
|
|
135
|
+
isUrlSafeString: typeof isUrlSafeString;
|
|
136
|
+
isString6To24CharacterLong: typeof isString6To24CharacterLong;
|
|
137
|
+
isString6To16CharacterLong: typeof isString6To16CharacterLong;
|
|
138
|
+
isProvinceString: typeof isProvinceString;
|
|
139
|
+
isBoolValue: typeof isBoolValue;
|
|
140
|
+
isPostalCodeString: typeof isPostalCodeString;
|
|
141
|
+
isSafeString: typeof isSafeString;
|
|
142
|
+
isInStringArray: typeof isInStringArray;
|
|
143
|
+
isCountryCodeString: typeof isCountryCodeString;
|
|
144
|
+
isValidDomainName: typeof isValidDomainName;
|
|
145
|
+
isValidTimestampzString: typeof isValidTimestampzString;
|
|
146
|
+
isValidTimestampString: typeof isValidTimestampString;
|
|
147
|
+
isValidUrl: typeof isValidUrl;
|
|
148
|
+
isValidArrayOfStrings: typeof isValidArrayOfStrings;
|
|
103
149
|
};
|
package/index.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
const validate = require('./lib/validate');
|
|
2
2
|
const validateProperties = require('./lib/validateProperties');
|
|
3
|
+
const validateWhitelistProperties = require('./lib/validateWhitelistProperties');
|
|
3
4
|
|
|
4
5
|
module.exports = {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
validate,
|
|
7
|
+
validateProperties,
|
|
8
|
+
validateWhitelistProperties,
|
|
9
|
+
...validate,
|
|
10
|
+
...validateProperties,
|
|
9
11
|
};
|