@speclynx/apidom-reference 4.13.0 → 4.14.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/src/util/url.cjs CHANGED
@@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequ
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.unsanitize = exports.toFileSystemPath = exports.stripHash = exports.sanitize = exports.resolve = exports.isURI = exports.isHttpUrl = exports.isFileSystemPath = exports.hasProtocol = exports.getProtocol = exports.getHash = exports.getExtension = exports.fromFileSystemPath = exports.cwd = void 0;
7
+ exports.unsanitize = exports.toFileSystemPath = exports.stripHash = exports.sanitize = exports.resolve = exports.isURI = exports.isHttpUrl = exports.isFileSystemPath = exports.hasProtocol = exports.getProtocol = exports.getHash = exports.getExtension = exports.getBasename = exports.fromFileSystemPath = exports.cwd = void 0;
8
8
  var _process = _interopRequireDefault(require("process"));
9
9
  var _ramda = require("ramda");
10
10
  var _ramdaAdjunct = require("ramda-adjunct");
@@ -40,25 +40,47 @@ const getProtocol = url => {
40
40
  exports.getProtocol = getProtocol;
41
41
  const hasProtocol = exports.hasProtocol = (0, _ramda.pipe)(getProtocol, _ramdaAdjunct.isNotUndefined);
42
42
 
43
+ /**
44
+ * Returns the final path segment of the given URI (the part after the last
45
+ * `/`). Inputs are URIs, whose path separator is `/` — filesystem paths are
46
+ * forward-slashed by `sanitize` before reaching here.
47
+ */
48
+ const getFilename = uri => uri.slice(uri.lastIndexOf('/') + 1);
49
+
43
50
  /**
44
51
  * Returns the lower-cased file extension of the given URL,
45
52
  * or an empty string if it has no extension.
46
53
  * @public
47
54
  */
48
55
  const getExtension = url => {
49
- const lastDotPosition = url.lastIndexOf('.');
56
+ const fileName = getFilename(url);
57
+ const lastDotPosition = fileName.lastIndexOf('.');
50
58
  if (lastDotPosition >= 0) {
51
- return url.substring(lastDotPosition).toLowerCase();
59
+ return fileName.substring(lastDotPosition).toLowerCase();
52
60
  }
53
61
  return '';
54
62
  };
55
63
 
64
+ /**
65
+ * Returns the final path segment of the given URI with its file extension
66
+ * removed (e.g. `./schemas/Pet.json` -> `Pet`). Returns the whole segment when
67
+ * there is no extension, and the whole URI when there is no path segment
68
+ * (e.g. a URN).
69
+ * @public
70
+ */
71
+ exports.getExtension = getExtension;
72
+ const getBasename = uri => {
73
+ const fileName = getFilename(uri);
74
+ const extension = getExtension(uri);
75
+ return extension === '' ? fileName : fileName.slice(0, -extension.length);
76
+ };
77
+
56
78
  /**
57
79
  * Determines whether the given path is a filesystem path.
58
80
  * This includes "file://" URLs.
59
81
  * @public
60
82
  */
61
- exports.getExtension = getExtension;
83
+ exports.getBasename = getBasename;
62
84
  const isFileSystemPath = uri => {
63
85
  const protocol = getProtocol(uri);
64
86
  return (0, _ramdaAdjunct.isUndefined)(protocol) || protocol === 'file' || /^[a-zA-Z]$/.test(protocol);
package/src/util/url.mjs CHANGED
@@ -33,19 +33,40 @@ export const getProtocol = url => {
33
33
  */
34
34
  export const hasProtocol = pipe(getProtocol, isNotUndefined);
35
35
 
36
+ /**
37
+ * Returns the final path segment of the given URI (the part after the last
38
+ * `/`). Inputs are URIs, whose path separator is `/` — filesystem paths are
39
+ * forward-slashed by `sanitize` before reaching here.
40
+ */
41
+ const getFilename = uri => uri.slice(uri.lastIndexOf('/') + 1);
42
+
36
43
  /**
37
44
  * Returns the lower-cased file extension of the given URL,
38
45
  * or an empty string if it has no extension.
39
46
  * @public
40
47
  */
41
48
  export const getExtension = url => {
42
- const lastDotPosition = url.lastIndexOf('.');
49
+ const fileName = getFilename(url);
50
+ const lastDotPosition = fileName.lastIndexOf('.');
43
51
  if (lastDotPosition >= 0) {
44
- return url.substring(lastDotPosition).toLowerCase();
52
+ return fileName.substring(lastDotPosition).toLowerCase();
45
53
  }
46
54
  return '';
47
55
  };
48
56
 
57
+ /**
58
+ * Returns the final path segment of the given URI with its file extension
59
+ * removed (e.g. `./schemas/Pet.json` -> `Pet`). Returns the whole segment when
60
+ * there is no extension, and the whole URI when there is no path segment
61
+ * (e.g. a URN).
62
+ * @public
63
+ */
64
+ export const getBasename = uri => {
65
+ const fileName = getFilename(uri);
66
+ const extension = getExtension(uri);
67
+ return extension === '' ? fileName : fileName.slice(0, -extension.length);
68
+ };
69
+
49
70
  /**
50
71
  * Determines whether the given path is a filesystem path.
51
72
  * This includes "file://" URLs.
@@ -240,6 +240,15 @@ export declare interface FileOptions {
240
240
  */
241
241
  declare const fromFileSystemPath: (uri: string) => string;
242
242
 
243
+ /**
244
+ * Returns the final path segment of the given URI with its file extension
245
+ * removed (e.g. `./schemas/Pet.json` -> `Pet`). Returns the whole segment when
246
+ * there is no extension, and the whole URI when there is no path segment
247
+ * (e.g. a URN).
248
+ * @public
249
+ */
250
+ declare const getBasename: (uri: string) => string;
251
+
243
252
  /**
244
253
  * Returns the lower-cased file extension of the given URL,
245
254
  * or an empty string if it has no extension.
@@ -627,6 +636,7 @@ declare namespace url {
627
636
  getProtocol,
628
637
  hasProtocol,
629
638
  getExtension,
639
+ getBasename,
630
640
  isFileSystemPath,
631
641
  isHttpUrl,
632
642
  isURI,
@@ -68,11 +68,11 @@ declare class OpenAPI2BundleVisitor {
68
68
  protected toBaseURI(uri: string): string;
69
69
  protected toReference(uri: string): Promise<Reference>;
70
70
  /**
71
- * Normalizes a self-file reference (e.g. `./root.json#/definitions/Pet`)
71
+ * Normalizes a self-reference (e.g. `./root.json#/definitions/Pet`)
72
72
  * to a bare fragment (`#/definitions/Pet`) so the bundled document stays
73
73
  * transferable. Bare fragments are returned unchanged.
74
74
  */
75
- protected normalizeSelfFileRef(ref: string): string;
75
+ protected normalizeSelfReference(ref: string): string;
76
76
  /**
77
77
  * Handles an error according to the `bundle.continueOnError` option.
78
78
  *
@@ -68,11 +68,11 @@ declare class OpenAPI3_0BundleVisitor {
68
68
  protected toBaseURI(uri: string): string;
69
69
  protected toReference(uri: string): Promise<Reference>;
70
70
  /**
71
- * Normalizes a self-file reference (e.g. `./root.json#/components/schemas/Pet`)
71
+ * Normalizes a self-reference (e.g. `./root.json#/components/schemas/Pet`)
72
72
  * to a bare fragment (`#/components/schemas/Pet`) so the bundled document stays
73
73
  * transferable. Bare fragments are returned unchanged.
74
74
  */
75
- protected normalizeSelfFileRef(ref: string): string;
75
+ protected normalizeSelfReference(ref: string): string;
76
76
  /**
77
77
  * Handles an error according to the `bundle.continueOnError` option.
78
78
  *
@@ -1,15 +1,19 @@
1
1
  import { ParseResultElement } from '@speclynx/apidom-datamodel';
2
2
  import File from '../../../File.ts';
3
3
  import BundleStrategy, { BundleStrategyOptions } from '../BundleStrategy.ts';
4
+ import OpenAPI3_1BundleVisitor from './visitor.ts';
5
+ import type { ReferenceOptions } from '../../../options/index.ts';
4
6
  export type { default as DereferenceStrategy, DereferenceStrategyOptions, } from '../../../dereference/strategies/DereferenceStrategy.ts';
5
7
  export type { default as File, FileOptions } from '../../../File.ts';
6
8
  export type { default as Reference, ReferenceOptions } from '../../../Reference.ts';
7
9
  export type { default as ReferenceSet, ReferenceSetOptions } from '../../../ReferenceSet.ts';
10
+ export type { OpenAPI3_1BundleVisitorOptions } from './visitor.ts';
8
11
  export type { ReferenceOptions as ApiDOMReferenceOptions, ReferenceBundleOptions as ApiDOMReferenceBundleOptions, ReferenceDereferenceOptions as ApiDOMReferenceDereferenceOptions, ReferenceParseOptions as ApiDOMReferenceParseOptions, ReferenceResolveOptions as ApiDOMReferenceResolveOptions, } from '../../../options/index.ts';
9
12
  export type { default as Parser, ParserOptions } from '../../../parse/parsers/Parser.ts';
10
13
  export type { default as Resolver, ResolverOptions } from '../../../resolve/resolvers/Resolver.ts';
11
14
  export type { default as ResolveStrategy, ResolveStrategyOptions, } from '../../../resolve/strategies/ResolveStrategy.ts';
12
15
  export type { default as BundleStrategy, BundleStrategyOptions } from '../BundleStrategy.ts';
16
+ export type { ComponentNamesStrategy, ComponentNameResolver, ComponentNameResolverArgs, ComponentNameCollisionSeverity, } from '../../../options/index.ts';
13
17
  /**
14
18
  * @public
15
19
  */
@@ -21,6 +25,7 @@ export interface OpenAPI3_1BundleStrategyOptions extends Omit<BundleStrategyOpti
21
25
  declare class OpenAPI3_1BundleStrategy extends BundleStrategy {
22
26
  constructor(options?: OpenAPI3_1BundleStrategyOptions);
23
27
  canBundle(file: File): boolean;
24
- bundle(file: File): Promise<ParseResultElement>;
28
+ bundle(file: File, options: ReferenceOptions): Promise<ParseResultElement>;
25
29
  }
30
+ export { OpenAPI3_1BundleVisitor };
26
31
  export default OpenAPI3_1BundleStrategy;
@@ -0,0 +1,141 @@
1
+ import { Element, ObjectElement, ParseResultElement } from '@speclynx/apidom-datamodel';
2
+ import { type Path } from '@speclynx/apidom-traverse';
3
+ import { OpenApi3_1Element } from '@speclynx/apidom-ns-openapi-3-1';
4
+ import Reference from '../../../Reference.ts';
5
+ import type { ReferenceOptions } from '../../../options/index.ts';
6
+ /**
7
+ * @public
8
+ */
9
+ export interface OpenAPI3_1BundleVisitorOptions {
10
+ readonly reference: Reference;
11
+ readonly options: ReferenceOptions;
12
+ readonly assignments?: Map<string, string>;
13
+ readonly reservedNames?: Map<string, Set<string>>;
14
+ readonly refractCache?: WeakMap<Element, Map<string, Element>>;
15
+ }
16
+ /**
17
+ * @public
18
+ */
19
+ declare class OpenAPI3_1BundleVisitor {
20
+ protected readonly reference: Reference;
21
+ protected readonly options: ReferenceOptions;
22
+ /**
23
+ * The base URI (without hash) of the entry document. A reference is
24
+ * considered internal when it resolves to this URI and external otherwise.
25
+ * Derived from the shared refSet's root reference.
26
+ */
27
+ protected get entryURI(): string;
28
+ /**
29
+ * The entry parse result. Derived from the shared refSet's root reference.
30
+ */
31
+ protected get entryParseResult(): ParseResultElement;
32
+ /**
33
+ * The entry document element. Hoisted external fragments are placed into its
34
+ * `components` object. The `canBundle` guard guarantees it is an
35
+ * OpenApi3_1Element.
36
+ */
37
+ protected get entryResult(): OpenApi3_1Element;
38
+ /**
39
+ * Shared across the entry document and every external document visitor.
40
+ * Guarantees each external fragment is hoisted exactly once and gives us a
41
+ * stable internal pointer to rewrite every referencing element to.
42
+ */
43
+ protected readonly assignments: Map<string, string>;
44
+ /**
45
+ * Component names already reserved per Components Object field. Reserved
46
+ * before recursion so collision suffixing (`Pet`, `Pet-2`, ...) accounts for
47
+ * components that are still being bundled.
48
+ */
49
+ protected readonly reservedNames: Map<string, Set<string>>;
50
+ /**
51
+ * Caches refracted fragments keyed by source element and target element type.
52
+ * The type is part of the key because the same source can be refracted into
53
+ * different semantic elements depending on the referencing context (e.g. a
54
+ * generic object referenced once as a Parameter and once as a Response).
55
+ */
56
+ protected readonly refractCache: WeakMap<Element, Map<string, Element>>;
57
+ constructor({ reference, options, assignments, reservedNames, refractCache, }: OpenAPI3_1BundleVisitorOptions);
58
+ protected getRefracted(source: Element, type: string): Element | undefined;
59
+ protected setRefracted(source: Element, type: string, refracted: Element): void;
60
+ protected toBaseURI(uri: string): string;
61
+ protected toReference(uri: string): Promise<Reference>;
62
+ /**
63
+ * Normalizes a self-reference (e.g. `./root.json#/components/schemas/Pet`)
64
+ * to a bare fragment (`#/components/schemas/Pet`) so the bundled document stays
65
+ * transferable. Bare fragments are returned unchanged.
66
+ */
67
+ protected normalizeSelfReference(ref: string): string;
68
+ /**
69
+ * Handles an error according to the `bundle.continueOnError` option.
70
+ *
71
+ * For new errors: wraps in UnresolvableReferenceError with structured
72
+ * context. For errors already wrapped by a nested visitor: prepends the
73
+ * current hop to the trace.
74
+ *
75
+ * Inner/intermediate visitors always throw to let the trace accumulate. Only
76
+ * the entry document visitor respects continueOnError (callback/swallow/throw).
77
+ */
78
+ protected handleError(message: string, error: Error, referencingElement: Element, refFieldName: string, refFieldValue: string, visitorPath: Path<Element>): void;
79
+ /**
80
+ * Lazily creates the Components Object (and the requested field within it)
81
+ * on the entry document, returning the field where a fragment is hoisted.
82
+ */
83
+ protected ensureComponentsField(field: string): ObjectElement;
84
+ /**
85
+ * Derives a component name from the referenced JSON Pointer's last token,
86
+ * falling back to the referenced file's basename.
87
+ */
88
+ protected basenameOf(jsonPointer: string, baseURI: string): string;
89
+ /**
90
+ * Computes the base component name (before collision suffixing) according to
91
+ * the configured naming strategy.
92
+ */
93
+ protected baseName(element: Element, field: string, jsonPointer: string, baseURI: string): string;
94
+ /**
95
+ * Computes a collision-free component name within the target field. A name is
96
+ * taken if it's already placed in components or reserved by a component that
97
+ * is still being bundled (reserved before recursion).
98
+ */
99
+ protected uniqueName(candidate: string, field: string): string;
100
+ /**
101
+ * Reports a collision-forced rename according to the configured severity.
102
+ * A rename means two distinct targets resolved to the same name; each keeps
103
+ * its own component (and origin), so report the rename per severity.
104
+ */
105
+ protected reportNameCollision(preferredName: string, componentName: string, field: string): void;
106
+ ReferenceElement(path: Path<Element>): Promise<void>;
107
+ /**
108
+ * Unlike OpenAPI 3.0 (which has no `components.pathItems` field and therefore
109
+ * inlines external Path Items in place), OpenAPI 3.1 hoists an external Path
110
+ * Item Object into `components.pathItems` and rewrites the referencing `$ref`
111
+ * to an internal pointer — mirroring how Reference Objects are bundled.
112
+ * Sibling fields next to the `$ref` (e.g. `summary`, `description`) are kept
113
+ * on the referencing element.
114
+ */
115
+ PathItemElement(path: Path<Element>): Promise<void>;
116
+ /**
117
+ * Schema Objects in OpenAPI 3.1 are a JSON Schema 2020-12 dialect, so they are
118
+ * bundled per the JSON Schema Compound Document rules: the external schema
119
+ * RESOURCE is embedded verbatim into `components.schemas` (carrying its `$id`),
120
+ * and the referencing `$ref` is left UNCHANGED — it keeps resolving against the
121
+ * embedded resource's `$id`. This mirrors the canonical hyperjump
122
+ * `json-schema-bundle` behavior (the whole resource is embedded once, keyed by
123
+ * its `$id`; references are not rewritten).
124
+ */
125
+ SchemaElement(path: Path<Element>): Promise<void>;
126
+ /**
127
+ * Example Object `externalValue` points at arbitrary external content that
128
+ * has no place in the Components Object. The referenced value is inlined into
129
+ * the Example's `value` field.
130
+ */
131
+ ExampleElement(path: Path<Element>): Promise<void>;
132
+ /**
133
+ * Link Object `operationRef` points at an Operation Object, which has no
134
+ * Components Object field in OpenAPI 3.1 and therefore cannot be hoisted or
135
+ * inlined. To keep the link resolvable from the bundled document, an external
136
+ * `operationRef` is rewritten to its absolute URI. Internal `operationRef`
137
+ * values and `operationId` links are left untouched.
138
+ */
139
+ LinkElement(path: Path<Element>): Promise<void>;
140
+ }
141
+ export default OpenAPI3_1BundleVisitor;
@@ -23,6 +23,14 @@ export declare const hasProtocol: (url: string) => boolean;
23
23
  * @public
24
24
  */
25
25
  export declare const getExtension: (url: string) => string;
26
+ /**
27
+ * Returns the final path segment of the given URI with its file extension
28
+ * removed (e.g. `./schemas/Pet.json` -> `Pet`). Returns the whole segment when
29
+ * there is no extension, and the whole URI when there is no path segment
30
+ * (e.g. a URN).
31
+ * @public
32
+ */
33
+ export declare const getBasename: (uri: string) => string;
26
34
  /**
27
35
  * Determines whether the given path is a filesystem path.
28
36
  * This includes "file://" URLs.