зеркало из https://github.com/github/ossar-action.git
GitHub OSSAR Action initial commit.
This commit is contained in:
Коммит
94c5e2a777
|
@ -0,0 +1,90 @@
|
|||
{
|
||||
"version": "1.0.0",
|
||||
"suppressionSets": {
|
||||
"default": {
|
||||
"name": "default",
|
||||
"createdDate": "2020-06-22 22:21:08Z",
|
||||
"lastUpdatedDate": "2020-06-22 22:21:08Z"
|
||||
}
|
||||
},
|
||||
"results": {
|
||||
"b55100af590384314d06fdb4f25f1b6e86e07aaf69010e8321c240cc3a7b324c": {
|
||||
"signature": "b55100af590384314d06fdb4f25f1b6e86e07aaf69010e8321c240cc3a7b324c",
|
||||
"target": "lib/msca-toolkit/msca-installer.js",
|
||||
"memberOf": [
|
||||
"default"
|
||||
],
|
||||
"tool": "ESLint",
|
||||
"ruleId": "security/detect-non-literal-fs-filename",
|
||||
"justification": null,
|
||||
"createdDate": "2020-06-22 22:21:08Z",
|
||||
"expirationDate": null,
|
||||
"type": "External"
|
||||
},
|
||||
"5609febb6d784c6ad6aabb0e4624c2e7f8ed212468ef12256e9d1f6c865241a1": {
|
||||
"signature": "5609febb6d784c6ad6aabb0e4624c2e7f8ed212468ef12256e9d1f6c865241a1",
|
||||
"target": "lib/msca-toolkit/msca-installer.js",
|
||||
"memberOf": [
|
||||
"default"
|
||||
],
|
||||
"tool": "ESLint",
|
||||
"ruleId": "security/detect-non-literal-fs-filename",
|
||||
"justification": null,
|
||||
"createdDate": "2020-06-22 22:21:08Z",
|
||||
"expirationDate": null,
|
||||
"type": "External"
|
||||
},
|
||||
"133408373b8725daf83aa009ca35add815e4deaadd56be6cfe0d8046b2710b91": {
|
||||
"signature": "133408373b8725daf83aa009ca35add815e4deaadd56be6cfe0d8046b2710b91",
|
||||
"target": "lib/msca-toolkit/msca-installer.js",
|
||||
"memberOf": [
|
||||
"default"
|
||||
],
|
||||
"tool": "ESLint",
|
||||
"ruleId": "security/detect-non-literal-fs-filename",
|
||||
"justification": null,
|
||||
"createdDate": "2020-06-22 22:21:08Z",
|
||||
"expirationDate": null,
|
||||
"type": "External"
|
||||
},
|
||||
"060c07f7a16a8a8c365e4ff1c079e4754ad6c19ff617729953dcea28fb363758": {
|
||||
"signature": "060c07f7a16a8a8c365e4ff1c079e4754ad6c19ff617729953dcea28fb363758",
|
||||
"target": "lib/msca-toolkit/msca-installer.js",
|
||||
"memberOf": [
|
||||
"default"
|
||||
],
|
||||
"tool": "ESLint",
|
||||
"ruleId": "security/detect-non-literal-fs-filename",
|
||||
"justification": null,
|
||||
"createdDate": "2020-06-22 22:21:08Z",
|
||||
"expirationDate": null,
|
||||
"type": "External"
|
||||
},
|
||||
"4da68ea9226ffbb2659163b8035d7d7ab26492c1009f9696606e32e6d919d874": {
|
||||
"signature": "4da68ea9226ffbb2659163b8035d7d7ab26492c1009f9696606e32e6d919d874",
|
||||
"target": "lib/msca-toolkit/msca-installer.js",
|
||||
"memberOf": [
|
||||
"default"
|
||||
],
|
||||
"tool": "ESLint",
|
||||
"ruleId": "security/detect-non-literal-fs-filename",
|
||||
"justification": null,
|
||||
"createdDate": "2020-06-22 22:21:08Z",
|
||||
"expirationDate": null,
|
||||
"type": "External"
|
||||
},
|
||||
"00e68c75c3d4c2a4e875be3b3b166ef4b70916316648b6e0e38fd3f81b40ed86": {
|
||||
"signature": "00e68c75c3d4c2a4e875be3b3b166ef4b70916316648b6e0e38fd3f81b40ed86",
|
||||
"target": "lib/msca-toolkit/msca-installer.js",
|
||||
"memberOf": [
|
||||
"default"
|
||||
],
|
||||
"tool": "ESLint",
|
||||
"ruleId": "security/detect-non-literal-fs-filename",
|
||||
"justification": null,
|
||||
"createdDate": "2020-06-22 22:21:08Z",
|
||||
"expirationDate": null,
|
||||
"type": "External"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
# sample-workflow-ubuntu-latest
|
||||
# docs are in the repo
|
||||
|
||||
name: OSSAR ubuntu-latest
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
sample:
|
||||
name: Open Source Static Analysis Runner
|
||||
|
||||
# OSSAR runs on windows-latest.
|
||||
# ubuntu-latest and macos-latest supporting coming soon
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
||||
# Checkout your code repository to scan
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
# Install dotnet, used by OSSAR
|
||||
- uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '3.1.201'
|
||||
|
||||
# Run open source static analysis tools
|
||||
- name: Run OSSAR
|
||||
uses: github/ossar-action@master
|
||||
id: ossar
|
||||
|
||||
# Upload results to the Security tab
|
||||
- name: Upload results to Security tab
|
||||
uses: github/codeql-action/upload-sarif@v1
|
||||
with:
|
||||
sarif_file: ${{ steps.ossar.outputs.sarifFile }}
|
|
@ -0,0 +1,37 @@
|
|||
# sample-workflow-windows-latest
|
||||
# docs are in the repo
|
||||
|
||||
name: OSSAR windows-latest
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
sample:
|
||||
name: Open Source Static Analysis Runner
|
||||
|
||||
# OSSAR runs on windows-latest.
|
||||
# ubuntu-latest and macos-latest supporting coming soon
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
|
||||
# Checkout your code repository to scan
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
# Install dotnet, used by OSSAR
|
||||
- uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '3.1.201'
|
||||
|
||||
# Run open source static analysis tools
|
||||
- name: Run OSSAR
|
||||
uses: github/ossar-action@master
|
||||
id: ossar
|
||||
|
||||
# Upload results to the Security tab
|
||||
- name: Upload results to Security tab
|
||||
uses: github/codeql-action/upload-sarif@v1
|
||||
with:
|
||||
sarif_file: ${{ steps.ossar.outputs.sarifFile }}
|
|
@ -0,0 +1,330 @@
|
|||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
**/Properties/launchSettings.json
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
# CodeRush
|
||||
.cr/
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
|
@ -0,0 +1,9 @@
|
|||
# Microsoft Open Source Code of Conduct
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||
|
||||
Resources:
|
||||
|
||||
- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
|
||||
- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
|
||||
- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
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
|
|
@ -0,0 +1,58 @@
|
|||
# actions/ossar
|
||||
|
||||
![OSSAR windows-latest](https://github.com/microsoft/security-code-analysis-action/workflows/OSSAR%20windows-latest/badge.svg)
|
||||
![OSSAR ubuntu-latest](https://github.com/microsoft/security-code-analysis-action/workflows/OSSAR%20ubuntu-latest/badge.svg)
|
||||
|
||||
Run multiple open source security static analysis tools without the added complexity with OSSAR (Open Source Static Analysis Runner).
|
||||
|
||||
This action runs the [Microsoft Security Code Analysis CLI](https://aka.ms/mscadocs) for security analysis by:
|
||||
|
||||
* Installing the Microsoft Security Code Analysis CLI
|
||||
* Installing the latest Microsoft security policy
|
||||
* Installing the latest Microsoft and 3rd party security tools
|
||||
* Automatic or user-provided configuration of security tools
|
||||
* Execution of a full suite of security tools
|
||||
* Normalized processing of results into the SARIF format
|
||||
* Build breaks and more
|
||||
|
||||
# Usage
|
||||
|
||||
See [action.yml](action.yml)
|
||||
|
||||
## Basic
|
||||
|
||||
Run OSSAR with the default policy and recommended tools.
|
||||
|
||||
```yaml
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '3.1.201'
|
||||
- name: Run OSSAR
|
||||
uses: github/ossar-action@master
|
||||
id: ossar
|
||||
- name: Upload results to Security tab
|
||||
uses: github/codeql-action/upload-sarif@v1
|
||||
with:
|
||||
sarif_file: ${{ steps.ossar.outputs.sarifFile }}
|
||||
```
|
||||
|
||||
## Upload Results to the Security tab
|
||||
|
||||
To upload results to the Security tab of your repo, run the `github/codeql-action/upload-sarif` action immediately after running MSCA. MSCA sets the action output variable `sarifFile` to the path of a single SARIF file that can be uploaded to this API.
|
||||
|
||||
```yaml
|
||||
- name: Upload results to Security tab
|
||||
uses: github/codeql-action/upload-sarif@v1
|
||||
with:
|
||||
sarif_file: ${{ steps.ossar.outputs.sarifFile }}
|
||||
```
|
||||
|
||||
# License
|
||||
|
||||
The scripts and documentation in this project are released under the [MIT License](LICENSE)
|
||||
|
||||
# Contributing
|
||||
|
||||
Contributions are welcome! See the [Contributor's Guide](docs/contributors.md).
|
|
@ -0,0 +1,35 @@
|
|||
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.1 BLOCK -->
|
||||
|
||||
## Security
|
||||
|
||||
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [many more](https://opensource.microsoft.com/).
|
||||
|
||||
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets Microsoft's [definition](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)) of a security vulnerability, please report it to us as described below.
|
||||
|
||||
## Reporting Security Issues
|
||||
|
||||
**Please do not report security vulnerabilities through public GitHub issues.** Instead, please report them to the Microsoft Security Response Center at [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://technet.microsoft.com/en-us/security/dn606155).
|
||||
|
||||
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
|
||||
|
||||
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
|
||||
|
||||
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
|
||||
* Full paths of source file(s) related to the manifestation of the issue
|
||||
* The location of the affected source code (tag/branch/commit or direct URL)
|
||||
* Any special configuration required to reproduce the issue
|
||||
* Step-by-step instructions to reproduce the issue
|
||||
* Proof-of-concept or exploit code (if possible)
|
||||
* Impact of the issue, including how an attacker might exploit the issue
|
||||
|
||||
This information will help us triage your report more quickly.
|
||||
|
||||
## Preferred Languages
|
||||
|
||||
We prefer all communications to be in English.
|
||||
|
||||
## Policy
|
||||
|
||||
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd).
|
||||
|
||||
<!-- END MICROSOFT SECURITY.MD BLOCK -->
|
|
@ -0,0 +1,17 @@
|
|||
name: 'ossar-action'
|
||||
description: 'Run multiple open source security static analysis tools without the added complexity with OSSAR (Open Source Static Analysis Runner)'
|
||||
author: 'GitHub'
|
||||
branding:
|
||||
icon: 'shield'
|
||||
color: 'black'
|
||||
inputs:
|
||||
config:
|
||||
description: A file path to a .gdnconfig file.
|
||||
policy:
|
||||
description: The name of the well known policy to use. If empty, defaults to the policy/github.gdnpolicy file in the action repo.
|
||||
outputs:
|
||||
sarifFile:
|
||||
description: A file path to a SARIF results file.
|
||||
runs:
|
||||
using: 'node12'
|
||||
main: 'lib/action.js'
|
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<PropertyGroup>
|
||||
<RepoDirectory Condition=" '$(RepoDirectory)' == '' ">$(MSBuildThisFileDirectory)</RepoDirectory>
|
||||
<MscaToolkitDirectory Condition=" '$(MscaToolkitDirectory)' == '' ">$(MSBuildThisFileDirectory)/src/msca-toolkit</MscaToolkitDirectory>
|
||||
<MscaToolkitProjFilePath Condition=" '$(MscaToolkitProjFilePath)' == '' ">$(MscaToolkitDirectory)/msca-toolkit.proj</MscaToolkitProjFilePath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="TypeScript">
|
||||
<TypeScriptCompileBlocked Condition=" '$(TypeScriptCompileBlocked)' == '' ">false</TypeScriptCompileBlocked>
|
||||
<TypeScriptToolsVersion Condition=" '$(TypeScriptToolsVersion)' == '' ">3.8</TypeScriptToolsVersion>
|
||||
<TypeScriptConfigFileName Condition=" '$(TypeScriptConfigFileName)' == '' ">tsconfig.json</TypeScriptConfigFileName>
|
||||
<TypeScriptConfigFilePath>$(MSBuildProjectDirectory)/$(TypeScriptConfigFileName)</TypeScriptConfigFilePath>
|
||||
<TscYieldDuringToolExecution>false</TscYieldDuringToolExecution>
|
||||
<TypeScriptRemoveComments>true</TypeScriptRemoveComments>
|
||||
<TypeScriptSourceMap>false</TypeScriptSourceMap>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="Npm">
|
||||
<NpmInstall Condition=" '$(NpmInstall)' == ''">false</NpmInstall>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- TypeScript Compiler imports -->
|
||||
<Import
|
||||
Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.targets"
|
||||
Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.targets')" />
|
||||
|
||||
<ItemGroup>
|
||||
<ConfigFiles Include="$(TypeScriptConfigFilePath)" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Override the TypeScript FindConfigFiles Target so that default tsconfig.json is not picked up -->
|
||||
<Target Name="FindConfigFiles"></Target>
|
||||
|
||||
<Target
|
||||
Name="NpmInstall"
|
||||
Inputs="$(MSBuildProjectDirectory)"
|
||||
Outputs="$(MSBuildProjectDirectory)\node_modules"
|
||||
Condition=" '$(NpmInstall)' == 'true' ">
|
||||
<Message Text="Installing npm dependencies in: $(MSBuildProjectDirectory)..." />
|
||||
<Exec Command="npm install" WorkingDirectory="$(MSBuildProjectDirectory)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="Build" DependsOnTargets="NpmInstall;$(CompileDependsOn)">
|
||||
<Message Text="TypeScriptConfigFilePath = $(TypeScriptConfigFilePath)..." />
|
||||
<Copy SourceFiles="$(MscaToolkitProjFilePath)" DestinationFolder="$(RepoDirectory)/lib/msca-toolkit" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,13 @@
|
|||
# Contributions
|
||||
|
||||
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
||||
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
|
||||
the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
|
||||
|
||||
When you submit a pull request, a CLA bot will automatically determine whether you need to provide
|
||||
a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
|
||||
provided by the bot. You will only need to do this once across all repos using our CLA.
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
|
||||
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
|
@ -0,0 +1,35 @@
|
|||
"use strict";
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||
result["default"] = mod;
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const core = __importStar(require("@actions/core"));
|
||||
const msca_toolkit_1 = require("./msca-toolkit/msca-toolkit");
|
||||
const path = __importStar(require("path"));
|
||||
let action = new msca_toolkit_1.MscaAction();
|
||||
let args = [];
|
||||
let config = core.getInput('config');
|
||||
if (!action.isNullOrWhiteSpace(config)) {
|
||||
args.push('-c');
|
||||
args.push(config);
|
||||
}
|
||||
let policy = core.getInput('policy');
|
||||
if (action.isNullOrWhiteSpace(policy)) {
|
||||
// Use the local policy file
|
||||
const actionDirectory = path.resolve(__dirname);
|
||||
core.debug(`actionDirectory = ${actionDirectory}`);
|
||||
const policyFilePath = path.resolve(path.join(actionDirectory, '../', 'policy', 'github.gdnpolicy'));
|
||||
core.debug(`policyFilePath = ${policyFilePath}`);
|
||||
args.push('--policy-file-path');
|
||||
args.push(policyFilePath);
|
||||
}
|
||||
else {
|
||||
// Use the defined policy
|
||||
args.push('-p');
|
||||
args.push(policy);
|
||||
}
|
||||
action.run(args);
|
|
@ -0,0 +1,226 @@
|
|||
"use strict";
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||
result["default"] = mod;
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const fs = __importStar(require("fs"));
|
||||
const path = __importStar(require("path"));
|
||||
const process = __importStar(require("process"));
|
||||
const core = __importStar(require("@actions/core"));
|
||||
const exec = __importStar(require("@actions/exec"));
|
||||
class MscaInstaller {
|
||||
install(cliVersion) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
console.log('Installing Microsot Security Code Analysis Cli...');
|
||||
if (process.env.MSCA_FILEPATH) {
|
||||
console.log(`MSCA Cli File Path overriden by %MSCA_FILEPATH%: ${process.env.MSCA_FILEPATH}`);
|
||||
return;
|
||||
}
|
||||
if (process.env.MSCA_DIRECTORY) {
|
||||
console.log(`MSCA Cli Directory overriden by %MSCA_DIRECTORY%: ${process.env.MSCA_DIRECTORY}`);
|
||||
// Set the mscai file path
|
||||
let mscaFilePath = path.join(process.env.MSCA_DIRECTORY, 'guardian');
|
||||
core.debug(`mscaFilePath = ${mscaFilePath}`);
|
||||
process.env.MSCA_FILEPATH = mscaFilePath;
|
||||
return;
|
||||
}
|
||||
// initialize the _msca directory
|
||||
let mscaDirectory = path.resolve(path.join(process.env.GITHUB_WORKSPACE, '../../_msca'));
|
||||
core.debug(`mscaDirectory = ${mscaDirectory}`);
|
||||
this.ensureDirectory(mscaDirectory);
|
||||
let mscaPackagesDirectory = path.join(mscaDirectory, 'versions');
|
||||
core.debug(`mscaPackagesDirectory = ${mscaPackagesDirectory}`);
|
||||
this.ensureDirectory(mscaPackagesDirectory);
|
||||
let mscaVersionsDirectory = path.join(mscaPackagesDirectory, 'microsoft.security.codeanalysis.cli');
|
||||
core.debug(`mscaVersionsDirectory = ${mscaVersionsDirectory}`);
|
||||
if (this.isInstalled(mscaVersionsDirectory, cliVersion)) {
|
||||
return;
|
||||
}
|
||||
let failed = false;
|
||||
let attempts = 0;
|
||||
let maxAttempts = 2;
|
||||
do {
|
||||
failed = false;
|
||||
const mscaToolkitDirectory = path.resolve(__dirname);
|
||||
core.debug(`mscaToolkitDirectory = ${mscaToolkitDirectory}`);
|
||||
const mscaProjectFile = path.join(mscaToolkitDirectory, 'msca-toolkit.proj');
|
||||
core.debug(`mscaProjectFile = ${mscaProjectFile}`);
|
||||
let args = [
|
||||
'restore',
|
||||
mscaProjectFile,
|
||||
`/p:MscaPackageVersion=${cliVersion}`,
|
||||
'--packages',
|
||||
mscaPackagesDirectory,
|
||||
'--source',
|
||||
'https://api.nuget.org/v3/index.json'
|
||||
];
|
||||
try {
|
||||
yield exec.exec('dotnet', args);
|
||||
}
|
||||
catch (error) {
|
||||
core.debug(error);
|
||||
failed = true;
|
||||
attempts += 1;
|
||||
if (attempts > maxAttempts) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (failed);
|
||||
this.resolvePackageDirectory(mscaVersionsDirectory, cliVersion);
|
||||
});
|
||||
}
|
||||
ensureDirectory(directory) {
|
||||
if (!fs.existsSync(directory)) {
|
||||
fs.mkdirSync(directory);
|
||||
}
|
||||
}
|
||||
isInstalled(mscaVersionsDirectory, cliVersion) {
|
||||
let installed = false;
|
||||
if (cliVersion.includes("*")) {
|
||||
core.debug(`MSCA Cli version contains a latest quantifier: ${cliVersion}. Continuing with install...`);
|
||||
return installed;
|
||||
}
|
||||
this.setMscaiVariablesWithVersion(mscaVersionsDirectory, cliVersion);
|
||||
if (fs.existsSync(process.env.MSCA_DIRECTORY)) {
|
||||
console.log(`MSCA Cli v${cliVersion} already installed.`);
|
||||
installed = true;
|
||||
}
|
||||
return installed;
|
||||
}
|
||||
resolvePackageDirectory(mscaVersionsDirectory, cliVersion) {
|
||||
if (cliVersion.includes("*")) {
|
||||
// find the latest directory
|
||||
let mscaPackageDirectory = this.findLatestVersionDirectory(mscaVersionsDirectory);
|
||||
this.setMscaiVariables(mscaPackageDirectory);
|
||||
}
|
||||
else {
|
||||
this.setMscaiVariablesWithVersion(mscaVersionsDirectory, cliVersion);
|
||||
}
|
||||
if (!fs.existsSync(process.env.MSCA_DIRECTORY)) {
|
||||
throw `Microsoft Security Code Analysis Cli v${cliVersion} was not found after installation.`;
|
||||
}
|
||||
}
|
||||
findLatestVersionDirectory(mscaVersionsDirectory, isPreRelease = false) {
|
||||
let latestDirectory = null;
|
||||
let latestVersionParts = null;
|
||||
let latestIsPreRelease = false;
|
||||
let latestPreReleaseFlag = null;
|
||||
// Get all of the directories in the versions directory
|
||||
core.debug(`Searching for all version folders in: ${mscaVersionsDirectory}`);
|
||||
let dirs = this.getDirectories(mscaVersionsDirectory);
|
||||
// Evaluate each directory
|
||||
for (let dirIndex = 0; dirIndex < dirs.length; dirIndex++) {
|
||||
let dir = dirs[dirIndex];
|
||||
if (dir == null || dir == "") {
|
||||
core.debug(`Skipping null or empty directory: ${dir}`);
|
||||
continue;
|
||||
}
|
||||
core.debug(`Evaluating mscai directory: ${dir}`);
|
||||
// If we reuse the same RegExp object, it will return null every other call
|
||||
const dirRegex = new RegExp(/^(\d+\.?){1,6}(\-\w+)?$/g);
|
||||
if (dirRegex.exec(dir) == null) {
|
||||
core.debug(`Skipping invalid version directory: ${dir}`);
|
||||
continue;
|
||||
}
|
||||
let fullVersionParts = dir.split("-");
|
||||
if (fullVersionParts == null || fullVersionParts.length < 0 || fullVersionParts.length > 2) {
|
||||
core.debug(`Skipping invalid version directory: ${dir}`);
|
||||
}
|
||||
let dirIsPreRelease = fullVersionParts.length > 1;
|
||||
if (!isPreRelease && dirIsPreRelease) {
|
||||
core.debug(`Skipping pre-release version directory: ${dir}`);
|
||||
continue;
|
||||
}
|
||||
let dirPreReleaseFlag = null;
|
||||
if (dirIsPreRelease) {
|
||||
dirPreReleaseFlag = fullVersionParts[1];
|
||||
}
|
||||
let versionNumbersString = fullVersionParts[0];
|
||||
let versionParts = dir.split(".");
|
||||
// If the latestDirectory isn't set yet, the folder is the latest directory
|
||||
let isLatest = latestDirectory == null || latestVersionParts == null;
|
||||
if (!isLatest) {
|
||||
// Evaluate the directory's version against the latest directory
|
||||
// Handle comparisions of separate level versions
|
||||
// Some packages exclude Patch or include Revisions up to two levels (Rev1 and Rev2)
|
||||
let maxVersionParts = versionParts.length;
|
||||
if (latestVersionParts.length > maxVersionParts) {
|
||||
maxVersionParts = latestVersionParts.length;
|
||||
}
|
||||
for (let versionPartIndex = 0; versionPartIndex < versionParts.length; versionPartIndex++) {
|
||||
let versionPart = 0;
|
||||
let latestVersionPart = 0;
|
||||
let isLastVersionPart = versionPartIndex == (maxVersionParts - 1);
|
||||
if (versionPartIndex < versionParts.length) {
|
||||
versionPart = parseInt(versionParts[versionPartIndex]);
|
||||
}
|
||||
if (versionPartIndex < latestVersionParts.length) {
|
||||
latestVersionPart = parseInt(latestVersionParts[versionPartIndex]);
|
||||
}
|
||||
if (versionPart > latestVersionPart) {
|
||||
isLatest = true;
|
||||
}
|
||||
else if (versionPart == latestVersionPart) {
|
||||
isLatest = isLastVersionPart
|
||||
&&
|
||||
((isPreRelease && latestIsPreRelease && dirPreReleaseFlag > latestPreReleaseFlag)
|
||||
||
|
||||
(!isPreRelease && latestIsPreRelease));
|
||||
}
|
||||
else {
|
||||
// Current version is less than latest found
|
||||
break;
|
||||
}
|
||||
if (isLatest) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isLatest) {
|
||||
core.debug(`Setting latest version directory: ${dir}`);
|
||||
latestDirectory = path.join(mscaVersionsDirectory, dir);
|
||||
latestVersionParts = versionParts;
|
||||
latestIsPreRelease = dirIsPreRelease;
|
||||
latestPreReleaseFlag = dirPreReleaseFlag;
|
||||
}
|
||||
}
|
||||
core.debug(`latestDirectory = ${latestDirectory}`);
|
||||
return latestDirectory;
|
||||
}
|
||||
getDirectories(directory) {
|
||||
// read the directory for all paths
|
||||
// filter for directories
|
||||
return fs.readdirSync(directory).filter(p => this.isDirectory(directory, p));
|
||||
}
|
||||
isDirectory(directory, p) {
|
||||
// statSync follows symlinks
|
||||
return fs.statSync(path.join(directory, p)).isDirectory();
|
||||
}
|
||||
setMscaiVariablesWithVersion(mscaVersionsDirectory, cliVersion) {
|
||||
let mscaPackageDirectory = path.join(mscaVersionsDirectory, cliVersion);
|
||||
core.debug(`mscaPackageDirectory = ${mscaPackageDirectory}`);
|
||||
this.setMscaiVariables(mscaPackageDirectory);
|
||||
}
|
||||
setMscaiVariables(mscaPackageDirectory) {
|
||||
let mscaDirectory = path.join(mscaPackageDirectory, 'tools');
|
||||
core.debug(`mscaDirectory = ${mscaDirectory}`);
|
||||
let mscaFilePath = path.join(mscaDirectory, 'guardian');
|
||||
core.debug(`mscaFilePath = ${mscaFilePath}`);
|
||||
process.env.MSCA_DIRECTORY = mscaDirectory;
|
||||
process.env.MSCA_FILEPATH = mscaFilePath;
|
||||
}
|
||||
}
|
||||
exports.MscaInstaller = MscaInstaller;
|
|
@ -0,0 +1,95 @@
|
|||
"use strict";
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||
result["default"] = mod;
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const path = __importStar(require("path"));
|
||||
const process = __importStar(require("process"));
|
||||
const core = __importStar(require("@actions/core"));
|
||||
const exec = __importStar(require("@actions/exec"));
|
||||
const msca_installer_1 = require("./msca-installer");
|
||||
class MscaAction {
|
||||
constructor() {
|
||||
this.cliVersion = '0.*';
|
||||
}
|
||||
setupEnvironment() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
console.log('------------------------------------------------------------------------------');
|
||||
if (!process.env.MSCA_FILEPATH) {
|
||||
let cliVersion = this.resolveCliVersion();
|
||||
let mscaInstaller = new msca_installer_1.MscaInstaller();
|
||||
yield mscaInstaller.install(cliVersion);
|
||||
}
|
||||
console.log('------------------------------------------------------------------------------');
|
||||
});
|
||||
}
|
||||
resolveCliVersion() {
|
||||
let cliVersion = this.cliVersion;
|
||||
if (process.env.MSCA_VERSION) {
|
||||
cliVersion = process.env.MSCA_VERSION;
|
||||
}
|
||||
return cliVersion;
|
||||
}
|
||||
isNullOrWhiteSpace(value) {
|
||||
return !value || !value.trim();
|
||||
}
|
||||
init() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let cliFilePath = process.env.MSCA_FILEPATH;
|
||||
core.debug(`cliFilePath = ${cliFilePath}`);
|
||||
try {
|
||||
yield exec.exec(cliFilePath, ['init', '--force']);
|
||||
}
|
||||
catch (error) {
|
||||
core.debug(error.Message);
|
||||
}
|
||||
});
|
||||
}
|
||||
run(inputArgs) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
yield this.setupEnvironment();
|
||||
yield this.init();
|
||||
let cliFilePath = process.env.MSCA_FILEPATH;
|
||||
core.debug(`cliFilePath = ${cliFilePath}`);
|
||||
let args = ['run'];
|
||||
if (inputArgs != null) {
|
||||
for (let i = 0; i < inputArgs.length; i++) {
|
||||
args.push(inputArgs[i]);
|
||||
}
|
||||
}
|
||||
args.push('--not-break-on-detections');
|
||||
if (core.isDebug()) {
|
||||
args.push('--logger-level');
|
||||
args.push('trace');
|
||||
}
|
||||
let sarifFile = path.join(process.env.GITHUB_WORKSPACE, '.gdn', 'msca.sarif');
|
||||
core.debug(`sarifFile = ${sarifFile}`);
|
||||
// Write it as a GitHub Action variable for follow up tasks to consume
|
||||
core.exportVariable('MSCA_SARIF_FILE', sarifFile);
|
||||
core.setOutput('sarifFile', sarifFile);
|
||||
args.push('--export-breaking-results-to-file');
|
||||
args.push(`${sarifFile}`);
|
||||
core.debug('Running Microsoft Security Code Analysis...');
|
||||
try {
|
||||
yield exec.exec(cliFilePath, args);
|
||||
}
|
||||
catch (error) {
|
||||
core.setFailed(error.Message);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.MscaAction = MscaAction;
|
|
@ -0,0 +1,13 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework Condition=" '$(TargetFramework)' == '' ">netcoreapp3.1</TargetFramework>
|
||||
<MscaPackageName Condition=" '$(MscaPackageName)' == '' ">Microsoft.Security.CodeAnalysis.Cli</MscaPackageName>
|
||||
<MscaPackageVersion Condition=" '$(MscaPackageVersion)' == '' ">0.*</MscaPackageVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="$(MscaPackageName)" Version="$(MscaPackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,15 @@
|
|||
#!/bin/sh
|
||||
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||
|
||||
case `uname` in
|
||||
*CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
|
||||
esac
|
||||
|
||||
if [ -x "$basedir/node" ]; then
|
||||
"$basedir/node" "$basedir/../esprima/bin/esparse.js" "$@"
|
||||
ret=$?
|
||||
else
|
||||
node "$basedir/../esprima/bin/esparse.js" "$@"
|
||||
ret=$?
|
||||
fi
|
||||
exit $ret
|
|
@ -0,0 +1,17 @@
|
|||
@ECHO off
|
||||
SETLOCAL
|
||||
CALL :find_dp0
|
||||
|
||||
IF EXIST "%dp0%\node.exe" (
|
||||
SET "_prog=%dp0%\node.exe"
|
||||
) ELSE (
|
||||
SET "_prog=node"
|
||||
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||
)
|
||||
|
||||
"%_prog%" "%dp0%\..\esprima\bin\esparse.js" %*
|
||||
ENDLOCAL
|
||||
EXIT /b %errorlevel%
|
||||
:find_dp0
|
||||
SET dp0=%~dp0
|
||||
EXIT /b
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env pwsh
|
||||
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||
|
||||
$exe=""
|
||||
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||
# Fix case when both the Windows and Linux builds of Node
|
||||
# are installed in the same directory
|
||||
$exe=".exe"
|
||||
}
|
||||
$ret=0
|
||||
if (Test-Path "$basedir/node$exe") {
|
||||
& "$basedir/node$exe" "$basedir/../esprima/bin/esparse.js" $args
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
& "node$exe" "$basedir/../esprima/bin/esparse.js" $args
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
|
@ -0,0 +1,15 @@
|
|||
#!/bin/sh
|
||||
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||
|
||||
case `uname` in
|
||||
*CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
|
||||
esac
|
||||
|
||||
if [ -x "$basedir/node" ]; then
|
||||
"$basedir/node" "$basedir/../esprima/bin/esvalidate.js" "$@"
|
||||
ret=$?
|
||||
else
|
||||
node "$basedir/../esprima/bin/esvalidate.js" "$@"
|
||||
ret=$?
|
||||
fi
|
||||
exit $ret
|
|
@ -0,0 +1,17 @@
|
|||
@ECHO off
|
||||
SETLOCAL
|
||||
CALL :find_dp0
|
||||
|
||||
IF EXIST "%dp0%\node.exe" (
|
||||
SET "_prog=%dp0%\node.exe"
|
||||
) ELSE (
|
||||
SET "_prog=node"
|
||||
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||
)
|
||||
|
||||
"%_prog%" "%dp0%\..\esprima\bin\esvalidate.js" %*
|
||||
ENDLOCAL
|
||||
EXIT /b %errorlevel%
|
||||
:find_dp0
|
||||
SET dp0=%~dp0
|
||||
EXIT /b
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env pwsh
|
||||
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||
|
||||
$exe=""
|
||||
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||
# Fix case when both the Windows and Linux builds of Node
|
||||
# are installed in the same directory
|
||||
$exe=".exe"
|
||||
}
|
||||
$ret=0
|
||||
if (Test-Path "$basedir/node$exe") {
|
||||
& "$basedir/node$exe" "$basedir/../esprima/bin/esvalidate.js" $args
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
& "node$exe" "$basedir/../esprima/bin/esvalidate.js" $args
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
|
@ -0,0 +1,15 @@
|
|||
#!/bin/sh
|
||||
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||
|
||||
case `uname` in
|
||||
*CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
|
||||
esac
|
||||
|
||||
if [ -x "$basedir/node" ]; then
|
||||
"$basedir/node" "$basedir/../js-yaml/bin/js-yaml.js" "$@"
|
||||
ret=$?
|
||||
else
|
||||
node "$basedir/../js-yaml/bin/js-yaml.js" "$@"
|
||||
ret=$?
|
||||
fi
|
||||
exit $ret
|
|
@ -0,0 +1,17 @@
|
|||
@ECHO off
|
||||
SETLOCAL
|
||||
CALL :find_dp0
|
||||
|
||||
IF EXIST "%dp0%\node.exe" (
|
||||
SET "_prog=%dp0%\node.exe"
|
||||
) ELSE (
|
||||
SET "_prog=node"
|
||||
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||
)
|
||||
|
||||
"%_prog%" "%dp0%\..\js-yaml\bin\js-yaml.js" %*
|
||||
ENDLOCAL
|
||||
EXIT /b %errorlevel%
|
||||
:find_dp0
|
||||
SET dp0=%~dp0
|
||||
EXIT /b
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env pwsh
|
||||
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||
|
||||
$exe=""
|
||||
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||
# Fix case when both the Windows and Linux builds of Node
|
||||
# are installed in the same directory
|
||||
$exe=".exe"
|
||||
}
|
||||
$ret=0
|
||||
if (Test-Path "$basedir/node$exe") {
|
||||
& "$basedir/node$exe" "$basedir/../js-yaml/bin/js-yaml.js" $args
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
& "node$exe" "$basedir/../js-yaml/bin/js-yaml.js" $args
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
|
@ -0,0 +1,146 @@
|
|||
# `@actions/core`
|
||||
|
||||
> Core functions for setting results, logging, registering secrets and exporting variables across actions
|
||||
|
||||
## Usage
|
||||
|
||||
### Import the package
|
||||
|
||||
```js
|
||||
// javascript
|
||||
const core = require('@actions/core');
|
||||
|
||||
// typescript
|
||||
import * as core from '@actions/core';
|
||||
```
|
||||
|
||||
#### Inputs/Outputs
|
||||
|
||||
Action inputs can be read with `getInput`. Outputs can be set with `setOutput` which makes them available to be mapped into inputs of other actions to ensure they are decoupled.
|
||||
|
||||
```js
|
||||
const myInput = core.getInput('inputName', { required: true });
|
||||
|
||||
core.setOutput('outputKey', 'outputVal');
|
||||
```
|
||||
|
||||
#### Exporting variables
|
||||
|
||||
Since each step runs in a separate process, you can use `exportVariable` to add it to this step and future steps environment blocks.
|
||||
|
||||
```js
|
||||
core.exportVariable('envVar', 'Val');
|
||||
```
|
||||
|
||||
#### Setting a secret
|
||||
|
||||
Setting a secret registers the secret with the runner to ensure it is masked in logs.
|
||||
|
||||
```js
|
||||
core.setSecret('myPassword');
|
||||
```
|
||||
|
||||
#### PATH Manipulation
|
||||
|
||||
To make a tool's path available in the path for the remainder of the job (without altering the machine or containers state), use `addPath`. The runner will prepend the path given to the jobs PATH.
|
||||
|
||||
```js
|
||||
core.addPath('/path/to/mytool');
|
||||
```
|
||||
|
||||
#### Exit codes
|
||||
|
||||
You should use this library to set the failing exit code for your action. If status is not set and the script runs to completion, that will lead to a success.
|
||||
|
||||
```js
|
||||
const core = require('@actions/core');
|
||||
|
||||
try {
|
||||
// Do stuff
|
||||
}
|
||||
catch (err) {
|
||||
// setFailed logs the message and sets a failing exit code
|
||||
core.setFailed(`Action failed with error ${err}`);
|
||||
}
|
||||
|
||||
Note that `setNeutral` is not yet implemented in actions V2 but equivalent functionality is being planned.
|
||||
|
||||
```
|
||||
|
||||
#### Logging
|
||||
|
||||
Finally, this library provides some utilities for logging. Note that debug logging is hidden from the logs by default. This behavior can be toggled by enabling the [Step Debug Logs](../../docs/action-debugging.md#step-debug-logs).
|
||||
|
||||
```js
|
||||
const core = require('@actions/core');
|
||||
|
||||
const myInput = core.getInput('input');
|
||||
try {
|
||||
core.debug('Inside try block');
|
||||
|
||||
if (!myInput) {
|
||||
core.warning('myInput was not set');
|
||||
}
|
||||
|
||||
if (core.isDebug()) {
|
||||
// curl -v https://github.com
|
||||
} else {
|
||||
// curl https://github.com
|
||||
}
|
||||
|
||||
// Do stuff
|
||||
}
|
||||
catch (err) {
|
||||
core.error(`Error ${err}, action may still succeed though`);
|
||||
}
|
||||
```
|
||||
|
||||
This library can also wrap chunks of output in foldable groups.
|
||||
|
||||
```js
|
||||
const core = require('@actions/core')
|
||||
|
||||
// Manually wrap output
|
||||
core.startGroup('Do some function')
|
||||
doSomeFunction()
|
||||
core.endGroup()
|
||||
|
||||
// Wrap an asynchronous function call
|
||||
const result = await core.group('Do something async', async () => {
|
||||
const response = await doSomeHTTPRequest()
|
||||
return response
|
||||
})
|
||||
```
|
||||
|
||||
#### Action state
|
||||
|
||||
You can use this library to save state and get state for sharing information between a given wrapper action:
|
||||
|
||||
**action.yml**
|
||||
```yaml
|
||||
name: 'Wrapper action sample'
|
||||
inputs:
|
||||
name:
|
||||
default: 'GitHub'
|
||||
runs:
|
||||
using: 'node12'
|
||||
main: 'main.js'
|
||||
post: 'cleanup.js'
|
||||
```
|
||||
|
||||
In action's `main.js`:
|
||||
|
||||
```js
|
||||
const core = require('@actions/core');
|
||||
|
||||
core.saveState("pidToKill", 12345);
|
||||
```
|
||||
|
||||
In action's `cleanup.js`:
|
||||
```js
|
||||
const core = require('@actions/core');
|
||||
|
||||
var pid = core.getState("pidToKill");
|
||||
|
||||
process.kill(pid);
|
||||
```
|
|
@ -0,0 +1,21 @@
|
|||
interface CommandProperties {
|
||||
[key: string]: any;
|
||||
}
|
||||
/**
|
||||
* Commands
|
||||
*
|
||||
* Command Format:
|
||||
* ::name key=value,key=value::message
|
||||
*
|
||||
* Examples:
|
||||
* ::warning::This is the message
|
||||
* ::set-env name=MY_VAR::some value
|
||||
*/
|
||||
export declare function issueCommand(command: string, properties: CommandProperties, message: any): void;
|
||||
export declare function issue(name: string, message?: string): void;
|
||||
/**
|
||||
* Sanitizes an input into a string so it can be passed into issueCommand safely
|
||||
* @param input input to sanitize into a string
|
||||
*/
|
||||
export declare function toCommandValue(input: any): string;
|
||||
export {};
|
|
@ -0,0 +1,92 @@
|
|||
"use strict";
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||
result["default"] = mod;
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const os = __importStar(require("os"));
|
||||
/**
|
||||
* Commands
|
||||
*
|
||||
* Command Format:
|
||||
* ::name key=value,key=value::message
|
||||
*
|
||||
* Examples:
|
||||
* ::warning::This is the message
|
||||
* ::set-env name=MY_VAR::some value
|
||||
*/
|
||||
function issueCommand(command, properties, message) {
|
||||
const cmd = new Command(command, properties, message);
|
||||
process.stdout.write(cmd.toString() + os.EOL);
|
||||
}
|
||||
exports.issueCommand = issueCommand;
|
||||
function issue(name, message = '') {
|
||||
issueCommand(name, {}, message);
|
||||
}
|
||||
exports.issue = issue;
|
||||
const CMD_STRING = '::';
|
||||
class Command {
|
||||
constructor(command, properties, message) {
|
||||
if (!command) {
|
||||
command = 'missing.command';
|
||||
}
|
||||
this.command = command;
|
||||
this.properties = properties;
|
||||
this.message = message;
|
||||
}
|
||||
toString() {
|
||||
let cmdStr = CMD_STRING + this.command;
|
||||
if (this.properties && Object.keys(this.properties).length > 0) {
|
||||
cmdStr += ' ';
|
||||
let first = true;
|
||||
for (const key in this.properties) {
|
||||
if (this.properties.hasOwnProperty(key)) {
|
||||
const val = this.properties[key];
|
||||
if (val) {
|
||||
if (first) {
|
||||
first = false;
|
||||
}
|
||||
else {
|
||||
cmdStr += ',';
|
||||
}
|
||||
cmdStr += `${key}=${escapeProperty(val)}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cmdStr += `${CMD_STRING}${escapeData(this.message)}`;
|
||||
return cmdStr;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Sanitizes an input into a string so it can be passed into issueCommand safely
|
||||
* @param input input to sanitize into a string
|
||||
*/
|
||||
function toCommandValue(input) {
|
||||
if (input === null || input === undefined) {
|
||||
return '';
|
||||
}
|
||||
else if (typeof input === 'string' || input instanceof String) {
|
||||
return input;
|
||||
}
|
||||
return JSON.stringify(input);
|
||||
}
|
||||
exports.toCommandValue = toCommandValue;
|
||||
function escapeData(s) {
|
||||
return toCommandValue(s)
|
||||
.replace(/%/g, '%25')
|
||||
.replace(/\r/g, '%0D')
|
||||
.replace(/\n/g, '%0A');
|
||||
}
|
||||
function escapeProperty(s) {
|
||||
return toCommandValue(s)
|
||||
.replace(/%/g, '%25')
|
||||
.replace(/\r/g, '%0D')
|
||||
.replace(/\n/g, '%0A')
|
||||
.replace(/:/g, '%3A')
|
||||
.replace(/,/g, '%2C');
|
||||
}
|
||||
//# sourceMappingURL=command.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"command.js","sourceRoot":"","sources":["../src/command.ts"],"names":[],"mappings":";;;;;;;;;AAAA,uCAAwB;AAWxB;;;;;;;;;GASG;AACH,SAAgB,YAAY,CAC1B,OAAe,EACf,UAA6B,EAC7B,OAAY;IAEZ,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,CAAA;IACrD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAA;AAC/C,CAAC;AAPD,oCAOC;AAED,SAAgB,KAAK,CAAC,IAAY,EAAE,UAAkB,EAAE;IACtD,YAAY,CAAC,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;AACjC,CAAC;AAFD,sBAEC;AAED,MAAM,UAAU,GAAG,IAAI,CAAA;AAEvB,MAAM,OAAO;IAKX,YAAY,OAAe,EAAE,UAA6B,EAAE,OAAe;QACzE,IAAI,CAAC,OAAO,EAAE;YACZ,OAAO,GAAG,iBAAiB,CAAA;SAC5B;QAED,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACtB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAC5B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;IACxB,CAAC;IAED,QAAQ;QACN,IAAI,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC,OAAO,CAAA;QAEtC,IAAI,IAAI,CAAC,UAAU,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE;YAC9D,MAAM,IAAI,GAAG,CAAA;YACb,IAAI,KAAK,GAAG,IAAI,CAAA;YAChB,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,UAAU,EAAE;gBACjC,IAAI,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE;oBACvC,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;oBAChC,IAAI,GAAG,EAAE;wBACP,IAAI,KAAK,EAAE;4BACT,KAAK,GAAG,KAAK,CAAA;yBACd;6BAAM;4BACL,MAAM,IAAI,GAAG,CAAA;yBACd;wBAED,MAAM,IAAI,GAAG,GAAG,IAAI,cAAc,CAAC,GAAG,CAAC,EAAE,CAAA;qBAC1C;iBACF;aACF;SACF;QAED,MAAM,IAAI,GAAG,UAAU,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAA;QACpD,OAAO,MAAM,CAAA;IACf,CAAC;CACF;AAED;;;GAGG;AACH,SAAgB,cAAc,CAAC,KAAU;IACvC,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE;QACzC,OAAO,EAAE,CAAA;KACV;SAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,YAAY,MAAM,EAAE;QAC/D,OAAO,KAAe,CAAA;KACvB;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;AAC9B,CAAC;AAPD,wCAOC;AAED,SAAS,UAAU,CAAC,CAAM;IACxB,OAAO,cAAc,CAAC,CAAC,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;SACpB,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;SACrB,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;AAC1B,CAAC;AAED,SAAS,cAAc,CAAC,CAAM;IAC5B,OAAO,cAAc,CAAC,CAAC,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;SACpB,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;SACrB,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;SACpB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;AACzB,CAAC"}
|
|
@ -0,0 +1,122 @@
|
|||
/**
|
||||
* Interface for getInput options
|
||||
*/
|
||||
export interface InputOptions {
|
||||
/** Optional. Whether the input is required. If required and not present, will throw. Defaults to false */
|
||||
required?: boolean;
|
||||
}
|
||||
/**
|
||||
* The code to exit an action
|
||||
*/
|
||||
export declare enum ExitCode {
|
||||
/**
|
||||
* A code indicating that the action was successful
|
||||
*/
|
||||
Success = 0,
|
||||
/**
|
||||
* A code indicating that the action was a failure
|
||||
*/
|
||||
Failure = 1
|
||||
}
|
||||
/**
|
||||
* Sets env variable for this action and future actions in the job
|
||||
* @param name the name of the variable to set
|
||||
* @param val the value of the variable. Non-string values will be converted to a string via JSON.stringify
|
||||
*/
|
||||
export declare function exportVariable(name: string, val: any): void;
|
||||
/**
|
||||
* Registers a secret which will get masked from logs
|
||||
* @param secret value of the secret
|
||||
*/
|
||||
export declare function setSecret(secret: string): void;
|
||||
/**
|
||||
* Prepends inputPath to the PATH (for this action and future actions)
|
||||
* @param inputPath
|
||||
*/
|
||||
export declare function addPath(inputPath: string): void;
|
||||
/**
|
||||
* Gets the value of an input. The value is also trimmed.
|
||||
*
|
||||
* @param name name of the input to get
|
||||
* @param options optional. See InputOptions.
|
||||
* @returns string
|
||||
*/
|
||||
export declare function getInput(name: string, options?: InputOptions): string;
|
||||
/**
|
||||
* Sets the value of an output.
|
||||
*
|
||||
* @param name name of the output to set
|
||||
* @param value value to store. Non-string values will be converted to a string via JSON.stringify
|
||||
*/
|
||||
export declare function setOutput(name: string, value: any): void;
|
||||
/**
|
||||
* Enables or disables the echoing of commands into stdout for the rest of the step.
|
||||
* Echoing is disabled by default if ACTIONS_STEP_DEBUG is not set.
|
||||
*
|
||||
*/
|
||||
export declare function setCommandEcho(enabled: boolean): void;
|
||||
/**
|
||||
* Sets the action status to failed.
|
||||
* When the action exits it will be with an exit code of 1
|
||||
* @param message add error issue message
|
||||
*/
|
||||
export declare function setFailed(message: string | Error): void;
|
||||
/**
|
||||
* Gets whether Actions Step Debug is on or not
|
||||
*/
|
||||
export declare function isDebug(): boolean;
|
||||
/**
|
||||
* Writes debug message to user log
|
||||
* @param message debug message
|
||||
*/
|
||||
export declare function debug(message: string): void;
|
||||
/**
|
||||
* Adds an error issue
|
||||
* @param message error issue message. Errors will be converted to string via toString()
|
||||
*/
|
||||
export declare function error(message: string | Error): void;
|
||||
/**
|
||||
* Adds an warning issue
|
||||
* @param message warning issue message. Errors will be converted to string via toString()
|
||||
*/
|
||||
export declare function warning(message: string | Error): void;
|
||||
/**
|
||||
* Writes info to log with console.log.
|
||||
* @param message info message
|
||||
*/
|
||||
export declare function info(message: string): void;
|
||||
/**
|
||||
* Begin an output group.
|
||||
*
|
||||
* Output until the next `groupEnd` will be foldable in this group
|
||||
*
|
||||
* @param name The name of the output group
|
||||
*/
|
||||
export declare function startGroup(name: string): void;
|
||||
/**
|
||||
* End an output group.
|
||||
*/
|
||||
export declare function endGroup(): void;
|
||||
/**
|
||||
* Wrap an asynchronous function call in a group.
|
||||
*
|
||||
* Returns the same type as the function itself.
|
||||
*
|
||||
* @param name The name of the group
|
||||
* @param fn The function to wrap in the group
|
||||
*/
|
||||
export declare function group<T>(name: string, fn: () => Promise<T>): Promise<T>;
|
||||
/**
|
||||
* Saves state for current action, the state can only be retrieved by this action's post job execution.
|
||||
*
|
||||
* @param name name of the state to store
|
||||
* @param value value to store. Non-string values will be converted to a string via JSON.stringify
|
||||
*/
|
||||
export declare function saveState(name: string, value: any): void;
|
||||
/**
|
||||
* Gets the value of an state set by this action's main execution.
|
||||
*
|
||||
* @param name name of the state to get
|
||||
* @returns string
|
||||
*/
|
||||
export declare function getState(name: string): string;
|
|
@ -0,0 +1,222 @@
|
|||
"use strict";
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||
result["default"] = mod;
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const command_1 = require("./command");
|
||||
const os = __importStar(require("os"));
|
||||
const path = __importStar(require("path"));
|
||||
/**
|
||||
* The code to exit an action
|
||||
*/
|
||||
var ExitCode;
|
||||
(function (ExitCode) {
|
||||
/**
|
||||
* A code indicating that the action was successful
|
||||
*/
|
||||
ExitCode[ExitCode["Success"] = 0] = "Success";
|
||||
/**
|
||||
* A code indicating that the action was a failure
|
||||
*/
|
||||
ExitCode[ExitCode["Failure"] = 1] = "Failure";
|
||||
})(ExitCode = exports.ExitCode || (exports.ExitCode = {}));
|
||||
//-----------------------------------------------------------------------
|
||||
// Variables
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Sets env variable for this action and future actions in the job
|
||||
* @param name the name of the variable to set
|
||||
* @param val the value of the variable. Non-string values will be converted to a string via JSON.stringify
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function exportVariable(name, val) {
|
||||
const convertedVal = command_1.toCommandValue(val);
|
||||
process.env[name] = convertedVal;
|
||||
command_1.issueCommand('set-env', { name }, convertedVal);
|
||||
}
|
||||
exports.exportVariable = exportVariable;
|
||||
/**
|
||||
* Registers a secret which will get masked from logs
|
||||
* @param secret value of the secret
|
||||
*/
|
||||
function setSecret(secret) {
|
||||
command_1.issueCommand('add-mask', {}, secret);
|
||||
}
|
||||
exports.setSecret = setSecret;
|
||||
/**
|
||||
* Prepends inputPath to the PATH (for this action and future actions)
|
||||
* @param inputPath
|
||||
*/
|
||||
function addPath(inputPath) {
|
||||
command_1.issueCommand('add-path', {}, inputPath);
|
||||
process.env['PATH'] = `${inputPath}${path.delimiter}${process.env['PATH']}`;
|
||||
}
|
||||
exports.addPath = addPath;
|
||||
/**
|
||||
* Gets the value of an input. The value is also trimmed.
|
||||
*
|
||||
* @param name name of the input to get
|
||||
* @param options optional. See InputOptions.
|
||||
* @returns string
|
||||
*/
|
||||
function getInput(name, options) {
|
||||
const val = process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] || '';
|
||||
if (options && options.required && !val) {
|
||||
throw new Error(`Input required and not supplied: ${name}`);
|
||||
}
|
||||
return val.trim();
|
||||
}
|
||||
exports.getInput = getInput;
|
||||
/**
|
||||
* Sets the value of an output.
|
||||
*
|
||||
* @param name name of the output to set
|
||||
* @param value value to store. Non-string values will be converted to a string via JSON.stringify
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function setOutput(name, value) {
|
||||
command_1.issueCommand('set-output', { name }, value);
|
||||
}
|
||||
exports.setOutput = setOutput;
|
||||
/**
|
||||
* Enables or disables the echoing of commands into stdout for the rest of the step.
|
||||
* Echoing is disabled by default if ACTIONS_STEP_DEBUG is not set.
|
||||
*
|
||||
*/
|
||||
function setCommandEcho(enabled) {
|
||||
command_1.issue('echo', enabled ? 'on' : 'off');
|
||||
}
|
||||
exports.setCommandEcho = setCommandEcho;
|
||||
//-----------------------------------------------------------------------
|
||||
// Results
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Sets the action status to failed.
|
||||
* When the action exits it will be with an exit code of 1
|
||||
* @param message add error issue message
|
||||
*/
|
||||
function setFailed(message) {
|
||||
process.exitCode = ExitCode.Failure;
|
||||
error(message);
|
||||
}
|
||||
exports.setFailed = setFailed;
|
||||
//-----------------------------------------------------------------------
|
||||
// Logging Commands
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets whether Actions Step Debug is on or not
|
||||
*/
|
||||
function isDebug() {
|
||||
return process.env['RUNNER_DEBUG'] === '1';
|
||||
}
|
||||
exports.isDebug = isDebug;
|
||||
/**
|
||||
* Writes debug message to user log
|
||||
* @param message debug message
|
||||
*/
|
||||
function debug(message) {
|
||||
command_1.issueCommand('debug', {}, message);
|
||||
}
|
||||
exports.debug = debug;
|
||||
/**
|
||||
* Adds an error issue
|
||||
* @param message error issue message. Errors will be converted to string via toString()
|
||||
*/
|
||||
function error(message) {
|
||||
command_1.issue('error', message instanceof Error ? message.toString() : message);
|
||||
}
|
||||
exports.error = error;
|
||||
/**
|
||||
* Adds an warning issue
|
||||
* @param message warning issue message. Errors will be converted to string via toString()
|
||||
*/
|
||||
function warning(message) {
|
||||
command_1.issue('warning', message instanceof Error ? message.toString() : message);
|
||||
}
|
||||
exports.warning = warning;
|
||||
/**
|
||||
* Writes info to log with console.log.
|
||||
* @param message info message
|
||||
*/
|
||||
function info(message) {
|
||||
process.stdout.write(message + os.EOL);
|
||||
}
|
||||
exports.info = info;
|
||||
/**
|
||||
* Begin an output group.
|
||||
*
|
||||
* Output until the next `groupEnd` will be foldable in this group
|
||||
*
|
||||
* @param name The name of the output group
|
||||
*/
|
||||
function startGroup(name) {
|
||||
command_1.issue('group', name);
|
||||
}
|
||||
exports.startGroup = startGroup;
|
||||
/**
|
||||
* End an output group.
|
||||
*/
|
||||
function endGroup() {
|
||||
command_1.issue('endgroup');
|
||||
}
|
||||
exports.endGroup = endGroup;
|
||||
/**
|
||||
* Wrap an asynchronous function call in a group.
|
||||
*
|
||||
* Returns the same type as the function itself.
|
||||
*
|
||||
* @param name The name of the group
|
||||
* @param fn The function to wrap in the group
|
||||
*/
|
||||
function group(name, fn) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
startGroup(name);
|
||||
let result;
|
||||
try {
|
||||
result = yield fn();
|
||||
}
|
||||
finally {
|
||||
endGroup();
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
exports.group = group;
|
||||
//-----------------------------------------------------------------------
|
||||
// Wrapper action state
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Saves state for current action, the state can only be retrieved by this action's post job execution.
|
||||
*
|
||||
* @param name name of the state to store
|
||||
* @param value value to store. Non-string values will be converted to a string via JSON.stringify
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function saveState(name, value) {
|
||||
command_1.issueCommand('save-state', { name }, value);
|
||||
}
|
||||
exports.saveState = saveState;
|
||||
/**
|
||||
* Gets the value of an state set by this action's main execution.
|
||||
*
|
||||
* @param name name of the state to get
|
||||
* @returns string
|
||||
*/
|
||||
function getState(name) {
|
||||
return process.env[`STATE_${name}`] || '';
|
||||
}
|
||||
exports.getState = getState;
|
||||
//# sourceMappingURL=core.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"core.js","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,uCAA6D;AAE7D,uCAAwB;AACxB,2CAA4B;AAU5B;;GAEG;AACH,IAAY,QAUX;AAVD,WAAY,QAAQ;IAClB;;OAEG;IACH,6CAAW,CAAA;IAEX;;OAEG;IACH,6CAAW,CAAA;AACb,CAAC,EAVW,QAAQ,GAAR,gBAAQ,KAAR,gBAAQ,QAUnB;AAED,yEAAyE;AACzE,YAAY;AACZ,yEAAyE;AAEzE;;;;GAIG;AACH,8DAA8D;AAC9D,SAAgB,cAAc,CAAC,IAAY,EAAE,GAAQ;IACnD,MAAM,YAAY,GAAG,wBAAc,CAAC,GAAG,CAAC,CAAA;IACxC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,YAAY,CAAA;IAChC,sBAAY,CAAC,SAAS,EAAE,EAAC,IAAI,EAAC,EAAE,YAAY,CAAC,CAAA;AAC/C,CAAC;AAJD,wCAIC;AAED;;;GAGG;AACH,SAAgB,SAAS,CAAC,MAAc;IACtC,sBAAY,CAAC,UAAU,EAAE,EAAE,EAAE,MAAM,CAAC,CAAA;AACtC,CAAC;AAFD,8BAEC;AAED;;;GAGG;AACH,SAAgB,OAAO,CAAC,SAAiB;IACvC,sBAAY,CAAC,UAAU,EAAE,EAAE,EAAE,SAAS,CAAC,CAAA;IACvC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,GAAG,SAAS,GAAG,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAA;AAC7E,CAAC;AAHD,0BAGC;AAED;;;;;;GAMG;AACH,SAAgB,QAAQ,CAAC,IAAY,EAAE,OAAsB;IAC3D,MAAM,GAAG,GACP,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,IAAI,EAAE,CAAA;IACrE,IAAI,OAAO,IAAI,OAAO,CAAC,QAAQ,IAAI,CAAC,GAAG,EAAE;QACvC,MAAM,IAAI,KAAK,CAAC,oCAAoC,IAAI,EAAE,CAAC,CAAA;KAC5D;IAED,OAAO,GAAG,CAAC,IAAI,EAAE,CAAA;AACnB,CAAC;AARD,4BAQC;AAED;;;;;GAKG;AACH,8DAA8D;AAC9D,SAAgB,SAAS,CAAC,IAAY,EAAE,KAAU;IAChD,sBAAY,CAAC,YAAY,EAAE,EAAC,IAAI,EAAC,EAAE,KAAK,CAAC,CAAA;AAC3C,CAAC;AAFD,8BAEC;AAED;;;;GAIG;AACH,SAAgB,cAAc,CAAC,OAAgB;IAC7C,eAAK,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;AACvC,CAAC;AAFD,wCAEC;AAED,yEAAyE;AACzE,UAAU;AACV,yEAAyE;AAEzE;;;;GAIG;AACH,SAAgB,SAAS,CAAC,OAAuB;IAC/C,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAA;IAEnC,KAAK,CAAC,OAAO,CAAC,CAAA;AAChB,CAAC;AAJD,8BAIC;AAED,yEAAyE;AACzE,mBAAmB;AACnB,yEAAyE;AAEzE;;GAEG;AACH,SAAgB,OAAO;IACrB,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,KAAK,GAAG,CAAA;AAC5C,CAAC;AAFD,0BAEC;AAED;;;GAGG;AACH,SAAgB,KAAK,CAAC,OAAe;IACnC,sBAAY,CAAC,OAAO,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;AACpC,CAAC;AAFD,sBAEC;AAED;;;GAGG;AACH,SAAgB,KAAK,CAAC,OAAuB;IAC3C,eAAK,CAAC,OAAO,EAAE,OAAO,YAAY,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAA;AACzE,CAAC;AAFD,sBAEC;AAED;;;GAGG;AACH,SAAgB,OAAO,CAAC,OAAuB;IAC7C,eAAK,CAAC,SAAS,EAAE,OAAO,YAAY,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAA;AAC3E,CAAC;AAFD,0BAEC;AAED;;;GAGG;AACH,SAAgB,IAAI,CAAC,OAAe;IAClC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,GAAG,CAAC,CAAA;AACxC,CAAC;AAFD,oBAEC;AAED;;;;;;GAMG;AACH,SAAgB,UAAU,CAAC,IAAY;IACrC,eAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;AACtB,CAAC;AAFD,gCAEC;AAED;;GAEG;AACH,SAAgB,QAAQ;IACtB,eAAK,CAAC,UAAU,CAAC,CAAA;AACnB,CAAC;AAFD,4BAEC;AAED;;;;;;;GAOG;AACH,SAAsB,KAAK,CAAI,IAAY,EAAE,EAAoB;;QAC/D,UAAU,CAAC,IAAI,CAAC,CAAA;QAEhB,IAAI,MAAS,CAAA;QAEb,IAAI;YACF,MAAM,GAAG,MAAM,EAAE,EAAE,CAAA;SACpB;gBAAS;YACR,QAAQ,EAAE,CAAA;SACX;QAED,OAAO,MAAM,CAAA;IACf,CAAC;CAAA;AAZD,sBAYC;AAED,yEAAyE;AACzE,uBAAuB;AACvB,yEAAyE;AAEzE;;;;;GAKG;AACH,8DAA8D;AAC9D,SAAgB,SAAS,CAAC,IAAY,EAAE,KAAU;IAChD,sBAAY,CAAC,YAAY,EAAE,EAAC,IAAI,EAAC,EAAE,KAAK,CAAC,CAAA;AAC3C,CAAC;AAFD,8BAEC;AAED;;;;;GAKG;AACH,SAAgB,QAAQ,CAAC,IAAY;IACnC,OAAO,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC,IAAI,EAAE,CAAA;AAC3C,CAAC;AAFD,4BAEC"}
|
|
@ -0,0 +1,69 @@
|
|||
{
|
||||
"_args": [
|
||||
[
|
||||
"@actions/core@1.2.4",
|
||||
"D:\\Repos\\security-code-analysis-action"
|
||||
]
|
||||
],
|
||||
"_from": "@actions/core@1.2.4",
|
||||
"_id": "@actions/core@1.2.4",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-YJCEq8BE3CdN8+7HPZ/4DxJjk/OkZV2FFIf+DlZTC/4iBlzYCD5yjRR6eiOS5llO11zbRltIRuKAjMKaWTE6cg==",
|
||||
"_location": "/@actions/core",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "version",
|
||||
"registry": true,
|
||||
"raw": "@actions/core@1.2.4",
|
||||
"name": "@actions/core",
|
||||
"escapedName": "@actions%2fcore",
|
||||
"scope": "@actions",
|
||||
"rawSpec": "1.2.4",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "1.2.4"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.4.tgz",
|
||||
"_spec": "1.2.4",
|
||||
"_where": "D:\\Repos\\security-code-analysis-action",
|
||||
"bugs": {
|
||||
"url": "https://github.com/actions/toolkit/issues"
|
||||
},
|
||||
"description": "Actions core lib",
|
||||
"devDependencies": {
|
||||
"@types/node": "^12.0.2"
|
||||
},
|
||||
"directories": {
|
||||
"lib": "lib",
|
||||
"test": "__tests__"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"homepage": "https://github.com/actions/toolkit/tree/master/packages/core",
|
||||
"keywords": [
|
||||
"github",
|
||||
"actions",
|
||||
"core"
|
||||
],
|
||||
"license": "MIT",
|
||||
"main": "lib/core.js",
|
||||
"name": "@actions/core",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/actions/toolkit.git",
|
||||
"directory": "packages/core"
|
||||
},
|
||||
"scripts": {
|
||||
"audit-moderate": "npm install && npm audit --audit-level=moderate",
|
||||
"test": "echo \"Error: run tests from root\" && exit 1",
|
||||
"tsc": "tsc"
|
||||
},
|
||||
"types": "lib/core.d.ts",
|
||||
"version": "1.2.4"
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
# `@actions/exec`
|
||||
|
||||
## Usage
|
||||
|
||||
#### Basic
|
||||
|
||||
You can use this package to execute tools in a cross platform way:
|
||||
|
||||
```js
|
||||
const exec = require('@actions/exec');
|
||||
|
||||
await exec.exec('node index.js');
|
||||
```
|
||||
|
||||
#### Args
|
||||
|
||||
You can also pass in arg arrays:
|
||||
|
||||
```js
|
||||
const exec = require('@actions/exec');
|
||||
|
||||
await exec.exec('node', ['index.js', 'foo=bar']);
|
||||
```
|
||||
|
||||
#### Output/options
|
||||
|
||||
Capture output or specify [other options](https://github.com/actions/toolkit/blob/d9347d4ab99fd507c0b9104b2cf79fb44fcc827d/packages/exec/src/interfaces.ts#L5):
|
||||
|
||||
```js
|
||||
const exec = require('@actions/exec');
|
||||
|
||||
let myOutput = '';
|
||||
let myError = '';
|
||||
|
||||
const options = {};
|
||||
options.listeners = {
|
||||
stdout: (data: Buffer) => {
|
||||
myOutput += data.toString();
|
||||
},
|
||||
stderr: (data: Buffer) => {
|
||||
myError += data.toString();
|
||||
}
|
||||
};
|
||||
options.cwd = './lib';
|
||||
|
||||
await exec.exec('node', ['index.js', 'foo=bar'], options);
|
||||
```
|
||||
|
||||
#### Exec tools not in the PATH
|
||||
|
||||
You can specify the full path for tools not in the PATH:
|
||||
|
||||
```js
|
||||
const exec = require('@actions/exec');
|
||||
|
||||
await exec.exec('"/path/to/my-tool"', ['arg1']);
|
||||
```
|
|
@ -0,0 +1,13 @@
|
|||
import { ExecOptions } from './interfaces';
|
||||
export { ExecOptions };
|
||||
/**
|
||||
* Exec a command.
|
||||
* Output will be streamed to the live console.
|
||||
* Returns promise with return code
|
||||
*
|
||||
* @param commandLine command to execute (can include additional args). Must be correctly escaped.
|
||||
* @param args optional arguments for tool. Escaping is handled by the lib.
|
||||
* @param options optional exec options. See ExecOptions
|
||||
* @returns Promise<number> exit code
|
||||
*/
|
||||
export declare function exec(commandLine: string, args?: string[], options?: ExecOptions): Promise<number>;
|
|
@ -0,0 +1,44 @@
|
|||
"use strict";
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||
result["default"] = mod;
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const tr = __importStar(require("./toolrunner"));
|
||||
/**
|
||||
* Exec a command.
|
||||
* Output will be streamed to the live console.
|
||||
* Returns promise with return code
|
||||
*
|
||||
* @param commandLine command to execute (can include additional args). Must be correctly escaped.
|
||||
* @param args optional arguments for tool. Escaping is handled by the lib.
|
||||
* @param options optional exec options. See ExecOptions
|
||||
* @returns Promise<number> exit code
|
||||
*/
|
||||
function exec(commandLine, args, options) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const commandArgs = tr.argStringToArray(commandLine);
|
||||
if (commandArgs.length === 0) {
|
||||
throw new Error(`Parameter 'commandLine' cannot be null or empty.`);
|
||||
}
|
||||
// Path to tool to execute should be first arg
|
||||
const toolPath = commandArgs[0];
|
||||
args = commandArgs.slice(1).concat(args || []);
|
||||
const runner = new tr.ToolRunner(toolPath, args, options);
|
||||
return runner.exec();
|
||||
});
|
||||
}
|
||||
exports.exec = exec;
|
||||
//# sourceMappingURL=exec.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"exec.js","sourceRoot":"","sources":["../src/exec.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AACA,iDAAkC;AAIlC;;;;;;;;;GASG;AACH,SAAsB,IAAI,CACxB,WAAmB,EACnB,IAAe,EACf,OAAqB;;QAErB,MAAM,WAAW,GAAG,EAAE,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAA;QACpD,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE;YAC5B,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAA;SACpE;QACD,8CAA8C;QAC9C,MAAM,QAAQ,GAAG,WAAW,CAAC,CAAC,CAAC,CAAA;QAC/B,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAA;QAC9C,MAAM,MAAM,GAAkB,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;QACxE,OAAO,MAAM,CAAC,IAAI,EAAE,CAAA;IACtB,CAAC;CAAA;AAdD,oBAcC"}
|
|
@ -0,0 +1,37 @@
|
|||
/// <reference types="node" />
|
||||
import * as stream from 'stream';
|
||||
/**
|
||||
* Interface for exec options
|
||||
*/
|
||||
export interface ExecOptions {
|
||||
/** optional working directory. defaults to current */
|
||||
cwd?: string;
|
||||
/** optional envvar dictionary. defaults to current process's env */
|
||||
env?: {
|
||||
[key: string]: string;
|
||||
};
|
||||
/** optional. defaults to false */
|
||||
silent?: boolean;
|
||||
/** optional out stream to use. Defaults to process.stdout */
|
||||
outStream?: stream.Writable;
|
||||
/** optional err stream to use. Defaults to process.stderr */
|
||||
errStream?: stream.Writable;
|
||||
/** optional. whether to skip quoting/escaping arguments if needed. defaults to false. */
|
||||
windowsVerbatimArguments?: boolean;
|
||||
/** optional. whether to fail if output to stderr. defaults to false */
|
||||
failOnStdErr?: boolean;
|
||||
/** optional. defaults to failing on non zero. ignore will not fail leaving it up to the caller */
|
||||
ignoreReturnCode?: boolean;
|
||||
/** optional. How long in ms to wait for STDIO streams to close after the exit event of the process before terminating. defaults to 10000 */
|
||||
delay?: number;
|
||||
/** optional. input to write to the process on STDIN. */
|
||||
input?: Buffer;
|
||||
/** optional. Listeners for output. Callback functions that will be called on these events */
|
||||
listeners?: {
|
||||
stdout?: (data: Buffer) => void;
|
||||
stderr?: (data: Buffer) => void;
|
||||
stdline?: (data: string) => void;
|
||||
errline?: (data: string) => void;
|
||||
debug?: (data: string) => void;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
//# sourceMappingURL=interfaces.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":""}
|
|
@ -0,0 +1,37 @@
|
|||
/// <reference types="node" />
|
||||
import * as events from 'events';
|
||||
import * as im from './interfaces';
|
||||
export declare class ToolRunner extends events.EventEmitter {
|
||||
constructor(toolPath: string, args?: string[], options?: im.ExecOptions);
|
||||
private toolPath;
|
||||
private args;
|
||||
private options;
|
||||
private _debug;
|
||||
private _getCommandString;
|
||||
private _processLineBuffer;
|
||||
private _getSpawnFileName;
|
||||
private _getSpawnArgs;
|
||||
private _endsWith;
|
||||
private _isCmdFile;
|
||||
private _windowsQuoteCmdArg;
|
||||
private _uvQuoteCmdArg;
|
||||
private _cloneExecOptions;
|
||||
private _getSpawnOptions;
|
||||
/**
|
||||
* Exec a tool.
|
||||
* Output will be streamed to the live console.
|
||||
* Returns promise with return code
|
||||
*
|
||||
* @param tool path to tool to exec
|
||||
* @param options optional exec options. See ExecOptions
|
||||
* @returns number
|
||||
*/
|
||||
exec(): Promise<number>;
|
||||
}
|
||||
/**
|
||||
* Convert an arg string to an array of args. Handles escaping
|
||||
*
|
||||
* @param argString string of arguments
|
||||
* @returns string[] array of arguments
|
||||
*/
|
||||
export declare function argStringToArray(argString: string): string[];
|
|
@ -0,0 +1,600 @@
|
|||
"use strict";
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||
result["default"] = mod;
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const os = __importStar(require("os"));
|
||||
const events = __importStar(require("events"));
|
||||
const child = __importStar(require("child_process"));
|
||||
const path = __importStar(require("path"));
|
||||
const io = __importStar(require("@actions/io"));
|
||||
const ioUtil = __importStar(require("@actions/io/lib/io-util"));
|
||||
/* eslint-disable @typescript-eslint/unbound-method */
|
||||
const IS_WINDOWS = process.platform === 'win32';
|
||||
/*
|
||||
* Class for running command line tools. Handles quoting and arg parsing in a platform agnostic way.
|
||||
*/
|
||||
class ToolRunner extends events.EventEmitter {
|
||||
constructor(toolPath, args, options) {
|
||||
super();
|
||||
if (!toolPath) {
|
||||
throw new Error("Parameter 'toolPath' cannot be null or empty.");
|
||||
}
|
||||
this.toolPath = toolPath;
|
||||
this.args = args || [];
|
||||
this.options = options || {};
|
||||
}
|
||||
_debug(message) {
|
||||
if (this.options.listeners && this.options.listeners.debug) {
|
||||
this.options.listeners.debug(message);
|
||||
}
|
||||
}
|
||||
_getCommandString(options, noPrefix) {
|
||||
const toolPath = this._getSpawnFileName();
|
||||
const args = this._getSpawnArgs(options);
|
||||
let cmd = noPrefix ? '' : '[command]'; // omit prefix when piped to a second tool
|
||||
if (IS_WINDOWS) {
|
||||
// Windows + cmd file
|
||||
if (this._isCmdFile()) {
|
||||
cmd += toolPath;
|
||||
for (const a of args) {
|
||||
cmd += ` ${a}`;
|
||||
}
|
||||
}
|
||||
// Windows + verbatim
|
||||
else if (options.windowsVerbatimArguments) {
|
||||
cmd += `"${toolPath}"`;
|
||||
for (const a of args) {
|
||||
cmd += ` ${a}`;
|
||||
}
|
||||
}
|
||||
// Windows (regular)
|
||||
else {
|
||||
cmd += this._windowsQuoteCmdArg(toolPath);
|
||||
for (const a of args) {
|
||||
cmd += ` ${this._windowsQuoteCmdArg(a)}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// OSX/Linux - this can likely be improved with some form of quoting.
|
||||
// creating processes on Unix is fundamentally different than Windows.
|
||||
// on Unix, execvp() takes an arg array.
|
||||
cmd += toolPath;
|
||||
for (const a of args) {
|
||||
cmd += ` ${a}`;
|
||||
}
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
_processLineBuffer(data, strBuffer, onLine) {
|
||||
try {
|
||||
let s = strBuffer + data.toString();
|
||||
let n = s.indexOf(os.EOL);
|
||||
while (n > -1) {
|
||||
const line = s.substring(0, n);
|
||||
onLine(line);
|
||||
// the rest of the string ...
|
||||
s = s.substring(n + os.EOL.length);
|
||||
n = s.indexOf(os.EOL);
|
||||
}
|
||||
strBuffer = s;
|
||||
}
|
||||
catch (err) {
|
||||
// streaming lines to console is best effort. Don't fail a build.
|
||||
this._debug(`error processing line. Failed with error ${err}`);
|
||||
}
|
||||
}
|
||||
_getSpawnFileName() {
|
||||
if (IS_WINDOWS) {
|
||||
if (this._isCmdFile()) {
|
||||
return process.env['COMSPEC'] || 'cmd.exe';
|
||||
}
|
||||
}
|
||||
return this.toolPath;
|
||||
}
|
||||
_getSpawnArgs(options) {
|
||||
if (IS_WINDOWS) {
|
||||
if (this._isCmdFile()) {
|
||||
let argline = `/D /S /C "${this._windowsQuoteCmdArg(this.toolPath)}`;
|
||||
for (const a of this.args) {
|
||||
argline += ' ';
|
||||
argline += options.windowsVerbatimArguments
|
||||
? a
|
||||
: this._windowsQuoteCmdArg(a);
|
||||
}
|
||||
argline += '"';
|
||||
return [argline];
|
||||
}
|
||||
}
|
||||
return this.args;
|
||||
}
|
||||
_endsWith(str, end) {
|
||||
return str.endsWith(end);
|
||||
}
|
||||
_isCmdFile() {
|
||||
const upperToolPath = this.toolPath.toUpperCase();
|
||||
return (this._endsWith(upperToolPath, '.CMD') ||
|
||||
this._endsWith(upperToolPath, '.BAT'));
|
||||
}
|
||||
_windowsQuoteCmdArg(arg) {
|
||||
// for .exe, apply the normal quoting rules that libuv applies
|
||||
if (!this._isCmdFile()) {
|
||||
return this._uvQuoteCmdArg(arg);
|
||||
}
|
||||
// otherwise apply quoting rules specific to the cmd.exe command line parser.
|
||||
// the libuv rules are generic and are not designed specifically for cmd.exe
|
||||
// command line parser.
|
||||
//
|
||||
// for a detailed description of the cmd.exe command line parser, refer to
|
||||
// http://stackoverflow.com/questions/4094699/how-does-the-windows-command-interpreter-cmd-exe-parse-scripts/7970912#7970912
|
||||
// need quotes for empty arg
|
||||
if (!arg) {
|
||||
return '""';
|
||||
}
|
||||
// determine whether the arg needs to be quoted
|
||||
const cmdSpecialChars = [
|
||||
' ',
|
||||
'\t',
|
||||
'&',
|
||||
'(',
|
||||
')',
|
||||
'[',
|
||||
']',
|
||||
'{',
|
||||
'}',
|
||||
'^',
|
||||
'=',
|
||||
';',
|
||||
'!',
|
||||
"'",
|
||||
'+',
|
||||
',',
|
||||
'`',
|
||||
'~',
|
||||
'|',
|
||||
'<',
|
||||
'>',
|
||||
'"'
|
||||
];
|
||||
let needsQuotes = false;
|
||||
for (const char of arg) {
|
||||
if (cmdSpecialChars.some(x => x === char)) {
|
||||
needsQuotes = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// short-circuit if quotes not needed
|
||||
if (!needsQuotes) {
|
||||
return arg;
|
||||
}
|
||||
// the following quoting rules are very similar to the rules that by libuv applies.
|
||||
//
|
||||
// 1) wrap the string in quotes
|
||||
//
|
||||
// 2) double-up quotes - i.e. " => ""
|
||||
//
|
||||
// this is different from the libuv quoting rules. libuv replaces " with \", which unfortunately
|
||||
// doesn't work well with a cmd.exe command line.
|
||||
//
|
||||
// note, replacing " with "" also works well if the arg is passed to a downstream .NET console app.
|
||||
// for example, the command line:
|
||||
// foo.exe "myarg:""my val"""
|
||||
// is parsed by a .NET console app into an arg array:
|
||||
// [ "myarg:\"my val\"" ]
|
||||
// which is the same end result when applying libuv quoting rules. although the actual
|
||||
// command line from libuv quoting rules would look like:
|
||||
// foo.exe "myarg:\"my val\""
|
||||
//
|
||||
// 3) double-up slashes that precede a quote,
|
||||
// e.g. hello \world => "hello \world"
|
||||
// hello\"world => "hello\\""world"
|
||||
// hello\\"world => "hello\\\\""world"
|
||||
// hello world\ => "hello world\\"
|
||||
//
|
||||
// technically this is not required for a cmd.exe command line, or the batch argument parser.
|
||||
// the reasons for including this as a .cmd quoting rule are:
|
||||
//
|
||||
// a) this is optimized for the scenario where the argument is passed from the .cmd file to an
|
||||
// external program. many programs (e.g. .NET console apps) rely on the slash-doubling rule.
|
||||
//
|
||||
// b) it's what we've been doing previously (by deferring to node default behavior) and we
|
||||
// haven't heard any complaints about that aspect.
|
||||
//
|
||||
// note, a weakness of the quoting rules chosen here, is that % is not escaped. in fact, % cannot be
|
||||
// escaped when used on the command line directly - even though within a .cmd file % can be escaped
|
||||
// by using %%.
|
||||
//
|
||||
// the saving grace is, on the command line, %var% is left as-is if var is not defined. this contrasts
|
||||
// the line parsing rules within a .cmd file, where if var is not defined it is replaced with nothing.
|
||||
//
|
||||
// one option that was explored was replacing % with ^% - i.e. %var% => ^%var^%. this hack would
|
||||
// often work, since it is unlikely that var^ would exist, and the ^ character is removed when the
|
||||
// variable is used. the problem, however, is that ^ is not removed when %* is used to pass the args
|
||||
// to an external program.
|
||||
//
|
||||
// an unexplored potential solution for the % escaping problem, is to create a wrapper .cmd file.
|
||||
// % can be escaped within a .cmd file.
|
||||
let reverse = '"';
|
||||
let quoteHit = true;
|
||||
for (let i = arg.length; i > 0; i--) {
|
||||
// walk the string in reverse
|
||||
reverse += arg[i - 1];
|
||||
if (quoteHit && arg[i - 1] === '\\') {
|
||||
reverse += '\\'; // double the slash
|
||||
}
|
||||
else if (arg[i - 1] === '"') {
|
||||
quoteHit = true;
|
||||
reverse += '"'; // double the quote
|
||||
}
|
||||
else {
|
||||
quoteHit = false;
|
||||
}
|
||||
}
|
||||
reverse += '"';
|
||||
return reverse
|
||||
.split('')
|
||||
.reverse()
|
||||
.join('');
|
||||
}
|
||||
_uvQuoteCmdArg(arg) {
|
||||
// Tool runner wraps child_process.spawn() and needs to apply the same quoting as
|
||||
// Node in certain cases where the undocumented spawn option windowsVerbatimArguments
|
||||
// is used.
|
||||
//
|
||||
// Since this function is a port of quote_cmd_arg from Node 4.x (technically, lib UV,
|
||||
// see https://github.com/nodejs/node/blob/v4.x/deps/uv/src/win/process.c for details),
|
||||
// pasting copyright notice from Node within this function:
|
||||
//
|
||||
// Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
//
|
||||
// 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.
|
||||
if (!arg) {
|
||||
// Need double quotation for empty argument
|
||||
return '""';
|
||||
}
|
||||
if (!arg.includes(' ') && !arg.includes('\t') && !arg.includes('"')) {
|
||||
// No quotation needed
|
||||
return arg;
|
||||
}
|
||||
if (!arg.includes('"') && !arg.includes('\\')) {
|
||||
// No embedded double quotes or backslashes, so I can just wrap
|
||||
// quote marks around the whole thing.
|
||||
return `"${arg}"`;
|
||||
}
|
||||
// Expected input/output:
|
||||
// input : hello"world
|
||||
// output: "hello\"world"
|
||||
// input : hello""world
|
||||
// output: "hello\"\"world"
|
||||
// input : hello\world
|
||||
// output: hello\world
|
||||
// input : hello\\world
|
||||
// output: hello\\world
|
||||
// input : hello\"world
|
||||
// output: "hello\\\"world"
|
||||
// input : hello\\"world
|
||||
// output: "hello\\\\\"world"
|
||||
// input : hello world\
|
||||
// output: "hello world\\" - note the comment in libuv actually reads "hello world\"
|
||||
// but it appears the comment is wrong, it should be "hello world\\"
|
||||
let reverse = '"';
|
||||
let quoteHit = true;
|
||||
for (let i = arg.length; i > 0; i--) {
|
||||
// walk the string in reverse
|
||||
reverse += arg[i - 1];
|
||||
if (quoteHit && arg[i - 1] === '\\') {
|
||||
reverse += '\\';
|
||||
}
|
||||
else if (arg[i - 1] === '"') {
|
||||
quoteHit = true;
|
||||
reverse += '\\';
|
||||
}
|
||||
else {
|
||||
quoteHit = false;
|
||||
}
|
||||
}
|
||||
reverse += '"';
|
||||
return reverse
|
||||
.split('')
|
||||
.reverse()
|
||||
.join('');
|
||||
}
|
||||
_cloneExecOptions(options) {
|
||||
options = options || {};
|
||||
const result = {
|
||||
cwd: options.cwd || process.cwd(),
|
||||
env: options.env || process.env,
|
||||
silent: options.silent || false,
|
||||
windowsVerbatimArguments: options.windowsVerbatimArguments || false,
|
||||
failOnStdErr: options.failOnStdErr || false,
|
||||
ignoreReturnCode: options.ignoreReturnCode || false,
|
||||
delay: options.delay || 10000
|
||||
};
|
||||
result.outStream = options.outStream || process.stdout;
|
||||
result.errStream = options.errStream || process.stderr;
|
||||
return result;
|
||||
}
|
||||
_getSpawnOptions(options, toolPath) {
|
||||
options = options || {};
|
||||
const result = {};
|
||||
result.cwd = options.cwd;
|
||||
result.env = options.env;
|
||||
result['windowsVerbatimArguments'] =
|
||||
options.windowsVerbatimArguments || this._isCmdFile();
|
||||
if (options.windowsVerbatimArguments) {
|
||||
result.argv0 = `"${toolPath}"`;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Exec a tool.
|
||||
* Output will be streamed to the live console.
|
||||
* Returns promise with return code
|
||||
*
|
||||
* @param tool path to tool to exec
|
||||
* @param options optional exec options. See ExecOptions
|
||||
* @returns number
|
||||
*/
|
||||
exec() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
// root the tool path if it is unrooted and contains relative pathing
|
||||
if (!ioUtil.isRooted(this.toolPath) &&
|
||||
(this.toolPath.includes('/') ||
|
||||
(IS_WINDOWS && this.toolPath.includes('\\')))) {
|
||||
// prefer options.cwd if it is specified, however options.cwd may also need to be rooted
|
||||
this.toolPath = path.resolve(process.cwd(), this.options.cwd || process.cwd(), this.toolPath);
|
||||
}
|
||||
// if the tool is only a file name, then resolve it from the PATH
|
||||
// otherwise verify it exists (add extension on Windows if necessary)
|
||||
this.toolPath = yield io.which(this.toolPath, true);
|
||||
return new Promise((resolve, reject) => {
|
||||
this._debug(`exec tool: ${this.toolPath}`);
|
||||
this._debug('arguments:');
|
||||
for (const arg of this.args) {
|
||||
this._debug(` ${arg}`);
|
||||
}
|
||||
const optionsNonNull = this._cloneExecOptions(this.options);
|
||||
if (!optionsNonNull.silent && optionsNonNull.outStream) {
|
||||
optionsNonNull.outStream.write(this._getCommandString(optionsNonNull) + os.EOL);
|
||||
}
|
||||
const state = new ExecState(optionsNonNull, this.toolPath);
|
||||
state.on('debug', (message) => {
|
||||
this._debug(message);
|
||||
});
|
||||
const fileName = this._getSpawnFileName();
|
||||
const cp = child.spawn(fileName, this._getSpawnArgs(optionsNonNull), this._getSpawnOptions(this.options, fileName));
|
||||
const stdbuffer = '';
|
||||
if (cp.stdout) {
|
||||
cp.stdout.on('data', (data) => {
|
||||
if (this.options.listeners && this.options.listeners.stdout) {
|
||||
this.options.listeners.stdout(data);
|
||||
}
|
||||
if (!optionsNonNull.silent && optionsNonNull.outStream) {
|
||||
optionsNonNull.outStream.write(data);
|
||||
}
|
||||
this._processLineBuffer(data, stdbuffer, (line) => {
|
||||
if (this.options.listeners && this.options.listeners.stdline) {
|
||||
this.options.listeners.stdline(line);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
const errbuffer = '';
|
||||
if (cp.stderr) {
|
||||
cp.stderr.on('data', (data) => {
|
||||
state.processStderr = true;
|
||||
if (this.options.listeners && this.options.listeners.stderr) {
|
||||
this.options.listeners.stderr(data);
|
||||
}
|
||||
if (!optionsNonNull.silent &&
|
||||
optionsNonNull.errStream &&
|
||||
optionsNonNull.outStream) {
|
||||
const s = optionsNonNull.failOnStdErr
|
||||
? optionsNonNull.errStream
|
||||
: optionsNonNull.outStream;
|
||||
s.write(data);
|
||||
}
|
||||
this._processLineBuffer(data, errbuffer, (line) => {
|
||||
if (this.options.listeners && this.options.listeners.errline) {
|
||||
this.options.listeners.errline(line);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
cp.on('error', (err) => {
|
||||
state.processError = err.message;
|
||||
state.processExited = true;
|
||||
state.processClosed = true;
|
||||
state.CheckComplete();
|
||||
});
|
||||
cp.on('exit', (code) => {
|
||||
state.processExitCode = code;
|
||||
state.processExited = true;
|
||||
this._debug(`Exit code ${code} received from tool '${this.toolPath}'`);
|
||||
state.CheckComplete();
|
||||
});
|
||||
cp.on('close', (code) => {
|
||||
state.processExitCode = code;
|
||||
state.processExited = true;
|
||||
state.processClosed = true;
|
||||
this._debug(`STDIO streams have closed for tool '${this.toolPath}'`);
|
||||
state.CheckComplete();
|
||||
});
|
||||
state.on('done', (error, exitCode) => {
|
||||
if (stdbuffer.length > 0) {
|
||||
this.emit('stdline', stdbuffer);
|
||||
}
|
||||
if (errbuffer.length > 0) {
|
||||
this.emit('errline', errbuffer);
|
||||
}
|
||||
cp.removeAllListeners();
|
||||
if (error) {
|
||||
reject(error);
|
||||
}
|
||||
else {
|
||||
resolve(exitCode);
|
||||
}
|
||||
});
|
||||
if (this.options.input) {
|
||||
if (!cp.stdin) {
|
||||
throw new Error('child process missing stdin');
|
||||
}
|
||||
cp.stdin.end(this.options.input);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.ToolRunner = ToolRunner;
|
||||
/**
|
||||
* Convert an arg string to an array of args. Handles escaping
|
||||
*
|
||||
* @param argString string of arguments
|
||||
* @returns string[] array of arguments
|
||||
*/
|
||||
function argStringToArray(argString) {
|
||||
const args = [];
|
||||
let inQuotes = false;
|
||||
let escaped = false;
|
||||
let arg = '';
|
||||
function append(c) {
|
||||
// we only escape double quotes.
|
||||
if (escaped && c !== '"') {
|
||||
arg += '\\';
|
||||
}
|
||||
arg += c;
|
||||
escaped = false;
|
||||
}
|
||||
for (let i = 0; i < argString.length; i++) {
|
||||
const c = argString.charAt(i);
|
||||
if (c === '"') {
|
||||
if (!escaped) {
|
||||
inQuotes = !inQuotes;
|
||||
}
|
||||
else {
|
||||
append(c);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (c === '\\' && escaped) {
|
||||
append(c);
|
||||
continue;
|
||||
}
|
||||
if (c === '\\' && inQuotes) {
|
||||
escaped = true;
|
||||
continue;
|
||||
}
|
||||
if (c === ' ' && !inQuotes) {
|
||||
if (arg.length > 0) {
|
||||
args.push(arg);
|
||||
arg = '';
|
||||
}
|
||||
continue;
|
||||
}
|
||||
append(c);
|
||||
}
|
||||
if (arg.length > 0) {
|
||||
args.push(arg.trim());
|
||||
}
|
||||
return args;
|
||||
}
|
||||
exports.argStringToArray = argStringToArray;
|
||||
class ExecState extends events.EventEmitter {
|
||||
constructor(options, toolPath) {
|
||||
super();
|
||||
this.processClosed = false; // tracks whether the process has exited and stdio is closed
|
||||
this.processError = '';
|
||||
this.processExitCode = 0;
|
||||
this.processExited = false; // tracks whether the process has exited
|
||||
this.processStderr = false; // tracks whether stderr was written to
|
||||
this.delay = 10000; // 10 seconds
|
||||
this.done = false;
|
||||
this.timeout = null;
|
||||
if (!toolPath) {
|
||||
throw new Error('toolPath must not be empty');
|
||||
}
|
||||
this.options = options;
|
||||
this.toolPath = toolPath;
|
||||
if (options.delay) {
|
||||
this.delay = options.delay;
|
||||
}
|
||||
}
|
||||
CheckComplete() {
|
||||
if (this.done) {
|
||||
return;
|
||||
}
|
||||
if (this.processClosed) {
|
||||
this._setResult();
|
||||
}
|
||||
else if (this.processExited) {
|
||||
this.timeout = setTimeout(ExecState.HandleTimeout, this.delay, this);
|
||||
}
|
||||
}
|
||||
_debug(message) {
|
||||
this.emit('debug', message);
|
||||
}
|
||||
_setResult() {
|
||||
// determine whether there is an error
|
||||
let error;
|
||||
if (this.processExited) {
|
||||
if (this.processError) {
|
||||
error = new Error(`There was an error when attempting to execute the process '${this.toolPath}'. This may indicate the process failed to start. Error: ${this.processError}`);
|
||||
}
|
||||
else if (this.processExitCode !== 0 && !this.options.ignoreReturnCode) {
|
||||
error = new Error(`The process '${this.toolPath}' failed with exit code ${this.processExitCode}`);
|
||||
}
|
||||
else if (this.processStderr && this.options.failOnStdErr) {
|
||||
error = new Error(`The process '${this.toolPath}' failed because one or more lines were written to the STDERR stream`);
|
||||
}
|
||||
}
|
||||
// clear the timeout
|
||||
if (this.timeout) {
|
||||
clearTimeout(this.timeout);
|
||||
this.timeout = null;
|
||||
}
|
||||
this.done = true;
|
||||
this.emit('done', error, this.processExitCode);
|
||||
}
|
||||
static HandleTimeout(state) {
|
||||
if (state.done) {
|
||||
return;
|
||||
}
|
||||
if (!state.processClosed && state.processExited) {
|
||||
const message = `The STDIO streams did not close within ${state.delay /
|
||||
1000} seconds of the exit event from process '${state.toolPath}'. This may indicate a child process inherited the STDIO streams and has not yet exited.`;
|
||||
state._debug(message);
|
||||
}
|
||||
state._setResult();
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=toolrunner.js.map
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -0,0 +1,69 @@
|
|||
{
|
||||
"_args": [
|
||||
[
|
||||
"@actions/exec@1.0.4",
|
||||
"D:\\Repos\\security-code-analysis-action"
|
||||
]
|
||||
],
|
||||
"_from": "@actions/exec@1.0.4",
|
||||
"_id": "@actions/exec@1.0.4",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-4DPChWow9yc9W3WqEbUj8Nr86xkpyE29ZzWjXucHItclLbEW6jr80Zx4nqv18QL6KK65+cifiQZXvnqgTV6oHw==",
|
||||
"_location": "/@actions/exec",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "version",
|
||||
"registry": true,
|
||||
"raw": "@actions/exec@1.0.4",
|
||||
"name": "@actions/exec",
|
||||
"escapedName": "@actions%2fexec",
|
||||
"scope": "@actions",
|
||||
"rawSpec": "1.0.4",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "1.0.4"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.0.4.tgz",
|
||||
"_spec": "1.0.4",
|
||||
"_where": "D:\\Repos\\security-code-analysis-action",
|
||||
"bugs": {
|
||||
"url": "https://github.com/actions/toolkit/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/io": "^1.0.1"
|
||||
},
|
||||
"description": "Actions exec lib",
|
||||
"directories": {
|
||||
"lib": "lib",
|
||||
"test": "__tests__"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"homepage": "https://github.com/actions/toolkit/tree/master/packages/exec",
|
||||
"keywords": [
|
||||
"github",
|
||||
"actions",
|
||||
"exec"
|
||||
],
|
||||
"license": "MIT",
|
||||
"main": "lib/exec.js",
|
||||
"name": "@actions/exec",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/actions/toolkit.git",
|
||||
"directory": "packages/exec"
|
||||
},
|
||||
"scripts": {
|
||||
"audit-moderate": "npm install && npm audit --audit-level=moderate",
|
||||
"test": "echo \"Error: run tests from root\" && exit 1",
|
||||
"tsc": "tsc"
|
||||
},
|
||||
"types": "lib/exec.d.ts",
|
||||
"version": "1.0.4"
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
# `@actions/io`
|
||||
|
||||
> Core functions for cli filesystem scenarios
|
||||
|
||||
## Usage
|
||||
|
||||
#### mkdir -p
|
||||
|
||||
Recursively make a directory. Follows rules specified in [man mkdir](https://linux.die.net/man/1/mkdir) with the `-p` option specified:
|
||||
|
||||
```js
|
||||
const io = require('@actions/io');
|
||||
|
||||
await io.mkdirP('path/to/make');
|
||||
```
|
||||
|
||||
#### cp/mv
|
||||
|
||||
Copy or move files or folders. Follows rules specified in [man cp](https://linux.die.net/man/1/cp) and [man mv](https://linux.die.net/man/1/mv):
|
||||
|
||||
```js
|
||||
const io = require('@actions/io');
|
||||
|
||||
// Recursive must be true for directories
|
||||
const options = { recursive: true, force: false }
|
||||
|
||||
await io.cp('path/to/directory', 'path/to/dest', options);
|
||||
await io.mv('path/to/file', 'path/to/dest');
|
||||
```
|
||||
|
||||
#### rm -rf
|
||||
|
||||
Remove a file or folder recursively. Follows rules specified in [man rm](https://linux.die.net/man/1/rm) with the `-r` and `-f` rules specified.
|
||||
|
||||
```js
|
||||
const io = require('@actions/io');
|
||||
|
||||
await io.rmRF('path/to/directory');
|
||||
await io.rmRF('path/to/file');
|
||||
```
|
||||
|
||||
#### which
|
||||
|
||||
Get the path to a tool and resolves via paths. Follows the rules specified in [man which](https://linux.die.net/man/1/which).
|
||||
|
||||
```js
|
||||
const exec = require('@actions/exec');
|
||||
const io = require('@actions/io');
|
||||
|
||||
const pythonPath: string = await io.which('python', true)
|
||||
|
||||
await exec.exec(`"${pythonPath}"`, ['main.py']);
|
||||
```
|
|
@ -0,0 +1,29 @@
|
|||
/// <reference types="node" />
|
||||
import * as fs from 'fs';
|
||||
export declare const chmod: typeof fs.promises.chmod, copyFile: typeof fs.promises.copyFile, lstat: typeof fs.promises.lstat, mkdir: typeof fs.promises.mkdir, readdir: typeof fs.promises.readdir, readlink: typeof fs.promises.readlink, rename: typeof fs.promises.rename, rmdir: typeof fs.promises.rmdir, stat: typeof fs.promises.stat, symlink: typeof fs.promises.symlink, unlink: typeof fs.promises.unlink;
|
||||
export declare const IS_WINDOWS: boolean;
|
||||
export declare function exists(fsPath: string): Promise<boolean>;
|
||||
export declare function isDirectory(fsPath: string, useStat?: boolean): Promise<boolean>;
|
||||
/**
|
||||
* On OSX/Linux, true if path starts with '/'. On Windows, true for paths like:
|
||||
* \, \hello, \\hello\share, C:, and C:\hello (and corresponding alternate separator cases).
|
||||
*/
|
||||
export declare function isRooted(p: string): boolean;
|
||||
/**
|
||||
* Recursively create a directory at `fsPath`.
|
||||
*
|
||||
* This implementation is optimistic, meaning it attempts to create the full
|
||||
* path first, and backs up the path stack from there.
|
||||
*
|
||||
* @param fsPath The path to create
|
||||
* @param maxDepth The maximum recursion depth
|
||||
* @param depth The current recursion depth
|
||||
*/
|
||||
export declare function mkdirP(fsPath: string, maxDepth?: number, depth?: number): Promise<void>;
|
||||
/**
|
||||
* Best effort attempt to determine whether a file exists and is executable.
|
||||
* @param filePath file path to check
|
||||
* @param extensions additional file extensions to try
|
||||
* @return if file exists and is executable, returns the file path. otherwise empty string.
|
||||
*/
|
||||
export declare function tryGetExecutablePath(filePath: string, extensions: string[]): Promise<string>;
|
|
@ -0,0 +1,195 @@
|
|||
"use strict";
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
var _a;
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const assert_1 = require("assert");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
_a = fs.promises, exports.chmod = _a.chmod, exports.copyFile = _a.copyFile, exports.lstat = _a.lstat, exports.mkdir = _a.mkdir, exports.readdir = _a.readdir, exports.readlink = _a.readlink, exports.rename = _a.rename, exports.rmdir = _a.rmdir, exports.stat = _a.stat, exports.symlink = _a.symlink, exports.unlink = _a.unlink;
|
||||
exports.IS_WINDOWS = process.platform === 'win32';
|
||||
function exists(fsPath) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
try {
|
||||
yield exports.stat(fsPath);
|
||||
}
|
||||
catch (err) {
|
||||
if (err.code === 'ENOENT') {
|
||||
return false;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
exports.exists = exists;
|
||||
function isDirectory(fsPath, useStat = false) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const stats = useStat ? yield exports.stat(fsPath) : yield exports.lstat(fsPath);
|
||||
return stats.isDirectory();
|
||||
});
|
||||
}
|
||||
exports.isDirectory = isDirectory;
|
||||
/**
|
||||
* On OSX/Linux, true if path starts with '/'. On Windows, true for paths like:
|
||||
* \, \hello, \\hello\share, C:, and C:\hello (and corresponding alternate separator cases).
|
||||
*/
|
||||
function isRooted(p) {
|
||||
p = normalizeSeparators(p);
|
||||
if (!p) {
|
||||
throw new Error('isRooted() parameter "p" cannot be empty');
|
||||
}
|
||||
if (exports.IS_WINDOWS) {
|
||||
return (p.startsWith('\\') || /^[A-Z]:/i.test(p) // e.g. \ or \hello or \\hello
|
||||
); // e.g. C: or C:\hello
|
||||
}
|
||||
return p.startsWith('/');
|
||||
}
|
||||
exports.isRooted = isRooted;
|
||||
/**
|
||||
* Recursively create a directory at `fsPath`.
|
||||
*
|
||||
* This implementation is optimistic, meaning it attempts to create the full
|
||||
* path first, and backs up the path stack from there.
|
||||
*
|
||||
* @param fsPath The path to create
|
||||
* @param maxDepth The maximum recursion depth
|
||||
* @param depth The current recursion depth
|
||||
*/
|
||||
function mkdirP(fsPath, maxDepth = 1000, depth = 1) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
assert_1.ok(fsPath, 'a path argument must be provided');
|
||||
fsPath = path.resolve(fsPath);
|
||||
if (depth >= maxDepth)
|
||||
return exports.mkdir(fsPath);
|
||||
try {
|
||||
yield exports.mkdir(fsPath);
|
||||
return;
|
||||
}
|
||||
catch (err) {
|
||||
switch (err.code) {
|
||||
case 'ENOENT': {
|
||||
yield mkdirP(path.dirname(fsPath), maxDepth, depth + 1);
|
||||
yield exports.mkdir(fsPath);
|
||||
return;
|
||||
}
|
||||
default: {
|
||||
let stats;
|
||||
try {
|
||||
stats = yield exports.stat(fsPath);
|
||||
}
|
||||
catch (err2) {
|
||||
throw err;
|
||||
}
|
||||
if (!stats.isDirectory())
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
exports.mkdirP = mkdirP;
|
||||
/**
|
||||
* Best effort attempt to determine whether a file exists and is executable.
|
||||
* @param filePath file path to check
|
||||
* @param extensions additional file extensions to try
|
||||
* @return if file exists and is executable, returns the file path. otherwise empty string.
|
||||
*/
|
||||
function tryGetExecutablePath(filePath, extensions) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let stats = undefined;
|
||||
try {
|
||||
// test file exists
|
||||
stats = yield exports.stat(filePath);
|
||||
}
|
||||
catch (err) {
|
||||
if (err.code !== 'ENOENT') {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`Unexpected error attempting to determine if executable file exists '${filePath}': ${err}`);
|
||||
}
|
||||
}
|
||||
if (stats && stats.isFile()) {
|
||||
if (exports.IS_WINDOWS) {
|
||||
// on Windows, test for valid extension
|
||||
const upperExt = path.extname(filePath).toUpperCase();
|
||||
if (extensions.some(validExt => validExt.toUpperCase() === upperExt)) {
|
||||
return filePath;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (isUnixExecutable(stats)) {
|
||||
return filePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
// try each extension
|
||||
const originalFilePath = filePath;
|
||||
for (const extension of extensions) {
|
||||
filePath = originalFilePath + extension;
|
||||
stats = undefined;
|
||||
try {
|
||||
stats = yield exports.stat(filePath);
|
||||
}
|
||||
catch (err) {
|
||||
if (err.code !== 'ENOENT') {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`Unexpected error attempting to determine if executable file exists '${filePath}': ${err}`);
|
||||
}
|
||||
}
|
||||
if (stats && stats.isFile()) {
|
||||
if (exports.IS_WINDOWS) {
|
||||
// preserve the case of the actual file (since an extension was appended)
|
||||
try {
|
||||
const directory = path.dirname(filePath);
|
||||
const upperName = path.basename(filePath).toUpperCase();
|
||||
for (const actualName of yield exports.readdir(directory)) {
|
||||
if (upperName === actualName.toUpperCase()) {
|
||||
filePath = path.join(directory, actualName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`Unexpected error attempting to determine the actual case of the file '${filePath}': ${err}`);
|
||||
}
|
||||
return filePath;
|
||||
}
|
||||
else {
|
||||
if (isUnixExecutable(stats)) {
|
||||
return filePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return '';
|
||||
});
|
||||
}
|
||||
exports.tryGetExecutablePath = tryGetExecutablePath;
|
||||
function normalizeSeparators(p) {
|
||||
p = p || '';
|
||||
if (exports.IS_WINDOWS) {
|
||||
// convert slashes on Windows
|
||||
p = p.replace(/\//g, '\\');
|
||||
// remove redundant slashes
|
||||
return p.replace(/\\\\+/g, '\\');
|
||||
}
|
||||
// remove redundant slashes
|
||||
return p.replace(/\/\/+/g, '/');
|
||||
}
|
||||
// on Mac/Linux, test the execute bit
|
||||
// R W X R W X R W X
|
||||
// 256 128 64 32 16 8 4 2 1
|
||||
function isUnixExecutable(stats) {
|
||||
return ((stats.mode & 1) > 0 ||
|
||||
((stats.mode & 8) > 0 && stats.gid === process.getgid()) ||
|
||||
((stats.mode & 64) > 0 && stats.uid === process.getuid()));
|
||||
}
|
||||
//# sourceMappingURL=io-util.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"io-util.js","sourceRoot":"","sources":["../src/io-util.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,mCAAyB;AACzB,yBAAwB;AACxB,6BAA4B;AAEf,gBAYE,qTAAA;AAEF,QAAA,UAAU,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAA;AAEtD,SAAsB,MAAM,CAAC,MAAc;;QACzC,IAAI;YACF,MAAM,YAAI,CAAC,MAAM,CAAC,CAAA;SACnB;QAAC,OAAO,GAAG,EAAE;YACZ,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE;gBACzB,OAAO,KAAK,CAAA;aACb;YAED,MAAM,GAAG,CAAA;SACV;QAED,OAAO,IAAI,CAAA;IACb,CAAC;CAAA;AAZD,wBAYC;AAED,SAAsB,WAAW,CAC/B,MAAc,EACd,UAAmB,KAAK;;QAExB,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,YAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,aAAK,CAAC,MAAM,CAAC,CAAA;QAChE,OAAO,KAAK,CAAC,WAAW,EAAE,CAAA;IAC5B,CAAC;CAAA;AAND,kCAMC;AAED;;;GAGG;AACH,SAAgB,QAAQ,CAAC,CAAS;IAChC,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC,CAAA;IAC1B,IAAI,CAAC,CAAC,EAAE;QACN,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAA;KAC5D;IAED,IAAI,kBAAU,EAAE;QACd,OAAO,CACL,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,8BAA8B;SACxE,CAAA,CAAC,sBAAsB;KACzB;IAED,OAAO,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;AAC1B,CAAC;AAbD,4BAaC;AAED;;;;;;;;;GASG;AACH,SAAsB,MAAM,CAC1B,MAAc,EACd,WAAmB,IAAI,EACvB,QAAgB,CAAC;;QAEjB,WAAE,CAAC,MAAM,EAAE,kCAAkC,CAAC,CAAA;QAE9C,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;QAE7B,IAAI,KAAK,IAAI,QAAQ;YAAE,OAAO,aAAK,CAAC,MAAM,CAAC,CAAA;QAE3C,IAAI;YACF,MAAM,aAAK,CAAC,MAAM,CAAC,CAAA;YACnB,OAAM;SACP;QAAC,OAAO,GAAG,EAAE;YACZ,QAAQ,GAAG,CAAC,IAAI,EAAE;gBAChB,KAAK,QAAQ,CAAC,CAAC;oBACb,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,KAAK,GAAG,CAAC,CAAC,CAAA;oBACvD,MAAM,aAAK,CAAC,MAAM,CAAC,CAAA;oBACnB,OAAM;iBACP;gBACD,OAAO,CAAC,CAAC;oBACP,IAAI,KAAe,CAAA;oBAEnB,IAAI;wBACF,KAAK,GAAG,MAAM,YAAI,CAAC,MAAM,CAAC,CAAA;qBAC3B;oBAAC,OAAO,IAAI,EAAE;wBACb,MAAM,GAAG,CAAA;qBACV;oBAED,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;wBAAE,MAAM,GAAG,CAAA;iBACpC;aACF;SACF;IACH,CAAC;CAAA;AAlCD,wBAkCC;AAED;;;;;GAKG;AACH,SAAsB,oBAAoB,CACxC,QAAgB,EAChB,UAAoB;;QAEpB,IAAI,KAAK,GAAyB,SAAS,CAAA;QAC3C,IAAI;YACF,mBAAmB;YACnB,KAAK,GAAG,MAAM,YAAI,CAAC,QAAQ,CAAC,CAAA;SAC7B;QAAC,OAAO,GAAG,EAAE;YACZ,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE;gBACzB,sCAAsC;gBACtC,OAAO,CAAC,GAAG,CACT,uEAAuE,QAAQ,MAAM,GAAG,EAAE,CAC3F,CAAA;aACF;SACF;QACD,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE;YAC3B,IAAI,kBAAU,EAAE;gBACd,uCAAuC;gBACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAA;gBACrD,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,QAAQ,CAAC,EAAE;oBACpE,OAAO,QAAQ,CAAA;iBAChB;aACF;iBAAM;gBACL,IAAI,gBAAgB,CAAC,KAAK,CAAC,EAAE;oBAC3B,OAAO,QAAQ,CAAA;iBAChB;aACF;SACF;QAED,qBAAqB;QACrB,MAAM,gBAAgB,GAAG,QAAQ,CAAA;QACjC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE;YAClC,QAAQ,GAAG,gBAAgB,GAAG,SAAS,CAAA;YAEvC,KAAK,GAAG,SAAS,CAAA;YACjB,IAAI;gBACF,KAAK,GAAG,MAAM,YAAI,CAAC,QAAQ,CAAC,CAAA;aAC7B;YAAC,OAAO,GAAG,EAAE;gBACZ,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE;oBACzB,sCAAsC;oBACtC,OAAO,CAAC,GAAG,CACT,uEAAuE,QAAQ,MAAM,GAAG,EAAE,CAC3F,CAAA;iBACF;aACF;YAED,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE;gBAC3B,IAAI,kBAAU,EAAE;oBACd,yEAAyE;oBACzE,IAAI;wBACF,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;wBACxC,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAA;wBACvD,KAAK,MAAM,UAAU,IAAI,MAAM,eAAO,CAAC,SAAS,CAAC,EAAE;4BACjD,IAAI,SAAS,KAAK,UAAU,CAAC,WAAW,EAAE,EAAE;gCAC1C,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAA;gCAC3C,MAAK;6BACN;yBACF;qBACF;oBAAC,OAAO,GAAG,EAAE;wBACZ,sCAAsC;wBACtC,OAAO,CAAC,GAAG,CACT,yEAAyE,QAAQ,MAAM,GAAG,EAAE,CAC7F,CAAA;qBACF;oBAED,OAAO,QAAQ,CAAA;iBAChB;qBAAM;oBACL,IAAI,gBAAgB,CAAC,KAAK,CAAC,EAAE;wBAC3B,OAAO,QAAQ,CAAA;qBAChB;iBACF;aACF;SACF;QAED,OAAO,EAAE,CAAA;IACX,CAAC;CAAA;AA5ED,oDA4EC;AAED,SAAS,mBAAmB,CAAC,CAAS;IACpC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAA;IACX,IAAI,kBAAU,EAAE;QACd,6BAA6B;QAC7B,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;QAE1B,2BAA2B;QAC3B,OAAO,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;KACjC;IAED,2BAA2B;IAC3B,OAAO,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;AACjC,CAAC;AAED,qCAAqC;AACrC,6BAA6B;AAC7B,6BAA6B;AAC7B,SAAS,gBAAgB,CAAC,KAAe;IACvC,OAAO,CACL,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC;QACpB,CAAC,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC;QACxD,CAAC,CAAC,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAC1D,CAAA;AACH,CAAC"}
|
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
* Interface for cp/mv options
|
||||
*/
|
||||
export interface CopyOptions {
|
||||
/** Optional. Whether to recursively copy all subdirectories. Defaults to false */
|
||||
recursive?: boolean;
|
||||
/** Optional. Whether to overwrite existing files in the destination. Defaults to true */
|
||||
force?: boolean;
|
||||
}
|
||||
/**
|
||||
* Interface for cp/mv options
|
||||
*/
|
||||
export interface MoveOptions {
|
||||
/** Optional. Whether to overwrite existing files in the destination. Defaults to true */
|
||||
force?: boolean;
|
||||
}
|
||||
/**
|
||||
* Copies a file or folder.
|
||||
* Based off of shelljs - https://github.com/shelljs/shelljs/blob/9237f66c52e5daa40458f94f9565e18e8132f5a6/src/cp.js
|
||||
*
|
||||
* @param source source path
|
||||
* @param dest destination path
|
||||
* @param options optional. See CopyOptions.
|
||||
*/
|
||||
export declare function cp(source: string, dest: string, options?: CopyOptions): Promise<void>;
|
||||
/**
|
||||
* Moves a path.
|
||||
*
|
||||
* @param source source path
|
||||
* @param dest destination path
|
||||
* @param options optional. See MoveOptions.
|
||||
*/
|
||||
export declare function mv(source: string, dest: string, options?: MoveOptions): Promise<void>;
|
||||
/**
|
||||
* Remove a path recursively with force
|
||||
*
|
||||
* @param inputPath path to remove
|
||||
*/
|
||||
export declare function rmRF(inputPath: string): Promise<void>;
|
||||
/**
|
||||
* Make a directory. Creates the full path with folders in between
|
||||
* Will throw if it fails
|
||||
*
|
||||
* @param fsPath path to create
|
||||
* @returns Promise<void>
|
||||
*/
|
||||
export declare function mkdirP(fsPath: string): Promise<void>;
|
||||
/**
|
||||
* Returns path of a tool had the tool actually been invoked. Resolves via paths.
|
||||
* If you check and the tool does not exist, it will throw.
|
||||
*
|
||||
* @param tool name of the tool
|
||||
* @param check whether to check if tool exists
|
||||
* @returns Promise<string> path to tool
|
||||
*/
|
||||
export declare function which(tool: string, check?: boolean): Promise<string>;
|
|
@ -0,0 +1,290 @@
|
|||
"use strict";
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const childProcess = require("child_process");
|
||||
const path = require("path");
|
||||
const util_1 = require("util");
|
||||
const ioUtil = require("./io-util");
|
||||
const exec = util_1.promisify(childProcess.exec);
|
||||
/**
|
||||
* Copies a file or folder.
|
||||
* Based off of shelljs - https://github.com/shelljs/shelljs/blob/9237f66c52e5daa40458f94f9565e18e8132f5a6/src/cp.js
|
||||
*
|
||||
* @param source source path
|
||||
* @param dest destination path
|
||||
* @param options optional. See CopyOptions.
|
||||
*/
|
||||
function cp(source, dest, options = {}) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const { force, recursive } = readCopyOptions(options);
|
||||
const destStat = (yield ioUtil.exists(dest)) ? yield ioUtil.stat(dest) : null;
|
||||
// Dest is an existing file, but not forcing
|
||||
if (destStat && destStat.isFile() && !force) {
|
||||
return;
|
||||
}
|
||||
// If dest is an existing directory, should copy inside.
|
||||
const newDest = destStat && destStat.isDirectory()
|
||||
? path.join(dest, path.basename(source))
|
||||
: dest;
|
||||
if (!(yield ioUtil.exists(source))) {
|
||||
throw new Error(`no such file or directory: ${source}`);
|
||||
}
|
||||
const sourceStat = yield ioUtil.stat(source);
|
||||
if (sourceStat.isDirectory()) {
|
||||
if (!recursive) {
|
||||
throw new Error(`Failed to copy. ${source} is a directory, but tried to copy without recursive flag.`);
|
||||
}
|
||||
else {
|
||||
yield cpDirRecursive(source, newDest, 0, force);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (path.relative(source, newDest) === '') {
|
||||
// a file cannot be copied to itself
|
||||
throw new Error(`'${newDest}' and '${source}' are the same file`);
|
||||
}
|
||||
yield copyFile(source, newDest, force);
|
||||
}
|
||||
});
|
||||
}
|
||||
exports.cp = cp;
|
||||
/**
|
||||
* Moves a path.
|
||||
*
|
||||
* @param source source path
|
||||
* @param dest destination path
|
||||
* @param options optional. See MoveOptions.
|
||||
*/
|
||||
function mv(source, dest, options = {}) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (yield ioUtil.exists(dest)) {
|
||||
let destExists = true;
|
||||
if (yield ioUtil.isDirectory(dest)) {
|
||||
// If dest is directory copy src into dest
|
||||
dest = path.join(dest, path.basename(source));
|
||||
destExists = yield ioUtil.exists(dest);
|
||||
}
|
||||
if (destExists) {
|
||||
if (options.force == null || options.force) {
|
||||
yield rmRF(dest);
|
||||
}
|
||||
else {
|
||||
throw new Error('Destination already exists');
|
||||
}
|
||||
}
|
||||
}
|
||||
yield mkdirP(path.dirname(dest));
|
||||
yield ioUtil.rename(source, dest);
|
||||
});
|
||||
}
|
||||
exports.mv = mv;
|
||||
/**
|
||||
* Remove a path recursively with force
|
||||
*
|
||||
* @param inputPath path to remove
|
||||
*/
|
||||
function rmRF(inputPath) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (ioUtil.IS_WINDOWS) {
|
||||
// Node doesn't provide a delete operation, only an unlink function. This means that if the file is being used by another
|
||||
// program (e.g. antivirus), it won't be deleted. To address this, we shell out the work to rd/del.
|
||||
try {
|
||||
if (yield ioUtil.isDirectory(inputPath, true)) {
|
||||
yield exec(`rd /s /q "${inputPath}"`);
|
||||
}
|
||||
else {
|
||||
yield exec(`del /f /a "${inputPath}"`);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
// if you try to delete a file that doesn't exist, desired result is achieved
|
||||
// other errors are valid
|
||||
if (err.code !== 'ENOENT')
|
||||
throw err;
|
||||
}
|
||||
// Shelling out fails to remove a symlink folder with missing source, this unlink catches that
|
||||
try {
|
||||
yield ioUtil.unlink(inputPath);
|
||||
}
|
||||
catch (err) {
|
||||
// if you try to delete a file that doesn't exist, desired result is achieved
|
||||
// other errors are valid
|
||||
if (err.code !== 'ENOENT')
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
else {
|
||||
let isDir = false;
|
||||
try {
|
||||
isDir = yield ioUtil.isDirectory(inputPath);
|
||||
}
|
||||
catch (err) {
|
||||
// if you try to delete a file that doesn't exist, desired result is achieved
|
||||
// other errors are valid
|
||||
if (err.code !== 'ENOENT')
|
||||
throw err;
|
||||
return;
|
||||
}
|
||||
if (isDir) {
|
||||
yield exec(`rm -rf "${inputPath}"`);
|
||||
}
|
||||
else {
|
||||
yield ioUtil.unlink(inputPath);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
exports.rmRF = rmRF;
|
||||
/**
|
||||
* Make a directory. Creates the full path with folders in between
|
||||
* Will throw if it fails
|
||||
*
|
||||
* @param fsPath path to create
|
||||
* @returns Promise<void>
|
||||
*/
|
||||
function mkdirP(fsPath) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
yield ioUtil.mkdirP(fsPath);
|
||||
});
|
||||
}
|
||||
exports.mkdirP = mkdirP;
|
||||
/**
|
||||
* Returns path of a tool had the tool actually been invoked. Resolves via paths.
|
||||
* If you check and the tool does not exist, it will throw.
|
||||
*
|
||||
* @param tool name of the tool
|
||||
* @param check whether to check if tool exists
|
||||
* @returns Promise<string> path to tool
|
||||
*/
|
||||
function which(tool, check) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (!tool) {
|
||||
throw new Error("parameter 'tool' is required");
|
||||
}
|
||||
// recursive when check=true
|
||||
if (check) {
|
||||
const result = yield which(tool, false);
|
||||
if (!result) {
|
||||
if (ioUtil.IS_WINDOWS) {
|
||||
throw new Error(`Unable to locate executable file: ${tool}. Please verify either the file path exists or the file can be found within a directory specified by the PATH environment variable. Also verify the file has a valid extension for an executable file.`);
|
||||
}
|
||||
else {
|
||||
throw new Error(`Unable to locate executable file: ${tool}. Please verify either the file path exists or the file can be found within a directory specified by the PATH environment variable. Also check the file mode to verify the file is executable.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
// build the list of extensions to try
|
||||
const extensions = [];
|
||||
if (ioUtil.IS_WINDOWS && process.env.PATHEXT) {
|
||||
for (const extension of process.env.PATHEXT.split(path.delimiter)) {
|
||||
if (extension) {
|
||||
extensions.push(extension);
|
||||
}
|
||||
}
|
||||
}
|
||||
// if it's rooted, return it if exists. otherwise return empty.
|
||||
if (ioUtil.isRooted(tool)) {
|
||||
const filePath = yield ioUtil.tryGetExecutablePath(tool, extensions);
|
||||
if (filePath) {
|
||||
return filePath;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
// if any path separators, return empty
|
||||
if (tool.includes('/') || (ioUtil.IS_WINDOWS && tool.includes('\\'))) {
|
||||
return '';
|
||||
}
|
||||
// build the list of directories
|
||||
//
|
||||
// Note, technically "where" checks the current directory on Windows. From a toolkit perspective,
|
||||
// it feels like we should not do this. Checking the current directory seems like more of a use
|
||||
// case of a shell, and the which() function exposed by the toolkit should strive for consistency
|
||||
// across platforms.
|
||||
const directories = [];
|
||||
if (process.env.PATH) {
|
||||
for (const p of process.env.PATH.split(path.delimiter)) {
|
||||
if (p) {
|
||||
directories.push(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
// return the first match
|
||||
for (const directory of directories) {
|
||||
const filePath = yield ioUtil.tryGetExecutablePath(directory + path.sep + tool, extensions);
|
||||
if (filePath) {
|
||||
return filePath;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
catch (err) {
|
||||
throw new Error(`which failed with message ${err.message}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
exports.which = which;
|
||||
function readCopyOptions(options) {
|
||||
const force = options.force == null ? true : options.force;
|
||||
const recursive = Boolean(options.recursive);
|
||||
return { force, recursive };
|
||||
}
|
||||
function cpDirRecursive(sourceDir, destDir, currentDepth, force) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
// Ensure there is not a run away recursive copy
|
||||
if (currentDepth >= 255)
|
||||
return;
|
||||
currentDepth++;
|
||||
yield mkdirP(destDir);
|
||||
const files = yield ioUtil.readdir(sourceDir);
|
||||
for (const fileName of files) {
|
||||
const srcFile = `${sourceDir}/${fileName}`;
|
||||
const destFile = `${destDir}/${fileName}`;
|
||||
const srcFileStat = yield ioUtil.lstat(srcFile);
|
||||
if (srcFileStat.isDirectory()) {
|
||||
// Recurse
|
||||
yield cpDirRecursive(srcFile, destFile, currentDepth, force);
|
||||
}
|
||||
else {
|
||||
yield copyFile(srcFile, destFile, force);
|
||||
}
|
||||
}
|
||||
// Change the mode for the newly created directory
|
||||
yield ioUtil.chmod(destDir, (yield ioUtil.stat(sourceDir)).mode);
|
||||
});
|
||||
}
|
||||
// Buffered file copy
|
||||
function copyFile(srcFile, destFile, force) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if ((yield ioUtil.lstat(srcFile)).isSymbolicLink()) {
|
||||
// unlink/re-link it
|
||||
try {
|
||||
yield ioUtil.lstat(destFile);
|
||||
yield ioUtil.unlink(destFile);
|
||||
}
|
||||
catch (e) {
|
||||
// Try to override file permission
|
||||
if (e.code === 'EPERM') {
|
||||
yield ioUtil.chmod(destFile, '0666');
|
||||
yield ioUtil.unlink(destFile);
|
||||
}
|
||||
// other errors = it doesn't exist, no work to do
|
||||
}
|
||||
// Copy over symlink
|
||||
const symlinkFull = yield ioUtil.readlink(srcFile);
|
||||
yield ioUtil.symlink(symlinkFull, destFile, ioUtil.IS_WINDOWS ? 'junction' : null);
|
||||
}
|
||||
else if (!(yield ioUtil.exists(destFile)) || force) {
|
||||
yield ioUtil.copyFile(srcFile, destFile);
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=io.js.map
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -0,0 +1,66 @@
|
|||
{
|
||||
"_args": [
|
||||
[
|
||||
"@actions/io@1.0.2",
|
||||
"D:\\Repos\\security-code-analysis-action"
|
||||
]
|
||||
],
|
||||
"_from": "@actions/io@1.0.2",
|
||||
"_id": "@actions/io@1.0.2",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-J8KuFqVPr3p6U8W93DOXlXW6zFvrQAJANdS+vw0YhusLIq+bszW8zmK2Fh1C2kDPX8FMvwIl1OUcFgvJoXLbAg==",
|
||||
"_location": "/@actions/io",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "version",
|
||||
"registry": true,
|
||||
"raw": "@actions/io@1.0.2",
|
||||
"name": "@actions/io",
|
||||
"escapedName": "@actions%2fio",
|
||||
"scope": "@actions",
|
||||
"rawSpec": "1.0.2",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "1.0.2"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/@actions/exec"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/@actions/io/-/io-1.0.2.tgz",
|
||||
"_spec": "1.0.2",
|
||||
"_where": "D:\\Repos\\security-code-analysis-action",
|
||||
"bugs": {
|
||||
"url": "https://github.com/actions/toolkit/issues"
|
||||
},
|
||||
"description": "Actions io lib",
|
||||
"directories": {
|
||||
"lib": "lib",
|
||||
"test": "__tests__"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"homepage": "https://github.com/actions/toolkit/tree/master/packages/io",
|
||||
"keywords": [
|
||||
"github",
|
||||
"actions",
|
||||
"io"
|
||||
],
|
||||
"license": "MIT",
|
||||
"main": "lib/io.js",
|
||||
"name": "@actions/io",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/actions/toolkit.git",
|
||||
"directory": "packages/io"
|
||||
},
|
||||
"scripts": {
|
||||
"audit-moderate": "npm install && npm audit --audit-level=moderate",
|
||||
"test": "echo \"Error: run tests from root\" && exit 1",
|
||||
"tsc": "tsc"
|
||||
},
|
||||
"types": "lib/io.d.ts",
|
||||
"version": "1.0.2"
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
1.0.10 / 2018-02-15
|
||||
------------------
|
||||
|
||||
- Use .concat instead of + for arrays, #122.
|
||||
|
||||
|
||||
1.0.9 / 2016-09-29
|
||||
------------------
|
||||
|
||||
- Rerelease after 1.0.8 - deps cleanup.
|
||||
|
||||
|
||||
1.0.8 / 2016-09-29
|
||||
------------------
|
||||
|
||||
- Maintenance (deps bump, fix node 6.5+ tests, coverage report).
|
||||
|
||||
|
||||
1.0.7 / 2016-03-17
|
||||
------------------
|
||||
|
||||
- Teach `addArgument` to accept string arg names. #97, @tomxtobin.
|
||||
|
||||
|
||||
1.0.6 / 2016-02-06
|
||||
------------------
|
||||
|
||||
- Maintenance: moved to eslint & updated CS.
|
||||
|
||||
|
||||
1.0.5 / 2016-02-05
|
||||
------------------
|
||||
|
||||
- Removed lodash dependency to significantly reduce install size.
|
||||
Thanks to @mourner.
|
||||
|
||||
|
||||
1.0.4 / 2016-01-17
|
||||
------------------
|
||||
|
||||
- Maintenance: lodash update to 4.0.0.
|
||||
|
||||
|
||||
1.0.3 / 2015-10-27
|
||||
------------------
|
||||
|
||||
- Fix parse `=` in args: `--examplepath="C:\myfolder\env=x64"`. #84, @CatWithApple.
|
||||
|
||||
|
||||
1.0.2 / 2015-03-22
|
||||
------------------
|
||||
|
||||
- Relaxed lodash version dependency.
|
||||
|
||||
|
||||
1.0.1 / 2015-02-20
|
||||
------------------
|
||||
|
||||
- Changed dependencies to be compatible with ancient nodejs.
|
||||
|
||||
|
||||
1.0.0 / 2015-02-19
|
||||
------------------
|
||||
|
||||
- Maintenance release.
|
||||
- Replaced `underscore` with `lodash`.
|
||||
- Bumped version to 1.0.0 to better reflect semver meaning.
|
||||
- HISTORY.md -> CHANGELOG.md
|
||||
|
||||
|
||||
0.1.16 / 2013-12-01
|
||||
-------------------
|
||||
|
||||
- Maintenance release. Updated dependencies and docs.
|
||||
|
||||
|
||||
0.1.15 / 2013-05-13
|
||||
-------------------
|
||||
|
||||
- Fixed #55, @trebor89
|
||||
|
||||
|
||||
0.1.14 / 2013-05-12
|
||||
-------------------
|
||||
|
||||
- Fixed #62, @maxtaco
|
||||
|
||||
|
||||
0.1.13 / 2013-04-08
|
||||
-------------------
|
||||
|
||||
- Added `.npmignore` to reduce package size
|
||||
|
||||
|
||||
0.1.12 / 2013-02-10
|
||||
-------------------
|
||||
|
||||
- Fixed conflictHandler (#46), @hpaulj
|
||||
|
||||
|
||||
0.1.11 / 2013-02-07
|
||||
-------------------
|
||||
|
||||
- Multiple bugfixes, @hpaulj
|
||||
- Added 70+ tests (ported from python), @hpaulj
|
||||
- Added conflictHandler, @applepicke
|
||||
- Added fromfilePrefixChar, @hpaulj
|
||||
|
||||
|
||||
0.1.10 / 2012-12-30
|
||||
-------------------
|
||||
|
||||
- Added [mutual exclusion](http://docs.python.org/dev/library/argparse.html#mutual-exclusion)
|
||||
support, thanks to @hpaulj
|
||||
- Fixed options check for `storeConst` & `appendConst` actions, thanks to @hpaulj
|
||||
|
||||
|
||||
0.1.9 / 2012-12-27
|
||||
------------------
|
||||
|
||||
- Fixed option dest interferens with other options (issue #23), thanks to @hpaulj
|
||||
- Fixed default value behavior with `*` positionals, thanks to @hpaulj
|
||||
- Improve `getDefault()` behavior, thanks to @hpaulj
|
||||
- Imrove negative argument parsing, thanks to @hpaulj
|
||||
|
||||
|
||||
0.1.8 / 2012-12-01
|
||||
------------------
|
||||
|
||||
- Fixed parser parents (issue #19), thanks to @hpaulj
|
||||
- Fixed negative argument parse (issue #20), thanks to @hpaulj
|
||||
|
||||
|
||||
0.1.7 / 2012-10-14
|
||||
------------------
|
||||
|
||||
- Fixed 'choices' argument parse (issue #16)
|
||||
- Fixed stderr output (issue #15)
|
||||
|
||||
|
||||
0.1.6 / 2012-09-09
|
||||
------------------
|
||||
|
||||
- Fixed check for conflict of options (thanks to @tomxtobin)
|
||||
|
||||
|
||||
0.1.5 / 2012-09-03
|
||||
------------------
|
||||
|
||||
- Fix parser #setDefaults method (thanks to @tomxtobin)
|
||||
|
||||
|
||||
0.1.4 / 2012-07-30
|
||||
------------------
|
||||
|
||||
- Fixed pseudo-argument support (thanks to @CGamesPlay)
|
||||
- Fixed addHelp default (should be true), if not set (thanks to @benblank)
|
||||
|
||||
|
||||
0.1.3 / 2012-06-27
|
||||
------------------
|
||||
|
||||
- Fixed formatter api name: Formatter -> HelpFormatter
|
||||
|
||||
|
||||
0.1.2 / 2012-05-29
|
||||
------------------
|
||||
|
||||
- Added basic tests
|
||||
- Removed excess whitespace in help
|
||||
- Fixed error reporting, when parcer with subcommands
|
||||
called with empty arguments
|
||||
|
||||
|
||||
0.1.1 / 2012-05-23
|
||||
------------------
|
||||
|
||||
- Fixed line wrapping in help formatter
|
||||
- Added better error reporting on invalid arguments
|
||||
|
||||
|
||||
0.1.0 / 2012-05-16
|
||||
------------------
|
||||
|
||||
- First release.
|
|
@ -0,0 +1,21 @@
|
|||
(The MIT License)
|
||||
|
||||
Copyright (C) 2012 by Vitaly Puzrin
|
||||
|
||||
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.
|
|
@ -0,0 +1,257 @@
|
|||
argparse
|
||||
========
|
||||
|
||||
[![Build Status](https://secure.travis-ci.org/nodeca/argparse.svg?branch=master)](http://travis-ci.org/nodeca/argparse)
|
||||
[![NPM version](https://img.shields.io/npm/v/argparse.svg)](https://www.npmjs.org/package/argparse)
|
||||
|
||||
CLI arguments parser for node.js. Javascript port of python's
|
||||
[argparse](http://docs.python.org/dev/library/argparse.html) module
|
||||
(original version 3.2). That's a full port, except some very rare options,
|
||||
recorded in issue tracker.
|
||||
|
||||
**NB. Difference with original.**
|
||||
|
||||
- Method names changed to camelCase. See [generated docs](http://nodeca.github.com/argparse/).
|
||||
- Use `defaultValue` instead of `default`.
|
||||
- Use `argparse.Const.REMAINDER` instead of `argparse.REMAINDER`, and
|
||||
similarly for constant values `OPTIONAL`, `ZERO_OR_MORE`, and `ONE_OR_MORE`
|
||||
(aliases for `nargs` values `'?'`, `'*'`, `'+'`, respectively), and
|
||||
`SUPPRESS`.
|
||||
|
||||
|
||||
Example
|
||||
=======
|
||||
|
||||
test.js file:
|
||||
|
||||
```javascript
|
||||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
var ArgumentParser = require('../lib/argparse').ArgumentParser;
|
||||
var parser = new ArgumentParser({
|
||||
version: '0.0.1',
|
||||
addHelp:true,
|
||||
description: 'Argparse example'
|
||||
});
|
||||
parser.addArgument(
|
||||
[ '-f', '--foo' ],
|
||||
{
|
||||
help: 'foo bar'
|
||||
}
|
||||
);
|
||||
parser.addArgument(
|
||||
[ '-b', '--bar' ],
|
||||
{
|
||||
help: 'bar foo'
|
||||
}
|
||||
);
|
||||
parser.addArgument(
|
||||
'--baz',
|
||||
{
|
||||
help: 'baz bar'
|
||||
}
|
||||
);
|
||||
var args = parser.parseArgs();
|
||||
console.dir(args);
|
||||
```
|
||||
|
||||
Display help:
|
||||
|
||||
```
|
||||
$ ./test.js -h
|
||||
usage: example.js [-h] [-v] [-f FOO] [-b BAR] [--baz BAZ]
|
||||
|
||||
Argparse example
|
||||
|
||||
Optional arguments:
|
||||
-h, --help Show this help message and exit.
|
||||
-v, --version Show program's version number and exit.
|
||||
-f FOO, --foo FOO foo bar
|
||||
-b BAR, --bar BAR bar foo
|
||||
--baz BAZ baz bar
|
||||
```
|
||||
|
||||
Parse arguments:
|
||||
|
||||
```
|
||||
$ ./test.js -f=3 --bar=4 --baz 5
|
||||
{ foo: '3', bar: '4', baz: '5' }
|
||||
```
|
||||
|
||||
More [examples](https://github.com/nodeca/argparse/tree/master/examples).
|
||||
|
||||
|
||||
ArgumentParser objects
|
||||
======================
|
||||
|
||||
```
|
||||
new ArgumentParser({parameters hash});
|
||||
```
|
||||
|
||||
Creates a new ArgumentParser object.
|
||||
|
||||
**Supported params:**
|
||||
|
||||
- ```description``` - Text to display before the argument help.
|
||||
- ```epilog``` - Text to display after the argument help.
|
||||
- ```addHelp``` - Add a -h/–help option to the parser. (default: true)
|
||||
- ```argumentDefault``` - Set the global default value for arguments. (default: null)
|
||||
- ```parents``` - A list of ArgumentParser objects whose arguments should also be included.
|
||||
- ```prefixChars``` - The set of characters that prefix optional arguments. (default: ‘-‘)
|
||||
- ```formatterClass``` - A class for customizing the help output.
|
||||
- ```prog``` - The name of the program (default: `path.basename(process.argv[1])`)
|
||||
- ```usage``` - The string describing the program usage (default: generated)
|
||||
- ```conflictHandler``` - Usually unnecessary, defines strategy for resolving conflicting optionals.
|
||||
|
||||
**Not supported yet**
|
||||
|
||||
- ```fromfilePrefixChars``` - The set of characters that prefix files from which additional arguments should be read.
|
||||
|
||||
|
||||
Details in [original ArgumentParser guide](http://docs.python.org/dev/library/argparse.html#argumentparser-objects)
|
||||
|
||||
|
||||
addArgument() method
|
||||
====================
|
||||
|
||||
```
|
||||
ArgumentParser.addArgument(name or flag or [name] or [flags...], {options})
|
||||
```
|
||||
|
||||
Defines how a single command-line argument should be parsed.
|
||||
|
||||
- ```name or flag or [name] or [flags...]``` - Either a positional name
|
||||
(e.g., `'foo'`), a single option (e.g., `'-f'` or `'--foo'`), an array
|
||||
of a single positional name (e.g., `['foo']`), or an array of options
|
||||
(e.g., `['-f', '--foo']`).
|
||||
|
||||
Options:
|
||||
|
||||
- ```action``` - The basic type of action to be taken when this argument is encountered at the command line.
|
||||
- ```nargs```- The number of command-line arguments that should be consumed.
|
||||
- ```constant``` - A constant value required by some action and nargs selections.
|
||||
- ```defaultValue``` - The value produced if the argument is absent from the command line.
|
||||
- ```type``` - The type to which the command-line argument should be converted.
|
||||
- ```choices``` - A container of the allowable values for the argument.
|
||||
- ```required``` - Whether or not the command-line option may be omitted (optionals only).
|
||||
- ```help``` - A brief description of what the argument does.
|
||||
- ```metavar``` - A name for the argument in usage messages.
|
||||
- ```dest``` - The name of the attribute to be added to the object returned by parseArgs().
|
||||
|
||||
Details in [original add_argument guide](http://docs.python.org/dev/library/argparse.html#the-add-argument-method)
|
||||
|
||||
|
||||
Action (some details)
|
||||
================
|
||||
|
||||
ArgumentParser objects associate command-line arguments with actions.
|
||||
These actions can do just about anything with the command-line arguments associated
|
||||
with them, though most actions simply add an attribute to the object returned by
|
||||
parseArgs(). The action keyword argument specifies how the command-line arguments
|
||||
should be handled. The supported actions are:
|
||||
|
||||
- ```store``` - Just stores the argument’s value. This is the default action.
|
||||
- ```storeConst``` - Stores value, specified by the const keyword argument.
|
||||
(Note that the const keyword argument defaults to the rather unhelpful None.)
|
||||
The 'storeConst' action is most commonly used with optional arguments, that
|
||||
specify some sort of flag.
|
||||
- ```storeTrue``` and ```storeFalse``` - Stores values True and False
|
||||
respectively. These are special cases of 'storeConst'.
|
||||
- ```append``` - Stores a list, and appends each argument value to the list.
|
||||
This is useful to allow an option to be specified multiple times.
|
||||
- ```appendConst``` - Stores a list, and appends value, specified by the
|
||||
const keyword argument to the list. (Note, that the const keyword argument defaults
|
||||
is None.) The 'appendConst' action is typically used when multiple arguments need
|
||||
to store constants to the same list.
|
||||
- ```count``` - Counts the number of times a keyword argument occurs. For example,
|
||||
used for increasing verbosity levels.
|
||||
- ```help``` - Prints a complete help message for all the options in the current
|
||||
parser and then exits. By default a help action is automatically added to the parser.
|
||||
See ArgumentParser for details of how the output is created.
|
||||
- ```version``` - Prints version information and exit. Expects a `version=`
|
||||
keyword argument in the addArgument() call.
|
||||
|
||||
Details in [original action guide](http://docs.python.org/dev/library/argparse.html#action)
|
||||
|
||||
|
||||
Sub-commands
|
||||
============
|
||||
|
||||
ArgumentParser.addSubparsers()
|
||||
|
||||
Many programs split their functionality into a number of sub-commands, for
|
||||
example, the svn program can invoke sub-commands like `svn checkout`, `svn update`,
|
||||
and `svn commit`. Splitting up functionality this way can be a particularly good
|
||||
idea when a program performs several different functions which require different
|
||||
kinds of command-line arguments. `ArgumentParser` supports creation of such
|
||||
sub-commands with `addSubparsers()` method. The `addSubparsers()` method is
|
||||
normally called with no arguments and returns an special action object.
|
||||
This object has a single method `addParser()`, which takes a command name and
|
||||
any `ArgumentParser` constructor arguments, and returns an `ArgumentParser` object
|
||||
that can be modified as usual.
|
||||
|
||||
Example:
|
||||
|
||||
sub_commands.js
|
||||
```javascript
|
||||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
var ArgumentParser = require('../lib/argparse').ArgumentParser;
|
||||
var parser = new ArgumentParser({
|
||||
version: '0.0.1',
|
||||
addHelp:true,
|
||||
description: 'Argparse examples: sub-commands',
|
||||
});
|
||||
|
||||
var subparsers = parser.addSubparsers({
|
||||
title:'subcommands',
|
||||
dest:"subcommand_name"
|
||||
});
|
||||
|
||||
var bar = subparsers.addParser('c1', {addHelp:true});
|
||||
bar.addArgument(
|
||||
[ '-f', '--foo' ],
|
||||
{
|
||||
action: 'store',
|
||||
help: 'foo3 bar3'
|
||||
}
|
||||
);
|
||||
var bar = subparsers.addParser(
|
||||
'c2',
|
||||
{aliases:['co'], addHelp:true}
|
||||
);
|
||||
bar.addArgument(
|
||||
[ '-b', '--bar' ],
|
||||
{
|
||||
action: 'store',
|
||||
type: 'int',
|
||||
help: 'foo3 bar3'
|
||||
}
|
||||
);
|
||||
|
||||
var args = parser.parseArgs();
|
||||
console.dir(args);
|
||||
|
||||
```
|
||||
|
||||
Details in [original sub-commands guide](http://docs.python.org/dev/library/argparse.html#sub-commands)
|
||||
|
||||
|
||||
Contributors
|
||||
============
|
||||
|
||||
- [Eugene Shkuropat](https://github.com/shkuropat)
|
||||
- [Paul Jacobson](https://github.com/hpaulj)
|
||||
|
||||
[others](https://github.com/nodeca/argparse/graphs/contributors)
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
Copyright (c) 2012 [Vitaly Puzrin](https://github.com/puzrin).
|
||||
Released under the MIT license. See
|
||||
[LICENSE](https://github.com/nodeca/argparse/blob/master/LICENSE) for details.
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = require('./lib/argparse');
|
|
@ -0,0 +1,146 @@
|
|||
/**
|
||||
* class Action
|
||||
*
|
||||
* Base class for all actions
|
||||
* Do not call in your code, use this class only for inherits your own action
|
||||
*
|
||||
* Information about how to convert command line strings to Javascript objects.
|
||||
* Action objects are used by an ArgumentParser to represent the information
|
||||
* needed to parse a single argument from one or more strings from the command
|
||||
* line. The keyword arguments to the Action constructor are also all attributes
|
||||
* of Action instances.
|
||||
*
|
||||
* ##### Allowed keywords:
|
||||
*
|
||||
* - `store`
|
||||
* - `storeConstant`
|
||||
* - `storeTrue`
|
||||
* - `storeFalse`
|
||||
* - `append`
|
||||
* - `appendConstant`
|
||||
* - `count`
|
||||
* - `help`
|
||||
* - `version`
|
||||
*
|
||||
* Information about action options see [[Action.new]]
|
||||
*
|
||||
* See also [original guide](http://docs.python.org/dev/library/argparse.html#action)
|
||||
*
|
||||
**/
|
||||
|
||||
'use strict';
|
||||
|
||||
|
||||
// Constants
|
||||
var c = require('./const');
|
||||
|
||||
|
||||
/**
|
||||
* new Action(options)
|
||||
*
|
||||
* Base class for all actions. Used only for inherits
|
||||
*
|
||||
*
|
||||
* ##### Options:
|
||||
*
|
||||
* - `optionStrings` A list of command-line option strings for the action.
|
||||
* - `dest` Attribute to hold the created object(s)
|
||||
* - `nargs` The number of command-line arguments that should be consumed.
|
||||
* By default, one argument will be consumed and a single value will be
|
||||
* produced.
|
||||
* - `constant` Default value for an action with no value.
|
||||
* - `defaultValue` The value to be produced if the option is not specified.
|
||||
* - `type` Cast to 'string'|'int'|'float'|'complex'|function (string). If
|
||||
* None, 'string'.
|
||||
* - `choices` The choices available.
|
||||
* - `required` True if the action must always be specified at the command
|
||||
* line.
|
||||
* - `help` The help describing the argument.
|
||||
* - `metavar` The name to be used for the option's argument with the help
|
||||
* string. If None, the 'dest' value will be used as the name.
|
||||
*
|
||||
* ##### nargs supported values:
|
||||
*
|
||||
* - `N` (an integer) consumes N arguments (and produces a list)
|
||||
* - `?` consumes zero or one arguments
|
||||
* - `*` consumes zero or more arguments (and produces a list)
|
||||
* - `+` consumes one or more arguments (and produces a list)
|
||||
*
|
||||
* Note: that the difference between the default and nargs=1 is that with the
|
||||
* default, a single value will be produced, while with nargs=1, a list
|
||||
* containing a single value will be produced.
|
||||
**/
|
||||
var Action = module.exports = function Action(options) {
|
||||
options = options || {};
|
||||
this.optionStrings = options.optionStrings || [];
|
||||
this.dest = options.dest;
|
||||
this.nargs = typeof options.nargs !== 'undefined' ? options.nargs : null;
|
||||
this.constant = typeof options.constant !== 'undefined' ? options.constant : null;
|
||||
this.defaultValue = options.defaultValue;
|
||||
this.type = typeof options.type !== 'undefined' ? options.type : null;
|
||||
this.choices = typeof options.choices !== 'undefined' ? options.choices : null;
|
||||
this.required = typeof options.required !== 'undefined' ? options.required : false;
|
||||
this.help = typeof options.help !== 'undefined' ? options.help : null;
|
||||
this.metavar = typeof options.metavar !== 'undefined' ? options.metavar : null;
|
||||
|
||||
if (!(this.optionStrings instanceof Array)) {
|
||||
throw new Error('optionStrings should be an array');
|
||||
}
|
||||
if (typeof this.required !== 'undefined' && typeof this.required !== 'boolean') {
|
||||
throw new Error('required should be a boolean');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Action#getName -> String
|
||||
*
|
||||
* Tells action name
|
||||
**/
|
||||
Action.prototype.getName = function () {
|
||||
if (this.optionStrings.length > 0) {
|
||||
return this.optionStrings.join('/');
|
||||
} else if (this.metavar !== null && this.metavar !== c.SUPPRESS) {
|
||||
return this.metavar;
|
||||
} else if (typeof this.dest !== 'undefined' && this.dest !== c.SUPPRESS) {
|
||||
return this.dest;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Action#isOptional -> Boolean
|
||||
*
|
||||
* Return true if optional
|
||||
**/
|
||||
Action.prototype.isOptional = function () {
|
||||
return !this.isPositional();
|
||||
};
|
||||
|
||||
/**
|
||||
* Action#isPositional -> Boolean
|
||||
*
|
||||
* Return true if positional
|
||||
**/
|
||||
Action.prototype.isPositional = function () {
|
||||
return (this.optionStrings.length === 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Action#call(parser, namespace, values, optionString) -> Void
|
||||
* - parser (ArgumentParser): current parser
|
||||
* - namespace (Namespace): namespace for output data
|
||||
* - values (Array): parsed values
|
||||
* - optionString (Array): input option string(not parsed)
|
||||
*
|
||||
* Call the action. Should be implemented in inherited classes
|
||||
*
|
||||
* ##### Example
|
||||
*
|
||||
* ActionCount.prototype.call = function (parser, namespace, values, optionString) {
|
||||
* namespace.set(this.dest, (namespace[this.dest] || 0) + 1);
|
||||
* };
|
||||
*
|
||||
**/
|
||||
Action.prototype.call = function () {
|
||||
throw new Error('.call() not defined');// Not Implemented error
|
||||
};
|
|
@ -0,0 +1,53 @@
|
|||
/*:nodoc:*
|
||||
* class ActionAppend
|
||||
*
|
||||
* This action stores a list, and appends each argument value to the list.
|
||||
* This is useful to allow an option to be specified multiple times.
|
||||
* This class inherided from [[Action]]
|
||||
*
|
||||
**/
|
||||
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
var Action = require('../action');
|
||||
|
||||
// Constants
|
||||
var c = require('../const');
|
||||
|
||||
/*:nodoc:*
|
||||
* new ActionAppend(options)
|
||||
* - options (object): options hash see [[Action.new]]
|
||||
*
|
||||
* Note: options.nargs should be optional for constants
|
||||
* and more then zero for other
|
||||
**/
|
||||
var ActionAppend = module.exports = function ActionAppend(options) {
|
||||
options = options || {};
|
||||
if (this.nargs <= 0) {
|
||||
throw new Error('nargs for append actions must be > 0; if arg ' +
|
||||
'strings are not supplying the value to append, ' +
|
||||
'the append const action may be more appropriate');
|
||||
}
|
||||
if (!!this.constant && this.nargs !== c.OPTIONAL) {
|
||||
throw new Error('nargs must be OPTIONAL to supply const');
|
||||
}
|
||||
Action.call(this, options);
|
||||
};
|
||||
util.inherits(ActionAppend, Action);
|
||||
|
||||
/*:nodoc:*
|
||||
* ActionAppend#call(parser, namespace, values, optionString) -> Void
|
||||
* - parser (ArgumentParser): current parser
|
||||
* - namespace (Namespace): namespace for output data
|
||||
* - values (Array): parsed values
|
||||
* - optionString (Array): input option string(not parsed)
|
||||
*
|
||||
* Call the action. Save result in namespace object
|
||||
**/
|
||||
ActionAppend.prototype.call = function (parser, namespace, values) {
|
||||
var items = (namespace[this.dest] || []).slice();
|
||||
items.push(values);
|
||||
namespace.set(this.dest, items);
|
||||
};
|
|
@ -0,0 +1,47 @@
|
|||
/*:nodoc:*
|
||||
* class ActionAppendConstant
|
||||
*
|
||||
* This stores a list, and appends the value specified by
|
||||
* the const keyword argument to the list.
|
||||
* (Note that the const keyword argument defaults to null.)
|
||||
* The 'appendConst' action is typically useful when multiple
|
||||
* arguments need to store constants to the same list.
|
||||
*
|
||||
* This class inherited from [[Action]]
|
||||
**/
|
||||
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
var Action = require('../../action');
|
||||
|
||||
/*:nodoc:*
|
||||
* new ActionAppendConstant(options)
|
||||
* - options (object): options hash see [[Action.new]]
|
||||
*
|
||||
**/
|
||||
var ActionAppendConstant = module.exports = function ActionAppendConstant(options) {
|
||||
options = options || {};
|
||||
options.nargs = 0;
|
||||
if (typeof options.constant === 'undefined') {
|
||||
throw new Error('constant option is required for appendAction');
|
||||
}
|
||||
Action.call(this, options);
|
||||
};
|
||||
util.inherits(ActionAppendConstant, Action);
|
||||
|
||||
/*:nodoc:*
|
||||
* ActionAppendConstant#call(parser, namespace, values, optionString) -> Void
|
||||
* - parser (ArgumentParser): current parser
|
||||
* - namespace (Namespace): namespace for output data
|
||||
* - values (Array): parsed values
|
||||
* - optionString (Array): input option string(not parsed)
|
||||
*
|
||||
* Call the action. Save result in namespace object
|
||||
**/
|
||||
ActionAppendConstant.prototype.call = function (parser, namespace) {
|
||||
var items = [].concat(namespace[this.dest] || []);
|
||||
items.push(this.constant);
|
||||
namespace.set(this.dest, items);
|
||||
};
|
|
@ -0,0 +1,40 @@
|
|||
/*:nodoc:*
|
||||
* class ActionCount
|
||||
*
|
||||
* This counts the number of times a keyword argument occurs.
|
||||
* For example, this is useful for increasing verbosity levels
|
||||
*
|
||||
* This class inherided from [[Action]]
|
||||
*
|
||||
**/
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
var Action = require('../action');
|
||||
|
||||
/*:nodoc:*
|
||||
* new ActionCount(options)
|
||||
* - options (object): options hash see [[Action.new]]
|
||||
*
|
||||
**/
|
||||
var ActionCount = module.exports = function ActionCount(options) {
|
||||
options = options || {};
|
||||
options.nargs = 0;
|
||||
|
||||
Action.call(this, options);
|
||||
};
|
||||
util.inherits(ActionCount, Action);
|
||||
|
||||
/*:nodoc:*
|
||||
* ActionCount#call(parser, namespace, values, optionString) -> Void
|
||||
* - parser (ArgumentParser): current parser
|
||||
* - namespace (Namespace): namespace for output data
|
||||
* - values (Array): parsed values
|
||||
* - optionString (Array): input option string(not parsed)
|
||||
*
|
||||
* Call the action. Save result in namespace object
|
||||
**/
|
||||
ActionCount.prototype.call = function (parser, namespace) {
|
||||
namespace.set(this.dest, (namespace[this.dest] || 0) + 1);
|
||||
};
|
|
@ -0,0 +1,47 @@
|
|||
/*:nodoc:*
|
||||
* class ActionHelp
|
||||
*
|
||||
* Support action for printing help
|
||||
* This class inherided from [[Action]]
|
||||
**/
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
var Action = require('../action');
|
||||
|
||||
// Constants
|
||||
var c = require('../const');
|
||||
|
||||
/*:nodoc:*
|
||||
* new ActionHelp(options)
|
||||
* - options (object): options hash see [[Action.new]]
|
||||
*
|
||||
**/
|
||||
var ActionHelp = module.exports = function ActionHelp(options) {
|
||||
options = options || {};
|
||||
if (options.defaultValue !== null) {
|
||||
options.defaultValue = options.defaultValue;
|
||||
} else {
|
||||
options.defaultValue = c.SUPPRESS;
|
||||
}
|
||||
options.dest = (options.dest !== null ? options.dest : c.SUPPRESS);
|
||||
options.nargs = 0;
|
||||
Action.call(this, options);
|
||||
|
||||
};
|
||||
util.inherits(ActionHelp, Action);
|
||||
|
||||
/*:nodoc:*
|
||||
* ActionHelp#call(parser, namespace, values, optionString)
|
||||
* - parser (ArgumentParser): current parser
|
||||
* - namespace (Namespace): namespace for output data
|
||||
* - values (Array): parsed values
|
||||
* - optionString (Array): input option string(not parsed)
|
||||
*
|
||||
* Print help and exit
|
||||
**/
|
||||
ActionHelp.prototype.call = function (parser) {
|
||||
parser.printHelp();
|
||||
parser.exit();
|
||||
};
|
|
@ -0,0 +1,50 @@
|
|||
/*:nodoc:*
|
||||
* class ActionStore
|
||||
*
|
||||
* This action just stores the argument’s value. This is the default action.
|
||||
*
|
||||
* This class inherited from [[Action]]
|
||||
*
|
||||
**/
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
var Action = require('../action');
|
||||
|
||||
// Constants
|
||||
var c = require('../const');
|
||||
|
||||
|
||||
/*:nodoc:*
|
||||
* new ActionStore(options)
|
||||
* - options (object): options hash see [[Action.new]]
|
||||
*
|
||||
**/
|
||||
var ActionStore = module.exports = function ActionStore(options) {
|
||||
options = options || {};
|
||||
if (this.nargs <= 0) {
|
||||
throw new Error('nargs for store actions must be > 0; if you ' +
|
||||
'have nothing to store, actions such as store ' +
|
||||
'true or store const may be more appropriate');
|
||||
|
||||
}
|
||||
if (typeof this.constant !== 'undefined' && this.nargs !== c.OPTIONAL) {
|
||||
throw new Error('nargs must be OPTIONAL to supply const');
|
||||
}
|
||||
Action.call(this, options);
|
||||
};
|
||||
util.inherits(ActionStore, Action);
|
||||
|
||||
/*:nodoc:*
|
||||
* ActionStore#call(parser, namespace, values, optionString) -> Void
|
||||
* - parser (ArgumentParser): current parser
|
||||
* - namespace (Namespace): namespace for output data
|
||||
* - values (Array): parsed values
|
||||
* - optionString (Array): input option string(not parsed)
|
||||
*
|
||||
* Call the action. Save result in namespace object
|
||||
**/
|
||||
ActionStore.prototype.call = function (parser, namespace, values) {
|
||||
namespace.set(this.dest, values);
|
||||
};
|
|
@ -0,0 +1,43 @@
|
|||
/*:nodoc:*
|
||||
* class ActionStoreConstant
|
||||
*
|
||||
* This action stores the value specified by the const keyword argument.
|
||||
* (Note that the const keyword argument defaults to the rather unhelpful null.)
|
||||
* The 'store_const' action is most commonly used with optional
|
||||
* arguments that specify some sort of flag.
|
||||
*
|
||||
* This class inherited from [[Action]]
|
||||
**/
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
var Action = require('../../action');
|
||||
|
||||
/*:nodoc:*
|
||||
* new ActionStoreConstant(options)
|
||||
* - options (object): options hash see [[Action.new]]
|
||||
*
|
||||
**/
|
||||
var ActionStoreConstant = module.exports = function ActionStoreConstant(options) {
|
||||
options = options || {};
|
||||
options.nargs = 0;
|
||||
if (typeof options.constant === 'undefined') {
|
||||
throw new Error('constant option is required for storeAction');
|
||||
}
|
||||
Action.call(this, options);
|
||||
};
|
||||
util.inherits(ActionStoreConstant, Action);
|
||||
|
||||
/*:nodoc:*
|
||||
* ActionStoreConstant#call(parser, namespace, values, optionString) -> Void
|
||||
* - parser (ArgumentParser): current parser
|
||||
* - namespace (Namespace): namespace for output data
|
||||
* - values (Array): parsed values
|
||||
* - optionString (Array): input option string(not parsed)
|
||||
*
|
||||
* Call the action. Save result in namespace object
|
||||
**/
|
||||
ActionStoreConstant.prototype.call = function (parser, namespace) {
|
||||
namespace.set(this.dest, this.constant);
|
||||
};
|
|
@ -0,0 +1,27 @@
|
|||
/*:nodoc:*
|
||||
* class ActionStoreFalse
|
||||
*
|
||||
* This action store the values False respectively.
|
||||
* This is special cases of 'storeConst'
|
||||
*
|
||||
* This class inherited from [[Action]]
|
||||
**/
|
||||
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
var ActionStoreConstant = require('./constant');
|
||||
|
||||
/*:nodoc:*
|
||||
* new ActionStoreFalse(options)
|
||||
* - options (object): hash of options see [[Action.new]]
|
||||
*
|
||||
**/
|
||||
var ActionStoreFalse = module.exports = function ActionStoreFalse(options) {
|
||||
options = options || {};
|
||||
options.constant = false;
|
||||
options.defaultValue = options.defaultValue !== null ? options.defaultValue : true;
|
||||
ActionStoreConstant.call(this, options);
|
||||
};
|
||||
util.inherits(ActionStoreFalse, ActionStoreConstant);
|
|
@ -0,0 +1,26 @@
|
|||
/*:nodoc:*
|
||||
* class ActionStoreTrue
|
||||
*
|
||||
* This action store the values True respectively.
|
||||
* This isspecial cases of 'storeConst'
|
||||
*
|
||||
* This class inherited from [[Action]]
|
||||
**/
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
var ActionStoreConstant = require('./constant');
|
||||
|
||||
/*:nodoc:*
|
||||
* new ActionStoreTrue(options)
|
||||
* - options (object): options hash see [[Action.new]]
|
||||
*
|
||||
**/
|
||||
var ActionStoreTrue = module.exports = function ActionStoreTrue(options) {
|
||||
options = options || {};
|
||||
options.constant = true;
|
||||
options.defaultValue = options.defaultValue !== null ? options.defaultValue : false;
|
||||
ActionStoreConstant.call(this, options);
|
||||
};
|
||||
util.inherits(ActionStoreTrue, ActionStoreConstant);
|
|
@ -0,0 +1,149 @@
|
|||
/** internal
|
||||
* class ActionSubparsers
|
||||
*
|
||||
* Support the creation of such sub-commands with the addSubparsers()
|
||||
*
|
||||
* This class inherited from [[Action]]
|
||||
**/
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
var format = require('util').format;
|
||||
|
||||
|
||||
var Action = require('../action');
|
||||
|
||||
// Constants
|
||||
var c = require('../const');
|
||||
|
||||
// Errors
|
||||
var argumentErrorHelper = require('../argument/error');
|
||||
|
||||
|
||||
/*:nodoc:*
|
||||
* new ChoicesPseudoAction(name, help)
|
||||
*
|
||||
* Create pseudo action for correct help text
|
||||
*
|
||||
**/
|
||||
function ChoicesPseudoAction(name, help) {
|
||||
var options = {
|
||||
optionStrings: [],
|
||||
dest: name,
|
||||
help: help
|
||||
};
|
||||
|
||||
Action.call(this, options);
|
||||
}
|
||||
|
||||
util.inherits(ChoicesPseudoAction, Action);
|
||||
|
||||
/**
|
||||
* new ActionSubparsers(options)
|
||||
* - options (object): options hash see [[Action.new]]
|
||||
*
|
||||
**/
|
||||
function ActionSubparsers(options) {
|
||||
options = options || {};
|
||||
options.dest = options.dest || c.SUPPRESS;
|
||||
options.nargs = c.PARSER;
|
||||
|
||||
this.debug = (options.debug === true);
|
||||
|
||||
this._progPrefix = options.prog;
|
||||
this._parserClass = options.parserClass;
|
||||
this._nameParserMap = {};
|
||||
this._choicesActions = [];
|
||||
|
||||
options.choices = this._nameParserMap;
|
||||
Action.call(this, options);
|
||||
}
|
||||
|
||||
util.inherits(ActionSubparsers, Action);
|
||||
|
||||
/*:nodoc:*
|
||||
* ActionSubparsers#addParser(name, options) -> ArgumentParser
|
||||
* - name (string): sub-command name
|
||||
* - options (object): see [[ArgumentParser.new]]
|
||||
*
|
||||
* Note:
|
||||
* addParser supports an additional aliases option,
|
||||
* which allows multiple strings to refer to the same subparser.
|
||||
* This example, like svn, aliases co as a shorthand for checkout
|
||||
*
|
||||
**/
|
||||
ActionSubparsers.prototype.addParser = function (name, options) {
|
||||
var parser;
|
||||
|
||||
var self = this;
|
||||
|
||||
options = options || {};
|
||||
|
||||
options.debug = (this.debug === true);
|
||||
|
||||
// set program from the existing prefix
|
||||
if (!options.prog) {
|
||||
options.prog = this._progPrefix + ' ' + name;
|
||||
}
|
||||
|
||||
var aliases = options.aliases || [];
|
||||
|
||||
// create a pseudo-action to hold the choice help
|
||||
if (!!options.help || typeof options.help === 'string') {
|
||||
var help = options.help;
|
||||
delete options.help;
|
||||
|
||||
var choiceAction = new ChoicesPseudoAction(name, help);
|
||||
this._choicesActions.push(choiceAction);
|
||||
}
|
||||
|
||||
// create the parser and add it to the map
|
||||
parser = new this._parserClass(options);
|
||||
this._nameParserMap[name] = parser;
|
||||
|
||||
// make parser available under aliases also
|
||||
aliases.forEach(function (alias) {
|
||||
self._nameParserMap[alias] = parser;
|
||||
});
|
||||
|
||||
return parser;
|
||||
};
|
||||
|
||||
ActionSubparsers.prototype._getSubactions = function () {
|
||||
return this._choicesActions;
|
||||
};
|
||||
|
||||
/*:nodoc:*
|
||||
* ActionSubparsers#call(parser, namespace, values, optionString) -> Void
|
||||
* - parser (ArgumentParser): current parser
|
||||
* - namespace (Namespace): namespace for output data
|
||||
* - values (Array): parsed values
|
||||
* - optionString (Array): input option string(not parsed)
|
||||
*
|
||||
* Call the action. Parse input aguments
|
||||
**/
|
||||
ActionSubparsers.prototype.call = function (parser, namespace, values) {
|
||||
var parserName = values[0];
|
||||
var argStrings = values.slice(1);
|
||||
|
||||
// set the parser name if requested
|
||||
if (this.dest !== c.SUPPRESS) {
|
||||
namespace[this.dest] = parserName;
|
||||
}
|
||||
|
||||
// select the parser
|
||||
if (this._nameParserMap[parserName]) {
|
||||
parser = this._nameParserMap[parserName];
|
||||
} else {
|
||||
throw argumentErrorHelper(format(
|
||||
'Unknown parser "%s" (choices: [%s]).',
|
||||
parserName,
|
||||
Object.keys(this._nameParserMap).join(', ')
|
||||
));
|
||||
}
|
||||
|
||||
// parse all the remaining options into the namespace
|
||||
parser.parseArgs(argStrings, namespace);
|
||||
};
|
||||
|
||||
module.exports = ActionSubparsers;
|
|
@ -0,0 +1,47 @@
|
|||
/*:nodoc:*
|
||||
* class ActionVersion
|
||||
*
|
||||
* Support action for printing program version
|
||||
* This class inherited from [[Action]]
|
||||
**/
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
var Action = require('../action');
|
||||
|
||||
//
|
||||
// Constants
|
||||
//
|
||||
var c = require('../const');
|
||||
|
||||
/*:nodoc:*
|
||||
* new ActionVersion(options)
|
||||
* - options (object): options hash see [[Action.new]]
|
||||
*
|
||||
**/
|
||||
var ActionVersion = module.exports = function ActionVersion(options) {
|
||||
options = options || {};
|
||||
options.defaultValue = (options.defaultValue ? options.defaultValue : c.SUPPRESS);
|
||||
options.dest = (options.dest || c.SUPPRESS);
|
||||
options.nargs = 0;
|
||||
this.version = options.version;
|
||||
Action.call(this, options);
|
||||
};
|
||||
util.inherits(ActionVersion, Action);
|
||||
|
||||
/*:nodoc:*
|
||||
* ActionVersion#call(parser, namespace, values, optionString) -> Void
|
||||
* - parser (ArgumentParser): current parser
|
||||
* - namespace (Namespace): namespace for output data
|
||||
* - values (Array): parsed values
|
||||
* - optionString (Array): input option string(not parsed)
|
||||
*
|
||||
* Print version and exit
|
||||
**/
|
||||
ActionVersion.prototype.call = function (parser) {
|
||||
var version = this.version || parser.version;
|
||||
var formatter = parser._getFormatter();
|
||||
formatter.addText(version);
|
||||
parser.exit(0, formatter.formatHelp());
|
||||
};
|
|
@ -0,0 +1,482 @@
|
|||
/** internal
|
||||
* class ActionContainer
|
||||
*
|
||||
* Action container. Parent for [[ArgumentParser]] and [[ArgumentGroup]]
|
||||
**/
|
||||
|
||||
'use strict';
|
||||
|
||||
var format = require('util').format;
|
||||
|
||||
// Constants
|
||||
var c = require('./const');
|
||||
|
||||
var $$ = require('./utils');
|
||||
|
||||
//Actions
|
||||
var ActionHelp = require('./action/help');
|
||||
var ActionAppend = require('./action/append');
|
||||
var ActionAppendConstant = require('./action/append/constant');
|
||||
var ActionCount = require('./action/count');
|
||||
var ActionStore = require('./action/store');
|
||||
var ActionStoreConstant = require('./action/store/constant');
|
||||
var ActionStoreTrue = require('./action/store/true');
|
||||
var ActionStoreFalse = require('./action/store/false');
|
||||
var ActionVersion = require('./action/version');
|
||||
var ActionSubparsers = require('./action/subparsers');
|
||||
|
||||
// Errors
|
||||
var argumentErrorHelper = require('./argument/error');
|
||||
|
||||
/**
|
||||
* new ActionContainer(options)
|
||||
*
|
||||
* Action container. Parent for [[ArgumentParser]] and [[ArgumentGroup]]
|
||||
*
|
||||
* ##### Options:
|
||||
*
|
||||
* - `description` -- A description of what the program does
|
||||
* - `prefixChars` -- Characters that prefix optional arguments
|
||||
* - `argumentDefault` -- The default value for all arguments
|
||||
* - `conflictHandler` -- The conflict handler to use for duplicate arguments
|
||||
**/
|
||||
var ActionContainer = module.exports = function ActionContainer(options) {
|
||||
options = options || {};
|
||||
|
||||
this.description = options.description;
|
||||
this.argumentDefault = options.argumentDefault;
|
||||
this.prefixChars = options.prefixChars || '';
|
||||
this.conflictHandler = options.conflictHandler;
|
||||
|
||||
// set up registries
|
||||
this._registries = {};
|
||||
|
||||
// register actions
|
||||
this.register('action', null, ActionStore);
|
||||
this.register('action', 'store', ActionStore);
|
||||
this.register('action', 'storeConst', ActionStoreConstant);
|
||||
this.register('action', 'storeTrue', ActionStoreTrue);
|
||||
this.register('action', 'storeFalse', ActionStoreFalse);
|
||||
this.register('action', 'append', ActionAppend);
|
||||
this.register('action', 'appendConst', ActionAppendConstant);
|
||||
this.register('action', 'count', ActionCount);
|
||||
this.register('action', 'help', ActionHelp);
|
||||
this.register('action', 'version', ActionVersion);
|
||||
this.register('action', 'parsers', ActionSubparsers);
|
||||
|
||||
// raise an exception if the conflict handler is invalid
|
||||
this._getHandler();
|
||||
|
||||
// action storage
|
||||
this._actions = [];
|
||||
this._optionStringActions = {};
|
||||
|
||||
// groups
|
||||
this._actionGroups = [];
|
||||
this._mutuallyExclusiveGroups = [];
|
||||
|
||||
// defaults storage
|
||||
this._defaults = {};
|
||||
|
||||
// determines whether an "option" looks like a negative number
|
||||
// -1, -1.5 -5e+4
|
||||
this._regexpNegativeNumber = new RegExp('^[-]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$');
|
||||
|
||||
// whether or not there are any optionals that look like negative
|
||||
// numbers -- uses a list so it can be shared and edited
|
||||
this._hasNegativeNumberOptionals = [];
|
||||
};
|
||||
|
||||
// Groups must be required, then ActionContainer already defined
|
||||
var ArgumentGroup = require('./argument/group');
|
||||
var MutuallyExclusiveGroup = require('./argument/exclusive');
|
||||
|
||||
//
|
||||
// Registration methods
|
||||
//
|
||||
|
||||
/**
|
||||
* ActionContainer#register(registryName, value, object) -> Void
|
||||
* - registryName (String) : object type action|type
|
||||
* - value (string) : keyword
|
||||
* - object (Object|Function) : handler
|
||||
*
|
||||
* Register handlers
|
||||
**/
|
||||
ActionContainer.prototype.register = function (registryName, value, object) {
|
||||
this._registries[registryName] = this._registries[registryName] || {};
|
||||
this._registries[registryName][value] = object;
|
||||
};
|
||||
|
||||
ActionContainer.prototype._registryGet = function (registryName, value, defaultValue) {
|
||||
if (arguments.length < 3) {
|
||||
defaultValue = null;
|
||||
}
|
||||
return this._registries[registryName][value] || defaultValue;
|
||||
};
|
||||
|
||||
//
|
||||
// Namespace default accessor methods
|
||||
//
|
||||
|
||||
/**
|
||||
* ActionContainer#setDefaults(options) -> Void
|
||||
* - options (object):hash of options see [[Action.new]]
|
||||
*
|
||||
* Set defaults
|
||||
**/
|
||||
ActionContainer.prototype.setDefaults = function (options) {
|
||||
options = options || {};
|
||||
for (var property in options) {
|
||||
if ($$.has(options, property)) {
|
||||
this._defaults[property] = options[property];
|
||||
}
|
||||
}
|
||||
|
||||
// if these defaults match any existing arguments, replace the previous
|
||||
// default on the object with the new one
|
||||
this._actions.forEach(function (action) {
|
||||
if ($$.has(options, action.dest)) {
|
||||
action.defaultValue = options[action.dest];
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* ActionContainer#getDefault(dest) -> Mixed
|
||||
* - dest (string): action destination
|
||||
*
|
||||
* Return action default value
|
||||
**/
|
||||
ActionContainer.prototype.getDefault = function (dest) {
|
||||
var result = $$.has(this._defaults, dest) ? this._defaults[dest] : null;
|
||||
|
||||
this._actions.forEach(function (action) {
|
||||
if (action.dest === dest && $$.has(action, 'defaultValue')) {
|
||||
result = action.defaultValue;
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
//
|
||||
// Adding argument actions
|
||||
//
|
||||
|
||||
/**
|
||||
* ActionContainer#addArgument(args, options) -> Object
|
||||
* - args (String|Array): argument key, or array of argument keys
|
||||
* - options (Object): action objects see [[Action.new]]
|
||||
*
|
||||
* #### Examples
|
||||
* - addArgument([ '-f', '--foo' ], { action: 'store', defaultValue: 1, ... })
|
||||
* - addArgument([ 'bar' ], { action: 'store', nargs: 1, ... })
|
||||
* - addArgument('--baz', { action: 'store', nargs: 1, ... })
|
||||
**/
|
||||
ActionContainer.prototype.addArgument = function (args, options) {
|
||||
args = args;
|
||||
options = options || {};
|
||||
|
||||
if (typeof args === 'string') {
|
||||
args = [ args ];
|
||||
}
|
||||
if (!Array.isArray(args)) {
|
||||
throw new TypeError('addArgument first argument should be a string or an array');
|
||||
}
|
||||
if (typeof options !== 'object' || Array.isArray(options)) {
|
||||
throw new TypeError('addArgument second argument should be a hash');
|
||||
}
|
||||
|
||||
// if no positional args are supplied or only one is supplied and
|
||||
// it doesn't look like an option string, parse a positional argument
|
||||
if (!args || args.length === 1 && this.prefixChars.indexOf(args[0][0]) < 0) {
|
||||
if (args && !!options.dest) {
|
||||
throw new Error('dest supplied twice for positional argument');
|
||||
}
|
||||
options = this._getPositional(args, options);
|
||||
|
||||
// otherwise, we're adding an optional argument
|
||||
} else {
|
||||
options = this._getOptional(args, options);
|
||||
}
|
||||
|
||||
// if no default was supplied, use the parser-level default
|
||||
if (typeof options.defaultValue === 'undefined') {
|
||||
var dest = options.dest;
|
||||
if ($$.has(this._defaults, dest)) {
|
||||
options.defaultValue = this._defaults[dest];
|
||||
} else if (typeof this.argumentDefault !== 'undefined') {
|
||||
options.defaultValue = this.argumentDefault;
|
||||
}
|
||||
}
|
||||
|
||||
// create the action object, and add it to the parser
|
||||
var ActionClass = this._popActionClass(options);
|
||||
if (typeof ActionClass !== 'function') {
|
||||
throw new Error(format('Unknown action "%s".', ActionClass));
|
||||
}
|
||||
var action = new ActionClass(options);
|
||||
|
||||
// throw an error if the action type is not callable
|
||||
var typeFunction = this._registryGet('type', action.type, action.type);
|
||||
if (typeof typeFunction !== 'function') {
|
||||
throw new Error(format('"%s" is not callable', typeFunction));
|
||||
}
|
||||
|
||||
return this._addAction(action);
|
||||
};
|
||||
|
||||
/**
|
||||
* ActionContainer#addArgumentGroup(options) -> ArgumentGroup
|
||||
* - options (Object): hash of options see [[ArgumentGroup.new]]
|
||||
*
|
||||
* Create new arguments groups
|
||||
**/
|
||||
ActionContainer.prototype.addArgumentGroup = function (options) {
|
||||
var group = new ArgumentGroup(this, options);
|
||||
this._actionGroups.push(group);
|
||||
return group;
|
||||
};
|
||||
|
||||
/**
|
||||
* ActionContainer#addMutuallyExclusiveGroup(options) -> ArgumentGroup
|
||||
* - options (Object): {required: false}
|
||||
*
|
||||
* Create new mutual exclusive groups
|
||||
**/
|
||||
ActionContainer.prototype.addMutuallyExclusiveGroup = function (options) {
|
||||
var group = new MutuallyExclusiveGroup(this, options);
|
||||
this._mutuallyExclusiveGroups.push(group);
|
||||
return group;
|
||||
};
|
||||
|
||||
ActionContainer.prototype._addAction = function (action) {
|
||||
var self = this;
|
||||
|
||||
// resolve any conflicts
|
||||
this._checkConflict(action);
|
||||
|
||||
// add to actions list
|
||||
this._actions.push(action);
|
||||
action.container = this;
|
||||
|
||||
// index the action by any option strings it has
|
||||
action.optionStrings.forEach(function (optionString) {
|
||||
self._optionStringActions[optionString] = action;
|
||||
});
|
||||
|
||||
// set the flag if any option strings look like negative numbers
|
||||
action.optionStrings.forEach(function (optionString) {
|
||||
if (optionString.match(self._regexpNegativeNumber)) {
|
||||
if (!self._hasNegativeNumberOptionals.some(Boolean)) {
|
||||
self._hasNegativeNumberOptionals.push(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// return the created action
|
||||
return action;
|
||||
};
|
||||
|
||||
ActionContainer.prototype._removeAction = function (action) {
|
||||
var actionIndex = this._actions.indexOf(action);
|
||||
if (actionIndex >= 0) {
|
||||
this._actions.splice(actionIndex, 1);
|
||||
}
|
||||
};
|
||||
|
||||
ActionContainer.prototype._addContainerActions = function (container) {
|
||||
// collect groups by titles
|
||||
var titleGroupMap = {};
|
||||
this._actionGroups.forEach(function (group) {
|
||||
if (titleGroupMap[group.title]) {
|
||||
throw new Error(format('Cannot merge actions - two groups are named "%s".', group.title));
|
||||
}
|
||||
titleGroupMap[group.title] = group;
|
||||
});
|
||||
|
||||
// map each action to its group
|
||||
var groupMap = {};
|
||||
function actionHash(action) {
|
||||
// unique (hopefully?) string suitable as dictionary key
|
||||
return action.getName();
|
||||
}
|
||||
container._actionGroups.forEach(function (group) {
|
||||
// if a group with the title exists, use that, otherwise
|
||||
// create a new group matching the container's group
|
||||
if (!titleGroupMap[group.title]) {
|
||||
titleGroupMap[group.title] = this.addArgumentGroup({
|
||||
title: group.title,
|
||||
description: group.description
|
||||
});
|
||||
}
|
||||
|
||||
// map the actions to their new group
|
||||
group._groupActions.forEach(function (action) {
|
||||
groupMap[actionHash(action)] = titleGroupMap[group.title];
|
||||
});
|
||||
}, this);
|
||||
|
||||
// add container's mutually exclusive groups
|
||||
// NOTE: if add_mutually_exclusive_group ever gains title= and
|
||||
// description= then this code will need to be expanded as above
|
||||
var mutexGroup;
|
||||
container._mutuallyExclusiveGroups.forEach(function (group) {
|
||||
mutexGroup = this.addMutuallyExclusiveGroup({
|
||||
required: group.required
|
||||
});
|
||||
// map the actions to their new mutex group
|
||||
group._groupActions.forEach(function (action) {
|
||||
groupMap[actionHash(action)] = mutexGroup;
|
||||
});
|
||||
}, this); // forEach takes a 'this' argument
|
||||
|
||||
// add all actions to this container or their group
|
||||
container._actions.forEach(function (action) {
|
||||
var key = actionHash(action);
|
||||
if (groupMap[key]) {
|
||||
groupMap[key]._addAction(action);
|
||||
} else {
|
||||
this._addAction(action);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
ActionContainer.prototype._getPositional = function (dest, options) {
|
||||
if (Array.isArray(dest)) {
|
||||
dest = dest[0];
|
||||
}
|
||||
// make sure required is not specified
|
||||
if (options.required) {
|
||||
throw new Error('"required" is an invalid argument for positionals.');
|
||||
}
|
||||
|
||||
// mark positional arguments as required if at least one is
|
||||
// always required
|
||||
if (options.nargs !== c.OPTIONAL && options.nargs !== c.ZERO_OR_MORE) {
|
||||
options.required = true;
|
||||
}
|
||||
if (options.nargs === c.ZERO_OR_MORE && typeof options.defaultValue === 'undefined') {
|
||||
options.required = true;
|
||||
}
|
||||
|
||||
// return the keyword arguments with no option strings
|
||||
options.dest = dest;
|
||||
options.optionStrings = [];
|
||||
return options;
|
||||
};
|
||||
|
||||
ActionContainer.prototype._getOptional = function (args, options) {
|
||||
var prefixChars = this.prefixChars;
|
||||
var optionStrings = [];
|
||||
var optionStringsLong = [];
|
||||
|
||||
// determine short and long option strings
|
||||
args.forEach(function (optionString) {
|
||||
// error on strings that don't start with an appropriate prefix
|
||||
if (prefixChars.indexOf(optionString[0]) < 0) {
|
||||
throw new Error(format('Invalid option string "%s": must start with a "%s".',
|
||||
optionString,
|
||||
prefixChars
|
||||
));
|
||||
}
|
||||
|
||||
// strings starting with two prefix characters are long options
|
||||
optionStrings.push(optionString);
|
||||
if (optionString.length > 1 && prefixChars.indexOf(optionString[1]) >= 0) {
|
||||
optionStringsLong.push(optionString);
|
||||
}
|
||||
});
|
||||
|
||||
// infer dest, '--foo-bar' -> 'foo_bar' and '-x' -> 'x'
|
||||
var dest = options.dest || null;
|
||||
delete options.dest;
|
||||
|
||||
if (!dest) {
|
||||
var optionStringDest = optionStringsLong.length ? optionStringsLong[0] : optionStrings[0];
|
||||
dest = $$.trimChars(optionStringDest, this.prefixChars);
|
||||
|
||||
if (dest.length === 0) {
|
||||
throw new Error(
|
||||
format('dest= is required for options like "%s"', optionStrings.join(', '))
|
||||
);
|
||||
}
|
||||
dest = dest.replace(/-/g, '_');
|
||||
}
|
||||
|
||||
// return the updated keyword arguments
|
||||
options.dest = dest;
|
||||
options.optionStrings = optionStrings;
|
||||
|
||||
return options;
|
||||
};
|
||||
|
||||
ActionContainer.prototype._popActionClass = function (options, defaultValue) {
|
||||
defaultValue = defaultValue || null;
|
||||
|
||||
var action = (options.action || defaultValue);
|
||||
delete options.action;
|
||||
|
||||
var actionClass = this._registryGet('action', action, action);
|
||||
return actionClass;
|
||||
};
|
||||
|
||||
ActionContainer.prototype._getHandler = function () {
|
||||
var handlerString = this.conflictHandler;
|
||||
var handlerFuncName = '_handleConflict' + $$.capitalize(handlerString);
|
||||
var func = this[handlerFuncName];
|
||||
if (typeof func === 'undefined') {
|
||||
var msg = 'invalid conflict resolution value: ' + handlerString;
|
||||
throw new Error(msg);
|
||||
} else {
|
||||
return func;
|
||||
}
|
||||
};
|
||||
|
||||
ActionContainer.prototype._checkConflict = function (action) {
|
||||
var optionStringActions = this._optionStringActions;
|
||||
var conflictOptionals = [];
|
||||
|
||||
// find all options that conflict with this option
|
||||
// collect pairs, the string, and an existing action that it conflicts with
|
||||
action.optionStrings.forEach(function (optionString) {
|
||||
var conflOptional = optionStringActions[optionString];
|
||||
if (typeof conflOptional !== 'undefined') {
|
||||
conflictOptionals.push([ optionString, conflOptional ]);
|
||||
}
|
||||
});
|
||||
|
||||
if (conflictOptionals.length > 0) {
|
||||
var conflictHandler = this._getHandler();
|
||||
conflictHandler.call(this, action, conflictOptionals);
|
||||
}
|
||||
};
|
||||
|
||||
ActionContainer.prototype._handleConflictError = function (action, conflOptionals) {
|
||||
var conflicts = conflOptionals.map(function (pair) { return pair[0]; });
|
||||
conflicts = conflicts.join(', ');
|
||||
throw argumentErrorHelper(
|
||||
action,
|
||||
format('Conflicting option string(s): %s', conflicts)
|
||||
);
|
||||
};
|
||||
|
||||
ActionContainer.prototype._handleConflictResolve = function (action, conflOptionals) {
|
||||
// remove all conflicting options
|
||||
var self = this;
|
||||
conflOptionals.forEach(function (pair) {
|
||||
var optionString = pair[0];
|
||||
var conflictingAction = pair[1];
|
||||
// remove the conflicting option string
|
||||
var i = conflictingAction.optionStrings.indexOf(optionString);
|
||||
if (i >= 0) {
|
||||
conflictingAction.optionStrings.splice(i, 1);
|
||||
}
|
||||
delete self._optionStringActions[optionString];
|
||||
// if the option now has no option string, remove it from the
|
||||
// container holding it
|
||||
if (conflictingAction.optionStrings.length === 0) {
|
||||
conflictingAction.container._removeAction(conflictingAction);
|
||||
}
|
||||
});
|
||||
};
|
|
@ -0,0 +1,14 @@
|
|||
'use strict';
|
||||
|
||||
module.exports.ArgumentParser = require('./argument_parser.js');
|
||||
module.exports.Namespace = require('./namespace');
|
||||
module.exports.Action = require('./action');
|
||||
module.exports.HelpFormatter = require('./help/formatter.js');
|
||||
module.exports.Const = require('./const.js');
|
||||
|
||||
module.exports.ArgumentDefaultsHelpFormatter =
|
||||
require('./help/added_formatters.js').ArgumentDefaultsHelpFormatter;
|
||||
module.exports.RawDescriptionHelpFormatter =
|
||||
require('./help/added_formatters.js').RawDescriptionHelpFormatter;
|
||||
module.exports.RawTextHelpFormatter =
|
||||
require('./help/added_formatters.js').RawTextHelpFormatter;
|
|
@ -0,0 +1,50 @@
|
|||
'use strict';
|
||||
|
||||
|
||||
var format = require('util').format;
|
||||
|
||||
|
||||
var ERR_CODE = 'ARGError';
|
||||
|
||||
/*:nodoc:*
|
||||
* argumentError(argument, message) -> TypeError
|
||||
* - argument (Object): action with broken argument
|
||||
* - message (String): error message
|
||||
*
|
||||
* Error format helper. An error from creating or using an argument
|
||||
* (optional or positional). The string value of this exception
|
||||
* is the message, augmented with information
|
||||
* about the argument that caused it.
|
||||
*
|
||||
* #####Example
|
||||
*
|
||||
* var argumentErrorHelper = require('./argument/error');
|
||||
* if (conflictOptionals.length > 0) {
|
||||
* throw argumentErrorHelper(
|
||||
* action,
|
||||
* format('Conflicting option string(s): %s', conflictOptionals.join(', '))
|
||||
* );
|
||||
* }
|
||||
*
|
||||
**/
|
||||
module.exports = function (argument, message) {
|
||||
var argumentName = null;
|
||||
var errMessage;
|
||||
var err;
|
||||
|
||||
if (argument.getName) {
|
||||
argumentName = argument.getName();
|
||||
} else {
|
||||
argumentName = '' + argument;
|
||||
}
|
||||
|
||||
if (!argumentName) {
|
||||
errMessage = message;
|
||||
} else {
|
||||
errMessage = format('argument "%s": %s', argumentName, message);
|
||||
}
|
||||
|
||||
err = new TypeError(errMessage);
|
||||
err.code = ERR_CODE;
|
||||
return err;
|
||||
};
|
|
@ -0,0 +1,54 @@
|
|||
/** internal
|
||||
* class MutuallyExclusiveGroup
|
||||
*
|
||||
* Group arguments.
|
||||
* By default, ArgumentParser groups command-line arguments
|
||||
* into “positional arguments” and “optional arguments”
|
||||
* when displaying help messages. When there is a better
|
||||
* conceptual grouping of arguments than this default one,
|
||||
* appropriate groups can be created using the addArgumentGroup() method
|
||||
*
|
||||
* This class inherited from [[ArgumentContainer]]
|
||||
**/
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
var ArgumentGroup = require('./group');
|
||||
|
||||
/**
|
||||
* new MutuallyExclusiveGroup(container, options)
|
||||
* - container (object): main container
|
||||
* - options (object): options.required -> true/false
|
||||
*
|
||||
* `required` could be an argument itself, but making it a property of
|
||||
* the options argument is more consistent with the JS adaptation of the Python)
|
||||
**/
|
||||
var MutuallyExclusiveGroup = module.exports = function MutuallyExclusiveGroup(container, options) {
|
||||
var required;
|
||||
options = options || {};
|
||||
required = options.required || false;
|
||||
ArgumentGroup.call(this, container);
|
||||
this.required = required;
|
||||
|
||||
};
|
||||
util.inherits(MutuallyExclusiveGroup, ArgumentGroup);
|
||||
|
||||
|
||||
MutuallyExclusiveGroup.prototype._addAction = function (action) {
|
||||
var msg;
|
||||
if (action.required) {
|
||||
msg = 'mutually exclusive arguments must be optional';
|
||||
throw new Error(msg);
|
||||
}
|
||||
action = this._container._addAction(action);
|
||||
this._groupActions.push(action);
|
||||
return action;
|
||||
};
|
||||
|
||||
|
||||
MutuallyExclusiveGroup.prototype._removeAction = function (action) {
|
||||
this._container._removeAction(action);
|
||||
this._groupActions.remove(action);
|
||||
};
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/** internal
|
||||
* class ArgumentGroup
|
||||
*
|
||||
* Group arguments.
|
||||
* By default, ArgumentParser groups command-line arguments
|
||||
* into “positional arguments” and “optional arguments”
|
||||
* when displaying help messages. When there is a better
|
||||
* conceptual grouping of arguments than this default one,
|
||||
* appropriate groups can be created using the addArgumentGroup() method
|
||||
*
|
||||
* This class inherited from [[ArgumentContainer]]
|
||||
**/
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
var ActionContainer = require('../action_container');
|
||||
|
||||
|
||||
/**
|
||||
* new ArgumentGroup(container, options)
|
||||
* - container (object): main container
|
||||
* - options (object): hash of group options
|
||||
*
|
||||
* #### options
|
||||
* - **prefixChars** group name prefix
|
||||
* - **argumentDefault** default argument value
|
||||
* - **title** group title
|
||||
* - **description** group description
|
||||
*
|
||||
**/
|
||||
var ArgumentGroup = module.exports = function ArgumentGroup(container, options) {
|
||||
|
||||
options = options || {};
|
||||
|
||||
// add any missing keyword arguments by checking the container
|
||||
options.conflictHandler = (options.conflictHandler || container.conflictHandler);
|
||||
options.prefixChars = (options.prefixChars || container.prefixChars);
|
||||
options.argumentDefault = (options.argumentDefault || container.argumentDefault);
|
||||
|
||||
ActionContainer.call(this, options);
|
||||
|
||||
// group attributes
|
||||
this.title = options.title;
|
||||
this._groupActions = [];
|
||||
|
||||
// share most attributes with the container
|
||||
this._container = container;
|
||||
this._registries = container._registries;
|
||||
this._actions = container._actions;
|
||||
this._optionStringActions = container._optionStringActions;
|
||||
this._defaults = container._defaults;
|
||||
this._hasNegativeNumberOptionals = container._hasNegativeNumberOptionals;
|
||||
this._mutuallyExclusiveGroups = container._mutuallyExclusiveGroups;
|
||||
};
|
||||
util.inherits(ArgumentGroup, ActionContainer);
|
||||
|
||||
|
||||
ArgumentGroup.prototype._addAction = function (action) {
|
||||
// Parent add action
|
||||
action = ActionContainer.prototype._addAction.call(this, action);
|
||||
this._groupActions.push(action);
|
||||
return action;
|
||||
};
|
||||
|
||||
|
||||
ArgumentGroup.prototype._removeAction = function (action) {
|
||||
// Parent remove action
|
||||
ActionContainer.prototype._removeAction.call(this, action);
|
||||
var actionIndex = this._groupActions.indexOf(action);
|
||||
if (actionIndex >= 0) {
|
||||
this._groupActions.splice(actionIndex, 1);
|
||||
}
|
||||
};
|
||||
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// Constants
|
||||
//
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports.EOL = '\n';
|
||||
|
||||
module.exports.SUPPRESS = '==SUPPRESS==';
|
||||
|
||||
module.exports.OPTIONAL = '?';
|
||||
|
||||
module.exports.ZERO_OR_MORE = '*';
|
||||
|
||||
module.exports.ONE_OR_MORE = '+';
|
||||
|
||||
module.exports.PARSER = 'A...';
|
||||
|
||||
module.exports.REMAINDER = '...';
|
||||
|
||||
module.exports._UNRECOGNIZED_ARGS_ATTR = '_unrecognized_args';
|
|
@ -0,0 +1,87 @@
|
|||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
// Constants
|
||||
var c = require('../const');
|
||||
|
||||
var $$ = require('../utils');
|
||||
var HelpFormatter = require('./formatter.js');
|
||||
|
||||
/**
|
||||
* new RawDescriptionHelpFormatter(options)
|
||||
* new ArgumentParser({formatterClass: argparse.RawDescriptionHelpFormatter, ...})
|
||||
*
|
||||
* Help message formatter which adds default values to argument help.
|
||||
*
|
||||
* Only the name of this class is considered a public API. All the methods
|
||||
* provided by the class are considered an implementation detail.
|
||||
**/
|
||||
|
||||
function ArgumentDefaultsHelpFormatter(options) {
|
||||
HelpFormatter.call(this, options);
|
||||
}
|
||||
|
||||
util.inherits(ArgumentDefaultsHelpFormatter, HelpFormatter);
|
||||
|
||||
ArgumentDefaultsHelpFormatter.prototype._getHelpString = function (action) {
|
||||
var help = action.help;
|
||||
if (action.help.indexOf('%(defaultValue)s') === -1) {
|
||||
if (action.defaultValue !== c.SUPPRESS) {
|
||||
var defaulting_nargs = [ c.OPTIONAL, c.ZERO_OR_MORE ];
|
||||
if (action.isOptional() || (defaulting_nargs.indexOf(action.nargs) >= 0)) {
|
||||
help += ' (default: %(defaultValue)s)';
|
||||
}
|
||||
}
|
||||
}
|
||||
return help;
|
||||
};
|
||||
|
||||
module.exports.ArgumentDefaultsHelpFormatter = ArgumentDefaultsHelpFormatter;
|
||||
|
||||
/**
|
||||
* new RawDescriptionHelpFormatter(options)
|
||||
* new ArgumentParser({formatterClass: argparse.RawDescriptionHelpFormatter, ...})
|
||||
*
|
||||
* Help message formatter which retains any formatting in descriptions.
|
||||
*
|
||||
* Only the name of this class is considered a public API. All the methods
|
||||
* provided by the class are considered an implementation detail.
|
||||
**/
|
||||
|
||||
function RawDescriptionHelpFormatter(options) {
|
||||
HelpFormatter.call(this, options);
|
||||
}
|
||||
|
||||
util.inherits(RawDescriptionHelpFormatter, HelpFormatter);
|
||||
|
||||
RawDescriptionHelpFormatter.prototype._fillText = function (text, width, indent) {
|
||||
var lines = text.split('\n');
|
||||
lines = lines.map(function (line) {
|
||||
return $$.trimEnd(indent + line);
|
||||
});
|
||||
return lines.join('\n');
|
||||
};
|
||||
module.exports.RawDescriptionHelpFormatter = RawDescriptionHelpFormatter;
|
||||
|
||||
/**
|
||||
* new RawTextHelpFormatter(options)
|
||||
* new ArgumentParser({formatterClass: argparse.RawTextHelpFormatter, ...})
|
||||
*
|
||||
* Help message formatter which retains formatting of all help text.
|
||||
*
|
||||
* Only the name of this class is considered a public API. All the methods
|
||||
* provided by the class are considered an implementation detail.
|
||||
**/
|
||||
|
||||
function RawTextHelpFormatter(options) {
|
||||
RawDescriptionHelpFormatter.call(this, options);
|
||||
}
|
||||
|
||||
util.inherits(RawTextHelpFormatter, RawDescriptionHelpFormatter);
|
||||
|
||||
RawTextHelpFormatter.prototype._splitLines = function (text) {
|
||||
return text.split('\n');
|
||||
};
|
||||
|
||||
module.exports.RawTextHelpFormatter = RawTextHelpFormatter;
|
|
@ -0,0 +1,795 @@
|
|||
/**
|
||||
* class HelpFormatter
|
||||
*
|
||||
* Formatter for generating usage messages and argument help strings. Only the
|
||||
* name of this class is considered a public API. All the methods provided by
|
||||
* the class are considered an implementation detail.
|
||||
*
|
||||
* Do not call in your code, use this class only for inherits your own forvatter
|
||||
*
|
||||
* ToDo add [additonal formatters][1]
|
||||
*
|
||||
* [1]:http://docs.python.org/dev/library/argparse.html#formatter-class
|
||||
**/
|
||||
'use strict';
|
||||
|
||||
var sprintf = require('sprintf-js').sprintf;
|
||||
|
||||
// Constants
|
||||
var c = require('../const');
|
||||
|
||||
var $$ = require('../utils');
|
||||
|
||||
|
||||
/*:nodoc:* internal
|
||||
* new Support(parent, heding)
|
||||
* - parent (object): parent section
|
||||
* - heading (string): header string
|
||||
*
|
||||
**/
|
||||
function Section(parent, heading) {
|
||||
this._parent = parent;
|
||||
this._heading = heading;
|
||||
this._items = [];
|
||||
}
|
||||
|
||||
/*:nodoc:* internal
|
||||
* Section#addItem(callback) -> Void
|
||||
* - callback (array): tuple with function and args
|
||||
*
|
||||
* Add function for single element
|
||||
**/
|
||||
Section.prototype.addItem = function (callback) {
|
||||
this._items.push(callback);
|
||||
};
|
||||
|
||||
/*:nodoc:* internal
|
||||
* Section#formatHelp(formatter) -> string
|
||||
* - formatter (HelpFormatter): current formatter
|
||||
*
|
||||
* Form help section string
|
||||
*
|
||||
**/
|
||||
Section.prototype.formatHelp = function (formatter) {
|
||||
var itemHelp, heading;
|
||||
|
||||
// format the indented section
|
||||
if (this._parent) {
|
||||
formatter._indent();
|
||||
}
|
||||
|
||||
itemHelp = this._items.map(function (item) {
|
||||
var obj, func, args;
|
||||
|
||||
obj = formatter;
|
||||
func = item[0];
|
||||
args = item[1];
|
||||
return func.apply(obj, args);
|
||||
});
|
||||
itemHelp = formatter._joinParts(itemHelp);
|
||||
|
||||
if (this._parent) {
|
||||
formatter._dedent();
|
||||
}
|
||||
|
||||
// return nothing if the section was empty
|
||||
if (!itemHelp) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// add the heading if the section was non-empty
|
||||
heading = '';
|
||||
if (this._heading && this._heading !== c.SUPPRESS) {
|
||||
var currentIndent = formatter.currentIndent;
|
||||
heading = $$.repeat(' ', currentIndent) + this._heading + ':' + c.EOL;
|
||||
}
|
||||
|
||||
// join the section-initialize newline, the heading and the help
|
||||
return formatter._joinParts([ c.EOL, heading, itemHelp, c.EOL ]);
|
||||
};
|
||||
|
||||
/**
|
||||
* new HelpFormatter(options)
|
||||
*
|
||||
* #### Options:
|
||||
* - `prog`: program name
|
||||
* - `indentIncriment`: indent step, default value 2
|
||||
* - `maxHelpPosition`: max help position, default value = 24
|
||||
* - `width`: line width
|
||||
*
|
||||
**/
|
||||
var HelpFormatter = module.exports = function HelpFormatter(options) {
|
||||
options = options || {};
|
||||
|
||||
this._prog = options.prog;
|
||||
|
||||
this._maxHelpPosition = options.maxHelpPosition || 24;
|
||||
this._width = (options.width || ((process.env.COLUMNS || 80) - 2));
|
||||
|
||||
this._currentIndent = 0;
|
||||
this._indentIncriment = options.indentIncriment || 2;
|
||||
this._level = 0;
|
||||
this._actionMaxLength = 0;
|
||||
|
||||
this._rootSection = new Section(null);
|
||||
this._currentSection = this._rootSection;
|
||||
|
||||
this._whitespaceMatcher = new RegExp('\\s+', 'g');
|
||||
this._longBreakMatcher = new RegExp(c.EOL + c.EOL + c.EOL + '+', 'g');
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._indent = function () {
|
||||
this._currentIndent += this._indentIncriment;
|
||||
this._level += 1;
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._dedent = function () {
|
||||
this._currentIndent -= this._indentIncriment;
|
||||
this._level -= 1;
|
||||
if (this._currentIndent < 0) {
|
||||
throw new Error('Indent decreased below 0.');
|
||||
}
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._addItem = function (func, args) {
|
||||
this._currentSection.addItem([ func, args ]);
|
||||
};
|
||||
|
||||
//
|
||||
// Message building methods
|
||||
//
|
||||
|
||||
/**
|
||||
* HelpFormatter#startSection(heading) -> Void
|
||||
* - heading (string): header string
|
||||
*
|
||||
* Start new help section
|
||||
*
|
||||
* See alse [code example][1]
|
||||
*
|
||||
* ##### Example
|
||||
*
|
||||
* formatter.startSection(actionGroup.title);
|
||||
* formatter.addText(actionGroup.description);
|
||||
* formatter.addArguments(actionGroup._groupActions);
|
||||
* formatter.endSection();
|
||||
*
|
||||
**/
|
||||
HelpFormatter.prototype.startSection = function (heading) {
|
||||
this._indent();
|
||||
var section = new Section(this._currentSection, heading);
|
||||
var func = section.formatHelp.bind(section);
|
||||
this._addItem(func, [ this ]);
|
||||
this._currentSection = section;
|
||||
};
|
||||
|
||||
/**
|
||||
* HelpFormatter#endSection -> Void
|
||||
*
|
||||
* End help section
|
||||
*
|
||||
* ##### Example
|
||||
*
|
||||
* formatter.startSection(actionGroup.title);
|
||||
* formatter.addText(actionGroup.description);
|
||||
* formatter.addArguments(actionGroup._groupActions);
|
||||
* formatter.endSection();
|
||||
**/
|
||||
HelpFormatter.prototype.endSection = function () {
|
||||
this._currentSection = this._currentSection._parent;
|
||||
this._dedent();
|
||||
};
|
||||
|
||||
/**
|
||||
* HelpFormatter#addText(text) -> Void
|
||||
* - text (string): plain text
|
||||
*
|
||||
* Add plain text into current section
|
||||
*
|
||||
* ##### Example
|
||||
*
|
||||
* formatter.startSection(actionGroup.title);
|
||||
* formatter.addText(actionGroup.description);
|
||||
* formatter.addArguments(actionGroup._groupActions);
|
||||
* formatter.endSection();
|
||||
*
|
||||
**/
|
||||
HelpFormatter.prototype.addText = function (text) {
|
||||
if (text && text !== c.SUPPRESS) {
|
||||
this._addItem(this._formatText, [ text ]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* HelpFormatter#addUsage(usage, actions, groups, prefix) -> Void
|
||||
* - usage (string): usage text
|
||||
* - actions (array): actions list
|
||||
* - groups (array): groups list
|
||||
* - prefix (string): usage prefix
|
||||
*
|
||||
* Add usage data into current section
|
||||
*
|
||||
* ##### Example
|
||||
*
|
||||
* formatter.addUsage(this.usage, this._actions, []);
|
||||
* return formatter.formatHelp();
|
||||
*
|
||||
**/
|
||||
HelpFormatter.prototype.addUsage = function (usage, actions, groups, prefix) {
|
||||
if (usage !== c.SUPPRESS) {
|
||||
this._addItem(this._formatUsage, [ usage, actions, groups, prefix ]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* HelpFormatter#addArgument(action) -> Void
|
||||
* - action (object): action
|
||||
*
|
||||
* Add argument into current section
|
||||
*
|
||||
* Single variant of [[HelpFormatter#addArguments]]
|
||||
**/
|
||||
HelpFormatter.prototype.addArgument = function (action) {
|
||||
if (action.help !== c.SUPPRESS) {
|
||||
var self = this;
|
||||
|
||||
// find all invocations
|
||||
var invocations = [ this._formatActionInvocation(action) ];
|
||||
var invocationLength = invocations[0].length;
|
||||
|
||||
var actionLength;
|
||||
|
||||
if (action._getSubactions) {
|
||||
this._indent();
|
||||
action._getSubactions().forEach(function (subaction) {
|
||||
|
||||
var invocationNew = self._formatActionInvocation(subaction);
|
||||
invocations.push(invocationNew);
|
||||
invocationLength = Math.max(invocationLength, invocationNew.length);
|
||||
|
||||
});
|
||||
this._dedent();
|
||||
}
|
||||
|
||||
// update the maximum item length
|
||||
actionLength = invocationLength + this._currentIndent;
|
||||
this._actionMaxLength = Math.max(this._actionMaxLength, actionLength);
|
||||
|
||||
// add the item to the list
|
||||
this._addItem(this._formatAction, [ action ]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* HelpFormatter#addArguments(actions) -> Void
|
||||
* - actions (array): actions list
|
||||
*
|
||||
* Mass add arguments into current section
|
||||
*
|
||||
* ##### Example
|
||||
*
|
||||
* formatter.startSection(actionGroup.title);
|
||||
* formatter.addText(actionGroup.description);
|
||||
* formatter.addArguments(actionGroup._groupActions);
|
||||
* formatter.endSection();
|
||||
*
|
||||
**/
|
||||
HelpFormatter.prototype.addArguments = function (actions) {
|
||||
var self = this;
|
||||
actions.forEach(function (action) {
|
||||
self.addArgument(action);
|
||||
});
|
||||
};
|
||||
|
||||
//
|
||||
// Help-formatting methods
|
||||
//
|
||||
|
||||
/**
|
||||
* HelpFormatter#formatHelp -> string
|
||||
*
|
||||
* Format help
|
||||
*
|
||||
* ##### Example
|
||||
*
|
||||
* formatter.addText(this.epilog);
|
||||
* return formatter.formatHelp();
|
||||
*
|
||||
**/
|
||||
HelpFormatter.prototype.formatHelp = function () {
|
||||
var help = this._rootSection.formatHelp(this);
|
||||
if (help) {
|
||||
help = help.replace(this._longBreakMatcher, c.EOL + c.EOL);
|
||||
help = $$.trimChars(help, c.EOL) + c.EOL;
|
||||
}
|
||||
return help;
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._joinParts = function (partStrings) {
|
||||
return partStrings.filter(function (part) {
|
||||
return (part && part !== c.SUPPRESS);
|
||||
}).join('');
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._formatUsage = function (usage, actions, groups, prefix) {
|
||||
if (!prefix && typeof prefix !== 'string') {
|
||||
prefix = 'usage: ';
|
||||
}
|
||||
|
||||
actions = actions || [];
|
||||
groups = groups || [];
|
||||
|
||||
|
||||
// if usage is specified, use that
|
||||
if (usage) {
|
||||
usage = sprintf(usage, { prog: this._prog });
|
||||
|
||||
// if no optionals or positionals are available, usage is just prog
|
||||
} else if (!usage && actions.length === 0) {
|
||||
usage = this._prog;
|
||||
|
||||
// if optionals and positionals are available, calculate usage
|
||||
} else if (!usage) {
|
||||
var prog = this._prog;
|
||||
var optionals = [];
|
||||
var positionals = [];
|
||||
var actionUsage;
|
||||
var textWidth;
|
||||
|
||||
// split optionals from positionals
|
||||
actions.forEach(function (action) {
|
||||
if (action.isOptional()) {
|
||||
optionals.push(action);
|
||||
} else {
|
||||
positionals.push(action);
|
||||
}
|
||||
});
|
||||
|
||||
// build full usage string
|
||||
actionUsage = this._formatActionsUsage([].concat(optionals, positionals), groups);
|
||||
usage = [ prog, actionUsage ].join(' ');
|
||||
|
||||
// wrap the usage parts if it's too long
|
||||
textWidth = this._width - this._currentIndent;
|
||||
if ((prefix.length + usage.length) > textWidth) {
|
||||
|
||||
// break usage into wrappable parts
|
||||
var regexpPart = new RegExp('\\(.*?\\)+|\\[.*?\\]+|\\S+', 'g');
|
||||
var optionalUsage = this._formatActionsUsage(optionals, groups);
|
||||
var positionalUsage = this._formatActionsUsage(positionals, groups);
|
||||
|
||||
|
||||
var optionalParts = optionalUsage.match(regexpPart);
|
||||
var positionalParts = positionalUsage.match(regexpPart) || [];
|
||||
|
||||
if (optionalParts.join(' ') !== optionalUsage) {
|
||||
throw new Error('assert "optionalParts.join(\' \') === optionalUsage"');
|
||||
}
|
||||
if (positionalParts.join(' ') !== positionalUsage) {
|
||||
throw new Error('assert "positionalParts.join(\' \') === positionalUsage"');
|
||||
}
|
||||
|
||||
// helper for wrapping lines
|
||||
/*eslint-disable func-style*/ // node 0.10 compat
|
||||
var _getLines = function (parts, indent, prefix) {
|
||||
var lines = [];
|
||||
var line = [];
|
||||
|
||||
var lineLength = prefix ? prefix.length - 1 : indent.length - 1;
|
||||
|
||||
parts.forEach(function (part) {
|
||||
if (lineLength + 1 + part.length > textWidth) {
|
||||
lines.push(indent + line.join(' '));
|
||||
line = [];
|
||||
lineLength = indent.length - 1;
|
||||
}
|
||||
line.push(part);
|
||||
lineLength += part.length + 1;
|
||||
});
|
||||
|
||||
if (line) {
|
||||
lines.push(indent + line.join(' '));
|
||||
}
|
||||
if (prefix) {
|
||||
lines[0] = lines[0].substr(indent.length);
|
||||
}
|
||||
return lines;
|
||||
};
|
||||
|
||||
var lines, indent, parts;
|
||||
// if prog is short, follow it with optionals or positionals
|
||||
if (prefix.length + prog.length <= 0.75 * textWidth) {
|
||||
indent = $$.repeat(' ', (prefix.length + prog.length + 1));
|
||||
if (optionalParts) {
|
||||
lines = [].concat(
|
||||
_getLines([ prog ].concat(optionalParts), indent, prefix),
|
||||
_getLines(positionalParts, indent)
|
||||
);
|
||||
} else if (positionalParts) {
|
||||
lines = _getLines([ prog ].concat(positionalParts), indent, prefix);
|
||||
} else {
|
||||
lines = [ prog ];
|
||||
}
|
||||
|
||||
// if prog is long, put it on its own line
|
||||
} else {
|
||||
indent = $$.repeat(' ', prefix.length);
|
||||
parts = optionalParts.concat(positionalParts);
|
||||
lines = _getLines(parts, indent);
|
||||
if (lines.length > 1) {
|
||||
lines = [].concat(
|
||||
_getLines(optionalParts, indent),
|
||||
_getLines(positionalParts, indent)
|
||||
);
|
||||
}
|
||||
lines = [ prog ].concat(lines);
|
||||
}
|
||||
// join lines into usage
|
||||
usage = lines.join(c.EOL);
|
||||
}
|
||||
}
|
||||
|
||||
// prefix with 'usage:'
|
||||
return prefix + usage + c.EOL + c.EOL;
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._formatActionsUsage = function (actions, groups) {
|
||||
// find group indices and identify actions in groups
|
||||
var groupActions = [];
|
||||
var inserts = [];
|
||||
var self = this;
|
||||
|
||||
groups.forEach(function (group) {
|
||||
var end;
|
||||
var i;
|
||||
|
||||
var start = actions.indexOf(group._groupActions[0]);
|
||||
if (start >= 0) {
|
||||
end = start + group._groupActions.length;
|
||||
|
||||
//if (actions.slice(start, end) === group._groupActions) {
|
||||
if ($$.arrayEqual(actions.slice(start, end), group._groupActions)) {
|
||||
group._groupActions.forEach(function (action) {
|
||||
groupActions.push(action);
|
||||
});
|
||||
|
||||
if (!group.required) {
|
||||
if (inserts[start]) {
|
||||
inserts[start] += ' [';
|
||||
} else {
|
||||
inserts[start] = '[';
|
||||
}
|
||||
inserts[end] = ']';
|
||||
} else {
|
||||
if (inserts[start]) {
|
||||
inserts[start] += ' (';
|
||||
} else {
|
||||
inserts[start] = '(';
|
||||
}
|
||||
inserts[end] = ')';
|
||||
}
|
||||
for (i = start + 1; i < end; i += 1) {
|
||||
inserts[i] = '|';
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// collect all actions format strings
|
||||
var parts = [];
|
||||
|
||||
actions.forEach(function (action, actionIndex) {
|
||||
var part;
|
||||
var optionString;
|
||||
var argsDefault;
|
||||
var argsString;
|
||||
|
||||
// suppressed arguments are marked with None
|
||||
// remove | separators for suppressed arguments
|
||||
if (action.help === c.SUPPRESS) {
|
||||
parts.push(null);
|
||||
if (inserts[actionIndex] === '|') {
|
||||
inserts.splice(actionIndex, actionIndex);
|
||||
} else if (inserts[actionIndex + 1] === '|') {
|
||||
inserts.splice(actionIndex + 1, actionIndex + 1);
|
||||
}
|
||||
|
||||
// produce all arg strings
|
||||
} else if (!action.isOptional()) {
|
||||
part = self._formatArgs(action, action.dest);
|
||||
|
||||
// if it's in a group, strip the outer []
|
||||
if (groupActions.indexOf(action) >= 0) {
|
||||
if (part[0] === '[' && part[part.length - 1] === ']') {
|
||||
part = part.slice(1, -1);
|
||||
}
|
||||
}
|
||||
// add the action string to the list
|
||||
parts.push(part);
|
||||
|
||||
// produce the first way to invoke the option in brackets
|
||||
} else {
|
||||
optionString = action.optionStrings[0];
|
||||
|
||||
// if the Optional doesn't take a value, format is: -s or --long
|
||||
if (action.nargs === 0) {
|
||||
part = '' + optionString;
|
||||
|
||||
// if the Optional takes a value, format is: -s ARGS or --long ARGS
|
||||
} else {
|
||||
argsDefault = action.dest.toUpperCase();
|
||||
argsString = self._formatArgs(action, argsDefault);
|
||||
part = optionString + ' ' + argsString;
|
||||
}
|
||||
// make it look optional if it's not required or in a group
|
||||
if (!action.required && groupActions.indexOf(action) < 0) {
|
||||
part = '[' + part + ']';
|
||||
}
|
||||
// add the action string to the list
|
||||
parts.push(part);
|
||||
}
|
||||
});
|
||||
|
||||
// insert things at the necessary indices
|
||||
for (var i = inserts.length - 1; i >= 0; --i) {
|
||||
if (inserts[i] !== null) {
|
||||
parts.splice(i, 0, inserts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// join all the action items with spaces
|
||||
var text = parts.filter(function (part) {
|
||||
return !!part;
|
||||
}).join(' ');
|
||||
|
||||
// clean up separators for mutually exclusive groups
|
||||
text = text.replace(/([\[(]) /g, '$1'); // remove spaces
|
||||
text = text.replace(/ ([\])])/g, '$1');
|
||||
text = text.replace(/\[ *\]/g, ''); // remove empty groups
|
||||
text = text.replace(/\( *\)/g, '');
|
||||
text = text.replace(/\(([^|]*)\)/g, '$1'); // remove () from single action groups
|
||||
|
||||
text = text.trim();
|
||||
|
||||
// return the text
|
||||
return text;
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._formatText = function (text) {
|
||||
text = sprintf(text, { prog: this._prog });
|
||||
var textWidth = this._width - this._currentIndent;
|
||||
var indentIncriment = $$.repeat(' ', this._currentIndent);
|
||||
return this._fillText(text, textWidth, indentIncriment) + c.EOL + c.EOL;
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._formatAction = function (action) {
|
||||
var self = this;
|
||||
|
||||
var helpText;
|
||||
var helpLines;
|
||||
var parts;
|
||||
var indentFirst;
|
||||
|
||||
// determine the required width and the entry label
|
||||
var helpPosition = Math.min(this._actionMaxLength + 2, this._maxHelpPosition);
|
||||
var helpWidth = this._width - helpPosition;
|
||||
var actionWidth = helpPosition - this._currentIndent - 2;
|
||||
var actionHeader = this._formatActionInvocation(action);
|
||||
|
||||
// no help; start on same line and add a final newline
|
||||
if (!action.help) {
|
||||
actionHeader = $$.repeat(' ', this._currentIndent) + actionHeader + c.EOL;
|
||||
|
||||
// short action name; start on the same line and pad two spaces
|
||||
} else if (actionHeader.length <= actionWidth) {
|
||||
actionHeader = $$.repeat(' ', this._currentIndent) +
|
||||
actionHeader +
|
||||
' ' +
|
||||
$$.repeat(' ', actionWidth - actionHeader.length);
|
||||
indentFirst = 0;
|
||||
|
||||
// long action name; start on the next line
|
||||
} else {
|
||||
actionHeader = $$.repeat(' ', this._currentIndent) + actionHeader + c.EOL;
|
||||
indentFirst = helpPosition;
|
||||
}
|
||||
|
||||
// collect the pieces of the action help
|
||||
parts = [ actionHeader ];
|
||||
|
||||
// if there was help for the action, add lines of help text
|
||||
if (action.help) {
|
||||
helpText = this._expandHelp(action);
|
||||
helpLines = this._splitLines(helpText, helpWidth);
|
||||
parts.push($$.repeat(' ', indentFirst) + helpLines[0] + c.EOL);
|
||||
helpLines.slice(1).forEach(function (line) {
|
||||
parts.push($$.repeat(' ', helpPosition) + line + c.EOL);
|
||||
});
|
||||
|
||||
// or add a newline if the description doesn't end with one
|
||||
} else if (actionHeader.charAt(actionHeader.length - 1) !== c.EOL) {
|
||||
parts.push(c.EOL);
|
||||
}
|
||||
// if there are any sub-actions, add their help as well
|
||||
if (action._getSubactions) {
|
||||
this._indent();
|
||||
action._getSubactions().forEach(function (subaction) {
|
||||
parts.push(self._formatAction(subaction));
|
||||
});
|
||||
this._dedent();
|
||||
}
|
||||
// return a single string
|
||||
return this._joinParts(parts);
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._formatActionInvocation = function (action) {
|
||||
if (!action.isOptional()) {
|
||||
var format_func = this._metavarFormatter(action, action.dest);
|
||||
var metavars = format_func(1);
|
||||
return metavars[0];
|
||||
}
|
||||
|
||||
var parts = [];
|
||||
var argsDefault;
|
||||
var argsString;
|
||||
|
||||
// if the Optional doesn't take a value, format is: -s, --long
|
||||
if (action.nargs === 0) {
|
||||
parts = parts.concat(action.optionStrings);
|
||||
|
||||
// if the Optional takes a value, format is: -s ARGS, --long ARGS
|
||||
} else {
|
||||
argsDefault = action.dest.toUpperCase();
|
||||
argsString = this._formatArgs(action, argsDefault);
|
||||
action.optionStrings.forEach(function (optionString) {
|
||||
parts.push(optionString + ' ' + argsString);
|
||||
});
|
||||
}
|
||||
return parts.join(', ');
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._metavarFormatter = function (action, metavarDefault) {
|
||||
var result;
|
||||
|
||||
if (action.metavar || action.metavar === '') {
|
||||
result = action.metavar;
|
||||
} else if (action.choices) {
|
||||
var choices = action.choices;
|
||||
|
||||
if (typeof choices === 'string') {
|
||||
choices = choices.split('').join(', ');
|
||||
} else if (Array.isArray(choices)) {
|
||||
choices = choices.join(',');
|
||||
} else {
|
||||
choices = Object.keys(choices).join(',');
|
||||
}
|
||||
result = '{' + choices + '}';
|
||||
} else {
|
||||
result = metavarDefault;
|
||||
}
|
||||
|
||||
return function (size) {
|
||||
if (Array.isArray(result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
var metavars = [];
|
||||
for (var i = 0; i < size; i += 1) {
|
||||
metavars.push(result);
|
||||
}
|
||||
return metavars;
|
||||
};
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._formatArgs = function (action, metavarDefault) {
|
||||
var result;
|
||||
var metavars;
|
||||
|
||||
var buildMetavar = this._metavarFormatter(action, metavarDefault);
|
||||
|
||||
switch (action.nargs) {
|
||||
/*eslint-disable no-undefined*/
|
||||
case undefined:
|
||||
case null:
|
||||
metavars = buildMetavar(1);
|
||||
result = '' + metavars[0];
|
||||
break;
|
||||
case c.OPTIONAL:
|
||||
metavars = buildMetavar(1);
|
||||
result = '[' + metavars[0] + ']';
|
||||
break;
|
||||
case c.ZERO_OR_MORE:
|
||||
metavars = buildMetavar(2);
|
||||
result = '[' + metavars[0] + ' [' + metavars[1] + ' ...]]';
|
||||
break;
|
||||
case c.ONE_OR_MORE:
|
||||
metavars = buildMetavar(2);
|
||||
result = '' + metavars[0] + ' [' + metavars[1] + ' ...]';
|
||||
break;
|
||||
case c.REMAINDER:
|
||||
result = '...';
|
||||
break;
|
||||
case c.PARSER:
|
||||
metavars = buildMetavar(1);
|
||||
result = metavars[0] + ' ...';
|
||||
break;
|
||||
default:
|
||||
metavars = buildMetavar(action.nargs);
|
||||
result = metavars.join(' ');
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._expandHelp = function (action) {
|
||||
var params = { prog: this._prog };
|
||||
|
||||
Object.keys(action).forEach(function (actionProperty) {
|
||||
var actionValue = action[actionProperty];
|
||||
|
||||
if (actionValue !== c.SUPPRESS) {
|
||||
params[actionProperty] = actionValue;
|
||||
}
|
||||
});
|
||||
|
||||
if (params.choices) {
|
||||
if (typeof params.choices === 'string') {
|
||||
params.choices = params.choices.split('').join(', ');
|
||||
} else if (Array.isArray(params.choices)) {
|
||||
params.choices = params.choices.join(', ');
|
||||
} else {
|
||||
params.choices = Object.keys(params.choices).join(', ');
|
||||
}
|
||||
}
|
||||
|
||||
return sprintf(this._getHelpString(action), params);
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._splitLines = function (text, width) {
|
||||
var lines = [];
|
||||
var delimiters = [ ' ', '.', ',', '!', '?' ];
|
||||
var re = new RegExp('[' + delimiters.join('') + '][^' + delimiters.join('') + ']*$');
|
||||
|
||||
text = text.replace(/[\n\|\t]/g, ' ');
|
||||
|
||||
text = text.trim();
|
||||
text = text.replace(this._whitespaceMatcher, ' ');
|
||||
|
||||
// Wraps the single paragraph in text (a string) so every line
|
||||
// is at most width characters long.
|
||||
text.split(c.EOL).forEach(function (line) {
|
||||
if (width >= line.length) {
|
||||
lines.push(line);
|
||||
return;
|
||||
}
|
||||
|
||||
var wrapStart = 0;
|
||||
var wrapEnd = width;
|
||||
var delimiterIndex = 0;
|
||||
while (wrapEnd <= line.length) {
|
||||
if (wrapEnd !== line.length && delimiters.indexOf(line[wrapEnd] < -1)) {
|
||||
delimiterIndex = (re.exec(line.substring(wrapStart, wrapEnd)) || {}).index;
|
||||
wrapEnd = wrapStart + delimiterIndex + 1;
|
||||
}
|
||||
lines.push(line.substring(wrapStart, wrapEnd));
|
||||
wrapStart = wrapEnd;
|
||||
wrapEnd += width;
|
||||
}
|
||||
if (wrapStart < line.length) {
|
||||
lines.push(line.substring(wrapStart, wrapEnd));
|
||||
}
|
||||
});
|
||||
|
||||
return lines;
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._fillText = function (text, width, indent) {
|
||||
var lines = this._splitLines(text, width);
|
||||
lines = lines.map(function (line) {
|
||||
return indent + line;
|
||||
});
|
||||
return lines.join(c.EOL);
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._getHelpString = function (action) {
|
||||
return action.help;
|
||||
};
|
|
@ -0,0 +1,76 @@
|
|||
/**
|
||||
* class Namespace
|
||||
*
|
||||
* Simple object for storing attributes. Implements equality by attribute names
|
||||
* and values, and provides a simple string representation.
|
||||
*
|
||||
* See also [original guide][1]
|
||||
*
|
||||
* [1]:http://docs.python.org/dev/library/argparse.html#the-namespace-object
|
||||
**/
|
||||
'use strict';
|
||||
|
||||
var $$ = require('./utils');
|
||||
|
||||
/**
|
||||
* new Namespace(options)
|
||||
* - options(object): predefined propertis for result object
|
||||
*
|
||||
**/
|
||||
var Namespace = module.exports = function Namespace(options) {
|
||||
$$.extend(this, options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Namespace#isset(key) -> Boolean
|
||||
* - key (string|number): property name
|
||||
*
|
||||
* Tells whenever `namespace` contains given `key` or not.
|
||||
**/
|
||||
Namespace.prototype.isset = function (key) {
|
||||
return $$.has(this, key);
|
||||
};
|
||||
|
||||
/**
|
||||
* Namespace#set(key, value) -> self
|
||||
* -key (string|number|object): propery name
|
||||
* -value (mixed): new property value
|
||||
*
|
||||
* Set the property named key with value.
|
||||
* If key object then set all key properties to namespace object
|
||||
**/
|
||||
Namespace.prototype.set = function (key, value) {
|
||||
if (typeof (key) === 'object') {
|
||||
$$.extend(this, key);
|
||||
} else {
|
||||
this[key] = value;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Namespace#get(key, defaultValue) -> mixed
|
||||
* - key (string|number): property name
|
||||
* - defaultValue (mixed): default value
|
||||
*
|
||||
* Return the property key or defaulValue if not set
|
||||
**/
|
||||
Namespace.prototype.get = function (key, defaultValue) {
|
||||
return !this[key] ? defaultValue : this[key];
|
||||
};
|
||||
|
||||
/**
|
||||
* Namespace#unset(key, defaultValue) -> mixed
|
||||
* - key (string|number): property name
|
||||
* - defaultValue (mixed): default value
|
||||
*
|
||||
* Return data[key](and delete it) or defaultValue
|
||||
**/
|
||||
Namespace.prototype.unset = function (key, defaultValue) {
|
||||
var value = this[key];
|
||||
if (value !== null) {
|
||||
delete this[key];
|
||||
return value;
|
||||
}
|
||||
return defaultValue;
|
||||
};
|
|
@ -0,0 +1,57 @@
|
|||
'use strict';
|
||||
|
||||
exports.repeat = function (str, num) {
|
||||
var result = '';
|
||||
for (var i = 0; i < num; i++) { result += str; }
|
||||
return result;
|
||||
};
|
||||
|
||||
exports.arrayEqual = function (a, b) {
|
||||
if (a.length !== b.length) { return false; }
|
||||
for (var i = 0; i < a.length; i++) {
|
||||
if (a[i] !== b[i]) { return false; }
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
exports.trimChars = function (str, chars) {
|
||||
var start = 0;
|
||||
var end = str.length - 1;
|
||||
while (chars.indexOf(str.charAt(start)) >= 0) { start++; }
|
||||
while (chars.indexOf(str.charAt(end)) >= 0) { end--; }
|
||||
return str.slice(start, end + 1);
|
||||
};
|
||||
|
||||
exports.capitalize = function (str) {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
};
|
||||
|
||||
exports.arrayUnion = function () {
|
||||
var result = [];
|
||||
for (var i = 0, values = {}; i < arguments.length; i++) {
|
||||
var arr = arguments[i];
|
||||
for (var j = 0; j < arr.length; j++) {
|
||||
if (!values[arr[j]]) {
|
||||
values[arr[j]] = true;
|
||||
result.push(arr[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
function has(obj, key) {
|
||||
return Object.prototype.hasOwnProperty.call(obj, key);
|
||||
}
|
||||
|
||||
exports.has = has;
|
||||
|
||||
exports.extend = function (dest, src) {
|
||||
for (var i in src) {
|
||||
if (has(src, i)) { dest[i] = src[i]; }
|
||||
}
|
||||
};
|
||||
|
||||
exports.trimEnd = function (str) {
|
||||
return str.replace(/\s+$/g, '');
|
||||
};
|
|
@ -0,0 +1,73 @@
|
|||
{
|
||||
"_args": [
|
||||
[
|
||||
"argparse@1.0.10",
|
||||
"D:\\Repos\\security-code-analysis-action"
|
||||
]
|
||||
],
|
||||
"_from": "argparse@1.0.10",
|
||||
"_id": "argparse@1.0.10",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
|
||||
"_location": "/argparse",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "version",
|
||||
"registry": true,
|
||||
"raw": "argparse@1.0.10",
|
||||
"name": "argparse",
|
||||
"escapedName": "argparse",
|
||||
"rawSpec": "1.0.10",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "1.0.10"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/js-yaml"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
||||
"_spec": "1.0.10",
|
||||
"_where": "D:\\Repos\\security-code-analysis-action",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nodeca/argparse/issues"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Eugene Shkuropat"
|
||||
},
|
||||
{
|
||||
"name": "Paul Jacobson"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"sprintf-js": "~1.0.2"
|
||||
},
|
||||
"description": "Very powerful CLI arguments parser. Native port of argparse - python's options parsing library",
|
||||
"devDependencies": {
|
||||
"eslint": "^2.13.1",
|
||||
"istanbul": "^0.4.5",
|
||||
"mocha": "^3.1.0",
|
||||
"ndoc": "^5.0.1"
|
||||
},
|
||||
"files": [
|
||||
"index.js",
|
||||
"lib/"
|
||||
],
|
||||
"homepage": "https://github.com/nodeca/argparse#readme",
|
||||
"keywords": [
|
||||
"cli",
|
||||
"parser",
|
||||
"argparse",
|
||||
"option",
|
||||
"args"
|
||||
],
|
||||
"license": "MIT",
|
||||
"name": "argparse",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/nodeca/argparse.git"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "make test"
|
||||
},
|
||||
"version": "1.0.10"
|
||||
}
|
|
@ -0,0 +1,235 @@
|
|||
2018-06-17: Version 4.0.1
|
||||
|
||||
* Fix parsing async get/set in a class (issue 1861, 1875)
|
||||
* Account for different return statement argument (issue 1829, 1897, 1928)
|
||||
* Correct the handling of HTML comment when parsing a module (issue 1841)
|
||||
* Fix incorrect parse async with proto-identifier-shorthand (issue 1847)
|
||||
* Fix negative column in binary expression (issue 1844)
|
||||
* Fix incorrect YieldExpression in object methods (issue 1834)
|
||||
* Various documentation fixes
|
||||
|
||||
2017-06-10: Version 4.0.0
|
||||
|
||||
* Support ES2017 async function and await expression (issue 1079)
|
||||
* Support ES2017 trailing commas in function parameters (issue 1550)
|
||||
* Explicitly distinguish parsing a module vs a script (issue 1576)
|
||||
* Fix JSX non-empty container (issue 1786)
|
||||
* Allow JSX element in a yield expression (issue 1765)
|
||||
* Allow `in` expression in a concise body with a function body (issue 1793)
|
||||
* Setter function argument must not be a rest parameter (issue 1693)
|
||||
* Limit strict mode directive to functions with a simple parameter list (issue 1677)
|
||||
* Prohibit any escape sequence in a reserved word (issue 1612)
|
||||
* Only permit hex digits in hex escape sequence (issue 1619)
|
||||
* Prohibit labelled class/generator/function declaration (issue 1484)
|
||||
* Limit function declaration as if statement clause only in non-strict mode (issue 1657)
|
||||
* Tolerate missing ) in a with and do-while statement (issue 1481)
|
||||
|
||||
2016-12-22: Version 3.1.3
|
||||
|
||||
* Support binding patterns as rest element (issue 1681)
|
||||
* Account for different possible arguments of a yield expression (issue 1469)
|
||||
|
||||
2016-11-24: Version 3.1.2
|
||||
|
||||
* Ensure that import specifier is more restrictive (issue 1615)
|
||||
* Fix duplicated JSX tokens (issue 1613)
|
||||
* Scan template literal in a JSX expression container (issue 1622)
|
||||
* Improve XHTML entity scanning in JSX (issue 1629)
|
||||
|
||||
2016-10-31: Version 3.1.1
|
||||
|
||||
* Fix assignment expression problem in an export declaration (issue 1596)
|
||||
* Fix incorrect tokenization of hex digits (issue 1605)
|
||||
|
||||
2016-10-09: Version 3.1.0
|
||||
|
||||
* Do not implicitly collect comments when comment attachment is specified (issue 1553)
|
||||
* Fix incorrect handling of duplicated proto shorthand fields (issue 1485)
|
||||
* Prohibit initialization in some variants of for statements (issue 1309, 1561)
|
||||
* Fix incorrect parsing of export specifier (issue 1578)
|
||||
* Fix ESTree compatibility for assignment pattern (issue 1575)
|
||||
|
||||
2016-09-03: Version 3.0.0
|
||||
|
||||
* Support ES2016 exponentiation expression (issue 1490)
|
||||
* Support JSX syntax (issue 1467)
|
||||
* Use the latest Unicode 8.0 (issue 1475)
|
||||
* Add the support for syntax node delegate (issue 1435)
|
||||
* Fix ESTree compatibility on meta property (issue 1338)
|
||||
* Fix ESTree compatibility on default parameter value (issue 1081)
|
||||
* Fix ESTree compatibility on try handler (issue 1030)
|
||||
|
||||
2016-08-23: Version 2.7.3
|
||||
|
||||
* Fix tokenizer confusion with a comment (issue 1493, 1516)
|
||||
|
||||
2016-02-02: Version 2.7.2
|
||||
|
||||
* Fix out-of-bound error location in an invalid string literal (issue 1457)
|
||||
* Fix shorthand object destructuring defaults in variable declarations (issue 1459)
|
||||
|
||||
2015-12-10: Version 2.7.1
|
||||
|
||||
* Do not allow trailing comma in a variable declaration (issue 1360)
|
||||
* Fix assignment to `let` in non-strict mode (issue 1376)
|
||||
* Fix missing delegate property in YieldExpression (issue 1407)
|
||||
|
||||
2015-10-22: Version 2.7.0
|
||||
|
||||
* Fix the handling of semicolon in a break statement (issue 1044)
|
||||
* Run the test suite with major web browsers (issue 1259, 1317)
|
||||
* Allow `let` as an identifier in non-strict mode (issue 1289)
|
||||
* Attach orphaned comments as `innerComments` (issue 1328)
|
||||
* Add the support for token delegator (issue 1332)
|
||||
|
||||
2015-09-01: Version 2.6.0
|
||||
|
||||
* Properly allow or prohibit `let` in a binding identifier/pattern (issue 1048, 1098)
|
||||
* Add sourceType field for Program node (issue 1159)
|
||||
* Ensure that strict mode reserved word binding throw an error (issue 1171)
|
||||
* Run the test suite with Node.js and IE 11 on Windows (issue 1294)
|
||||
* Allow binding pattern with no initializer in a for statement (issue 1301)
|
||||
|
||||
2015-07-31: Version 2.5.0
|
||||
|
||||
* Run the test suite in a browser environment (issue 1004)
|
||||
* Ensure a comma between imported default binding and named imports (issue 1046)
|
||||
* Distinguish `yield` as a keyword vs an identifier (issue 1186)
|
||||
* Support ES6 meta property `new.target` (issue 1203)
|
||||
* Fix the syntax node for yield with expression (issue 1223)
|
||||
* Fix the check of duplicated proto in property names (issue 1225)
|
||||
* Fix ES6 Unicode escape in identifier name (issue 1229)
|
||||
* Support ES6 IdentifierStart and IdentifierPart (issue 1232)
|
||||
* Treat await as a reserved word when parsing as a module (issue 1234)
|
||||
* Recognize identifier characters from Unicode SMP (issue 1244)
|
||||
* Ensure that export and import can be followed by a comma (issue 1250)
|
||||
* Fix yield operator precedence (issue 1262)
|
||||
|
||||
2015-07-01: Version 2.4.1
|
||||
|
||||
* Fix some cases of comment attachment (issue 1071, 1175)
|
||||
* Fix the handling of destructuring in function arguments (issue 1193)
|
||||
* Fix invalid ranges in assignment expression (issue 1201)
|
||||
|
||||
2015-06-26: Version 2.4.0
|
||||
|
||||
* Support ES6 for-of iteration (issue 1047)
|
||||
* Support ES6 spread arguments (issue 1169)
|
||||
* Minimize npm payload (issue 1191)
|
||||
|
||||
2015-06-16: Version 2.3.0
|
||||
|
||||
* Support ES6 generator (issue 1033)
|
||||
* Improve parsing of regular expressions with `u` flag (issue 1179)
|
||||
|
||||
2015-04-17: Version 2.2.0
|
||||
|
||||
* Support ES6 import and export declarations (issue 1000)
|
||||
* Fix line terminator before arrow not recognized as error (issue 1009)
|
||||
* Support ES6 destructuring (issue 1045)
|
||||
* Support ES6 template literal (issue 1074)
|
||||
* Fix the handling of invalid/incomplete string escape sequences (issue 1106)
|
||||
* Fix ES3 static member access restriction (issue 1120)
|
||||
* Support for `super` in ES6 class (issue 1147)
|
||||
|
||||
2015-03-09: Version 2.1.0
|
||||
|
||||
* Support ES6 class (issue 1001)
|
||||
* Support ES6 rest parameter (issue 1011)
|
||||
* Expand the location of property getter, setter, and methods (issue 1029)
|
||||
* Enable TryStatement transition to a single handler (issue 1031)
|
||||
* Support ES6 computed property name (issue 1037)
|
||||
* Tolerate unclosed block comment (issue 1041)
|
||||
* Support ES6 lexical declaration (issue 1065)
|
||||
|
||||
2015-02-06: Version 2.0.0
|
||||
|
||||
* Support ES6 arrow function (issue 517)
|
||||
* Support ES6 Unicode code point escape (issue 521)
|
||||
* Improve the speed and accuracy of comment attachment (issue 522)
|
||||
* Support ES6 default parameter (issue 519)
|
||||
* Support ES6 regular expression flags (issue 557)
|
||||
* Fix scanning of implicit octal literals (issue 565)
|
||||
* Fix the handling of automatic semicolon insertion (issue 574)
|
||||
* Support ES6 method definition (issue 620)
|
||||
* Support ES6 octal integer literal (issue 621)
|
||||
* Support ES6 binary integer literal (issue 622)
|
||||
* Support ES6 object literal property value shorthand (issue 624)
|
||||
|
||||
2015-03-03: Version 1.2.5
|
||||
|
||||
* Fix scanning of implicit octal literals (issue 565)
|
||||
|
||||
2015-02-05: Version 1.2.4
|
||||
|
||||
* Fix parsing of LeftHandSideExpression in ForInStatement (issue 560)
|
||||
* Fix the handling of automatic semicolon insertion (issue 574)
|
||||
|
||||
2015-01-18: Version 1.2.3
|
||||
|
||||
* Fix division by this (issue 616)
|
||||
|
||||
2014-05-18: Version 1.2.2
|
||||
|
||||
* Fix duplicated tokens when collecting comments (issue 537)
|
||||
|
||||
2014-05-04: Version 1.2.1
|
||||
|
||||
* Ensure that Program node may still have leading comments (issue 536)
|
||||
|
||||
2014-04-29: Version 1.2.0
|
||||
|
||||
* Fix semicolon handling for expression statement (issue 462, 533)
|
||||
* Disallow escaped characters in regular expression flags (issue 503)
|
||||
* Performance improvement for location tracking (issue 520)
|
||||
* Improve the speed of comment attachment (issue 522)
|
||||
|
||||
2014-03-26: Version 1.1.1
|
||||
|
||||
* Fix token handling of forward slash after an array literal (issue 512)
|
||||
|
||||
2014-03-23: Version 1.1.0
|
||||
|
||||
* Optionally attach comments to the owning syntax nodes (issue 197)
|
||||
* Simplify binary parsing with stack-based shift reduce (issue 352)
|
||||
* Always include the raw source of literals (issue 376)
|
||||
* Add optional input source information (issue 386)
|
||||
* Tokenizer API for pure lexical scanning (issue 398)
|
||||
* Improve the web site and its online demos (issue 337, 400, 404)
|
||||
* Performance improvement for location tracking (issue 417, 424)
|
||||
* Support HTML comment syntax (issue 451)
|
||||
* Drop support for legacy browsers (issue 474)
|
||||
|
||||
2013-08-27: Version 1.0.4
|
||||
|
||||
* Minimize the payload for packages (issue 362)
|
||||
* Fix missing cases on an empty switch statement (issue 436)
|
||||
* Support escaped ] in regexp literal character classes (issue 442)
|
||||
* Tolerate invalid left-hand side expression (issue 130)
|
||||
|
||||
2013-05-17: Version 1.0.3
|
||||
|
||||
* Variable declaration needs at least one declarator (issue 391)
|
||||
* Fix benchmark's variance unit conversion (issue 397)
|
||||
* IE < 9: \v should be treated as vertical tab (issue 405)
|
||||
* Unary expressions should always have prefix: true (issue 418)
|
||||
* Catch clause should only accept an identifier (issue 423)
|
||||
* Tolerate setters without parameter (issue 426)
|
||||
|
||||
2012-11-02: Version 1.0.2
|
||||
|
||||
Improvement:
|
||||
|
||||
* Fix esvalidate JUnit output upon a syntax error (issue 374)
|
||||
|
||||
2012-10-28: Version 1.0.1
|
||||
|
||||
Improvements:
|
||||
|
||||
* esvalidate understands shebang in a Unix shell script (issue 361)
|
||||
* esvalidate treats fatal parsing failure as an error (issue 361)
|
||||
* Reduce Node.js package via .npmignore (issue 362)
|
||||
|
||||
2012-10-22: Version 1.0.0
|
||||
|
||||
Initial release.
|
|
@ -0,0 +1,21 @@
|
|||
Copyright JS Foundation and other contributors, https://js.foundation/
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,46 @@
|
|||
[![NPM version](https://img.shields.io/npm/v/esprima.svg)](https://www.npmjs.com/package/esprima)
|
||||
[![npm download](https://img.shields.io/npm/dm/esprima.svg)](https://www.npmjs.com/package/esprima)
|
||||
[![Build Status](https://img.shields.io/travis/jquery/esprima/master.svg)](https://travis-ci.org/jquery/esprima)
|
||||
[![Coverage Status](https://img.shields.io/codecov/c/github/jquery/esprima/master.svg)](https://codecov.io/github/jquery/esprima)
|
||||
|
||||
**Esprima** ([esprima.org](http://esprima.org), BSD license) is a high performance,
|
||||
standard-compliant [ECMAScript](http://www.ecma-international.org/publications/standards/Ecma-262.htm)
|
||||
parser written in ECMAScript (also popularly known as
|
||||
[JavaScript](https://en.wikipedia.org/wiki/JavaScript)).
|
||||
Esprima is created and maintained by [Ariya Hidayat](https://twitter.com/ariyahidayat),
|
||||
with the help of [many contributors](https://github.com/jquery/esprima/contributors).
|
||||
|
||||
### Features
|
||||
|
||||
- Full support for ECMAScript 2017 ([ECMA-262 8th Edition](http://www.ecma-international.org/publications/standards/Ecma-262.htm))
|
||||
- Sensible [syntax tree format](https://github.com/estree/estree/blob/master/es5.md) as standardized by [ESTree project](https://github.com/estree/estree)
|
||||
- Experimental support for [JSX](https://facebook.github.io/jsx/), a syntax extension for [React](https://facebook.github.io/react/)
|
||||
- Optional tracking of syntax node location (index-based and line-column)
|
||||
- [Heavily tested](http://esprima.org/test/ci.html) (~1500 [unit tests](https://github.com/jquery/esprima/tree/master/test/fixtures) with [full code coverage](https://codecov.io/github/jquery/esprima))
|
||||
|
||||
### API
|
||||
|
||||
Esprima can be used to perform [lexical analysis](https://en.wikipedia.org/wiki/Lexical_analysis) (tokenization) or [syntactic analysis](https://en.wikipedia.org/wiki/Parsing) (parsing) of a JavaScript program.
|
||||
|
||||
A simple example on Node.js REPL:
|
||||
|
||||
```javascript
|
||||
> var esprima = require('esprima');
|
||||
> var program = 'const answer = 42';
|
||||
|
||||
> esprima.tokenize(program);
|
||||
[ { type: 'Keyword', value: 'const' },
|
||||
{ type: 'Identifier', value: 'answer' },
|
||||
{ type: 'Punctuator', value: '=' },
|
||||
{ type: 'Numeric', value: '42' } ]
|
||||
|
||||
> esprima.parseScript(program);
|
||||
{ type: 'Program',
|
||||
body:
|
||||
[ { type: 'VariableDeclaration',
|
||||
declarations: [Object],
|
||||
kind: 'const' } ],
|
||||
sourceType: 'script' }
|
||||
```
|
||||
|
||||
For more information, please read the [complete documentation](http://esprima.org/doc).
|
|
@ -0,0 +1,139 @@
|
|||
#!/usr/bin/env node
|
||||
/*
|
||||
Copyright JS Foundation and other contributors, https://js.foundation/
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*jslint sloppy:true node:true rhino:true */
|
||||
|
||||
var fs, esprima, fname, forceFile, content, options, syntax;
|
||||
|
||||
if (typeof require === 'function') {
|
||||
fs = require('fs');
|
||||
try {
|
||||
esprima = require('esprima');
|
||||
} catch (e) {
|
||||
esprima = require('../');
|
||||
}
|
||||
} else if (typeof load === 'function') {
|
||||
try {
|
||||
load('esprima.js');
|
||||
} catch (e) {
|
||||
load('../esprima.js');
|
||||
}
|
||||
}
|
||||
|
||||
// Shims to Node.js objects when running under Rhino.
|
||||
if (typeof console === 'undefined' && typeof process === 'undefined') {
|
||||
console = { log: print };
|
||||
fs = { readFileSync: readFile };
|
||||
process = { argv: arguments, exit: quit };
|
||||
process.argv.unshift('esparse.js');
|
||||
process.argv.unshift('rhino');
|
||||
}
|
||||
|
||||
function showUsage() {
|
||||
console.log('Usage:');
|
||||
console.log(' esparse [options] [file.js]');
|
||||
console.log();
|
||||
console.log('Available options:');
|
||||
console.log();
|
||||
console.log(' --comment Gather all line and block comments in an array');
|
||||
console.log(' --loc Include line-column location info for each syntax node');
|
||||
console.log(' --range Include index-based range for each syntax node');
|
||||
console.log(' --raw Display the raw value of literals');
|
||||
console.log(' --tokens List all tokens in an array');
|
||||
console.log(' --tolerant Tolerate errors on a best-effort basis (experimental)');
|
||||
console.log(' -v, --version Shows program version');
|
||||
console.log();
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
options = {};
|
||||
|
||||
process.argv.splice(2).forEach(function (entry) {
|
||||
|
||||
if (forceFile || entry === '-' || entry.slice(0, 1) !== '-') {
|
||||
if (typeof fname === 'string') {
|
||||
console.log('Error: more than one input file.');
|
||||
process.exit(1);
|
||||
} else {
|
||||
fname = entry;
|
||||
}
|
||||
} else if (entry === '-h' || entry === '--help') {
|
||||
showUsage();
|
||||
} else if (entry === '-v' || entry === '--version') {
|
||||
console.log('ECMAScript Parser (using Esprima version', esprima.version, ')');
|
||||
console.log();
|
||||
process.exit(0);
|
||||
} else if (entry === '--comment') {
|
||||
options.comment = true;
|
||||
} else if (entry === '--loc') {
|
||||
options.loc = true;
|
||||
} else if (entry === '--range') {
|
||||
options.range = true;
|
||||
} else if (entry === '--raw') {
|
||||
options.raw = true;
|
||||
} else if (entry === '--tokens') {
|
||||
options.tokens = true;
|
||||
} else if (entry === '--tolerant') {
|
||||
options.tolerant = true;
|
||||
} else if (entry === '--') {
|
||||
forceFile = true;
|
||||
} else {
|
||||
console.log('Error: unknown option ' + entry + '.');
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
// Special handling for regular expression literal since we need to
|
||||
// convert it to a string literal, otherwise it will be decoded
|
||||
// as object "{}" and the regular expression would be lost.
|
||||
function adjustRegexLiteral(key, value) {
|
||||
if (key === 'value' && value instanceof RegExp) {
|
||||
value = value.toString();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function run(content) {
|
||||
syntax = esprima.parse(content, options);
|
||||
console.log(JSON.stringify(syntax, adjustRegexLiteral, 4));
|
||||
}
|
||||
|
||||
try {
|
||||
if (fname && (fname !== '-' || forceFile)) {
|
||||
run(fs.readFileSync(fname, 'utf-8'));
|
||||
} else {
|
||||
var content = '';
|
||||
process.stdin.resume();
|
||||
process.stdin.on('data', function(chunk) {
|
||||
content += chunk;
|
||||
});
|
||||
process.stdin.on('end', function() {
|
||||
run(content);
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Error: ' + e.message);
|
||||
process.exit(1);
|
||||
}
|
|
@ -0,0 +1,236 @@
|
|||
#!/usr/bin/env node
|
||||
/*
|
||||
Copyright JS Foundation and other contributors, https://js.foundation/
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*jslint sloppy:true plusplus:true node:true rhino:true */
|
||||
/*global phantom:true */
|
||||
|
||||
var fs, system, esprima, options, fnames, forceFile, count;
|
||||
|
||||
if (typeof esprima === 'undefined') {
|
||||
// PhantomJS can only require() relative files
|
||||
if (typeof phantom === 'object') {
|
||||
fs = require('fs');
|
||||
system = require('system');
|
||||
esprima = require('./esprima');
|
||||
} else if (typeof require === 'function') {
|
||||
fs = require('fs');
|
||||
try {
|
||||
esprima = require('esprima');
|
||||
} catch (e) {
|
||||
esprima = require('../');
|
||||
}
|
||||
} else if (typeof load === 'function') {
|
||||
try {
|
||||
load('esprima.js');
|
||||
} catch (e) {
|
||||
load('../esprima.js');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Shims to Node.js objects when running under PhantomJS 1.7+.
|
||||
if (typeof phantom === 'object') {
|
||||
fs.readFileSync = fs.read;
|
||||
process = {
|
||||
argv: [].slice.call(system.args),
|
||||
exit: phantom.exit,
|
||||
on: function (evt, callback) {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
process.argv.unshift('phantomjs');
|
||||
}
|
||||
|
||||
// Shims to Node.js objects when running under Rhino.
|
||||
if (typeof console === 'undefined' && typeof process === 'undefined') {
|
||||
console = { log: print };
|
||||
fs = { readFileSync: readFile };
|
||||
process = {
|
||||
argv: arguments,
|
||||
exit: quit,
|
||||
on: function (evt, callback) {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
process.argv.unshift('esvalidate.js');
|
||||
process.argv.unshift('rhino');
|
||||
}
|
||||
|
||||
function showUsage() {
|
||||
console.log('Usage:');
|
||||
console.log(' esvalidate [options] [file.js...]');
|
||||
console.log();
|
||||
console.log('Available options:');
|
||||
console.log();
|
||||
console.log(' --format=type Set the report format, plain (default) or junit');
|
||||
console.log(' -v, --version Print program version');
|
||||
console.log();
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
options = {
|
||||
format: 'plain'
|
||||
};
|
||||
|
||||
fnames = [];
|
||||
|
||||
process.argv.splice(2).forEach(function (entry) {
|
||||
|
||||
if (forceFile || entry === '-' || entry.slice(0, 1) !== '-') {
|
||||
fnames.push(entry);
|
||||
} else if (entry === '-h' || entry === '--help') {
|
||||
showUsage();
|
||||
} else if (entry === '-v' || entry === '--version') {
|
||||
console.log('ECMAScript Validator (using Esprima version', esprima.version, ')');
|
||||
console.log();
|
||||
process.exit(0);
|
||||
} else if (entry.slice(0, 9) === '--format=') {
|
||||
options.format = entry.slice(9);
|
||||
if (options.format !== 'plain' && options.format !== 'junit') {
|
||||
console.log('Error: unknown report format ' + options.format + '.');
|
||||
process.exit(1);
|
||||
}
|
||||
} else if (entry === '--') {
|
||||
forceFile = true;
|
||||
} else {
|
||||
console.log('Error: unknown option ' + entry + '.');
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
if (fnames.length === 0) {
|
||||
fnames.push('');
|
||||
}
|
||||
|
||||
if (options.format === 'junit') {
|
||||
console.log('<?xml version="1.0" encoding="UTF-8"?>');
|
||||
console.log('<testsuites>');
|
||||
}
|
||||
|
||||
count = 0;
|
||||
|
||||
function run(fname, content) {
|
||||
var timestamp, syntax, name;
|
||||
try {
|
||||
if (typeof content !== 'string') {
|
||||
throw content;
|
||||
}
|
||||
|
||||
if (content[0] === '#' && content[1] === '!') {
|
||||
content = '//' + content.substr(2, content.length);
|
||||
}
|
||||
|
||||
timestamp = Date.now();
|
||||
syntax = esprima.parse(content, { tolerant: true });
|
||||
|
||||
if (options.format === 'junit') {
|
||||
|
||||
name = fname;
|
||||
if (name.lastIndexOf('/') >= 0) {
|
||||
name = name.slice(name.lastIndexOf('/') + 1);
|
||||
}
|
||||
|
||||
console.log('<testsuite name="' + fname + '" errors="0" ' +
|
||||
' failures="' + syntax.errors.length + '" ' +
|
||||
' tests="' + syntax.errors.length + '" ' +
|
||||
' time="' + Math.round((Date.now() - timestamp) / 1000) +
|
||||
'">');
|
||||
|
||||
syntax.errors.forEach(function (error) {
|
||||
var msg = error.message;
|
||||
msg = msg.replace(/^Line\ [0-9]*\:\ /, '');
|
||||
console.log(' <testcase name="Line ' + error.lineNumber + ': ' + msg + '" ' +
|
||||
' time="0">');
|
||||
console.log(' <error type="SyntaxError" message="' + error.message + '">' +
|
||||
error.message + '(' + name + ':' + error.lineNumber + ')' +
|
||||
'</error>');
|
||||
console.log(' </testcase>');
|
||||
});
|
||||
|
||||
console.log('</testsuite>');
|
||||
|
||||
} else if (options.format === 'plain') {
|
||||
|
||||
syntax.errors.forEach(function (error) {
|
||||
var msg = error.message;
|
||||
msg = msg.replace(/^Line\ [0-9]*\:\ /, '');
|
||||
msg = fname + ':' + error.lineNumber + ': ' + msg;
|
||||
console.log(msg);
|
||||
++count;
|
||||
});
|
||||
|
||||
}
|
||||
} catch (e) {
|
||||
++count;
|
||||
if (options.format === 'junit') {
|
||||
console.log('<testsuite name="' + fname + '" errors="1" failures="0" tests="1" ' +
|
||||
' time="' + Math.round((Date.now() - timestamp) / 1000) + '">');
|
||||
console.log(' <testcase name="' + e.message + '" ' + ' time="0">');
|
||||
console.log(' <error type="ParseError" message="' + e.message + '">' +
|
||||
e.message + '(' + fname + ((e.lineNumber) ? ':' + e.lineNumber : '') +
|
||||
')</error>');
|
||||
console.log(' </testcase>');
|
||||
console.log('</testsuite>');
|
||||
} else {
|
||||
console.log(fname + ':' + e.lineNumber + ': ' + e.message.replace(/^Line\ [0-9]*\:\ /, ''));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fnames.forEach(function (fname) {
|
||||
var content = '';
|
||||
try {
|
||||
if (fname && (fname !== '-' || forceFile)) {
|
||||
content = fs.readFileSync(fname, 'utf-8');
|
||||
} else {
|
||||
fname = '';
|
||||
process.stdin.resume();
|
||||
process.stdin.on('data', function(chunk) {
|
||||
content += chunk;
|
||||
});
|
||||
process.stdin.on('end', function() {
|
||||
run(fname, content);
|
||||
});
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
content = e;
|
||||
}
|
||||
run(fname, content);
|
||||
});
|
||||
|
||||
process.on('exit', function () {
|
||||
if (options.format === 'junit') {
|
||||
console.log('</testsuites>');
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (count === 0 && typeof phantom === 'object') {
|
||||
process.exit(0);
|
||||
}
|
||||
});
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -0,0 +1,140 @@
|
|||
{
|
||||
"_args": [
|
||||
[
|
||||
"esprima@4.0.1",
|
||||
"D:\\Repos\\security-code-analysis-action"
|
||||
]
|
||||
],
|
||||
"_from": "esprima@4.0.1",
|
||||
"_id": "esprima@4.0.1",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
|
||||
"_location": "/esprima",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "version",
|
||||
"registry": true,
|
||||
"raw": "esprima@4.0.1",
|
||||
"name": "esprima",
|
||||
"escapedName": "esprima",
|
||||
"rawSpec": "4.0.1",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "4.0.1"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/js-yaml"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||
"_spec": "4.0.1",
|
||||
"_where": "D:\\Repos\\security-code-analysis-action",
|
||||
"author": {
|
||||
"name": "Ariya Hidayat",
|
||||
"email": "ariya.hidayat@gmail.com"
|
||||
},
|
||||
"bin": {
|
||||
"esparse": "bin/esparse.js",
|
||||
"esvalidate": "bin/esvalidate.js"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/jquery/esprima/issues"
|
||||
},
|
||||
"description": "ECMAScript parsing infrastructure for multipurpose analysis",
|
||||
"devDependencies": {
|
||||
"codecov.io": "~0.1.6",
|
||||
"escomplex-js": "1.2.0",
|
||||
"everything.js": "~1.0.3",
|
||||
"glob": "~7.1.0",
|
||||
"istanbul": "~0.4.0",
|
||||
"json-diff": "~0.3.1",
|
||||
"karma": "~1.3.0",
|
||||
"karma-chrome-launcher": "~2.0.0",
|
||||
"karma-detect-browsers": "~2.2.3",
|
||||
"karma-edge-launcher": "~0.2.0",
|
||||
"karma-firefox-launcher": "~1.0.0",
|
||||
"karma-ie-launcher": "~1.0.0",
|
||||
"karma-mocha": "~1.3.0",
|
||||
"karma-safari-launcher": "~1.0.0",
|
||||
"karma-safaritechpreview-launcher": "~0.0.4",
|
||||
"karma-sauce-launcher": "~1.1.0",
|
||||
"lodash": "~3.10.1",
|
||||
"mocha": "~3.2.0",
|
||||
"node-tick-processor": "~0.0.2",
|
||||
"regenerate": "~1.3.2",
|
||||
"temp": "~0.8.3",
|
||||
"tslint": "~5.1.0",
|
||||
"typescript": "~2.3.2",
|
||||
"typescript-formatter": "~5.1.3",
|
||||
"unicode-8.0.0": "~0.7.0",
|
||||
"webpack": "~1.14.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
},
|
||||
"files": [
|
||||
"bin",
|
||||
"dist/esprima.js"
|
||||
],
|
||||
"homepage": "http://esprima.org",
|
||||
"keywords": [
|
||||
"ast",
|
||||
"ecmascript",
|
||||
"esprima",
|
||||
"javascript",
|
||||
"parser",
|
||||
"syntax"
|
||||
],
|
||||
"license": "BSD-2-Clause",
|
||||
"main": "dist/esprima.js",
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "Ariya Hidayat",
|
||||
"email": "ariya.hidayat@gmail.com",
|
||||
"url": "http://ariya.ofilabs.com"
|
||||
}
|
||||
],
|
||||
"name": "esprima",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/jquery/esprima.git"
|
||||
},
|
||||
"scripts": {
|
||||
"all-tests": "npm run verify-line-ending && npm run generate-fixtures && npm run unit-tests && npm run api-tests && npm run grammar-tests && npm run regression-tests && npm run hostile-env-tests",
|
||||
"analyze-coverage": "istanbul cover test/unit-tests.js",
|
||||
"api-tests": "mocha -R dot test/api-tests.js",
|
||||
"appveyor": "npm run compile && npm run all-tests && npm run browser-tests",
|
||||
"benchmark": "npm run benchmark-parser && npm run benchmark-tokenizer",
|
||||
"benchmark-parser": "node -expose_gc test/benchmark-parser.js",
|
||||
"benchmark-tokenizer": "node --expose_gc test/benchmark-tokenizer.js",
|
||||
"browser-tests": "npm run compile && npm run generate-fixtures && cd test && karma start --single-run",
|
||||
"check-coverage": "istanbul check-coverage --statement 100 --branch 100 --function 100",
|
||||
"check-version": "node test/check-version.js",
|
||||
"circleci": "npm test && npm run codecov && npm run downstream",
|
||||
"code-style": "tsfmt --verify src/*.ts && tsfmt --verify test/*.js",
|
||||
"codecov": "istanbul report cobertura && codecov < ./coverage/cobertura-coverage.xml",
|
||||
"compile": "tsc -p src/ && webpack && node tools/fixupbundle.js",
|
||||
"complexity": "node test/check-complexity.js",
|
||||
"downstream": "node test/downstream.js",
|
||||
"droneio": "npm run compile && npm run all-tests && npm run saucelabs",
|
||||
"dynamic-analysis": "npm run analyze-coverage && npm run check-coverage",
|
||||
"format-code": "tsfmt -r src/*.ts && tsfmt -r test/*.js",
|
||||
"generate-fixtures": "node tools/generate-fixtures.js",
|
||||
"generate-regex": "node tools/generate-identifier-regex.js",
|
||||
"generate-xhtml-entities": "node tools/generate-xhtml-entities.js",
|
||||
"grammar-tests": "node test/grammar-tests.js",
|
||||
"hostile-env-tests": "node test/hostile-environment-tests.js",
|
||||
"prepublish": "npm run compile",
|
||||
"profile": "node --prof test/profile.js && mv isolate*.log v8.log && node-tick-processor",
|
||||
"regression-tests": "node test/regression-tests.js",
|
||||
"saucelabs": "npm run saucelabs-evergreen && npm run saucelabs-ie && npm run saucelabs-safari",
|
||||
"saucelabs-evergreen": "cd test && karma start saucelabs-evergreen.conf.js",
|
||||
"saucelabs-ie": "cd test && karma start saucelabs-ie.conf.js",
|
||||
"saucelabs-safari": "cd test && karma start saucelabs-safari.conf.js",
|
||||
"static-analysis": "npm run check-version && npm run tslint && npm run code-style && npm run complexity",
|
||||
"test": "npm run compile && npm run all-tests && npm run static-analysis && npm run dynamic-analysis",
|
||||
"travis": "npm test",
|
||||
"tslint": "tslint src/*.ts",
|
||||
"unit-tests": "node test/unit-tests.js",
|
||||
"verify-line-ending": "node test/verify-line-ending.js"
|
||||
},
|
||||
"version": "4.0.1"
|
||||
}
|
|
@ -0,0 +1,501 @@
|
|||
3.13.1 / 2019-04-05
|
||||
-------------------
|
||||
|
||||
- Fix possible code execution in (already unsafe) `.load()`, #480.
|
||||
|
||||
|
||||
3.13.0 / 2019-03-20
|
||||
-------------------
|
||||
|
||||
- Security fix: `safeLoad()` can hang when arrays with nested refs
|
||||
used as key. Now throws exception for nested arrays. #475.
|
||||
|
||||
|
||||
3.12.2 / 2019-02-26
|
||||
-------------------
|
||||
|
||||
- Fix `noArrayIndent` option for root level, #468.
|
||||
|
||||
|
||||
3.12.1 / 2019-01-05
|
||||
-------------------
|
||||
|
||||
- Added `noArrayIndent` option, #432.
|
||||
|
||||
|
||||
3.12.0 / 2018-06-02
|
||||
-------------------
|
||||
|
||||
- Support arrow functions without a block statement, #421.
|
||||
|
||||
|
||||
3.11.0 / 2018-03-05
|
||||
-------------------
|
||||
|
||||
- Fix dump in bin/octal/hex formats for negative integers, #399.
|
||||
- Add arrow functions suport for `!!js/function`.
|
||||
|
||||
|
||||
3.10.0 / 2017-09-10
|
||||
-------------------
|
||||
|
||||
- Fix `condenseFlow` output (quote keys for sure, instead of spaces), #371, #370.
|
||||
- Dump astrals as codepoints instead of surrogate pair, #368.
|
||||
|
||||
|
||||
3.9.1 / 2017-07-08
|
||||
------------------
|
||||
|
||||
- Ensure stack is present for custom errors in node 7.+, #351.
|
||||
|
||||
|
||||
3.9.0 / 2017-07-08
|
||||
------------------
|
||||
|
||||
- Add `condenseFlow` option (to create pretty URL query params), #346.
|
||||
- Support array return from safeLoadAll/loadAll, #350.
|
||||
|
||||
|
||||
3.8.4 / 2017-05-08
|
||||
------------------
|
||||
|
||||
- Dumper: prevent space after dash for arrays that wrap, #343.
|
||||
|
||||
|
||||
3.8.3 / 2017-04-05
|
||||
------------------
|
||||
|
||||
- Should not allow numbers to begin and end with underscore, #335.
|
||||
|
||||
|
||||
3.8.2 / 2017-03-02
|
||||
------------------
|
||||
|
||||
- Fix `!!float 123` (integers) parse, #333.
|
||||
- Don't allow leading zeros in floats (except 0, 0.xxx).
|
||||
- Allow positive exponent without sign in floats.
|
||||
|
||||
|
||||
3.8.1 / 2017-02-07
|
||||
------------------
|
||||
|
||||
- Maintenance: update browserified build.
|
||||
|
||||
|
||||
3.8.0 / 2017-02-07
|
||||
------------------
|
||||
|
||||
- Fix reported position for `duplicated mapping key` errors.
|
||||
Now points to block start instead of block end.
|
||||
(#243, thanks to @shockey).
|
||||
|
||||
|
||||
3.7.0 / 2016-11-12
|
||||
------------------
|
||||
|
||||
- Fix parsing of quotes followed by newlines (#304, thanks to @dplepage).
|
||||
- Support polymorphism for tags (#300, thanks to @monken).
|
||||
|
||||
|
||||
3.6.1 / 2016-05-11
|
||||
------------------
|
||||
|
||||
- Fix output cut on a pipe, #286.
|
||||
|
||||
|
||||
3.6.0 / 2016-04-16
|
||||
------------------
|
||||
|
||||
- Dumper rewrite, fix multiple bugs with trailing `\n`.
|
||||
Big thanks to @aepsilon!
|
||||
- Loader: fix leading/trailing newlines in block scalars, @aepsilon.
|
||||
|
||||
|
||||
3.5.5 / 2016-03-17
|
||||
------------------
|
||||
|
||||
- Date parse fix: don't allow dates with on digit in month and day, #268.
|
||||
|
||||
|
||||
3.5.4 / 2016-03-09
|
||||
------------------
|
||||
|
||||
- `noCompatMode` for dumper, to disable quoting YAML 1.1 values.
|
||||
|
||||
|
||||
3.5.3 / 2016-02-11
|
||||
------------------
|
||||
|
||||
- Maintenance release.
|
||||
|
||||
|
||||
3.5.2 / 2016-01-11
|
||||
------------------
|
||||
|
||||
- Maintenance: missed comma in bower config.
|
||||
|
||||
|
||||
3.5.1 / 2016-01-11
|
||||
------------------
|
||||
|
||||
- Removed `inherit` dependency, #239.
|
||||
- Better browserify workaround for esprima load.
|
||||
- Demo rewrite.
|
||||
|
||||
|
||||
3.5.0 / 2016-01-10
|
||||
------------------
|
||||
|
||||
- Dumper. Fold strings only, #217.
|
||||
- Dumper. `norefs` option, to clone linked objects, #229.
|
||||
- Loader. Throw a warning for duplicate keys, #166.
|
||||
- Improved browserify support (mark `esprima` & `Buffer` excluded).
|
||||
|
||||
|
||||
3.4.6 / 2015-11-26
|
||||
------------------
|
||||
|
||||
- Use standalone `inherit` to keep browserified files clear.
|
||||
|
||||
|
||||
3.4.5 / 2015-11-23
|
||||
------------------
|
||||
|
||||
- Added `lineWidth` option to dumper.
|
||||
|
||||
|
||||
3.4.4 / 2015-11-21
|
||||
------------------
|
||||
|
||||
- Fixed floats dump (missed dot for scientific format), #220.
|
||||
- Allow non-printable characters inside quoted scalars, #192.
|
||||
|
||||
|
||||
3.4.3 / 2015-10-10
|
||||
------------------
|
||||
|
||||
- Maintenance release - deps bump (esprima, argparse).
|
||||
|
||||
|
||||
3.4.2 / 2015-09-09
|
||||
------------------
|
||||
|
||||
- Fixed serialization of duplicated entries in sequences, #205.
|
||||
Thanks to @vogelsgesang.
|
||||
|
||||
|
||||
3.4.1 / 2015-09-05
|
||||
------------------
|
||||
|
||||
- Fixed stacktrace handling in generated errors, for browsers (FF/IE).
|
||||
|
||||
|
||||
3.4.0 / 2015-08-23
|
||||
------------------
|
||||
|
||||
- Fixed multiline keys dump, #197. Thanks to @tcr.
|
||||
- Don't throw on warnongs anymore. Use `onWarning` option to catch.
|
||||
- Throw error on unknown tags (was warning before).
|
||||
- Fixed heading line breaks in some scalars (regression).
|
||||
- Reworked internals of error class.
|
||||
|
||||
|
||||
3.3.1 / 2015-05-13
|
||||
------------------
|
||||
|
||||
- Added `.sortKeys` dumper option, thanks to @rjmunro.
|
||||
- Fixed astral characters support, #191.
|
||||
|
||||
|
||||
3.3.0 / 2015-04-26
|
||||
------------------
|
||||
|
||||
- Significantly improved long strings formatting in dumper, thanks to @isaacs.
|
||||
- Strip BOM if exists.
|
||||
|
||||
|
||||
3.2.7 / 2015-02-19
|
||||
------------------
|
||||
|
||||
- Maintenance release.
|
||||
- Updated dependencies.
|
||||
- HISTORY.md -> CHANGELOG.md
|
||||
|
||||
|
||||
3.2.6 / 2015-02-07
|
||||
------------------
|
||||
|
||||
- Fixed encoding of UTF-16 surrogate pairs. (e.g. "\U0001F431" CAT FACE).
|
||||
- Fixed demo dates dump (#113, thanks to @Hypercubed).
|
||||
|
||||
|
||||
3.2.5 / 2014-12-28
|
||||
------------------
|
||||
|
||||
- Fixed resolving of all built-in types on empty nodes.
|
||||
- Fixed invalid warning on empty lines within quoted scalars and flow collections.
|
||||
- Fixed bug: Tag on an empty node didn't resolve in some cases.
|
||||
|
||||
|
||||
3.2.4 / 2014-12-19
|
||||
------------------
|
||||
|
||||
- Fixed resolving of !!null tag on an empty node.
|
||||
|
||||
|
||||
3.2.3 / 2014-11-08
|
||||
------------------
|
||||
|
||||
- Implemented dumping of objects with circular and cross references.
|
||||
- Partially fixed aliasing of constructed objects. (see issue #141 for details)
|
||||
|
||||
|
||||
3.2.2 / 2014-09-07
|
||||
------------------
|
||||
|
||||
- Fixed infinite loop on unindented block scalars.
|
||||
- Rewritten base64 encode/decode in binary type, to keep code licence clear.
|
||||
|
||||
|
||||
3.2.1 / 2014-08-24
|
||||
------------------
|
||||
|
||||
- Nothig new. Just fix npm publish error.
|
||||
|
||||
|
||||
3.2.0 / 2014-08-24
|
||||
------------------
|
||||
|
||||
- Added input piping support to CLI.
|
||||
- Fixed typo, that could cause hand on initial indent (#139).
|
||||
|
||||
|
||||
3.1.0 / 2014-07-07
|
||||
------------------
|
||||
|
||||
- 1.5x-2x speed boost.
|
||||
- Removed deprecated `require('xxx.yml')` support.
|
||||
- Significant code cleanup and refactoring.
|
||||
- Internal API changed. If you used custom types - see updated examples.
|
||||
Others are not affected.
|
||||
- Even if the input string has no trailing line break character,
|
||||
it will be parsed as if it has one.
|
||||
- Added benchmark scripts.
|
||||
- Moved bower files to /dist folder
|
||||
- Bugfixes.
|
||||
|
||||
|
||||
3.0.2 / 2014-02-27
|
||||
------------------
|
||||
|
||||
- Fixed bug: "constructor" string parsed as `null`.
|
||||
|
||||
|
||||
3.0.1 / 2013-12-22
|
||||
------------------
|
||||
|
||||
- Fixed parsing of literal scalars. (issue #108)
|
||||
- Prevented adding unnecessary spaces in object dumps. (issue #68)
|
||||
- Fixed dumping of objects with very long (> 1024 in length) keys.
|
||||
|
||||
|
||||
3.0.0 / 2013-12-16
|
||||
------------------
|
||||
|
||||
- Refactored code. Changed API for custom types.
|
||||
- Removed output colors in CLI, dump json by default.
|
||||
- Removed big dependencies from browser version (esprima, buffer)
|
||||
- load `esprima` manually, if !!js/function needed
|
||||
- !!bin now returns Array in browser
|
||||
- AMD support.
|
||||
- Don't quote dumped strings because of `-` & `?` (if not first char).
|
||||
- __Deprecated__ loading yaml files via `require()`, as not recommended
|
||||
behaviour for node.
|
||||
|
||||
|
||||
2.1.3 / 2013-10-16
|
||||
------------------
|
||||
|
||||
- Fix wrong loading of empty block scalars.
|
||||
|
||||
|
||||
2.1.2 / 2013-10-07
|
||||
------------------
|
||||
|
||||
- Fix unwanted line breaks in folded scalars.
|
||||
|
||||
|
||||
2.1.1 / 2013-10-02
|
||||
------------------
|
||||
|
||||
- Dumper now respects deprecated booleans syntax from YAML 1.0/1.1
|
||||
- Fixed reader bug in JSON-like sequences/mappings.
|
||||
|
||||
|
||||
2.1.0 / 2013-06-05
|
||||
------------------
|
||||
|
||||
- Add standard YAML schemas: Failsafe (`FAILSAFE_SCHEMA`),
|
||||
JSON (`JSON_SCHEMA`) and Core (`CORE_SCHEMA`).
|
||||
- Rename `DEFAULT_SCHEMA` to `DEFAULT_FULL_SCHEMA`
|
||||
and `SAFE_SCHEMA` to `DEFAULT_SAFE_SCHEMA`.
|
||||
- Bug fix: export `NIL` constant from the public interface.
|
||||
- Add `skipInvalid` dumper option.
|
||||
- Use `safeLoad` for `require` extension.
|
||||
|
||||
|
||||
2.0.5 / 2013-04-26
|
||||
------------------
|
||||
|
||||
- Close security issue in !!js/function constructor.
|
||||
Big thanks to @nealpoole for security audit.
|
||||
|
||||
|
||||
2.0.4 / 2013-04-08
|
||||
------------------
|
||||
|
||||
- Updated .npmignore to reduce package size
|
||||
|
||||
|
||||
2.0.3 / 2013-02-26
|
||||
------------------
|
||||
|
||||
- Fixed dumping of empty arrays ans objects. ([] and {} instead of null)
|
||||
|
||||
|
||||
2.0.2 / 2013-02-15
|
||||
------------------
|
||||
|
||||
- Fixed input validation: tabs are printable characters.
|
||||
|
||||
|
||||
2.0.1 / 2013-02-09
|
||||
------------------
|
||||
|
||||
- Fixed error, when options not passed to function cass
|
||||
|
||||
|
||||
2.0.0 / 2013-02-09
|
||||
------------------
|
||||
|
||||
- Full rewrite. New architecture. Fast one-stage parsing.
|
||||
- Changed custom types API.
|
||||
- Added YAML dumper.
|
||||
|
||||
|
||||
1.0.3 / 2012-11-05
|
||||
------------------
|
||||
|
||||
- Fixed utf-8 files loading.
|
||||
|
||||
|
||||
1.0.2 / 2012-08-02
|
||||
------------------
|
||||
|
||||
- Pull out hand-written shims. Use ES5-Shims for old browsers support. See #44.
|
||||
- Fix timstamps incorectly parsed in local time when no time part specified.
|
||||
|
||||
|
||||
1.0.1 / 2012-07-07
|
||||
------------------
|
||||
|
||||
- Fixes `TypeError: 'undefined' is not an object` under Safari. Thanks Phuong.
|
||||
- Fix timestamps incorrectly parsed in local time. Thanks @caolan. Closes #46.
|
||||
|
||||
|
||||
1.0.0 / 2012-07-01
|
||||
------------------
|
||||
|
||||
- `y`, `yes`, `n`, `no`, `on`, `off` are not converted to Booleans anymore.
|
||||
Fixes #42.
|
||||
- `require(filename)` now returns a single document and throws an Error if
|
||||
file contains more than one document.
|
||||
- CLI was merged back from js-yaml.bin
|
||||
|
||||
|
||||
0.3.7 / 2012-02-28
|
||||
------------------
|
||||
|
||||
- Fix export of `addConstructor()`. Closes #39.
|
||||
|
||||
|
||||
0.3.6 / 2012-02-22
|
||||
------------------
|
||||
|
||||
- Removed AMD parts - too buggy to use. Need help to rewrite from scratch
|
||||
- Removed YUI compressor warning (renamed `double` variable). Closes #40.
|
||||
|
||||
|
||||
0.3.5 / 2012-01-10
|
||||
------------------
|
||||
|
||||
- Workagound for .npmignore fuckup under windows. Thanks to airportyh.
|
||||
|
||||
|
||||
0.3.4 / 2011-12-24
|
||||
------------------
|
||||
|
||||
- Fixes str[] for oldIEs support.
|
||||
- Adds better has change support for browserified demo.
|
||||
- improves compact output of Error. Closes #33.
|
||||
|
||||
|
||||
0.3.3 / 2011-12-20
|
||||
------------------
|
||||
|
||||
- jsyaml executable moved to separate module.
|
||||
- adds `compact` stringification of Errors.
|
||||
|
||||
|
||||
0.3.2 / 2011-12-16
|
||||
------------------
|
||||
|
||||
- Fixes ug with block style scalars. Closes #26.
|
||||
- All sources are passing JSLint now.
|
||||
- Fixes bug in Safari. Closes #28.
|
||||
- Fixes bug in Opers. Closes #29.
|
||||
- Improves browser support. Closes #20.
|
||||
- Added jsyaml executable.
|
||||
- Added !!js/function support. Closes #12.
|
||||
|
||||
|
||||
0.3.1 / 2011-11-18
|
||||
------------------
|
||||
|
||||
- Added AMD support for browserified version.
|
||||
- Wrapped browserified js-yaml into closure.
|
||||
- Fixed the resolvement of non-specific tags. Closes #17.
|
||||
- Added permalinks for online demo YAML snippets. Now we have YPaste service, lol.
|
||||
- Added !!js/regexp and !!js/undefined types. Partially solves #12.
|
||||
- Fixed !!set mapping.
|
||||
- Fixed month parse in dates. Closes #19.
|
||||
|
||||
|
||||
0.3.0 / 2011-11-09
|
||||
------------------
|
||||
|
||||
- Removed JS.Class dependency. Closes #3.
|
||||
- Added browserified version. Closes #13.
|
||||
- Added live demo of browserified version.
|
||||
- Ported some of the PyYAML tests. See #14.
|
||||
- Fixed timestamp bug when fraction was given.
|
||||
|
||||
|
||||
0.2.2 / 2011-11-06
|
||||
------------------
|
||||
|
||||
- Fixed crash on docs without ---. Closes #8.
|
||||
- Fixed miltiline string parse
|
||||
- Fixed tests/comments for using array as key
|
||||
|
||||
|
||||
0.2.1 / 2011-11-02
|
||||
------------------
|
||||
|
||||
- Fixed short file read (<4k). Closes #9.
|
||||
|
||||
|
||||
0.2.0 / 2011-11-02
|
||||
------------------
|
||||
|
||||
- First public release
|
|
@ -0,0 +1,21 @@
|
|||
(The MIT License)
|
||||
|
||||
Copyright (C) 2011-2015 by Vitaly Puzrin
|
||||
|
||||
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.
|
|
@ -0,0 +1,314 @@
|
|||
JS-YAML - YAML 1.2 parser / writer for JavaScript
|
||||
=================================================
|
||||
|
||||
[![Build Status](https://travis-ci.org/nodeca/js-yaml.svg?branch=master)](https://travis-ci.org/nodeca/js-yaml)
|
||||
[![NPM version](https://img.shields.io/npm/v/js-yaml.svg)](https://www.npmjs.org/package/js-yaml)
|
||||
|
||||
__[Online Demo](http://nodeca.github.com/js-yaml/)__
|
||||
|
||||
|
||||
This is an implementation of [YAML](http://yaml.org/), a human-friendly data
|
||||
serialization language. Started as [PyYAML](http://pyyaml.org/) port, it was
|
||||
completely rewritten from scratch. Now it's very fast, and supports 1.2 spec.
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
### YAML module for node.js
|
||||
|
||||
```
|
||||
npm install js-yaml
|
||||
```
|
||||
|
||||
|
||||
### CLI executable
|
||||
|
||||
If you want to inspect your YAML files from CLI, install js-yaml globally:
|
||||
|
||||
```
|
||||
npm install -g js-yaml
|
||||
```
|
||||
|
||||
#### Usage
|
||||
|
||||
```
|
||||
usage: js-yaml [-h] [-v] [-c] [-t] file
|
||||
|
||||
Positional arguments:
|
||||
file File with YAML document(s)
|
||||
|
||||
Optional arguments:
|
||||
-h, --help Show this help message and exit.
|
||||
-v, --version Show program's version number and exit.
|
||||
-c, --compact Display errors in compact mode
|
||||
-t, --trace Show stack trace on error
|
||||
```
|
||||
|
||||
|
||||
### Bundled YAML library for browsers
|
||||
|
||||
``` html
|
||||
<!-- esprima required only for !!js/function -->
|
||||
<script src="esprima.js"></script>
|
||||
<script src="js-yaml.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
var doc = jsyaml.load('greeting: hello\nname: world');
|
||||
</script>
|
||||
```
|
||||
|
||||
Browser support was done mostly for the online demo. If you find any errors - feel
|
||||
free to send pull requests with fixes. Also note, that IE and other old browsers
|
||||
needs [es5-shims](https://github.com/kriskowal/es5-shim) to operate.
|
||||
|
||||
Notes:
|
||||
|
||||
1. We have no resources to support browserified version. Don't expect it to be
|
||||
well tested. Don't expect fast fixes if something goes wrong there.
|
||||
2. `!!js/function` in browser bundle will not work by default. If you really need
|
||||
it - load `esprima` parser first (via amd or directly).
|
||||
3. `!!bin` in browser will return `Array`, because browsers do not support
|
||||
node.js `Buffer` and adding Buffer shims is completely useless on practice.
|
||||
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
Here we cover the most 'useful' methods. If you need advanced details (creating
|
||||
your own tags), see [wiki](https://github.com/nodeca/js-yaml/wiki) and
|
||||
[examples](https://github.com/nodeca/js-yaml/tree/master/examples) for more
|
||||
info.
|
||||
|
||||
``` javascript
|
||||
yaml = require('js-yaml');
|
||||
fs = require('fs');
|
||||
|
||||
// Get document, or throw exception on error
|
||||
try {
|
||||
var doc = yaml.safeLoad(fs.readFileSync('/home/ixti/example.yml', 'utf8'));
|
||||
console.log(doc);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### safeLoad (string [ , options ])
|
||||
|
||||
**Recommended loading way.** Parses `string` as single YAML document. Returns a JavaScript
|
||||
object or throws `YAMLException` on error. By default, does not support regexps,
|
||||
functions and undefined. This method is safe for untrusted data.
|
||||
|
||||
options:
|
||||
|
||||
- `filename` _(default: null)_ - string to be used as a file path in
|
||||
error/warning messages.
|
||||
- `onWarning` _(default: null)_ - function to call on warning messages.
|
||||
Loader will call this function with an instance of `YAMLException` for each warning.
|
||||
- `schema` _(default: `DEFAULT_SAFE_SCHEMA`)_ - specifies a schema to use.
|
||||
- `FAILSAFE_SCHEMA` - only strings, arrays and plain objects:
|
||||
http://www.yaml.org/spec/1.2/spec.html#id2802346
|
||||
- `JSON_SCHEMA` - all JSON-supported types:
|
||||
http://www.yaml.org/spec/1.2/spec.html#id2803231
|
||||
- `CORE_SCHEMA` - same as `JSON_SCHEMA`:
|
||||
http://www.yaml.org/spec/1.2/spec.html#id2804923
|
||||
- `DEFAULT_SAFE_SCHEMA` - all supported YAML types, without unsafe ones
|
||||
(`!!js/undefined`, `!!js/regexp` and `!!js/function`):
|
||||
http://yaml.org/type/
|
||||
- `DEFAULT_FULL_SCHEMA` - all supported YAML types.
|
||||
- `json` _(default: false)_ - compatibility with JSON.parse behaviour. If true, then duplicate keys in a mapping will override values rather than throwing an error.
|
||||
|
||||
NOTE: This function **does not** understand multi-document sources, it throws
|
||||
exception on those.
|
||||
|
||||
NOTE: JS-YAML **does not** support schema-specific tag resolution restrictions.
|
||||
So, the JSON schema is not as strictly defined in the YAML specification.
|
||||
It allows numbers in any notation, use `Null` and `NULL` as `null`, etc.
|
||||
The core schema also has no such restrictions. It allows binary notation for integers.
|
||||
|
||||
|
||||
### load (string [ , options ])
|
||||
|
||||
**Use with care with untrusted sources**. The same as `safeLoad()` but uses
|
||||
`DEFAULT_FULL_SCHEMA` by default - adds some JavaScript-specific types:
|
||||
`!!js/function`, `!!js/regexp` and `!!js/undefined`. For untrusted sources, you
|
||||
must additionally validate object structure to avoid injections:
|
||||
|
||||
``` javascript
|
||||
var untrusted_code = '"toString": !<tag:yaml.org,2002:js/function> "function (){very_evil_thing();}"';
|
||||
|
||||
// I'm just converting that string, what could possibly go wrong?
|
||||
require('js-yaml').load(untrusted_code) + ''
|
||||
```
|
||||
|
||||
|
||||
### safeLoadAll (string [, iterator] [, options ])
|
||||
|
||||
Same as `safeLoad()`, but understands multi-document sources. Applies
|
||||
`iterator` to each document if specified, or returns array of documents.
|
||||
|
||||
``` javascript
|
||||
var yaml = require('js-yaml');
|
||||
|
||||
yaml.safeLoadAll(data, function (doc) {
|
||||
console.log(doc);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
### loadAll (string [, iterator] [ , options ])
|
||||
|
||||
Same as `safeLoadAll()` but uses `DEFAULT_FULL_SCHEMA` by default.
|
||||
|
||||
|
||||
### safeDump (object [ , options ])
|
||||
|
||||
Serializes `object` as a YAML document. Uses `DEFAULT_SAFE_SCHEMA`, so it will
|
||||
throw an exception if you try to dump regexps or functions. However, you can
|
||||
disable exceptions by setting the `skipInvalid` option to `true`.
|
||||
|
||||
options:
|
||||
|
||||
- `indent` _(default: 2)_ - indentation width to use (in spaces).
|
||||
- `noArrayIndent` _(default: false)_ - when true, will not add an indentation level to array elements
|
||||
- `skipInvalid` _(default: false)_ - do not throw on invalid types (like function
|
||||
in the safe schema) and skip pairs and single values with such types.
|
||||
- `flowLevel` (default: -1) - specifies level of nesting, when to switch from
|
||||
block to flow style for collections. -1 means block style everwhere
|
||||
- `styles` - "tag" => "style" map. Each tag may have own set of styles.
|
||||
- `schema` _(default: `DEFAULT_SAFE_SCHEMA`)_ specifies a schema to use.
|
||||
- `sortKeys` _(default: `false`)_ - if `true`, sort keys when dumping YAML. If a
|
||||
function, use the function to sort the keys.
|
||||
- `lineWidth` _(default: `80`)_ - set max line width.
|
||||
- `noRefs` _(default: `false`)_ - if `true`, don't convert duplicate objects into references
|
||||
- `noCompatMode` _(default: `false`)_ - if `true` don't try to be compatible with older
|
||||
yaml versions. Currently: don't quote "yes", "no" and so on, as required for YAML 1.1
|
||||
- `condenseFlow` _(default: `false`)_ - if `true` flow sequences will be condensed, omitting the space between `a, b`. Eg. `'[a,b]'`, and omitting the space between `key: value` and quoting the key. Eg. `'{"a":b}'` Can be useful when using yaml for pretty URL query params as spaces are %-encoded.
|
||||
|
||||
The following table show availlable styles (e.g. "canonical",
|
||||
"binary"...) available for each tag (.e.g. !!null, !!int ...). Yaml
|
||||
output is shown on the right side after `=>` (default setting) or `->`:
|
||||
|
||||
``` none
|
||||
!!null
|
||||
"canonical" -> "~"
|
||||
"lowercase" => "null"
|
||||
"uppercase" -> "NULL"
|
||||
"camelcase" -> "Null"
|
||||
|
||||
!!int
|
||||
"binary" -> "0b1", "0b101010", "0b1110001111010"
|
||||
"octal" -> "01", "052", "016172"
|
||||
"decimal" => "1", "42", "7290"
|
||||
"hexadecimal" -> "0x1", "0x2A", "0x1C7A"
|
||||
|
||||
!!bool
|
||||
"lowercase" => "true", "false"
|
||||
"uppercase" -> "TRUE", "FALSE"
|
||||
"camelcase" -> "True", "False"
|
||||
|
||||
!!float
|
||||
"lowercase" => ".nan", '.inf'
|
||||
"uppercase" -> ".NAN", '.INF'
|
||||
"camelcase" -> ".NaN", '.Inf'
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
``` javascript
|
||||
safeDump (object, {
|
||||
'styles': {
|
||||
'!!null': 'canonical' // dump null as ~
|
||||
},
|
||||
'sortKeys': true // sort object keys
|
||||
});
|
||||
```
|
||||
|
||||
### dump (object [ , options ])
|
||||
|
||||
Same as `safeDump()` but without limits (uses `DEFAULT_FULL_SCHEMA` by default).
|
||||
|
||||
|
||||
Supported YAML types
|
||||
--------------------
|
||||
|
||||
The list of standard YAML tags and corresponding JavaScipt types. See also
|
||||
[YAML tag discussion](http://pyyaml.org/wiki/YAMLTagDiscussion) and
|
||||
[YAML types repository](http://yaml.org/type/).
|
||||
|
||||
```
|
||||
!!null '' # null
|
||||
!!bool 'yes' # bool
|
||||
!!int '3...' # number
|
||||
!!float '3.14...' # number
|
||||
!!binary '...base64...' # buffer
|
||||
!!timestamp 'YYYY-...' # date
|
||||
!!omap [ ... ] # array of key-value pairs
|
||||
!!pairs [ ... ] # array or array pairs
|
||||
!!set { ... } # array of objects with given keys and null values
|
||||
!!str '...' # string
|
||||
!!seq [ ... ] # array
|
||||
!!map { ... } # object
|
||||
```
|
||||
|
||||
**JavaScript-specific tags**
|
||||
|
||||
```
|
||||
!!js/regexp /pattern/gim # RegExp
|
||||
!!js/undefined '' # Undefined
|
||||
!!js/function 'function () {...}' # Function
|
||||
```
|
||||
|
||||
Caveats
|
||||
-------
|
||||
|
||||
Note, that you use arrays or objects as key in JS-YAML. JS does not allow objects
|
||||
or arrays as keys, and stringifies (by calling `toString()` method) them at the
|
||||
moment of adding them.
|
||||
|
||||
``` yaml
|
||||
---
|
||||
? [ foo, bar ]
|
||||
: - baz
|
||||
? { foo: bar }
|
||||
: - baz
|
||||
- baz
|
||||
```
|
||||
|
||||
``` javascript
|
||||
{ "foo,bar": ["baz"], "[object Object]": ["baz", "baz"] }
|
||||
```
|
||||
|
||||
Also, reading of properties on implicit block mapping keys is not supported yet.
|
||||
So, the following YAML document cannot be loaded.
|
||||
|
||||
``` yaml
|
||||
&anchor foo:
|
||||
foo: bar
|
||||
*anchor: duplicate key
|
||||
baz: bat
|
||||
*anchor: duplicate key
|
||||
```
|
||||
|
||||
|
||||
Breaking changes in 2.x.x -> 3.x.x
|
||||
----------------------------------
|
||||
|
||||
If you have not used __custom__ tags or loader classes and not loaded yaml
|
||||
files via `require()`, no changes are needed. Just upgrade the library.
|
||||
|
||||
Otherwise, you should:
|
||||
|
||||
1. Replace all occurrences of `require('xxxx.yml')` by `fs.readFileSync()` +
|
||||
`yaml.safeLoad()`.
|
||||
2. rewrite your custom tags constructors and custom loader
|
||||
classes, to conform the new API. See
|
||||
[examples](https://github.com/nodeca/js-yaml/tree/master/examples) and
|
||||
[wiki](https://github.com/nodeca/js-yaml/wiki) for details.
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
View the [LICENSE](https://github.com/nodeca/js-yaml/blob/master/LICENSE) file
|
||||
(MIT).
|
|
@ -0,0 +1,132 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
|
||||
'use strict';
|
||||
|
||||
/*eslint-disable no-console*/
|
||||
|
||||
|
||||
// stdlib
|
||||
var fs = require('fs');
|
||||
|
||||
|
||||
// 3rd-party
|
||||
var argparse = require('argparse');
|
||||
|
||||
|
||||
// internal
|
||||
var yaml = require('..');
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
var cli = new argparse.ArgumentParser({
|
||||
prog: 'js-yaml',
|
||||
version: require('../package.json').version,
|
||||
addHelp: true
|
||||
});
|
||||
|
||||
|
||||
cli.addArgument([ '-c', '--compact' ], {
|
||||
help: 'Display errors in compact mode',
|
||||
action: 'storeTrue'
|
||||
});
|
||||
|
||||
|
||||
// deprecated (not needed after we removed output colors)
|
||||
// option suppressed, but not completely removed for compatibility
|
||||
cli.addArgument([ '-j', '--to-json' ], {
|
||||
help: argparse.Const.SUPPRESS,
|
||||
dest: 'json',
|
||||
action: 'storeTrue'
|
||||
});
|
||||
|
||||
|
||||
cli.addArgument([ '-t', '--trace' ], {
|
||||
help: 'Show stack trace on error',
|
||||
action: 'storeTrue'
|
||||
});
|
||||
|
||||
cli.addArgument([ 'file' ], {
|
||||
help: 'File to read, utf-8 encoded without BOM',
|
||||
nargs: '?',
|
||||
defaultValue: '-'
|
||||
});
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
var options = cli.parseArgs();
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function readFile(filename, encoding, callback) {
|
||||
if (options.file === '-') {
|
||||
// read from stdin
|
||||
|
||||
var chunks = [];
|
||||
|
||||
process.stdin.on('data', function (chunk) {
|
||||
chunks.push(chunk);
|
||||
});
|
||||
|
||||
process.stdin.on('end', function () {
|
||||
return callback(null, Buffer.concat(chunks).toString(encoding));
|
||||
});
|
||||
} else {
|
||||
fs.readFile(filename, encoding, callback);
|
||||
}
|
||||
}
|
||||
|
||||
readFile(options.file, 'utf8', function (error, input) {
|
||||
var output, isYaml;
|
||||
|
||||
if (error) {
|
||||
if (error.code === 'ENOENT') {
|
||||
console.error('File not found: ' + options.file);
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
console.error(
|
||||
options.trace && error.stack ||
|
||||
error.message ||
|
||||
String(error));
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
output = JSON.parse(input);
|
||||
isYaml = false;
|
||||
} catch (err) {
|
||||
if (err instanceof SyntaxError) {
|
||||
try {
|
||||
output = [];
|
||||
yaml.loadAll(input, function (doc) { output.push(doc); }, {});
|
||||
isYaml = true;
|
||||
|
||||
if (output.length === 0) output = null;
|
||||
else if (output.length === 1) output = output[0];
|
||||
|
||||
} catch (e) {
|
||||
if (options.trace && err.stack) console.error(e.stack);
|
||||
else console.error(e.toString(options.compact));
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
} else {
|
||||
console.error(
|
||||
options.trace && err.stack ||
|
||||
err.message ||
|
||||
String(err));
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (isYaml) console.log(JSON.stringify(output, null, ' '));
|
||||
else console.log(yaml.dump(output));
|
||||
});
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -0,0 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
|
||||
var yaml = require('./lib/js-yaml.js');
|
||||
|
||||
|
||||
module.exports = yaml;
|
|
@ -0,0 +1,39 @@
|
|||
'use strict';
|
||||
|
||||
|
||||
var loader = require('./js-yaml/loader');
|
||||
var dumper = require('./js-yaml/dumper');
|
||||
|
||||
|
||||
function deprecated(name) {
|
||||
return function () {
|
||||
throw new Error('Function ' + name + ' is deprecated and cannot be used.');
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
module.exports.Type = require('./js-yaml/type');
|
||||
module.exports.Schema = require('./js-yaml/schema');
|
||||
module.exports.FAILSAFE_SCHEMA = require('./js-yaml/schema/failsafe');
|
||||
module.exports.JSON_SCHEMA = require('./js-yaml/schema/json');
|
||||
module.exports.CORE_SCHEMA = require('./js-yaml/schema/core');
|
||||
module.exports.DEFAULT_SAFE_SCHEMA = require('./js-yaml/schema/default_safe');
|
||||
module.exports.DEFAULT_FULL_SCHEMA = require('./js-yaml/schema/default_full');
|
||||
module.exports.load = loader.load;
|
||||
module.exports.loadAll = loader.loadAll;
|
||||
module.exports.safeLoad = loader.safeLoad;
|
||||
module.exports.safeLoadAll = loader.safeLoadAll;
|
||||
module.exports.dump = dumper.dump;
|
||||
module.exports.safeDump = dumper.safeDump;
|
||||
module.exports.YAMLException = require('./js-yaml/exception');
|
||||
|
||||
// Deprecated schema names from JS-YAML 2.0.x
|
||||
module.exports.MINIMAL_SCHEMA = require('./js-yaml/schema/failsafe');
|
||||
module.exports.SAFE_SCHEMA = require('./js-yaml/schema/default_safe');
|
||||
module.exports.DEFAULT_SCHEMA = require('./js-yaml/schema/default_full');
|
||||
|
||||
// Deprecated functions from JS-YAML 1.x.x
|
||||
module.exports.scan = deprecated('scan');
|
||||
module.exports.parse = deprecated('parse');
|
||||
module.exports.compose = deprecated('compose');
|
||||
module.exports.addConstructor = deprecated('addConstructor');
|
|
@ -0,0 +1,59 @@
|
|||
'use strict';
|
||||
|
||||
|
||||
function isNothing(subject) {
|
||||
return (typeof subject === 'undefined') || (subject === null);
|
||||
}
|
||||
|
||||
|
||||
function isObject(subject) {
|
||||
return (typeof subject === 'object') && (subject !== null);
|
||||
}
|
||||
|
||||
|
||||
function toArray(sequence) {
|
||||
if (Array.isArray(sequence)) return sequence;
|
||||
else if (isNothing(sequence)) return [];
|
||||
|
||||
return [ sequence ];
|
||||
}
|
||||
|
||||
|
||||
function extend(target, source) {
|
||||
var index, length, key, sourceKeys;
|
||||
|
||||
if (source) {
|
||||
sourceKeys = Object.keys(source);
|
||||
|
||||
for (index = 0, length = sourceKeys.length; index < length; index += 1) {
|
||||
key = sourceKeys[index];
|
||||
target[key] = source[key];
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
function repeat(string, count) {
|
||||
var result = '', cycle;
|
||||
|
||||
for (cycle = 0; cycle < count; cycle += 1) {
|
||||
result += string;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
function isNegativeZero(number) {
|
||||
return (number === 0) && (Number.NEGATIVE_INFINITY === 1 / number);
|
||||
}
|
||||
|
||||
|
||||
module.exports.isNothing = isNothing;
|
||||
module.exports.isObject = isObject;
|
||||
module.exports.toArray = toArray;
|
||||
module.exports.repeat = repeat;
|
||||
module.exports.isNegativeZero = isNegativeZero;
|
||||
module.exports.extend = extend;
|
|
@ -0,0 +1,827 @@
|
|||
'use strict';
|
||||
|
||||
/*eslint-disable no-use-before-define*/
|
||||
|
||||
var common = require('./common');
|
||||
var YAMLException = require('./exception');
|
||||
var DEFAULT_FULL_SCHEMA = require('./schema/default_full');
|
||||
var DEFAULT_SAFE_SCHEMA = require('./schema/default_safe');
|
||||
|
||||
var _toString = Object.prototype.toString;
|
||||
var _hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
|
||||
var CHAR_TAB = 0x09; /* Tab */
|
||||
var CHAR_LINE_FEED = 0x0A; /* LF */
|
||||
var CHAR_SPACE = 0x20; /* Space */
|
||||
var CHAR_EXCLAMATION = 0x21; /* ! */
|
||||
var CHAR_DOUBLE_QUOTE = 0x22; /* " */
|
||||
var CHAR_SHARP = 0x23; /* # */
|
||||
var CHAR_PERCENT = 0x25; /* % */
|
||||
var CHAR_AMPERSAND = 0x26; /* & */
|
||||
var CHAR_SINGLE_QUOTE = 0x27; /* ' */
|
||||
var CHAR_ASTERISK = 0x2A; /* * */
|
||||
var CHAR_COMMA = 0x2C; /* , */
|
||||
var CHAR_MINUS = 0x2D; /* - */
|
||||
var CHAR_COLON = 0x3A; /* : */
|
||||
var CHAR_GREATER_THAN = 0x3E; /* > */
|
||||
var CHAR_QUESTION = 0x3F; /* ? */
|
||||
var CHAR_COMMERCIAL_AT = 0x40; /* @ */
|
||||
var CHAR_LEFT_SQUARE_BRACKET = 0x5B; /* [ */
|
||||
var CHAR_RIGHT_SQUARE_BRACKET = 0x5D; /* ] */
|
||||
var CHAR_GRAVE_ACCENT = 0x60; /* ` */
|
||||
var CHAR_LEFT_CURLY_BRACKET = 0x7B; /* { */
|
||||
var CHAR_VERTICAL_LINE = 0x7C; /* | */
|
||||
var CHAR_RIGHT_CURLY_BRACKET = 0x7D; /* } */
|
||||
|
||||
var ESCAPE_SEQUENCES = {};
|
||||
|
||||
ESCAPE_SEQUENCES[0x00] = '\\0';
|
||||
ESCAPE_SEQUENCES[0x07] = '\\a';
|
||||
ESCAPE_SEQUENCES[0x08] = '\\b';
|
||||
ESCAPE_SEQUENCES[0x09] = '\\t';
|
||||
ESCAPE_SEQUENCES[0x0A] = '\\n';
|
||||
ESCAPE_SEQUENCES[0x0B] = '\\v';
|
||||
ESCAPE_SEQUENCES[0x0C] = '\\f';
|
||||
ESCAPE_SEQUENCES[0x0D] = '\\r';
|
||||
ESCAPE_SEQUENCES[0x1B] = '\\e';
|
||||
ESCAPE_SEQUENCES[0x22] = '\\"';
|
||||
ESCAPE_SEQUENCES[0x5C] = '\\\\';
|
||||
ESCAPE_SEQUENCES[0x85] = '\\N';
|
||||
ESCAPE_SEQUENCES[0xA0] = '\\_';
|
||||
ESCAPE_SEQUENCES[0x2028] = '\\L';
|
||||
ESCAPE_SEQUENCES[0x2029] = '\\P';
|
||||
|
||||
var DEPRECATED_BOOLEANS_SYNTAX = [
|
||||
'y', 'Y', 'yes', 'Yes', 'YES', 'on', 'On', 'ON',
|
||||
'n', 'N', 'no', 'No', 'NO', 'off', 'Off', 'OFF'
|
||||
];
|
||||
|
||||
function compileStyleMap(schema, map) {
|
||||
var result, keys, index, length, tag, style, type;
|
||||
|
||||
if (map === null) return {};
|
||||
|
||||
result = {};
|
||||
keys = Object.keys(map);
|
||||
|
||||
for (index = 0, length = keys.length; index < length; index += 1) {
|
||||
tag = keys[index];
|
||||
style = String(map[tag]);
|
||||
|
||||
if (tag.slice(0, 2) === '!!') {
|
||||
tag = 'tag:yaml.org,2002:' + tag.slice(2);
|
||||
}
|
||||
type = schema.compiledTypeMap['fallback'][tag];
|
||||
|
||||
if (type && _hasOwnProperty.call(type.styleAliases, style)) {
|
||||
style = type.styleAliases[style];
|
||||
}
|
||||
|
||||
result[tag] = style;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function encodeHex(character) {
|
||||
var string, handle, length;
|
||||
|
||||
string = character.toString(16).toUpperCase();
|
||||
|
||||
if (character <= 0xFF) {
|
||||
handle = 'x';
|
||||
length = 2;
|
||||
} else if (character <= 0xFFFF) {
|
||||
handle = 'u';
|
||||
length = 4;
|
||||
} else if (character <= 0xFFFFFFFF) {
|
||||
handle = 'U';
|
||||
length = 8;
|
||||
} else {
|
||||
throw new YAMLException('code point within a string may not be greater than 0xFFFFFFFF');
|
||||
}
|
||||
|
||||
return '\\' + handle + common.repeat('0', length - string.length) + string;
|
||||
}
|
||||
|
||||
function State(options) {
|
||||
this.schema = options['schema'] || DEFAULT_FULL_SCHEMA;
|
||||
this.indent = Math.max(1, (options['indent'] || 2));
|
||||
this.noArrayIndent = options['noArrayIndent'] || false;
|
||||
this.skipInvalid = options['skipInvalid'] || false;
|
||||
this.flowLevel = (common.isNothing(options['flowLevel']) ? -1 : options['flowLevel']);
|
||||
this.styleMap = compileStyleMap(this.schema, options['styles'] || null);
|
||||
this.sortKeys = options['sortKeys'] || false;
|
||||
this.lineWidth = options['lineWidth'] || 80;
|
||||
this.noRefs = options['noRefs'] || false;
|
||||
this.noCompatMode = options['noCompatMode'] || false;
|
||||
this.condenseFlow = options['condenseFlow'] || false;
|
||||
|
||||
this.implicitTypes = this.schema.compiledImplicit;
|
||||
this.explicitTypes = this.schema.compiledExplicit;
|
||||
|
||||
this.tag = null;
|
||||
this.result = '';
|
||||
|
||||
this.duplicates = [];
|
||||
this.usedDuplicates = null;
|
||||
}
|
||||
|
||||
// Indents every line in a string. Empty lines (\n only) are not indented.
|
||||
function indentString(string, spaces) {
|
||||
var ind = common.repeat(' ', spaces),
|
||||
position = 0,
|
||||
next = -1,
|
||||
result = '',
|
||||
line,
|
||||
length = string.length;
|
||||
|
||||
while (position < length) {
|
||||
next = string.indexOf('\n', position);
|
||||
if (next === -1) {
|
||||
line = string.slice(position);
|
||||
position = length;
|
||||
} else {
|
||||
line = string.slice(position, next + 1);
|
||||
position = next + 1;
|
||||
}
|
||||
|
||||
if (line.length && line !== '\n') result += ind;
|
||||
|
||||
result += line;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function generateNextLine(state, level) {
|
||||
return '\n' + common.repeat(' ', state.indent * level);
|
||||
}
|
||||
|
||||
function testImplicitResolving(state, str) {
|
||||
var index, length, type;
|
||||
|
||||
for (index = 0, length = state.implicitTypes.length; index < length; index += 1) {
|
||||
type = state.implicitTypes[index];
|
||||
|
||||
if (type.resolve(str)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// [33] s-white ::= s-space | s-tab
|
||||
function isWhitespace(c) {
|
||||
return c === CHAR_SPACE || c === CHAR_TAB;
|
||||
}
|
||||
|
||||
// Returns true if the character can be printed without escaping.
|
||||
// From YAML 1.2: "any allowed characters known to be non-printable
|
||||
// should also be escaped. [However,] This isn’t mandatory"
|
||||
// Derived from nb-char - \t - #x85 - #xA0 - #x2028 - #x2029.
|
||||
function isPrintable(c) {
|
||||
return (0x00020 <= c && c <= 0x00007E)
|
||||
|| ((0x000A1 <= c && c <= 0x00D7FF) && c !== 0x2028 && c !== 0x2029)
|
||||
|| ((0x0E000 <= c && c <= 0x00FFFD) && c !== 0xFEFF /* BOM */)
|
||||
|| (0x10000 <= c && c <= 0x10FFFF);
|
||||
}
|
||||
|
||||
// Simplified test for values allowed after the first character in plain style.
|
||||
function isPlainSafe(c) {
|
||||
// Uses a subset of nb-char - c-flow-indicator - ":" - "#"
|
||||
// where nb-char ::= c-printable - b-char - c-byte-order-mark.
|
||||
return isPrintable(c) && c !== 0xFEFF
|
||||
// - c-flow-indicator
|
||||
&& c !== CHAR_COMMA
|
||||
&& c !== CHAR_LEFT_SQUARE_BRACKET
|
||||
&& c !== CHAR_RIGHT_SQUARE_BRACKET
|
||||
&& c !== CHAR_LEFT_CURLY_BRACKET
|
||||
&& c !== CHAR_RIGHT_CURLY_BRACKET
|
||||
// - ":" - "#"
|
||||
&& c !== CHAR_COLON
|
||||
&& c !== CHAR_SHARP;
|
||||
}
|
||||
|
||||
// Simplified test for values allowed as the first character in plain style.
|
||||
function isPlainSafeFirst(c) {
|
||||
// Uses a subset of ns-char - c-indicator
|
||||
// where ns-char = nb-char - s-white.
|
||||
return isPrintable(c) && c !== 0xFEFF
|
||||
&& !isWhitespace(c) // - s-white
|
||||
// - (c-indicator ::=
|
||||
// “-” | “?” | “:” | “,” | “[” | “]” | “{” | “}”
|
||||
&& c !== CHAR_MINUS
|
||||
&& c !== CHAR_QUESTION
|
||||
&& c !== CHAR_COLON
|
||||
&& c !== CHAR_COMMA
|
||||
&& c !== CHAR_LEFT_SQUARE_BRACKET
|
||||
&& c !== CHAR_RIGHT_SQUARE_BRACKET
|
||||
&& c !== CHAR_LEFT_CURLY_BRACKET
|
||||
&& c !== CHAR_RIGHT_CURLY_BRACKET
|
||||
// | “#” | “&” | “*” | “!” | “|” | “>” | “'” | “"”
|
||||
&& c !== CHAR_SHARP
|
||||
&& c !== CHAR_AMPERSAND
|
||||
&& c !== CHAR_ASTERISK
|
||||
&& c !== CHAR_EXCLAMATION
|
||||
&& c !== CHAR_VERTICAL_LINE
|
||||
&& c !== CHAR_GREATER_THAN
|
||||
&& c !== CHAR_SINGLE_QUOTE
|
||||
&& c !== CHAR_DOUBLE_QUOTE
|
||||
// | “%” | “@” | “`”)
|
||||
&& c !== CHAR_PERCENT
|
||||
&& c !== CHAR_COMMERCIAL_AT
|
||||
&& c !== CHAR_GRAVE_ACCENT;
|
||||
}
|
||||
|
||||
// Determines whether block indentation indicator is required.
|
||||
function needIndentIndicator(string) {
|
||||
var leadingSpaceRe = /^\n* /;
|
||||
return leadingSpaceRe.test(string);
|
||||
}
|
||||
|
||||
var STYLE_PLAIN = 1,
|
||||
STYLE_SINGLE = 2,
|
||||
STYLE_LITERAL = 3,
|
||||
STYLE_FOLDED = 4,
|
||||
STYLE_DOUBLE = 5;
|
||||
|
||||
// Determines which scalar styles are possible and returns the preferred style.
|
||||
// lineWidth = -1 => no limit.
|
||||
// Pre-conditions: str.length > 0.
|
||||
// Post-conditions:
|
||||
// STYLE_PLAIN or STYLE_SINGLE => no \n are in the string.
|
||||
// STYLE_LITERAL => no lines are suitable for folding (or lineWidth is -1).
|
||||
// STYLE_FOLDED => a line > lineWidth and can be folded (and lineWidth != -1).
|
||||
function chooseScalarStyle(string, singleLineOnly, indentPerLevel, lineWidth, testAmbiguousType) {
|
||||
var i;
|
||||
var char;
|
||||
var hasLineBreak = false;
|
||||
var hasFoldableLine = false; // only checked if shouldTrackWidth
|
||||
var shouldTrackWidth = lineWidth !== -1;
|
||||
var previousLineBreak = -1; // count the first line correctly
|
||||
var plain = isPlainSafeFirst(string.charCodeAt(0))
|
||||
&& !isWhitespace(string.charCodeAt(string.length - 1));
|
||||
|
||||
if (singleLineOnly) {
|
||||
// Case: no block styles.
|
||||
// Check for disallowed characters to rule out plain and single.
|
||||
for (i = 0; i < string.length; i++) {
|
||||
char = string.charCodeAt(i);
|
||||
if (!isPrintable(char)) {
|
||||
return STYLE_DOUBLE;
|
||||
}
|
||||
plain = plain && isPlainSafe(char);
|
||||
}
|
||||
} else {
|
||||
// Case: block styles permitted.
|
||||
for (i = 0; i < string.length; i++) {
|
||||
char = string.charCodeAt(i);
|
||||
if (char === CHAR_LINE_FEED) {
|
||||
hasLineBreak = true;
|
||||
// Check if any line can be folded.
|
||||
if (shouldTrackWidth) {
|
||||
hasFoldableLine = hasFoldableLine ||
|
||||
// Foldable line = too long, and not more-indented.
|
||||
(i - previousLineBreak - 1 > lineWidth &&
|
||||
string[previousLineBreak + 1] !== ' ');
|
||||
previousLineBreak = i;
|
||||
}
|
||||
} else if (!isPrintable(char)) {
|
||||
return STYLE_DOUBLE;
|
||||
}
|
||||
plain = plain && isPlainSafe(char);
|
||||
}
|
||||
// in case the end is missing a \n
|
||||
hasFoldableLine = hasFoldableLine || (shouldTrackWidth &&
|
||||
(i - previousLineBreak - 1 > lineWidth &&
|
||||
string[previousLineBreak + 1] !== ' '));
|
||||
}
|
||||
// Although every style can represent \n without escaping, prefer block styles
|
||||
// for multiline, since they're more readable and they don't add empty lines.
|
||||
// Also prefer folding a super-long line.
|
||||
if (!hasLineBreak && !hasFoldableLine) {
|
||||
// Strings interpretable as another type have to be quoted;
|
||||
// e.g. the string 'true' vs. the boolean true.
|
||||
return plain && !testAmbiguousType(string)
|
||||
? STYLE_PLAIN : STYLE_SINGLE;
|
||||
}
|
||||
// Edge case: block indentation indicator can only have one digit.
|
||||
if (indentPerLevel > 9 && needIndentIndicator(string)) {
|
||||
return STYLE_DOUBLE;
|
||||
}
|
||||
// At this point we know block styles are valid.
|
||||
// Prefer literal style unless we want to fold.
|
||||
return hasFoldableLine ? STYLE_FOLDED : STYLE_LITERAL;
|
||||
}
|
||||
|
||||
// Note: line breaking/folding is implemented for only the folded style.
|
||||
// NB. We drop the last trailing newline (if any) of a returned block scalar
|
||||
// since the dumper adds its own newline. This always works:
|
||||
// • No ending newline => unaffected; already using strip "-" chomping.
|
||||
// • Ending newline => removed then restored.
|
||||
// Importantly, this keeps the "+" chomp indicator from gaining an extra line.
|
||||
function writeScalar(state, string, level, iskey) {
|
||||
state.dump = (function () {
|
||||
if (string.length === 0) {
|
||||
return "''";
|
||||
}
|
||||
if (!state.noCompatMode &&
|
||||
DEPRECATED_BOOLEANS_SYNTAX.indexOf(string) !== -1) {
|
||||
return "'" + string + "'";
|
||||
}
|
||||
|
||||
var indent = state.indent * Math.max(1, level); // no 0-indent scalars
|
||||
// As indentation gets deeper, let the width decrease monotonically
|
||||
// to the lower bound min(state.lineWidth, 40).
|
||||
// Note that this implies
|
||||
// state.lineWidth ≤ 40 + state.indent: width is fixed at the lower bound.
|
||||
// state.lineWidth > 40 + state.indent: width decreases until the lower bound.
|
||||
// This behaves better than a constant minimum width which disallows narrower options,
|
||||
// or an indent threshold which causes the width to suddenly increase.
|
||||
var lineWidth = state.lineWidth === -1
|
||||
? -1 : Math.max(Math.min(state.lineWidth, 40), state.lineWidth - indent);
|
||||
|
||||
// Without knowing if keys are implicit/explicit, assume implicit for safety.
|
||||
var singleLineOnly = iskey
|
||||
// No block styles in flow mode.
|
||||
|| (state.flowLevel > -1 && level >= state.flowLevel);
|
||||
function testAmbiguity(string) {
|
||||
return testImplicitResolving(state, string);
|
||||
}
|
||||
|
||||
switch (chooseScalarStyle(string, singleLineOnly, state.indent, lineWidth, testAmbiguity)) {
|
||||
case STYLE_PLAIN:
|
||||
return string;
|
||||
case STYLE_SINGLE:
|
||||
return "'" + string.replace(/'/g, "''") + "'";
|
||||
case STYLE_LITERAL:
|
||||
return '|' + blockHeader(string, state.indent)
|
||||
+ dropEndingNewline(indentString(string, indent));
|
||||
case STYLE_FOLDED:
|
||||
return '>' + blockHeader(string, state.indent)
|
||||
+ dropEndingNewline(indentString(foldString(string, lineWidth), indent));
|
||||
case STYLE_DOUBLE:
|
||||
return '"' + escapeString(string, lineWidth) + '"';
|
||||
default:
|
||||
throw new YAMLException('impossible error: invalid scalar style');
|
||||
}
|
||||
}());
|
||||
}
|
||||
|
||||
// Pre-conditions: string is valid for a block scalar, 1 <= indentPerLevel <= 9.
|
||||
function blockHeader(string, indentPerLevel) {
|
||||
var indentIndicator = needIndentIndicator(string) ? String(indentPerLevel) : '';
|
||||
|
||||
// note the special case: the string '\n' counts as a "trailing" empty line.
|
||||
var clip = string[string.length - 1] === '\n';
|
||||
var keep = clip && (string[string.length - 2] === '\n' || string === '\n');
|
||||
var chomp = keep ? '+' : (clip ? '' : '-');
|
||||
|
||||
return indentIndicator + chomp + '\n';
|
||||
}
|
||||
|
||||
// (See the note for writeScalar.)
|
||||
function dropEndingNewline(string) {
|
||||
return string[string.length - 1] === '\n' ? string.slice(0, -1) : string;
|
||||
}
|
||||
|
||||
// Note: a long line without a suitable break point will exceed the width limit.
|
||||
// Pre-conditions: every char in str isPrintable, str.length > 0, width > 0.
|
||||
function foldString(string, width) {
|
||||
// In folded style, $k$ consecutive newlines output as $k+1$ newlines—
|
||||
// unless they're before or after a more-indented line, or at the very
|
||||
// beginning or end, in which case $k$ maps to $k$.
|
||||
// Therefore, parse each chunk as newline(s) followed by a content line.
|
||||
var lineRe = /(\n+)([^\n]*)/g;
|
||||
|
||||
// first line (possibly an empty line)
|
||||
var result = (function () {
|
||||
var nextLF = string.indexOf('\n');
|
||||
nextLF = nextLF !== -1 ? nextLF : string.length;
|
||||
lineRe.lastIndex = nextLF;
|
||||
return foldLine(string.slice(0, nextLF), width);
|
||||
}());
|
||||
// If we haven't reached the first content line yet, don't add an extra \n.
|
||||
var prevMoreIndented = string[0] === '\n' || string[0] === ' ';
|
||||
var moreIndented;
|
||||
|
||||
// rest of the lines
|
||||
var match;
|
||||
while ((match = lineRe.exec(string))) {
|
||||
var prefix = match[1], line = match[2];
|
||||
moreIndented = (line[0] === ' ');
|
||||
result += prefix
|
||||
+ (!prevMoreIndented && !moreIndented && line !== ''
|
||||
? '\n' : '')
|
||||
+ foldLine(line, width);
|
||||
prevMoreIndented = moreIndented;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Greedy line breaking.
|
||||
// Picks the longest line under the limit each time,
|
||||
// otherwise settles for the shortest line over the limit.
|
||||
// NB. More-indented lines *cannot* be folded, as that would add an extra \n.
|
||||
function foldLine(line, width) {
|
||||
if (line === '' || line[0] === ' ') return line;
|
||||
|
||||
// Since a more-indented line adds a \n, breaks can't be followed by a space.
|
||||
var breakRe = / [^ ]/g; // note: the match index will always be <= length-2.
|
||||
var match;
|
||||
// start is an inclusive index. end, curr, and next are exclusive.
|
||||
var start = 0, end, curr = 0, next = 0;
|
||||
var result = '';
|
||||
|
||||
// Invariants: 0 <= start <= length-1.
|
||||
// 0 <= curr <= next <= max(0, length-2). curr - start <= width.
|
||||
// Inside the loop:
|
||||
// A match implies length >= 2, so curr and next are <= length-2.
|
||||
while ((match = breakRe.exec(line))) {
|
||||
next = match.index;
|
||||
// maintain invariant: curr - start <= width
|
||||
if (next - start > width) {
|
||||
end = (curr > start) ? curr : next; // derive end <= length-2
|
||||
result += '\n' + line.slice(start, end);
|
||||
// skip the space that was output as \n
|
||||
start = end + 1; // derive start <= length-1
|
||||
}
|
||||
curr = next;
|
||||
}
|
||||
|
||||
// By the invariants, start <= length-1, so there is something left over.
|
||||
// It is either the whole string or a part starting from non-whitespace.
|
||||
result += '\n';
|
||||
// Insert a break if the remainder is too long and there is a break available.
|
||||
if (line.length - start > width && curr > start) {
|
||||
result += line.slice(start, curr) + '\n' + line.slice(curr + 1);
|
||||
} else {
|
||||
result += line.slice(start);
|
||||
}
|
||||
|
||||
return result.slice(1); // drop extra \n joiner
|
||||
}
|
||||
|
||||
// Escapes a double-quoted string.
|
||||
function escapeString(string) {
|
||||
var result = '';
|
||||
var char, nextChar;
|
||||
var escapeSeq;
|
||||
|
||||
for (var i = 0; i < string.length; i++) {
|
||||
char = string.charCodeAt(i);
|
||||
// Check for surrogate pairs (reference Unicode 3.0 section "3.7 Surrogates").
|
||||
if (char >= 0xD800 && char <= 0xDBFF/* high surrogate */) {
|
||||
nextChar = string.charCodeAt(i + 1);
|
||||
if (nextChar >= 0xDC00 && nextChar <= 0xDFFF/* low surrogate */) {
|
||||
// Combine the surrogate pair and store it escaped.
|
||||
result += encodeHex((char - 0xD800) * 0x400 + nextChar - 0xDC00 + 0x10000);
|
||||
// Advance index one extra since we already used that char here.
|
||||
i++; continue;
|
||||
}
|
||||
}
|
||||
escapeSeq = ESCAPE_SEQUENCES[char];
|
||||
result += !escapeSeq && isPrintable(char)
|
||||
? string[i]
|
||||
: escapeSeq || encodeHex(char);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function writeFlowSequence(state, level, object) {
|
||||
var _result = '',
|
||||
_tag = state.tag,
|
||||
index,
|
||||
length;
|
||||
|
||||
for (index = 0, length = object.length; index < length; index += 1) {
|
||||
// Write only valid elements.
|
||||
if (writeNode(state, level, object[index], false, false)) {
|
||||
if (index !== 0) _result += ',' + (!state.condenseFlow ? ' ' : '');
|
||||
_result += state.dump;
|
||||
}
|
||||
}
|
||||
|
||||
state.tag = _tag;
|
||||
state.dump = '[' + _result + ']';
|
||||
}
|
||||
|
||||
function writeBlockSequence(state, level, object, compact) {
|
||||
var _result = '',
|
||||
_tag = state.tag,
|
||||
index,
|
||||
length;
|
||||
|
||||
for (index = 0, length = object.length; index < length; index += 1) {
|
||||
// Write only valid elements.
|
||||
if (writeNode(state, level + 1, object[index], true, true)) {
|
||||
if (!compact || index !== 0) {
|
||||
_result += generateNextLine(state, level);
|
||||
}
|
||||
|
||||
if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) {
|
||||
_result += '-';
|
||||
} else {
|
||||
_result += '- ';
|
||||
}
|
||||
|
||||
_result += state.dump;
|
||||
}
|
||||
}
|
||||
|
||||
state.tag = _tag;
|
||||
state.dump = _result || '[]'; // Empty sequence if no valid values.
|
||||
}
|
||||
|
||||
function writeFlowMapping(state, level, object) {
|
||||
var _result = '',
|
||||
_tag = state.tag,
|
||||
objectKeyList = Object.keys(object),
|
||||
index,
|
||||
length,
|
||||
objectKey,
|
||||
objectValue,
|
||||
pairBuffer;
|
||||
|
||||
for (index = 0, length = objectKeyList.length; index < length; index += 1) {
|
||||
pairBuffer = state.condenseFlow ? '"' : '';
|
||||
|
||||
if (index !== 0) pairBuffer += ', ';
|
||||
|
||||
objectKey = objectKeyList[index];
|
||||
objectValue = object[objectKey];
|
||||
|
||||
if (!writeNode(state, level, objectKey, false, false)) {
|
||||
continue; // Skip this pair because of invalid key;
|
||||
}
|
||||
|
||||
if (state.dump.length > 1024) pairBuffer += '? ';
|
||||
|
||||
pairBuffer += state.dump + (state.condenseFlow ? '"' : '') + ':' + (state.condenseFlow ? '' : ' ');
|
||||
|
||||
if (!writeNode(state, level, objectValue, false, false)) {
|
||||
continue; // Skip this pair because of invalid value.
|
||||
}
|
||||
|
||||
pairBuffer += state.dump;
|
||||
|
||||
// Both key and value are valid.
|
||||
_result += pairBuffer;
|
||||
}
|
||||
|
||||
state.tag = _tag;
|
||||
state.dump = '{' + _result + '}';
|
||||
}
|
||||
|
||||
function writeBlockMapping(state, level, object, compact) {
|
||||
var _result = '',
|
||||
_tag = state.tag,
|
||||
objectKeyList = Object.keys(object),
|
||||
index,
|
||||
length,
|
||||
objectKey,
|
||||
objectValue,
|
||||
explicitPair,
|
||||
pairBuffer;
|
||||
|
||||
// Allow sorting keys so that the output file is deterministic
|
||||
if (state.sortKeys === true) {
|
||||
// Default sorting
|
||||
objectKeyList.sort();
|
||||
} else if (typeof state.sortKeys === 'function') {
|
||||
// Custom sort function
|
||||
objectKeyList.sort(state.sortKeys);
|
||||
} else if (state.sortKeys) {
|
||||
// Something is wrong
|
||||
throw new YAMLException('sortKeys must be a boolean or a function');
|
||||
}
|
||||
|
||||
for (index = 0, length = objectKeyList.length; index < length; index += 1) {
|
||||
pairBuffer = '';
|
||||
|
||||
if (!compact || index !== 0) {
|
||||
pairBuffer += generateNextLine(state, level);
|
||||
}
|
||||
|
||||
objectKey = objectKeyList[index];
|
||||
objectValue = object[objectKey];
|
||||
|
||||
if (!writeNode(state, level + 1, objectKey, true, true, true)) {
|
||||
continue; // Skip this pair because of invalid key.
|
||||
}
|
||||
|
||||
explicitPair = (state.tag !== null && state.tag !== '?') ||
|
||||
(state.dump && state.dump.length > 1024);
|
||||
|
||||
if (explicitPair) {
|
||||
if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) {
|
||||
pairBuffer += '?';
|
||||
} else {
|
||||
pairBuffer += '? ';
|
||||
}
|
||||
}
|
||||
|
||||
pairBuffer += state.dump;
|
||||
|
||||
if (explicitPair) {
|
||||
pairBuffer += generateNextLine(state, level);
|
||||
}
|
||||
|
||||
if (!writeNode(state, level + 1, objectValue, true, explicitPair)) {
|
||||
continue; // Skip this pair because of invalid value.
|
||||
}
|
||||
|
||||
if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) {
|
||||
pairBuffer += ':';
|
||||
} else {
|
||||
pairBuffer += ': ';
|
||||
}
|
||||
|
||||
pairBuffer += state.dump;
|
||||
|
||||
// Both key and value are valid.
|
||||
_result += pairBuffer;
|
||||
}
|
||||
|
||||
state.tag = _tag;
|
||||
state.dump = _result || '{}'; // Empty mapping if no valid pairs.
|
||||
}
|
||||
|
||||
function detectType(state, object, explicit) {
|
||||
var _result, typeList, index, length, type, style;
|
||||
|
||||
typeList = explicit ? state.explicitTypes : state.implicitTypes;
|
||||
|
||||
for (index = 0, length = typeList.length; index < length; index += 1) {
|
||||
type = typeList[index];
|
||||
|
||||
if ((type.instanceOf || type.predicate) &&
|
||||
(!type.instanceOf || ((typeof object === 'object') && (object instanceof type.instanceOf))) &&
|
||||
(!type.predicate || type.predicate(object))) {
|
||||
|
||||
state.tag = explicit ? type.tag : '?';
|
||||
|
||||
if (type.represent) {
|
||||
style = state.styleMap[type.tag] || type.defaultStyle;
|
||||
|
||||
if (_toString.call(type.represent) === '[object Function]') {
|
||||
_result = type.represent(object, style);
|
||||
} else if (_hasOwnProperty.call(type.represent, style)) {
|
||||
_result = type.represent[style](object, style);
|
||||
} else {
|
||||
throw new YAMLException('!<' + type.tag + '> tag resolver accepts not "' + style + '" style');
|
||||
}
|
||||
|
||||
state.dump = _result;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Serializes `object` and writes it to global `result`.
|
||||
// Returns true on success, or false on invalid object.
|
||||
//
|
||||
function writeNode(state, level, object, block, compact, iskey) {
|
||||
state.tag = null;
|
||||
state.dump = object;
|
||||
|
||||
if (!detectType(state, object, false)) {
|
||||
detectType(state, object, true);
|
||||
}
|
||||
|
||||
var type = _toString.call(state.dump);
|
||||
|
||||
if (block) {
|
||||
block = (state.flowLevel < 0 || state.flowLevel > level);
|
||||
}
|
||||
|
||||
var objectOrArray = type === '[object Object]' || type === '[object Array]',
|
||||
duplicateIndex,
|
||||
duplicate;
|
||||
|
||||
if (objectOrArray) {
|
||||
duplicateIndex = state.duplicates.indexOf(object);
|
||||
duplicate = duplicateIndex !== -1;
|
||||
}
|
||||
|
||||
if ((state.tag !== null && state.tag !== '?') || duplicate || (state.indent !== 2 && level > 0)) {
|
||||
compact = false;
|
||||
}
|
||||
|
||||
if (duplicate && state.usedDuplicates[duplicateIndex]) {
|
||||
state.dump = '*ref_' + duplicateIndex;
|
||||
} else {
|
||||
if (objectOrArray && duplicate && !state.usedDuplicates[duplicateIndex]) {
|
||||
state.usedDuplicates[duplicateIndex] = true;
|
||||
}
|
||||
if (type === '[object Object]') {
|
||||
if (block && (Object.keys(state.dump).length !== 0)) {
|
||||
writeBlockMapping(state, level, state.dump, compact);
|
||||
if (duplicate) {
|
||||
state.dump = '&ref_' + duplicateIndex + state.dump;
|
||||
}
|
||||
} else {
|
||||
writeFlowMapping(state, level, state.dump);
|
||||
if (duplicate) {
|
||||
state.dump = '&ref_' + duplicateIndex + ' ' + state.dump;
|
||||
}
|
||||
}
|
||||
} else if (type === '[object Array]') {
|
||||
var arrayLevel = (state.noArrayIndent && (level > 0)) ? level - 1 : level;
|
||||
if (block && (state.dump.length !== 0)) {
|
||||
writeBlockSequence(state, arrayLevel, state.dump, compact);
|
||||
if (duplicate) {
|
||||
state.dump = '&ref_' + duplicateIndex + state.dump;
|
||||
}
|
||||
} else {
|
||||
writeFlowSequence(state, arrayLevel, state.dump);
|
||||
if (duplicate) {
|
||||
state.dump = '&ref_' + duplicateIndex + ' ' + state.dump;
|
||||
}
|
||||
}
|
||||
} else if (type === '[object String]') {
|
||||
if (state.tag !== '?') {
|
||||
writeScalar(state, state.dump, level, iskey);
|
||||
}
|
||||
} else {
|
||||
if (state.skipInvalid) return false;
|
||||
throw new YAMLException('unacceptable kind of an object to dump ' + type);
|
||||
}
|
||||
|
||||
if (state.tag !== null && state.tag !== '?') {
|
||||
state.dump = '!<' + state.tag + '> ' + state.dump;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function getDuplicateReferences(object, state) {
|
||||
var objects = [],
|
||||
duplicatesIndexes = [],
|
||||
index,
|
||||
length;
|
||||
|
||||
inspectNode(object, objects, duplicatesIndexes);
|
||||
|
||||
for (index = 0, length = duplicatesIndexes.length; index < length; index += 1) {
|
||||
state.duplicates.push(objects[duplicatesIndexes[index]]);
|
||||
}
|
||||
state.usedDuplicates = new Array(length);
|
||||
}
|
||||
|
||||
function inspectNode(object, objects, duplicatesIndexes) {
|
||||
var objectKeyList,
|
||||
index,
|
||||
length;
|
||||
|
||||
if (object !== null && typeof object === 'object') {
|
||||
index = objects.indexOf(object);
|
||||
if (index !== -1) {
|
||||
if (duplicatesIndexes.indexOf(index) === -1) {
|
||||
duplicatesIndexes.push(index);
|
||||
}
|
||||
} else {
|
||||
objects.push(object);
|
||||
|
||||
if (Array.isArray(object)) {
|
||||
for (index = 0, length = object.length; index < length; index += 1) {
|
||||
inspectNode(object[index], objects, duplicatesIndexes);
|
||||
}
|
||||
} else {
|
||||
objectKeyList = Object.keys(object);
|
||||
|
||||
for (index = 0, length = objectKeyList.length; index < length; index += 1) {
|
||||
inspectNode(object[objectKeyList[index]], objects, duplicatesIndexes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function dump(input, options) {
|
||||
options = options || {};
|
||||
|
||||
var state = new State(options);
|
||||
|
||||
if (!state.noRefs) getDuplicateReferences(input, state);
|
||||
|
||||
if (writeNode(state, 0, input, true, true)) return state.dump + '\n';
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
function safeDump(input, options) {
|
||||
return dump(input, common.extend({ schema: DEFAULT_SAFE_SCHEMA }, options));
|
||||
}
|
||||
|
||||
module.exports.dump = dump;
|
||||
module.exports.safeDump = safeDump;
|
|
@ -0,0 +1,43 @@
|
|||
// YAML error class. http://stackoverflow.com/questions/8458984
|
||||
//
|
||||
'use strict';
|
||||
|
||||
function YAMLException(reason, mark) {
|
||||
// Super constructor
|
||||
Error.call(this);
|
||||
|
||||
this.name = 'YAMLException';
|
||||
this.reason = reason;
|
||||
this.mark = mark;
|
||||
this.message = (this.reason || '(unknown reason)') + (this.mark ? ' ' + this.mark.toString() : '');
|
||||
|
||||
// Include stack trace in error object
|
||||
if (Error.captureStackTrace) {
|
||||
// Chrome and NodeJS
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
} else {
|
||||
// FF, IE 10+ and Safari 6+. Fallback for others
|
||||
this.stack = (new Error()).stack || '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Inherit from Error
|
||||
YAMLException.prototype = Object.create(Error.prototype);
|
||||
YAMLException.prototype.constructor = YAMLException;
|
||||
|
||||
|
||||
YAMLException.prototype.toString = function toString(compact) {
|
||||
var result = this.name + ': ';
|
||||
|
||||
result += this.reason || '(unknown reason)';
|
||||
|
||||
if (!compact && this.mark) {
|
||||
result += ' ' + this.mark.toString();
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
module.exports = YAMLException;
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,76 @@
|
|||
'use strict';
|
||||
|
||||
|
||||
var common = require('./common');
|
||||
|
||||
|
||||
function Mark(name, buffer, position, line, column) {
|
||||
this.name = name;
|
||||
this.buffer = buffer;
|
||||
this.position = position;
|
||||
this.line = line;
|
||||
this.column = column;
|
||||
}
|
||||
|
||||
|
||||
Mark.prototype.getSnippet = function getSnippet(indent, maxLength) {
|
||||
var head, start, tail, end, snippet;
|
||||
|
||||
if (!this.buffer) return null;
|
||||
|
||||
indent = indent || 4;
|
||||
maxLength = maxLength || 75;
|
||||
|
||||
head = '';
|
||||
start = this.position;
|
||||
|
||||
while (start > 0 && '\x00\r\n\x85\u2028\u2029'.indexOf(this.buffer.charAt(start - 1)) === -1) {
|
||||
start -= 1;
|
||||
if (this.position - start > (maxLength / 2 - 1)) {
|
||||
head = ' ... ';
|
||||
start += 5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tail = '';
|
||||
end = this.position;
|
||||
|
||||
while (end < this.buffer.length && '\x00\r\n\x85\u2028\u2029'.indexOf(this.buffer.charAt(end)) === -1) {
|
||||
end += 1;
|
||||
if (end - this.position > (maxLength / 2 - 1)) {
|
||||
tail = ' ... ';
|
||||
end -= 5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
snippet = this.buffer.slice(start, end);
|
||||
|
||||
return common.repeat(' ', indent) + head + snippet + tail + '\n' +
|
||||
common.repeat(' ', indent + this.position - start + head.length) + '^';
|
||||
};
|
||||
|
||||
|
||||
Mark.prototype.toString = function toString(compact) {
|
||||
var snippet, where = '';
|
||||
|
||||
if (this.name) {
|
||||
where += 'in "' + this.name + '" ';
|
||||
}
|
||||
|
||||
where += 'at line ' + (this.line + 1) + ', column ' + (this.column + 1);
|
||||
|
||||
if (!compact) {
|
||||
snippet = this.getSnippet();
|
||||
|
||||
if (snippet) {
|
||||
where += ':\n' + snippet;
|
||||
}
|
||||
}
|
||||
|
||||
return where;
|
||||
};
|
||||
|
||||
|
||||
module.exports = Mark;
|
|
@ -0,0 +1,108 @@
|
|||
'use strict';
|
||||
|
||||
/*eslint-disable max-len*/
|
||||
|
||||
var common = require('./common');
|
||||
var YAMLException = require('./exception');
|
||||
var Type = require('./type');
|
||||
|
||||
|
||||
function compileList(schema, name, result) {
|
||||
var exclude = [];
|
||||
|
||||
schema.include.forEach(function (includedSchema) {
|
||||
result = compileList(includedSchema, name, result);
|
||||
});
|
||||
|
||||
schema[name].forEach(function (currentType) {
|
||||
result.forEach(function (previousType, previousIndex) {
|
||||
if (previousType.tag === currentType.tag && previousType.kind === currentType.kind) {
|
||||
exclude.push(previousIndex);
|
||||
}
|
||||
});
|
||||
|
||||
result.push(currentType);
|
||||
});
|
||||
|
||||
return result.filter(function (type, index) {
|
||||
return exclude.indexOf(index) === -1;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function compileMap(/* lists... */) {
|
||||
var result = {
|
||||
scalar: {},
|
||||
sequence: {},
|
||||
mapping: {},
|
||||
fallback: {}
|
||||
}, index, length;
|
||||
|
||||
function collectType(type) {
|
||||
result[type.kind][type.tag] = result['fallback'][type.tag] = type;
|
||||
}
|
||||
|
||||
for (index = 0, length = arguments.length; index < length; index += 1) {
|
||||
arguments[index].forEach(collectType);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
function Schema(definition) {
|
||||
this.include = definition.include || [];
|
||||
this.implicit = definition.implicit || [];
|
||||
this.explicit = definition.explicit || [];
|
||||
|
||||
this.implicit.forEach(function (type) {
|
||||
if (type.loadKind && type.loadKind !== 'scalar') {
|
||||
throw new YAMLException('There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.');
|
||||
}
|
||||
});
|
||||
|
||||
this.compiledImplicit = compileList(this, 'implicit', []);
|
||||
this.compiledExplicit = compileList(this, 'explicit', []);
|
||||
this.compiledTypeMap = compileMap(this.compiledImplicit, this.compiledExplicit);
|
||||
}
|
||||
|
||||
|
||||
Schema.DEFAULT = null;
|
||||
|
||||
|
||||
Schema.create = function createSchema() {
|
||||
var schemas, types;
|
||||
|
||||
switch (arguments.length) {
|
||||
case 1:
|
||||
schemas = Schema.DEFAULT;
|
||||
types = arguments[0];
|
||||
break;
|
||||
|
||||
case 2:
|
||||
schemas = arguments[0];
|
||||
types = arguments[1];
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new YAMLException('Wrong number of arguments for Schema.create function');
|
||||
}
|
||||
|
||||
schemas = common.toArray(schemas);
|
||||
types = common.toArray(types);
|
||||
|
||||
if (!schemas.every(function (schema) { return schema instanceof Schema; })) {
|
||||
throw new YAMLException('Specified list of super schemas (or a single Schema object) contains a non-Schema object.');
|
||||
}
|
||||
|
||||
if (!types.every(function (type) { return type instanceof Type; })) {
|
||||
throw new YAMLException('Specified list of YAML types (or a single Type object) contains a non-Type object.');
|
||||
}
|
||||
|
||||
return new Schema({
|
||||
include: schemas,
|
||||
explicit: types
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
module.exports = Schema;
|
|
@ -0,0 +1,18 @@
|
|||
// Standard YAML's Core schema.
|
||||
// http://www.yaml.org/spec/1.2/spec.html#id2804923
|
||||
//
|
||||
// NOTE: JS-YAML does not support schema-specific tag resolution restrictions.
|
||||
// So, Core schema has no distinctions from JSON schema is JS-YAML.
|
||||
|
||||
|
||||
'use strict';
|
||||
|
||||
|
||||
var Schema = require('../schema');
|
||||
|
||||
|
||||
module.exports = new Schema({
|
||||
include: [
|
||||
require('./json')
|
||||
]
|
||||
});
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче