skuba 13.0.0-custom-conditions-exports-20250730060544 → 13.0.0-custom-conditions-exports-20250923003120

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.
Files changed (138) hide show
  1. package/README.md +1 -2
  2. package/config/tsconfig.json +2 -1
  3. package/jest/moduleNameMapper.js +3 -0
  4. package/lib/cli/build/assets.js +1 -1
  5. package/lib/cli/build/assets.js.map +2 -2
  6. package/lib/cli/build/esbuild.js +1 -1
  7. package/lib/cli/build/esbuild.js.map +2 -2
  8. package/lib/cli/build/index.js +1 -1
  9. package/lib/cli/build/index.js.map +2 -2
  10. package/lib/cli/build/tsc.d.ts +9 -2
  11. package/lib/cli/build/tsc.js +76 -40
  12. package/lib/cli/build/tsc.js.map +3 -3
  13. package/lib/cli/configure/analyseDependencies.d.ts +2 -2
  14. package/lib/cli/configure/analyseDependencies.js.map +1 -1
  15. package/lib/cli/configure/analysis/package.d.ts +1 -1
  16. package/lib/cli/configure/analysis/package.js +1 -1
  17. package/lib/cli/configure/analysis/package.js.map +2 -2
  18. package/lib/cli/configure/ensureTemplateCompletion.d.ts +2 -2
  19. package/lib/cli/configure/ensureTemplateCompletion.js.map +1 -1
  20. package/lib/cli/configure/getEntryPoint.d.ts +2 -2
  21. package/lib/cli/configure/getEntryPoint.js.map +1 -1
  22. package/lib/cli/configure/getProjectType.d.ts +2 -2
  23. package/lib/cli/configure/getProjectType.js.map +1 -1
  24. package/lib/cli/configure/processing/package.js +8 -2
  25. package/lib/cli/configure/processing/package.js.map +2 -2
  26. package/lib/cli/init/getConfig.js +1 -1
  27. package/lib/cli/init/getConfig.js.map +2 -2
  28. package/lib/cli/lint/internal.js +1 -1
  29. package/lib/cli/lint/internal.js.map +2 -2
  30. package/lib/cli/lint/internalLints/patchRenovateConfig.js +2 -2
  31. package/lib/cli/lint/internalLints/patchRenovateConfig.js.map +1 -1
  32. package/lib/cli/lint/internalLints/upgrade/index.d.ts +2 -2
  33. package/lib/cli/lint/internalLints/upgrade/index.js +7 -3
  34. package/lib/cli/lint/internalLints/upgrade/index.js.map +2 -2
  35. package/lib/cli/lint/internalLints/upgrade/patches/12.0.2/index.js +3 -3
  36. package/lib/cli/lint/internalLints/upgrade/patches/12.0.2/index.js.map +2 -2
  37. package/lib/cli/lint/internalLints/upgrade/patches/12.0.2/unhandledRejections.d.ts +4 -0
  38. package/lib/cli/lint/internalLints/upgrade/patches/12.0.2/unhandledRejections.js +162 -0
  39. package/lib/cli/lint/internalLints/upgrade/patches/12.0.2/unhandledRejections.js.map +7 -0
  40. package/lib/cli/lint/internalLints/upgrade/patches/12.1.1/index.js +35 -0
  41. package/lib/cli/lint/internalLints/upgrade/patches/12.1.1/index.js.map +7 -0
  42. package/lib/cli/lint/internalLints/upgrade/patches/12.1.1/patchJestSnapshots.d.ts +3 -0
  43. package/lib/cli/lint/internalLints/upgrade/patches/12.1.1/patchJestSnapshots.js +105 -0
  44. package/lib/cli/lint/internalLints/upgrade/patches/12.1.1/patchJestSnapshots.js.map +7 -0
  45. package/lib/cli/lint/internalLints/upgrade/patches/12.2.0/configureTsConfigForESM.d.ts +23 -0
  46. package/lib/cli/lint/internalLints/upgrade/patches/12.2.0/configureTsConfigForESM.js +321 -0
  47. package/lib/cli/lint/internalLints/upgrade/patches/12.2.0/configureTsConfigForESM.js.map +7 -0
  48. package/lib/cli/lint/internalLints/upgrade/patches/12.2.0/index.d.ts +2 -0
  49. package/lib/cli/lint/internalLints/upgrade/patches/{12.0.1 → 12.2.0}/index.js +5 -0
  50. package/lib/cli/lint/internalLints/upgrade/patches/12.2.0/index.js.map +7 -0
  51. package/lib/cli/lint/internalLints/upgrade/patches/{12.0.2 → 12.2.0}/rewriteSrcImports.js +7 -4
  52. package/lib/cli/lint/internalLints/upgrade/patches/{12.0.2 → 12.2.0}/rewriteSrcImports.js.map +3 -3
  53. package/lib/cli/lint/internalLints/upgrade/patches/8.2.1/upgradeESLint.js +1 -1
  54. package/lib/cli/lint/internalLints/upgrade/patches/8.2.1/upgradeESLint.js.map +2 -2
  55. package/lib/cli/node/index.js +6 -0
  56. package/lib/cli/node/index.js.map +2 -2
  57. package/lib/cli/start/index.js +6 -0
  58. package/lib/cli/start/index.js.map +2 -2
  59. package/lib/cli/test/index.d.ts +1 -1
  60. package/lib/cli/test/index.js +18 -4
  61. package/lib/cli/test/index.js.map +2 -2
  62. package/lib/utils/args.d.ts +2 -0
  63. package/lib/utils/args.js +5 -0
  64. package/lib/utils/args.js.map +2 -2
  65. package/lib/utils/manifest.d.ts +1 -1
  66. package/lib/utils/manifest.js +1 -1
  67. package/lib/utils/manifest.js.map +2 -2
  68. package/lib/utils/template.d.ts +1 -1
  69. package/package.json +17 -20
  70. package/template/base/_.prettierrc.js +1 -1
  71. package/template/base/_eslint.config.js +1 -1
  72. package/template/base/_pnpm-workspace.yaml +1 -0
  73. package/template/base/jest.setup.ts +1 -1
  74. package/template/base/tsconfig.build.json +3 -0
  75. package/template/base/tsconfig.json +0 -1
  76. package/template/express-rest-api/.buildkite/pipeline.yml +6 -0
  77. package/template/express-rest-api/.env +1 -1
  78. package/template/express-rest-api/.gantry/dev.yml +5 -1
  79. package/template/express-rest-api/.gantry/prod.yml +5 -1
  80. package/template/express-rest-api/Dockerfile +1 -1
  81. package/template/express-rest-api/Dockerfile.dev-deps +1 -1
  82. package/template/express-rest-api/README.md +5 -5
  83. package/template/express-rest-api/gantry.apply.yml +17 -1
  84. package/template/express-rest-api/package.json +11 -5
  85. package/template/express-rest-api/src/api/healthCheck.ts +2 -2
  86. package/template/express-rest-api/src/config.ts +7 -7
  87. package/template/express-rest-api/src/framework/logging.ts +11 -7
  88. package/template/express-rest-api/src/framework/metrics.ts +1 -1
  89. package/template/express-rest-api/src/listen.ts +6 -0
  90. package/template/express-rest-api/src/tracing.ts +56 -0
  91. package/template/greeter/Dockerfile +1 -1
  92. package/template/greeter/README.md +2 -2
  93. package/template/greeter/package.json +2 -2
  94. package/template/koa-rest-api/.buildkite/pipeline.yml +6 -0
  95. package/template/koa-rest-api/.env +1 -1
  96. package/template/koa-rest-api/.gantry/dev.yml +3 -3
  97. package/template/koa-rest-api/.gantry/prod.yml +3 -3
  98. package/template/koa-rest-api/Dockerfile.dev-deps +1 -1
  99. package/template/koa-rest-api/README.md +6 -6
  100. package/template/koa-rest-api/gantry.apply.yml +15 -3
  101. package/template/koa-rest-api/package.json +10 -11
  102. package/template/koa-rest-api/skuba.template.js +1 -1
  103. package/template/koa-rest-api/src/api/healthCheck.ts +2 -2
  104. package/template/koa-rest-api/src/config.ts +7 -7
  105. package/template/koa-rest-api/src/framework/logging.ts +12 -8
  106. package/template/koa-rest-api/src/framework/metrics.ts +1 -1
  107. package/template/koa-rest-api/src/framework/server.test.ts +7 -8
  108. package/template/koa-rest-api/src/framework/server.ts +1 -4
  109. package/template/koa-rest-api/src/listen.ts +6 -0
  110. package/template/lambda-sqs-worker-cdk/.buildkite/pipeline.yml +6 -2
  111. package/template/lambda-sqs-worker-cdk/.env +1 -1
  112. package/template/lambda-sqs-worker-cdk/Dockerfile +1 -1
  113. package/template/lambda-sqs-worker-cdk/README.md +8 -8
  114. package/template/lambda-sqs-worker-cdk/infra/__snapshots__/appStack.test.ts.snap +54 -26
  115. package/template/lambda-sqs-worker-cdk/infra/appStack.test.ts +5 -22
  116. package/template/lambda-sqs-worker-cdk/infra/appStack.ts +16 -9
  117. package/template/lambda-sqs-worker-cdk/infra/config.ts +34 -20
  118. package/template/lambda-sqs-worker-cdk/infra/index.ts +1 -1
  119. package/template/lambda-sqs-worker-cdk/package.json +7 -9
  120. package/template/lambda-sqs-worker-cdk/src/app.test.ts +91 -51
  121. package/template/lambda-sqs-worker-cdk/src/app.ts +10 -9
  122. package/template/lambda-sqs-worker-cdk/src/config.ts +11 -16
  123. package/template/lambda-sqs-worker-cdk/src/framework/handler.test.ts +10 -5
  124. package/template/lambda-sqs-worker-cdk/src/framework/handler.ts +48 -24
  125. package/template/lambda-sqs-worker-cdk/src/framework/logging.ts +23 -11
  126. package/template/lambda-sqs-worker-cdk/src/framework/metrics.ts +1 -4
  127. package/template/lambda-sqs-worker-cdk/src/testing/handler.ts +4 -1
  128. package/template/lambda-sqs-worker-cdk/tsconfig.json +1 -2
  129. package/template/oss-npm-package/.github/workflows/release.yml +5 -6
  130. package/template/oss-npm-package/.github/workflows/validate.yml +5 -5
  131. package/template/oss-npm-package/_package.json +0 -3
  132. package/template/oss-npm-package/skuba.template.js +1 -1
  133. package/lib/cli/lint/internalLints/upgrade/patches/12.0.1/configureTsConfigForESM.d.ts +0 -6
  134. package/lib/cli/lint/internalLints/upgrade/patches/12.0.1/configureTsConfigForESM.js +0 -249
  135. package/lib/cli/lint/internalLints/upgrade/patches/12.0.1/configureTsConfigForESM.js.map +0 -7
  136. package/lib/cli/lint/internalLints/upgrade/patches/12.0.1/index.js.map +0 -7
  137. /package/lib/cli/lint/internalLints/upgrade/patches/{12.0.1 → 12.1.1}/index.d.ts +0 -0
  138. /package/lib/cli/lint/internalLints/upgrade/patches/{12.0.2 → 12.2.0}/rewriteSrcImports.d.ts +0 -0
