@ontrails/adapter-kit 1.0.0-beta.29 → 1.0.0-beta.32

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ontrails/adapter-kit",
3
- "version": "1.0.0-beta.29",
3
+ "version": "1.0.0-beta.32",
4
4
  "description": "Internal adapter authoring kit for Trails metadata, scaffolding, and checks.",
5
5
  "files": [
6
6
  "src/**/*.ts",
@@ -19,5 +19,8 @@
19
19
  "typecheck": "tsc --noEmit",
20
20
  "lint": "oxlint ./src",
21
21
  "clean": "rm -rf dist *.tsbuildinfo"
22
+ },
23
+ "dependencies": {
24
+ "@ontrails/core": "^1.0.0-beta.32"
22
25
  }
23
26
  }
package/src/catalog.ts CHANGED
@@ -6,15 +6,11 @@
6
6
  * internal tooling package.
7
7
  */
8
8
 
9
- import {
10
- existsSync,
11
- readdirSync,
12
- readFileSync,
13
- realpathSync,
14
- statSync,
15
- } from 'node:fs';
9
+ import { existsSync, readFileSync, realpathSync, statSync } from 'node:fs';
16
10
  import { dirname, join, resolve } from 'node:path';
17
11
 
12
+ import { listWorkspacePackages } from '@ontrails/core';
13
+
18
14
  export const adapterTargetPlacements = ['extracted', 'subpath'] as const;
19
15
 
20
16
  export type AdapterTargetPlacementValue =
@@ -66,16 +62,16 @@ export interface AdapterTargetCatalog {
66
62
  readonly targets: readonly AdapterTargetCatalogEntry[];
67
63
  }
68
64
 
69
- interface RootManifest {
70
- readonly workspaces?: unknown;
71
- }
72
-
73
65
  export interface AdapterTargetPackageManifest {
74
66
  readonly exports?: unknown;
75
67
  readonly name?: unknown;
76
68
  readonly trails?: unknown;
77
69
  }
78
70
 
