declapract-typescript-ehmpathy 0.42.3 → 0.42.5
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/dist/practices/artifact/best-practice/package.json +1 -1
- package/dist/practices/cicd-service/best-practice/package.json +1 -1
- package/dist/practices/config/best-practice/src/utils/config/getConfig.ts +4 -3
- package/dist/practices/environments/best-practice/package.json +7 -0
- package/dist/practices/environments/best-practice/package.json.declapract.ts +3 -0
- package/dist/practices/environments/best-practice/src/utils/environment.ts +105 -13
- package/dist/practices/git/best-practice/.gitignore.declapract.ts +1 -0
- package/dist/practices/lint/bad-practices/depcheck-denylisted-ignores/.declapract.readme.md +8 -0
- package/dist/practices/lint/bad-practices/depcheck-denylisted-ignores/.depcheckrc.yml.declapract.ts +59 -0
- package/dist/practices/lint/best-practice/.depcheckrc.yml +3 -7
- package/dist/practices/lint/best-practice/.depcheckrc.yml.declapract.ts +38 -1
- package/dist/practices/persist-with-rds/bad-practices/old-integration-test-db-dir/.declapract.readme.md +1 -1
- package/dist/practices/persist-with-rds/bad-practices/old-integration-test-db-dir/provision/docker/integration_test_db/<star><star>/<star>.declapract.ts +13 -1
- package/dist/practices/persist-with-rds/bad-practices/old-integration-test-db-hyphen-dir/.declapract.readme.md +1 -0
- package/dist/practices/persist-with-rds/bad-practices/old-integration-test-db-hyphen-dir/provision/docker/integration-test-db/<star><star>/<star>.declapract.ts +15 -0
- package/dist/practices/persist-with-rds/bad-practices/old-integration-test-db-paths/.declapract.readme.md +1 -0
- package/dist/practices/persist-with-rds/bad-practices/old-integration-test-db-paths/package.json +8 -0
- package/dist/practices/persist-with-rds/bad-practices/old-integration-test-db-paths/package.json.declapract.ts +10 -0
- package/dist/practices/persist-with-rds/best-practice/package.json +5 -5
- package/dist/practices/persist-with-rds/best-practice/provision/docker/{integration-test-db → testdb}/build-image.dockerfile +1 -1
- package/dist/practices/persist-with-rds/best-practice/provision/docker/{integration-test-db → testdb}/docker-compose.yml +5 -0
- package/dist/practices/persist-with-rds/best-practice/provision/schema/deploy.database.sh +1 -1
- package/dist/practices/persist-with-rds/best-practice/src/utils/database/getDatabaseConnection.ts +2 -1
- package/dist/practices/pnpm/best-practice/.agent/repo=.this/skills/use.npm.alias.sh +6 -5
- package/dist/practices/prettier/best-practice/.prettierignore +1 -0
- package/dist/practices/prettier/best-practice/prettier.config.js +1 -0
- package/dist/practices/provision-github/best-practice/package.json +1 -1
- package/dist/practices/tests/bad-practices/deprecated-test-deps/.declapract.readme.md +7 -0
- package/dist/practices/tests/bad-practices/deprecated-test-deps/package.json +9 -0
- package/dist/practices/tests/bad-practices/deprecated-test-deps/package.json.declapract.ts +39 -0
- package/dist/practices/tests/best-practice/jest.acceptance.config.ts +1 -3
- package/dist/practices/tests/best-practice/jest.acceptance.env.ts +1 -1
- package/dist/practices/tests/best-practice/jest.integration.config.ts +1 -3
- package/dist/practices/tests/best-practice/jest.integration.env.ts +3 -2
- package/dist/practices/tests/best-practice/jest.unit.config.ts +1 -3
- package/dist/practices/tests/best-practice/package.json +2 -5
- package/dist/practices/typescript/best-practice/package.json +1 -1
- package/dist/practices/typescript/best-practice/tsconfig.build.json +2 -1
- package/dist/practices/typescript/best-practice/tsconfig.json +1 -0
- package/package.json +3 -2
- /package/dist/practices/persist-with-rds/best-practice/provision/docker/{integration-test-db → testdb}/init/.gitignore +0 -0
- /package/dist/practices/persist-with-rds/best-practice/provision/docker/{integration-test-db → testdb}/init/readme.md +0 -0
- /package/dist/practices/persist-with-rds/best-practice/provision/docker/{integration-test-db → testdb}/wait-for-postgres.sh +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"devDependencies": {
|
|
3
|
-
"declastruct": "@declapract{check.minVersion('1.
|
|
3
|
+
"declastruct": "@declapract{check.minVersion('1.4.0')}",
|
|
4
4
|
"declastruct-aws": "@declapract{check.minVersion('1.0.3')}",
|
|
5
5
|
"declastruct-unix-network": "@declapract{check.minVersion('1.0.0')}"
|
|
6
6
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
// export a default instance of the config object
|
|
2
2
|
import ConfigCache from 'config-with-paramstore';
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import { Config } from './Config';
|
|
4
|
+
import { getEnvironment } from '../environment';
|
|
5
|
+
import { type Config } from './Config';
|
|
6
6
|
|
|
7
7
|
export const configInstance = new ConfigCache();
|
|
8
|
-
export const getConfig = async (): Promise<Config> =>
|
|
8
|
+
export const getConfig = async (): Promise<Config> =>
|
|
9
|
+
configInstance.get((await getEnvironment()).config);
|
|
@@ -1,8 +1,29 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
IAMClient,
|
|
3
|
+
ListAccountAliasesCommand,
|
|
4
|
+
type ListAccountAliasesCommandOutput,
|
|
5
|
+
} from '@aws-sdk/client-iam';
|
|
6
|
+
import { UnexpectedCodePathError } from 'helpful-errors';
|
|
7
|
+
import { createCache } from 'simple-in-memory-cache';
|
|
8
|
+
import { createIsOfEnum, type Literalize } from 'type-fns';
|
|
9
|
+
import { withSimpleCache } from 'with-simple-cache';
|
|
2
10
|
|
|
3
11
|
import { log } from './logger';
|
|
4
12
|
|
|
5
|
-
export enum
|
|
13
|
+
export enum ConfigChoice {
|
|
14
|
+
PRODUCTION = 'prod',
|
|
15
|
+
DEVELOPMENT = 'dev',
|
|
16
|
+
TEST = 'test',
|
|
17
|
+
}
|
|
18
|
+
export const isOfConfigChoice = createIsOfEnum(ConfigChoice);
|
|
19
|
+
|
|
20
|
+
export enum Access {
|
|
21
|
+
PRODUCTION = 'prod',
|
|
22
|
+
DEVELOPMENT = 'dev',
|
|
23
|
+
}
|
|
24
|
+
export const isOfAccess = createIsOfEnum(Access);
|
|
25
|
+
|
|
26
|
+
export enum Stage { // todo: deprecate stage
|
|
6
27
|
PRODUCTION = 'prod',
|
|
7
28
|
DEVELOPMENT = 'dev',
|
|
8
29
|
TEST = 'test',
|
|
@@ -19,7 +40,7 @@ export const isOfStage = createIsOfEnum(Stage);
|
|
|
19
40
|
*/
|
|
20
41
|
const TIMEZONE = process.env.TZ;
|
|
21
42
|
if (TIMEZONE !== 'UTC') {
|
|
22
|
-
log.
|
|
43
|
+
log.debug(
|
|
23
44
|
'env.TZ is not set to UTC. this can cause issues. updating this on your behalf',
|
|
24
45
|
{ found: TIMEZONE, desire: 'UTC' },
|
|
25
46
|
);
|
|
@@ -43,27 +64,98 @@ const inferStageFromNodeEnv = () => {
|
|
|
43
64
|
/**
|
|
44
65
|
* a method that exposes relevant environmental variables in a standard way
|
|
45
66
|
*/
|
|
46
|
-
const
|
|
67
|
+
export const getStage = (): Stage => {
|
|
47
68
|
const stage = process.env.STAGE ?? inferStageFromNodeEnv(); // figure it out from NODE_ENV if not explicitly defined
|
|
48
69
|
if (!stage) throw new Error('process.env.STAGE must be defined');
|
|
49
70
|
if (!isOfStage(stage)) throw new Error(`invalid stage defined '${stage}'`);
|
|
50
|
-
return
|
|
71
|
+
return stage;
|
|
51
72
|
};
|
|
52
73
|
|
|
53
|
-
|
|
54
|
-
|
|
74
|
+
/**
|
|
75
|
+
* .what = infer access (prod/dev) from curernt credentials
|
|
76
|
+
*
|
|
77
|
+
* .why?
|
|
78
|
+
* - allows detection of the access grain we are currently authenticated into, if authenticated
|
|
79
|
+
* - account aliases typically contain the environment (e.g., 'ahbode-dev', 'ahbode-prod')
|
|
80
|
+
*/
|
|
81
|
+
export const inferAccess = withSimpleCache(
|
|
82
|
+
async (): Promise<Access | null> => {
|
|
83
|
+
// skip aws api calls if no credentials are configured
|
|
84
|
+
if (!process.env.AWS_PROFILE && !process.env.AWS_ACCESS_KEY_ID) return null;
|
|
85
|
+
|
|
86
|
+
// grab the alias of the current account
|
|
87
|
+
const iam = new IAMClient({});
|
|
88
|
+
const response: ListAccountAliasesCommandOutput = await iam.send(
|
|
89
|
+
new ListAccountAliasesCommand({}),
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
// infer access from alias
|
|
93
|
+
const alias = response.AccountAliases?.[0];
|
|
94
|
+
if (alias?.includes('prod')) return Access.PRODUCTION;
|
|
95
|
+
if (alias?.includes('dev')) return Access.DEVELOPMENT;
|
|
96
|
+
throw new Error(`Could not infer access from account alias '${alias}'`);
|
|
97
|
+
},
|
|
98
|
+
{ cache: createCache() },
|
|
99
|
+
);
|
|
55
100
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
101
|
+
/**
|
|
102
|
+
* infer stage from access (prod/dev)
|
|
103
|
+
*
|
|
104
|
+
* logic:
|
|
105
|
+
* - if NODE_ENV === 'test', return test (test environment always uses test config)
|
|
106
|
+
* - otherwise, defer to access from AWS credentials
|
|
107
|
+
*/
|
|
108
|
+
const inferConfigChoice = async (): Promise<ConfigChoice> => {
|
|
109
|
+
// grab some facts
|
|
110
|
+
const access = await inferAccess();
|
|
111
|
+
const envarNode = process.env.NODE_ENV;
|
|
112
|
+
const envarConfig = process.env.CONFIG ?? process.env.STAGE; // fallback to stage as alias to config choice
|
|
113
|
+
|
|
114
|
+
// if access is against prod, then must use prod config; no exceptions
|
|
115
|
+
if (access === Access.PRODUCTION) return ConfigChoice.PRODUCTION;
|
|
116
|
+
|
|
117
|
+
// if access is against prep and asked for dev, then use dev config
|
|
118
|
+
if (access === Access.DEVELOPMENT && envarConfig === 'dev')
|
|
119
|
+
return ConfigChoice.DEVELOPMENT;
|
|
120
|
+
|
|
121
|
+
// if access is against prep and asked for test, then use test config
|
|
122
|
+
if (access === Access.DEVELOPMENT && envarNode === 'test')
|
|
123
|
+
return ConfigChoice.TEST;
|
|
124
|
+
|
|
125
|
+
// if access is against prep and not asked for test, then must use dev config
|
|
126
|
+
if (access === Access.DEVELOPMENT) return ConfigChoice.DEVELOPMENT;
|
|
127
|
+
|
|
128
|
+
// otherwise, unsupported
|
|
129
|
+
throw new UnexpectedCodePathError(
|
|
130
|
+
'Could not infer config choice: NODE_ENV is not test and no valid access could be determined',
|
|
131
|
+
{ access, envarNode, envarConfig },
|
|
132
|
+
);
|
|
133
|
+
};
|
|
59
134
|
|
|
60
135
|
// export the v3 environmental variables
|
|
61
|
-
export
|
|
62
|
-
|
|
136
|
+
export interface Environment {
|
|
137
|
+
/**
|
|
138
|
+
* .what = the choice of config to execute against
|
|
139
|
+
*/
|
|
140
|
+
config: Literalize<ConfigChoice>;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* .what = the resources accessible from this environment, if any
|
|
144
|
+
*/
|
|
145
|
+
access: Literalize<Access> | null;
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* .what = the server that hosts this environment
|
|
149
|
+
*/
|
|
150
|
+
server: 'CICD' | 'AWS:LAMBDA' | 'LOCAL';
|
|
151
|
+
}
|
|
152
|
+
export const getEnvironment = async (): Promise<Environment> => ({
|
|
153
|
+
config: await inferConfigChoice(),
|
|
154
|
+
access: await inferAccess(),
|
|
63
155
|
server: (() => {
|
|
64
156
|
if (process.env.CI) return 'CICD' as const;
|
|
65
157
|
if (process.env.LAMBDA_TASK_ROOT) return 'AWS:LAMBDA' as const;
|
|
66
158
|
return 'LOCAL' as const; // default to local
|
|
67
159
|
})(),
|
|
68
160
|
// region: // todo
|
|
69
|
-
};
|
|
161
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
These packages should not be ignored in depcheck - they are either deprecated or have better alternatives:
|
|
2
|
+
|
|
3
|
+
- date-fns: use luxon instead
|
|
4
|
+
- procedure-fns: deprecated
|
|
5
|
+
- ts-node: use tsx instead
|
|
6
|
+
- ts-jest: use @swc/jest instead
|
|
7
|
+
- core-js: no longer needed with modern node
|
|
8
|
+
- babel-jest: use @swc/jest instead
|
package/dist/practices/lint/bad-practices/depcheck-denylisted-ignores/.depcheckrc.yml.declapract.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { FileCheckFunction, FileFixFunction } from 'declapract';
|
|
2
|
+
import expect from 'expect';
|
|
3
|
+
import yaml from 'yaml';
|
|
4
|
+
|
|
5
|
+
const denylist = [
|
|
6
|
+
'date-fns',
|
|
7
|
+
'procedure-fns',
|
|
8
|
+
'ts-node',
|
|
9
|
+
'ts-jest',
|
|
10
|
+
'core-js',
|
|
11
|
+
'babel-jest',
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
export const check: FileCheckFunction = (contents) => {
|
|
15
|
+
if (!contents) throw new Error('no file found'); // no file = not bad practice
|
|
16
|
+
|
|
17
|
+
const parsed = yaml.parse(contents) as { ignores?: string[] };
|
|
18
|
+
const currentIgnores = parsed?.ignores ?? [];
|
|
19
|
+
|
|
20
|
+
// Find denylisted ignores that are present
|
|
21
|
+
const denylistedPresent = currentIgnores.filter((item) =>
|
|
22
|
+
denylist.includes(item),
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
// Bad practice: throw if no denylisted items found (all is fine), return if denylisted items exist
|
|
26
|
+
if (denylistedPresent.length === 0) {
|
|
27
|
+
throw new Error('no denylisted packages found in ignores');
|
|
28
|
+
}
|
|
29
|
+
// Return (don't throw) = bad practice detected
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const fix: FileFixFunction = (contents) => {
|
|
33
|
+
if (!contents) return { contents };
|
|
34
|
+
|
|
35
|
+
// Parse using parseDocument to preserve comments
|
|
36
|
+
const doc = yaml.parseDocument(contents);
|
|
37
|
+
const parsed = doc.toJSON() as { ignores?: string[] };
|
|
38
|
+
const currentIgnores = parsed?.ignores ?? [];
|
|
39
|
+
|
|
40
|
+
// Find denylisted ignores that are present
|
|
41
|
+
const denylistedPresent = currentIgnores.filter((item) =>
|
|
42
|
+
denylist.includes(item),
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
if (denylistedPresent.length === 0) return { contents };
|
|
46
|
+
|
|
47
|
+
// Remove denylisted ignores from the document
|
|
48
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
49
|
+
const ignoresNode = doc.get('ignores') as any;
|
|
50
|
+
if (ignoresNode?.items) {
|
|
51
|
+
// Filter out denylisted items
|
|
52
|
+
ignoresNode.items = ignoresNode.items.filter(
|
|
53
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
54
|
+
(item: any) => !denylist.includes(item.value ?? item),
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return { contents: doc.toString() };
|
|
59
|
+
};
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
ignores:
|
|
2
|
-
-
|
|
2
|
+
- rhachet
|
|
3
3
|
- declapract
|
|
4
4
|
- declapract-typescript-ehmpathy
|
|
5
5
|
- '@commitlint/config-conventional'
|
|
6
6
|
- '@trivago/prettier-plugin-sort-imports'
|
|
7
7
|
- '@tsconfig/node-lts-strictest'
|
|
8
|
-
- babel-jest
|
|
9
|
-
- core-js
|
|
10
|
-
- ts-jest
|
|
11
8
|
- tsx
|
|
12
9
|
- husky
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
- helpful-errors
|
|
10
|
+
- '@swc/core'
|
|
11
|
+
- '@swc/jest'
|
|
@@ -1,4 +1,41 @@
|
|
|
1
1
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
2
|
-
import { FileCheckType } from 'declapract';
|
|
2
|
+
import { FileCheckType, FileFixFunction } from 'declapract';
|
|
3
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
4
|
+
import yaml from 'yaml';
|
|
3
5
|
|
|
4
6
|
export const check = FileCheckType.CONTAINS;
|
|
7
|
+
|
|
8
|
+
export const fix: FileFixFunction = (contents, context) => {
|
|
9
|
+
if (!contents) return { contents: context.declaredFileContents };
|
|
10
|
+
|
|
11
|
+
const declaredContents = context.declaredFileContents ?? '';
|
|
12
|
+
|
|
13
|
+
// Parse both files as YAML (using parseDocument to preserve comments)
|
|
14
|
+
const currentDoc = yaml.parseDocument(contents);
|
|
15
|
+
const declaredParsed = yaml.parse(declaredContents) as { ignores?: string[] };
|
|
16
|
+
|
|
17
|
+
const currentIgnores =
|
|
18
|
+
(currentDoc.toJSON() as { ignores?: string[] })?.ignores ?? [];
|
|
19
|
+
const declaredIgnores = declaredParsed?.ignores ?? [];
|
|
20
|
+
|
|
21
|
+
// Find missing ignores
|
|
22
|
+
const missingIgnores = declaredIgnores.filter(
|
|
23
|
+
(item) => !currentIgnores.includes(item),
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
if (missingIgnores.length === 0) return { contents };
|
|
27
|
+
|
|
28
|
+
// Add missing ignores to the document (preserves comments)
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
|
+
let ignoresNode = currentDoc.get('ignores') as any;
|
|
31
|
+
if (!ignoresNode) {
|
|
32
|
+
currentDoc.set('ignores', []);
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
34
|
+
ignoresNode = currentDoc.get('ignores') as any;
|
|
35
|
+
}
|
|
36
|
+
for (const ignore of missingIgnores) {
|
|
37
|
+
ignoresNode.add(ignore);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return { contents: currentDoc.toString() };
|
|
41
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
we switched from `provision/docker/integration_test_db` to `provision/docker/
|
|
1
|
+
we switched from `provision/docker/integration_test_db` to `provision/docker/testdb`
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
-
import { FileCheckType } from 'declapract';
|
|
1
|
+
import { FileCheckType, FileFixFunction } from 'declapract';
|
|
2
2
|
|
|
3
3
|
export const check = FileCheckType.EXISTS; // if a file exists with this path pattern, then it's bad practice
|
|
4
|
+
|
|
5
|
+
export const fix: FileFixFunction = async (contents, { relativeFilePath }) => {
|
|
6
|
+
// Move from integration_test_db to testdb
|
|
7
|
+
const newPath = relativeFilePath.replace(
|
|
8
|
+
'provision/docker/integration_test_db',
|
|
9
|
+
'provision/docker/testdb',
|
|
10
|
+
);
|
|
11
|
+
return {
|
|
12
|
+
contents,
|
|
13
|
+
relativeFilePath: newPath,
|
|
14
|
+
};
|
|
15
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
we switched from `provision/docker/integration-test-db` to `provision/docker/testdb`
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { FileCheckType, FileFixFunction } from 'declapract';
|
|
2
|
+
|
|
3
|
+
export const check = FileCheckType.EXISTS; // if a file exists with this path pattern, then it's bad practice
|
|
4
|
+
|
|
5
|
+
export const fix: FileFixFunction = async (contents, { relativeFilePath }) => {
|
|
6
|
+
// Move from integration-test-db to testdb
|
|
7
|
+
const newPath = relativeFilePath.replace(
|
|
8
|
+
'provision/docker/integration-test-db',
|
|
9
|
+
'provision/docker/testdb',
|
|
10
|
+
);
|
|
11
|
+
return {
|
|
12
|
+
contents,
|
|
13
|
+
relativeFilePath: newPath,
|
|
14
|
+
};
|
|
15
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
we switched from `provision/docker/integration-test-db` to `provision/docker/testdb` - this detects old paths in package.json scripts
|
package/dist/practices/persist-with-rds/bad-practices/old-integration-test-db-paths/package.json
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
"scripts": {
|
|
3
|
+
"provision:testdb:docker:prepare": "@declapract{check.contains('integration-test-db')}",
|
|
4
|
+
"provision:testdb:docker:up": "@declapract{check.contains('integration-test-db')}",
|
|
5
|
+
"provision:testdb:docker:await": "@declapract{check.contains('integration-test-db')}",
|
|
6
|
+
"provision:testdb:docker:down": "@declapract{check.contains('integration-test-db')}"
|
|
7
|
+
}
|
|
8
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FileCheckType, FileFixFunction } from 'declapract';
|
|
2
|
+
|
|
3
|
+
export const check = FileCheckType.CONTAINS;
|
|
4
|
+
|
|
5
|
+
export const fix: FileFixFunction = (contents) => {
|
|
6
|
+
if (!contents) return { contents }; // do nothing if no contents
|
|
7
|
+
// Replace integration-test-db with testdb in all paths
|
|
8
|
+
const fixed = contents.replace(/integration-test-db/g, 'testdb');
|
|
9
|
+
return { contents: fixed };
|
|
10
|
+
};
|
|
@@ -18,11 +18,11 @@
|
|
|
18
18
|
"provision:schema:plan": "npx sql-schema-control plan -c provision/schema/control.yml",
|
|
19
19
|
"provision:schema:apply": "npx sql-schema-control apply -c provision/schema/control.yml",
|
|
20
20
|
"provision:schema:sync": "npx sql-schema-control sync -c provision/schema/control.yml",
|
|
21
|
-
"provision:testdb:docker:clear": "docker rm -f $(docker ps -a -f
|
|
22
|
-
"provision:testdb:docker:prepare": "cp provision/schema/sql/init/.extensions.sql provision/docker/
|
|
23
|
-
"provision:testdb:docker:up": "docker compose -f ./provision/docker/
|
|
24
|
-
"provision:testdb:docker:await": "docker compose -f ./provision/docker/
|
|
25
|
-
"provision:testdb:docker:down": "docker compose -f ./provision/docker/
|
|
21
|
+
"provision:testdb:docker:clear": "for port in $(docker compose -f ./provision/docker/testdb/docker-compose.yml config --format json | jq -r '.services[].ports[]?.published'); do docker rm -f $(docker ps -a -f \"publish=$port\" -q) 2>/dev/null || true; done && echo 'ensured ports are available 👍'",
|
|
22
|
+
"provision:testdb:docker:prepare": "cp provision/schema/sql/init/.extensions.sql provision/docker/testdb/init/extensions.sql && cp provision/schema/sql/init/.schema.sql provision/docker/testdb/init/schema.sql && cp provision/schema/sql/init/.user.cicd.sql provision/docker/testdb/init/user.cicd.sql",
|
|
23
|
+
"provision:testdb:docker:up": "docker compose -f ./provision/docker/testdb/docker-compose.yml up -d --force-recreate --build --renew-anon-volumes",
|
|
24
|
+
"provision:testdb:docker:await": "docker compose -f ./provision/docker/testdb/docker-compose.yml exec -T postgres /root/wait-for-postgres.sh",
|
|
25
|
+
"provision:testdb:docker:down": "docker compose -f ./provision/docker/testdb/docker-compose.yml down",
|
|
26
26
|
"provision:testdb": "npm run provision:testdb:docker:clear && npm run provision:testdb:docker:prepare && npm run provision:testdb:docker:up && npm run provision:testdb:docker:await && npm run provision:schema:plan && npm run provision:schema:apply && npm run provision:schema:plan",
|
|
27
27
|
"start:testdb": "npm run provision:testdb",
|
|
28
28
|
"start:livedb:dev": "echo 'will ping the database until assured its not asleep' && STAGE=dev .agent/repo=.this/skills/use.rds.capacity.sh"
|
|
@@ -11,3 +11,8 @@ services:
|
|
|
11
11
|
environment:
|
|
12
12
|
POSTGRES_PASSWORD: a-secure-password # default user is `postgres`
|
|
13
13
|
POSTGRES_DB: @declapract{variable.databaseName} # creates the database for us automatically
|
|
14
|
+
healthcheck:
|
|
15
|
+
test: ['CMD-SHELL', 'pg_isready -U postgres -d homeservicesdb']
|
|
16
|
+
interval: 5s
|
|
17
|
+
timeout: 5s
|
|
18
|
+
retries: 5
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
##
|
|
14
14
|
## usage example:
|
|
15
15
|
## ```sh
|
|
16
|
-
## ./provision/schema/deploy.database.sh dev $(op get
|
|
16
|
+
## ./provision/schema/deploy.database.sh dev $(op item get ahbodedb.dev.postgres --fields label=password --format json | jq -r .value)
|
|
17
17
|
## ```
|
|
18
18
|
#####################################################
|
|
19
19
|
|
package/dist/practices/persist-with-rds/best-practice/src/utils/database/getDatabaseConnection.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { HelpfulError, UnexpectedCodePathError } from 'helpful-errors';
|
|
|
2
2
|
import pg, { Client, QueryResult, QueryResultRow } from 'pg';
|
|
3
3
|
|
|
4
4
|
import { getConfig } from '../config/getConfig';
|
|
5
|
-
import {
|
|
5
|
+
import { getEnvironment } from '../environment';
|
|
6
6
|
|
|
7
7
|
// https://github.com/brianc/node-postgres/pull/353#issuecomment-283709264
|
|
8
8
|
pg.types.setTypeParser(20, (value) => parseInt(value, 10)); // cast bigints to numbers; by default, pg returns bigints as strings, since max val of bigint is bigger than max safe value in js
|
|
@@ -40,6 +40,7 @@ values:
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export const getDatabaseConnection = async (): Promise<DatabaseConnection> => {
|
|
43
|
+
const environment = await getEnvironment();
|
|
43
44
|
const config = await getConfig();
|
|
44
45
|
const target = config.database.target;
|
|
45
46
|
const role = config.database.role.crud;
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
# What it does:
|
|
8
8
|
# 1. Creates an alias 'npm.slow' pointing to the original npm binary
|
|
9
9
|
# 2. Creates an alias 'npm' that redirects to pnpm
|
|
10
|
-
# 3.
|
|
10
|
+
# 3. Sets up pnpm tab completion (works for both pnpm and npm alias)
|
|
11
|
+
# 4. Everything goes in ~/.bash_aliases (works in both bash and zsh)
|
|
11
12
|
#
|
|
12
13
|
# When to use:
|
|
13
14
|
# - After setting up a new development environment
|
|
@@ -19,15 +20,15 @@
|
|
|
19
20
|
set -euo pipefail
|
|
20
21
|
|
|
21
22
|
BASH_ALIASES="${HOME}/.bash_aliases"
|
|
22
|
-
|
|
23
|
-
# ensure ~/.bash_aliases exists
|
|
24
23
|
touch "$BASH_ALIASES"
|
|
25
24
|
|
|
26
25
|
# findsert npm.slow (only add if not already defined)
|
|
27
26
|
if ! grep -q "^alias npm.slow=" "$BASH_ALIASES" 2>/dev/null; then
|
|
28
27
|
NPM_PATH=$(which npm)
|
|
29
28
|
echo "alias npm.slow=\"$NPM_PATH\"" >> "$BASH_ALIASES"
|
|
30
|
-
echo "
|
|
29
|
+
echo "👍 findsert: alias npm.slow=\"$NPM_PATH\""
|
|
30
|
+
else
|
|
31
|
+
echo "👍 findsert: npm.slow alias already exists"
|
|
31
32
|
fi
|
|
32
33
|
|
|
33
34
|
# upsert npm => pnpm
|
|
@@ -36,7 +37,7 @@ if grep -q "^alias npm=" "$BASH_ALIASES" 2>/dev/null; then
|
|
|
36
37
|
else
|
|
37
38
|
echo 'alias npm="pnpm"' >> "$BASH_ALIASES"
|
|
38
39
|
fi
|
|
39
|
-
echo "
|
|
40
|
+
echo "👍 upsert: alias npm=\"pnpm\""
|
|
40
41
|
|
|
41
42
|
# report
|
|
42
43
|
echo ""
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
These test dependencies are deprecated and should be removed:
|
|
2
|
+
|
|
3
|
+
- babel-jest: use @swc/jest instead (faster)
|
|
4
|
+
- @babel/core: no longer needed with @swc/jest
|
|
5
|
+
- @babel/preset-env: no longer needed with @swc/jest
|
|
6
|
+
- core-js: no longer needed with modern node
|
|
7
|
+
- ts-jest: use @swc/jest instead (faster)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"devDependencies": {
|
|
3
|
+
"babel-jest": "@declapract{check.minVersion('0.0.0')}",
|
|
4
|
+
"@babel/core": "@declapract{check.minVersion('0.0.0')}",
|
|
5
|
+
"@babel/preset-env": "@declapract{check.minVersion('0.0.0')}",
|
|
6
|
+
"core-js": "@declapract{check.minVersion('0.0.0')}",
|
|
7
|
+
"ts-jest": "@declapract{check.minVersion('0.0.0')}"
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { FileCheckType, FileFixFunction } from 'declapract';
|
|
2
|
+
|
|
3
|
+
export const check = FileCheckType.CONTAINS;
|
|
4
|
+
|
|
5
|
+
const deprecatedDeps = [
|
|
6
|
+
'babel-jest',
|
|
7
|
+
'@babel/core',
|
|
8
|
+
'@babel/preset-env',
|
|
9
|
+
'core-js',
|
|
10
|
+
'ts-jest',
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
export const fix: FileFixFunction = (contents) => {
|
|
14
|
+
if (!contents) return { contents }; // do nothing if no contents
|
|
15
|
+
const packageJSON = JSON.parse(contents);
|
|
16
|
+
|
|
17
|
+
// Remove deprecated deps from devDependencies
|
|
18
|
+
const updatedDevDeps = { ...packageJSON.devDependencies };
|
|
19
|
+
for (const dep of deprecatedDeps) {
|
|
20
|
+
delete updatedDevDeps[dep];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Remove deprecated deps from dependencies (in case they're there)
|
|
24
|
+
const updatedDeps = { ...packageJSON.dependencies };
|
|
25
|
+
for (const dep of deprecatedDeps) {
|
|
26
|
+
delete updatedDeps[dep];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const updatedPackageJSON = {
|
|
30
|
+
...packageJSON,
|
|
31
|
+
dependencies: Object.keys(updatedDeps).length > 0 ? updatedDeps : undefined,
|
|
32
|
+
devDependencies:
|
|
33
|
+
Object.keys(updatedDevDeps).length > 0 ? updatedDevDeps : undefined,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
contents: JSON.stringify(updatedPackageJSON, null, 2),
|
|
38
|
+
};
|
|
39
|
+
};
|
|
@@ -12,15 +12,13 @@ const config: Config = {
|
|
|
12
12
|
testEnvironment: 'node',
|
|
13
13
|
moduleFileExtensions: ['js', 'ts'],
|
|
14
14
|
transform: {
|
|
15
|
-
'^.+\\.
|
|
16
|
-
'^.+\\.(js|jsx|mjs)$': 'babel-jest', // transform esm modules with babel
|
|
15
|
+
'^.+\\.(t|j)sx?$': '@swc/jest',
|
|
17
16
|
},
|
|
18
17
|
transformIgnorePatterns: [
|
|
19
18
|
// here's an example of how to ignore esm module transformation, when needed
|
|
20
19
|
// 'node_modules/(?!(@octokit|universal-user-agent|before-after-hook)/)',
|
|
21
20
|
],
|
|
22
21
|
testMatch: ['**/*.acceptance.test.ts'],
|
|
23
|
-
setupFiles: ['core-js'],
|
|
24
22
|
setupFilesAfterEnv: ['./jest.acceptance.env.ts'],
|
|
25
23
|
|
|
26
24
|
// use 50% of threads to leave headroom for other processes
|
|
@@ -21,7 +21,7 @@ if (!existsSync(join(process.cwd(), 'package.json')))
|
|
|
21
21
|
* - prevent time wasted waiting on tests to fail due to lack of credentials
|
|
22
22
|
* - prevent time wasted debugging tests which are failing due to hard-to-read missed credential errors
|
|
23
23
|
*/
|
|
24
|
-
const declapractUsePath = join(process.cwd(), 'declapract.use.
|
|
24
|
+
const declapractUsePath = join(process.cwd(), 'declapract.use.yml');
|
|
25
25
|
const requiresAwsAuth =
|
|
26
26
|
existsSync(declapractUsePath) &&
|
|
27
27
|
readFileSync(declapractUsePath, 'utf8').includes('awsAccountId');
|
|
@@ -12,15 +12,13 @@ const config: Config = {
|
|
|
12
12
|
testEnvironment: 'node',
|
|
13
13
|
moduleFileExtensions: ['js', 'ts'],
|
|
14
14
|
transform: {
|
|
15
|
-
'^.+\\.
|
|
16
|
-
'^.+\\.(js|jsx|mjs)$': 'babel-jest', // transform esm modules with babel
|
|
15
|
+
'^.+\\.(t|j)sx?$': '@swc/jest',
|
|
17
16
|
},
|
|
18
17
|
transformIgnorePatterns: [
|
|
19
18
|
// here's an example of how to ignore esm module transformation, when needed
|
|
20
19
|
// 'node_modules/(?!(@octokit|universal-user-agent|before-after-hook)/)',
|
|
21
20
|
],
|
|
22
21
|
testMatch: ['**/*.integration.test.ts'],
|
|
23
|
-
setupFiles: ['core-js'],
|
|
24
22
|
setupFilesAfterEnv: ['./jest.integration.env.ts'],
|
|
25
23
|
|
|
26
24
|
// use 50% of threads to leave headroom for other processes
|
|
@@ -23,7 +23,8 @@ if (!existsSync(join(process.cwd(), 'package.json')))
|
|
|
23
23
|
* - prevent executing financially impacting mutations
|
|
24
24
|
*/
|
|
25
25
|
if (
|
|
26
|
-
(process.env.NODE_ENV !== 'test' ||
|
|
26
|
+
(process.env.NODE_ENV !== 'test' ||
|
|
27
|
+
(process.env.STAGE && process.env.STAGE !== 'test')) &&
|
|
27
28
|
process.env.I_KNOW_WHAT_IM_DOING !== 'true'
|
|
28
29
|
)
|
|
29
30
|
throw new Error(`integration.test is not targeting stage 'test'`);
|
|
@@ -34,7 +35,7 @@ if (
|
|
|
34
35
|
* - prevent time wasted waiting on tests to fail due to lack of credentials
|
|
35
36
|
* - prevent time wasted debugging tests which are failing due to hard-to-read missed credential errors
|
|
36
37
|
*/
|
|
37
|
-
const declapractUsePath = join(process.cwd(), 'declapract.use.
|
|
38
|
+
const declapractUsePath = join(process.cwd(), 'declapract.use.yml');
|
|
38
39
|
const requiresAwsAuth =
|
|
39
40
|
existsSync(declapractUsePath) &&
|
|
40
41
|
readFileSync(declapractUsePath, 'utf8').includes('awsAccountId');
|
|
@@ -12,8 +12,7 @@ const config: Config = {
|
|
|
12
12
|
testEnvironment: 'node',
|
|
13
13
|
moduleFileExtensions: ['js', 'ts'],
|
|
14
14
|
transform: {
|
|
15
|
-
'^.+\\.
|
|
16
|
-
'^.+\\.(js|jsx|mjs)$': 'babel-jest', // transform esm modules with babel
|
|
15
|
+
'^.+\\.(t|j)sx?$': '@swc/jest',
|
|
17
16
|
},
|
|
18
17
|
transformIgnorePatterns: [
|
|
19
18
|
// here's an example of how to ignore esm module transformation, when needed
|
|
@@ -25,7 +24,6 @@ const config: Config = {
|
|
|
25
24
|
'!**/*.acceptance.test.ts',
|
|
26
25
|
'!**/*.integration.test.ts',
|
|
27
26
|
],
|
|
28
|
-
setupFiles: ['core-js'],
|
|
29
27
|
setupFilesAfterEnv: ['./jest.unit.env.ts'],
|
|
30
28
|
|
|
31
29
|
// use 50% of threads to leave headroom for other processes
|
|
@@ -3,12 +3,9 @@
|
|
|
3
3
|
"@types/jest": "@declapract{check.minVersion('29.2.4')}",
|
|
4
4
|
"jest": "@declapract{check.minVersion('29.3.1')}",
|
|
5
5
|
"test-fns": "@declapract{check.minVersion('1.4.2')}",
|
|
6
|
-
"ts-jest": "@declapract{check.minVersion('29.4.5')}",
|
|
7
6
|
"tsx": "@declapract{check.minVersion('4.20.6')}",
|
|
8
|
-
"core
|
|
9
|
-
"@
|
|
10
|
-
"@babel/preset-env": "@declapract{check.minVersion('7.28.5')}",
|
|
11
|
-
"babel-jest": "@declapract{check.minVersion('30.2.0')}"
|
|
7
|
+
"@swc/core": "@declapract{check.minVersion('1.15.3')}",
|
|
8
|
+
"@swc/jest": "@declapract{check.minVersion('0.2.39')}"
|
|
12
9
|
},
|
|
13
10
|
"scripts": {
|
|
14
11
|
"test:unit": "jest -c ./jest.unit.config.ts --forceExit --verbose --passWithNoTests $([ -z $THOROUGH ] && echo '--changedSince=main')",
|
|
@@ -7,6 +7,6 @@
|
|
|
7
7
|
"build:clean": "rm dist/ -rf",
|
|
8
8
|
"build:compile": "tsc -p ./tsconfig.build.json",
|
|
9
9
|
"build": "npm run build:clean && npm run build:compile && npm run build:artifact",
|
|
10
|
-
"test:types": "tsc -p ./tsconfig.
|
|
10
|
+
"test:types": "tsc -p ./tsconfig.json --noEmit"
|
|
11
11
|
}
|
|
12
12
|
}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "declapract-typescript-ehmpathy",
|
|
3
3
|
"author": "ehmpathy",
|
|
4
4
|
"description": "declapract best practices declarations for typescript",
|
|
5
|
-
"version": "0.42.
|
|
5
|
+
"version": "0.42.5",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "src/index.js",
|
|
8
8
|
"repository": "ehmpathy/declapract-typescript-ehmpathy",
|
|
@@ -46,7 +46,8 @@
|
|
|
46
46
|
"expect": "29.4.2",
|
|
47
47
|
"flat": "5.0.2",
|
|
48
48
|
"helpful-errors": "1.5.3",
|
|
49
|
-
"simple-log-methods": "0.5.0"
|
|
49
|
+
"simple-log-methods": "0.5.0",
|
|
50
|
+
"yaml": "1.10.2"
|
|
50
51
|
},
|
|
51
52
|
"peerDependencies": {
|
|
52
53
|
"declapract": ">=0.12.1"
|
|
File without changes
|
|
File without changes
|