@@ -1,7 +1,10 @@
1
1
  import { isLambdaHook } from '@seek/aws-codedeploy-hooks';
2
2
  import type { SQSEvent } from 'aws-lambda';
3
3
 
4
- import { createHandler } from '#src/framework/handler.js';
4
+ import {
5
+ createBatchSQSHandler,
6
+ createHandler,
7
+ } from '#src/framework/handler.js';
5
8
  import { logger } from '#src/framework/logging.js';
6
9
  import { metricsClient } from '#src/framework/metrics.js';
7
10
  import { validateJson } from '#src/framework/validation.js';
@@ -34,19 +37,17 @@ export const handler = createHandler<SQSEvent>(async (event, ctx) => {
34
37
 
35
38
  const count = event.Records.length;
36
39
 
37
- if (count !== 1) {
38
- throw Error(`Received ${count} records`);
40
+ if (!count) {
41
+ throw Error('Received 0 records');
39
42
  }
40
-
41
43
  logger.debug({ count }, 'Received jobs');
42
44
 
43
- metricsClient.distribution('job.received', event.Records.length);
45
+ metricsClient.distribution('job.received', count);
44
46
 
45
- const record = event.Records[0];
46
- if (!record) {
47
- throw new Error('Malformed SQS event with no records');
48
- }
47
+ return recordHandler(event, ctx);
48
+ });
49
49
 
50
+ const recordHandler = createBatchSQSHandler(async (record, _ctx) => {
50
51
  const { body } = record;
51
52
 
52
53
  // TODO: this throws an error, which will cause the Lambda function to retry
@@ -1,27 +1,25 @@
1
1
  import { Env } from 'skuba-dive';
2
2
 
3
3
  interface Config {
4
- environment: Environment;
4
+ deployment: Deployment;
5
5
 
6
6
  logLevel: string;
7
- metrics: boolean;
8
7
  name: string;
9
8
  version: string;
10
9
 
11
10
  destinationSnsTopicArn: string;
12
11
  }
13
12
 
14
- type Environment = (typeof environments)[number];
13
+ type Deployment = (typeof deployments)[number];
15
14
 
16
- const environments = ['local', 'test', 'dev', 'prod'] as const;
15
+ const deployments = ['local', 'test', 'dev', 'prod'] as const;
17
16
 
18
- const environment = Env.oneOf(environments)('ENVIRONMENT');
17
+ const deployment = Env.oneOf(deployments)('DEPLOYMENT');
19
18
 
20
19
  /* istanbul ignore next: config verification makes more sense in a smoke test */
21
- const configs: Record<Environment, () => Omit<Config, 'environment'>> = {
20
+ const configs: Record<Deployment, () => Omit<Config, 'deployment'>> = {
22
21
  local: () => ({
23
22
  logLevel: 'debug',
24
- metrics: false,
25
23
  name: '<%- serviceName %>',
26
24
  version: 'local',
27
25
 
@@ -30,7 +28,6 @@ const configs: Record<Environment, () => Omit<Config, 'environment'>> = {
30
28
 
31
29
  test: () => ({
32
30
  logLevel: Env.string('LOG_LEVEL', { default: 'debug' }),
33
- metrics: false,
34
31
  name: '<%- serviceName %>',
35
32
  version: 'test',
36
33
 
@@ -39,24 +36,22 @@ const configs: Record<Environment, () => Omit<Config, 'environment'>> = {
39
36
 
40
37
  dev: () => ({
41
38
  logLevel: 'debug',
42
- metrics: true,
43
- name: Env.string('SERVICE'),
44
- version: Env.string('VERSION'),
39
+ name: Env.string('DD_SERVICE'),
40
+ version: Env.string('DD_VERSION'),
45
41
 
46
42
  destinationSnsTopicArn: Env.string('DESTINATION_SNS_TOPIC_ARN'),
47
43
  }),
48
44
 
49
45
  prod: () => ({
50
46
  logLevel: 'info',
51
- metrics: true,
52
- name: Env.string('SERVICE'),
53
- version: Env.string('VERSION'),
47
+ name: Env.string('DD_SERVICE'),
48
+ version: Env.string('DD_VERSION'),
54
49
 
55
50
  destinationSnsTopicArn: Env.string('DESTINATION_SNS_TOPIC_ARN'),
56
51
  }),
57
52
  };
58
53
 
59
54
  export const config: Config = {
60
- ...configs[environment](),
61
- environment,
55
+ ...configs[deployment](),
56
+ deployment,
62
57
  };
@@ -1,3 +1,5 @@
1
+ import type { SQSEvent } from 'aws-lambda';
2
+
1
3
  import { createHandler } from './handler.js';
2
4
  import { logger, stdoutMock } from './logging.js';
3
5
 
@@ -6,12 +8,14 @@ import { chance } from '#src/testing/types.js';
6
8
 
7
9
  describe('createHandler', () => {
8
10
  const ctx = createCtx();
9
- const input = chance.paragraph();
11
+ const input: SQSEvent = {
12
+ Records: [],
13
+ };
10
14
 
11
15
  afterEach(stdoutMock.clear);
12
16
 
13
17
  it('handles happy path', async () => {
14
- const output = chance.paragraph();
18
+ const output = chance.sentence();
15
19
 
16
20
  const handler = createHandler((event) => {
17
21
  expect(event).toBe(input);
@@ -32,7 +36,8 @@ describe('createHandler', () => {
32
36
  {
33
37
  awsRequestId: '-',
34
38
  level: 20,
35
- msg: 'Function succeeded',
39
+ output,
40
+ msg: 'Function completed',
36
41
  },
37
42
  ]);
38
43
  });
@@ -47,7 +52,7 @@ describe('createHandler', () => {
47
52
  expect(stdoutMock.calls).toMatchObject([
48
53
  {
49
54
  awsRequestId: '-',
50
- err: {
55
+ error: {
51
56
  message: err.message,
52
57
  type: 'Error',
53
58
  },
@@ -69,7 +74,7 @@ describe('createHandler', () => {
69
74
  expect(stdoutMock.calls).toMatchObject([
70
75
  {
71
76
  awsRequestId: '-',
72
- err: {
77
+ error: {
73
78
  message: err.message,
74
79
  type: 'Error',
75
80
  },
@@ -1,40 +1,64 @@
1
- import type { Context as LambdaContext } from 'aws-lambda';
2
- import { datadog } from 'datadog-lambda-js';
1
+ import type {
2
+ Context as LambdaContext,
3
+ SQSBatchItemFailure,
4
+ SQSBatchResponse,
5
+ SQSEvent,
6
+ SQSRecord,
7
+ } from 'aws-lambda';
3
8
 
4
- import { config } from '#src/config.js';
5
- import { logger, loggerContext } from '#src/framework/logging.js';
9
+ import {
10
+ lambdaContext,
11
+ logger,
12
+ recordContext,
13
+ } from '#src/framework/logging.js';
6
14
 
7
15
  type Handler<Event, Output> = (
8
16
  event: Event,
9
17
  ctx: LambdaContext,
10
18
  ) => Promise<Output>;
11
19
 
12
- /**
13
- * Conditionally applies the Datadog wrapper to a Lambda handler.
14
- *
15
- * This also "fixes" its broken type definitions.
16
- */
17
- const withDatadog = <Event, Output = unknown>(
18
- fn: Handler<Event, Output>,
19
- ): Handler<Event, Output> =>
20
- // istanbul ignore next
21
- config.metrics ? (datadog(fn) as Handler<Event, Output>) : fn;
22
-
23
- export const createHandler = <Event, Output = unknown>(
24
- fn: (event: Event, ctx: LambdaContext) => Promise<Output>,
25
- ) =>
26
- withDatadog<Event>((event, ctx) =>
27
- loggerContext.run({ awsRequestId: ctx.awsRequestId }, async () => {
20
+ export const createHandler =
21
+ <Event extends SQSEvent, Output = unknown>(
22
+ fn: (event: Event, ctx: LambdaContext) => Promise<Output>,
23
+ ): Handler<Event, Output> =>
24
+ async (event, ctx) =>
25
+ lambdaContext.run({ awsRequestId: ctx.awsRequestId }, async () => {
28
26
  try {
29
27
  const output = await fn(event, ctx);
30
28
 
31
- logger.debug('Function succeeded');
29
+ logger.debug({ output }, 'Function completed');
32
30
 
33
31
  return output;
34
32
  } catch (err) {
35
- logger.error({ err }, 'Function failed');
33
+ logger.error(err, 'Function failed');
36
34
 
37
35
  throw new Error('Function failed');
38
36
  }
39
- }),
40
- );
37
+ });
38
+
39
+ export const createBatchSQSHandler =
40
+ (
41
+ fn: (record: SQSRecord, ctx: LambdaContext) => Promise<unknown>,
42
+ ): Handler<SQSEvent, SQSBatchResponse> =>
43
+ async (event, ctx) => {
44
+ const processRecord = (
45
+ record: SQSRecord,
46
+ ): Promise<SQSBatchItemFailure | undefined> =>
47
+ recordContext.run({ sqsMessageId: record.messageId }, async () => {
48
+ try {
49
+ await fn(record, ctx);
50
+ return;
51
+ } catch (err) {
52
+ logger.error(err, 'Processing record failed');
53
+ return {
54
+ itemIdentifier: record.messageId,
55
+ };
56
+ }
57
+ });
58
+
59
+ const results = await Promise.all(event.Records.map(processRecord));
60
+
61
+ return {
62
+ batchItemFailures: results.filter((item) => item !== undefined),
63
+ };
64
+ };
@@ -1,17 +1,22 @@
1
1
  import { AsyncLocalStorage } from 'async_hooks';
2
2
 
3
- import createLogger, { createDestination } from '@seek/logger';
3
+ import { createDestination, createLogger } from '@seek/logger';
4
4
 
5
5
  import { config } from '#src/config.js';
6
6
 
7
- interface LoggerContext {
7
+ interface LambdaContext {
8
8
  awsRequestId: string;
9
9
  }
10
10
 
11
- export const loggerContext = new AsyncLocalStorage<LoggerContext>();
11
+ interface RecordContext {
12
+ sqsMessageId: string;
13
+ }
14
+
15
+ export const lambdaContext = new AsyncLocalStorage<LambdaContext>();
16
+ export const recordContext = new AsyncLocalStorage<RecordContext>();
12
17
 
13
18
  const { destination, stdoutMock } = createDestination({
14
- mock: config.environment === 'test' && {
19
+ mock: config.deployment === 'test' && {
15
20
  redact: ['awsRequestId'],
16
21
  },
17
22
  });
@@ -20,19 +25,26 @@ export { stdoutMock };
20
25
 
21
26
  export const logger = createLogger(
22
27
  {
23
- base: {
24
- environment: config.environment,
25
- version: config.version,
28
+ eeeoh: {
29
+ /**
30
+ * TODO: choose an appropriate Datadog log tier.
31
+ *
32
+ * https://github.com/seek-oss/logger/blob/master/docs/eeeoh.md#datadog-log-tiers
33
+ */
34
+ datadog: 'tin',
35
+ team: '<%- teamName %>',
36
+ use: 'environment',
26
37
  },
27
38
 
28
39
  level: config.logLevel,
29
40
 
30
- mixin: () => ({ ...loggerContext.getStore() }),
31
-
32
- name: config.name,
41
+ mixin: () => ({
42
+ ...lambdaContext.getStore(),
43
+ ...recordContext.getStore(),
44
+ }),
33
45
 
34
46
  transport:
35
- config.environment === 'local' ? { target: 'pino-pretty' } : undefined,
47
+ config.deployment === 'local' ? { target: 'pino-pretty' } : undefined,
36
48
  },
37
49
  destination,
38
50
  );
@@ -7,8 +7,5 @@ const prefix = `${config.name}.`;
7
7
  export const metricsClient = {
8
8
  distribution: (
9
9
  ...[name, ...rest]: Parameters<typeof sendDistributionMetric>
10
- ) =>
11
- config.metrics
12
- ? sendDistributionMetric(`${prefix}${name}`, ...rest)
13
- : undefined,
10
+ ) => sendDistributionMetric(`${prefix}${name}`, ...rest),
14
11
  };
@@ -9,5 +9,8 @@ export const createCtx = () =>
9
9
 
10
10
  export const createSqsEvent = (bodies: string[]) =>
11
11
  ({
12
- Records: bodies.map((body) => ({ body })),
12
+ Records: bodies.map((body) => ({
13
+ body,
14
+ messageId: chance.guid({ version: 4 }),
15
+ })),
13
16
  }) as SQSEvent;
@@ -1,8 +1,7 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "customConditions": ["@seek/<%- serviceName %>/source"],
4
- "baseUrl": ".",
5
- "module": "node18",
4
+
6
5
  "moduleResolution": "node16",
7
6
  "lib": ["ES2024"],
8
7
  "outDir": "lib",
@@ -18,18 +18,18 @@ jobs:
18
18
  timeout-minutes: 20
19
19
  steps:
20
20
  - name: Check out repo
21
- uses: actions/checkout@v4
21
+ uses: actions/checkout@v5
22
22
  with:
23
23
  fetch-depth: 0
24
24
 
25
+ - name: Set up pnpm
26
+ uses: pnpm/action-setup@v4
27
+
25
28
  - name: Set up Node.js
26
- uses: actions/setup-node@v4
29
+ uses: actions/setup-node@v5
27
30
  with:
28
31
  node-version: ^22.14
29
32
 
30
- - name: Set up pnpm
31
- run: corepack enable pnpm && corepack install
32
-
33
33
  - name: Install dependencies
34
34
  run: pnpm install --frozen-lockfile
35
35
 
@@ -37,4 +37,3 @@ jobs:
37
37
  run: pnpm release
38
38
  env:
39
39
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
40
- NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -16,16 +16,16 @@ jobs:
16
16
  timeout-minutes: 20
17
17
  steps:
18
18
  - name: Check out repo
19
- uses: actions/checkout@v4
19
+ uses: actions/checkout@v5
20
+
21
+ - name: Set up pnpm
22
+ uses: pnpm/action-setup@v4
20
23
 
21
24
  - name: Set up Node.js
22
- uses: actions/setup-node@v4
25
+ uses: actions/setup-node@v5
23
26
  with:
24
27
  node-version: ^22.14
25
28
 
26
- - name: Set up pnpm
27
- run: corepack enable pnpm && corepack install
28
-
29
29
  - name: Install dependencies
30
30
  run: pnpm install --frozen-lockfile
31
31
 
@@ -47,8 +47,5 @@
47
47
  "packageManager": "pnpm@10.7.0",
48
48
  "engines": {
49
49
  "node": ">=20.9.0"
50
- },
51
- "publishConfig": {
52
- "provenance": true
53
50
  }
54
51
  }
@@ -2,7 +2,7 @@
2
2
  * Run `skuba configure` to finish templating and remove this file.
3
3
  */
4
4
 
5
- export default {
5
+ module.exports = {
6
6
  entryPoint: 'src/index.ts',
7
7
  fields: [
8
8
  {
@@ -1,6 +0,0 @@
1
- import type { PatchFunction } from '../../index.js';
2
- export declare const addJestModuleNameMapper: (contents: string, subfolderPaths: string[]) => string;
3
- export declare const replacePackageJson: (contents: string, repoName: string) => string;
4
- export declare const replaceTsconfig: (contents: string, repoName: string, isMonoRepo: boolean) => string;
5
- export declare const tryConfigureTsConfigForESM: PatchFunction;
6
- export declare const configureTsConfigForESM: PatchFunction;
@@ -1,249 +0,0 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
- var configureTsConfigForESM_exports = {};
30
- __export(configureTsConfigForESM_exports, {
31
- addJestModuleNameMapper: () => addJestModuleNameMapper,
32
- configureTsConfigForESM: () => configureTsConfigForESM,
33
- replacePackageJson: () => replacePackageJson,
34
- replaceTsconfig: () => replaceTsconfig,
35
- tryConfigureTsConfigForESM: () => tryConfigureTsConfigForESM
36
- });
37
- module.exports = __toCommonJS(configureTsConfigForESM_exports);
38
- var import_util = require("util");
39
- var import_fast_glob = require("fast-glob");
40
- var import_fs_extra = __toESM(require("fs-extra"));
41
- var import_zod = require("zod");
42
- var import__ = require("../../../../../../index.js");
43
- var import_logging = require("../../../../../../utils/logging.js");
44
- const packageJsonSchema = import_zod.z.object({
45
- imports: import_zod.z.record(import_zod.z.record(import_zod.z.string())).optional()
46
- }).passthrough();
47
- const tsConfigSchema = import_zod.z.object({
48
- compilerOptions: import_zod.z.object({
49
- customConditions: import_zod.z.array(import_zod.z.string()).optional(),
50
- rootDir: import_zod.z.string().optional(),
51
- paths: import_zod.z.record(import_zod.z.unknown()).optional()
52
- }).passthrough().optional()
53
- }).passthrough();
54
- const getRepoName = async () => {
55
- try {
56
- const dir = process.cwd();
57
- const { repo } = await import__.Git.getOwnerAndRepo({ dir });
58
- return repo;
59
- } catch (error) {
60
- import_logging.log.warn(`Error getting repository information: ${String(error)}`);
61
- throw error;
62
- }
63
- };
64
- const fetchFiles = async (files) => Promise.all(
65
- files.map(async (file) => {
66
- const contents = await import_fs_extra.default.promises.readFile(file, "utf8");
67
- return {
68
- file,
69
- contents
70
- };
71
- })
72
- );
73
- const formatModuleNameMapper = (subfolderPaths) => subfolderPaths.map((subfolderPath) => `<rootDir>/${subfolderPath}/src`);
74
- const isTypeScriptJestConfig = (contents) => contents.includes("Jest.mergePreset") || contents.includes("export default") || contents.includes("import");
75
- const addModuleNameMapperToTypeScript = (contents, moduleNameMapper) => {
76
- const moduleNameMapperStr = JSON.stringify(moduleNameMapper, null, 2).split("\n").map((line, index) => index === 0 ? line : ` ${line}`).join("\n");
77
- const mergePresetRegex = /(Jest\.mergePreset\(\s*\{)/;
78
- const match = mergePresetRegex.exec(contents);
79
- if (match?.index !== void 0) {
80
- const insertIndex = match.index + match[0].length;
81
- const before = contents.slice(0, insertIndex);
82
- const after = contents.slice(insertIndex);
83
- return `${before}
84
- moduleNameMapper: ${moduleNameMapperStr},${after}`;
85
- }
86
- return contents;
87
- };
88
- const addJestModuleNameMapper = (contents, subfolderPaths) => {
89
- const formattedNames = formatModuleNameMapper(subfolderPaths);
90
- const formattedNamesWithPath = formattedNames.map((name) => `${name}/$1`);
91
- const moduleNameMapper = {
92
- "^(\\.{1,2}/.*)\\.js$": "$1",
93
- "^#src$": formattedNames,
94
- "^#src/(.*)\\.js$": formattedNamesWithPath,
95
- "^#src/(.*)$": formattedNamesWithPath
96
- };
97
- if (isTypeScriptJestConfig(contents)) {
98
- return addModuleNameMapperToTypeScript(contents, moduleNameMapper);
99
- }
100
- try {
101
- const parseResult = packageJsonSchema.safeParse(JSON.parse(contents));
102
- if (!parseResult.success) {
103
- import_logging.log.warn(
104
- `Failed to parse Jest config as JSON: ${parseResult.error.message}`
105
- );
106
- return contents;
107
- }
108
- const jestConfig = parseResult.data;
109
- jestConfig.moduleNameMapper = moduleNameMapper;
110
- return JSON.stringify(jestConfig, null, 2);
111
- } catch (error) {
112
- import_logging.log.warn(`Failed to parse Jest config: ${String(error)}`);
113
- return contents;
114
- }
115
- };
116
- const replacePackageJson = (contents, repoName) => {
117
- try {
118
- const parseResult = packageJsonSchema.safeParse(JSON.parse(contents));
119
- if (!parseResult.success) {
120
- import_logging.log.warn(`Failed to parse package.json: ${parseResult.error.message}`);
121
- return contents;
122
- }
123
- const packageJson = parseResult.data;
124
- packageJson.imports = {
125
- ...packageJson.imports ?? {},
126
- "#src/*": {
127
- [`@seek/${repoName}/source`]: "./src/*",
128
- default: "./lib/*"
129
- }
130
- };
131
- return JSON.stringify(packageJson, null, 2);
132
- } catch (error) {
133
- import_logging.log.warn(`Failed to parse package.json as JSON: ${String(error)}`);
134
- return contents;
135
- }
136
- };
137
- const replaceTsconfig = (contents, repoName, isMonoRepo) => {
138
- try {
139
- const jsonWithNoComments = contents.replace(/\/\/.*|\/\*[\s\S]*?\*\//g, "").trim();
140
- const parseResult = tsConfigSchema.safeParse(
141
- JSON.parse(jsonWithNoComments)
142
- );
143
- if (!parseResult.success) {
144
- import_logging.log.warn(`Failed to parse tsconfig.json: ${parseResult.error.message}`);
145
- return contents;
146
- }
147
- const tsconfigJson = parseResult.data;
148
- if (typeof tsconfigJson.extends === "string" && !tsconfigJson.extends.startsWith("skuba/")) {
149
- import_logging.log.subtle(
150
- "Skipping tsconfig.json that does not extend skuba/config/tsconfig.json"
151
- );
152
- return contents;
153
- }
154
- if (!tsconfigJson.compilerOptions || typeof tsconfigJson.compilerOptions !== "object") {
155
- tsconfigJson.compilerOptions = {};
156
- }
157
- const compilerOptions = tsconfigJson.compilerOptions;
158
- if (compilerOptions.paths !== void 0 && !isMonoRepo) {
159
- delete compilerOptions.paths;
160
- }
161
- compilerOptions.customConditions ??= [];
162
- if (compilerOptions.customConditions.includes(`@seek/${repoName}/source`)) {
163
- import_logging.log.subtle(
164
- "Custom condition mapping already exists in tsconfig.json, skipping"
165
- );
166
- return contents;
167
- }
168
- compilerOptions.customConditions = [`@seek/${repoName}/source`];
169
- compilerOptions.rootDir ??= ".";
170
- return JSON.stringify(tsconfigJson, null, 2);
171
- } catch (error) {
172
- import_logging.log.warn(`Failed to parse tsconfig.json as JSON: ${String(error)}`);
173
- return contents;
174
- }
175
- };
176
- const tryConfigureTsConfigForESM = async ({
177
- mode
178
- }) => {
179
- const packageJsonPatterns = ["**/package.*json"];
180
- const tsconfigJsonPatterns = ["**/tsconfig.*json"];
181
- const jestConfigPatterns = ["**/jest.config.*ts"];
182
- const globOptions = {
183
- ignore: ["**/node_modules/**", "**/tsconfig.build.json"]
184
- };
185
- const [packageJsonFiles, tsconfigJsonFiles, jestConfigFiles] = await Promise.all([
186
- fetchFiles(await (0, import_fast_glob.glob)(packageJsonPatterns, globOptions)),
187
- fetchFiles(await (0, import_fast_glob.glob)(tsconfigJsonPatterns, globOptions)),
188
- fetchFiles(await (0, import_fast_glob.glob)(jestConfigPatterns, globOptions))
189
- ]);
190
- const subfolderPaths = packageJsonFiles.map(({ file }) => file.split("/").slice(0, -1).join("/")).filter((path) => path !== "");
191
- const repoName = await getRepoName();
192
- if (!repoName) {
193
- return { result: "skip", reason: "no repository name found" };
194
- }
195
- const replacedPackageJsonFiles = packageJsonFiles.map(
196
- ({ file, contents }) => ({
197
- file,
198
- before: contents,
199
- after: replacePackageJson(contents, repoName)
200
- })
201
- );
202
- const replacedTsconfigJsonFiles = tsconfigJsonFiles.map(
203
- ({ file, contents }) => ({
204
- file,
205
- before: contents,
206
- after: replaceTsconfig(contents, repoName, subfolderPaths.length > 0)
207
- })
208
- );
209
- const replacedJestConfigFiles = subfolderPaths.length > 0 ? jestConfigFiles.map(({ file, contents }) => ({
210
- file,
211
- before: contents,
212
- after: addJestModuleNameMapper(contents, subfolderPaths)
213
- })) : [];
214
- if (mode === "lint") {
215
- return {
216
- result: "apply"
217
- };
218
- }
219
- await Promise.all(
220
- [
221
- ...replacedPackageJsonFiles,
222
- ...replacedTsconfigJsonFiles.filter(
223
- ({ after }) => typeof after === "string"
224
- ),
225
- ...replacedJestConfigFiles
226
- ].map(async ({ file, after }) => {
227
- await import_fs_extra.default.promises.writeFile(file, after);
228
- })
229
- );
230
- return { result: "apply" };
231
- };
232
- const configureTsConfigForESM = async (config) => {
233
- try {
234
- return await tryConfigureTsConfigForESM(config);
235
- } catch (err) {
236
- import_logging.log.warn("Failed to write configure `tsconfig.json` and `package.json`");
237
- import_logging.log.subtle((0, import_util.inspect)(err));
238
- return { result: "skip", reason: "due to an error" };
239
- }
240
- };
241
- // Annotate the CommonJS export names for ESM import in node:
242
- 0 && (module.exports = {
243
- addJestModuleNameMapper,
244
- configureTsConfigForESM,
245
- replacePackageJson,
246
- replaceTsconfig,
247
- tryConfigureTsConfigForESM
248
- });
249
- //# sourceMappingURL=configureTsConfigForESM.js.map