@thymian/plugin-sampler 0.3.0-canary.20261007-e6cb8dc → 0.3.0-canary.20261007-cdbe1d3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/check-result.d.ts +88 -0
- package/dist/cli/check-result.d.ts.map +1 -0
- package/dist/cli/check-result.js +160 -0
- package/dist/cli/check-result.js.map +1 -0
- package/dist/cli/commands/sampler/check.d.ts +32 -4
- package/dist/cli/commands/sampler/check.d.ts.map +1 -1
- package/dist/cli/commands/sampler/check.js +126 -88
- package/dist/cli/commands/sampler/check.js.map +1 -1
- package/dist/cli/commands/sampler/init.d.ts +4 -6
- package/dist/cli/commands/sampler/init.d.ts.map +1 -1
- package/dist/cli/commands/sampler/init.js +33 -49
- package/dist/cli/commands/sampler/init.js.map +1 -1
- package/dist/cli/commands/sampler/show.d.ts +11 -0
- package/dist/cli/commands/sampler/show.d.ts.map +1 -0
- package/dist/cli/commands/sampler/show.js +36 -0
- package/dist/cli/commands/sampler/show.js.map +1 -0
- package/dist/cli/commands/sampler/sync.d.ts +11 -0
- package/dist/cli/commands/sampler/sync.d.ts.map +1 -0
- package/dist/cli/commands/sampler/sync.js +65 -0
- package/dist/cli/commands/sampler/sync.js.map +1 -0
- package/dist/cli/commands/sampler/validate.d.ts +3 -10
- package/dist/cli/commands/sampler/validate.d.ts.map +1 -1
- package/dist/cli/commands/sampler/validate.js +57 -126
- package/dist/cli/commands/sampler/validate.js.map +1 -1
- package/dist/generation/closed-schema.d.ts +22 -0
- package/dist/generation/closed-schema.d.ts.map +1 -0
- package/dist/generation/closed-schema.js +45 -0
- package/dist/generation/closed-schema.js.map +1 -0
- package/dist/generation/content-type-strategies/json.content-type-strategy.d.ts.map +1 -1
- package/dist/generation/content-type-strategies/json.content-type-strategy.js +3 -1
- package/dist/generation/content-type-strategies/json.content-type-strategy.js.map +1 -1
- package/dist/generation/content-type-strategies/xml.content-type-strategy.d.ts.map +1 -1
- package/dist/generation/content-type-strategies/xml.content-type-strategy.js +3 -1
- package/dist/generation/content-type-strategies/xml.content-type-strategy.js.map +1 -1
- package/dist/generation/generate-request-sample.d.ts +12 -0
- package/dist/generation/generate-request-sample.d.ts.map +1 -0
- package/dist/generation/{generate-samples.js → generate-request-sample.js} +11 -4
- package/dist/generation/generate-request-sample.js.map +1 -0
- package/dist/generation/request-generators/default-request-generator.d.ts +14 -0
- package/dist/generation/request-generators/default-request-generator.d.ts.map +1 -1
- package/dist/generation/request-generators/default-request-generator.js +18 -1
- package/dist/generation/request-generators/default-request-generator.js.map +1 -1
- package/dist/generation/types/declaration-set.d.ts +124 -0
- package/dist/generation/types/declaration-set.d.ts.map +1 -0
- package/dist/generation/types/declaration-set.js +389 -0
- package/dist/generation/types/declaration-set.js.map +1 -0
- package/dist/generation/types/example-reflection.d.ts +21 -0
- package/dist/generation/types/example-reflection.d.ts.map +1 -0
- package/dist/generation/types/example-reflection.js +135 -0
- package/dist/generation/types/example-reflection.js.map +1 -0
- package/dist/generation/types/generate-type-surface.d.ts +23 -0
- package/dist/generation/types/generate-type-surface.d.ts.map +1 -0
- package/dist/generation/types/generate-type-surface.js +671 -0
- package/dist/generation/types/generate-type-surface.js.map +1 -0
- package/dist/generation/types/schema-type.d.ts +20 -0
- package/dist/generation/types/schema-type.d.ts.map +1 -0
- package/dist/generation/types/schema-type.js +203 -0
- package/dist/generation/types/schema-type.js.map +1 -0
- package/dist/generation/types/self-check-surface.d.ts +32 -0
- package/dist/generation/types/self-check-surface.d.ts.map +1 -0
- package/dist/generation/types/self-check-surface.js +92 -0
- package/dist/generation/types/self-check-surface.js.map +1 -0
- package/dist/generation/types/type-names.d.ts +135 -0
- package/dist/generation/types/type-names.d.ts.map +1 -0
- package/dist/generation/types/type-names.js +213 -0
- package/dist/generation/types/type-names.js.map +1 -0
- package/dist/generation/types/write-type-surface.d.ts +58 -0
- package/dist/generation/types/write-type-surface.d.ts.map +1 -0
- package/dist/generation/types/write-type-surface.js +119 -0
- package/dist/generation/types/write-type-surface.js.map +1 -0
- package/dist/hooks/create-hook-utils.d.ts +22 -6
- package/dist/hooks/create-hook-utils.d.ts.map +1 -1
- package/dist/hooks/create-hook-utils.js +74 -96
- package/dist/hooks/create-hook-utils.js.map +1 -1
- package/dist/hooks/hook-api.d.ts +49 -0
- package/dist/hooks/hook-api.d.ts.map +1 -0
- package/dist/hooks/hook-api.js +105 -0
- package/dist/hooks/hook-api.js.map +1 -0
- package/dist/hooks/hook-diagnostics.d.ts +45 -0
- package/dist/hooks/hook-diagnostics.d.ts.map +1 -0
- package/dist/hooks/hook-diagnostics.js +80 -0
- package/dist/hooks/hook-diagnostics.js.map +1 -0
- package/dist/hooks/hook-errors.d.ts +33 -0
- package/dist/hooks/hook-errors.d.ts.map +1 -1
- package/dist/hooks/hook-errors.js +46 -0
- package/dist/hooks/hook-errors.js.map +1 -1
- package/dist/hooks/hook-registration.d.ts +108 -0
- package/dist/hooks/hook-registration.d.ts.map +1 -0
- package/dist/hooks/hook-registration.js +69 -0
- package/dist/hooks/hook-registration.js.map +1 -0
- package/dist/hooks/hook-runner.d.ts +111 -11
- package/dist/hooks/hook-runner.d.ts.map +1 -1
- package/dist/hooks/hook-runner.js +309 -142
- package/dist/hooks/hook-runner.js.map +1 -1
- package/dist/hooks/hook-utils-factory.d.ts +19 -0
- package/dist/hooks/hook-utils-factory.d.ts.map +1 -0
- package/dist/hooks/hook-utils-factory.js +2 -0
- package/dist/hooks/hook-utils-factory.js.map +1 -0
- package/dist/hooks/hook-utils.d.ts +80 -12
- package/dist/hooks/hook-utils.d.ts.map +1 -1
- package/dist/hooks/invoke-hook.d.ts +71 -0
- package/dist/hooks/invoke-hook.d.ts.map +1 -0
- package/dist/hooks/invoke-hook.js +161 -0
- package/dist/hooks/invoke-hook.js.map +1 -0
- package/dist/hooks/load-user-hooks.d.ts +96 -0
- package/dist/hooks/load-user-hooks.d.ts.map +1 -0
- package/dist/hooks/load-user-hooks.js +432 -0
- package/dist/hooks/load-user-hooks.js.map +1 -0
- package/dist/hooks/nested-request.d.ts +21 -0
- package/dist/hooks/nested-request.d.ts.map +1 -0
- package/dist/hooks/nested-request.js +24 -0
- package/dist/hooks/nested-request.js.map +1 -0
- package/dist/hooks/overlay-args.d.ts +40 -0
- package/dist/hooks/overlay-args.d.ts.map +1 -0
- package/dist/hooks/overlay-args.js +84 -0
- package/dist/hooks/overlay-args.js.map +1 -0
- package/dist/hooks/resolve-targeting.d.ts +16 -0
- package/dist/hooks/resolve-targeting.d.ts.map +1 -0
- package/dist/hooks/resolve-targeting.js +168 -0
- package/dist/hooks/resolve-targeting.js.map +1 -0
- package/dist/hooks/run-scoped-hooks.d.ts +83 -0
- package/dist/hooks/run-scoped-hooks.d.ts.map +1 -0
- package/dist/hooks/run-scoped-hooks.js +153 -0
- package/dist/hooks/run-scoped-hooks.js.map +1 -0
- package/dist/index.d.ts +42 -19
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +152 -165
- package/dist/index.js.map +1 -1
- package/dist/request-sampler.d.ts +40 -11
- package/dist/request-sampler.d.ts.map +1 -1
- package/dist/request-sampler.js +51 -76
- package/dist/request-sampler.js.map +1 -1
- package/dist/sampler-paths.d.ts +19 -0
- package/dist/sampler-paths.d.ts.map +1 -0
- package/dist/sampler-paths.js +22 -0
- package/dist/sampler-paths.js.map +1 -0
- package/dist/selectors/nearest-paths.d.ts +14 -0
- package/dist/selectors/nearest-paths.d.ts.map +1 -0
- package/dist/selectors/nearest-paths.js +32 -0
- package/dist/selectors/nearest-paths.js.map +1 -0
- package/dist/selectors/path-glob.d.ts +94 -0
- package/dist/selectors/path-glob.d.ts.map +1 -0
- package/dist/selectors/path-glob.js +136 -0
- package/dist/selectors/path-glob.js.map +1 -0
- package/dist/selectors/selector-errors.d.ts +17 -0
- package/dist/selectors/selector-errors.d.ts.map +1 -0
- package/dist/selectors/selector-errors.js +139 -0
- package/dist/selectors/selector-errors.js.map +1 -0
- package/dist/selectors/selector.d.ts +55 -0
- package/dist/selectors/selector.d.ts.map +1 -0
- package/dist/selectors/selector.js +305 -0
- package/dist/selectors/selector.js.map +1 -0
- package/dist/selectors/transaction-catalog.d.ts +96 -0
- package/dist/selectors/transaction-catalog.d.ts.map +1 -0
- package/dist/selectors/transaction-catalog.js +193 -0
- package/dist/selectors/transaction-catalog.js.map +1 -0
- package/dist/selectors/transaction-filter.d.ts +119 -0
- package/dist/selectors/transaction-filter.d.ts.map +1 -0
- package/dist/selectors/transaction-filter.js +191 -0
- package/dist/selectors/transaction-filter.js.map +1 -0
- package/dist/ts-path.d.ts +36 -0
- package/dist/ts-path.d.ts.map +1 -0
- package/dist/ts-path.js +46 -0
- package/dist/ts-path.js.map +1 -0
- package/dist/utils.d.ts +1 -2
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +2 -20
- package/dist/utils.js.map +1 -1
- package/dist/validation/canonicalize.d.ts +17 -0
- package/dist/validation/canonicalize.d.ts.map +1 -0
- package/dist/validation/canonicalize.js +29 -0
- package/dist/validation/canonicalize.js.map +1 -0
- package/dist/validation/shared-compiler-host.d.ts +17 -0
- package/dist/validation/shared-compiler-host.d.ts.map +1 -0
- package/dist/validation/shared-compiler-host.js +58 -0
- package/dist/validation/shared-compiler-host.js.map +1 -0
- package/dist/validation/typecheck-hooks.d.ts +37 -0
- package/dist/validation/typecheck-hooks.d.ts.map +1 -0
- package/dist/validation/typecheck-hooks.js +169 -0
- package/dist/validation/typecheck-hooks.js.map +1 -0
- package/dist/validation/validate-sampler.d.ts +79 -0
- package/dist/validation/validate-sampler.d.ts.map +1 -0
- package/dist/validation/validate-sampler.js +89 -0
- package/dist/validation/validate-sampler.js.map +1 -0
- package/package.json +7 -11
- package/dist/cli/commands/sampler/generate/hook.d.ts +0 -10
- package/dist/cli/commands/sampler/generate/hook.d.ts.map +0 -1
- package/dist/cli/commands/sampler/generate/hook.js +0 -19
- package/dist/cli/commands/sampler/generate/hook.js.map +0 -1
- package/dist/cli/generate-hook.d.ts +0 -4
- package/dist/cli/generate-hook.d.ts.map +0 -1
- package/dist/cli/generate-hook.js +0 -96
- package/dist/cli/generate-hook.js.map +0 -1
- package/dist/cli/templates.d.ts +0 -4
- package/dist/cli/templates.d.ts.map +0 -1
- package/dist/cli/templates.js +0 -28
- package/dist/cli/templates.js.map +0 -1
- package/dist/constants.d.ts +0 -12
- package/dist/constants.d.ts.map +0 -1
- package/dist/constants.js +0 -16
- package/dist/constants.js.map +0 -1
- package/dist/generation/generate-samples-for-thymian-format.d.ts +0 -4
- package/dist/generation/generate-samples-for-thymian-format.d.ts.map +0 -1
- package/dist/generation/generate-samples-for-thymian-format.js +0 -18
- package/dist/generation/generate-samples-for-thymian-format.js.map +0 -1
- package/dist/generation/generate-samples.d.ts +0 -4
- package/dist/generation/generate-samples.d.ts.map +0 -1
- package/dist/generation/generate-samples.js.map +0 -1
- package/dist/hooks/generate-request-types.d.ts +0 -34
- package/dist/hooks/generate-request-types.d.ts.map +0 -1
- package/dist/hooks/generate-request-types.js +0 -458
- package/dist/hooks/generate-request-types.js.map +0 -1
- package/dist/hooks/hook-types.d.ts +0 -7
- package/dist/hooks/hook-types.d.ts.map +0 -1
- package/dist/hooks/hook-types.js +0 -2
- package/dist/hooks/hook-types.js.map +0 -1
- package/dist/hooks/load-hooks-from-samples.d.ts +0 -3
- package/dist/hooks/load-hooks-from-samples.d.ts.map +0 -1
- package/dist/hooks/load-hooks-from-samples.js +0 -22
- package/dist/hooks/load-hooks-from-samples.js.map +0 -1
- package/dist/hooks/ts-config.d.ts +0 -10
- package/dist/hooks/ts-config.d.ts.map +0 -1
- package/dist/hooks/ts-config.js +0 -10
- package/dist/hooks/ts-config.js.map +0 -1
- package/dist/samples-structure/file-request-sample.d.ts +0 -20
- package/dist/samples-structure/file-request-sample.d.ts.map +0 -1
- package/dist/samples-structure/file-request-sample.js +0 -5
- package/dist/samples-structure/file-request-sample.js.map +0 -1
- package/dist/samples-structure/get-path-transaction-id.d.ts +0 -3
- package/dist/samples-structure/get-path-transaction-id.d.ts.map +0 -1
- package/dist/samples-structure/get-path-transaction-id.js +0 -22
- package/dist/samples-structure/get-path-transaction-id.js.map +0 -1
- package/dist/samples-structure/merge-tree.d.ts +0 -5
- package/dist/samples-structure/merge-tree.d.ts.map +0 -1
- package/dist/samples-structure/merge-tree.js +0 -118
- package/dist/samples-structure/merge-tree.js.map +0 -1
- package/dist/samples-structure/read-samples-from-dir.d.ts +0 -13
- package/dist/samples-structure/read-samples-from-dir.d.ts.map +0 -1
- package/dist/samples-structure/read-samples-from-dir.js +0 -205
- package/dist/samples-structure/read-samples-from-dir.js.map +0 -1
- package/dist/samples-structure/samples-from-transactions.d.ts +0 -5
- package/dist/samples-structure/samples-from-transactions.d.ts.map +0 -1
- package/dist/samples-structure/samples-from-transactions.js +0 -120
- package/dist/samples-structure/samples-from-transactions.js.map +0 -1
- package/dist/samples-structure/samples-tree-structure.d.ts +0 -106
- package/dist/samples-structure/samples-tree-structure.d.ts.map +0 -1
- package/dist/samples-structure/samples-tree-structure.js +0 -26
- package/dist/samples-structure/samples-tree-structure.js.map +0 -1
- package/dist/samples-structure/structure-meta-on-disc.d.ts +0 -11
- package/dist/samples-structure/structure-meta-on-disc.d.ts.map +0 -1
- package/dist/samples-structure/structure-meta-on-disc.js +0 -2
- package/dist/samples-structure/structure-meta-on-disc.js.map +0 -1
- package/dist/samples-structure/traverse.d.ts +0 -4
- package/dist/samples-structure/traverse.d.ts.map +0 -1
- package/dist/samples-structure/traverse.js +0 -13
- package/dist/samples-structure/traverse.js.map +0 -1
- package/dist/samples-structure/write-samples-to-dir.d.ts +0 -37
- package/dist/samples-structure/write-samples-to-dir.d.ts.map +0 -1
- package/dist/samples-structure/write-samples-to-dir.js +0 -183
- package/dist/samples-structure/write-samples-to-dir.js.map +0 -1
- package/dist/validation/validate-sampler-output.d.ts +0 -38
- package/dist/validation/validate-sampler-output.d.ts.map +0 -1
- package/dist/validation/validate-sampler-output.js +0 -288
- package/dist/validation/validate-sampler-output.js.map +0 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type SamplerPaths = {
|
|
2
|
+
/** The per-sampler root, `<cwd>/.thymian/sampler` by default. */
|
|
3
|
+
root: string;
|
|
4
|
+
/** The committed type surface. Regenerated wholesale. */
|
|
5
|
+
generatedDir: string;
|
|
6
|
+
/** The recursive hook tree the loader scans. */
|
|
7
|
+
hooksDir: string;
|
|
8
|
+
/** The tsconfig `init` scaffolds once and thereafter never touches. */
|
|
9
|
+
tsconfigPath: string;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* The single source of truth for every sampler path.
|
|
13
|
+
*
|
|
14
|
+
* `path` is the plugin option. It named the v1 samples tree, which no longer
|
|
15
|
+
* exists; it now names the sampler root, so a project that kept its sampler
|
|
16
|
+
* somewhere other than `.thymian/sampler` keeps one option to say so.
|
|
17
|
+
*/
|
|
18
|
+
export declare function resolveSamplerPaths(cwd: string, path?: string): SamplerPaths;
|
|
19
|
+
//# sourceMappingURL=sampler-paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sampler-paths.d.ts","sourceRoot":"","sources":["../src/sampler-paths.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,YAAY,GAAG;IACzB,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,YAAY,EAAE,MAAM,CAAC;IACrB,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,uEAAuE;IACvE,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,YAAY,CAa5E"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { isAbsolute, join } from 'node:path';
|
|
2
|
+
/**
|
|
3
|
+
* The single source of truth for every sampler path.
|
|
4
|
+
*
|
|
5
|
+
* `path` is the plugin option. It named the v1 samples tree, which no longer
|
|
6
|
+
* exists; it now names the sampler root, so a project that kept its sampler
|
|
7
|
+
* somewhere other than `.thymian/sampler` keeps one option to say so.
|
|
8
|
+
*/
|
|
9
|
+
export function resolveSamplerPaths(cwd, path) {
|
|
10
|
+
const root = path
|
|
11
|
+
? isAbsolute(path)
|
|
12
|
+
? path
|
|
13
|
+
: join(cwd, path)
|
|
14
|
+
: join(cwd, '.thymian', 'sampler');
|
|
15
|
+
return {
|
|
16
|
+
root,
|
|
17
|
+
generatedDir: join(root, 'generated'),
|
|
18
|
+
hooksDir: join(root, 'hooks'),
|
|
19
|
+
tsconfigPath: join(root, 'tsconfig.json'),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=sampler-paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sampler-paths.js","sourceRoot":"","sources":["../src/sampler-paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAa7C;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAW,EAAE,IAAa;IAC5D,MAAM,IAAI,GAAG,IAAI;QACf,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;YAChB,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC;QACnB,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;IAErC,OAAO;QACL,IAAI;QACJ,YAAY,EAAE,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC;QACrC,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC;QAC7B,YAAY,EAAE,IAAI,CAAC,IAAI,EAAE,eAAe,CAAC;KAC1C,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Paths that share `value`'s longest literal prefix, as message lines.
|
|
3
|
+
*
|
|
4
|
+
* Walks the prefix from the longest down to the shortest, so the reader is
|
|
5
|
+
* pointed at the narrowest subtree that actually has anything in it rather
|
|
6
|
+
* than at the whole description. No fuzzy matching: it would add a
|
|
7
|
+
* dependency and make the ordering unexplainable.
|
|
8
|
+
*
|
|
9
|
+
* Shared between a vacuous filter path value and a Selector whose path is a
|
|
10
|
+
* typo — the same prefix walk, so the two diagnostics agree on what "near"
|
|
11
|
+
* means instead of carrying two guesses that could disagree.
|
|
12
|
+
*/
|
|
13
|
+
export declare function nearestPathHints(value: string, paths: readonly string[]): string[];
|
|
14
|
+
//# sourceMappingURL=nearest-paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nearest-paths.d.ts","sourceRoot":"","sources":["../../src/selectors/nearest-paths.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,SAAS,MAAM,EAAE,GACvB,MAAM,EAAE,CAoBV"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const MAX_NEAR_PATHS = 5;
|
|
2
|
+
/**
|
|
3
|
+
* Paths that share `value`'s longest literal prefix, as message lines.
|
|
4
|
+
*
|
|
5
|
+
* Walks the prefix from the longest down to the shortest, so the reader is
|
|
6
|
+
* pointed at the narrowest subtree that actually has anything in it rather
|
|
7
|
+
* than at the whole description. No fuzzy matching: it would add a
|
|
8
|
+
* dependency and make the ordering unexplainable.
|
|
9
|
+
*
|
|
10
|
+
* Shared between a vacuous filter path value and a Selector whose path is a
|
|
11
|
+
* typo — the same prefix walk, so the two diagnostics agree on what "near"
|
|
12
|
+
* means instead of carrying two guesses that could disagree.
|
|
13
|
+
*/
|
|
14
|
+
export function nearestPathHints(value, paths) {
|
|
15
|
+
const segments = value.split('/');
|
|
16
|
+
for (let depth = segments.length - 1; depth > 0; depth--) {
|
|
17
|
+
const prefix = `${segments.slice(0, depth).join('/')}/`;
|
|
18
|
+
const candidates = paths
|
|
19
|
+
.filter((path) => path.startsWith(prefix))
|
|
20
|
+
.slice(0, MAX_NEAR_PATHS);
|
|
21
|
+
if (candidates.length > 0) {
|
|
22
|
+
return [
|
|
23
|
+
`Paths under "${prefix}" are:`,
|
|
24
|
+
...candidates.map((path) => `"${path}"`),
|
|
25
|
+
];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return [
|
|
29
|
+
`No path in the loaded API description begins with "${segments[1] ? `/${segments[1]}` : value}".`,
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=nearest-paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nearest-paths.js","sourceRoot":"","sources":["../../src/selectors/nearest-paths.ts"],"names":[],"mappings":"AAAA,MAAM,cAAc,GAAG,CAAC,CAAC;AAEzB;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,gBAAgB,CAC9B,KAAa,EACb,KAAwB;IAExB,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAElC,KAAK,IAAI,KAAK,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC;QACzD,MAAM,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;QACxD,MAAM,UAAU,GAAG,KAAK;aACrB,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;aACzC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;QAE5B,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,OAAO;gBACL,gBAAgB,MAAM,QAAQ;gBAC9B,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,GAAG,CAAC;aACzC,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO;QACL,sDAAsD,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI;KAClG,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* # The path-glob grammar — FROZEN
|
|
3
|
+
*
|
|
4
|
+
* A glob is a string compared against a path as the transaction catalog spells
|
|
5
|
+
* it: beginning with `/`, already carrying the API description's server base
|
|
6
|
+
* path, with `{param}` in template form. Both sides are compared **segment by
|
|
7
|
+
* segment**, where a segment is a maximal run of characters containing no `/`.
|
|
8
|
+
*
|
|
9
|
+
* ```ebnf
|
|
10
|
+
* glob = segment , { "/" , segment } , [ "/" , deep-wildcard ] ;
|
|
11
|
+
* segment = wildcard | literal-segment ;
|
|
12
|
+
* wildcard = "*" ; (* the WHOLE segment, never part *)
|
|
13
|
+
* deep-wildcard = "**" ; (* final position only *)
|
|
14
|
+
* literal-segment = { literal-char } ; (* matched byte-for-byte *)
|
|
15
|
+
* literal-char = ? any character except "/" ? ;
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* ## The decisions (all of them explicit, all of them frozen)
|
|
19
|
+
*
|
|
20
|
+
* 1. **`*` matches exactly one whole segment.** It never matches part of a
|
|
21
|
+
* segment. `/foo*` is therefore **not a legal glob** — it is a segment whose
|
|
22
|
+
* literal text happens to be `foo*`, which matches no real path, and which
|
|
23
|
+
* `validate` reports as "matches nothing". It is deliberately *not* a
|
|
24
|
+
* separate "malformed glob" diagnostic: one diagnostic for "this names
|
|
25
|
+
* nothing" is the whole promise, and a second class of error would have to
|
|
26
|
+
* be kept in sync with the first.
|
|
27
|
+
* 2. **`*` matches exactly one segment — never zero.** `/users/*` does not
|
|
28
|
+
* match `/users`, and does not match `/users/` (whose trailing segment is
|
|
29
|
+
* the empty string).
|
|
30
|
+
* 3. **`*` never crosses `/`.** `/users/*` does not match `/users/1/orders`.
|
|
31
|
+
* 4. **A trailing `**` matches one *or more* segments.** `/admin/**` matches
|
|
32
|
+
* `/admin/users` and `/admin/users/42/roles`, and does **not** match
|
|
33
|
+
* `/admin` itself. A user who wants both writes two entries. This is the
|
|
34
|
+
* decision most likely to be argued later, so: it is one-or-more, and the
|
|
35
|
+
* reason is that `/admin/**` reads as "everything *under* /admin", and a
|
|
36
|
+
* zero-or-more reading makes `{ path: '/admin/**' }` silently a superset of
|
|
37
|
+
* `{ path: '/admin' }` — two different intents spelled the same way.
|
|
38
|
+
* 5. **`**` is legal only as the final segment.** Leading and mid-path `**`
|
|
39
|
+
* are out; mid-path `**` is deferred. A `**` anywhere else is, again, just a
|
|
40
|
+
* literal segment that matches nothing.
|
|
41
|
+
* 6. **`{id}` — and any other brace text — is a literal.** Real paths contain
|
|
42
|
+
* `{id}`, `{launchId}` and so on, because the loader keeps the template
|
|
43
|
+
* form. A glob spells them exactly as the path does. Braces are **not**
|
|
44
|
+
* metacharacters and never will be in this grammar.
|
|
45
|
+
* 7. **Matching is case-sensitive and exact.** `/Users/*` does not match
|
|
46
|
+
* `/users/1`. No normalisation, no trailing-slash tolerance, no percent
|
|
47
|
+
* decoding.
|
|
48
|
+
* 8. **A glob containing no metacharacter is just an exact path.** It has to
|
|
49
|
+
* equal a path the catalog holds, and it is validated by the same rule as
|
|
50
|
+
* every other glob: does it name at least one path.
|
|
51
|
+
* 9. **Anchoring.** A glob is matched against the whole path string, anchored
|
|
52
|
+
* at both ends — there is no implicit prefix or suffix wildcard. The string
|
|
53
|
+
* it is anchored against carries the server base path, so on a description
|
|
54
|
+
* whose server is `https://api.example.com/v1`, the glob for the spec's own
|
|
55
|
+
* `/admin/**` example is `/v1/admin/**`.
|
|
56
|
+
*
|
|
57
|
+
* ## Deliberately excluded — this list is closed
|
|
58
|
+
*
|
|
59
|
+
* `?` (single character); character classes (`[a-z]`); brace alternation
|
|
60
|
+
* (`{a,b}`); regular expressions of any kind; leading or mid-path `**`;
|
|
61
|
+
* negation inside a glob (exclusion is `not:`, a filter-level feature);
|
|
62
|
+
* case-insensitive matching; escaping (there is no escape character, because
|
|
63
|
+
* there is nothing to escape: `*` in a literal position is already just a
|
|
64
|
+
* character that matches nothing); and **globbing on any filter field other
|
|
65
|
+
* than `path`** — `method`, `status`, `statusClass`, `requestMediaType` and
|
|
66
|
+
* `responseMediaType` stay closed unions.
|
|
67
|
+
*
|
|
68
|
+
* Anything not on the "in" list is out.
|
|
69
|
+
*
|
|
70
|
+
* The semantics above are stated as data in `bench/glob-corpus.ts`, and
|
|
71
|
+
* {@link matchesPathGlob} is checked against that corpus and nothing else.
|
|
72
|
+
*/
|
|
73
|
+
/**
|
|
74
|
+
* Whether `glob` names `path`.
|
|
75
|
+
*
|
|
76
|
+
* Written directly from the decision list above, iteratively rather than
|
|
77
|
+
* recursively, so that reading it against the grammar is a one-pass job.
|
|
78
|
+
*/
|
|
79
|
+
export declare function matchesPathGlob(glob: string, path: string): boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Whether a path value carries a wildcard at all (decision 8).
|
|
82
|
+
*
|
|
83
|
+
* Only used for the wording of a diagnostic: an exact path that names nothing
|
|
84
|
+
* and a glob that names nothing are the same fault, but "no path is spelled
|
|
85
|
+
* that way" and "that glob matches nothing" are not the same sentence.
|
|
86
|
+
*
|
|
87
|
+
* Any `*` counts, not only a whole-segment one. `/v1/launch*` is a glob the
|
|
88
|
+
* user wrote — `PathGlob` accepts it and the grammar says so — it is just a
|
|
89
|
+
* glob that names nothing, because decision 1 makes `launch*` a literal
|
|
90
|
+
* segment. Testing for a whole-segment `*` instead told that user no path was
|
|
91
|
+
* *spelled* `/v1/launch*`, which is true and unhelpful.
|
|
92
|
+
*/
|
|
93
|
+
export declare function hasWildcard(value: string): boolean;
|
|
94
|
+
//# sourceMappingURL=path-glob.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-glob.d.ts","sourceRoot":"","sources":["../../src/selectors/path-glob.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AAEH;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAkDnE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAElD"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* # The path-glob grammar — FROZEN
|
|
3
|
+
*
|
|
4
|
+
* A glob is a string compared against a path as the transaction catalog spells
|
|
5
|
+
* it: beginning with `/`, already carrying the API description's server base
|
|
6
|
+
* path, with `{param}` in template form. Both sides are compared **segment by
|
|
7
|
+
* segment**, where a segment is a maximal run of characters containing no `/`.
|
|
8
|
+
*
|
|
9
|
+
* ```ebnf
|
|
10
|
+
* glob = segment , { "/" , segment } , [ "/" , deep-wildcard ] ;
|
|
11
|
+
* segment = wildcard | literal-segment ;
|
|
12
|
+
* wildcard = "*" ; (* the WHOLE segment, never part *)
|
|
13
|
+
* deep-wildcard = "**" ; (* final position only *)
|
|
14
|
+
* literal-segment = { literal-char } ; (* matched byte-for-byte *)
|
|
15
|
+
* literal-char = ? any character except "/" ? ;
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* ## The decisions (all of them explicit, all of them frozen)
|
|
19
|
+
*
|
|
20
|
+
* 1. **`*` matches exactly one whole segment.** It never matches part of a
|
|
21
|
+
* segment. `/foo*` is therefore **not a legal glob** — it is a segment whose
|
|
22
|
+
* literal text happens to be `foo*`, which matches no real path, and which
|
|
23
|
+
* `validate` reports as "matches nothing". It is deliberately *not* a
|
|
24
|
+
* separate "malformed glob" diagnostic: one diagnostic for "this names
|
|
25
|
+
* nothing" is the whole promise, and a second class of error would have to
|
|
26
|
+
* be kept in sync with the first.
|
|
27
|
+
* 2. **`*` matches exactly one segment — never zero.** `/users/*` does not
|
|
28
|
+
* match `/users`, and does not match `/users/` (whose trailing segment is
|
|
29
|
+
* the empty string).
|
|
30
|
+
* 3. **`*` never crosses `/`.** `/users/*` does not match `/users/1/orders`.
|
|
31
|
+
* 4. **A trailing `**` matches one *or more* segments.** `/admin/**` matches
|
|
32
|
+
* `/admin/users` and `/admin/users/42/roles`, and does **not** match
|
|
33
|
+
* `/admin` itself. A user who wants both writes two entries. This is the
|
|
34
|
+
* decision most likely to be argued later, so: it is one-or-more, and the
|
|
35
|
+
* reason is that `/admin/**` reads as "everything *under* /admin", and a
|
|
36
|
+
* zero-or-more reading makes `{ path: '/admin/**' }` silently a superset of
|
|
37
|
+
* `{ path: '/admin' }` — two different intents spelled the same way.
|
|
38
|
+
* 5. **`**` is legal only as the final segment.** Leading and mid-path `**`
|
|
39
|
+
* are out; mid-path `**` is deferred. A `**` anywhere else is, again, just a
|
|
40
|
+
* literal segment that matches nothing.
|
|
41
|
+
* 6. **`{id}` — and any other brace text — is a literal.** Real paths contain
|
|
42
|
+
* `{id}`, `{launchId}` and so on, because the loader keeps the template
|
|
43
|
+
* form. A glob spells them exactly as the path does. Braces are **not**
|
|
44
|
+
* metacharacters and never will be in this grammar.
|
|
45
|
+
* 7. **Matching is case-sensitive and exact.** `/Users/*` does not match
|
|
46
|
+
* `/users/1`. No normalisation, no trailing-slash tolerance, no percent
|
|
47
|
+
* decoding.
|
|
48
|
+
* 8. **A glob containing no metacharacter is just an exact path.** It has to
|
|
49
|
+
* equal a path the catalog holds, and it is validated by the same rule as
|
|
50
|
+
* every other glob: does it name at least one path.
|
|
51
|
+
* 9. **Anchoring.** A glob is matched against the whole path string, anchored
|
|
52
|
+
* at both ends — there is no implicit prefix or suffix wildcard. The string
|
|
53
|
+
* it is anchored against carries the server base path, so on a description
|
|
54
|
+
* whose server is `https://api.example.com/v1`, the glob for the spec's own
|
|
55
|
+
* `/admin/**` example is `/v1/admin/**`.
|
|
56
|
+
*
|
|
57
|
+
* ## Deliberately excluded — this list is closed
|
|
58
|
+
*
|
|
59
|
+
* `?` (single character); character classes (`[a-z]`); brace alternation
|
|
60
|
+
* (`{a,b}`); regular expressions of any kind; leading or mid-path `**`;
|
|
61
|
+
* negation inside a glob (exclusion is `not:`, a filter-level feature);
|
|
62
|
+
* case-insensitive matching; escaping (there is no escape character, because
|
|
63
|
+
* there is nothing to escape: `*` in a literal position is already just a
|
|
64
|
+
* character that matches nothing); and **globbing on any filter field other
|
|
65
|
+
* than `path`** — `method`, `status`, `statusClass`, `requestMediaType` and
|
|
66
|
+
* `responseMediaType` stay closed unions.
|
|
67
|
+
*
|
|
68
|
+
* Anything not on the "in" list is out.
|
|
69
|
+
*
|
|
70
|
+
* The semantics above are stated as data in `bench/glob-corpus.ts`, and
|
|
71
|
+
* {@link matchesPathGlob} is checked against that corpus and nothing else.
|
|
72
|
+
*/
|
|
73
|
+
/**
|
|
74
|
+
* Whether `glob` names `path`.
|
|
75
|
+
*
|
|
76
|
+
* Written directly from the decision list above, iteratively rather than
|
|
77
|
+
* recursively, so that reading it against the grammar is a one-pass job.
|
|
78
|
+
*/
|
|
79
|
+
export function matchesPathGlob(glob, path) {
|
|
80
|
+
const globSegments = glob.split('/');
|
|
81
|
+
const pathSegments = path.split('/');
|
|
82
|
+
const deep = globSegments.at(-1) === '**';
|
|
83
|
+
// Decision 5: `**` is legal only as the final segment. Anywhere else it is a
|
|
84
|
+
// literal segment, which is what the equality branch below gives it.
|
|
85
|
+
const fixed = deep ? globSegments.slice(0, -1) : globSegments;
|
|
86
|
+
// Decision 4: a trailing `**` needs one or more segments to consume, so the
|
|
87
|
+
// path must be strictly longer than the fixed prefix. Without a trailing
|
|
88
|
+
// `**` the two must have the same number of segments — decisions 2 and 3.
|
|
89
|
+
if (deep
|
|
90
|
+
? pathSegments.length <= fixed.length
|
|
91
|
+
: pathSegments.length !== fixed.length) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
for (const [index, globSegment] of fixed.entries()) {
|
|
95
|
+
const pathSegment = pathSegments[index] ?? '';
|
|
96
|
+
if (globSegment === '*') {
|
|
97
|
+
// Decision 2: exactly one segment, never zero. An empty segment is not a
|
|
98
|
+
// segment.
|
|
99
|
+
if (pathSegment === '') {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
// Decisions 1, 6, 7, 8: everything else is literal, compared exactly.
|
|
105
|
+
if (globSegment !== pathSegment) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Decision 4 again, for what the tail actually holds. The length test above
|
|
110
|
+
// proves the tail is non-empty as a list, not that it holds a segment: a
|
|
111
|
+
// path written with a trailing slash splits to one final empty string, so
|
|
112
|
+
// `/admin/**` matched `/admin/` and `/**` matched `/`. `*` already refuses an
|
|
113
|
+
// empty segment above, and "one or more segments" has to mean the same thing
|
|
114
|
+
// in both spellings.
|
|
115
|
+
if (deep && pathSegments.slice(fixed.length).every((s) => s === '')) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Whether a path value carries a wildcard at all (decision 8).
|
|
122
|
+
*
|
|
123
|
+
* Only used for the wording of a diagnostic: an exact path that names nothing
|
|
124
|
+
* and a glob that names nothing are the same fault, but "no path is spelled
|
|
125
|
+
* that way" and "that glob matches nothing" are not the same sentence.
|
|
126
|
+
*
|
|
127
|
+
* Any `*` counts, not only a whole-segment one. `/v1/launch*` is a glob the
|
|
128
|
+
* user wrote — `PathGlob` accepts it and the grammar says so — it is just a
|
|
129
|
+
* glob that names nothing, because decision 1 makes `launch*` a literal
|
|
130
|
+
* segment. Testing for a whole-segment `*` instead told that user no path was
|
|
131
|
+
* *spelled* `/v1/launch*`, which is true and unhelpful.
|
|
132
|
+
*/
|
|
133
|
+
export function hasWildcard(value) {
|
|
134
|
+
return value.includes('*');
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=path-glob.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-glob.js","sourceRoot":"","sources":["../../src/selectors/path-glob.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AAEH;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,IAAY;IACxD,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACrC,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACrC,MAAM,IAAI,GAAG,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IAE1C,6EAA6E;IAC7E,qEAAqE;IACrE,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;IAE9D,4EAA4E;IAC5E,yEAAyE;IACzE,0EAA0E;IAC1E,IACE,IAAI;QACF,CAAC,CAAC,YAAY,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM;QACrC,CAAC,CAAC,YAAY,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,EACxC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,KAAK,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;QACnD,MAAM,WAAW,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAE9C,IAAI,WAAW,KAAK,GAAG,EAAE,CAAC;YACxB,yEAAyE;YACzE,WAAW;YACX,IAAI,WAAW,KAAK,EAAE,EAAE,CAAC;gBACvB,OAAO,KAAK,CAAC;YACf,CAAC;YAED,SAAS;QACX,CAAC;QAED,sEAAsE;QACtE,IAAI,WAAW,KAAK,WAAW,EAAE,CAAC;YAChC,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,4EAA4E;IAC5E,yEAAyE;IACzE,0EAA0E;IAC1E,8EAA8E;IAC9E,6EAA6E;IAC7E,qBAAqB;IACrB,IAAI,IAAI,IAAI,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC;QACpE,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,OAAO,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ThymianBaseError, type ThymianHttpTransaction } from '@thymian/core';
|
|
2
|
+
/**
|
|
3
|
+
* Two transactions in the loaded format render the same selector. Fail-fast:
|
|
4
|
+
* nothing is dropped, overwritten or resolved "last wins". This is the one hard
|
|
5
|
+
* error at catalog build — rendering itself never rejects.
|
|
6
|
+
*/
|
|
7
|
+
export declare function selectorCollisionError(selector: string, first: ThymianHttpTransaction, second: ThymianHttpTransaction): ThymianBaseError;
|
|
8
|
+
/**
|
|
9
|
+
* A well-formed selector that names no transaction in the loaded format. The
|
|
10
|
+
* near-miss candidates are supplied by the catalog, which is the only thing that
|
|
11
|
+
* knows what is loaded. A dangling selector is never auto-rebound to a
|
|
12
|
+
* "close enough" transaction.
|
|
13
|
+
*/
|
|
14
|
+
export declare function unknownSelectorError(selector: string, suggestions: string[]): ThymianBaseError;
|
|
15
|
+
/** The value is not a selector at all. */
|
|
16
|
+
export declare function malformedSelectorError(value: string, hints?: string[]): ThymianBaseError;
|
|
17
|
+
//# sourceMappingURL=selector-errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selector-errors.d.ts","sourceRoot":"","sources":["../../src/selectors/selector-errors.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAGhB,KAAK,sBAAsB,EAE5B,MAAM,eAAe,CAAC;AA2HvB;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,sBAAsB,EAC7B,MAAM,EAAE,sBAAsB,GAC7B,gBAAgB,CAalB;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EAAE,GACpB,gBAAgB,CASlB;AAED,0CAA0C;AAC1C,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,EACb,KAAK,GAAE,MAAM,EAAO,GACnB,gBAAgB,CAalB"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { ThymianBaseError, thymianRequestToOrigin, } from '@thymian/core';
|
|
2
|
+
/**
|
|
3
|
+
* The selector grammar, written the way the reference pages write it. Kept next
|
|
4
|
+
* to the errors so the diagnostic and the parser cannot drift apart in wording.
|
|
5
|
+
*/
|
|
6
|
+
const SELECTOR_GRAMMAR = 'METHOD SP path [ SP "(" requestMediaType ")" ] SP "->" SP status [ SP "(" responseMediaType ")" ]';
|
|
7
|
+
const SELECTOR_EXAMPLE = 'POST /astronauts (application/json) -> 201 (application/json)';
|
|
8
|
+
function locationToString(location) {
|
|
9
|
+
if (!location) {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
const file = 'path' in location ? location.path : location.uri;
|
|
13
|
+
if (!location.position) {
|
|
14
|
+
return file;
|
|
15
|
+
}
|
|
16
|
+
return `${file}:${location.position.line}:${location.position.column}`;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* `thymianRequestToOrigin` runs the origin through `normalizeUrl`, which throws
|
|
20
|
+
* when `protocol://host:port` is not a URL — an OpenAPI `servers` entry like
|
|
21
|
+
* `file:///tmp/api` leaves `host` empty. That failure must never replace the
|
|
22
|
+
* diagnostic the user actually needs to read.
|
|
23
|
+
*
|
|
24
|
+
* `normalizeUrl` returns `url.toString()`, which appends the empty path as a
|
|
25
|
+
* trailing slash. These sentences end in a period, so the slash is dropped: an
|
|
26
|
+
* origin has none.
|
|
27
|
+
*/
|
|
28
|
+
function originOf(req) {
|
|
29
|
+
try {
|
|
30
|
+
const origin = thymianRequestToOrigin(req);
|
|
31
|
+
return origin.endsWith('/') ? origin.slice(0, -1) : origin;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The source pointer a diagnostic prints.
|
|
39
|
+
*
|
|
40
|
+
* `sourceName` is typed `string` on every node and edge but is not one at
|
|
41
|
+
* runtime: `plugin-openapi` defaults it to `document.info.title`, the config
|
|
42
|
+
* never requires an explicit name, and a missing `title` only warns. So it can
|
|
43
|
+
* arrive `''` or `undefined`, and an unnamed source is named as such — it must
|
|
44
|
+
* never render as `Source ""`, and it must never turn the diagnostic the user
|
|
45
|
+
* needs into a `TypeError`.
|
|
46
|
+
*/
|
|
47
|
+
function describeSource(sourceName, origin, location) {
|
|
48
|
+
const where = locationToString(location);
|
|
49
|
+
return ((sourceName
|
|
50
|
+
? `Source "${sourceName}" describes it`
|
|
51
|
+
: 'An unnamed source describes it') +
|
|
52
|
+
(origin ? ` at ${origin}` : '') +
|
|
53
|
+
(where ? ` (${where}).` : '.'));
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Names a transaction from its RESPONSE node, and takes the location from the
|
|
57
|
+
* same producer — never from a mixture.
|
|
58
|
+
*
|
|
59
|
+
* Of the three carriers of a `sourceName`, the response node is the only one
|
|
60
|
+
* that belongs to the description that actually declared this transaction. A
|
|
61
|
+
* request node is deduped *across* sources, because `sourceName` sits in core's
|
|
62
|
+
* ignored hash properties, and the transaction edge then inherits that deduped
|
|
63
|
+
* name. A response node cannot be shared while a collision exists — its id is
|
|
64
|
+
* derived from the request id and the response's semantic hash, so two sources
|
|
65
|
+
* share it only when the whole transaction is identical, and then it merges and
|
|
66
|
+
* there is nothing to collide.
|
|
67
|
+
*
|
|
68
|
+
* Mixing carriers is what prints source A's name over source B's file: core
|
|
69
|
+
* rewrites an edge's `sourceName` but leaves the producer's `sourceLocation`
|
|
70
|
+
* alone. The edge is consulted for the location only, where it is the same
|
|
71
|
+
* producer's as the response node's.
|
|
72
|
+
*/
|
|
73
|
+
function describeTransaction(transaction) {
|
|
74
|
+
return describeSource(transaction.thymianRes.sourceName, originOf(transaction.thymianReq), transaction.thymianRes.sourceLocation ??
|
|
75
|
+
transaction.transaction.sourceLocation);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The advice every collision gets, whichever kind it is.
|
|
79
|
+
*
|
|
80
|
+
* There is deliberately **no** same-source/cross-source classification. Telling
|
|
81
|
+
* the two apart needs a per-specification identity, and the graph carries only a
|
|
82
|
+
* source *name*: it defaults to `document.info.title` and is never required, so
|
|
83
|
+
* a staging and a production description of one API — the flagship cross-source
|
|
84
|
+
* cause — are indistinguishable by any name-based test, an unnamed description
|
|
85
|
+
* is indistinguishable from every other unnamed one, and a request node deduped
|
|
86
|
+
* across sources hands its name to an edge that never declared it.
|
|
87
|
+
*
|
|
88
|
+
* So the advice names both remedies without asserting which applies. The two
|
|
89
|
+
* lines above it already print each transaction's source and, where the
|
|
90
|
+
* description carries one, its file and position — the evidence a classifier
|
|
91
|
+
* never had, handed to the one reader who can use it.
|
|
92
|
+
*/
|
|
93
|
+
const COLLISION_ADVICE = [
|
|
94
|
+
'A selector is host-stripped and carries no query parameters or headers, so two transactions collide whenever they agree on method, path, status and media types — whether they come from one description or two.',
|
|
95
|
+
'If the two lines above point at different documents, load those sources separately — a source-discriminator syntax does not exist.',
|
|
96
|
+
'If they point at one document, give the two operations distinct paths, methods, statuses or media types.',
|
|
97
|
+
];
|
|
98
|
+
/**
|
|
99
|
+
* Two transactions in the loaded format render the same selector. Fail-fast:
|
|
100
|
+
* nothing is dropped, overwritten or resolved "last wins". This is the one hard
|
|
101
|
+
* error at catalog build — rendering itself never rejects.
|
|
102
|
+
*/
|
|
103
|
+
export function selectorCollisionError(selector, first, second) {
|
|
104
|
+
return new ThymianBaseError(`Two transactions resolve to the same selector "${selector}".`, {
|
|
105
|
+
name: 'SelectorCollisionError',
|
|
106
|
+
ref: 'https://thymian.dev/references/errors/selector-collision-error/',
|
|
107
|
+
suggestions: [
|
|
108
|
+
describeTransaction(first),
|
|
109
|
+
describeTransaction(second),
|
|
110
|
+
...COLLISION_ADVICE,
|
|
111
|
+
],
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* A well-formed selector that names no transaction in the loaded format. The
|
|
116
|
+
* near-miss candidates are supplied by the catalog, which is the only thing that
|
|
117
|
+
* knows what is loaded. A dangling selector is never auto-rebound to a
|
|
118
|
+
* "close enough" transaction.
|
|
119
|
+
*/
|
|
120
|
+
export function unknownSelectorError(selector, suggestions) {
|
|
121
|
+
return new ThymianBaseError(`No transaction matches the selector "${selector}".`, {
|
|
122
|
+
name: 'UnknownSelectorError',
|
|
123
|
+
ref: 'https://thymian.dev/references/errors/unknown-selector-error/',
|
|
124
|
+
suggestions,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
/** The value is not a selector at all. */
|
|
128
|
+
export function malformedSelectorError(value, hints = []) {
|
|
129
|
+
return new ThymianBaseError(`"${value}" is not a valid transaction selector.`, {
|
|
130
|
+
name: 'MalformedSelectorError',
|
|
131
|
+
ref: 'https://thymian.dev/references/errors/malformed-selector-error/',
|
|
132
|
+
suggestions: [
|
|
133
|
+
...hints,
|
|
134
|
+
`Write a selector as ${SELECTOR_GRAMMAR}.`,
|
|
135
|
+
`For example: "${SELECTOR_EXAMPLE}".`,
|
|
136
|
+
],
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=selector-errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selector-errors.js","sourceRoot":"","sources":["../../src/selectors/selector-errors.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAIhB,sBAAsB,GACvB,MAAM,eAAe,CAAC;AAEvB;;;GAGG;AACH,MAAM,gBAAgB,GACpB,mGAAmG,CAAC;AAEtG,MAAM,gBAAgB,GACpB,+DAA+D,CAAC;AAElE,SAAS,gBAAgB,CACvB,QAA2C;IAE3C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,IAAI,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC;IAE/D,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,GAAG,IAAI,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;AACzE,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,QAAQ,CAAC,GAAuB;IACvC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC;QAE3C,OAAO,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC7D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,cAAc,CACrB,UAA8B,EAC9B,MAA0B,EAC1B,QAA2C;IAE3C,MAAM,KAAK,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAEzC,OAAO,CACL,CAAC,UAAU;QACT,CAAC,CAAC,WAAW,UAAU,gBAAgB;QACvC,CAAC,CAAC,gCAAgC,CAAC;QACrC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/B,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAC/B,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,SAAS,mBAAmB,CAAC,WAAmC;IAC9D,OAAO,cAAc,CACnB,WAAW,CAAC,UAAU,CAAC,UAAU,EACjC,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,EAChC,WAAW,CAAC,UAAU,CAAC,cAAc;QACnC,WAAW,CAAC,WAAW,CAAC,cAAc,CACzC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,gBAAgB,GAAG;IACvB,kNAAkN;IAClN,oIAAoI;IACpI,0GAA0G;CAC3G,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CACpC,QAAgB,EAChB,KAA6B,EAC7B,MAA8B;IAE9B,OAAO,IAAI,gBAAgB,CACzB,kDAAkD,QAAQ,IAAI,EAC9D;QACE,IAAI,EAAE,wBAAwB;QAC9B,GAAG,EAAE,iEAAiE;QACtE,WAAW,EAAE;YACX,mBAAmB,CAAC,KAAK,CAAC;YAC1B,mBAAmB,CAAC,MAAM,CAAC;YAC3B,GAAG,gBAAgB;SACpB;KACF,CACF,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAClC,QAAgB,EAChB,WAAqB;IAErB,OAAO,IAAI,gBAAgB,CACzB,wCAAwC,QAAQ,IAAI,EACpD;QACE,IAAI,EAAE,sBAAsB;QAC5B,GAAG,EAAE,+DAA+D;QACpE,WAAW;KACZ,CACF,CAAC;AACJ,CAAC;AAED,0CAA0C;AAC1C,MAAM,UAAU,sBAAsB,CACpC,KAAa,EACb,QAAkB,EAAE;IAEpB,OAAO,IAAI,gBAAgB,CACzB,IAAI,KAAK,wCAAwC,EACjD;QACE,IAAI,EAAE,wBAAwB;QAC9B,GAAG,EAAE,iEAAiE;QACtE,WAAW,EAAE;YACX,GAAG,KAAK;YACR,uBAAuB,gBAAgB,GAAG;YAC1C,iBAAiB,gBAAgB,IAAI;SACtC;KACF,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { canonicalPath, encodeMediaType, encodeMethod, encodePath, formatRequestSelector, formatResponseSelector, formatSelector, type Selector, selectorForTransaction } from '@thymian/core';
|
|
2
|
+
/**
|
|
3
|
+
* The selector grammar, plugin side: everything that reads a selector.
|
|
4
|
+
*
|
|
5
|
+
* **Rendering lives in `@thymian/core`** (`selector/render-selector.ts`) and is
|
|
6
|
+
* re-exported here, because a selector is two things at once — the sampler's
|
|
7
|
+
* *address* of a Transaction and the application's *label* for one — and every
|
|
8
|
+
* surface core prints has to render the same grammar the sampler resolves
|
|
9
|
+
* (ADR-0022). What stays here is what only an address needs: parsing back,
|
|
10
|
+
* near-miss diagnostics and the catalog's ordering.
|
|
11
|
+
*
|
|
12
|
+
* The reader below is the inverse of core's encoders. The two are one grammar
|
|
13
|
+
* split across two packages, so the round-trip property — every rendered
|
|
14
|
+
* selector parses, and parses back to what it was rendered from — is the test
|
|
15
|
+
* that keeps them honest.
|
|
16
|
+
*/
|
|
17
|
+
export { canonicalPath, encodeMediaType, encodeMethod, encodePath, formatRequestSelector, formatResponseSelector, formatSelector, type Selector, selectorForTransaction, };
|
|
18
|
+
export type SelectorParts = {
|
|
19
|
+
method: string;
|
|
20
|
+
path: string;
|
|
21
|
+
requestMediaType?: string;
|
|
22
|
+
status: number;
|
|
23
|
+
responseMediaType?: string;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Total order on selectors, by UTF-16 code unit.
|
|
27
|
+
*
|
|
28
|
+
* Deliberately not `localeCompare`: the catalog's order is the order of the
|
|
29
|
+
* generated type surface, and a locale-sensitive comparison would make the
|
|
30
|
+
* committed types depend on the machine that generated them.
|
|
31
|
+
*/
|
|
32
|
+
export declare function compareSelectors(a: Selector, b: Selector): number;
|
|
33
|
+
/**
|
|
34
|
+
* Parses a selector back into its components.
|
|
35
|
+
*
|
|
36
|
+
* For DIAGNOSTICS ONLY. Resolution is a map lookup
|
|
37
|
+
* (`TransactionCatalog.resolve`); a parse happens only after a miss, to decide
|
|
38
|
+
* whether the value was malformed or merely unknown. Do not move a parse onto
|
|
39
|
+
* the happy path.
|
|
40
|
+
*/
|
|
41
|
+
export declare function parseSelector(value: string): SelectorParts;
|
|
42
|
+
/** Whether `value` is a syntactically well-formed selector. */
|
|
43
|
+
export declare function isSelector(value: string): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* The suggestions a malformed selector's diagnostic carries — the grammar,
|
|
46
|
+
* an example, and a canonical-form guess when the value is close. Never
|
|
47
|
+
* throws.
|
|
48
|
+
*
|
|
49
|
+
* Reads `malformedSelectorError`'s own message composition rather than
|
|
50
|
+
* duplicating it, so a hook-target diagnostic for a malformed Selector and
|
|
51
|
+
* the error `catalog.resolve` throws for one typed on the CLI say exactly the
|
|
52
|
+
* same thing — one grammar, one set of hints, two call sites.
|
|
53
|
+
*/
|
|
54
|
+
export declare function malformedSelectorHints(value: string): string[];
|
|
55
|
+
//# sourceMappingURL=selector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selector.d.ts","sourceRoot":"","sources":["../../src/selectors/selector.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,eAAe,EACf,YAAY,EACZ,UAAU,EAEV,qBAAqB,EACrB,sBAAsB,EACtB,cAAc,EACd,KAAK,QAAQ,EAEb,sBAAsB,EACvB,MAAM,eAAe,CAAC;AAIvB;;;;;;;;;;;;;;GAcG;AACH,OAAO,EACL,aAAa,EACb,eAAe,EACf,YAAY,EACZ,UAAU,EACV,qBAAqB,EACrB,sBAAsB,EACtB,cAAc,EACd,KAAK,QAAQ,EACb,sBAAsB,GACvB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAwGF;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,MAAM,CAEjE;AA2HD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,CAQ1D;AAED,+DAA+D;AAC/D,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAI9D"}
|