Initial commit

This commit is contained in:
2025-03-07 19:22:02 +01:00
commit 4a98255d83
55743 changed files with 5280367 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
{
"plugins": [
"office-addins"
],
"extends": [
"plugin:office-addins/react"
]
}
+8
View File
@@ -0,0 +1,8 @@
{
"extends": [
"development"
],
"hints": {
"typescript-config/strict": "off"
}
}
+14
View File
@@ -0,0 +1,14 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
// List of extensions which should be recommended for users of this workspace.
"recommendations": [
"ms-edgedevtools.vscode-edge-devtools",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"msoffice.microsoft-office-add-in-debugger"
],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": []
}
+26
View File
@@ -0,0 +1,26 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "PowerPoint Desktop (Edge Chromium)",
"type": "msedge",
"request": "attach",
"port": 9229,
"timeout": 600000,
"webRoot": "${workspaceRoot}",
"preLaunchTask": "Debug: PowerPoint Desktop",
"postDebugTask": "Stop Debug"
},
{
"name": "PowerPoint Desktop (Edge Legacy)",
"type": "office-addin",
"request": "attach",
"url": "https://localhost:3000/taskpane.html?_host_Info=PowerPoint$Win32$16.01$en-US$$$$0",
"port": 9222,
"timeout": 600000,
"webRoot": "${workspaceRoot}",
"preLaunchTask": "Debug: PowerPoint Desktop",
"postDebugTask": "Stop Debug"
}
]
}
+8
View File
@@ -0,0 +1,8 @@
{
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript"
]
}
+160
View File
@@ -0,0 +1,160 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Build (Development)",
"type": "npm",
"script": "build:dev",
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"clear": true,
"panel": "shared",
"showReuseMessage": false
}
},
{
"label": "Build (Production)",
"type": "npm",
"script": "build",
"group": "build",
"presentation": {
"clear": true,
"panel": "shared",
"showReuseMessage": false
}
},
{
"label": "Debug: Excel Desktop",
"type": "shell",
"command": "npm",
"args": [
"run",
"start",
"--",
"desktop",
"--app",
"excel"
],
"presentation": {
"clear": true,
"panel": "dedicated"
},
"problemMatcher": []
},
{
"label": "Debug: Outlook Desktop",
"type": "shell",
"command": "npm",
"args": [
"run",
"start",
"--",
"desktop",
"--app",
"outlook"
],
"presentation": {
"clear": true,
"panel": "dedicated"
},
"problemMatcher": []
},
{
"label": "Debug: PowerPoint Desktop",
"type": "shell",
"command": "npm",
"args": [
"run",
"start",
"--",
"desktop",
"--app",
"powerpoint"
],
"presentation": {
"clear": true,
"panel": "dedicated"
},
"problemMatcher": []
},
{
"label": "Debug: Word Desktop",
"type": "shell",
"command": "npm",
"args": [
"run",
"start",
"--",
"desktop",
"--app",
"word"
],
"presentation": {
"clear": true,
"panel": "dedicated"
},
"problemMatcher": []
},
{
"label": "Dev Server",
"type": "npm",
"script": "dev-server",
"presentation": {
"clear": true,
"panel": "dedicated"
},
"problemMatcher": []
},
{
"label": "Install",
"type": "npm",
"script": "install",
"presentation": {
"clear": true,
"panel": "shared",
"showReuseMessage": false
},
"problemMatcher": []
},
{
"label": "Lint: Check for problems",
"type": "npm",
"script": "lint",
"problemMatcher": [
"$eslint-stylish"
]
},
{
"label": "Lint: Fix all auto-fixable problems",
"type": "npm",
"script": "lint:fix",
"problemMatcher": [
"$eslint-stylish"
]
},
{
"label": "Stop Debug",
"type": "npm",
"script": "stop",
"presentation": {
"clear": true,
"panel": "shared",
"showReuseMessage": false
},
"problemMatcher": []
},
{
"label": "Watch",
"type": "npm",
"script": "watch",
"presentation": {
"clear": true,
"panel": "dedicated"
},
"problemMatcher": []
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

+13
View File
@@ -0,0 +1,13 @@
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"esmodules": false
}
}
],
"@babel/preset-typescript"
]
}
+85
View File
@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<OfficeApp xmlns="http://schemas.microsoft.com/office/appforoffice/1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bt="http://schemas.microsoft.com/office/officeappbasictypes/1.0" xmlns:ov="http://schemas.microsoft.com/office/taskpaneappversionoverrides" xsi:type="TaskPaneApp">
<Id>be5c6f61-4bbf-4bd2-a8da-5031abf096a5</Id>
<Version>1.0.0.0</Version>
<ProviderName>Contoso</ProviderName>
<DefaultLocale>en-US</DefaultLocale>
<DisplayName DefaultValue="Edison"/>
<Description DefaultValue="Edison - PowerPoint shape tools for better presentations."/>
<IconUrl DefaultValue="https://localhost:3000/assets/icon-32.png"/>
<HighResolutionIconUrl DefaultValue="https://localhost:3000/assets/icon-64.png"/>
<SupportUrl DefaultValue="https://www.contoso.com/help"/>
<AppDomains>
<AppDomain>https://www.contoso.com</AppDomain>
</AppDomains>
<Hosts>
<Host Name="Presentation"/>
</Hosts>
<DefaultSettings>
<SourceLocation DefaultValue="https://localhost:3000/taskpane.html"/>
</DefaultSettings>
<Permissions>ReadWriteDocument</Permissions>
<VersionOverrides xmlns="http://schemas.microsoft.com/office/taskpaneappversionoverrides" xsi:type="VersionOverridesV1_0">
<Hosts>
<Host xsi:type="Presentation">
<DesktopFormFactor>
<GetStarted>
<Title resid="GetStarted.Title"/>
<Description resid="GetStarted.Description"/>
<LearnMoreUrl resid="GetStarted.LearnMoreUrl"/>
</GetStarted>
<FunctionFile resid="Commands.Url"/>
<ExtensionPoint xsi:type="PrimaryCommandSurface">
<OfficeTab id="TabHome">
<Group id="CommandsGroup">
<Label resid="CommandsGroup.Label"/>
<Icon>
<bt:Image size="16" resid="Icon.16x16"/>
<bt:Image size="32" resid="Icon.32x32"/>
<bt:Image size="80" resid="Icon.80x80"/>
</Icon>
<Control xsi:type="Button" id="TaskpaneButton">
<Label resid="TaskpaneButton.Label"/>
<Supertip>
<Title resid="TaskpaneButton.Label"/>
<Description resid="TaskpaneButton.Tooltip"/>
</Supertip>
<Icon>
<bt:Image size="16" resid="Icon.16x16"/>
<bt:Image size="32" resid="Icon.32x32"/>
<bt:Image size="80" resid="Icon.80x80"/>
</Icon>
<Action xsi:type="ShowTaskpane">
<TaskpaneId>ButtonId1</TaskpaneId>
<SourceLocation resid="Taskpane.Url"/>
</Action>
</Control>
</Group>
</OfficeTab>
</ExtensionPoint>
</DesktopFormFactor>
</Host>
</Hosts>
<Resources>
<bt:Images>
<bt:Image id="Icon.16x16" DefaultValue="https://localhost:3000/assets/icon-16.png"/>
<bt:Image id="Icon.32x32" DefaultValue="https://localhost:3000/assets/icon-32.png"/>
<bt:Image id="Icon.80x80" DefaultValue="https://localhost:3000/assets/icon-80.png"/>
</bt:Images>
<bt:Urls>
<bt:Url id="GetStarted.LearnMoreUrl" DefaultValue="https://go.microsoft.com/fwlink/?LinkId=276812"/>
<bt:Url id="Commands.Url" DefaultValue="https://localhost:3000/commands.html"/>
<bt:Url id="Taskpane.Url" DefaultValue="https://localhost:3000/taskpane.html"/>
</bt:Urls>
<bt:ShortStrings>
<bt:String id="GetStarted.Title" DefaultValue="Get started with your sample add-in!"/>
<bt:String id="CommandsGroup.Label" DefaultValue="Edison"/>
<bt:String id="TaskpaneButton.Label" DefaultValue="Open Sidebar"/>
</bt:ShortStrings>
<bt:LongStrings>
<bt:String id="GetStarted.Description" DefaultValue="Your sample add-in loaded successfully."/>
<bt:String id="TaskpaneButton.Tooltip" DefaultValue="Click to open the add-in taskpane"/>
</bt:LongStrings>
</Resources>
</VersionOverrides>
</OfficeApp>
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../acorn/bin/acorn
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../ansi-html-community/bin/ansi-html
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../swagger2openapi/boast.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../browserslist/cli.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../detect-port/bin/detect-port.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../detect-port/bin/detect-port.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../envinfo/dist/cli.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../errno/cli.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../eslint/bin/eslint.js
+1
View File
@@ -0,0 +1 @@
../eslint-config-prettier/bin/cli.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../esprima/bin/esparse.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../esprima/bin/esvalidate.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../flat/cli.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../fast-xml-parser/src/cli/cli.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../handlebars/bin/handlebars
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../he/bin/he
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../html-minifier-terser/cli.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../image-size/bin/image-size.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../import-local/fixtures/cli.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../is-docker/cli.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../is-inside-container/cli.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../js-yaml/bin/js-yaml.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../jsesc/bin/jsesc
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../json5/lib/cli.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../less/bin/lessc
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../loose-envify/cli.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../mime/cli.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../mkcert/dist/cli.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../multicast-dns/cli.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../mustache/bin/mustache
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../needle/bin/needle
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../which/bin/node-which
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../swagger2openapi/oas-validate.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../office-addin-cli/cli.js
+1
View File
@@ -0,0 +1 @@
../office-addin-debugging/cli.js
+1
View File
@@ -0,0 +1 @@
../office-addin-dev-certs/cli.js
+1
View File
@@ -0,0 +1 @@
../office-addin-dev-settings/cli.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../office-addin-lint/lib/cli.js
+1
View File
@@ -0,0 +1 @@
../office-addin-manifest/cli.js
+1
View File
@@ -0,0 +1 @@
../office-addin-manifest-converter/cli.js
+1
View File
@@ -0,0 +1 @@
../office-addin-node-debugger/cli.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../office-addin-project/cli.js
+1
View File
@@ -0,0 +1 @@
../office-addin-usage-data/cli.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../@babel/parser/bin/babel-parser.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../prebuild-install/bin.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../prettier/bin/prettier.cjs
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../rc/cli.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../regjsparser/bin/parser
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../oas-resolver/resolve.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../semver/bin/semver.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../swagger2openapi/swagger2openapi.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../@microsoft/teamsapp-cli/cli.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../terser/bin/terser
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../tree-kill/cli.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../typescript/bin/tsc
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../typescript/bin/tsserver
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../uglify-js/bin/uglifyjs
+1
View File
@@ -0,0 +1 @@
../update-browserslist-db/cli.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../uuid/dist/bin/uuid
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../webpack/bin/webpack.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../webpack-cli/bin/cli.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../webpack-dev-server/bin/webpack-dev-server.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../yaml/bin.mjs
+16647
View File
File diff suppressed because it is too large Load Diff
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+218
View File
@@ -0,0 +1,218 @@
# @ampproject/remapping
> Remap sequential sourcemaps through transformations to point at the original source code
Remapping allows you to take the sourcemaps generated through transforming your code and "remap"
them to the original source locations. Think "my minified code, transformed with babel and bundled
with webpack", all pointing to the correct location in your original source code.
With remapping, none of your source code transformations need to be aware of the input's sourcemap,
they only need to generate an output sourcemap. This greatly simplifies building custom
transformations (think a find-and-replace).
## Installation
```sh
npm install @ampproject/remapping
```
## Usage
```typescript
function remapping(
map: SourceMap | SourceMap[],
loader: (file: string, ctx: LoaderContext) => (SourceMap | null | undefined),
options?: { excludeContent: boolean, decodedMappings: boolean }
): SourceMap;
// LoaderContext gives the loader the importing sourcemap, tree depth, the ability to override the
// "source" location (where child sources are resolved relative to, or the location of original
// source), and the ability to override the "content" of an original source for inclusion in the
// output sourcemap.
type LoaderContext = {
readonly importer: string;
readonly depth: number;
source: string;
content: string | null | undefined;
}
```
`remapping` takes the final output sourcemap, and a `loader` function. For every source file pointer
in the sourcemap, the `loader` will be called with the resolved path. If the path itself represents
a transformed file (it has a sourcmap associated with it), then the `loader` should return that
sourcemap. If not, the path will be treated as an original, untransformed source code.
```js
// Babel transformed "helloworld.js" into "transformed.js"
const transformedMap = JSON.stringify({
file: 'transformed.js',
// 1st column of 2nd line of output file translates into the 1st source
// file, line 3, column 2
mappings: ';CAEE',
sources: ['helloworld.js'],
version: 3,
});
// Uglify minified "transformed.js" into "transformed.min.js"
const minifiedTransformedMap = JSON.stringify({
file: 'transformed.min.js',
// 0th column of 1st line of output file translates into the 1st source
// file, line 2, column 1.
mappings: 'AACC',
names: [],
sources: ['transformed.js'],
version: 3,
});
const remapped = remapping(
minifiedTransformedMap,
(file, ctx) => {
// The "transformed.js" file is an transformed file.
if (file === 'transformed.js') {
// The root importer is empty.
console.assert(ctx.importer === '');
// The depth in the sourcemap tree we're currently loading.
// The root `minifiedTransformedMap` is depth 0, and its source children are depth 1, etc.
console.assert(ctx.depth === 1);
return transformedMap;
}
// Loader will be called to load transformedMap's source file pointers as well.
console.assert(file === 'helloworld.js');
// `transformed.js`'s sourcemap points into `helloworld.js`.
console.assert(ctx.importer === 'transformed.js');
// This is a source child of `transformed`, which is a source child of `minifiedTransformedMap`.
console.assert(ctx.depth === 2);
return null;
}
);
console.log(remapped);
// {
// file: 'transpiled.min.js',
// mappings: 'AAEE',
// sources: ['helloworld.js'],
// version: 3,
// };
```
In this example, `loader` will be called twice:
1. `"transformed.js"`, the first source file pointer in the `minifiedTransformedMap`. We return the
associated sourcemap for it (its a transformed file, after all) so that sourcemap locations can
be traced through it into the source files it represents.
2. `"helloworld.js"`, our original, unmodified source code. This file does not have a sourcemap, so
we return `null`.
The `remapped` sourcemap now points from `transformed.min.js` into locations in `helloworld.js`. If
you were to read the `mappings`, it says "0th column of the first line output line points to the 1st
column of the 2nd line of the file `helloworld.js`".
### Multiple transformations of a file
As a convenience, if you have multiple single-source transformations of a file, you may pass an
array of sourcemap files in the order of most-recent transformation sourcemap first. Note that this
changes the `importer` and `depth` of each call to our loader. So our above example could have been
written as:
```js
const remapped = remapping(
[minifiedTransformedMap, transformedMap],
() => null
);
console.log(remapped);
// {
// file: 'transpiled.min.js',
// mappings: 'AAEE',
// sources: ['helloworld.js'],
// version: 3,
// };
```
### Advanced control of the loading graph
#### `source`
The `source` property can overridden to any value to change the location of the current load. Eg,
for an original source file, it allows us to change the location to the original source regardless
of what the sourcemap source entry says. And for transformed files, it allows us to change the
relative resolving location for child sources of the loaded sourcemap.
```js
const remapped = remapping(
minifiedTransformedMap,
(file, ctx) => {
if (file === 'transformed.js') {
// We pretend the transformed.js file actually exists in the 'src/' directory. When the nested
// source files are loaded, they will now be relative to `src/`.
ctx.source = 'src/transformed.js';
return transformedMap;
}
console.assert(file === 'src/helloworld.js');
// We could futher change the source of this original file, eg, to be inside a nested directory
// itself. This will be reflected in the remapped sourcemap.
ctx.source = 'src/nested/transformed.js';
return null;
}
);
console.log(remapped);
// {
// …,
// sources: ['src/nested/helloworld.js'],
// };
```
#### `content`
The `content` property can be overridden when we encounter an original source file. Eg, this allows
you to manually provide the source content of the original file regardless of whether the
`sourcesContent` field is present in the parent sourcemap. It can also be set to `null` to remove
the source content.
```js
const remapped = remapping(
minifiedTransformedMap,
(file, ctx) => {
if (file === 'transformed.js') {
// transformedMap does not include a `sourcesContent` field, so usually the remapped sourcemap
// would not include any `sourcesContent` values.
return transformedMap;
}
console.assert(file === 'helloworld.js');
// We can read the file to provide the source content.
ctx.content = fs.readFileSync(file, 'utf8');
return null;
}
);
console.log(remapped);
// {
// …,
// sourcesContent: [
// 'console.log("Hello world!")',
// ],
// };
```
### Options
#### excludeContent
By default, `excludeContent` is `false`. Passing `{ excludeContent: true }` will exclude the
`sourcesContent` field from the returned sourcemap. This is mainly useful when you want to reduce
the size out the sourcemap.
#### decodedMappings
By default, `decodedMappings` is `false`. Passing `{ decodedMappings: true }` will leave the
`mappings` field in a [decoded state](https://github.com/rich-harris/sourcemap-codec) instead of
encoding into a VLQ string.
+197
View File
@@ -0,0 +1,197 @@
import { decodedMappings, traceSegment, TraceMap } from '@jridgewell/trace-mapping';
import { GenMapping, maybeAddSegment, setSourceContent, setIgnore, toDecodedMap, toEncodedMap } from '@jridgewell/gen-mapping';
const SOURCELESS_MAPPING = /* #__PURE__ */ SegmentObject('', -1, -1, '', null, false);
const EMPTY_SOURCES = [];
function SegmentObject(source, line, column, name, content, ignore) {
return { source, line, column, name, content, ignore };
}
function Source(map, sources, source, content, ignore) {
return {
map,
sources,
source,
content,
ignore,
};
}
/**
* MapSource represents a single sourcemap, with the ability to trace mappings into its child nodes
* (which may themselves be SourceMapTrees).
*/
function MapSource(map, sources) {
return Source(map, sources, '', null, false);
}
/**
* A "leaf" node in the sourcemap tree, representing an original, unmodified source file. Recursive
* segment tracing ends at the `OriginalSource`.
*/
function OriginalSource(source, content, ignore) {
return Source(null, EMPTY_SOURCES, source, content, ignore);
}
/**
* traceMappings is only called on the root level SourceMapTree, and begins the process of
* resolving each mapping in terms of the original source files.
*/
function traceMappings(tree) {
// TODO: Eventually support sourceRoot, which has to be removed because the sources are already
// fully resolved. We'll need to make sources relative to the sourceRoot before adding them.
const gen = new GenMapping({ file: tree.map.file });
const { sources: rootSources, map } = tree;
const rootNames = map.names;
const rootMappings = decodedMappings(map);
for (let i = 0; i < rootMappings.length; i++) {
const segments = rootMappings[i];
for (let j = 0; j < segments.length; j++) {
const segment = segments[j];
const genCol = segment[0];
let traced = SOURCELESS_MAPPING;
// 1-length segments only move the current generated column, there's no source information
// to gather from it.
if (segment.length !== 1) {
const source = rootSources[segment[1]];
traced = originalPositionFor(source, segment[2], segment[3], segment.length === 5 ? rootNames[segment[4]] : '');
// If the trace is invalid, then the trace ran into a sourcemap that doesn't contain a
// respective segment into an original source.
if (traced == null)
continue;
}
const { column, line, name, content, source, ignore } = traced;
maybeAddSegment(gen, i, genCol, source, line, column, name);
if (source && content != null)
setSourceContent(gen, source, content);
if (ignore)
setIgnore(gen, source, true);
}
}
return gen;
}
/**
* originalPositionFor is only called on children SourceMapTrees. It recurses down into its own
* child SourceMapTrees, until we find the original source map.
*/
function originalPositionFor(source, line, column, name) {
if (!source.map) {
return SegmentObject(source.source, line, column, name, source.content, source.ignore);
}
const segment = traceSegment(source.map, line, column);
// If we couldn't find a segment, then this doesn't exist in the sourcemap.
if (segment == null)
return null;
// 1-length segments only move the current generated column, there's no source information
// to gather from it.
if (segment.length === 1)
return SOURCELESS_MAPPING;
return originalPositionFor(source.sources[segment[1]], segment[2], segment[3], segment.length === 5 ? source.map.names[segment[4]] : name);
}
function asArray(value) {
if (Array.isArray(value))
return value;
return [value];
}
/**
* Recursively builds a tree structure out of sourcemap files, with each node
* being either an `OriginalSource` "leaf" or a `SourceMapTree` composed of
* `OriginalSource`s and `SourceMapTree`s.
*
* Every sourcemap is composed of a collection of source files and mappings
* into locations of those source files. When we generate a `SourceMapTree` for
* the sourcemap, we attempt to load each source file's own sourcemap. If it
* does not have an associated sourcemap, it is considered an original,
* unmodified source file.
*/
function buildSourceMapTree(input, loader) {
const maps = asArray(input).map((m) => new TraceMap(m, ''));
const map = maps.pop();
for (let i = 0; i < maps.length; i++) {
if (maps[i].sources.length > 1) {
throw new Error(`Transformation map ${i} must have exactly one source file.\n` +
'Did you specify these with the most recent transformation maps first?');
}
}
let tree = build(map, loader, '', 0);
for (let i = maps.length - 1; i >= 0; i--) {
tree = MapSource(maps[i], [tree]);
}
return tree;
}
function build(map, loader, importer, importerDepth) {
const { resolvedSources, sourcesContent, ignoreList } = map;
const depth = importerDepth + 1;
const children = resolvedSources.map((sourceFile, i) => {
// The loading context gives the loader more information about why this file is being loaded
// (eg, from which importer). It also allows the loader to override the location of the loaded
// sourcemap/original source, or to override the content in the sourcesContent field if it's
// an unmodified source file.
const ctx = {
importer,
depth,
source: sourceFile || '',
content: undefined,
ignore: undefined,
};
// Use the provided loader callback to retrieve the file's sourcemap.
// TODO: We should eventually support async loading of sourcemap files.
const sourceMap = loader(ctx.source, ctx);
const { source, content, ignore } = ctx;
// If there is a sourcemap, then we need to recurse into it to load its source files.
if (sourceMap)
return build(new TraceMap(sourceMap, source), loader, source, depth);
// Else, it's an unmodified source file.
// The contents of this unmodified source file can be overridden via the loader context,
// allowing it to be explicitly null or a string. If it remains undefined, we fall back to
// the importing sourcemap's `sourcesContent` field.
const sourceContent = content !== undefined ? content : sourcesContent ? sourcesContent[i] : null;
const ignored = ignore !== undefined ? ignore : ignoreList ? ignoreList.includes(i) : false;
return OriginalSource(source, sourceContent, ignored);
});
return MapSource(map, children);
}
/**
* A SourceMap v3 compatible sourcemap, which only includes fields that were
* provided to it.
*/
class SourceMap {
constructor(map, options) {
const out = options.decodedMappings ? toDecodedMap(map) : toEncodedMap(map);
this.version = out.version; // SourceMap spec says this should be first.
this.file = out.file;
this.mappings = out.mappings;
this.names = out.names;
this.ignoreList = out.ignoreList;
this.sourceRoot = out.sourceRoot;
this.sources = out.sources;
if (!options.excludeContent) {
this.sourcesContent = out.sourcesContent;
}
}
toString() {
return JSON.stringify(this);
}
}
/**
* Traces through all the mappings in the root sourcemap, through the sources
* (and their sourcemaps), all the way back to the original source location.
*
* `loader` will be called every time we encounter a source file. If it returns
* a sourcemap, we will recurse into that sourcemap to continue the trace. If
* it returns a falsey value, that source file is treated as an original,
* unmodified source file.
*
* Pass `excludeContent` to exclude any self-containing source file content
* from the output sourcemap.
*
* Pass `decodedMappings` to receive a SourceMap with decoded (instead of
* VLQ encoded) mappings.
*/
function remapping(input, loader, options) {
const opts = typeof options === 'object' ? options : { excludeContent: !!options, decodedMappings: false };
const tree = buildSourceMapTree(input, loader);
return new SourceMap(traceMappings(tree), opts);
}
export { remapping as default };
//# sourceMappingURL=remapping.mjs.map
File diff suppressed because one or more lines are too long
+202
View File
@@ -0,0 +1,202 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('@jridgewell/trace-mapping'), require('@jridgewell/gen-mapping')) :
typeof define === 'function' && define.amd ? define(['@jridgewell/trace-mapping', '@jridgewell/gen-mapping'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.remapping = factory(global.traceMapping, global.genMapping));
})(this, (function (traceMapping, genMapping) { 'use strict';
const SOURCELESS_MAPPING = /* #__PURE__ */ SegmentObject('', -1, -1, '', null, false);
const EMPTY_SOURCES = [];
function SegmentObject(source, line, column, name, content, ignore) {
return { source, line, column, name, content, ignore };
}
function Source(map, sources, source, content, ignore) {
return {
map,
sources,
source,
content,
ignore,
};
}
/**
* MapSource represents a single sourcemap, with the ability to trace mappings into its child nodes
* (which may themselves be SourceMapTrees).
*/
function MapSource(map, sources) {
return Source(map, sources, '', null, false);
}
/**
* A "leaf" node in the sourcemap tree, representing an original, unmodified source file. Recursive
* segment tracing ends at the `OriginalSource`.
*/
function OriginalSource(source, content, ignore) {
return Source(null, EMPTY_SOURCES, source, content, ignore);
}
/**
* traceMappings is only called on the root level SourceMapTree, and begins the process of
* resolving each mapping in terms of the original source files.
*/
function traceMappings(tree) {
// TODO: Eventually support sourceRoot, which has to be removed because the sources are already
// fully resolved. We'll need to make sources relative to the sourceRoot before adding them.
const gen = new genMapping.GenMapping({ file: tree.map.file });
const { sources: rootSources, map } = tree;
const rootNames = map.names;
const rootMappings = traceMapping.decodedMappings(map);
for (let i = 0; i < rootMappings.length; i++) {
const segments = rootMappings[i];
for (let j = 0; j < segments.length; j++) {
const segment = segments[j];
const genCol = segment[0];
let traced = SOURCELESS_MAPPING;
// 1-length segments only move the current generated column, there's no source information
// to gather from it.
if (segment.length !== 1) {
const source = rootSources[segment[1]];
traced = originalPositionFor(source, segment[2], segment[3], segment.length === 5 ? rootNames[segment[4]] : '');
// If the trace is invalid, then the trace ran into a sourcemap that doesn't contain a
// respective segment into an original source.
if (traced == null)
continue;
}
const { column, line, name, content, source, ignore } = traced;
genMapping.maybeAddSegment(gen, i, genCol, source, line, column, name);
if (source && content != null)
genMapping.setSourceContent(gen, source, content);
if (ignore)
genMapping.setIgnore(gen, source, true);
}
}
return gen;
}
/**
* originalPositionFor is only called on children SourceMapTrees. It recurses down into its own
* child SourceMapTrees, until we find the original source map.
*/
function originalPositionFor(source, line, column, name) {
if (!source.map) {
return SegmentObject(source.source, line, column, name, source.content, source.ignore);
}
const segment = traceMapping.traceSegment(source.map, line, column);
// If we couldn't find a segment, then this doesn't exist in the sourcemap.
if (segment == null)
return null;
// 1-length segments only move the current generated column, there's no source information
// to gather from it.
if (segment.length === 1)
return SOURCELESS_MAPPING;
return originalPositionFor(source.sources[segment[1]], segment[2], segment[3], segment.length === 5 ? source.map.names[segment[4]] : name);
}
function asArray(value) {
if (Array.isArray(value))
return value;
return [value];
}
/**
* Recursively builds a tree structure out of sourcemap files, with each node
* being either an `OriginalSource` "leaf" or a `SourceMapTree` composed of
* `OriginalSource`s and `SourceMapTree`s.
*
* Every sourcemap is composed of a collection of source files and mappings
* into locations of those source files. When we generate a `SourceMapTree` for
* the sourcemap, we attempt to load each source file's own sourcemap. If it
* does not have an associated sourcemap, it is considered an original,
* unmodified source file.
*/
function buildSourceMapTree(input, loader) {
const maps = asArray(input).map((m) => new traceMapping.TraceMap(m, ''));
const map = maps.pop();
for (let i = 0; i < maps.length; i++) {
if (maps[i].sources.length > 1) {
throw new Error(`Transformation map ${i} must have exactly one source file.\n` +
'Did you specify these with the most recent transformation maps first?');
}
}
let tree = build(map, loader, '', 0);
for (let i = maps.length - 1; i >= 0; i--) {
tree = MapSource(maps[i], [tree]);
}
return tree;
}
function build(map, loader, importer, importerDepth) {
const { resolvedSources, sourcesContent, ignoreList } = map;
const depth = importerDepth + 1;
const children = resolvedSources.map((sourceFile, i) => {
// The loading context gives the loader more information about why this file is being loaded
// (eg, from which importer). It also allows the loader to override the location of the loaded
// sourcemap/original source, or to override the content in the sourcesContent field if it's
// an unmodified source file.
const ctx = {
importer,
depth,
source: sourceFile || '',
content: undefined,
ignore: undefined,
};
// Use the provided loader callback to retrieve the file's sourcemap.
// TODO: We should eventually support async loading of sourcemap files.
const sourceMap = loader(ctx.source, ctx);
const { source, content, ignore } = ctx;
// If there is a sourcemap, then we need to recurse into it to load its source files.
if (sourceMap)
return build(new traceMapping.TraceMap(sourceMap, source), loader, source, depth);
// Else, it's an unmodified source file.
// The contents of this unmodified source file can be overridden via the loader context,
// allowing it to be explicitly null or a string. If it remains undefined, we fall back to
// the importing sourcemap's `sourcesContent` field.
const sourceContent = content !== undefined ? content : sourcesContent ? sourcesContent[i] : null;
const ignored = ignore !== undefined ? ignore : ignoreList ? ignoreList.includes(i) : false;
return OriginalSource(source, sourceContent, ignored);
});
return MapSource(map, children);
}
/**
* A SourceMap v3 compatible sourcemap, which only includes fields that were
* provided to it.
*/
class SourceMap {
constructor(map, options) {
const out = options.decodedMappings ? genMapping.toDecodedMap(map) : genMapping.toEncodedMap(map);
this.version = out.version; // SourceMap spec says this should be first.
this.file = out.file;
this.mappings = out.mappings;
this.names = out.names;
this.ignoreList = out.ignoreList;
this.sourceRoot = out.sourceRoot;
this.sources = out.sources;
if (!options.excludeContent) {
this.sourcesContent = out.sourcesContent;
}
}
toString() {
return JSON.stringify(this);
}
}
/**
* Traces through all the mappings in the root sourcemap, through the sources
* (and their sourcemaps), all the way back to the original source location.
*
* `loader` will be called every time we encounter a source file. If it returns
* a sourcemap, we will recurse into that sourcemap to continue the trace. If
* it returns a falsey value, that source file is treated as an original,
* unmodified source file.
*
* Pass `excludeContent` to exclude any self-containing source file content
* from the output sourcemap.
*
* Pass `decodedMappings` to receive a SourceMap with decoded (instead of
* VLQ encoded) mappings.
*/
function remapping(input, loader, options) {
const opts = typeof options === 'object' ? options : { excludeContent: !!options, decodedMappings: false };
const tree = buildSourceMapTree(input, loader);
return new SourceMap(traceMappings(tree), opts);
}
return remapping;
}));
//# sourceMappingURL=remapping.umd.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,14 @@
import type { MapSource as MapSourceType } from './source-map-tree';
import type { SourceMapInput, SourceMapLoader } from './types';
/**
* Recursively builds a tree structure out of sourcemap files, with each node
* being either an `OriginalSource` "leaf" or a `SourceMapTree` composed of
* `OriginalSource`s and `SourceMapTree`s.
*
* Every sourcemap is composed of a collection of source files and mappings
* into locations of those source files. When we generate a `SourceMapTree` for
* the sourcemap, we attempt to load each source file's own sourcemap. If it
* does not have an associated sourcemap, it is considered an original,
* unmodified source file.
*/
export default function buildSourceMapTree(input: SourceMapInput | SourceMapInput[], loader: SourceMapLoader): MapSourceType;
+20
View File
@@ -0,0 +1,20 @@
import SourceMap from './source-map';
import type { SourceMapInput, SourceMapLoader, Options } from './types';
export type { SourceMapSegment, EncodedSourceMap, EncodedSourceMap as RawSourceMap, DecodedSourceMap, SourceMapInput, SourceMapLoader, LoaderContext, Options, } from './types';
export type { SourceMap };
/**
* Traces through all the mappings in the root sourcemap, through the sources
* (and their sourcemaps), all the way back to the original source location.
*
* `loader` will be called every time we encounter a source file. If it returns
* a sourcemap, we will recurse into that sourcemap to continue the trace. If
* it returns a falsey value, that source file is treated as an original,
* unmodified source file.
*
* Pass `excludeContent` to exclude any self-containing source file content
* from the output sourcemap.
*
* Pass `decodedMappings` to receive a SourceMap with decoded (instead of
* VLQ encoded) mappings.
*/
export default function remapping(input: SourceMapInput | SourceMapInput[], loader: SourceMapLoader, options?: boolean | Options): SourceMap;
+45
View File
@@ -0,0 +1,45 @@
import { GenMapping } from '@jridgewell/gen-mapping';
import type { TraceMap } from '@jridgewell/trace-mapping';
export declare type SourceMapSegmentObject = {
column: number;
line: number;
name: string;
source: string;
content: string | null;
ignore: boolean;
};
export declare type OriginalSource = {
map: null;
sources: Sources[];
source: string;
content: string | null;
ignore: boolean;
};
export declare type MapSource = {
map: TraceMap;
sources: Sources[];
source: string;
content: null;
ignore: false;
};
export declare type Sources = OriginalSource | MapSource;
/**
* MapSource represents a single sourcemap, with the ability to trace mappings into its child nodes
* (which may themselves be SourceMapTrees).
*/
export declare function MapSource(map: TraceMap, sources: Sources[]): MapSource;
/**
* A "leaf" node in the sourcemap tree, representing an original, unmodified source file. Recursive
* segment tracing ends at the `OriginalSource`.
*/
export declare function OriginalSource(source: string, content: string | null, ignore: boolean): OriginalSource;
/**
* traceMappings is only called on the root level SourceMapTree, and begins the process of
* resolving each mapping in terms of the original source files.
*/
export declare function traceMappings(tree: MapSource): GenMapping;
/**
* originalPositionFor is only called on children SourceMapTrees. It recurses down into its own
* child SourceMapTrees, until we find the original source map.
*/
export declare function originalPositionFor(source: Sources, line: number, column: number, name: string): SourceMapSegmentObject | null;
+18
View File
@@ -0,0 +1,18 @@
import type { GenMapping } from '@jridgewell/gen-mapping';
import type { DecodedSourceMap, EncodedSourceMap, Options } from './types';
/**
* A SourceMap v3 compatible sourcemap, which only includes fields that were
* provided to it.
*/
export default class SourceMap {
file?: string | null;
mappings: EncodedSourceMap['mappings'] | DecodedSourceMap['mappings'];
sourceRoot?: string;
names: string[];
sources: (string | null)[];
sourcesContent?: (string | null)[];
version: 3;
ignoreList: number[] | undefined;
constructor(map: GenMapping, options: Options);
toString(): string;
}
+15
View File
@@ -0,0 +1,15 @@
import type { SourceMapInput } from '@jridgewell/trace-mapping';
export type { SourceMapSegment, DecodedSourceMap, EncodedSourceMap, } from '@jridgewell/trace-mapping';
export type { SourceMapInput };
export declare type LoaderContext = {
readonly importer: string;
readonly depth: number;
source: string;
content: string | null | undefined;
ignore: boolean | undefined;
};
export declare type SourceMapLoader = (file: string, ctx: LoaderContext) => SourceMapInput | null | undefined | void;
export declare type Options = {
excludeContent?: boolean;
decodedMappings?: boolean;
};
+75
View File
@@ -0,0 +1,75 @@
{
"name": "@ampproject/remapping",
"version": "2.3.0",
"description": "Remap sequential sourcemaps through transformations to point at the original source code",
"keywords": [
"source",
"map",
"remap"
],
"main": "dist/remapping.umd.js",
"module": "dist/remapping.mjs",
"types": "dist/types/remapping.d.ts",
"exports": {
".": [
{
"types": "./dist/types/remapping.d.ts",
"browser": "./dist/remapping.umd.js",
"require": "./dist/remapping.umd.js",
"import": "./dist/remapping.mjs"
},
"./dist/remapping.umd.js"
],
"./package.json": "./package.json"
},
"files": [
"dist"
],
"author": "Justin Ridgewell <jridgewell@google.com>",
"repository": {
"type": "git",
"url": "git+https://github.com/ampproject/remapping.git"
},
"license": "Apache-2.0",
"engines": {
"node": ">=6.0.0"
},
"scripts": {
"build": "run-s -n build:*",
"build:rollup": "rollup -c rollup.config.js",
"build:ts": "tsc --project tsconfig.build.json",
"lint": "run-s -n lint:*",
"lint:prettier": "npm run test:lint:prettier -- --write",
"lint:ts": "npm run test:lint:ts -- --fix",
"prebuild": "rm -rf dist",
"prepublishOnly": "npm run preversion",
"preversion": "run-s test build",
"test": "run-s -n test:lint test:only",
"test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand",
"test:lint": "run-s -n test:lint:*",
"test:lint:prettier": "prettier --check '{src,test}/**/*.ts'",
"test:lint:ts": "eslint '{src,test}/**/*.ts'",
"test:only": "jest --coverage",
"test:watch": "jest --coverage --watch"
},
"devDependencies": {
"@rollup/plugin-typescript": "8.3.2",
"@types/jest": "27.4.1",
"@typescript-eslint/eslint-plugin": "5.20.0",
"@typescript-eslint/parser": "5.20.0",
"eslint": "8.14.0",
"eslint-config-prettier": "8.5.0",
"jest": "27.5.1",
"jest-config": "27.5.1",
"npm-run-all": "4.1.5",
"prettier": "2.6.2",
"rollup": "2.70.2",
"ts-jest": "27.1.4",
"tslib": "2.4.0",
"typescript": "4.6.3"
},
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.24"
}
}
+21
View File
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 James Messinger
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+168
View File
@@ -0,0 +1,168 @@
# JSON Schema $Ref Parser
#### Parse, Resolve, and Dereference JSON Schema $ref pointers
[![Build Status](https://github.com/APIDevTools/json-schema-ref-parser/workflows/CI-CD/badge.svg?branch=master)](https://github.com/APIDevTools/json-schema-ref-parser/actions)
[![Coverage Status](https://coveralls.io/repos/github/APIDevTools/json-schema-ref-parser/badge.svg?branch=master)](https://coveralls.io/github/APIDevTools/json-schema-ref-parser)
[![npm](https://img.shields.io/npm/v/@apidevtools/json-schema-ref-parser.svg)](https://www.npmjs.com/package/@apidevtools/json-schema-ref-parser)
[![License](https://img.shields.io/npm/l/@apidevtools/json-schema-ref-parser.svg)](LICENSE)
[![Buy us a tree](https://img.shields.io/badge/Treeware-%F0%9F%8C%B3-lightgreen)](https://plant.treeware.earth/APIDevTools/json-schema-ref-parser)
## Installation
Install using [npm](https://docs.npmjs.com/about-npm/):
```bash
npm install @apidevtools/json-schema-ref-parser
yarn add @apidevtools/json-schema-ref-parser
bun add @apidevtools/json-schema-ref-parser
```
## The Problem:
You've got a JSON Schema with `$ref` pointers to other files and/or URLs. Maybe you know all the referenced files ahead
of time. Maybe you don't. Maybe some are local files, and others are remote URLs. Maybe they are a mix of JSON and YAML
format. Maybe some of the files contain cross-references to each other.
```json
{
"definitions": {
"person": {
// references an external file
"$ref": "schemas/people/Bruce-Wayne.json"
},
"place": {
// references a sub-schema in an external file
"$ref": "schemas/places.yaml#/definitions/Gotham-City"
},
"thing": {
// references a URL
"$ref": "http://wayne-enterprises.com/things/batmobile"
},
"color": {
// references a value in an external file via an internal reference
"$ref": "#/definitions/thing/properties/colors/black-as-the-night"
}
}
}
```
## The Solution:
JSON Schema $Ref Parser is a full [JSON Reference](https://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03)
and [JSON Pointer](https://tools.ietf.org/html/rfc6901) implementation that crawls even the most
complex [JSON Schemas](http://json-schema.org/latest/json-schema-core.html) and gives you simple, straightforward
JavaScript objects.
- Use **JSON** or **YAML** schemas &mdash; or even a mix of both!
- Supports `$ref` pointers to external files and URLs, as well
as [custom sources](https://apitools.dev/json-schema-ref-parser/docs/plugins/resolvers.html) such as databases
- Can [bundle](https://apitools.dev/json-schema-ref-parser/docs/ref-parser.html#bundlepath-options-callback) multiple
files into a single schema that only has _internal_ `$ref` pointers
- Can [dereference](https://apitools.dev/json-schema-ref-parser/docs/ref-parser.html#dereferencepath-options-callback)
your schema, producing a plain-old JavaScript object that's easy to work with
- Supports [circular references](https://apitools.dev/json-schema-ref-parser/docs/#circular-refs), nested references,
back-references, and cross-references between files
- Maintains object reference equality &mdash; `$ref` pointers to the same value always resolve to the same object
instance
- Compatible with Node LTS and beyond, and all major web browsers on Windows, Mac, and Linux
## Example
```javascript
import $RefParser from "@apidevtools/json-schema-ref-parser";
try {
await $RefParser.dereference(mySchema);
// note - by default, mySchema is modified in place, and the returned value is a reference to the same object
console.log(mySchema.definitions.person.properties.firstName);
// if you want to avoid modifying the original schema, you can disable the `mutateInputSchema` option
let clonedSchema = await $RefParser.dereference(mySchema, { mutateInputSchema: false });
console.log(clonedSchema.definitions.person.properties.firstName);
} catch (err) {
console.error(err);
}
```
For more detailed examples, please see the [API Documentation](https://apitools.dev/json-schema-ref-parser/docs/)
## Polyfills
If you are using Node.js < 18, you'll need a polyfill for `fetch`,
like [node-fetch](https://github.com/node-fetch/node-fetch):
```javascript
import fetch from "node-fetch";
globalThis.fetch = fetch;
```
## Browser support
JSON Schema $Ref Parser supports recent versions of every major web browser. Older browsers may
require [Babel](https://babeljs.io/) and/or [polyfills](https://babeljs.io/docs/en/next/babel-polyfill).
To use JSON Schema $Ref Parser in a browser, you'll need to use a bundling tool such
as [Webpack](https://webpack.js.org/), [Rollup](https://rollupjs.org/), [Parcel](https://parceljs.org/),
or [Browserify](http://browserify.org/). Some bundlers may require a bit of configuration, such as
setting `browser: true` in [rollup-plugin-resolve](https://github.com/rollup/rollup-plugin-node-resolve).
#### Webpack 5
Webpack 5 has dropped the default export of node core modules in favour of polyfills, you'll need to set them up
yourself ( after npm-installing them )
Edit your `webpack.config.js` :
```js
config.resolve.fallback = {
path: require.resolve("path-browserify"),
fs: require.resolve("browserify-fs"),
};
config.plugins.push(
new webpack.ProvidePlugin({
Buffer: ["buffer", "Buffer"],
}),
);
```
## API Documentation
Full API documentation is available [right here](https://apitools.dev/json-schema-ref-parser/docs/)
## Contributing
I welcome any contributions, enhancements, and
bug-fixes. [Open an issue](https://github.com/APIDevTools/json-schema-ref-parser/issues) on GitHub
and [submit a pull request](https://github.com/APIDevTools/json-schema-ref-parser/pulls).
#### Building/Testing
To build/test the project locally on your computer:
1. **Clone this repo**<br>
`git clone https://github.com/APIDevTools/json-schema-ref-parser.git`
2. **Install dependencies**<br>
`yarn install`
3. **Run the tests**<br>
`yarn test`
## License
JSON Schema $Ref Parser is 100% free and open-source, under the [MIT license](LICENSE). Use it however you want.
This package is [Treeware](http://treeware.earth). If you use it in production, then we ask that you [**buy the world a
tree**](https://plant.treeware.earth/APIDevTools/json-schema-ref-parser) to thank us for our work. By contributing to
the Treeware forest youll be creating employment for local families and restoring wildlife habitats.
## Big Thanks To
Thanks to these awesome companies for their support of Open Source developers ❤
[![Stoplight](https://svgshare.com/i/TK5.svg)](https://stoplight.io/?utm_source=github&utm_medium=readme&utm_campaign=json_schema_ref_parser)
[![SauceLabs](https://jstools.dev/img/badges/sauce-labs.svg)](https://saucelabs.com)
[![Coveralls](https://jstools.dev/img/badges/coveralls.svg)](https://coveralls.io)
+27
View File
@@ -0,0 +1,27 @@
import type $RefParser from "./index";
import type { ParserOptions } from "./index";
import type { JSONSchema } from "./index";
export interface InventoryEntry {
$ref: any;
parent: any;
key: any;
pathFromRoot: any;
depth: any;
file: any;
hash: any;
value: any;
circular: any;
extended: any;
external: any;
indirections: any;
}
/**
* Bundles all external JSON references into the main JSON schema, thus resulting in a schema that
* only has *internal* references, not any *external* references.
* This method mutates the JSON schema object, adding new references and re-mapping existing ones.
*
* @param parser
* @param options
*/
declare function bundle<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(parser: $RefParser<S, O>, options: O): void;
export default bundle;
+283
View File
@@ -0,0 +1,283 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const ref_js_1 = __importDefault(require("./ref.js"));
const pointer_js_1 = __importDefault(require("./pointer.js"));
const url = __importStar(require("./util/url.js"));
/**
* Bundles all external JSON references into the main JSON schema, thus resulting in a schema that
* only has *internal* references, not any *external* references.
* This method mutates the JSON schema object, adding new references and re-mapping existing ones.
*
* @param parser
* @param options
*/
function bundle(parser, options) {
// console.log('Bundling $ref pointers in %s', parser.$refs._root$Ref.path);
// Build an inventory of all $ref pointers in the JSON Schema
const inventory = [];
crawl(parser, "schema", parser.$refs._root$Ref.path + "#", "#", 0, inventory, parser.$refs, options);
// Remap all $ref pointers
remap(inventory);
}
/**
* Recursively crawls the given value, and inventories all JSON references.
*
* @param parent - The object containing the value to crawl. If the value is not an object or array, it will be ignored.
* @param key - The property key of `parent` to be crawled
* @param path - The full path of the property being crawled, possibly with a JSON Pointer in the hash
* @param pathFromRoot - The path of the property being crawled, from the schema root
* @param indirections
* @param inventory - An array of already-inventoried $ref pointers
* @param $refs
* @param options
*/
function crawl(parent, key, path, pathFromRoot, indirections, inventory, $refs, options) {
const obj = key === null ? parent : parent[key];
if (obj && typeof obj === "object" && !ArrayBuffer.isView(obj)) {
if (ref_js_1.default.isAllowed$Ref(obj)) {
inventory$Ref(parent, key, path, pathFromRoot, indirections, inventory, $refs, options);
}
else {
// Crawl the object in a specific order that's optimized for bundling.
// This is important because it determines how `pathFromRoot` gets built,
// which later determines which keys get dereferenced and which ones get remapped
const keys = Object.keys(obj).sort((a, b) => {
// Most people will expect references to be bundled into the the "definitions" property,
// so we always crawl that property first, if it exists.
if (a === "definitions") {
return -1;
}
else if (b === "definitions") {
return 1;
}
else {
// Otherwise, crawl the keys based on their length.
// This produces the shortest possible bundled references
return a.length - b.length;
}
});
for (const key of keys) {
const keyPath = pointer_js_1.default.join(path, key);
const keyPathFromRoot = pointer_js_1.default.join(pathFromRoot, key);
const value = obj[key];
if (ref_js_1.default.isAllowed$Ref(value)) {
inventory$Ref(obj, key, path, keyPathFromRoot, indirections, inventory, $refs, options);
}
else {
crawl(obj, key, keyPath, keyPathFromRoot, indirections, inventory, $refs, options);
}
}
}
}
}
/**
* Inventories the given JSON Reference (i.e. records detailed information about it so we can
* optimize all $refs in the schema), and then crawls the resolved value.
*
* @param $refParent - The object that contains a JSON Reference as one of its keys
* @param $refKey - The key in `$refParent` that is a JSON Reference
* @param path - The full path of the JSON Reference at `$refKey`, possibly with a JSON Pointer in the hash
* @param indirections - unknown
* @param pathFromRoot - The path of the JSON Reference at `$refKey`, from the schema root
* @param inventory - An array of already-inventoried $ref pointers
* @param $refs
* @param options
*/
function inventory$Ref($refParent, $refKey, path, pathFromRoot, indirections, inventory, $refs, options) {
const $ref = $refKey === null ? $refParent : $refParent[$refKey];
const $refPath = url.resolve(path, $ref.$ref);
const pointer = $refs._resolve($refPath, pathFromRoot, options);
if (pointer === null) {
return;
}
const parsed = pointer_js_1.default.parse(pathFromRoot);
const depth = parsed.length;
const file = url.stripHash(pointer.path);
const hash = url.getHash(pointer.path);
const external = file !== $refs._root$Ref.path;
const extended = ref_js_1.default.isExtended$Ref($ref);
indirections += pointer.indirections;
const existingEntry = findInInventory(inventory, $refParent, $refKey);
if (existingEntry) {
// This $Ref has already been inventoried, so we don't need to process it again
if (depth < existingEntry.depth || indirections < existingEntry.indirections) {
removeFromInventory(inventory, existingEntry);
}
else {
return;
}
}
inventory.push({
$ref, // The JSON Reference (e.g. {$ref: string})
parent: $refParent, // The object that contains this $ref pointer
key: $refKey, // The key in `parent` that is the $ref pointer
pathFromRoot, // The path to the $ref pointer, from the JSON Schema root
depth, // How far from the JSON Schema root is this $ref pointer?
file, // The file that the $ref pointer resolves to
hash, // The hash within `file` that the $ref pointer resolves to
value: pointer.value, // The resolved value of the $ref pointer
circular: pointer.circular, // Is this $ref pointer DIRECTLY circular? (i.e. it references itself)
extended, // Does this $ref extend its resolved value? (i.e. it has extra properties, in addition to "$ref")
external, // Does this $ref pointer point to a file other than the main JSON Schema file?
indirections, // The number of indirect references that were traversed to resolve the value
});
// Recursively crawl the resolved value
if (!existingEntry || external) {
crawl(pointer.value, null, pointer.path, pathFromRoot, indirections + 1, inventory, $refs, options);
}
}
/**
* Re-maps every $ref pointer, so that they're all relative to the root of the JSON Schema.
* Each referenced value is dereferenced EXACTLY ONCE. All subsequent references to the same
* value are re-mapped to point to the first reference.
*
* @example: {
* first: { $ref: somefile.json#/some/part },
* second: { $ref: somefile.json#/another/part },
* third: { $ref: somefile.json },
* fourth: { $ref: somefile.json#/some/part/sub/part }
* }
*
* In this example, there are four references to the same file, but since the third reference points
* to the ENTIRE file, that's the only one we need to dereference. The other three can just be
* remapped to point inside the third one.
*
* On the other hand, if the third reference DIDN'T exist, then the first and second would both need
* to be dereferenced, since they point to different parts of the file. The fourth reference does NOT
* need to be dereferenced, because it can be remapped to point inside the first one.
*
* @param inventory
*/
function remap(inventory) {
// Group & sort all the $ref pointers, so they're in the order that we need to dereference/remap them
inventory.sort((a, b) => {
if (a.file !== b.file) {
// Group all the $refs that point to the same file
return a.file < b.file ? -1 : +1;
}
else if (a.hash !== b.hash) {
// Group all the $refs that point to the same part of the file
return a.hash < b.hash ? -1 : +1;
}
else if (a.circular !== b.circular) {
// If the $ref points to itself, then sort it higher than other $refs that point to this $ref
return a.circular ? -1 : +1;
}
else if (a.extended !== b.extended) {
// If the $ref extends the resolved value, then sort it lower than other $refs that don't extend the value
return a.extended ? +1 : -1;
}
else if (a.indirections !== b.indirections) {
// Sort direct references higher than indirect references
return a.indirections - b.indirections;
}
else if (a.depth !== b.depth) {
// Sort $refs by how close they are to the JSON Schema root
return a.depth - b.depth;
}
else {
// Determine how far each $ref is from the "definitions" property.
// Most people will expect references to be bundled into the the "definitions" property if possible.
const aDefinitionsIndex = a.pathFromRoot.lastIndexOf("/definitions");
const bDefinitionsIndex = b.pathFromRoot.lastIndexOf("/definitions");
if (aDefinitionsIndex !== bDefinitionsIndex) {
// Give higher priority to the $ref that's closer to the "definitions" property
return bDefinitionsIndex - aDefinitionsIndex;
}
else {
// All else is equal, so use the shorter path, which will produce the shortest possible reference
return a.pathFromRoot.length - b.pathFromRoot.length;
}
}
});
let file, hash, pathFromRoot;
for (const entry of inventory) {
// console.log('Re-mapping $ref pointer "%s" at %s', entry.$ref.$ref, entry.pathFromRoot);
if (!entry.external) {
// This $ref already resolves to the main JSON Schema file
entry.$ref.$ref = entry.hash;
}
else if (entry.file === file && entry.hash === hash) {
// This $ref points to the same value as the prevous $ref, so remap it to the same path
entry.$ref.$ref = pathFromRoot;
}
else if (entry.file === file && entry.hash.indexOf(hash + "/") === 0) {
// This $ref points to a sub-value of the prevous $ref, so remap it beneath that path
entry.$ref.$ref = pointer_js_1.default.join(pathFromRoot, pointer_js_1.default.parse(entry.hash.replace(hash, "#")));
}
else {
// We've moved to a new file or new hash
file = entry.file;
hash = entry.hash;
pathFromRoot = entry.pathFromRoot;
// This is the first $ref to point to this value, so dereference the value.
// Any other $refs that point to the same value will point to this $ref instead
entry.$ref = entry.parent[entry.key] = ref_js_1.default.dereference(entry.$ref, entry.value);
if (entry.circular) {
// This $ref points to itself
entry.$ref.$ref = entry.pathFromRoot;
}
}
}
// we want to ensure that any $refs that point to another $ref are remapped to point to the final value
// let hadChange = true;
// while (hadChange) {
// hadChange = false;
// for (const entry of inventory) {
// if (entry.$ref && typeof entry.$ref === "object" && "$ref" in entry.$ref) {
// const resolved = inventory.find((e: InventoryEntry) => e.pathFromRoot === entry.$ref.$ref);
// if (resolved) {
// const resolvedPointsToAnotherRef =
// resolved.$ref && typeof resolved.$ref === "object" && "$ref" in resolved.$ref;
// if (resolvedPointsToAnotherRef && entry.$ref.$ref !== resolved.$ref.$ref) {
// // console.log('Re-mapping $ref pointer "%s" at %s', entry.$ref.$ref, entry.pathFromRoot);
// entry.$ref.$ref = resolved.$ref.$ref;
// hadChange = true;
// }
// }
// }
// }
// }
}
/**
* TODO
*/
function findInInventory(inventory, $refParent, $refKey) {
for (const existingEntry of inventory) {
if (existingEntry && existingEntry.parent === $refParent && existingEntry.key === $refKey) {
return existingEntry;
}
}
return undefined;
}
function removeFromInventory(inventory, entry) {
const index = inventory.indexOf(entry);
inventory.splice(index, 1);
}
exports.default = bundle;
@@ -0,0 +1,12 @@
import type { ParserOptions } from "./options.js";
import type { JSONSchema } from "./types";
import type $RefParser from "./index";
export default dereference;
/**
* Crawls the JSON schema, finds all JSON references, and dereferences them.
* This method mutates the JSON schema object, replacing JSON references with their resolved value.
*
* @param parser
* @param options
*/
declare function dereference<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(parser: $RefParser<S, O>, options: O): void;
@@ -0,0 +1,216 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const ref_js_1 = __importDefault(require("./ref.js"));
const pointer_js_1 = __importDefault(require("./pointer.js"));
const ono_1 = require("@jsdevtools/ono");
const url = __importStar(require("./util/url.js"));
const errors_1 = require("./util/errors");
exports.default = dereference;
/**
* Crawls the JSON schema, finds all JSON references, and dereferences them.
* This method mutates the JSON schema object, replacing JSON references with their resolved value.
*
* @param parser
* @param options
*/
function dereference(parser, options) {
const start = Date.now();
// console.log('Dereferencing $ref pointers in %s', parser.$refs._root$Ref.path);
const dereferenced = crawl(parser.schema, parser.$refs._root$Ref.path, "#", new Set(), new Set(), new Map(), parser.$refs, options, start);
parser.$refs.circular = dereferenced.circular;
parser.schema = dereferenced.value;
}
/**
* Recursively crawls the given value, and dereferences any JSON references.
*
* @param obj - The value to crawl. If it's not an object or array, it will be ignored.
* @param path - The full path of `obj`, possibly with a JSON Pointer in the hash
* @param pathFromRoot - The path of `obj` from the schema root
* @param parents - An array of the parent objects that have already been dereferenced
* @param processedObjects - An array of all the objects that have already been processed
* @param dereferencedCache - An map of all the dereferenced objects
* @param $refs
* @param options
* @param startTime - The time when the dereferencing started
* @returns
*/
function crawl(obj, path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options, startTime) {
let dereferenced;
const result = {
value: obj,
circular: false,
};
if (options && options.timeoutMs) {
if (Date.now() - startTime > options.timeoutMs) {
throw new errors_1.TimeoutError(options.timeoutMs);
}
}
const derefOptions = (options.dereference || {});
const isExcludedPath = derefOptions.excludedPathMatcher || (() => false);
if (derefOptions?.circular === "ignore" || !processedObjects.has(obj)) {
if (obj && typeof obj === "object" && !ArrayBuffer.isView(obj) && !isExcludedPath(pathFromRoot)) {
parents.add(obj);
processedObjects.add(obj);
if (ref_js_1.default.isAllowed$Ref(obj, options)) {
dereferenced = dereference$Ref(obj, path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options, startTime);
result.circular = dereferenced.circular;
result.value = dereferenced.value;
}
else {
for (const key of Object.keys(obj)) {
const keyPath = pointer_js_1.default.join(path, key);
const keyPathFromRoot = pointer_js_1.default.join(pathFromRoot, key);
if (isExcludedPath(keyPathFromRoot)) {
continue;
}
const value = obj[key];
let circular = false;
if (ref_js_1.default.isAllowed$Ref(value, options)) {
dereferenced = dereference$Ref(value, keyPath, keyPathFromRoot, parents, processedObjects, dereferencedCache, $refs, options, startTime);
circular = dereferenced.circular;
// Avoid pointless mutations; breaks frozen objects to no profit
if (obj[key] !== dereferenced.value) {
obj[key] = dereferenced.value;
derefOptions?.onDereference?.(value.$ref, obj[key], obj, key);
}
}
else {
if (!parents.has(value)) {
dereferenced = crawl(value, keyPath, keyPathFromRoot, parents, processedObjects, dereferencedCache, $refs, options, startTime);
circular = dereferenced.circular;
// Avoid pointless mutations; breaks frozen objects to no profit
if (obj[key] !== dereferenced.value) {
obj[key] = dereferenced.value;
}
}
else {
circular = foundCircularReference(keyPath, $refs, options);
}
}
// Set the "isCircular" flag if this or any other property is circular
result.circular = result.circular || circular;
}
}
parents.delete(obj);
}
}
return result;
}
/**
* Dereferences the given JSON Reference, and then crawls the resulting value.
*
* @param $ref - The JSON Reference to resolve
* @param path - The full path of `$ref`, possibly with a JSON Pointer in the hash
* @param pathFromRoot - The path of `$ref` from the schema root
* @param parents - An array of the parent objects that have already been dereferenced
* @param processedObjects - An array of all the objects that have already been dereferenced
* @param dereferencedCache - An map of all the dereferenced objects
* @param $refs
* @param options
* @returns
*/
function dereference$Ref($ref, path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options, startTime) {
const isExternalRef = ref_js_1.default.isExternal$Ref($ref);
const shouldResolveOnCwd = isExternalRef && options?.dereference?.externalReferenceResolution === "root";
const $refPath = url.resolve(shouldResolveOnCwd ? url.cwd() : path, $ref.$ref);
const cache = dereferencedCache.get($refPath);
if (cache && !cache.circular) {
const refKeys = Object.keys($ref);
if (refKeys.length > 1) {
const extraKeys = {};
for (const key of refKeys) {
if (key !== "$ref" && !(key in cache.value)) {
// @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
extraKeys[key] = $ref[key];
}
}
return {
circular: cache.circular,
value: Object.assign({}, cache.value, extraKeys),
};
}
return cache;
}
const pointer = $refs._resolve($refPath, path, options);
if (pointer === null) {
return {
circular: false,
value: null,
};
}
// Check for circular references
const directCircular = pointer.circular;
let circular = directCircular || parents.has(pointer.value);
if (circular) {
foundCircularReference(path, $refs, options);
}
// Dereference the JSON reference
let dereferencedValue = ref_js_1.default.dereference($ref, pointer.value);
// Crawl the dereferenced value (unless it's circular)
if (!circular) {
// Determine if the dereferenced value is circular
const dereferenced = crawl(dereferencedValue, pointer.path, pathFromRoot, parents, processedObjects, dereferencedCache, $refs, options, startTime);
circular = dereferenced.circular;
dereferencedValue = dereferenced.value;
}
if (circular && !directCircular && options.dereference?.circular === "ignore") {
// The user has chosen to "ignore" circular references, so don't change the value
dereferencedValue = $ref;
}
if (directCircular) {
// The pointer is a DIRECT circular reference (i.e. it references itself).
// So replace the $ref path with the absolute path from the JSON Schema root
dereferencedValue.$ref = pathFromRoot;
}
const dereferencedObject = {
circular,
value: dereferencedValue,
};
// only cache if no extra properties than $ref
if (Object.keys($ref).length === 1) {
dereferencedCache.set($refPath, dereferencedObject);
}
return dereferencedObject;
}
/**
* Called when a circular reference is found.
* It sets the {@link $Refs#circular} flag, and throws an error if options.dereference.circular is false.
*
* @param keyPath - The JSON Reference path of the circular reference
* @param $refs
* @param options
* @returns - always returns true, to indicate that a circular reference was found
*/
function foundCircularReference(keyPath, $refs, options) {
$refs.circular = true;
if (!options.dereference.circular) {
throw ono_1.ono.reference(`Circular $ref pointer found at ${keyPath}`);
}
return true;
}
+162
View File
@@ -0,0 +1,162 @@
import $Refs from "./refs.js";
import normalizeArgs from "./normalize-args.js";
import _dereference from "./dereference.js";
import { JSONParserError, InvalidPointerError, MissingPointerError, ResolverError, ParserError, UnmatchedParserError, UnmatchedResolverError, isHandledError, JSONParserErrorGroup } from "./util/errors.js";
import type { ParserOptions } from "./options.js";
import { getJsonSchemaRefParserDefaultOptions } from "./options.js";
import type { $RefsCallback, JSONSchema, SchemaCallback, FileInfo, Plugin, ResolverOptions, HTTPResolverOptions } from "./types/index.js";
export type RefParserSchema = string | JSONSchema;
/**
* This class parses a JSON schema, builds a map of its JSON references and their resolved values,
* and provides methods for traversing, manipulating, and dereferencing those references.
*
* @class
*/
export declare class $RefParser<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>> {
/**
* The parsed (and possibly dereferenced) JSON schema object
*
* @type {object}
* @readonly
*/
schema: S | null;
/**
* The resolved JSON references
*
* @type {$Refs}
* @readonly
*/
$refs: $Refs<S, O>;
/**
* Parses the given JSON schema.
* This method does not resolve any JSON references.
* It just reads a single file in JSON or YAML format, and parse it as a JavaScript object.
*
* @param [path] - The file path or URL of the JSON schema
* @param [schema] - A JSON schema object. This object will be used instead of reading from `path`.
* @param [options] - Options that determine how the schema is parsed
* @param [callback] - An error-first callback. The second parameter is the parsed JSON schema object.
* @returns - The returned promise resolves with the parsed JSON schema object.
*/
parse(schema: S | string | unknown): Promise<S>;
parse(schema: S | string | unknown, callback: SchemaCallback<S>): Promise<void>;
parse(schema: S | string | unknown, options: O): Promise<S>;
parse(schema: S | string | unknown, options: O, callback: SchemaCallback<S>): Promise<void>;
parse(baseUrl: string, schema: S | string | unknown, options: O): Promise<S>;
parse(baseUrl: string, schema: S | string | unknown, options: O, callback: SchemaCallback<S>): Promise<void>;
static parse<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(schema: S | string | unknown): Promise<S>;
static parse<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(schema: S | string | unknown, callback: SchemaCallback<S>): Promise<void>;
static parse<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(schema: S | string | unknown, options: O): Promise<S>;
static parse<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(schema: S | string | unknown, options: O, callback: SchemaCallback<S>): Promise<void>;
static parse<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(baseUrl: string, schema: S | string | unknown, options: O): Promise<S>;
static parse<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(baseUrl: string, schema: S | string | unknown, options: O, callback: SchemaCallback<S>): Promise<void>;
/**
* *This method is used internally by other methods, such as `bundle` and `dereference`. You probably won't need to call this method yourself.*
*
* Resolves all JSON references (`$ref` pointers) in the given JSON Schema file. If it references any other files/URLs, then they will be downloaded and resolved as well. This method **does not** dereference anything. It simply gives you a `$Refs` object, which is a map of all the resolved references and their values.
*
* See https://apitools.dev/json-schema-ref-parser/docs/ref-parser.html#resolveschema-options-callback
*
* @param schema A JSON Schema object, or the file path or URL of a JSON Schema file. See the `parse` method for more info.
* @param options (optional)
* @param callback (optional) A callback that will receive a `$Refs` object
*/
resolve(schema: S | string | unknown): Promise<$Refs<S, O>>;
resolve(schema: S | string | unknown, callback: $RefsCallback<S, O>): Promise<void>;
resolve(schema: S | string | unknown, options: O): Promise<$Refs<S, O>>;
resolve(schema: S | string | unknown, options: O, callback: $RefsCallback<S, O>): Promise<void>;
resolve(baseUrl: string, schema: S | string | unknown, options: O): Promise<$Refs<S, O>>;
resolve(baseUrl: string, schema: S | string | unknown, options: O, callback: $RefsCallback<S, O>): Promise<void>;
/**
* *This method is used internally by other methods, such as `bundle` and `dereference`. You probably won't need to call this method yourself.*
*
* Resolves all JSON references (`$ref` pointers) in the given JSON Schema file. If it references any other files/URLs, then they will be downloaded and resolved as well. This method **does not** dereference anything. It simply gives you a `$Refs` object, which is a map of all the resolved references and their values.
*
* See https://apitools.dev/json-schema-ref-parser/docs/ref-parser.html#resolveschema-options-callback
*
* @param schema A JSON Schema object, or the file path or URL of a JSON Schema file. See the `parse` method for more info.
* @param options (optional)
* @param callback (optional) A callback that will receive a `$Refs` object
*/
static resolve<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(schema: S | string | unknown): Promise<$Refs<S, O>>;
static resolve<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(schema: S | string | unknown, callback: $RefsCallback<S, O>): Promise<void>;
static resolve<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(schema: S | string | unknown, options: O): Promise<$Refs<S, O>>;
static resolve<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(schema: S | string | unknown, options: O, callback: $RefsCallback<S, O>): Promise<void>;
static resolve<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(baseUrl: string, schema: S | string | unknown, options: O): Promise<$Refs<S, O>>;
static resolve<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(baseUrl: string, schema: S | string | unknown, options: O, callback: $RefsCallback<S, O>): Promise<void>;
/**
* Bundles all referenced files/URLs into a single schema that only has internal `$ref` pointers. This lets you split-up your schema however you want while you're building it, but easily combine all those files together when it's time to package or distribute the schema to other people. The resulting schema size will be small, since it will still contain internal JSON references rather than being fully-dereferenced.
*
* This also eliminates the risk of circular references, so the schema can be safely serialized using `JSON.stringify()`.
*
* See https://apitools.dev/json-schema-ref-parser/docs/ref-parser.html#bundleschema-options-callback
*
* @param schema A JSON Schema object, or the file path or URL of a JSON Schema file. See the `parse` method for more info.
* @param options (optional)
* @param callback (optional) A callback that will receive the bundled schema object
*/
static bundle<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(schema: S | string | unknown): Promise<S>;
static bundle<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(schema: S | string | unknown, callback: SchemaCallback<S>): Promise<void>;
static bundle<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(schema: S | string | unknown, options: O): Promise<S>;
static bundle<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(schema: S | string | unknown, options: O, callback: SchemaCallback<S>): Promise<void>;
static bundle<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(baseUrl: string, schema: S | string | unknown, options: O): Promise<S>;
static bundle<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(baseUrl: string, schema: S | string | unknown, options: O, callback: SchemaCallback<S>): Promise<S>;
/**
* Bundles all referenced files/URLs into a single schema that only has internal `$ref` pointers. This lets you split-up your schema however you want while you're building it, but easily combine all those files together when it's time to package or distribute the schema to other people. The resulting schema size will be small, since it will still contain internal JSON references rather than being fully-dereferenced.
*
* This also eliminates the risk of circular references, so the schema can be safely serialized using `JSON.stringify()`.
*
* See https://apitools.dev/json-schema-ref-parser/docs/ref-parser.html#bundleschema-options-callback
*
* @param schema A JSON Schema object, or the file path or URL of a JSON Schema file. See the `parse` method for more info.
* @param options (optional)
* @param callback (optional) A callback that will receive the bundled schema object
*/
bundle(schema: S | string | unknown): Promise<S>;
bundle(schema: S | string | unknown, callback: SchemaCallback<S>): Promise<void>;
bundle(schema: S | string | unknown, options: O): Promise<S>;
bundle(schema: S | string | unknown, options: O, callback: SchemaCallback<S>): Promise<void>;
bundle(baseUrl: string, schema: S | string | unknown, options: O): Promise<S>;
bundle(baseUrl: string, schema: S | string | unknown, options: O, callback: SchemaCallback<S>): Promise<void>;
/**
* Dereferences all `$ref` pointers in the JSON Schema, replacing each reference with its resolved value. This results in a schema object that does not contain any `$ref` pointers. Instead, it's a normal JavaScript object tree that can easily be crawled and used just like any other JavaScript object. This is great for programmatic usage, especially when using tools that don't understand JSON references.
*
* The dereference method maintains object reference equality, meaning that all `$ref` pointers that point to the same object will be replaced with references to the same object. Again, this is great for programmatic usage, but it does introduce the risk of circular references, so be careful if you intend to serialize the schema using `JSON.stringify()`. Consider using the bundle method instead, which does not create circular references.
*
* See https://apitools.dev/json-schema-ref-parser/docs/ref-parser.html#dereferenceschema-options-callback
*
* @param schema A JSON Schema object, or the file path or URL of a JSON Schema file. See the `parse` method for more info.
* @param options (optional)
* @param callback (optional) A callback that will receive the dereferenced schema object
*/
static dereference<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(schema: S | string | unknown): Promise<S>;
static dereference<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(schema: S | string | unknown, callback: SchemaCallback<S>): Promise<void>;
static dereference<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(schema: S | string | unknown, options: O): Promise<S>;
static dereference<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(schema: S | string | unknown, options: O, callback: SchemaCallback<S>): Promise<void>;
static dereference<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(baseUrl: string, schema: S | string | unknown, options: O): Promise<S>;
static dereference<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(baseUrl: string, schema: S | string | unknown, options: O, callback: SchemaCallback<S>): Promise<void>;
/**
* Dereferences all `$ref` pointers in the JSON Schema, replacing each reference with its resolved value. This results in a schema object that does not contain any `$ref` pointers. Instead, it's a normal JavaScript object tree that can easily be crawled and used just like any other JavaScript object. This is great for programmatic usage, especially when using tools that don't understand JSON references.
*
* The dereference method maintains object reference equality, meaning that all `$ref` pointers that point to the same object will be replaced with references to the same object. Again, this is great for programmatic usage, but it does introduce the risk of circular references, so be careful if you intend to serialize the schema using `JSON.stringify()`. Consider using the bundle method instead, which does not create circular references.
*
* See https://apitools.dev/json-schema-ref-parser/docs/ref-parser.html#dereferenceschema-options-callback
*
* @param baseUrl
* @param schema A JSON Schema object, or the file path or URL of a JSON Schema file. See the `parse` method for more info.
* @param options (optional)
* @param callback (optional) A callback that will receive the dereferenced schema object
*/
dereference(baseUrl: string, schema: S | string | unknown, options: O, callback: SchemaCallback<S>): Promise<void>;
dereference(schema: S | string | unknown, options: O, callback: SchemaCallback<S>): Promise<void>;
dereference(schema: S | string | unknown, callback: SchemaCallback<S>): Promise<void>;
dereference(baseUrl: string, schema: S | string | unknown, options: O): Promise<S>;
dereference(schema: S | string | unknown, options: O): Promise<S>;
dereference(schema: S | string | unknown): Promise<S>;
}
export default $RefParser;
export declare const parse: typeof $RefParser.parse;
export declare const resolve: typeof $RefParser.resolve;
export declare const bundle: typeof $RefParser.bundle;
export declare const dereference: typeof $RefParser.dereference;
export { UnmatchedResolverError, JSONParserError, JSONSchema, InvalidPointerError, MissingPointerError, ResolverError, ParserError, UnmatchedParserError, ParserOptions, $RefsCallback, isHandledError, JSONParserErrorGroup, SchemaCallback, FileInfo, Plugin, ResolverOptions, HTTPResolverOptions, _dereference as dereferenceInternal, normalizeArgs as jsonSchemaParserNormalizeArgs, getJsonSchemaRefParserDefaultOptions, };
+206
View File
@@ -0,0 +1,206 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getJsonSchemaRefParserDefaultOptions = exports.jsonSchemaParserNormalizeArgs = exports.dereferenceInternal = exports.JSONParserErrorGroup = exports.isHandledError = exports.UnmatchedParserError = exports.ParserError = exports.ResolverError = exports.MissingPointerError = exports.InvalidPointerError = exports.JSONParserError = exports.UnmatchedResolverError = exports.dereference = exports.bundle = exports.resolve = exports.parse = exports.$RefParser = void 0;
const refs_js_1 = __importDefault(require("./refs.js"));
const parse_js_1 = __importDefault(require("./parse.js"));
const normalize_args_js_1 = __importDefault(require("./normalize-args.js"));
exports.jsonSchemaParserNormalizeArgs = normalize_args_js_1.default;
const resolve_external_js_1 = __importDefault(require("./resolve-external.js"));
const bundle_js_1 = __importDefault(require("./bundle.js"));
const dereference_js_1 = __importDefault(require("./dereference.js"));
exports.dereferenceInternal = dereference_js_1.default;
const url = __importStar(require("./util/url.js"));
const errors_js_1 = require("./util/errors.js");
Object.defineProperty(exports, "JSONParserError", { enumerable: true, get: function () { return errors_js_1.JSONParserError; } });
Object.defineProperty(exports, "InvalidPointerError", { enumerable: true, get: function () { return errors_js_1.InvalidPointerError; } });
Object.defineProperty(exports, "MissingPointerError", { enumerable: true, get: function () { return errors_js_1.MissingPointerError; } });
Object.defineProperty(exports, "ResolverError", { enumerable: true, get: function () { return errors_js_1.ResolverError; } });
Object.defineProperty(exports, "ParserError", { enumerable: true, get: function () { return errors_js_1.ParserError; } });
Object.defineProperty(exports, "UnmatchedParserError", { enumerable: true, get: function () { return errors_js_1.UnmatchedParserError; } });
Object.defineProperty(exports, "UnmatchedResolverError", { enumerable: true, get: function () { return errors_js_1.UnmatchedResolverError; } });
Object.defineProperty(exports, "isHandledError", { enumerable: true, get: function () { return errors_js_1.isHandledError; } });
Object.defineProperty(exports, "JSONParserErrorGroup", { enumerable: true, get: function () { return errors_js_1.JSONParserErrorGroup; } });
const ono_1 = require("@jsdevtools/ono");
const maybe_js_1 = __importDefault(require("./util/maybe.js"));
const options_js_1 = require("./options.js");
Object.defineProperty(exports, "getJsonSchemaRefParserDefaultOptions", { enumerable: true, get: function () { return options_js_1.getJsonSchemaRefParserDefaultOptions; } });
/**
* This class parses a JSON schema, builds a map of its JSON references and their resolved values,
* and provides methods for traversing, manipulating, and dereferencing those references.
*
* @class
*/
class $RefParser {
constructor() {
/**
* The parsed (and possibly dereferenced) JSON schema object
*
* @type {object}
* @readonly
*/
this.schema = null;
/**
* The resolved JSON references
*
* @type {$Refs}
* @readonly
*/
this.$refs = new refs_js_1.default();
}
async parse() {
const args = (0, normalize_args_js_1.default)(arguments);
let promise;
if (!args.path && !args.schema) {
const err = (0, ono_1.ono)(`Expected a file path, URL, or object. Got ${args.path || args.schema}`);
return (0, maybe_js_1.default)(args.callback, Promise.reject(err));
}
// Reset everything
this.schema = null;
this.$refs = new refs_js_1.default();
// If the path is a filesystem path, then convert it to a URL.
// NOTE: According to the JSON Reference spec, these should already be URLs,
// but, in practice, many people use local filesystem paths instead.
// So we're being generous here and doing the conversion automatically.
// This is not intended to be a 100% bulletproof solution.
// If it doesn't work for your use-case, then use a URL instead.
let pathType = "http";
if (url.isFileSystemPath(args.path)) {
args.path = url.fromFileSystemPath(args.path);
pathType = "file";
}
else if (!args.path && args.schema && "$id" in args.schema && args.schema.$id) {
// when schema id has defined an URL should use that hostname to request the references,
// instead of using the current page URL
const params = url.parse(args.schema.$id);
const port = params.protocol === "https:" ? 443 : 80;
args.path = `${params.protocol}//${params.hostname}:${port}`;
}
// Resolve the absolute path of the schema
args.path = url.resolve(url.cwd(), args.path);
if (args.schema && typeof args.schema === "object") {
// A schema object was passed-in.
// So immediately add a new $Ref with the schema object as its value
const $ref = this.$refs._add(args.path);
$ref.value = args.schema;
$ref.pathType = pathType;
promise = Promise.resolve(args.schema);
}
else {
// Parse the schema file/url
promise = (0, parse_js_1.default)(args.path, this.$refs, args.options);
}
try {
const result = await promise;
if (result !== null && typeof result === "object" && !Buffer.isBuffer(result)) {
this.schema = result;
return (0, maybe_js_1.default)(args.callback, Promise.resolve(this.schema));
}
else if (args.options.continueOnError) {
this.schema = null; // it's already set to null at line 79, but let's set it again for the sake of readability
return (0, maybe_js_1.default)(args.callback, Promise.resolve(this.schema));
}
else {
throw ono_1.ono.syntax(`"${this.$refs._root$Ref.path || result}" is not a valid JSON Schema`);
}
}
catch (err) {
if (!args.options.continueOnError || !(0, errors_js_1.isHandledError)(err)) {
return (0, maybe_js_1.default)(args.callback, Promise.reject(err));
}
if (this.$refs._$refs[url.stripHash(args.path)]) {
this.$refs._$refs[url.stripHash(args.path)].addError(err);
}
return (0, maybe_js_1.default)(args.callback, Promise.resolve(null));
}
}
static parse() {
const parser = new $RefParser();
return parser.parse.apply(parser, arguments);
}
async resolve() {
const args = (0, normalize_args_js_1.default)(arguments);
try {
await this.parse(args.path, args.schema, args.options);
await (0, resolve_external_js_1.default)(this, args.options);
finalize(this);
return (0, maybe_js_1.default)(args.callback, Promise.resolve(this.$refs));
}
catch (err) {
return (0, maybe_js_1.default)(args.callback, Promise.reject(err));
}
}
static resolve() {
const instance = new $RefParser();
return instance.resolve.apply(instance, arguments);
}
static bundle() {
const instance = new $RefParser();
return instance.bundle.apply(instance, arguments);
}
async bundle() {
const args = (0, normalize_args_js_1.default)(arguments);
try {
await this.resolve(args.path, args.schema, args.options);
(0, bundle_js_1.default)(this, args.options);
finalize(this);
return (0, maybe_js_1.default)(args.callback, Promise.resolve(this.schema));
}
catch (err) {
return (0, maybe_js_1.default)(args.callback, Promise.reject(err));
}
}
static dereference() {
const instance = new $RefParser();
return instance.dereference.apply(instance, arguments);
}
async dereference() {
const args = (0, normalize_args_js_1.default)(arguments);
try {
await this.resolve(args.path, args.schema, args.options);
(0, dereference_js_1.default)(this, args.options);
finalize(this);
return (0, maybe_js_1.default)(args.callback, Promise.resolve(this.schema));
}
catch (err) {
return (0, maybe_js_1.default)(args.callback, Promise.reject(err));
}
}
}
exports.$RefParser = $RefParser;
exports.default = $RefParser;
function finalize(parser) {
const errors = errors_js_1.JSONParserErrorGroup.getParserErrors(parser);
if (errors.length > 0) {
throw new errors_js_1.JSONParserErrorGroup(parser);
}
}
exports.parse = $RefParser.parse;
exports.resolve = $RefParser.resolve;
exports.bundle = $RefParser.bundle;
exports.dereference = $RefParser.dereference;
@@ -0,0 +1,13 @@
import type { Options, ParserOptions } from "./options.js";
import type { JSONSchema, SchemaCallback } from "./types";
export interface NormalizedArguments<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>> {
path: string;
schema: S;
options: O & Options<S>;
callback: SchemaCallback<S>;
}
/**
* Normalizes the given arguments, accounting for optional args.
*/
export declare function normalizeArgs<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(_args: Partial<IArguments>): NormalizedArguments<S, O>;
export default normalizeArgs;
@@ -0,0 +1,55 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.normalizeArgs = normalizeArgs;
const options_js_1 = require("./options.js");
/**
* Normalizes the given arguments, accounting for optional args.
*/
function normalizeArgs(_args) {
let path;
let schema;
let options;
let callback;
const args = Array.prototype.slice.call(_args);
if (typeof args[args.length - 1] === "function") {
// The last parameter is a callback function
callback = args.pop();
}
if (typeof args[0] === "string") {
// The first parameter is the path
path = args[0];
if (typeof args[2] === "object") {
// The second parameter is the schema, and the third parameter is the options
schema = args[1];
options = args[2];
}
else {
// The second parameter is the options
schema = undefined;
options = args[1];
}
}
else {
// The first parameter is the schema
path = "";
schema = args[0];
options = args[1];
}
try {
options = (0, options_js_1.getNewOptions)(options);
}
catch (e) {
console.error(`JSON Schema Ref Parser: Error normalizing options: ${e}`);
}
if (!options.mutateInputSchema && typeof schema === "object") {
// Make a deep clone of the schema, so that we don't alter the original object
schema = JSON.parse(JSON.stringify(schema));
}
return {
path,
schema,
options,
callback,
};
}
exports.default = normalizeArgs;

Some files were not shown because too many files have changed in this diff Show More