plumb-fhir 0.6.2 → 0.8.0
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/CHANGELOG.md +24 -0
- package/README.md +76 -2
- package/dist/cjs/check.d.ts +89 -0
- package/dist/cjs/check.d.ts.map +1 -0
- package/dist/cjs/commands.d.ts +3 -0
- package/dist/cjs/commands.d.ts.map +1 -1
- package/dist/cjs/config.d.ts +12 -1
- package/dist/cjs/config.d.ts.map +1 -1
- package/dist/cjs/emit/print.d.ts.map +1 -1
- package/dist/cjs/index.cjs +38 -2
- package/dist/cjs/index.cjs.map +3 -3
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/esm/check.d.ts +89 -0
- package/dist/esm/check.d.ts.map +1 -0
- package/dist/esm/cli.mjs +3097 -2747
- package/dist/esm/cli.mjs.map +4 -4
- package/dist/esm/commands.d.ts +3 -0
- package/dist/esm/commands.d.ts.map +1 -1
- package/dist/esm/config.d.ts +12 -1
- package/dist/esm/config.d.ts.map +1 -1
- package/dist/esm/emit/print.d.ts.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.mjs +38 -2
- package/dist/esm/index.mjs.map +3 -3
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.8.0 (2026-10-05)
|
|
4
|
+
|
|
5
|
+
- **`plumb check`** reports every `MedplumClient` read or write of a type a
|
|
6
|
+
selected profile fully holds that goes around `readProfiled`,
|
|
7
|
+
`searchProfiled`, `createProfiled`, `updateProfiled` or `stampProfiled`,
|
|
8
|
+
by the types the compiler infers, so an inferred write is found as surely as
|
|
9
|
+
a literal one. A committed baseline lets a project adopt it with a backlog:
|
|
10
|
+
only new or grown findings fail. `// plumb-check: <reason>` marks a
|
|
11
|
+
deliberate exception. It needs the project's TypeScript 5 or 6 (design 07).
|
|
12
|
+
- **`stampProfiled` returns its resource branded** (`T & Stamped`, an optional
|
|
13
|
+
unique-symbol property), which `check` reads to accept a stamped write
|
|
14
|
+
through a variable. Callers see no difference.
|
|
15
|
+
- `check` in the config: `tsconfig`, `baseline` and `ignore`.
|
|
16
|
+
|
|
17
|
+
## 0.7.0 (2026-10-05)
|
|
18
|
+
|
|
19
|
+
- **`stampProfiled(resource, options?)`** returns the copy `createProfiled`
|
|
20
|
+
would write, routed and stamped, without writing it: for conditional
|
|
21
|
+
creates, upserts and batch or transaction entries. It takes the same
|
|
22
|
+
options, is typed the same way, and throws the same `RoutingError` (#124).
|
|
23
|
+
- The README says `updateProfiled` stamps a record that was unstamped, so
|
|
24
|
+
edits of stored records that fail the profile start being refused; and to
|
|
25
|
+
commit `fsh-generated/resources/` but gitignore SUSHI's index files (#125).
|
|
26
|
+
|
|
3
27
|
## 0.6.2 (2026-10-05)
|
|
4
28
|
|
|
5
29
|
`validate` and `push` from an installed Plumb, and on Medplum's `awslambda`
|
package/README.md
CHANGED
|
@@ -185,8 +185,11 @@ export default defineConfig({
|
|
|
185
185
|
✔ sushi 1 StructureDefinitions, 0 ValueSets 6.8s
|
|
186
186
|
```
|
|
187
187
|
|
|
188
|
-
- **Commit `fsh-generated/`** with the FSH. It is the JSON `push`
|
|
189
|
-
Medplum, and `validateProfiled` reads it without running SUSHI.
|
|
188
|
+
- **Commit `fsh-generated/resources/`** with the FSH. It is the JSON `push`
|
|
189
|
+
loads into Medplum, and `validateProfiled` reads it without running SUSHI.
|
|
190
|
+
SUSHI's own `fsh-index.txt` and `data/` are bookkeeping no command reads:
|
|
191
|
+
gitignore them. Marking the generated folders `linguist-generated` in
|
|
192
|
+
`.gitattributes` collapses them in review diffs.
|
|
190
193
|
- **`generate --check` in CI** rebuilds the FSH into a temporary folder and
|
|
191
194
|
fails when the committed `fsh-generated/` or the types differ from it.
|
|
192
195
|
- **SUSHI's errors stop `generate`**, with their FSH file and line. Its
|
|
@@ -240,6 +243,22 @@ const saved = await createProfiled(medplum, bp); // stamped, then medplum.create
|
|
|
240
243
|
- They take any client with `createResource` and `updateResource`, such as
|
|
241
244
|
a `MedplumClient`, so the generated code needs nothing from Plumb at run
|
|
242
245
|
time.
|
|
246
|
+
- **`stampProfiled(resource, options?)`** returns the copy `createProfiled`
|
|
247
|
+
would write, stamped and not written, for the writes it cannot make: a
|
|
248
|
+
conditional create, an upsert, a batch or transaction entry. It takes the
|
|
249
|
+
same options and throws the same `RoutingError`:
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
await medplum.createResourceIfNoneExist(
|
|
253
|
+
stampProfiled(coverage, { profile: USCoreCoverageProfileUrl }),
|
|
254
|
+
`identifier=${system}|${value}`,
|
|
255
|
+
);
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
- **Moving an edit path to `updateProfiled` stamps records that were
|
|
259
|
+
unstamped**, so the server starts holding them to the profile: an edit of a
|
|
260
|
+
stored record that does not meet it is refused from then on. Run
|
|
261
|
+
`plumb validate` and fix what fails before moving edit paths.
|
|
243
262
|
|
|
244
263
|
**Keys come from each profile:** every fixed or pattern value on a required
|
|
245
264
|
first-level element (a pinned `code`), and every required slice's
|
|
@@ -360,6 +379,61 @@ read would refuse. History is not offered typed: an old version may predate
|
|
|
360
379
|
its stamp, so read it with `medplum.readHistory` and `asProfiled` it if you
|
|
361
380
|
must.
|
|
362
381
|
|
|
382
|
+
## Find code that goes around Plumb
|
|
383
|
+
|
|
384
|
+
The profiled reads and writes only help where they are called. `plumb check`
|
|
385
|
+
reads your code the way the compiler does and reports every `MedplumClient`
|
|
386
|
+
read or write of a profiled type that does not go through them, including a
|
|
387
|
+
write whose type is only inferred:
|
|
388
|
+
|
|
389
|
+
```ts
|
|
390
|
+
export default defineConfig({
|
|
391
|
+
// …igs, profiles, out
|
|
392
|
+
check: {
|
|
393
|
+
tsconfig: ['apps/web/tsconfig.json'],
|
|
394
|
+
baseline: './plumb-check-baseline.json',
|
|
395
|
+
ignore: ['**/*.test.ts', '**/*.stories.tsx'],
|
|
396
|
+
},
|
|
397
|
+
});
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
```bash
|
|
401
|
+
npx plumb check
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
```text
|
|
405
|
+
plumb check
|
|
406
|
+
✖ check 2 new, 248 in the baseline, in 2767 files 6.2s
|
|
407
|
+
apps/web/src/lib/goals/goal.ts:41:10 readResource Goal → readProfiled
|
|
408
|
+
apps/web/src/lib/coverage/save.ts:90:5 createResource Coverage → createProfiled, updateProfiled or stampProfiled
|
|
409
|
+
Failed in 6.2s
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
- **What it reports:** `readResource`, `searchResources`, `searchOne`,
|
|
413
|
+
`searchResourcePages`, `createResource`, `updateResource`, `upsertResource`
|
|
414
|
+
and `createResourceIfNoneExist` on a `MedplumClient` (or a class deriving
|
|
415
|
+
from it), for a type every resource of which a selected profile holds: one
|
|
416
|
+
with a profile that routes on no keys, or a `defaultProfile`. A type whose
|
|
417
|
+
profiles are keyed on content (one code of Observation) is not reported, and
|
|
418
|
+
neither is `string` or `ResourceType`.
|
|
419
|
+
- **A stamped write passes,** through a variable too: `stampProfiled` returns
|
|
420
|
+
its resource branded, and `check` reads the brand from the type.
|
|
421
|
+
- **A deliberate exception** takes a comment with a reason on the line before:
|
|
422
|
+
`// plumb-check: the backfill reads unstamped records to stamp them`.
|
|
423
|
+
- **The baseline** is a committed count per file, method and type. `check`
|
|
424
|
+
fails only when a count grows or a new one appears, so new raw access is
|
|
425
|
+
refused at once while the backlog shrinks. `--update-baseline` records
|
|
426
|
+
fixes; it refuses growth unless `--allow-growth` is given.
|
|
427
|
+
- **Paths** in the output, the baseline and `ignore` are relative to the
|
|
428
|
+
deepest folder holding the config and every tsconfig, so a monorepo's config
|
|
429
|
+
in one package checks code in another.
|
|
430
|
+
- **TypeScript:** `check` compiles with your project's own `typescript`, which
|
|
431
|
+
needs its compiler API: TypeScript 5 or 6. TypeScript 7's native package has
|
|
432
|
+
none yet, and `check` exits 2 on it.
|
|
433
|
+
|
|
434
|
+
Exit codes: 0 when nothing is new, 1 when something is (or the baseline would
|
|
435
|
+
grow), 2 for usage, config and set-up errors.
|
|
436
|
+
|
|
363
437
|
## Check stored data, then load profiles
|
|
364
438
|
|
|
365
439
|
Medplum validates a resource when it is written, and never again. Tightening a
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type * as TS from 'typescript5';
|
|
2
|
+
import type { PlumbConfig } from './config.js';
|
|
3
|
+
import { type Route } from './emit/routes.js';
|
|
4
|
+
/** A `MedplumClient` read or write of a profiled type that goes around Plumb. */
|
|
5
|
+
export interface Finding {
|
|
6
|
+
/** Relative to the config's folder, with forward slashes. */
|
|
7
|
+
file: string;
|
|
8
|
+
line: number;
|
|
9
|
+
column: number;
|
|
10
|
+
method: string;
|
|
11
|
+
/** The profiled resource types the call can touch, sorted. */
|
|
12
|
+
resourceTypes: string[];
|
|
13
|
+
/** What to call instead, or why the finding stands. */
|
|
14
|
+
instead: string;
|
|
15
|
+
}
|
|
16
|
+
export interface FindOptions {
|
|
17
|
+
/** The project's TypeScript module, with its compiler API. */
|
|
18
|
+
ts: typeof TS;
|
|
19
|
+
/** The folder findings are relative to, and `ignore` is matched from. */
|
|
20
|
+
base: string;
|
|
21
|
+
tsconfig: string[];
|
|
22
|
+
/** Resource types a selected profile constrains. */
|
|
23
|
+
profiledTypes: ReadonlySet<string>;
|
|
24
|
+
/** The generated folder, never checked. */
|
|
25
|
+
out: string;
|
|
26
|
+
ignore?: string[];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Compiles each project and reports every raw `MedplumClient` read or write of
|
|
30
|
+
* a profiled type, with the type the checker infers, not the text written.
|
|
31
|
+
*/
|
|
32
|
+
export declare function findRawAccess(options: FindOptions): {
|
|
33
|
+
findings: Finding[];
|
|
34
|
+
files: number;
|
|
35
|
+
};
|
|
36
|
+
/** Accepted findings, counted per file, method and resource types. */
|
|
37
|
+
export type Baseline = Record<string, number>;
|
|
38
|
+
export declare function countFindings(findings: Finding[]): Baseline;
|
|
39
|
+
export interface BaselineComparison {
|
|
40
|
+
/** Findings under a key that is new or grew: every one of them, since a line cannot be told apart. */
|
|
41
|
+
fresh: Finding[];
|
|
42
|
+
/** How many findings the baseline accepts that are now gone. */
|
|
43
|
+
fixed: number;
|
|
44
|
+
/** Findings the baseline accepts. */
|
|
45
|
+
accepted: number;
|
|
46
|
+
}
|
|
47
|
+
/** A finding fails only where its key's count exceeds the baseline's. */
|
|
48
|
+
export declare function compareBaseline(findings: Finding[], baseline: Baseline): BaselineComparison;
|
|
49
|
+
export interface CheckResult {
|
|
50
|
+
ok: boolean;
|
|
51
|
+
findings: Finding[];
|
|
52
|
+
comparison: BaselineComparison;
|
|
53
|
+
files: number;
|
|
54
|
+
/** Set when `updateBaseline` wrote the file. */
|
|
55
|
+
baselineWritten?: boolean;
|
|
56
|
+
errors: {
|
|
57
|
+
code: 'no-check-config' | 'no-compiler-api' | 'no-lock' | 'baseline-growth';
|
|
58
|
+
message: string;
|
|
59
|
+
}[];
|
|
60
|
+
}
|
|
61
|
+
export interface CheckOptions {
|
|
62
|
+
config: PlumbConfig;
|
|
63
|
+
configPath: string;
|
|
64
|
+
/** The project's TypeScript; resolved from the config's folder by default. */
|
|
65
|
+
ts?: typeof TS;
|
|
66
|
+
cacheDir?: string;
|
|
67
|
+
updateBaseline?: boolean;
|
|
68
|
+
allowGrowth?: boolean;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* `plumb check`: loads the selected profiles for the types they constrain,
|
|
72
|
+
* compiles the configured projects, and compares what it finds with the
|
|
73
|
+
* baseline, or rewrites the baseline.
|
|
74
|
+
*/
|
|
75
|
+
export declare function checkProject(options: CheckOptions): Promise<CheckResult>;
|
|
76
|
+
/**
|
|
77
|
+
* The folder findings and `ignore` globs are relative to: the deepest one
|
|
78
|
+
* holding the config and every tsconfig, so a monorepo's config in one package
|
|
79
|
+
* checks code in another, and baseline keys do not depend on where it runs.
|
|
80
|
+
*/
|
|
81
|
+
export declare function checkRoot(configPath: string, tsconfig: string[]): string;
|
|
82
|
+
/**
|
|
83
|
+
* The types every resource of which a selected profile holds: one with a
|
|
84
|
+
* profile that routes on no keys, or a `defaultProfile`. A profile keyed on
|
|
85
|
+
* content (one code of Observation) holds only some, so raw access to the type
|
|
86
|
+
* is not wrong and is not reported.
|
|
87
|
+
*/
|
|
88
|
+
export declare function enforcedTypes(routes: Record<string, Route[]>, defaultProfile?: Record<string, string[]>): Set<string>;
|
|
89
|
+
//# sourceMappingURL=check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/check.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,KAAK,KAAK,EAAe,MAAM,kBAAkB,CAAC;AAI3D,iFAAiF;AACjF,MAAM,WAAW,OAAO;IACtB,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;CACjB;AAiBD,MAAM,WAAW,WAAW;IAC1B,8DAA8D;IAC9D,EAAE,EAAE,OAAO,EAAE,CAAC;IACd,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,oDAAoD;IACpD,aAAa,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACnC,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG;IAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAe1F;AAoHD,sEAAsE;AACtE,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAI9C,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,QAAQ,CAI3D;AAED,MAAM,WAAW,kBAAkB;IACjC,sGAAsG;IACtG,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,yEAAyE;AACzE,wBAAgB,eAAe,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,QAAQ,GAAG,kBAAkB,CAS3F;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,UAAU,EAAE,kBAAkB,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,MAAM,EAAE;QACN,IAAI,EAAE,iBAAiB,GAAG,iBAAiB,GAAG,SAAS,GAAG,iBAAiB,CAAC;QAC5E,OAAO,EAAE,MAAM,CAAC;KACjB,EAAE,CAAC;CACL;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,8EAA8E;IAC9E,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CA2D9E;AAeD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAQxE;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,EAC/B,cAAc,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAM,GAC5C,GAAG,CAAC,MAAM,CAAC,CAKb"}
|
package/dist/cjs/commands.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type * as TS from 'typescript5';
|
|
1
2
|
import { type Checked } from './conformance.js';
|
|
2
3
|
import { type Step } from './generate.js';
|
|
3
4
|
export interface CliIo {
|
|
@@ -9,6 +10,8 @@ export interface CliIo {
|
|
|
9
10
|
stderr: (text: string) => void;
|
|
10
11
|
cacheDir?: string;
|
|
11
12
|
fetch?: typeof globalThis.fetch;
|
|
13
|
+
/** The TypeScript `check` compiles with; the project's own by default. */
|
|
14
|
+
typescript?: typeof TS;
|
|
12
15
|
}
|
|
13
16
|
/** What a step did, as one line: its name, its counts and its time. */
|
|
14
17
|
export declare function formatStep(step: Step, out: string): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/commands.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/commands.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAGvC,OAAO,EACL,KAAK,OAAO,EAIb,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAiC,KAAK,IAAI,EAAE,MAAM,eAAe,CAAC;AAGzE,MAAM,WAAW,KAAK;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACxC,6DAA6D;IAC7D,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC,0EAA0E;IAC1E,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC;CACxB;AA+DD,uEAAuE;AACvE,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAe1D;AAED,2EAA2E;AAC3E,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAwBpE;AA8KD,KAAK,KAAK,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,CAAC,CAAC;AAIjD,kGAAkG;AAClG,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,KAAK,GAAG,MAAM,EAAE,CAexD"}
|
package/dist/cjs/config.d.ts
CHANGED
|
@@ -36,6 +36,17 @@ export interface PlumbConfig {
|
|
|
36
36
|
defaultProfile?: Record<string, string[]>;
|
|
37
37
|
/** What `push` writes to each environment's project besides its profiles. */
|
|
38
38
|
project?: ProjectConfig;
|
|
39
|
+
/** What `plumb check` reads. */
|
|
40
|
+
check?: CheckConfig;
|
|
41
|
+
}
|
|
42
|
+
/** What `plumb check` reads: the project's code, for raw access to profiled types. */
|
|
43
|
+
export interface CheckConfig {
|
|
44
|
+
/** The TypeScript projects to check, each compiled once; a path or several. */
|
|
45
|
+
tsconfig: string | string[];
|
|
46
|
+
/** The committed file of accepted findings; without one, every finding fails. */
|
|
47
|
+
baseline?: string;
|
|
48
|
+
/** Globs, relative to the config, of files not to check (tests, stories). */
|
|
49
|
+
ignore?: string[];
|
|
39
50
|
}
|
|
40
51
|
/**
|
|
41
52
|
* A project's configuration, as a project admin can write it. Policies and
|
|
@@ -94,7 +105,7 @@ export interface ResolvedEnvironment {
|
|
|
94
105
|
clientId: string;
|
|
95
106
|
clientSecret: string;
|
|
96
107
|
}
|
|
97
|
-
export type ConfigErrorCode = 'config-not-found' | 'unsupported-syntax' | 'unresolved-import' | 'no-default-export' | 'unknown-key' | 'missing-out' | 'invalid-type' | 'invalid-ig' | 'unlisted-ig' | 'invalid-profile' | 'invalid-max-codes' | 'invalid-base-url' | 'unknown-environment' | 'missing-variable' | 'invalid-route' | 'unselected-route' | 'invalid-route-element' | 'invalid-default-profile' | 'versioned-url' | 'fsh-and-local' | 'no-sushi-config' | 'invalid-setting' | 'super-admin-field' | 'unknown-access-policy' | 'duplicate-key';
|
|
108
|
+
export type ConfigErrorCode = 'config-not-found' | 'unsupported-syntax' | 'unresolved-import' | 'no-default-export' | 'unknown-key' | 'missing-out' | 'invalid-type' | 'invalid-ig' | 'unlisted-ig' | 'invalid-profile' | 'invalid-max-codes' | 'invalid-base-url' | 'unknown-environment' | 'missing-variable' | 'invalid-route' | 'unselected-route' | 'invalid-route-element' | 'invalid-default-profile' | 'versioned-url' | 'fsh-and-local' | 'no-sushi-config' | 'invalid-setting' | 'super-admin-field' | 'unknown-access-policy' | 'duplicate-key' | 'invalid-check';
|
|
98
109
|
export interface ConfigError {
|
|
99
110
|
code: ConfigErrorCode;
|
|
100
111
|
message: string;
|
package/dist/cjs/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,YAAY,EAEZ,MAAM,EACN,mBAAmB,EACpB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,WAAW;IAC1B,4DAA4D;IAC5D,GAAG,EAAE,MAAM,EAAE,CAAC;IACd;;;OAGG;IACH,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE;QACT,0FAA0F;QAC1F,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,kEAAkE;IAClE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC3C;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,KAAK,CAAC,CAAC;IAC1C;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC1C,6EAA6E;IAC7E,OAAO,CAAC,EAAE,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"print.d.ts","sourceRoot":"","sources":["../../../src/emit/print.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAS,OAAO,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAiB,YAAY,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE5E,uFAAuF;AACvF,eAAO,MAAM,MAAM,0BAA0B,CAAC;AAqG9C,wFAAwF;AACxF,wBAAgB,SAAS,CAAC,CAAC,EAAE,QAAQ,GAAG,MAAM,CAgD7C;
|
|
1
|
+
{"version":3,"file":"print.d.ts","sourceRoot":"","sources":["../../../src/emit/print.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAS,OAAO,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAiB,YAAY,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE5E,uFAAuF;AACvF,eAAO,MAAM,MAAM,0BAA0B,CAAC;AAqG9C,wFAAwF;AACxF,wBAAgB,SAAS,CAAC,CAAC,EAAE,QAAQ,GAAG,MAAM,CAgD7C;AA2WD,KAAK,YAAY,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC,CAAC;AAkR5F,kHAAkH;AAClH,wBAAgB,UAAU,CACxB,MAAM,EAAE,YAAY,EAAE,EACtB,MAAM,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,MAAM,EACvC,OAAO,GAAE,YAAiF,GACzF,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAyBrB"}
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -44,7 +44,8 @@ var KEYS = /* @__PURE__ */ new Set([
|
|
|
44
44
|
"environments",
|
|
45
45
|
"routes",
|
|
46
46
|
"defaultProfile",
|
|
47
|
-
"project"
|
|
47
|
+
"project",
|
|
48
|
+
"check"
|
|
48
49
|
]);
|
|
49
50
|
var ENVIRONMENT_KEYS = ["baseUrl", "clientId", "clientSecret", "settings"];
|
|
50
51
|
var PROJECT_KEYS = ["settings", "secrets", "accessPolicies", "defaultAccessPolicies", "clients"];
|
|
@@ -92,6 +93,7 @@ async function loadConfig(options) {
|
|
|
92
93
|
config: {
|
|
93
94
|
...config,
|
|
94
95
|
out: (0, import_node_path.resolve)(base2, config.out),
|
|
96
|
+
...config.check ? { check: resolveCheck(base2, config.check) } : {},
|
|
95
97
|
...fsh ? { fsh } : {},
|
|
96
98
|
...local ? { local } : {}
|
|
97
99
|
}
|
|
@@ -139,7 +141,8 @@ function check(config) {
|
|
|
139
141
|
...checkEnvironments(record.environments),
|
|
140
142
|
...checkRouteRows(record),
|
|
141
143
|
...checkDefaultProfile(record.defaultProfile),
|
|
142
|
-
...checkProject(record.project)
|
|
144
|
+
...checkProject(record.project),
|
|
145
|
+
...checkCheck(record.check)
|
|
143
146
|
);
|
|
144
147
|
for (const key of ["local", "fsh"]) {
|
|
145
148
|
if (record[key] !== void 0 && typeof record[key] !== "string") {
|
|
@@ -184,6 +187,32 @@ function checkWildcards(record) {
|
|
|
184
187
|
] : [];
|
|
185
188
|
});
|
|
186
189
|
}
|
|
190
|
+
function checkCheck(check2) {
|
|
191
|
+
if (check2 === void 0) return [];
|
|
192
|
+
if (typeof check2 !== "object" || check2 === null || Array.isArray(check2)) {
|
|
193
|
+
return [{ code: "invalid-type", path: "check", message: '"check" must be an object.' }];
|
|
194
|
+
}
|
|
195
|
+
const errors = Object.keys(check2).filter((key) => !["tsconfig", "baseline", "ignore"].includes(key)).map((key) => ({
|
|
196
|
+
code: "unknown-key",
|
|
197
|
+
path: `check.${key}`,
|
|
198
|
+
message: `Unknown config key "check.${key}".`
|
|
199
|
+
}));
|
|
200
|
+
const { tsconfig, baseline, ignore } = check2;
|
|
201
|
+
const strings = (v) => Array.isArray(v) && v.every((x) => typeof x === "string");
|
|
202
|
+
const invalid = (key, expected) => ({
|
|
203
|
+
code: "invalid-check",
|
|
204
|
+
path: `check.${key}`,
|
|
205
|
+
message: `"check.${key}" must be ${expected}.`
|
|
206
|
+
});
|
|
207
|
+
if (!(typeof tsconfig === "string" || strings(tsconfig) && tsconfig.length > 0)) {
|
|
208
|
+
errors.push(invalid("tsconfig", "a tsconfig path, or a list of them"));
|
|
209
|
+
}
|
|
210
|
+
if (baseline !== void 0 && typeof baseline !== "string") {
|
|
211
|
+
errors.push(invalid("baseline", "a path"));
|
|
212
|
+
}
|
|
213
|
+
if (ignore !== void 0 && !strings(ignore)) errors.push(invalid("ignore", "a list of globs"));
|
|
214
|
+
return errors;
|
|
215
|
+
}
|
|
187
216
|
function checkBindings(bindings) {
|
|
188
217
|
if (bindings === void 0) return [];
|
|
189
218
|
if (typeof bindings !== "object" || bindings === null || Array.isArray(bindings)) {
|
|
@@ -453,6 +482,13 @@ function checkClients(clients, checkPolicyKey) {
|
|
|
453
482
|
return errors;
|
|
454
483
|
});
|
|
455
484
|
}
|
|
485
|
+
function resolveCheck(base2, check2) {
|
|
486
|
+
return {
|
|
487
|
+
tsconfig: [check2.tsconfig].flat().map((path) => (0, import_node_path.resolve)(base2, path)),
|
|
488
|
+
...check2.baseline ? { baseline: (0, import_node_path.resolve)(base2, check2.baseline) } : {},
|
|
489
|
+
ignore: check2.ignore ?? []
|
|
490
|
+
};
|
|
491
|
+
}
|
|
456
492
|
|
|
457
493
|
// src/validate.ts
|
|
458
494
|
var import_node_path4 = require("node:path");
|