71
+ type NamedAdapterTargetPackageManifest = AdapterTargetPackageManifest & {
72
+ readonly name: string;
73
+ };
74
+
79
75
  export interface AdapterTargetParseContext {
80
76
  readonly blockedExportSpecifiers: readonly string[];
81
77
  readonly exportTargets: Readonly<Record<string, string>>;
@@ -181,14 +177,6 @@ const localDeclarationKind = (
181
177
  return typeDeclarationPattern.test(code) ? 'type' : undefined;
182
178
  };
183
179
 
184
- const readJson = <T>(path: string): T | undefined => {
185
- try {
186
- return JSON.parse(readFileSync(path, 'utf8')) as T;
187
- } catch {
188
- return undefined;
189
- }
190
- };
191
-
192
180
  const maskDeadSourceText = (
193
181
  source: string,
194
182
  options: { strings: boolean }
@@ -414,44 +402,6 @@ const exportedLocalBindingKind = (
414
402
  return importSpecifier ? resolveImportKind(importSpecifier) : undefined;
415
403
  };
416
404
 
417
- const workspacePatternsFromManifest = (
418
- manifest: RootManifest | undefined
419
- ): readonly string[] => {
420
- const { workspaces } = manifest ?? {};
421
- if (Array.isArray(workspaces)) {
422
- return workspaces.filter(
423
- (pattern): pattern is string => typeof pattern === 'string'
424
- );
425
- }
426
-
427
- const packages = isRecord(workspaces) ? workspaces['packages'] : undefined;
428
- return Array.isArray(packages)
429
- ? packages.filter(
430
- (pattern): pattern is string => typeof pattern === 'string'
431
- )
432
- : [];
433
- };
434
-
435
- const workspaceDirsForPattern = (
436
- rootDir: string,
437
- pattern: string
438
- ): readonly string[] => {
439
- if (!pattern.endsWith('/*')) {
440
- const workspaceDir = join(rootDir, pattern);
441
- return existsSync(workspaceDir) ? [workspaceDir] : [];
442
- }
443
-
444
- const groupDir = join(rootDir, pattern.slice(0, -2));
445
- if (!existsSync(groupDir)) {
446
- return [];
447
- }
448
-
449
- return readdirSync(groupDir, { withFileTypes: true })
450
- .filter((entry) => entry.isDirectory())
451
- .map((entry) => join(groupDir, entry.name))
452
- .toSorted();
453
- };
454
-
455
405
  const exportConditions = new Set([
456
406
  'bun',
457
407
  'node',
@@ -1401,40 +1351,27 @@ export const parseAdapterTargetsFromManifest = (
1401
1351
  export const deriveAdapterTargetCatalog = (
1402
1352
  rootDir: string
1403
1353
  ): AdapterTargetCatalog => {
1404
- const normalizedRoot = normalizeRealPath(rootDir);
1405
- const rootManifest = readJson<RootManifest>(
1406
- join(normalizedRoot, 'package.json')
1407
- );
1408
1354
  const diagnostics: AdapterTargetCatalogDiagnostic[] = [];
1409
1355
  const targets: AdapterTargetCatalogEntry[] = [];
1410
1356
 
1411
- for (const pattern of workspacePatternsFromManifest(rootManifest)) {
1412
- for (const workspaceDir of workspaceDirsForPattern(
1413
- normalizedRoot,
1414
- pattern
1415
- )) {
1416
- const packageJsonPath = join(workspaceDir, 'package.json');
1417
- const manifest = readJson<AdapterTargetPackageManifest>(packageJsonPath);
1418
- if (!manifest || typeof manifest.name !== 'string') {
1419
- continue;
1420
- }
1421
-
1422
- const packageRoot = normalizeRealPath(dirname(packageJsonPath));
1423
- const normalizedExports = normalizeExportTargets(
1424
- packageRoot,
1425
- manifest.name,
1426
- manifest.exports
1427
- );
1428
- const parsed = parseAdapterTargetsFromManifest(manifest, {
1429
- blockedExportSpecifiers: normalizedExports.blocked,
1430
- exportTargets: normalizedExports.targets,
1431
- packageJsonPath: normalizeRealPath(packageJsonPath),
1432
- packageName: manifest.name,
1433
- packageRoot,
1434
- });
1435
- diagnostics.push(...parsed.diagnostics);
1436
- targets.push(...parsed.targets);
1437
- }
1357
+ for (const workspacePackage of listWorkspacePackages<NamedAdapterTargetPackageManifest>(
1358
+ rootDir
1359
+ )) {
1360
+ const { manifest, packageJsonPath, packageRoot } = workspacePackage;
1361
+ const normalizedExports = normalizeExportTargets(
1362
+ packageRoot,
1363
+ manifest.name,
1364
+ manifest.exports
1365
+ );
1366
+ const parsed = parseAdapterTargetsFromManifest(manifest, {
1367
+ blockedExportSpecifiers: normalizedExports.blocked,
1368
+ exportTargets: normalizedExports.targets,
1369
+ packageJsonPath,
1370
+ packageName: manifest.name,
1371
+ packageRoot,
1372
+ });
1373
+ diagnostics.push(...parsed.diagnostics);
1374
+ targets.push(...parsed.targets);
1438
1375
  }
1439
1376
 
1440
1377
  const sortedTargets = targets.toSorted((left, right) =>
package/src/check.ts CHANGED
@@ -14,6 +14,12 @@ import {
14
14
  } from 'node:fs';
15
15
  import { dirname, join, relative, resolve } from 'node:path';
16
16
 
17
+ import { escapeRegExp, listWorkspacePackages } from '@ontrails/core';
18
+ import type {
19
+ DiagnosticBase,
20
+ WorkspacePackage as CoreWorkspacePackage,
21
+ } from '@ontrails/core';
22
+
17
23
  import { deriveAdapterTargetCatalog } from './catalog.js';
18
24
  import type {
19
25
  AdapterTargetCatalog,
@@ -33,15 +39,14 @@ export type AdapterCheckDiagnosticCode =
33
39
  | 'unknown-adapter-target'
34
40
  | 'unsupported-placement';
35
41
 
36
- export type AdapterCheckDiagnosticSeverity = 'error' | 'warn';
42
+ export type AdapterCheckDiagnosticSeverity = DiagnosticBase['severity'];
37
43
 
38
- export interface AdapterCheckDiagnostic {
44
+ export interface AdapterCheckDiagnostic extends DiagnosticBase<AdapterCheckDiagnosticCode> {
39
45
  readonly code: AdapterCheckDiagnosticCode;
40
46
  readonly message: string;
41
47
  readonly packageJsonPath: string;
42
48
  readonly packageName?: string | undefined;
43
49
  readonly placement?: AdapterTargetPlacement | undefined;
44
- readonly severity: AdapterCheckDiagnosticSeverity;
45
50
  readonly target?: string | undefined;
46
51
  }
47
52
 
@@ -93,10 +98,6 @@ export interface AdapterCheckReport {
93
98
  readonly targets: readonly AdapterTargetCatalogEntry[];
94
99
  }
95
100
 
96
- interface RootManifest {
97
- readonly workspaces?: unknown;
98
- }
99
-
100
101
  interface AdapterCheckPackageManifest {
101
102
  readonly dependencies?: unknown;
102
103
  readonly devDependencies?: unknown;
@@ -107,12 +108,7 @@ interface AdapterCheckPackageManifest {
107
108
  readonly trails?: unknown;
108
109
  }
109
110
 
110
- interface WorkspacePackage {
111
- readonly manifest: AdapterCheckPackageManifest;
112
- readonly packageJsonPath: string;
113
- readonly packageRoot: string;
114
- readonly workspacePath: string;
115
- }
111
+ type WorkspacePackage = CoreWorkspacePackage<AdapterCheckPackageManifest>;
116
112
 
117
113
  interface AdapterMetadata {
118
114
  readonly target: string;
@@ -135,84 +131,8 @@ const normalizeRealPath = (path: string): string => {
135
131
  }
136
132
  };
137
133
 
138
- const readJson = <T>(path: string): T | undefined => {
139
- try {
140
- return JSON.parse(readFileSync(path, 'utf8')) as T;
141
- } catch {
142
- return undefined;
143
- }
144
- };
145
-
146
- const workspacePatternsFromManifest = (
147
- manifest: RootManifest | undefined
148
- ): readonly string[] => {
149
- const { workspaces } = manifest ?? {};
150
- if (Array.isArray(workspaces)) {
151
- return workspaces.filter(
152
- (pattern): pattern is string => typeof pattern === 'string'
153
- );
154
- }
155
-
156
- const packages = isRecord(workspaces) ? workspaces['packages'] : undefined;
157
- return Array.isArray(packages)
158
- ? packages.filter(
159
- (pattern): pattern is string => typeof pattern === 'string'
160
- )
161
- : [];
162
- };
163
-
164
- const workspaceDirsForPattern = (
165
- rootDir: string,
166
- pattern: string
167
- ): readonly string[] => {
168
- if (!pattern.endsWith('/*')) {
169
- const workspaceDir = join(rootDir, pattern);
170
- return existsSync(workspaceDir) ? [workspaceDir] : [];
171
- }
172
-
173
- const groupDir = join(rootDir, pattern.slice(0, -2));
174
- if (!existsSync(groupDir)) {
175
- return [];
176
- }
177
-
178
- return readdirSync(groupDir, { withFileTypes: true })
179
- .filter((entry) => entry.isDirectory())
180
- .map((entry) => join(groupDir, entry.name))
181
- .toSorted();
182
- };
183
-
184
- const workspacePackages = (rootDir: string): readonly WorkspacePackage[] => {
185
- const normalizedRoot = normalizeRealPath(rootDir);
186
- const rootManifest = readJson<RootManifest>(
187
- join(normalizedRoot, 'package.json')
188
- );
189
- const packages: WorkspacePackage[] = [];
190
-
191
- for (const pattern of workspacePatternsFromManifest(rootManifest)) {
192
- for (const workspaceDir of workspaceDirsForPattern(
193
- normalizedRoot,
194
- pattern
195
- )) {
196
- const packageJsonPath = join(workspaceDir, 'package.json');
197
- const manifest = readJson<AdapterCheckPackageManifest>(packageJsonPath);
198
- if (!manifest || typeof manifest.name !== 'string') {
199
- continue;
200
- }
201
-
202
- const packageRoot = normalizeRealPath(dirname(packageJsonPath));
203
- packages.push({
204
- manifest,
205
- packageJsonPath: normalizeRealPath(packageJsonPath),
206
- packageRoot,
207
- workspacePath: normalizePath(relative(normalizedRoot, packageRoot)),
208
- });
209
- }
210
- }
211
-
212
- return packages.toSorted((left, right) =>
213
- left.workspacePath.localeCompare(right.workspacePath)
214
- );
215
- };
134
+ const workspacePackages = (rootDir: string): readonly WorkspacePackage[] =>
135
+ listWorkspacePackages<AdapterCheckPackageManifest>(rootDir);
216
136
 
217
137
  const resolveExportTarget = (
218
138
  target: unknown,
@@ -433,9 +353,6 @@ const collectSourceFiles = (dir: string): readonly string[] => {
433
353
  return files.toSorted();
434
354
  };
435
355
 
436
- const escapeRegExp = (value: string): string =>
437
- value.replaceAll(/[.*+?^${}()|[\]\\]/gu, '\\$&');
438
-
439
356
  const isIdentifierChar = (char: string | undefined): boolean =>
440
357
  char !== undefined && /[$\w]/u.test(char);
441
358