ddd-ts-kit 0.1.0 → 0.1.1
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/README.md +43 -3
- package/dist/affected/changed-paths.d.ts +8 -0
- package/dist/affected/changed-paths.d.ts.map +1 -0
- package/dist/affected/changed-paths.js +21 -0
- package/dist/affected/changed-paths.js.map +1 -0
- package/dist/affected/downstreams-of.d.ts +4 -0
- package/dist/affected/downstreams-of.d.ts.map +1 -0
- package/dist/affected/downstreams-of.js +16 -0
- package/dist/affected/downstreams-of.js.map +1 -0
- package/dist/affected/everything.d.ts +5 -0
- package/dist/affected/everything.d.ts.map +1 -0
- package/dist/affected/everything.js +5 -0
- package/dist/affected/everything.js.map +1 -0
- package/dist/affected/format-selection.d.ts +10 -0
- package/dist/affected/format-selection.d.ts.map +1 -0
- package/dist/affected/format-selection.js +45 -0
- package/dist/affected/format-selection.js.map +1 -0
- package/dist/affected/path-reach.d.ts +12 -0
- package/dist/affected/path-reach.d.ts.map +1 -0
- package/dist/affected/path-reach.js +2 -0
- package/dist/affected/path-reach.js.map +1 -0
- package/dist/affected/reach-of.d.ts +10 -0
- package/dist/affected/reach-of.d.ts.map +1 -0
- package/dist/affected/reach-of.js +30 -0
- package/dist/affected/reach-of.js.map +1 -0
- package/dist/affected/select-affected.d.ts +11 -0
- package/dist/affected/select-affected.d.ts.map +1 -0
- package/dist/affected/select-affected.js +39 -0
- package/dist/affected/select-affected.js.map +1 -0
- package/dist/affected/selection.d.ts +14 -0
- package/dist/affected/selection.d.ts.map +1 -0
- package/dist/affected/selection.js +2 -0
- package/dist/affected/selection.js.map +1 -0
- package/dist/commands/affected.d.ts +8 -0
- package/dist/commands/affected.d.ts.map +1 -0
- package/dist/commands/affected.js +38 -0
- package/dist/commands/affected.js.map +1 -0
- package/dist/commands/docs.d.ts.map +1 -1
- package/dist/commands/docs.js +2 -0
- package/dist/commands/docs.js.map +1 -1
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/generate.js +5 -0
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +6 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +1 -1
- package/dist/config/index.js.map +1 -1
- package/dist/config/parse-stack.d.ts.map +1 -1
- package/dist/config/parse-stack.js +2 -1
- package/dist/config/parse-stack.js.map +1 -1
- package/dist/config/serialize-config.js +2 -2
- package/dist/config/serialize-config.js.map +1 -1
- package/dist/config/stack.d.ts +7 -0
- package/dist/config/stack.d.ts.map +1 -1
- package/dist/config/stack.js +1 -0
- package/dist/config/stack.js.map +1 -1
- package/dist/depcruise/cruise-configuration.js +3 -1
- package/dist/depcruise/cruise-configuration.js.map +1 -1
- package/dist/generate/apply-wiring.js +1 -1
- package/dist/generate/apply-wiring.js.map +1 -1
- package/dist/generate/kinds/adapter-kind.d.ts.map +1 -1
- package/dist/generate/kinds/adapter-kind.js +5 -2
- package/dist/generate/kinds/adapter-kind.js.map +1 -1
- package/dist/generate/kinds/declare-context-entries.d.ts +10 -0
- package/dist/generate/kinds/declare-context-entries.d.ts.map +1 -0
- package/dist/generate/kinds/declare-context-entries.js +31 -0
- package/dist/generate/kinds/declare-context-entries.js.map +1 -0
- package/dist/generate/kinds/generate-context.d.ts.map +1 -1
- package/dist/generate/kinds/generate-context.js +2 -0
- package/dist/generate/kinds/generate-context.js.map +1 -1
- package/dist/generate/kinds/import-assembler.d.ts +9 -0
- package/dist/generate/kinds/import-assembler.d.ts.map +1 -0
- package/dist/generate/kinds/import-assembler.js +29 -0
- package/dist/generate/kinds/import-assembler.js.map +1 -0
- package/dist/generate/kinds/write-context-files.d.ts.map +1 -1
- package/dist/generate/kinds/write-context-files.js +10 -2
- package/dist/generate/kinds/write-context-files.js.map +1 -1
- package/dist/generate/kinds/write-own-policy.d.ts +9 -0
- package/dist/generate/kinds/write-own-policy.d.ts.map +1 -0
- package/dist/generate/kinds/write-own-policy.js +13 -0
- package/dist/generate/kinds/write-own-policy.js.map +1 -0
- package/dist/generate/shared-writes.d.ts.map +1 -1
- package/dist/generate/shared-writes.js +6 -0
- package/dist/generate/shared-writes.js.map +1 -1
- package/dist/generate/stop-ignoring-validation.d.ts +9 -0
- package/dist/generate/stop-ignoring-validation.d.ts.map +1 -0
- package/dist/generate/stop-ignoring-validation.js +36 -0
- package/dist/generate/stop-ignoring-validation.js.map +1 -0
- package/dist/init/files/architecture-files.d.ts +9 -0
- package/dist/init/files/architecture-files.d.ts.map +1 -0
- package/dist/init/files/architecture-files.js +10 -0
- package/dist/init/files/architecture-files.js.map +1 -0
- package/dist/init/files/init-files.d.ts.map +1 -1
- package/dist/init/files/init-files.js +2 -0
- package/dist/init/files/init-files.js.map +1 -1
- package/dist/init/files/persistence-files.d.ts.map +1 -1
- package/dist/init/files/persistence-files.js +5 -1
- package/dist/init/files/persistence-files.js.map +1 -1
- package/dist/init/files/pipeline-files.d.ts.map +1 -1
- package/dist/init/files/pipeline-files.js +5 -1
- package/dist/init/files/pipeline-files.js.map +1 -1
- package/dist/init/files/platform-files.d.ts.map +1 -1
- package/dist/init/files/platform-files.js +3 -1
- package/dist/init/files/platform-files.js.map +1 -1
- package/dist/init/files/project-files.d.ts.map +1 -1
- package/dist/init/files/project-files.js +3 -1
- package/dist/init/files/project-files.js.map +1 -1
- package/dist/init/knip-vars.d.ts +3 -3
- package/dist/init/knip-vars.d.ts.map +1 -1
- package/dist/init/knip-vars.js +27 -5
- package/dist/init/knip-vars.js.map +1 -1
- package/dist/init/manifest/documentation-scripts.d.ts.map +1 -1
- package/dist/init/manifest/documentation-scripts.js +2 -0
- package/dist/init/manifest/documentation-scripts.js.map +1 -1
- package/dist/init/manifest/scripts-for.d.ts +5 -1
- package/dist/init/manifest/scripts-for.d.ts.map +1 -1
- package/dist/init/manifest/scripts-for.js +10 -1
- package/dist/init/manifest/scripts-for.js.map +1 -1
- package/dist/init/manifest/versions.js +23 -23
- package/dist/init/manifest/write-manifest.d.ts.map +1 -1
- package/dist/init/manifest/write-manifest.js +18 -1
- package/dist/init/manifest/write-manifest.js.map +1 -1
- package/dist/init/run-init.d.ts.map +1 -1
- package/dist/init/run-init.js +24 -4
- package/dist/init/run-init.js.map +1 -1
- package/dist/init/stack/resolve-stack.d.ts.map +1 -1
- package/dist/init/stack/resolve-stack.js +3 -1
- package/dist/init/stack/resolve-stack.js.map +1 -1
- package/dist/init/stack/stack-options.d.ts +1 -0
- package/dist/init/stack/stack-options.d.ts.map +1 -1
- package/dist/init/template-vars.d.ts.map +1 -1
- package/dist/init/template-vars.js +2 -0
- package/dist/init/template-vars.js.map +1 -1
- package/dist/init/validation-dependencies.d.ts +10 -0
- package/dist/init/validation-dependencies.d.ts.map +1 -0
- package/dist/init/validation-dependencies.js +23 -0
- package/dist/init/validation-dependencies.js.map +1 -0
- package/dist/init/write-contracts.d.ts +10 -0
- package/dist/init/write-contracts.d.ts.map +1 -0
- package/dist/init/write-contracts.js +33 -0
- package/dist/init/write-contracts.js.map +1 -0
- package/dist/package-manager/default-package-manager.d.ts +8 -0
- package/dist/package-manager/default-package-manager.d.ts.map +1 -0
- package/dist/package-manager/default-package-manager.js +7 -0
- package/dist/package-manager/default-package-manager.js.map +1 -0
- package/dist/package-manager/dialect.d.ts +3 -0
- package/dist/package-manager/dialect.d.ts.map +1 -0
- package/dist/package-manager/dialect.js +2 -0
- package/dist/package-manager/dialect.js.map +1 -0
- package/dist/package-manager/dialects.d.ts +5 -0
- package/dist/package-manager/dialects.d.ts.map +1 -0
- package/dist/package-manager/dialects.js +21 -0
- package/dist/package-manager/dialects.js.map +1 -0
- package/dist/package-manager/in-dialect.d.ts +8 -0
- package/dist/package-manager/in-dialect.d.ts.map +1 -0
- package/dist/package-manager/in-dialect.js +10 -0
- package/dist/package-manager/in-dialect.js.map +1 -0
- package/dist/package-manager/lockfiles.d.ts +4 -0
- package/dist/package-manager/lockfiles.d.ts.map +1 -0
- package/dist/package-manager/lockfiles.js +6 -0
- package/dist/package-manager/lockfiles.js.map +1 -0
- package/dist/package-manager/package-manager-of.d.ts +4 -0
- package/dist/package-manager/package-manager-of.d.ts.map +1 -0
- package/dist/package-manager/package-manager-of.js +15 -0
- package/dist/package-manager/package-manager-of.js.map +1 -0
- package/dist/package-manager/package-manager-vars.d.ts +5 -0
- package/dist/package-manager/package-manager-vars.d.ts.map +1 -0
- package/dist/package-manager/package-manager-vars.js +13 -0
- package/dist/package-manager/package-manager-vars.js.map +1 -0
- package/dist/package-manager/pinned-package-managers.d.ts +7 -0
- package/dist/package-manager/pinned-package-managers.d.ts.map +1 -0
- package/dist/package-manager/pinned-package-managers.js +9 -0
- package/dist/package-manager/pinned-package-managers.js.map +1 -0
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +8 -2
- package/dist/run.js.map +1 -1
- package/dist/templating/render.d.ts.map +1 -1
- package/dist/templating/render.js +2 -1
- package/dist/templating/render.js.map +1 -1
- package/dist/templating/rendering.js +1 -1
- package/dist/templating/rendering.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/workspace/workspace.d.ts +5 -1
- package/dist/workspace/workspace.d.ts.map +1 -1
- package/dist/workspace/workspace.js +13 -3
- package/dist/workspace/workspace.js.map +1 -1
- package/package.json +2 -2
- package/templates/architecture/extractable.declared.spec.ts.tpl +6 -6
- package/templates/architecture/extractable.manual.spec.ts.tpl +4 -0
- package/templates/architecture/extractable.tsyringe.spec.ts.tpl +6 -0
- package/templates/docs/asyncapi.json.tpl +12 -0
- package/templates/docs/event-catalog.md +3 -0
- package/templates/docs/openapi.json.tpl +354 -0
- package/templates/init/README.md.tpl +1 -0
- package/templates/init/docker/Dockerfile.tpl +9 -2
- package/templates/init/jest.config.js.tpl +3 -1
- package/templates/init/platform/compose-application.tsyringe.ts.tpl +0 -6
- package/templates/init/platform/database/journal.drizzle.json +5 -0
- package/templates/init/pnpm-workspace.yaml +8 -0
- package/templates/init/rules/infrastructure.md.tpl +2 -2
- package/templates/init/scripts/events.ts.tpl +1 -1
- package/templates/init/scripts/openapi.ts.tpl +1 -1
- package/templates/pipeline/biome.json.tpl +2 -1
- package/templates/pipeline/github/actions/setup/action.yml.tpl +37 -0
- package/templates/pipeline/github/scripts/start-postgres.sh +47 -0
- package/templates/pipeline/github/workflows/ci.yml +68 -110
- package/templates/pipeline/github/workflows/pr-title.yml +1 -5
- package/templates/pipeline/gitlab/{gitlab-ci.yml → gitlab-ci.yml.tpl} +59 -31
- package/templates/pipeline/knip.json.tpl +9 -10
- package/templates/pipeline/package-scripts.json +1 -1
- package/templates/pipeline/vitest.config.ts.tpl +7 -3
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: Setup
|
|
2
|
+
description: Node, then the dependencies of the lockfile, restored from the cache when a run already installed them.
|
|
3
|
+
|
|
4
|
+
inputs:
|
|
5
|
+
node-version:
|
|
6
|
+
description: The Node.js release line the pipeline runs on.
|
|
7
|
+
default: '24'
|
|
8
|
+
|
|
9
|
+
runs:
|
|
10
|
+
using: composite
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/setup-node@v7
|
|
13
|
+
with:
|
|
14
|
+
node-version: ${{ inputs.node-version }}
|
|
15
|
+
{{#if pm.corepack}}
|
|
16
|
+
- name: The package manager package.json pins
|
|
17
|
+
shell: bash
|
|
18
|
+
run: corepack enable
|
|
19
|
+
{{/if}}
|
|
20
|
+
# One install per lockfile, shared by every job and every run. The key holds the lockfile and
|
|
21
|
+
# package.json: a hit is what a fresh install of that lockfile gives, and a manifest that left
|
|
22
|
+
# its lockfile behind is installed again, which refuses it.
|
|
23
|
+
- name: Dependencies, as a run already installed them for this lockfile
|
|
24
|
+
id: modules
|
|
25
|
+
uses: actions/cache@v6
|
|
26
|
+
with:
|
|
27
|
+
path: node_modules
|
|
28
|
+
key: modules-${{ runner.os }}-${{ runner.arch }}-node${{ inputs.node-version }}-${{ hashFiles('package-lock.json', 'package.json') }}
|
|
29
|
+
- name: Install (no run installed this lockfile yet, or the cache was evicted)
|
|
30
|
+
if: steps.modules.outputs.cache-hit != 'true'
|
|
31
|
+
shell: bash
|
|
32
|
+
run: npm ci
|
|
33
|
+
{{#if orm.prisma}}
|
|
34
|
+
- name: The Prisma client and the schema of the tests, build products of prisma/schema.prisma
|
|
35
|
+
shell: bash
|
|
36
|
+
run: npm run db:client
|
|
37
|
+
{{/if}}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Starts the PostgreSQL the specs run against and waits until it accepts connections.
|
|
3
|
+
# A `services:` container is pulled once, before the job, and one refusal of a registry fails
|
|
4
|
+
# the run (a public mirror answered "toomanyrequests" once): here the image is pulled with
|
|
5
|
+
# retries, from the next registry when one refuses.
|
|
6
|
+
set -eu
|
|
7
|
+
|
|
8
|
+
IMAGE="${POSTGRES_IMAGE:-postgres:18}"
|
|
9
|
+
REGISTRIES="${POSTGRES_REGISTRIES:-mirror.gcr.io/library public.ecr.aws/docker/library docker.io/library}"
|
|
10
|
+
|
|
11
|
+
pulled=""
|
|
12
|
+
|
|
13
|
+
for attempt in 1 2 3; do
|
|
14
|
+
for registry in $REGISTRIES; do
|
|
15
|
+
if docker pull --quiet "$registry/$IMAGE"; then
|
|
16
|
+
pulled="$registry/$IMAGE"
|
|
17
|
+
break 2
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
echo "Pulling $registry/$IMAGE failed (attempt $attempt)."
|
|
21
|
+
done
|
|
22
|
+
|
|
23
|
+
sleep $((attempt * 5))
|
|
24
|
+
done
|
|
25
|
+
|
|
26
|
+
if [ -z "$pulled" ]; then
|
|
27
|
+
echo "No registry served $IMAGE." >&2
|
|
28
|
+
exit 1
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
docker run --detach --name postgres --publish 5432:5432 \
|
|
32
|
+
--env POSTGRES_USER=app --env POSTGRES_PASSWORD=app --env POSTGRES_DB=app \
|
|
33
|
+
--health-cmd "pg_isready -U app -d app" --health-interval 2s --health-timeout 3s --health-retries 30 \
|
|
34
|
+
"$pulled" > /dev/null
|
|
35
|
+
|
|
36
|
+
for second in $(seq 1 60); do
|
|
37
|
+
if [ "$(docker inspect --format '{{.State.Health.Status}}' postgres)" = "healthy" ]; then
|
|
38
|
+
echo "PostgreSQL is ready ($pulled, ${second}s)."
|
|
39
|
+
exit 0
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
sleep 1
|
|
43
|
+
done
|
|
44
|
+
|
|
45
|
+
docker logs postgres >&2
|
|
46
|
+
echo "PostgreSQL did not become healthy." >&2
|
|
47
|
+
exit 1
|
|
@@ -4,29 +4,39 @@ on:
|
|
|
4
4
|
push:
|
|
5
5
|
branches: [main]
|
|
6
6
|
pull_request:
|
|
7
|
+
schedule:
|
|
8
|
+
# Every night, everything: a pull request runs the specs of the contexts its change reaches.
|
|
9
|
+
- cron: '0 3 * * *'
|
|
7
10
|
|
|
8
11
|
concurrency:
|
|
9
12
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
10
|
-
|
|
13
|
+
# A newer commit of a pull request supersedes the run in progress; the default branch finishes every run.
|
|
14
|
+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
|
11
15
|
|
|
12
16
|
permissions:
|
|
13
17
|
contents: read
|
|
14
18
|
|
|
15
|
-
env:
|
|
16
|
-
NODE_VERSION: 24
|
|
17
|
-
|
|
18
19
|
jobs:
|
|
19
20
|
install:
|
|
20
21
|
name: Install
|
|
21
22
|
runs-on: ubuntu-latest
|
|
22
23
|
timeout-minutes: 10
|
|
24
|
+
outputs:
|
|
25
|
+
scope: ${{ steps.affected.outputs.scope }}
|
|
26
|
+
contexts: ${{ steps.affected.outputs.contexts }}
|
|
27
|
+
args: ${{ steps.affected.outputs.args }}
|
|
28
|
+
lint: ${{ steps.affected.outputs.lint }}
|
|
23
29
|
steps:
|
|
24
30
|
- uses: actions/checkout@v7
|
|
25
|
-
- uses: actions/setup-node@v7
|
|
26
31
|
with:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
-
|
|
32
|
+
# A pull request is checked out as its merge commit, whose first parent is the base it is compared with.
|
|
33
|
+
fetch-depth: 2
|
|
34
|
+
- uses: ./.github/actions/setup
|
|
35
|
+
- name: What this run covers (everything on the default branch and at night, the affected contexts on a pull request)
|
|
36
|
+
id: affected
|
|
37
|
+
env:
|
|
38
|
+
BASE: ${{ github.event_name == 'pull_request' && 'HEAD^1' || '' }}
|
|
39
|
+
run: npx --no -- ddd-ts-kit affected --base "$BASE" --format github | tee -a "$GITHUB_OUTPUT"
|
|
30
40
|
|
|
31
41
|
typecheck:
|
|
32
42
|
name: Typecheck
|
|
@@ -35,11 +45,7 @@ jobs:
|
|
|
35
45
|
timeout-minutes: 10
|
|
36
46
|
steps:
|
|
37
47
|
- uses: actions/checkout@v7
|
|
38
|
-
- uses: actions/setup
|
|
39
|
-
with:
|
|
40
|
-
node-version: ${{ env.NODE_VERSION }}
|
|
41
|
-
cache: npm
|
|
42
|
-
- run: npm ci
|
|
48
|
+
- uses: ./.github/actions/setup
|
|
43
49
|
- run: npm run ci:typecheck
|
|
44
50
|
|
|
45
51
|
lint:
|
|
@@ -49,13 +55,12 @@ jobs:
|
|
|
49
55
|
timeout-minutes: 10
|
|
50
56
|
steps:
|
|
51
57
|
- uses: actions/checkout@v7
|
|
52
|
-
- uses: actions/setup
|
|
53
|
-
with:
|
|
54
|
-
node-version: ${{ env.NODE_VERSION }}
|
|
55
|
-
cache: npm
|
|
56
|
-
- run: npm ci
|
|
58
|
+
- uses: ./.github/actions/setup
|
|
57
59
|
- run: npm run ci:format
|
|
58
|
-
-
|
|
60
|
+
- name: Lint (the contexts a pull request does not reach are left to the default branch)
|
|
61
|
+
env:
|
|
62
|
+
LINT: ${{ needs.install.outputs.lint }}
|
|
63
|
+
run: npm run ci:lint -- $LINT
|
|
59
64
|
|
|
60
65
|
architecture:
|
|
61
66
|
name: Architecture
|
|
@@ -64,11 +69,7 @@ jobs:
|
|
|
64
69
|
timeout-minutes: 10
|
|
65
70
|
steps:
|
|
66
71
|
- uses: actions/checkout@v7
|
|
67
|
-
- uses: actions/setup
|
|
68
|
-
with:
|
|
69
|
-
node-version: ${{ env.NODE_VERSION }}
|
|
70
|
-
cache: npm
|
|
71
|
-
- run: npm ci
|
|
72
|
+
- uses: ./.github/actions/setup
|
|
72
73
|
- name: Architecture rules
|
|
73
74
|
run: npm run ci:arch:check -- --format github
|
|
74
75
|
- name: Dependency graph
|
|
@@ -81,26 +82,23 @@ jobs:
|
|
|
81
82
|
timeout-minutes: 10
|
|
82
83
|
steps:
|
|
83
84
|
- uses: actions/checkout@v7
|
|
84
|
-
- uses: actions/setup
|
|
85
|
-
with:
|
|
86
|
-
node-version: ${{ env.NODE_VERSION }}
|
|
87
|
-
cache: npm
|
|
88
|
-
- run: npm ci
|
|
85
|
+
- uses: ./.github/actions/setup
|
|
89
86
|
- run: npm run ci:deadcode
|
|
90
87
|
|
|
91
88
|
unit:
|
|
92
89
|
name: Unit tests
|
|
93
|
-
needs:
|
|
90
|
+
needs: install
|
|
94
91
|
runs-on: ubuntu-latest
|
|
95
92
|
timeout-minutes: 15
|
|
96
93
|
steps:
|
|
97
94
|
- uses: actions/checkout@v7
|
|
98
|
-
- uses: actions/setup
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
95
|
+
- uses: ./.github/actions/setup
|
|
96
|
+
- name: Unit specs, each context held to its coverage thresholds
|
|
97
|
+
if: ${{ needs.install.outputs.scope != 'none' }}
|
|
98
|
+
env:
|
|
99
|
+
DDD_TS_KIT_AFFECTED: ${{ needs.install.outputs.contexts }}
|
|
100
|
+
PARTIAL: ${{ needs.install.outputs.args }}
|
|
101
|
+
run: npm run ci:test:unit -- $PARTIAL
|
|
104
102
|
- uses: actions/upload-artifact@v7
|
|
105
103
|
if: ${{ !cancelled() }}
|
|
106
104
|
with:
|
|
@@ -111,79 +109,57 @@ jobs:
|
|
|
111
109
|
|
|
112
110
|
integration:
|
|
113
111
|
name: Integration tests
|
|
114
|
-
needs:
|
|
112
|
+
needs: install
|
|
115
113
|
runs-on: ubuntu-latest
|
|
116
114
|
timeout-minutes: 20
|
|
117
115
|
env:
|
|
118
116
|
DATABASE_URL: postgres://app:app@localhost:5432/app
|
|
119
|
-
services:
|
|
120
|
-
postgres:
|
|
121
|
-
image: public.ecr.aws/docker/library/postgres:18
|
|
122
|
-
env:
|
|
123
|
-
POSTGRES_USER: app
|
|
124
|
-
POSTGRES_PASSWORD: app
|
|
125
|
-
POSTGRES_DB: app
|
|
126
|
-
ports:
|
|
127
|
-
- 5432:5432
|
|
128
|
-
options: >-
|
|
129
|
-
--health-cmd "pg_isready -U app -d app"
|
|
130
|
-
--health-interval 2s
|
|
131
|
-
--health-timeout 3s
|
|
132
|
-
--health-retries 30
|
|
133
117
|
steps:
|
|
134
118
|
- uses: actions/checkout@v7
|
|
135
|
-
- uses: actions/setup
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
-
|
|
140
|
-
|
|
141
|
-
-
|
|
119
|
+
- uses: ./.github/actions/setup
|
|
120
|
+
- name: PostgreSQL
|
|
121
|
+
if: ${{ needs.install.outputs.scope != 'none' }}
|
|
122
|
+
run: sh .github/scripts/start-postgres.sh
|
|
123
|
+
- if: ${{ needs.install.outputs.scope != 'none' }}
|
|
124
|
+
run: npm run db:migrate
|
|
125
|
+
- name: Integration specs, each context held to its coverage thresholds
|
|
126
|
+
if: ${{ needs.install.outputs.scope != 'none' }}
|
|
127
|
+
env:
|
|
128
|
+
DDD_TS_KIT_AFFECTED: ${{ needs.install.outputs.contexts }}
|
|
129
|
+
PARTIAL: ${{ needs.install.outputs.args }}
|
|
130
|
+
run: npm run ci:test:integration -- $PARTIAL
|
|
142
131
|
|
|
143
132
|
e2e:
|
|
144
133
|
name: End-to-end tests
|
|
145
|
-
needs:
|
|
134
|
+
needs: install
|
|
146
135
|
runs-on: ubuntu-latest
|
|
147
136
|
timeout-minutes: 20
|
|
148
137
|
env:
|
|
149
138
|
DATABASE_URL: postgres://app:app@localhost:5432/app
|
|
150
|
-
services:
|
|
151
|
-
postgres:
|
|
152
|
-
image: public.ecr.aws/docker/library/postgres:18
|
|
153
|
-
env:
|
|
154
|
-
POSTGRES_USER: app
|
|
155
|
-
POSTGRES_PASSWORD: app
|
|
156
|
-
POSTGRES_DB: app
|
|
157
|
-
ports:
|
|
158
|
-
- 5432:5432
|
|
159
|
-
options: >-
|
|
160
|
-
--health-cmd "pg_isready -U app -d app"
|
|
161
|
-
--health-interval 2s
|
|
162
|
-
--health-timeout 3s
|
|
163
|
-
--health-retries 30
|
|
164
139
|
steps:
|
|
165
140
|
- uses: actions/checkout@v7
|
|
166
|
-
- uses: actions/setup
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
-
|
|
171
|
-
|
|
172
|
-
-
|
|
141
|
+
- uses: ./.github/actions/setup
|
|
142
|
+
- name: PostgreSQL
|
|
143
|
+
if: ${{ needs.install.outputs.scope != 'none' }}
|
|
144
|
+
run: sh .github/scripts/start-postgres.sh
|
|
145
|
+
- if: ${{ needs.install.outputs.scope != 'none' }}
|
|
146
|
+
run: npm run db:migrate
|
|
147
|
+
- name: End-to-end specs (the whole application, whatever the contexts a change reaches)
|
|
148
|
+
if: ${{ needs.install.outputs.scope != 'none' }}
|
|
149
|
+
run: npm run ci:test:e2e
|
|
173
150
|
|
|
174
|
-
|
|
175
|
-
name:
|
|
176
|
-
needs:
|
|
151
|
+
build:
|
|
152
|
+
name: Build, docs and contract drift
|
|
153
|
+
needs: install
|
|
177
154
|
runs-on: ubuntu-latest
|
|
178
155
|
timeout-minutes: 10
|
|
179
156
|
steps:
|
|
180
157
|
- uses: actions/checkout@v7
|
|
181
|
-
- uses: actions/setup
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
- run: npm run ci:docs
|
|
158
|
+
- uses: ./.github/actions/setup
|
|
159
|
+
- name: The production build
|
|
160
|
+
run: npm run ci:build
|
|
161
|
+
- name: Generated documents and contracts, from that build
|
|
162
|
+
run: npm run ci:docs
|
|
187
163
|
|
|
188
164
|
security:
|
|
189
165
|
name: Security
|
|
@@ -194,11 +170,7 @@ jobs:
|
|
|
194
170
|
- uses: actions/checkout@v7
|
|
195
171
|
with:
|
|
196
172
|
fetch-depth: 0
|
|
197
|
-
- uses: actions/setup
|
|
198
|
-
with:
|
|
199
|
-
node-version: ${{ env.NODE_VERSION }}
|
|
200
|
-
cache: npm
|
|
201
|
-
- run: npm ci
|
|
173
|
+
- uses: ./.github/actions/setup
|
|
202
174
|
- name: Production dependencies audit
|
|
203
175
|
run: npm run ci:audit
|
|
204
176
|
- name: Dependency review
|
|
@@ -210,23 +182,9 @@ jobs:
|
|
|
210
182
|
if: ${{ !cancelled() }}
|
|
211
183
|
run: docker run --rm --volume "$GITHUB_WORKSPACE:/repo" ghcr.io/gitleaks/gitleaks:v8.30.1 git /repo --redact --no-banner
|
|
212
184
|
|
|
213
|
-
build:
|
|
214
|
-
name: Build
|
|
215
|
-
needs: e2e
|
|
216
|
-
runs-on: ubuntu-latest
|
|
217
|
-
timeout-minutes: 10
|
|
218
|
-
steps:
|
|
219
|
-
- uses: actions/checkout@v7
|
|
220
|
-
- uses: actions/setup-node@v7
|
|
221
|
-
with:
|
|
222
|
-
node-version: ${{ env.NODE_VERSION }}
|
|
223
|
-
cache: npm
|
|
224
|
-
- run: npm ci
|
|
225
|
-
- run: npm run ci:build
|
|
226
|
-
|
|
227
185
|
image:
|
|
228
186
|
name: Docker image
|
|
229
|
-
needs:
|
|
187
|
+
needs: install
|
|
230
188
|
runs-on: ubuntu-latest
|
|
231
189
|
timeout-minutes: 20
|
|
232
190
|
steps:
|
|
@@ -243,7 +201,7 @@ jobs:
|
|
|
243
201
|
gate:
|
|
244
202
|
name: gate
|
|
245
203
|
if: ${{ always() }}
|
|
246
|
-
needs: [install, typecheck, lint, architecture, deadcode, unit, integration, e2e,
|
|
204
|
+
needs: [install, typecheck, lint, architecture, deadcode, unit, integration, e2e, build, security, image]
|
|
247
205
|
runs-on: ubuntu-latest
|
|
248
206
|
timeout-minutes: 5
|
|
249
207
|
steps:
|
|
@@ -18,11 +18,7 @@ jobs:
|
|
|
18
18
|
timeout-minutes: 5
|
|
19
19
|
steps:
|
|
20
20
|
- uses: actions/checkout@v7
|
|
21
|
-
- uses: actions/setup
|
|
22
|
-
with:
|
|
23
|
-
node-version: 24
|
|
24
|
-
cache: npm
|
|
25
|
-
- run: npm ci
|
|
21
|
+
- uses: ./.github/actions/setup
|
|
26
22
|
- name: The title is a conventional commit subject
|
|
27
23
|
env:
|
|
28
24
|
TITLE: ${{ github.event.pull_request.title }}
|
|
@@ -4,6 +4,8 @@ workflow:
|
|
|
4
4
|
rules:
|
|
5
5
|
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
6
6
|
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
|
7
|
+
# A pipeline schedule (Build > Pipeline schedules, every night on the default branch) runs everything.
|
|
8
|
+
- if: $CI_PIPELINE_SOURCE == "schedule"
|
|
7
9
|
|
|
8
10
|
include:
|
|
9
11
|
- template: Jobs/SAST.gitlab-ci.yml
|
|
@@ -14,32 +16,47 @@ include:
|
|
|
14
16
|
|
|
15
17
|
stages:
|
|
16
18
|
- install
|
|
17
|
-
- static
|
|
18
19
|
- test
|
|
19
|
-
- verify
|
|
20
20
|
- security
|
|
21
|
-
- package
|
|
22
21
|
- gate
|
|
23
22
|
|
|
24
23
|
variables:
|
|
25
24
|
AST_ENABLE_MR_PIPELINES: 'true'
|
|
26
25
|
NODE_IMAGE: node:24-bookworm-slim
|
|
26
|
+
# Behind the dependency proxy of a group, a registry that rate-limits is never asked twice:
|
|
27
|
+
# POSTGRES_IMAGE: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/postgres:18
|
|
27
28
|
POSTGRES_IMAGE: postgres:18
|
|
28
29
|
|
|
29
30
|
default:
|
|
31
|
+
# A newer commit of a merge request supersedes the pipeline in progress; the default branch finishes every pipeline.
|
|
30
32
|
interruptible: true
|
|
31
|
-
|
|
33
|
+
# An image that could not be pulled (a registry that rate-limits once) or a runner that failed is tried again; a failing script is not.
|
|
34
|
+
retry:
|
|
35
|
+
max: 2
|
|
36
|
+
when: [runner_system_failure, stuck_or_timeout_failure, scheduler_failure]
|
|
37
|
+
|
|
38
|
+
# One install per lockfile, shared by every job and every pipeline. The key holds the lockfile
|
|
39
|
+
# and package.json: a hit is what a fresh install of that lockfile gives. A job that finds no
|
|
40
|
+
# cache installs.
|
|
32
41
|
.node:
|
|
33
42
|
image: $NODE_IMAGE
|
|
34
43
|
cache:
|
|
35
44
|
key:
|
|
36
45
|
files:
|
|
37
46
|
- package-lock.json
|
|
47
|
+
- package.json
|
|
38
48
|
paths:
|
|
39
|
-
-
|
|
49
|
+
- node_modules/
|
|
40
50
|
policy: pull
|
|
41
51
|
before_script:
|
|
42
|
-
|
|
52
|
+
{{#if pm.corepack}}
|
|
53
|
+
- corepack enable
|
|
54
|
+
{{/if}}
|
|
55
|
+
- test -d node_modules || npm ci
|
|
56
|
+
{{#if orm.prisma}}
|
|
57
|
+
# The Prisma client and the schema of the tests are build products of prisma/schema.prisma.
|
|
58
|
+
- npm run db:client
|
|
59
|
+
{{/if}}
|
|
43
60
|
|
|
44
61
|
.postgres:
|
|
45
62
|
services:
|
|
@@ -61,19 +78,28 @@ default:
|
|
|
61
78
|
install:
|
|
62
79
|
extends: .node
|
|
63
80
|
stage: install
|
|
81
|
+
# The image with git: what a merge request covers is read from the difference with its target.
|
|
82
|
+
image: node:24-bookworm
|
|
64
83
|
cache:
|
|
65
84
|
key:
|
|
66
85
|
files:
|
|
67
86
|
- package-lock.json
|
|
87
|
+
- package.json
|
|
68
88
|
paths:
|
|
69
|
-
-
|
|
89
|
+
- node_modules/
|
|
70
90
|
policy: pull-push
|
|
71
91
|
script:
|
|
72
|
-
- node --version
|
|
92
|
+
- node --version
|
|
93
|
+
- if [ -n "${CI_MERGE_REQUEST_DIFF_BASE_SHA:-}" ]; then git fetch --quiet --depth=1 origin "$CI_MERGE_REQUEST_DIFF_BASE_SHA"; fi
|
|
94
|
+
# Everything on the default branch and on a schedule, the affected contexts on a merge request.
|
|
95
|
+
- npx --no -- ddd-ts-kit affected --base "${CI_MERGE_REQUEST_DIFF_BASE_SHA:-}" --format env | tee affected.env
|
|
96
|
+
artifacts:
|
|
97
|
+
reports:
|
|
98
|
+
dotenv: affected.env
|
|
73
99
|
|
|
74
100
|
merge-request-title:
|
|
75
101
|
extends: .node
|
|
76
|
-
stage:
|
|
102
|
+
stage: test
|
|
77
103
|
needs: [install]
|
|
78
104
|
rules:
|
|
79
105
|
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
@@ -82,21 +108,22 @@ merge-request-title:
|
|
|
82
108
|
|
|
83
109
|
typecheck:
|
|
84
110
|
extends: .node
|
|
85
|
-
stage:
|
|
111
|
+
stage: test
|
|
86
112
|
needs: [install]
|
|
87
113
|
script:
|
|
88
114
|
- npm run ci:typecheck
|
|
89
115
|
|
|
90
116
|
lint:
|
|
91
117
|
extends: .node
|
|
92
|
-
stage:
|
|
118
|
+
stage: test
|
|
93
119
|
needs: [install]
|
|
94
120
|
variables:
|
|
95
121
|
ESLINT_CODE_QUALITY_REPORT: reports/gl-code-quality-eslint.json
|
|
96
122
|
script:
|
|
97
123
|
- mkdir -p reports
|
|
98
124
|
- npm run ci:format
|
|
99
|
-
|
|
125
|
+
# The contexts a merge request does not reach are left to the default branch.
|
|
126
|
+
- npm run ci:lint -- --format gitlab $AFFECTED_LINT
|
|
100
127
|
artifacts:
|
|
101
128
|
when: always
|
|
102
129
|
expire_in: 14 days
|
|
@@ -105,7 +132,7 @@ lint:
|
|
|
105
132
|
|
|
106
133
|
architecture:
|
|
107
134
|
extends: .node
|
|
108
|
-
stage:
|
|
135
|
+
stage: test
|
|
109
136
|
needs: [install]
|
|
110
137
|
script:
|
|
111
138
|
- mkdir -p reports
|
|
@@ -119,7 +146,7 @@ architecture:
|
|
|
119
146
|
|
|
120
147
|
deadcode:
|
|
121
148
|
extends: .node
|
|
122
|
-
stage:
|
|
149
|
+
stage: test
|
|
123
150
|
needs: [install]
|
|
124
151
|
script:
|
|
125
152
|
- npm run ci:deadcode
|
|
@@ -127,9 +154,11 @@ deadcode:
|
|
|
127
154
|
unit:
|
|
128
155
|
extends: [.node, .junit]
|
|
129
156
|
stage: test
|
|
130
|
-
needs: [
|
|
157
|
+
needs: [install]
|
|
131
158
|
script:
|
|
132
|
-
-
|
|
159
|
+
- if [ "$AFFECTED_SCOPE" = "none" ]; then echo "Only documents changed, no spec to run."; exit 0; fi
|
|
160
|
+
- export DDD_TS_KIT_AFFECTED="$AFFECTED_CONTEXTS"
|
|
161
|
+
- npm run ci:test:unit -- --reporter=default --reporter=junit --outputFile.junit=reports/junit.xml $AFFECTED_ARGS
|
|
133
162
|
coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'
|
|
134
163
|
artifacts:
|
|
135
164
|
when: always
|
|
@@ -143,24 +172,30 @@ unit:
|
|
|
143
172
|
integration:
|
|
144
173
|
extends: [.node, .postgres, .junit]
|
|
145
174
|
stage: test
|
|
146
|
-
needs: [
|
|
175
|
+
needs: [install]
|
|
147
176
|
script:
|
|
177
|
+
- if [ "$AFFECTED_SCOPE" = "none" ]; then echo "Only documents changed, no spec to run."; exit 0; fi
|
|
178
|
+
- export DDD_TS_KIT_AFFECTED="$AFFECTED_CONTEXTS"
|
|
148
179
|
- npm run db:migrate
|
|
149
|
-
- npm run ci:test:integration -- --reporter=default --reporter=junit --outputFile.junit=reports/junit.xml
|
|
180
|
+
- npm run ci:test:integration -- --reporter=default --reporter=junit --outputFile.junit=reports/junit.xml $AFFECTED_ARGS
|
|
150
181
|
|
|
151
182
|
e2e:
|
|
152
183
|
extends: [.node, .postgres, .junit]
|
|
153
184
|
stage: test
|
|
154
|
-
needs: [
|
|
185
|
+
needs: [install]
|
|
155
186
|
script:
|
|
187
|
+
- if [ "$AFFECTED_SCOPE" = "none" ]; then echo "Only documents changed, no spec to run."; exit 0; fi
|
|
156
188
|
- npm run db:migrate
|
|
189
|
+
# The whole application, whatever the contexts a change reaches.
|
|
157
190
|
- npm run ci:test:e2e -- --reporter=default --reporter=junit --outputFile.junit=reports/junit.xml
|
|
158
191
|
|
|
159
|
-
|
|
192
|
+
build:
|
|
160
193
|
extends: .node
|
|
161
|
-
stage:
|
|
162
|
-
needs: [
|
|
194
|
+
stage: test
|
|
195
|
+
needs: [install]
|
|
163
196
|
script:
|
|
197
|
+
- npm run ci:build
|
|
198
|
+
# The generated documents and contracts, from that build.
|
|
164
199
|
- npm run ci:docs
|
|
165
200
|
|
|
166
201
|
audit:
|
|
@@ -181,16 +216,9 @@ secrets:
|
|
|
181
216
|
script:
|
|
182
217
|
- gitleaks git . --redact --no-banner
|
|
183
218
|
|
|
184
|
-
build:
|
|
185
|
-
extends: .node
|
|
186
|
-
stage: package
|
|
187
|
-
needs: [e2e]
|
|
188
|
-
script:
|
|
189
|
-
- npm run ci:build
|
|
190
|
-
|
|
191
219
|
image:
|
|
192
|
-
stage:
|
|
193
|
-
needs: [
|
|
220
|
+
stage: test
|
|
221
|
+
needs: []
|
|
194
222
|
image:
|
|
195
223
|
name: moby/buildkit:v0.34.0-rootless
|
|
196
224
|
entrypoint: ['']
|
|
@@ -1,26 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://unpkg.com/knip@6/schema.json",
|
|
3
3
|
"entry": [
|
|
4
|
-
{{#if
|
|
5
|
-
"{{config.contextsDir}}/*/*.module.ts",
|
|
6
|
-
{{/if}}
|
|
7
|
-
{{#if assembly.discovery}}
|
|
8
|
-
"{{config.contextsDir}}/*/{application,infrastructure}/**/*.{{knip.discovered}}.ts",
|
|
9
|
-
{{/if}}
|
|
10
|
-
"{{config.contextsDir}}/*/published-language/index.ts",
|
|
4
|
+
{{#if tests.jest}}
|
|
11
5
|
"{{config.contextsDir}}/*/test/fakes/*.ts",
|
|
6
|
+
{{/if}}
|
|
12
7
|
{{#if knip.apps}}
|
|
13
8
|
"{{config.sourceRoot}}/apps/*/main.ts",
|
|
14
9
|
{{/if}}
|
|
15
10
|
"scripts/*.ts"{{knip.e2eEntry}}
|
|
16
11
|
],
|
|
17
12
|
"project": ["{{config.sourceRoot}}/**/*.ts", "scripts/**/*.ts"{{knip.e2eProject}}],
|
|
18
|
-
{{#if
|
|
19
|
-
"ignoreDependencies":
|
|
13
|
+
{{#if knip.ignores}}
|
|
14
|
+
"ignoreDependencies": {{knip.ignored}},
|
|
20
15
|
{{/if}}
|
|
21
16
|
"ignoreExportsUsedInFile": true,
|
|
22
17
|
"vitest": {
|
|
23
18
|
"config": ["vitest.config.ts"{{knip.e2eConfig}}],
|
|
24
|
-
"entry": [
|
|
19
|
+
"entry": [
|
|
20
|
+
"{{config.sourceRoot}}/**/*.spec.ts",
|
|
21
|
+
"{{config.contextsDir}}/*/test/fakes/*.ts",
|
|
22
|
+
"test/architecture/**/*.spec.ts"{{knip.e2eSpecs}}{{knip.testDatabase}}
|
|
23
|
+
]
|
|
25
24
|
}
|
|
26
25
|
}
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"@biomejs/biome": "2.5.15",
|
|
24
24
|
"@commitlint/cli": "^21.2.3",
|
|
25
25
|
"@commitlint/config-conventional": "^21.2.3",
|
|
26
|
-
"@ddd-ts-kit/eslint-plugin": "^0.1.
|
|
26
|
+
"@ddd-ts-kit/eslint-plugin": "^0.1.1",
|
|
27
27
|
"@eslint/js": "^10.0.1",
|
|
28
28
|
"@typescript/native": "npm:typescript@~7.0.2",
|
|
29
29
|
"@vitest/coverage-v8": "5.0.3",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { governedCoverage } from '@ddd-ts-kit/testing/coverage';
|
|
1
|
+
import { governedCoverage, unaffectedContexts } from '@ddd-ts-kit/testing/coverage';
|
|
2
2
|
{{#if decorators.standard}}
|
|
3
3
|
import { decorators } from '@ddd-ts-kit/testing/vitest';
|
|
4
4
|
{{/if}}
|
|
@@ -9,6 +9,8 @@ import { defineConfig } from 'vitest/config';
|
|
|
9
9
|
|
|
10
10
|
const INTEGRATION_SPECS = '{{config.contextsDir}}/*/test/integration/**/*.spec.ts';
|
|
11
11
|
const INTEGRATION_MODE = 'integration';
|
|
12
|
+
// A pull request names the contexts its change reaches (DDD_TS_KIT_AFFECTED, from `ddd-ts-kit affected`): the specs of the others are left to the default branch.
|
|
13
|
+
const NOT_AFFECTED = unaffectedContexts().map((directory) => `${directory}**`);
|
|
12
14
|
|
|
13
15
|
export default defineConfig(({ mode }) => ({
|
|
14
16
|
{{#if decorators.standard}}
|
|
@@ -22,6 +24,8 @@ export default defineConfig(({ mode }) => ({
|
|
|
22
24
|
// An import alias is resolved from the "paths" of tsconfig.json, which name the sources.
|
|
23
25
|
resolve: { tsconfigPaths: true },
|
|
24
26
|
test: {
|
|
27
|
+
// The integration project has no spec before the first repository or adapter of the project: its run passes until then.
|
|
28
|
+
passWithNoTests: mode === INTEGRATION_MODE,
|
|
25
29
|
{{#if assembly.discovery}}
|
|
26
30
|
// Discovery imports the role files of a context itself: inlined, the package loads them through the runner, which compiles them.
|
|
27
31
|
server: { deps: { inline: ['@ddd-ts-kit/di'] } },
|
|
@@ -32,10 +36,10 @@ export default defineConfig(({ mode }) => ({
|
|
|
32
36
|
test: {
|
|
33
37
|
name: 'unit',
|
|
34
38
|
include: ['{{config.sourceRoot}}/**/*.spec.ts', 'test/architecture/**/*.spec.ts'],
|
|
35
|
-
exclude: [INTEGRATION_SPECS],
|
|
39
|
+
exclude: [INTEGRATION_SPECS, ...NOT_AFFECTED],
|
|
36
40
|
},
|
|
37
41
|
},
|
|
38
|
-
{ extends: true, test: { name: INTEGRATION_MODE, include: [INTEGRATION_SPECS] } },
|
|
42
|
+
{ extends: true, test: { name: INTEGRATION_MODE, include: [INTEGRATION_SPECS], exclude: NOT_AFFECTED } },
|
|
39
43
|
],
|
|
40
44
|
coverage: {
|
|
41
45
|
provider: 'v8',
|