зеркало из https://github.com/Azure/autorest.git
Run prettier on all files
This commit is contained in:
Родитель
43fea261a0
Коммит
2a9ab1fde5
|
@ -1,4 +1,4 @@
|
|||
// set the base folder of this project
|
||||
global.basefolder = `${__dirname}`
|
||||
require ("rechoir").prepare(require('interpret').extensions, './.gulp/gulpfile.iced');
|
||||
require ('./.gulp/gulpfile.iced')
|
||||
global.basefolder = `${__dirname}`;
|
||||
require("rechoir").prepare(require("interpret").extensions, "./.gulp/gulpfile.iced");
|
||||
require("./.gulp/gulpfile.iced");
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
parser: '@typescript-eslint/parser'
|
||||
parser: "@typescript-eslint/parser"
|
||||
plugins:
|
||||
- '@typescript-eslint'
|
||||
- "@typescript-eslint"
|
||||
- prettier
|
||||
env:
|
||||
es6: true
|
||||
|
@ -17,28 +17,28 @@ parserOptions:
|
|||
sourceType: module
|
||||
warnOnUnsupportedTypeScriptVersion: false
|
||||
rules:
|
||||
'@typescript-eslint/no-this-alias': 'off'
|
||||
'@typescript-eslint/interface-name-prefix': 'off'
|
||||
'@typescript-eslint/explicit-function-return-type': 'off'
|
||||
'@typescript-eslint/no-explicit-any': 'off'
|
||||
'@typescript-eslint/no-empty-interface': 'off'
|
||||
'@typescript-eslint/no-namespace': 'off'
|
||||
'@typescript-eslint/explicit-member-accessibility': 'off'
|
||||
'@typescript-eslint/no-unused-vars': 'off'
|
||||
'@typescript-eslint/no-parameter-properties': 'off'
|
||||
'@typescript-eslint/no-angle-bracket-type-assertion': 'off'
|
||||
'require-atomic-updates': 'off'
|
||||
'@typescript-eslint/consistent-type-assertions':
|
||||
"@typescript-eslint/no-this-alias": "off"
|
||||
"@typescript-eslint/interface-name-prefix": "off"
|
||||
"@typescript-eslint/explicit-function-return-type": "off"
|
||||
"@typescript-eslint/no-explicit-any": "off"
|
||||
"@typescript-eslint/no-empty-interface": "off"
|
||||
"@typescript-eslint/no-namespace": "off"
|
||||
"@typescript-eslint/explicit-member-accessibility": "off"
|
||||
"@typescript-eslint/no-unused-vars": "off"
|
||||
"@typescript-eslint/no-parameter-properties": "off"
|
||||
"@typescript-eslint/no-angle-bracket-type-assertion": "off"
|
||||
"require-atomic-updates": "off"
|
||||
"@typescript-eslint/consistent-type-assertions":
|
||||
- warn
|
||||
- assertionStyle: 'angle-bracket'
|
||||
- assertionStyle: "angle-bracket"
|
||||
|
||||
'@typescript-eslint/array-type':
|
||||
"@typescript-eslint/array-type":
|
||||
- warn
|
||||
- default: generic
|
||||
no-undef: 'off'
|
||||
no-unused-vars: 'off'
|
||||
no-undef: "off"
|
||||
no-unused-vars: "off"
|
||||
linebreak-style:
|
||||
- 'warn'
|
||||
- "warn"
|
||||
- unix
|
||||
semi:
|
||||
- warn
|
||||
|
|
|
@ -4,49 +4,48 @@ on:
|
|||
push:
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: '0 19 * * 0'
|
||||
- cron: "0 19 * * 0"
|
||||
|
||||
jobs:
|
||||
CodeQL-Build:
|
||||
|
||||
# CodeQL runs on ubuntu-latest and windows-latest
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
fetch-depth: 2
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
fetch-depth: 2
|
||||
|
||||
# If this run was triggered by a pull request event, then checkout
|
||||
# the head of the pull request instead of the merge commit.
|
||||
- run: git checkout HEAD^2
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
# Override language selection by uncommenting this and choosing your languages
|
||||
# with:
|
||||
# languages: go, javascript, csharp, python, cpp, java
|
||||
# If this run was triggered by a pull request event, then checkout
|
||||
# the head of the pull request instead of the merge commit.
|
||||
- run: git checkout HEAD^2
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
# Override language selection by uncommenting this and choosing your languages
|
||||
# with:
|
||||
# languages: go, javascript, csharp, python, cpp, java
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
trailingComma: 'all'
|
||||
trailingComma: "all"
|
||||
printWidth: 120
|
||||
quoteProps: 'consistent'
|
||||
endOfLine: 'auto'
|
||||
quoteProps: "consistent"
|
||||
endOfLine: "auto"
|
||||
arrowParens: always
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
const { spawn } = require('child_process');
|
||||
const { readFileSync } = require('fs');
|
||||
const { resolve } = require('path');
|
||||
const { spawn } = require("child_process");
|
||||
const { readFileSync } = require("fs");
|
||||
const { resolve } = require("path");
|
||||
|
||||
function read(filename) {
|
||||
const txt = readFileSync(filename, "utf8")
|
||||
|
@ -17,8 +17,6 @@ const repo = `${__dirname}/..`;
|
|||
const rush = read(`${repo}/rush.json`);
|
||||
const pjs = {};
|
||||
|
||||
|
||||
|
||||
function forEachProject(onEach) {
|
||||
// load all the projects
|
||||
for (const each of rush.projects) {
|
||||
|
@ -42,28 +40,33 @@ function npmForEach(cmd) {
|
|||
const proc = spawn("npm", ["--silent", "run", cmd], { cwd: location, shell: true, stdio: "inherit" });
|
||||
procs.push(proc);
|
||||
result[name] = {
|
||||
name, location, project, proc,
|
||||
name,
|
||||
location,
|
||||
project,
|
||||
proc,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
procs.forEach(proc => proc.on("close", (code, signal) => {
|
||||
count--;
|
||||
exitCode += code;
|
||||
procs.forEach((proc) =>
|
||||
proc.on("close", (code, signal) => {
|
||||
count--;
|
||||
exitCode += code;
|
||||
|
||||
if (count === 0) {
|
||||
const t2 = process.uptime() * 100;
|
||||
if (count === 0) {
|
||||
const t2 = process.uptime() * 100;
|
||||
|
||||
console.log('---------------------------------------------------------');
|
||||
if (exitCode !== 0) {
|
||||
console.log(` Done : command '${cmd}' - ${Math.floor(t2 - t1) / 100} s -- Errors ${exitCode} `)
|
||||
} else {
|
||||
console.log(` Done : command '${cmd}' - ${Math.floor(t2 - t1) / 100} s -- No Errors `)
|
||||
console.log("---------------------------------------------------------");
|
||||
if (exitCode !== 0) {
|
||||
console.log(` Done : command '${cmd}' - ${Math.floor(t2 - t1) / 100} s -- Errors ${exitCode} `);
|
||||
} else {
|
||||
console.log(` Done : command '${cmd}' - ${Math.floor(t2 - t1) / 100} s -- No Errors `);
|
||||
}
|
||||
console.log("---------------------------------------------------------");
|
||||
process.exit(exitCode);
|
||||
}
|
||||
console.log('---------------------------------------------------------');
|
||||
process.exit(exitCode);
|
||||
}
|
||||
}));
|
||||
}),
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
// Runs the npm run command on each project that has it.
|
||||
require('./for-each').npm(process.argv[2]);
|
||||
require("./for-each").npm(process.argv[2]);
|
||||
|
|
|
@ -4,60 +4,59 @@
|
|||
# https://docs.microsoft.com/azure/devops/pipelines/languages/javascript
|
||||
|
||||
trigger:
|
||||
- master
|
||||
- master
|
||||
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
vmImage: "ubuntu-latest"
|
||||
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: '10.x'
|
||||
displayName: 'Install Node.js'
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: "10.x"
|
||||
displayName: "Install Node.js"
|
||||
|
||||
- script: |
|
||||
# ensure latest npm is installed
|
||||
npm install -g npm
|
||||
- script: |
|
||||
# ensure latest npm is installed
|
||||
npm install -g npm
|
||||
|
||||
npm install -g publish-release
|
||||
npm install -g publish-release
|
||||
|
||||
# Remove any existing node_modules folder just in case
|
||||
rm -rf node_modules
|
||||
# Remove any existing node_modules folder just in case
|
||||
rm -rf node_modules
|
||||
|
||||
# make sure the versions are all synchronized
|
||||
npx @microsoft/rush set-versions
|
||||
rc=$?; if [ $rc -ne 0 ]; then exit $rc ; fi
|
||||
# make sure the versions are all synchronized
|
||||
npx @microsoft/rush set-versions
|
||||
rc=$?; if [ $rc -ne 0 ]; then exit $rc ; fi
|
||||
|
||||
# copy the autorest folder into autorestautorest
|
||||
# and tweak the files so we can build @autorest/autorest too.
|
||||
cp -r autorest autorestautorest
|
||||
sed 's/\"name\": \"autorest\",/\"name\": \"@autorest\/autorest\",/g' -i autorestautorest/package.json
|
||||
sed 's/\"autorest\":/\"autorest-beta\":/g' -i autorestautorest/package.json
|
||||
sed 's/.*#region.*//g' -i rush.json
|
||||
# copy the autorest folder into autorestautorest
|
||||
# and tweak the files so we can build @autorest/autorest too.
|
||||
cp -r autorest autorestautorest
|
||||
sed 's/\"name\": \"autorest\",/\"name\": \"@autorest\/autorest\",/g' -i autorestautorest/package.json
|
||||
sed 's/\"autorest\":/\"autorest-beta\":/g' -i autorestautorest/package.json
|
||||
sed 's/.*#region.*//g' -i rush.json
|
||||
|
||||
# pull in dependencies
|
||||
npx @microsoft/rush update
|
||||
rc=$?; if [ $rc -ne 0 ]; then exit $rc ; fi
|
||||
# pull in dependencies
|
||||
npx @microsoft/rush update
|
||||
rc=$?; if [ $rc -ne 0 ]; then exit $rc ; fi
|
||||
|
||||
# compile the code
|
||||
npx @microsoft/rush rebuild
|
||||
rc=$?; if [ $rc -ne 0 ]; then exit $rc ; fi
|
||||
# compile the code
|
||||
npx @microsoft/rush rebuild
|
||||
rc=$?; if [ $rc -ne 0 ]; then exit $rc ; fi
|
||||
|
||||
# build the packages
|
||||
npx @microsoft/rush publish --publish --pack --include-all
|
||||
rc=$?; if [ $rc -ne 0 ]; then exit $rc ; fi
|
||||
# build the packages
|
||||
npx @microsoft/rush publish --publish --pack --include-all
|
||||
rc=$?; if [ $rc -ne 0 ]; then exit $rc ; fi
|
||||
|
||||
# publish packages to a github release.
|
||||
# publish packages to a github release.
|
||||
|
||||
# publish autorest cli and beta (@autorest/autorest)
|
||||
cd autorest
|
||||
v=`node -e "console.log(require('./package.json').version)"`
|
||||
publish-release --token $(azuresdk-github-pat) --repo autorest --owner azure --name autorest-$v --tag autorest-$v --notes='prerelease build' --prerelease --editRelease false --assets ../common/temp/artifacts/packages/autorest-$v.tgz --assets ../common/temp/artifacts/packages/autorest-autorest-$v.tgz --target_commitish $(Build.SourceBranchName)
|
||||
cd ..
|
||||
|
||||
# publish autorest core
|
||||
cd core
|
||||
v=`node -e "console.log(require('./package.json').version)"`
|
||||
publish-release --token $(azuresdk-github-pat) --repo autorest --owner azure --name autorest-core-$v --tag autorest-core-$v --notes='prerelease build' --prerelease --editRelease false --assets ../common/temp/artifacts/packages/autorest-core-$v.tgz --target_commitish $(Build.SourceBranchName)
|
||||
cd ..
|
||||
# publish autorest cli and beta (@autorest/autorest)
|
||||
cd autorest
|
||||
v=`node -e "console.log(require('./package.json').version)"`
|
||||
publish-release --token $(azuresdk-github-pat) --repo autorest --owner azure --name autorest-$v --tag autorest-$v --notes='prerelease build' --prerelease --editRelease false --assets ../common/temp/artifacts/packages/autorest-$v.tgz --assets ../common/temp/artifacts/packages/autorest-autorest-$v.tgz --target_commitish $(Build.SourceBranchName)
|
||||
cd ..
|
||||
|
||||
# publish autorest core
|
||||
cd core
|
||||
v=`node -e "console.log(require('./package.json').version)"`
|
||||
publish-release --token $(azuresdk-github-pat) --repo autorest --owner azure --name autorest-core-$v --tag autorest-core-$v --notes='prerelease build' --prerelease --editRelease false --assets ../common/temp/artifacts/packages/autorest-core-$v.tgz --target_commitish $(Build.SourceBranchName)
|
||||
cd ..
|
||||
|
|
|
@ -3,42 +3,42 @@
|
|||
# if you want to set a secondary tag on the package (like V2), set the $(altTag) variable
|
||||
|
||||
trigger:
|
||||
- master
|
||||
- master
|
||||
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
vmImage: "ubuntu-latest"
|
||||
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: '12.x'
|
||||
displayName: 'Install Node.js'
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: "12.x"
|
||||
displayName: "Install Node.js"
|
||||
|
||||
- script: |
|
||||
# ensure latest npm is installed
|
||||
npm install -g npm
|
||||
npm config set //registry.npmjs.org/:_authToken=$(azure-sdk-npm-token)
|
||||
- script: |
|
||||
# ensure latest npm is installed
|
||||
npm install -g npm
|
||||
npm config set //registry.npmjs.org/:_authToken=$(azure-sdk-npm-token)
|
||||
|
||||
# grab the file specified
|
||||
wget $(pkg)
|
||||
rc=$?; if [ $rc -ne 0 ]; then exit $rc ; fi
|
||||
|
||||
# determine the tag
|
||||
npmTag="latest"
|
||||
if [ -n "$(tag)" ]; then
|
||||
npmTag=$(tag)
|
||||
fi
|
||||
|
||||
# publish it to npm
|
||||
for file in *.tgz
|
||||
do
|
||||
npm publish $file --tag $npmTag --access public
|
||||
# grab the file specified
|
||||
wget $(pkg)
|
||||
rc=$?; if [ $rc -ne 0 ]; then exit $rc ; fi
|
||||
|
||||
# set the alternate tag, if applicable
|
||||
if [ -n "$(altTag)" ]; then
|
||||
tar -zxvf $file
|
||||
cd package/
|
||||
npm dist-tag add $(npm show . name)@$(npm show . version) --tag $(altTag)
|
||||
# determine the tag
|
||||
npmTag="latest"
|
||||
if [ -n "$(tag)" ]; then
|
||||
npmTag=$(tag)
|
||||
fi
|
||||
done
|
||||
|
||||
# publish it to npm
|
||||
for file in *.tgz
|
||||
do
|
||||
npm publish $file --tag $npmTag --access public
|
||||
rc=$?; if [ $rc -ne 0 ]; then exit $rc ; fi
|
||||
|
||||
# set the alternate tag, if applicable
|
||||
if [ -n "$(altTag)" ]; then
|
||||
tar -zxvf $file
|
||||
cd package/
|
||||
npm dist-tag add $(npm show . name)@$(npm show . version) --tag $(altTag)
|
||||
fi
|
||||
done
|
||||
|
|
|
@ -5,59 +5,59 @@ debug: false
|
|||
specs:
|
||||
- specRootPath: ../node_modules/@microsoft.azure/autorest.testserver/swagger
|
||||
specPaths:
|
||||
- additionalProperties.json
|
||||
- azure-parameter-grouping.json
|
||||
- azure-report.json
|
||||
- azure-resource-x.json
|
||||
- azure-resource.json
|
||||
- azure-special-properties.json
|
||||
- body-array.json
|
||||
- body-boolean.json
|
||||
- body-boolean.quirks.json
|
||||
- body-byte.json
|
||||
- body-complex.json
|
||||
- body-date.json
|
||||
- body-datetime-rfc1123.json
|
||||
- body-datetime.json
|
||||
- body-duration.json
|
||||
- body-dictionary.json
|
||||
- body-file.json
|
||||
# Not yet supported by AutoRest v3 and Modelerfour
|
||||
# - body-formdata-urlencoded.json
|
||||
# - body-formdata.json
|
||||
- body-integer.json
|
||||
- body-number.json
|
||||
- body-number.quirks.json
|
||||
- body-string.json
|
||||
- body-string.quirks.json
|
||||
- complex-model.json
|
||||
- custom-baseUrl.json
|
||||
- custom-baseUrl-more-options.json
|
||||
- custom-baseUrl-paging.json
|
||||
- extensible-enums-swagger.json
|
||||
- head-exceptions.json
|
||||
- head.json
|
||||
- header.json
|
||||
- httpInfrastructure.json
|
||||
- httpInfrastructure.quirks.json
|
||||
- lro.json
|
||||
- media_types.json
|
||||
- model-flattening.json
|
||||
- multiapi-v1.json
|
||||
- multiapi-v2.json
|
||||
- multiapi-v3.json
|
||||
- object-type.json
|
||||
- paging.json
|
||||
- parameter-flattening.json
|
||||
- report.json
|
||||
- required-optional.json
|
||||
- storage.json
|
||||
- subscriptionId-apiVersion.json
|
||||
- url-multi-collectionFormat.json
|
||||
- url.json
|
||||
- validation.json
|
||||
- xml-service.json
|
||||
- xms-error-responses.json
|
||||
- additionalProperties.json
|
||||
- azure-parameter-grouping.json
|
||||
- azure-report.json
|
||||
- azure-resource-x.json
|
||||
- azure-resource.json
|
||||
- azure-special-properties.json
|
||||
- body-array.json
|
||||
- body-boolean.json
|
||||
- body-boolean.quirks.json
|
||||
- body-byte.json
|
||||
- body-complex.json
|
||||
- body-date.json
|
||||
- body-datetime-rfc1123.json
|
||||
- body-datetime.json
|
||||
- body-duration.json
|
||||
- body-dictionary.json
|
||||
- body-file.json
|
||||
# Not yet supported by AutoRest v3 and Modelerfour
|
||||
# - body-formdata-urlencoded.json
|
||||
# - body-formdata.json
|
||||
- body-integer.json
|
||||
- body-number.json
|
||||
- body-number.quirks.json
|
||||
- body-string.json
|
||||
- body-string.quirks.json
|
||||
- complex-model.json
|
||||
- custom-baseUrl.json
|
||||
- custom-baseUrl-more-options.json
|
||||
- custom-baseUrl-paging.json
|
||||
- extensible-enums-swagger.json
|
||||
- head-exceptions.json
|
||||
- head.json
|
||||
- header.json
|
||||
- httpInfrastructure.json
|
||||
- httpInfrastructure.quirks.json
|
||||
- lro.json
|
||||
- media_types.json
|
||||
- model-flattening.json
|
||||
- multiapi-v1.json
|
||||
- multiapi-v2.json
|
||||
- multiapi-v3.json
|
||||
- object-type.json
|
||||
- paging.json
|
||||
- parameter-flattening.json
|
||||
- report.json
|
||||
- required-optional.json
|
||||
- storage.json
|
||||
- subscriptionId-apiVersion.json
|
||||
- url-multi-collectionFormat.json
|
||||
- url.json
|
||||
- validation.json
|
||||
- xml-service.json
|
||||
- xms-error-responses.json
|
||||
languages:
|
||||
- language: python
|
||||
outputPath: ../core/test/regression/python
|
||||
|
|
|
@ -1,44 +1,42 @@
|
|||
const { exec } = require('child_process');
|
||||
const { writeFileSync } = require('fs');
|
||||
const { forEachProject, projectCount } = require('./for-each');
|
||||
const { exec } = require("child_process");
|
||||
const { writeFileSync } = require("fs");
|
||||
const { forEachProject, projectCount } = require("./for-each");
|
||||
|
||||
let count = projectCount;
|
||||
|
||||
|
||||
function updateVersion(name, project, location, patch) {
|
||||
const origJson = JSON.stringify(project, null, 2);
|
||||
|
||||
// update the third digit
|
||||
const verInfo = project.version.split('.');
|
||||
const verInfo = project.version.split(".");
|
||||
verInfo[2] = patch;
|
||||
project.version = verInfo.join('.');
|
||||
project.version = verInfo.join(".");
|
||||
|
||||
// write the file if it's changed
|
||||
const newJson = JSON.stringify(project, null, 2);
|
||||
if (origJson !== newJson) {
|
||||
console.log(`Writing project '${name}' version to '${project.version}' in '${location}'`);
|
||||
writeFileSync(`${location}/package.json`, newJson)
|
||||
writeFileSync(`${location}/package.json`, newJson);
|
||||
}
|
||||
|
||||
count--;
|
||||
if (count === 0) {
|
||||
// last one!
|
||||
// call sync-versions
|
||||
require('./sync-versions');
|
||||
require("./sync-versions");
|
||||
}
|
||||
}
|
||||
|
||||
if (process.argv[2] === '--reset') {
|
||||
if (process.argv[2] === "--reset") {
|
||||
forEachProject((name, location, project) => {
|
||||
updateVersion(name, project, location, 0);
|
||||
})
|
||||
});
|
||||
} else {
|
||||
// Sets the patch version on each package.json in the project.
|
||||
forEachProject((name, location, project) => {
|
||||
exec(`git rev-list --parents HEAD --count --full-history .`, { cwd: location }, (o, stdout) => {
|
||||
const patch = (parseInt(stdout.trim()) + (Number(project.patchOffset) || -1));
|
||||
const patch = parseInt(stdout.trim()) + (Number(project.patchOffset) || -1);
|
||||
updateVersion(name, project, location, patch);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
const { readFileSync, writeFileSync } = require('fs');
|
||||
const { readFileSync, writeFileSync } = require("fs");
|
||||
|
||||
function read(filename) {
|
||||
const txt = readFileSync(filename, 'utf8')
|
||||
.replace(/\r/gm, '')
|
||||
.replace(/\n/gm, '«')
|
||||
.replace(/\/\*.*?\*\//gm, '')
|
||||
.replace(/«/gm, '\n')
|
||||
.replace(/\s+\/\/.*/g, '');
|
||||
const txt = readFileSync(filename, "utf8")
|
||||
.replace(/\r/gm, "")
|
||||
.replace(/\n/gm, "«")
|
||||
.replace(/\/\*.*?\*\//gm, "")
|
||||
.replace(/«/gm, "\n")
|
||||
.replace(/\s+\/\/.*/g, "");
|
||||
return JSON.parse(txt);
|
||||
}
|
||||
|
||||
|
@ -15,26 +15,29 @@ const rush = read(`${__dirname}/../rush.json`);
|
|||
const pjs = {};
|
||||
|
||||
function writeIfChanged(filename, content) {
|
||||
const orig = JSON.parse(readFileSync(filename))
|
||||
const orig = JSON.parse(readFileSync(filename));
|
||||
const origJson = JSON.stringify(orig, null, 2);
|
||||
const json = JSON.stringify(content, null, 2);
|
||||
|
||||
if (origJson !== json) {
|
||||
console.log(`Writing updated file '${filename}'`)
|
||||
writeFileSync(filename, json)
|
||||
console.log(`Writing updated file '${filename}'`);
|
||||
writeFileSync(filename, json);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function versionToInt(ver) {
|
||||
let v = ver.replace(/[^\d\.]/g, '').split('.').slice(0, 3);
|
||||
let v = ver
|
||||
.replace(/[^\d\.]/g, "")
|
||||
.split(".")
|
||||
.slice(0, 3);
|
||||
while (v.length < 3) {
|
||||
v.unshift(0);
|
||||
}
|
||||
let n = 0;
|
||||
for (let i = 0; i < v.length; i++) {
|
||||
n = n + ((2 ** (i * 16)) * parseInt(v[v.length - 1 - i]))
|
||||
n = n + 2 ** (i * 16) * parseInt(v[v.length - 1 - i]);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
@ -51,7 +54,6 @@ function setPeerDependencies(dependencies) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
function recordDeps(dependencies) {
|
||||
for (const packageName in dependencies) {
|
||||
const packageVersion = dependencies[packageName];
|
||||
|
@ -71,7 +73,6 @@ function recordDeps(dependencies) {
|
|||
}
|
||||
const v2 = versionToInt(packageList[packageName]);
|
||||
if (v > v2) {
|
||||
|
||||
packageList[packageName] = packageVersion;
|
||||
}
|
||||
} else {
|
||||
|
@ -82,7 +83,7 @@ function recordDeps(dependencies) {
|
|||
function fixDeps(pj, dependencies) {
|
||||
for (const packageName in dependencies) {
|
||||
if (dependencies[packageName] !== packageList[packageName]) {
|
||||
console.log(`updating ${pj}:${packageName} from '${dependencies[packageName]}' to '${packageList[packageName]}'`)
|
||||
console.log(`updating ${pj}:${packageName} from '${dependencies[packageName]}' to '${packageList[packageName]}'`);
|
||||
dependencies[packageName] = packageList[packageName];
|
||||
}
|
||||
}
|
||||
|
@ -100,8 +101,8 @@ for (const pj of Object.getOwnPropertyNames(pjs)) {
|
|||
const each = pjs[pj];
|
||||
setPeerDependencies(each.dependencies);
|
||||
setPeerDependencies(each.devDependencies);
|
||||
if (each['static-link']) {
|
||||
setPeerDependencies(each['static-link'].dependencies);
|
||||
if (each["static-link"]) {
|
||||
setPeerDependencies(each["static-link"].dependencies);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,8 +112,8 @@ for (const pj of Object.getOwnPropertyNames(pjs)) {
|
|||
const each = pjs[pj];
|
||||
recordDeps(each.dependencies);
|
||||
recordDeps(each.devDependencies);
|
||||
if (each['static-link']) {
|
||||
recordDeps(each['static-link'].dependencies);
|
||||
if (each["static-link"]) {
|
||||
recordDeps(each["static-link"].dependencies);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,8 +121,8 @@ for (const pj of Object.getOwnPropertyNames(pjs)) {
|
|||
const each = pjs[pj];
|
||||
fixDeps(pj, each.dependencies);
|
||||
fixDeps(pj, each.devDependencies);
|
||||
if (each['static-link']) {
|
||||
fixDeps(pj, each['static-link'].dependencies);
|
||||
if (each["static-link"]) {
|
||||
fixDeps(pj, each["static-link"].dependencies);
|
||||
}
|
||||
}
|
||||
var changed = 0;
|
||||
|
@ -138,5 +139,5 @@ for (const each of rush.projects) {
|
|||
if (changed) {
|
||||
console.log(`Updated ${changed} files.`);
|
||||
} else {
|
||||
console.log('No changes made')
|
||||
}
|
||||
console.log("No changes made");
|
||||
}
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
trigger: none
|
||||
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
vmImage: "ubuntu-latest"
|
||||
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: '14.x'
|
||||
displayName: 'Install Node.js'
|
||||
versionSpec: "14.x"
|
||||
displayName: "Install Node.js"
|
||||
|
||||
- script: |
|
||||
npm install -g npm
|
||||
|
@ -21,14 +21,14 @@ steps:
|
|||
|
||||
# Tests are disabled for now, failures to be investigated (Azure/autorest#3400)
|
||||
#npx @microsoft/rush test
|
||||
displayName: 'Rush install, build and test'
|
||||
displayName: "Rush install, build and test"
|
||||
|
||||
- script: npx @microsoft/rush lint -v
|
||||
displayName: Lint
|
||||
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: '3.x'
|
||||
versionSpec: "3.x"
|
||||
displayName: Install Python 3
|
||||
|
||||
- script: |
|
||||
|
|
|
@ -1,25 +1,23 @@
|
|||
var cp = require('child_process');
|
||||
var cp = require("child_process");
|
||||
|
||||
require('./for-each').forEachProject((packageName, projectFolder, project) => {
|
||||
require("./for-each").forEachProject((packageName, projectFolder, project) => {
|
||||
if (project.scripts.watch) {
|
||||
console.log(`npm run watch {cwd: ${__dirname}/../${projectFolder}}`);
|
||||
const proc = cp.spawn('npm', ['run', 'watch'], { cwd: projectFolder, shell: true, stdio: "inherit" });
|
||||
const proc = cp.spawn("npm", ["run", "watch"], { cwd: projectFolder, shell: true, stdio: "inherit" });
|
||||
proc.on("error", (c, s) => {
|
||||
console.log(packageName);
|
||||
console.error(c);
|
||||
console.error(s);
|
||||
});
|
||||
proc.on('exit', (c, s) => {
|
||||
proc.on("exit", (c, s) => {
|
||||
console.log(packageName);
|
||||
console.error(c);
|
||||
console.error(s);
|
||||
});
|
||||
proc.on('message', (c, s) => {
|
||||
proc.on("message", (c, s) => {
|
||||
console.log(packageName);
|
||||
console.error(c);
|
||||
console.error(s);
|
||||
})
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
# configure plugins first
|
||||
parser: "@typescript-eslint/parser"
|
||||
plugins:
|
||||
- "@typescript-eslint"
|
||||
- "@typescript-eslint"
|
||||
|
||||
# then inherit the common settings
|
||||
extends:
|
||||
- "../.default-eslintrc.yaml"
|
||||
- "../.default-eslintrc.yaml"
|
||||
|
|
206
autorest/app.ts
206
autorest/app.ts
|
@ -5,32 +5,47 @@
|
|||
declare const isDebuggerEnabled;
|
||||
const cwd = process.cwd();
|
||||
|
||||
import { isFile, readdir, rmdir, isDirectory } from '@azure-tools/async-io';
|
||||
import { Exception, LazyPromise } from '@azure-tools/tasks';
|
||||
import { homedir } from 'os';
|
||||
import chalk from 'chalk';
|
||||
import { join, dirname } from 'path';
|
||||
import { gt } from 'semver';
|
||||
import { availableVersions, newCorePackage, oldCorePackage, ensureAutorestHome, extensionManager, installedCores, networkEnabled, pkgVersion, resolvePathForLocalVersion, rootFolder, selectVersion, tryRequire, resolveEntrypoint, runCoreOutOfProc } from './autorest-as-a-service';
|
||||
import { color } from './coloring';
|
||||
import { tmpdir } from 'os';
|
||||
import * as vm from 'vm';
|
||||
import { isFile, readdir, rmdir, isDirectory } from "@azure-tools/async-io";
|
||||
import { Exception, LazyPromise } from "@azure-tools/tasks";
|
||||
import { homedir } from "os";
|
||||
import chalk from "chalk";
|
||||
import { join, dirname } from "path";
|
||||
import { gt } from "semver";
|
||||
import {
|
||||
availableVersions,
|
||||
newCorePackage,
|
||||
oldCorePackage,
|
||||
ensureAutorestHome,
|
||||
extensionManager,
|
||||
installedCores,
|
||||
networkEnabled,
|
||||
pkgVersion,
|
||||
resolvePathForLocalVersion,
|
||||
rootFolder,
|
||||
selectVersion,
|
||||
tryRequire,
|
||||
resolveEntrypoint,
|
||||
runCoreOutOfProc,
|
||||
} from "./autorest-as-a-service";
|
||||
import { color } from "./coloring";
|
||||
import { tmpdir } from "os";
|
||||
import * as vm from "vm";
|
||||
|
||||
import { ResolveUri, ReadUri, EnumerateFiles } from '@azure-tools/uri';
|
||||
import { ResolveUri, ReadUri, EnumerateFiles } from "@azure-tools/uri";
|
||||
|
||||
const launchCore = isDebuggerEnabled ? tryRequire : runCoreOutOfProc;
|
||||
|
||||
// aliases, round one.
|
||||
if (process.argv.indexOf('--no-upgrade-check') !== -1) {
|
||||
process.argv.push('--skip-upgrade-check');
|
||||
if (process.argv.indexOf("--no-upgrade-check") !== -1) {
|
||||
process.argv.push("--skip-upgrade-check");
|
||||
}
|
||||
|
||||
if (process.argv.indexOf('--json') !== -1) {
|
||||
process.argv.push('--message-format=json');
|
||||
if (process.argv.indexOf("--json") !== -1) {
|
||||
process.argv.push("--message-format=json");
|
||||
}
|
||||
|
||||
if (process.argv.indexOf('--yaml') !== -1) {
|
||||
process.argv.push('--message-format=yaml');
|
||||
if (process.argv.indexOf("--yaml") !== -1) {
|
||||
process.argv.push("--message-format=yaml");
|
||||
}
|
||||
|
||||
function parseArgs(autorestArgs: Array<string>): any {
|
||||
|
@ -39,8 +54,8 @@ function parseArgs(autorestArgs: Array<string>): any {
|
|||
const match = /^--([^=:]+)([=:](.+))?$/g.exec(arg);
|
||||
if (match) {
|
||||
const key = match[1];
|
||||
let rawValue = match[3] || 'true';
|
||||
if (rawValue.startsWith('.')) {
|
||||
let rawValue = match[3] || "true";
|
||||
if (rawValue.startsWith(".")) {
|
||||
// starts with a . or .. -> this is a relative path to current directory
|
||||
rawValue = join(cwd, rawValue);
|
||||
}
|
||||
|
@ -54,7 +69,7 @@ function parseArgs(autorestArgs: Array<string>): any {
|
|||
try {
|
||||
value = JSON.parse(rawValue);
|
||||
// restrict allowed types (because with great type selection comes great responsibility)
|
||||
if (typeof value !== 'string' && typeof value !== 'boolean') {
|
||||
if (typeof value !== "string" && typeof value !== "boolean") {
|
||||
value = rawValue;
|
||||
}
|
||||
} catch (e) {
|
||||
|
@ -70,33 +85,49 @@ const args = parseArgs(process.argv);
|
|||
(<any>global).__args = args;
|
||||
|
||||
// aliases
|
||||
args['info'] = args['info'] || args['list-installed'];
|
||||
args['preview'] = args['preview'] || args['prerelease'];
|
||||
if (args['v3'] && !args['version']) {
|
||||
// --v3 without --version infers --version:~3.0.6212 +
|
||||
args['version'] = '~3.0.6212';
|
||||
args["info"] = args["info"] || args["list-installed"];
|
||||
args["preview"] = args["preview"] || args["prerelease"];
|
||||
if (args["v3"] && !args["version"]) {
|
||||
// --v3 without --version infers --version:~3.0.6212 +
|
||||
args["version"] = "~3.0.6212";
|
||||
}
|
||||
|
||||
// Suppress the banner if the message-format is set to something other than regular.
|
||||
if ((!args['message-format']) || args['message-format'] === 'regular') {
|
||||
console.log(chalk.green.bold.underline(`AutoRest code generation utility [cli version: ${chalk.white.bold(pkgVersion)}; node: ${chalk.white.bold(process.version)}, max-memory: ${Math.round((require('v8').getHeapStatistics().heap_size_limit) / (1024 * 1024)) & 0xffffffff00} MB]`));
|
||||
console.log(color('(C) 2018 **Microsoft Corporation.**'));
|
||||
console.log(chalk.blue.bold.underline('https://aka.ms/autorest'));
|
||||
if (!args["message-format"] || args["message-format"] === "regular") {
|
||||
console.log(
|
||||
chalk.green.bold.underline(
|
||||
`AutoRest code generation utility [cli version: ${chalk.white.bold(pkgVersion)}; node: ${chalk.white.bold(
|
||||
process.version,
|
||||
)}, max-memory: ${
|
||||
Math.round(require("v8").getHeapStatistics().heap_size_limit / (1024 * 1024)) & 0xffffffff00
|
||||
} MB]`,
|
||||
),
|
||||
);
|
||||
console.log(color("(C) 2018 **Microsoft Corporation.**"));
|
||||
console.log(chalk.blue.bold.underline("https://aka.ms/autorest"));
|
||||
}
|
||||
|
||||
// argument tweakin'
|
||||
const preview: boolean = args.preview;
|
||||
args.info = (args.version === '' || args.version === true) || args.info; // show --info if they use unparameterized --version.
|
||||
const listAvailable: boolean = args['list-available'] || false;
|
||||
args.info = args.version === "" || args.version === true || args.info; // show --info if they use unparameterized --version.
|
||||
const listAvailable: boolean = args["list-available"] || false;
|
||||
const force = args.force || false;
|
||||
|
||||
/** Check if there is an update for the bootstrapper available. */
|
||||
const checkBootstrapper = new LazyPromise(async () => {
|
||||
if (await networkEnabled && !args['skip-upgrade-check']) {
|
||||
if ((await networkEnabled) && !args["skip-upgrade-check"]) {
|
||||
try {
|
||||
const pkg = await (await extensionManager).findPackage('autorest', preview ? 'preview' : 'latest');
|
||||
const pkg = await (await extensionManager).findPackage("autorest", preview ? "preview" : "latest");
|
||||
if (gt(pkg.version, pkgVersion)) {
|
||||
console.log(color(`\n## There is a new version of AutoRest available (${pkg.version}).\n > You can install the newer version with with \`npm install -g autorest@${preview ? 'preview' : 'latest'}\`\n`));
|
||||
console.log(
|
||||
color(
|
||||
`\n## There is a new version of AutoRest available (${
|
||||
pkg.version
|
||||
}).\n > You can install the newer version with with \`npm install -g autorest@${
|
||||
preview ? "preview" : "latest"
|
||||
}\`\n`,
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
// no message then.
|
||||
|
@ -106,21 +137,25 @@ const checkBootstrapper = new LazyPromise(async () => {
|
|||
|
||||
/** Shows the valid available autorest core packages. */
|
||||
async function showAvailableCores(): Promise<number> {
|
||||
let table = '';
|
||||
let table = "";
|
||||
let max = 10;
|
||||
const cores = await availableVersions();
|
||||
for (const v of cores) {
|
||||
max--;
|
||||
table += `\n ${chalk.cyan.bold(newCorePackage.padEnd(30, ' '))} ${chalk.grey.bold(v.padEnd(14, ' '))} `;
|
||||
table += `\n ${chalk.cyan.bold(newCorePackage.padEnd(30, " "))} ${chalk.grey.bold(v.padEnd(14, " "))} `;
|
||||
if (!max) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (args.json) {
|
||||
console.log(JSON.stringify(cores, null, ' '));
|
||||
console.log(JSON.stringify(cores, null, " "));
|
||||
} else {
|
||||
if (table) {
|
||||
console.log(`${chalk.green.bold.underline(' Extension Name'.padEnd(30, ' '))} ${chalk.green.bold.underline('Version'.padEnd(14, ' '))}\n${table}`);
|
||||
console.log(
|
||||
`${chalk.green.bold.underline(" Extension Name".padEnd(30, " "))} ${chalk.green.bold.underline(
|
||||
"Version".padEnd(14, " "),
|
||||
)}\n${table}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -129,19 +164,29 @@ async function showAvailableCores(): Promise<number> {
|
|||
/** Shows all the autorest extensions that are installed. */
|
||||
async function showInstalledExtensions(): Promise<number> {
|
||||
const extensions = await (await extensionManager).getInstalledExtensions();
|
||||
let table = '';
|
||||
let table = "";
|
||||
if (extensions.length > 0) {
|
||||
for (const extension of extensions) {
|
||||
table += `\n ${chalk.cyan((extension.name === newCorePackage || extension.name === oldCorePackage ? 'core' : 'extension').padEnd(10))} ${chalk.cyan.bold(extension.name.padEnd(40))} ${chalk.cyan(extension.version.padEnd(12))} ${chalk.cyan(extension.location)}`;
|
||||
table += `\n ${chalk.cyan(
|
||||
(extension.name === newCorePackage || extension.name === oldCorePackage ? "core" : "extension").padEnd(10),
|
||||
)} ${chalk.cyan.bold(extension.name.padEnd(40))} ${chalk.cyan(extension.version.padEnd(12))} ${chalk.cyan(
|
||||
extension.location,
|
||||
)}`;
|
||||
}
|
||||
}
|
||||
if (args.json) {
|
||||
console.log(JSON.stringify(extensions, null, ' '));
|
||||
console.log(JSON.stringify(extensions, null, " "));
|
||||
} else {
|
||||
if (table) {
|
||||
console.log(color(`\n\n# Showing All Installed Extensions\n\n ${chalk.underline('Type'.padEnd(10))} ${chalk.underline('Extension Name'.padEnd(40))} ${chalk.underline('Version'.padEnd(12))} ${chalk.underline('Location')} ${table}\n\n`));
|
||||
console.log(
|
||||
color(
|
||||
`\n\n# Showing All Installed Extensions\n\n ${chalk.underline("Type".padEnd(10))} ${chalk.underline(
|
||||
"Extension Name".padEnd(40),
|
||||
)} ${chalk.underline("Version".padEnd(12))} ${chalk.underline("Location")} ${table}\n\n`,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
console.log(color('\n\n# Showing All Installed Extensions\n\n > No Extensions are currently installed.\n\n'));
|
||||
console.log(color("\n\n# Showing All Installed Extensions\n\n > No Extensions are currently installed.\n\n"));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -152,7 +197,7 @@ async function clearTempData() {
|
|||
const all = [];
|
||||
const tmp = tmpdir();
|
||||
for (const each of await readdir(tmp)) {
|
||||
if (each.startsWith('autorest')) {
|
||||
if (each.startsWith("autorest")) {
|
||||
const name = join(tmp, each);
|
||||
if (await isDirectory(name)) {
|
||||
all.push(rmdir(name));
|
||||
|
@ -168,29 +213,35 @@ async function clearTempData() {
|
|||
async function configurationSpecifiedVersion(selectedVersion: any) {
|
||||
try {
|
||||
// we can either have a selectedVerison object or a path. See if we can find the AutoRest API
|
||||
const autorestApi = await resolveEntrypoint(typeof selectedVersion === 'string' ? selectedVersion : await selectedVersion.modulePath, 'main');
|
||||
const autorestApi = await resolveEntrypoint(
|
||||
typeof selectedVersion === "string" ? selectedVersion : await selectedVersion.modulePath,
|
||||
"main",
|
||||
);
|
||||
|
||||
// things we need in the sandbox.
|
||||
const sandbox = {
|
||||
require, console, rfs: {
|
||||
require,
|
||||
console,
|
||||
rfs: {
|
||||
EnumerateFileUris: async (folderUri: string): Promise<Array<string>> => {
|
||||
return EnumerateFiles(folderUri, ['readme.md']);
|
||||
return EnumerateFiles(folderUri, ["readme.md"]);
|
||||
},
|
||||
ReadFile: async (uri: string): Promise<string> => {
|
||||
return ReadUri(uri);
|
||||
},
|
||||
WriteFile: async (uri: string, content: string): Promise<void> => {
|
||||
//return WriteString(uri, content);
|
||||
}
|
||||
},
|
||||
},
|
||||
cfgfile: ResolveUri(cwd, args.configFileOrFolder || '.'),
|
||||
switches: args
|
||||
cfgfile: ResolveUri(cwd, args.configFileOrFolder || "."),
|
||||
switches: args,
|
||||
};
|
||||
|
||||
// *sigh* ... there's a bug in most versions of autorest-core that to use the API you have to
|
||||
// *sigh* ... there's a bug in most versions of autorest-core that to use the API you have to
|
||||
// have the current directory set to the package location. We'll fix this in the future versions.
|
||||
process.chdir(dirname(autorestApi));
|
||||
const configSpecifiedVersion = await vm.runInNewContext(`
|
||||
const configSpecifiedVersion = await vm.runInNewContext(
|
||||
`
|
||||
async function go() {
|
||||
// load the autorest api library
|
||||
const r = require('${autorestApi}');
|
||||
|
@ -203,12 +254,18 @@ async function configurationSpecifiedVersion(selectedVersion: any) {
|
|||
return (await api.view).rawConfig.version;
|
||||
}
|
||||
go();
|
||||
`, sandbox);
|
||||
`,
|
||||
sandbox,
|
||||
);
|
||||
|
||||
// if we got back a result, lets return that.
|
||||
if (configSpecifiedVersion) {
|
||||
selectedVersion = await selectVersion(configSpecifiedVersion, false);
|
||||
console.log(chalk.yellow(`NOTE: AutoRest core version selected from configuration: ${chalk.yellow.bold(configSpecifiedVersion)}.`));
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
`NOTE: AutoRest core version selected from configuration: ${chalk.yellow.bold(configSpecifiedVersion)}.`,
|
||||
),
|
||||
);
|
||||
}
|
||||
return selectedVersion;
|
||||
} catch {
|
||||
|
@ -233,7 +290,7 @@ async function main() {
|
|||
/* make sure we have a .autorest folder */
|
||||
await ensureAutorestHome();
|
||||
|
||||
if (args.reset || args['clear-temp']) {
|
||||
if (args.reset || args["clear-temp"]) {
|
||||
// clear out all the temp-data too
|
||||
await clearTempData();
|
||||
}
|
||||
|
@ -247,10 +304,18 @@ async function main() {
|
|||
|
||||
try {
|
||||
await (await extensionManager).reset();
|
||||
console.log(color('\n\n## Cleared the AutoRest extension folder.\nOn the next run, extensions will be reacquired from the repository.'));
|
||||
console.log(
|
||||
color(
|
||||
"\n\n## Cleared the AutoRest extension folder.\nOn the next run, extensions will be reacquired from the repository.",
|
||||
),
|
||||
);
|
||||
process.exit(0);
|
||||
} catch (e) {
|
||||
console.log(color('\n\n## The AutoRest extension folder appears to be locked.\nDo you have a process that is currently using AutoRest (perhaps the vscode extension?).\n\nUnable to reset the extension folder, exiting.'));
|
||||
console.log(
|
||||
color(
|
||||
"\n\n## The AutoRest extension folder appears to be locked.\nDo you have a process that is currently using AutoRest (perhaps the vscode extension?).\n\nUnable to reset the extension folder, exiting.",
|
||||
),
|
||||
);
|
||||
process.exit(10);
|
||||
}
|
||||
}
|
||||
|
@ -258,7 +323,8 @@ async function main() {
|
|||
// We have a chance to fail again later if this proves problematic.
|
||||
}
|
||||
|
||||
let requestedVersion: string = args.version || (args.latest && 'latest') || (args.preview && 'preview') || 'latest-installed';
|
||||
let requestedVersion: string =
|
||||
args.version || (args.latest && "latest") || (args.preview && "preview") || "latest-installed";
|
||||
|
||||
// check to see if local installed core is available.
|
||||
let localVersion = resolvePathForLocalVersion(args.version ? requestedVersion : null);
|
||||
|
@ -279,7 +345,7 @@ async function main() {
|
|||
// if this is still valid, then we're not overriding it from configuration.
|
||||
if (localVersion) {
|
||||
process.chdir(cwd);
|
||||
if (await launchCore(localVersion, 'app.js')) {
|
||||
if (await launchCore(localVersion, "app.js")) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -311,7 +377,15 @@ async function main() {
|
|||
|
||||
for (const each of process.argv) {
|
||||
let keep = true;
|
||||
for (const discard of ['--version', '--list-installed', '--list-available', '--reset', '--latest', '--latest-release', '--runtime-id']) {
|
||||
for (const discard of [
|
||||
"--version",
|
||||
"--list-installed",
|
||||
"--list-available",
|
||||
"--reset",
|
||||
"--latest",
|
||||
"--latest-release",
|
||||
"--runtime-id",
|
||||
]) {
|
||||
if (each === discard || each.startsWith(`${discard}=`) || each.startsWith(`${discard}:`)) {
|
||||
keep = false;
|
||||
}
|
||||
|
@ -324,15 +398,14 @@ async function main() {
|
|||
|
||||
// use this to make the core aware that this run may be legal even without any inputs
|
||||
// this is a valid scenario for "preparation calls" to autorest like `autorest --reset` or `autorest --latest`
|
||||
if (args.reset || args.latest || args.version == 'latest') {
|
||||
if (args.reset || args.latest || args.version == "latest") {
|
||||
// if there is *any* other argument left, that's an indicator that the core is supposed to do something
|
||||
process.argv.push('--allow-no-input');
|
||||
process.argv.push("--allow-no-input");
|
||||
}
|
||||
|
||||
|
||||
// if they never said the version on the command line, we should make a check for the config version.
|
||||
if (!args.version) {
|
||||
selectedVersion = await configurationSpecifiedVersion(selectedVersion) || selectedVersion;
|
||||
selectedVersion = (await configurationSpecifiedVersion(selectedVersion)) || selectedVersion;
|
||||
}
|
||||
|
||||
if (args.debug) {
|
||||
|
@ -342,12 +415,12 @@ async function main() {
|
|||
// reset the working folder to the correct place.
|
||||
process.chdir(cwd);
|
||||
|
||||
const result = await launchCore(await selectedVersion.modulePath, 'app.js');
|
||||
const result = await launchCore(await selectedVersion.modulePath, "app.js");
|
||||
if (!result) {
|
||||
throw new Error(`Unable to start AutoRest Core from ${await selectedVersion.modulePath}`);
|
||||
}
|
||||
} catch (exception) {
|
||||
console.log(chalk.redBright('Failure:'));
|
||||
console.log(chalk.redBright("Failure:"));
|
||||
console.error(chalk.bold(exception));
|
||||
console.error(chalk.bold((<Error>exception).stack));
|
||||
process.exit(1);
|
||||
|
@ -355,4 +428,3 @@ async function main() {
|
|||
}
|
||||
|
||||
main();
|
||||
|
||||
|
|
|
@ -1,39 +1,41 @@
|
|||
import { lookup } from 'dns';
|
||||
import { Extension, ExtensionManager, Package } from '@azure-tools/extension';
|
||||
import { homedir } from 'os';
|
||||
import { dirname, join, resolve } from 'path';
|
||||
import { lookup } from "dns";
|
||||
import { Extension, ExtensionManager, Package } from "@azure-tools/extension";
|
||||
import { homedir } from "os";
|
||||
import { dirname, join, resolve } from "path";
|
||||
|
||||
import { Exception } from '@azure-tools/tasks';
|
||||
import { Exception } from "@azure-tools/tasks";
|
||||
|
||||
import * as semver from 'semver';
|
||||
import { isFile, mkdir, isDirectory } from '@azure-tools/async-io';
|
||||
import { When } from '@azure-tools/tasks';
|
||||
import { mkdtempSync, rmdirSync } from 'fs';
|
||||
import { tmpdir } from 'os';
|
||||
import { spawn } from 'child_process';
|
||||
import * as semver from "semver";
|
||||
import { isFile, mkdir, isDirectory } from "@azure-tools/async-io";
|
||||
import { When } from "@azure-tools/tasks";
|
||||
import { mkdtempSync, rmdirSync } from "fs";
|
||||
import { tmpdir } from "os";
|
||||
import { spawn } from "child_process";
|
||||
|
||||
export const pkgVersion: string = require(`${__dirname}/../package.json`).version;
|
||||
process.env['autorest.home'] = process.env['autorest.home'] || homedir();
|
||||
process.env["autorest.home"] = process.env["autorest.home"] || homedir();
|
||||
|
||||
try {
|
||||
rmdirSync(mkdtempSync(join(process.env['autorest.home'], 'temp')));
|
||||
rmdirSync(mkdtempSync(join(process.env["autorest.home"], "temp")));
|
||||
} catch {
|
||||
// hmm. the home directory isn't writable. let's fallback to $tmp
|
||||
process.env['autorest.home'] = tmpdir();
|
||||
process.env["autorest.home"] = tmpdir();
|
||||
}
|
||||
|
||||
export const rootFolder = join(process.env['autorest.home'], '.autorest');
|
||||
export const rootFolder = join(process.env["autorest.home"], ".autorest");
|
||||
const args = (<any>global).__args || {};
|
||||
|
||||
export const extensionManager: Promise<ExtensionManager> = ExtensionManager.Create(rootFolder);
|
||||
export const oldCorePackage = '@microsoft.azure/autorest-core';
|
||||
export const newCorePackage = '@autorest/core';
|
||||
export const oldCorePackage = "@microsoft.azure/autorest-core";
|
||||
export const newCorePackage = "@autorest/core";
|
||||
|
||||
const basePkgVersion = semver.parse(pkgVersion.indexOf('-') > -1 ? pkgVersion.substring(0, pkgVersion.indexOf('-')) : pkgVersion);
|
||||
const basePkgVersion = semver.parse(
|
||||
pkgVersion.indexOf("-") > -1 ? pkgVersion.substring(0, pkgVersion.indexOf("-")) : pkgVersion,
|
||||
);
|
||||
const versionRange = `~${basePkgVersion.major}.${basePkgVersion.minor}.0`; // the version range of the core package required.
|
||||
|
||||
export const networkEnabled: Promise<boolean> = new Promise<boolean>((r, j) => {
|
||||
lookup('8.8.8.8', 4, (err, address, family) => {
|
||||
lookup("8.8.8.8", 4, (err, address, family) => {
|
||||
r(err ? false : true);
|
||||
});
|
||||
});
|
||||
|
@ -41,7 +43,9 @@ export const networkEnabled: Promise<boolean> = new Promise<boolean>((r, j) => {
|
|||
export async function availableVersions() {
|
||||
if (await networkEnabled) {
|
||||
try {
|
||||
const vers = (await (await extensionManager).getPackageVersions(newCorePackage)).sort((b, a) => semver.compare(a, b));
|
||||
const vers = (await (await extensionManager).getPackageVersions(newCorePackage)).sort((b, a) =>
|
||||
semver.compare(a, b),
|
||||
);
|
||||
const result = new Array<string>();
|
||||
for (const ver of vers) {
|
||||
if (semver.satisfies(ver, versionRange)) {
|
||||
|
@ -52,17 +56,21 @@ export async function availableVersions() {
|
|||
} catch (e) {
|
||||
console.info(`No available versions of package ${newCorePackage} found.`);
|
||||
}
|
||||
|
||||
} else {
|
||||
console.info('Skipping getting available versions because network is not detected.');
|
||||
console.info("Skipping getting available versions because network is not detected.");
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
export async function installedCores() {
|
||||
const extensions = await (await extensionManager).getInstalledExtensions();
|
||||
const result = (extensions.length > 0) ? extensions.filter(ext => (ext.name === newCorePackage || ext.name === oldCorePackage) && semver.satisfies(ext.version, versionRange)) : new Array<Extension>();
|
||||
const result =
|
||||
extensions.length > 0
|
||||
? extensions.filter(
|
||||
(ext) =>
|
||||
(ext.name === newCorePackage || ext.name === oldCorePackage) && semver.satisfies(ext.version, versionRange),
|
||||
)
|
||||
: new Array<Extension>();
|
||||
return result.sort((a, b) => semver.compare(b.version, a.version));
|
||||
}
|
||||
|
||||
|
@ -72,11 +80,11 @@ export function resolvePathForLocalVersion(requestedVersion: string | null): str
|
|||
if (/^~[/|\\]/g.exec(requestedVersion)) {
|
||||
requestedVersion = join(homedir(), requestedVersion.substring(2));
|
||||
}
|
||||
return requestedVersion ? resolve(requestedVersion) : dirname(require.resolve('@autorest/core/package.json'));
|
||||
return requestedVersion ? resolve(requestedVersion) : dirname(require.resolve("@autorest/core/package.json"));
|
||||
} catch (e) {
|
||||
// fallback to old-core name
|
||||
try {
|
||||
return dirname(require.resolve('@microsoft.azure/autorest-core/package.json'));
|
||||
return dirname(require.resolve("@microsoft.azure/autorest-core/package.json"));
|
||||
} catch {
|
||||
// no dice
|
||||
}
|
||||
|
@ -84,14 +92,13 @@ export function resolvePathForLocalVersion(requestedVersion: string | null): str
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
export async function resolveEntrypoint(localPath: string | null, entrypoint: string): Promise<string | null> {
|
||||
try {
|
||||
// did they specify the package directory directly
|
||||
// did they specify the package directory directly
|
||||
if (await isDirectory(localPath)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const pkg = require(`${localPath}/package.json`);
|
||||
if (pkg.name === 'autorest') {
|
||||
if (pkg.name === "autorest") {
|
||||
// you've tried loading the bootstrapper not the core!
|
||||
console.error(`The location you have specified is not autorest-core, it's autorest bootstrapper: ${pkg.name}`);
|
||||
process.exit(1);
|
||||
|
@ -103,35 +110,35 @@ export async function resolveEntrypoint(localPath: string | null, entrypoint: st
|
|||
|
||||
if (pkg.name === oldCorePackage || pkg.name === newCorePackage) {
|
||||
if (args.debug) {
|
||||
console.log('Looks like a core package.');
|
||||
console.log("Looks like a core package.");
|
||||
}
|
||||
switch (entrypoint) {
|
||||
case 'main':
|
||||
case 'main.js':
|
||||
case "main":
|
||||
case "main.js":
|
||||
entrypoint = pkg.main;
|
||||
break;
|
||||
|
||||
case 'language-service':
|
||||
case 'language-service.js':
|
||||
case 'autorest-language-service':
|
||||
entrypoint = pkg.bin['autorest-language-service'];
|
||||
case "language-service":
|
||||
case "language-service.js":
|
||||
case "autorest-language-service":
|
||||
entrypoint = pkg.bin["autorest-language-service"];
|
||||
break;
|
||||
|
||||
case 'autorest':
|
||||
case 'autorest-core':
|
||||
case 'app.js':
|
||||
case 'app':
|
||||
entrypoint = pkg.bin['autorest-core'] || pkg.bin['core'];
|
||||
case "autorest":
|
||||
case "autorest-core":
|
||||
case "app.js":
|
||||
case "app":
|
||||
entrypoint = pkg.bin["autorest-core"] || pkg.bin["core"];
|
||||
break;
|
||||
|
||||
case 'module':
|
||||
case "module":
|
||||
// special case: look for the main entrypoint
|
||||
// but return the module folder
|
||||
if (await isFile(`${localPath}/${pkg.main}`)) {
|
||||
if (args.debug) {
|
||||
console.log(`special case: '${localPath}/${pkg.main}' .`);
|
||||
}
|
||||
return localPath.replace(/\\/g, '/');
|
||||
return localPath.replace(/\\/g, "/");
|
||||
}
|
||||
}
|
||||
const path = `${localPath}/${entrypoint}`;
|
||||
|
@ -139,7 +146,7 @@ export async function resolveEntrypoint(localPath: string | null, entrypoint: st
|
|||
if (args.debug) {
|
||||
console.log(`Using Entrypoint: '${localPath}/${entrypoint}' .`);
|
||||
}
|
||||
return path.replace(/\\/g, '/');
|
||||
return path.replace(/\\/g, "/");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -153,24 +160,26 @@ export async function runCoreOutOfProc(localPath: string | null, entrypoint: str
|
|||
try {
|
||||
const ep = await resolveEntrypoint(localPath, entrypoint);
|
||||
if (ep) {
|
||||
// Creates the nodejs command to load the target core
|
||||
// Creates the nodejs command to load the target core
|
||||
// - copies the argv parameters
|
||||
// - loads our static loader (so the newer loader is used, and we can get to 'chalk' in our static fs)
|
||||
// - loads our static loader (so the newer loader is used, and we can get to 'chalk' in our static fs)
|
||||
// - loads the js file with coloring (core expects a global function called 'color' )
|
||||
// - loads the actual entrypoint that we expect is there.
|
||||
// - loads the actual entrypoint that we expect is there.
|
||||
const cmd = `
|
||||
process.argv = ${ JSON.stringify(process.argv)};
|
||||
process.argv = ${JSON.stringify(process.argv)};
|
||||
if (require('fs').existsSync('${__dirname}/static-loader.js')) { require('${__dirname}/static-loader.js').load('${__dirname}/static_modules.fs'); }
|
||||
const { color } = require('${__dirname}/coloring');
|
||||
require('${ep}')
|
||||
`.replace(/"/g, '\'').replace(/(\\(?![']))+/g, '/');
|
||||
`
|
||||
.replace(/"/g, "'")
|
||||
.replace(/(\\(?![']))+/g, "/");
|
||||
|
||||
const p = spawn(process.execPath, ['-e', cmd], { stdio: ['inherit', 'inherit', 'inherit',] });
|
||||
p.on('close', (code, signal) => {
|
||||
const p = spawn(process.execPath, ["-e", cmd], { stdio: ["inherit", "inherit", "inherit"] });
|
||||
p.on("close", (code, signal) => {
|
||||
process.exit(code);
|
||||
});
|
||||
// set up a promise to wait for the event to fire
|
||||
await When(p, 'exit', 'close');
|
||||
await When(p, "exit", "close");
|
||||
process.exit(0);
|
||||
}
|
||||
} catch (E) {
|
||||
|
@ -205,12 +214,11 @@ export async function selectVersion(requestedVersion: string, force: boolean, mi
|
|||
}
|
||||
|
||||
if (currentVersion) {
|
||||
|
||||
if (args.debug) {
|
||||
console.log(`The most recent installed version is ${currentVersion.version}`);
|
||||
}
|
||||
|
||||
if (requestedVersion === 'latest-installed' || (requestedVersion === 'latest' && false == await networkEnabled)) {
|
||||
if (requestedVersion === "latest-installed" || (requestedVersion === "latest" && false == (await networkEnabled))) {
|
||||
if (args.debug) {
|
||||
console.log(`requesting current version '${currentVersion.version}'`);
|
||||
}
|
||||
|
@ -239,31 +247,36 @@ export async function selectVersion(requestedVersion: string, force: boolean, mi
|
|||
}
|
||||
|
||||
// if it's not a file, and the network isn't available, we can't continue.
|
||||
if (!await isFile(requestedVersion) && !(await networkEnabled)) {
|
||||
if (!(await isFile(requestedVersion)) && !(await networkEnabled)) {
|
||||
// no network enabled.
|
||||
throw new Exception(`Network access is not available, requested version '${requestedVersion}' is not installed. `);
|
||||
throw new Exception(
|
||||
`Network access is not available, requested version '${requestedVersion}' is not installed. `,
|
||||
);
|
||||
}
|
||||
|
||||
// after this point, latest-installed must mean latest.
|
||||
if (requestedVersion === 'latest-installed') {
|
||||
requestedVersion = 'latest';
|
||||
if (requestedVersion === "latest-installed") {
|
||||
requestedVersion = "latest";
|
||||
}
|
||||
|
||||
// if they have requested 'latest' -- they really mean latest with same major version number
|
||||
if (requestedVersion === 'latest') {
|
||||
if (requestedVersion === "latest") {
|
||||
requestedVersion = versionRange;
|
||||
}
|
||||
let corePackageName = newCorePackage;
|
||||
|
||||
let pkg: Package;
|
||||
try {
|
||||
// try the package
|
||||
// try the package
|
||||
pkg = await (await extensionManager).findPackage(newCorePackage, requestedVersion);
|
||||
} catch {
|
||||
// try a prerelease version from github.
|
||||
try {
|
||||
const rv = requestedVersion.replace(/^[~|^]/g, '');
|
||||
pkg = await (await extensionManager).findPackage('core', `https://github.com/Azure/autorest/releases/download/autorest-core-${rv}/autorest-core-${rv}.tgz`);
|
||||
const rv = requestedVersion.replace(/^[~|^]/g, "");
|
||||
pkg = await (await extensionManager).findPackage(
|
||||
"core",
|
||||
`https://github.com/Azure/autorest/releases/download/autorest-core-${rv}/autorest-core-${rv}.tgz`,
|
||||
);
|
||||
} catch {
|
||||
// fallback to old package name
|
||||
try {
|
||||
|
@ -273,7 +286,9 @@ export async function selectVersion(requestedVersion: string, force: boolean, mi
|
|||
}
|
||||
}
|
||||
if (!pkg) {
|
||||
throw new Exception(`Unable to find a valid AutoRest core package '${newCorePackage}' @ '${requestedVersion}'.`);
|
||||
throw new Exception(
|
||||
`Unable to find a valid AutoRest core package '${newCorePackage}' @ '${requestedVersion}'.`,
|
||||
);
|
||||
}
|
||||
corePackageName = oldCorePackage;
|
||||
}
|
||||
|
@ -283,7 +298,7 @@ export async function selectVersion(requestedVersion: string, force: boolean, mi
|
|||
}
|
||||
}
|
||||
|
||||
// pkg.version == the actual version
|
||||
// pkg.version == the actual version
|
||||
// check if it's installed already.
|
||||
selectedVersion = await (await extensionManager).getInstalledExtension(corePackageName, pkg.version);
|
||||
|
||||
|
@ -293,7 +308,11 @@ export async function selectVersion(requestedVersion: string, force: boolean, mi
|
|||
console.log(`**Installing package** ${corePackageName}@${pkg.version}\n[This will take a few moments...]`);
|
||||
}
|
||||
|
||||
selectedVersion = await (await extensionManager).installPackage(pkg, force, 5 * 60 * 1000, installer => installer.Message.Subscribe((s, m) => { if (args.debug) console.log(`Installer: ${m}`); }));
|
||||
selectedVersion = await (await extensionManager).installPackage(pkg, force, 5 * 60 * 1000, (installer) =>
|
||||
installer.Message.Subscribe((s, m) => {
|
||||
if (args.debug) console.log(`Installer: ${m}`);
|
||||
}),
|
||||
);
|
||||
if (args.debug) {
|
||||
console.log(`Extension location: ${selectedVersion.packageJsonPath}`);
|
||||
}
|
||||
|
@ -304,4 +323,4 @@ export async function selectVersion(requestedVersion: string, force: boolean, mi
|
|||
}
|
||||
}
|
||||
return selectedVersion;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import chalk from 'chalk';
|
||||
import chalk from "chalk";
|
||||
|
||||
function addStyle(style: string, text: string): string {
|
||||
return `▌PUSH:${style}▐${text}▌POP▐`;
|
||||
}
|
||||
function compileStyledText(text: string): string {
|
||||
const styleStack = ['(x => x)'];
|
||||
let result = '';
|
||||
const styleStack = ["(x => x)"];
|
||||
let result = "";
|
||||
let consumedUpTo = 0;
|
||||
const appendPart = (end: number) => {
|
||||
const CHALK = chalk;
|
||||
|
@ -16,10 +16,10 @@ function compileStyledText(text: string): string {
|
|||
const commandRegex = /▌(.+?)▐/g;
|
||||
let i: RegExpExecArray;
|
||||
// eslint-disable-next-line no-cond-assign
|
||||
while (i = commandRegex.exec(text)) {
|
||||
while ((i = commandRegex.exec(text))) {
|
||||
const startIndex = i.index;
|
||||
const length = i[0].length;
|
||||
const command = i[1].split(':');
|
||||
const command = i[1].split(":");
|
||||
|
||||
// append up to here with current style
|
||||
appendPart(startIndex);
|
||||
|
@ -27,10 +27,10 @@ function compileStyledText(text: string): string {
|
|||
// process command
|
||||
consumedUpTo += length;
|
||||
switch (command[0]) {
|
||||
case 'PUSH':
|
||||
styleStack.push('CHALK.' + command[1]);
|
||||
case "PUSH":
|
||||
styleStack.push("CHALK." + command[1]);
|
||||
break;
|
||||
case 'POP':
|
||||
case "POP":
|
||||
styleStack.pop();
|
||||
break;
|
||||
}
|
||||
|
@ -40,21 +40,26 @@ function compileStyledText(text: string): string {
|
|||
}
|
||||
|
||||
export function color(text: string): string {
|
||||
return compileStyledText(text.
|
||||
replace(/\*\*(.*?)\*\*/gm, addStyle('bold', '$1')).
|
||||
replace(/(\[.*?s\])/gm, addStyle('yellow.bold', '$1')).
|
||||
replace(/^# (.*)/gm, addStyle('greenBright', '$1')).
|
||||
replace(/^## (.*)/gm, addStyle('green', '$1')).
|
||||
replace(/^### (.*)/gm, addStyle('cyanBright', '$1')).
|
||||
replace(/(https?:\/\/\S*)/gm, addStyle('blue.bold.underline', '$1')).
|
||||
replace(/__(.*)__/gm, addStyle('italic', '$1')).
|
||||
replace(/^>(.*)/gm, addStyle('cyan', ' $1')).
|
||||
replace(/^!(.*)/gm, addStyle('red.bold', ' $1')).
|
||||
replace(/^(ERROR) (.*?):(.*)/gm, `\n${addStyle('red.bold', '$1')} ${addStyle('green', '$2')}:$3`).
|
||||
replace(/^(WARNING) (.*?):(.*)/gm, `\n${addStyle('yellow.bold', '$1')} ${addStyle('green', '$2')}:$3`).
|
||||
replace(/^(\s* - \w*:\/\/\S*):(\d*):(\d*) (.*)/gm, `${addStyle('cyan', '$1')}:${addStyle('cyan.bold', '$2')}:${addStyle('cyan.bold', '$3')} $4`).
|
||||
replace(/`(.+?)`/gm, addStyle('gray', '$1')).
|
||||
replace(/"(.*?)"/gm, addStyle('gray', '"$1"')).
|
||||
replace(/'(.*?)'/gm, addStyle('gray', '\'$1\'')));
|
||||
return compileStyledText(
|
||||
text
|
||||
.replace(/\*\*(.*?)\*\*/gm, addStyle("bold", "$1"))
|
||||
.replace(/(\[.*?s\])/gm, addStyle("yellow.bold", "$1"))
|
||||
.replace(/^# (.*)/gm, addStyle("greenBright", "$1"))
|
||||
.replace(/^## (.*)/gm, addStyle("green", "$1"))
|
||||
.replace(/^### (.*)/gm, addStyle("cyanBright", "$1"))
|
||||
.replace(/(https?:\/\/\S*)/gm, addStyle("blue.bold.underline", "$1"))
|
||||
.replace(/__(.*)__/gm, addStyle("italic", "$1"))
|
||||
.replace(/^>(.*)/gm, addStyle("cyan", " $1"))
|
||||
.replace(/^!(.*)/gm, addStyle("red.bold", " $1"))
|
||||
.replace(/^(ERROR) (.*?):(.*)/gm, `\n${addStyle("red.bold", "$1")} ${addStyle("green", "$2")}:$3`)
|
||||
.replace(/^(WARNING) (.*?):(.*)/gm, `\n${addStyle("yellow.bold", "$1")} ${addStyle("green", "$2")}:$3`)
|
||||
.replace(
|
||||
/^(\s* - \w*:\/\/\S*):(\d*):(\d*) (.*)/gm,
|
||||
`${addStyle("cyan", "$1")}:${addStyle("cyan.bold", "$2")}:${addStyle("cyan.bold", "$3")} $4`,
|
||||
)
|
||||
.replace(/`(.+?)`/gm, addStyle("gray", "$1"))
|
||||
.replace(/"(.*?)"/gm, addStyle("gray", '"$1"'))
|
||||
.replace(/'(.*?)'/gm, addStyle("gray", "'$1'")),
|
||||
);
|
||||
}
|
||||
(<any>global).color = color;
|
||||
(<any>global).color = color;
|
||||
|
|
|
@ -5,65 +5,67 @@
|
|||
|
||||
// if this is being run directly, call the app entrypoint (we're probably running the local folder)
|
||||
if (require.main === module) {
|
||||
require('../entrypoints/app');
|
||||
require("../entrypoints/app");
|
||||
}
|
||||
|
||||
// load modules from static linker filesystem.
|
||||
if (process.argv.indexOf('--no-static-loader') === -1 && process.env['no-static-loader'] === undefined && require('fs').existsSync('./static-loader.js')) {
|
||||
require('./static-loader.js').load(`${__dirname}/static_modules.fs`);
|
||||
if (
|
||||
process.argv.indexOf("--no-static-loader") === -1 &&
|
||||
process.env["no-static-loader"] === undefined &&
|
||||
require("fs").existsSync("./static-loader.js")
|
||||
) {
|
||||
require("./static-loader.js").load(`${__dirname}/static_modules.fs`);
|
||||
}
|
||||
// everything else.
|
||||
import { tryRequire, resolveEntrypoint, ensureAutorestHome, selectVersion } from './autorest-as-a-service';
|
||||
import { resolve } from 'path';
|
||||
import { tryRequire, resolveEntrypoint, ensureAutorestHome, selectVersion } from "./autorest-as-a-service";
|
||||
import { resolve } from "path";
|
||||
|
||||
import { LanguageClient } from 'vscode-languageclient';
|
||||
import { LanguageClient } from "vscode-languageclient";
|
||||
|
||||
// exports the public AutoRest definitions
|
||||
import { GenerationResults, IFileSystem, AutoRest as IAutoRest } from 'autorest-core';
|
||||
export { Message, Artifact, GenerationResults, IFileSystem } from 'autorest-core';
|
||||
import { GenerationResults, IFileSystem, AutoRest as IAutoRest } from "autorest-core";
|
||||
export { Message, Artifact, GenerationResults, IFileSystem } from "autorest-core";
|
||||
|
||||
/**
|
||||
* The Channel that a message is registered with.
|
||||
*/
|
||||
export enum Channel {
|
||||
/** Information is considered the mildest of responses; not necesarily actionable. */
|
||||
Information = <any>'information',
|
||||
Information = <any>"information",
|
||||
|
||||
/** Warnings are considered important for best practices, but not catastrophic in nature. */
|
||||
Warning = <any>'warning',
|
||||
Warning = <any>"warning",
|
||||
|
||||
/** Errors are considered blocking issues that block a successful operation. */
|
||||
Error = <any>'error',
|
||||
Error = <any>"error",
|
||||
|
||||
/** Debug messages are designed for the developer to communicate internal autorest implementation details. */
|
||||
Debug = <any>'debug',
|
||||
Debug = <any>"debug",
|
||||
|
||||
/** Verbose messages give the user additional clarity on the process. */
|
||||
Verbose = <any>'verbose',
|
||||
Verbose = <any>"verbose",
|
||||
|
||||
/** Catastrophic failure, likely abending the process. */
|
||||
Fatal = <any>'fatal',
|
||||
Fatal = <any>"fatal",
|
||||
|
||||
/** Hint messages offer guidance or support without forcing action. */
|
||||
Hint = <any>'hint',
|
||||
Hint = <any>"hint",
|
||||
|
||||
/** File represents a file output from an extension. Details are a Artifact and are required. */
|
||||
File = <any>'file',
|
||||
File = <any>"file",
|
||||
|
||||
/** content represents an update/creation of a configuration file. The final uri will be in the same folder as the primary config file. */
|
||||
Configuration = <any>'configuration',
|
||||
Configuration = <any>"configuration",
|
||||
|
||||
/** Protect is a path to not remove during a clear-output-folder. */
|
||||
Protect = <any>'protect',
|
||||
|
||||
|
||||
Protect = <any>"protect",
|
||||
}
|
||||
|
||||
export enum DocumentType {
|
||||
OpenAPI2 = <any>'OpenAPI2',
|
||||
OpenAPI3 = <any>'OpenAPI3',
|
||||
LiterateConfiguration = <any>'LiterateConfiguration',
|
||||
Unknown = <any>'Unknown'
|
||||
OpenAPI2 = <any>"OpenAPI2",
|
||||
OpenAPI3 = <any>"OpenAPI3",
|
||||
LiterateConfiguration = <any>"LiterateConfiguration",
|
||||
Unknown = <any>"Unknown",
|
||||
}
|
||||
|
||||
let resolveAutoRest: (value?: IAutoRest | PromiseLike<IAutoRest>) => void;
|
||||
|
@ -91,13 +93,16 @@ let modulePath: string | undefined = undefined;
|
|||
*
|
||||
* @see { @link initialize }
|
||||
*/
|
||||
export async function getLanguageServiceEntrypoint(requestedVersion = 'latest-installed', minimumVersion?: string): Promise<string> {
|
||||
export async function getLanguageServiceEntrypoint(
|
||||
requestedVersion = "latest-installed",
|
||||
minimumVersion?: string,
|
||||
): Promise<string> {
|
||||
if (!modulePath && !busy) {
|
||||
// if we haven't already got autorest-core, let's do that now with the default settings.
|
||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||
await initialize(requestedVersion, minimumVersion);
|
||||
}
|
||||
return resolveEntrypoint(modulePath, 'language-service');
|
||||
return resolveEntrypoint(modulePath, "language-service");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -111,13 +116,16 @@ export async function getLanguageServiceEntrypoint(requestedVersion = 'latest-in
|
|||
*
|
||||
* @see {@link initialize}
|
||||
* */
|
||||
export async function getApplicationEntrypoint(requestedVersion = 'latest-installed', minimumVersion?: string): Promise<string> {
|
||||
export async function getApplicationEntrypoint(
|
||||
requestedVersion = "latest-installed",
|
||||
minimumVersion?: string,
|
||||
): Promise<string> {
|
||||
if (!modulePath && !busy) {
|
||||
// if we haven't already got autorest-core, let's do that now with the default settings.
|
||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||
await initialize(requestedVersion, minimumVersion);
|
||||
}
|
||||
return resolveEntrypoint(modulePath, 'app');
|
||||
return resolveEntrypoint(modulePath, "app");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -135,12 +143,12 @@ export async function getApplicationEntrypoint(requestedVersion = 'latest-instal
|
|||
*
|
||||
* @param minimumVersion - a semver string representing the lowest autorest-core version that is considered acceptable.
|
||||
*/
|
||||
export async function initialize(requestedVersion = 'latest-installed', minimumVersion?: string) {
|
||||
export async function initialize(requestedVersion = "latest-installed", minimumVersion?: string) {
|
||||
if (modulePath) {
|
||||
return;
|
||||
}
|
||||
if (busy) {
|
||||
throw new Error('initialize is already in progress.');
|
||||
throw new Error("initialize is already in progress.");
|
||||
}
|
||||
|
||||
busy = true;
|
||||
|
@ -153,7 +161,7 @@ export async function initialize(requestedVersion = 'latest-installed', minimumV
|
|||
const localVersion = resolve(requestedVersion);
|
||||
|
||||
// try to use a specified folder
|
||||
modulePath = await resolveEntrypoint(localVersion, 'module');
|
||||
modulePath = await resolveEntrypoint(localVersion, "module");
|
||||
|
||||
if (modulePath) {
|
||||
return;
|
||||
|
@ -165,9 +173,11 @@ export async function initialize(requestedVersion = 'latest-installed', minimumV
|
|||
// logic to resolve and optionally install a autorest core package.
|
||||
// will throw if it's not doable.
|
||||
const selectedVersion = await selectVersion(requestedVersion, false, minimumVersion);
|
||||
modulePath = await resolveEntrypoint(await selectedVersion.modulePath, 'module');
|
||||
modulePath = await resolveEntrypoint(await selectedVersion.modulePath, "module");
|
||||
if (!modulePath) {
|
||||
rejectAutoRest(new Error(`Unable to start AutoRest Core from ${requestedVersion}/${await selectedVersion.modulePath}`));
|
||||
rejectAutoRest(
|
||||
new Error(`Unable to start AutoRest Core from ${requestedVersion}/${await selectedVersion.modulePath}`),
|
||||
);
|
||||
throw new Error(`Unable to start AutoRest Core from ${requestedVersion}/${await selectedVersion.modulePath}`);
|
||||
}
|
||||
} finally {
|
||||
|
@ -177,7 +187,6 @@ export async function initialize(requestedVersion = 'latest-installed', minimumV
|
|||
|
||||
/** Bootstraps the core module if it's not already done and returns the AutoRest class. */
|
||||
async function ensureCoreLoaded(): Promise<IAutoRest> {
|
||||
|
||||
if (!modulePath && !busy) {
|
||||
// if we haven't already got autorest-core, let's do that now with the default settings.
|
||||
await initialize();
|
||||
|
@ -185,14 +194,14 @@ async function ensureCoreLoaded(): Promise<IAutoRest> {
|
|||
|
||||
if (modulePath && !coreModule) {
|
||||
// get the library entrypoint
|
||||
coreModule = await tryRequire(modulePath, 'main');
|
||||
coreModule = await tryRequire(modulePath, "main");
|
||||
|
||||
// assign the type to the Async Class Identity
|
||||
resolveAutoRest(coreModule.AutoRest);
|
||||
}
|
||||
|
||||
// wait for class definition
|
||||
return <any>(await AutoRest);
|
||||
return <any>await AutoRest;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -214,24 +223,24 @@ export async function create(fileSystem?: IFileSystem, configFileOrFolderUri?: s
|
|||
|
||||
if (modulePath && !coreModule) {
|
||||
// get the library entrypoint
|
||||
coreModule = await tryRequire(modulePath, 'main');
|
||||
coreModule = await tryRequire(modulePath, "main");
|
||||
|
||||
// assign the type to the Async Class Identity
|
||||
resolveAutoRest(coreModule.AutoRest);
|
||||
}
|
||||
|
||||
// wait for class definition
|
||||
const CAutoRest = <any>(await AutoRest);
|
||||
const CAutoRest = <any>await AutoRest;
|
||||
|
||||
// return new instance of the AutoRest interface.
|
||||
return new CAutoRest(fileSystem, configFileOrFolderUri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a document's content, does this represent a openapi document of some sort?
|
||||
*
|
||||
* @param content - the document content to evaluate
|
||||
*/
|
||||
* Given a document's content, does this represent a openapi document of some sort?
|
||||
*
|
||||
* @param content - the document content to evaluate
|
||||
*/
|
||||
export async function isOpenApiDocument(content: string): Promise<boolean> {
|
||||
await ensureCoreLoaded();
|
||||
return coreModule.IsOpenApiDocument(content);
|
||||
|
@ -273,10 +282,8 @@ export async function toJSON(content: string): Promise<string> {
|
|||
return await coreModule.LiterateToJson(content);
|
||||
}
|
||||
|
||||
|
||||
/** This is a convenience class for accessing the requests supported by AutoRest when used as a language service */
|
||||
export class AutoRestLanguageService {
|
||||
|
||||
/**
|
||||
* Represents a convenience layer on the remote language service functions (on top of LSP-defined functions)
|
||||
*
|
||||
|
@ -285,9 +292,7 @@ export class AutoRestLanguageService {
|
|||
* this requires a reference to the language client so that the methods can await the onReady signal
|
||||
* before attempting to send requests.
|
||||
*/
|
||||
public constructor(private languageClient: LanguageClient) {
|
||||
|
||||
}
|
||||
public constructor(private languageClient: LanguageClient) {}
|
||||
|
||||
/**
|
||||
* Runs autorest to process a file
|
||||
|
@ -305,7 +310,11 @@ export class AutoRestLanguageService {
|
|||
public async generate(documentUri: string, language: string, configuration: any): Promise<GenerationResults> {
|
||||
// don't call before the client is ready.
|
||||
await this.languageClient.onReady();
|
||||
return await this.languageClient.sendRequest<GenerationResults>('generate', { documentUri: documentUri, language: language, configuration: configuration });
|
||||
return await this.languageClient.sendRequest<GenerationResults>("generate", {
|
||||
documentUri: documentUri,
|
||||
language: language,
|
||||
configuration: configuration,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -320,7 +329,7 @@ export class AutoRestLanguageService {
|
|||
// don't call before the client is ready.
|
||||
await this.languageClient.onReady();
|
||||
|
||||
return await this.languageClient.sendRequest<boolean>('isOpenApiDocument', { contentOrUri: contentOrUri });
|
||||
return await this.languageClient.sendRequest<boolean>("isOpenApiDocument", { contentOrUri: contentOrUri });
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -335,54 +344,57 @@ export class AutoRestLanguageService {
|
|||
// don't call before the client is ready.
|
||||
await this.languageClient.onReady();
|
||||
|
||||
return await this.languageClient.sendRequest<boolean>('isConfigurationDocument', { contentOrUri: contentOrUri });
|
||||
return await this.languageClient.sendRequest<boolean>("isConfigurationDocument", { contentOrUri: contentOrUri });
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file as a JSON string. This can be a .YAML, .MD or .JSON file to begin with.
|
||||
*
|
||||
* @param contentOrUri either a URL to a file on disk or http/s, or the content of a file itself.
|
||||
* @returns async: string containing the file as JSON
|
||||
*/
|
||||
* Returns the file as a JSON string. This can be a .YAML, .MD or .JSON file to begin with.
|
||||
*
|
||||
* @param contentOrUri either a URL to a file on disk or http/s, or the content of a file itself.
|
||||
* @returns async: string containing the file as JSON
|
||||
*/
|
||||
public async toJSON(contentOrUri: string): Promise<string> {
|
||||
// don't call before the client is ready.
|
||||
await this.languageClient.onReady();
|
||||
|
||||
return await this.languageClient.sendRequest<string>('toJSON', { contentOrUri: contentOrUri });
|
||||
return await this.languageClient.sendRequest<string>("toJSON", { contentOrUri: contentOrUri });
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the configuration file for a given document URI.
|
||||
*
|
||||
* @param documentUri the URL to a file on disk or http/s. The passed in file can be an OpenAPI file or an AutoRest configuration file.
|
||||
* @returns async: the URI to the configuration file or an empty string if no configuration could be found.
|
||||
*
|
||||
*/
|
||||
* Finds the configuration file for a given document URI.
|
||||
*
|
||||
* @param documentUri the URL to a file on disk or http/s. The passed in file can be an OpenAPI file or an AutoRest configuration file.
|
||||
* @returns async: the URI to the configuration file or an empty string if no configuration could be found.
|
||||
*
|
||||
*/
|
||||
public async detectConfigurationFile(documentUri: string): Promise<string> {
|
||||
// don't call before the client is ready.
|
||||
await this.languageClient.onReady();
|
||||
|
||||
return await this.languageClient.sendRequest<string>('detectConfigurationFile', { documentUri: documentUri });
|
||||
return await this.languageClient.sendRequest<string>("detectConfigurationFile", { documentUri: documentUri });
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a file is an OpenAPI document or a configuration file in one attempt.
|
||||
*
|
||||
* @param contentOrUri either a URL to a file on disk or http/s, or the content of a file itself.
|
||||
* @returns async:
|
||||
* true - the file is a configuration file or OpenAPI (2.0) file
|
||||
* false - the file was not recognized.
|
||||
*/
|
||||
* Determines if a file is an OpenAPI document or a configuration file in one attempt.
|
||||
*
|
||||
* @param contentOrUri either a URL to a file on disk or http/s, or the content of a file itself.
|
||||
* @returns async:
|
||||
* true - the file is a configuration file or OpenAPI (2.0) file
|
||||
* false - the file was not recognized.
|
||||
*/
|
||||
public async isSupportedDocument(languageId: string, contentOrUri: string): Promise<boolean> {
|
||||
// don't call before the client is ready.
|
||||
await this.languageClient.onReady();
|
||||
|
||||
return await this.languageClient.sendRequest<boolean>('isSupportedDocument', { languageId: languageId, contentOrUri: contentOrUri });
|
||||
return await this.languageClient.sendRequest<boolean>("isSupportedDocument", {
|
||||
languageId: languageId,
|
||||
contentOrUri: contentOrUri,
|
||||
});
|
||||
}
|
||||
|
||||
public async identifyDocument(contentOrUri: string): Promise<DocumentType> {
|
||||
// don't call before the client is ready.
|
||||
await this.languageClient.onReady();
|
||||
return await this.languageClient.sendRequest<DocumentType>('identifyDocument', { contentOrUri: contentOrUri });
|
||||
return await this.languageClient.sendRequest<DocumentType>("identifyDocument", { contentOrUri: contentOrUri });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,4 +78,4 @@
|
|||
"chalk": "2.3.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { suite, test, slow, timeout, skip, only } from 'mocha-typescript';
|
||||
import { suite, test, slow, timeout, skip, only } from "mocha-typescript";
|
||||
|
||||
@suite class Hello {
|
||||
@test 'world'() {
|
||||
@suite
|
||||
class Hello {
|
||||
@test world() {
|
||||
// empty test
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,21 +11,9 @@
|
|||
"declaration": true,
|
||||
"stripInternal": true,
|
||||
"target": "es2018",
|
||||
"types": [
|
||||
"node",
|
||||
"mocha"
|
||||
],
|
||||
"typeRoots": [
|
||||
"./node_modules/@types"
|
||||
],
|
||||
"lib": [
|
||||
"es2018"
|
||||
]
|
||||
"types": ["node", "mocha"],
|
||||
"typeRoots": ["./node_modules/@types"],
|
||||
"lib": ["es2018"]
|
||||
},
|
||||
"exclude": [
|
||||
"dist",
|
||||
"node_modules",
|
||||
"_lib",
|
||||
"lib/core/language-service"
|
||||
]
|
||||
}
|
||||
"exclude": ["dist", "node_modules", "_lib", "lib/core/language-service"]
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
# configure plugins first
|
||||
parser: "@typescript-eslint/parser"
|
||||
plugins:
|
||||
- "@typescript-eslint"
|
||||
- "@typescript-eslint"
|
||||
|
||||
# then inherit the common settings
|
||||
extends:
|
||||
- "../.default-eslintrc.yaml"
|
||||
- "../.default-eslintrc.yaml"
|
||||
|
|
327
core/app.ts
327
core/app.ts
|
@ -9,7 +9,7 @@
|
|||
if (!String.prototype.padEnd) {
|
||||
String.prototype.padEnd = function padEnd(targetLength, padString) {
|
||||
targetLength = targetLength >> 0; // floor if number or convert non-number to 0;
|
||||
padString = String(padString || ' ');
|
||||
padString = String(padString || " ");
|
||||
if (this.length > targetLength) {
|
||||
return String(this);
|
||||
} else {
|
||||
|
@ -22,37 +22,53 @@ if (!String.prototype.padEnd) {
|
|||
};
|
||||
}
|
||||
|
||||
require('events').EventEmitter.defaultMaxListeners = 100;
|
||||
process.env['ELECTRON_RUN_AS_NODE'] = '1';
|
||||
delete process.env['ELECTRON_NO_ATTACH_CONSOLE'];
|
||||
(<any>global).autorestVersion = require('../package.json').version;
|
||||
require("events").EventEmitter.defaultMaxListeners = 100;
|
||||
process.env["ELECTRON_RUN_AS_NODE"] = "1";
|
||||
delete process.env["ELECTRON_NO_ATTACH_CONSOLE"];
|
||||
(<any>global).autorestVersion = require("../package.json").version;
|
||||
|
||||
const color: (text: string) => string = (<any>global).color ? (<any>global).color : p => p;
|
||||
const color: (text: string) => string = (<any>global).color ? (<any>global).color : (p) => p;
|
||||
|
||||
// start of autorest-ng
|
||||
// the console app starts for real here.
|
||||
|
||||
import { CreateObject, DataStore, EnhancedFileSystem, nodes, Parse, RealFileSystem, Stringify } from '@azure-tools/datastore';
|
||||
import { ClearFolder, CreateFolderUri, MakeRelativeUri, ReadUri, ResolveUri, WriteBinary, WriteString } from '@azure-tools/uri';
|
||||
import { ChildProcess } from 'child_process';
|
||||
import { join, resolve as currentDirectory } from 'path';
|
||||
import { Help } from './help';
|
||||
import { CreateConfiguration, isLegacy } from './legacyCli';
|
||||
import { Artifact } from './lib/artifact';
|
||||
import { AutoRest, ConfigurationView, IsOpenApiDocument, Shutdown } from './lib/autorest-core';
|
||||
import { AutoRestConfigurationImpl, MergeConfigurations } from './lib/configuration';
|
||||
import { Exception, OperationCanceledException } from './lib/exception';
|
||||
import { Channel, Message } from './lib/message';
|
||||
import { ShallowCopy } from './lib/source-map/merging';
|
||||
import { homedir } from 'os';
|
||||
import {
|
||||
CreateObject,
|
||||
DataStore,
|
||||
EnhancedFileSystem,
|
||||
nodes,
|
||||
Parse,
|
||||
RealFileSystem,
|
||||
Stringify,
|
||||
} from "@azure-tools/datastore";
|
||||
import {
|
||||
ClearFolder,
|
||||
CreateFolderUri,
|
||||
MakeRelativeUri,
|
||||
ReadUri,
|
||||
ResolveUri,
|
||||
WriteBinary,
|
||||
WriteString,
|
||||
} from "@azure-tools/uri";
|
||||
import { ChildProcess } from "child_process";
|
||||
import { join, resolve as currentDirectory } from "path";
|
||||
import { Help } from "./help";
|
||||
import { CreateConfiguration, isLegacy } from "./legacyCli";
|
||||
import { Artifact } from "./lib/artifact";
|
||||
import { AutoRest, ConfigurationView, IsOpenApiDocument, Shutdown } from "./lib/autorest-core";
|
||||
import { AutoRestConfigurationImpl, MergeConfigurations } from "./lib/configuration";
|
||||
import { Exception, OperationCanceledException } from "./lib/exception";
|
||||
import { Channel, Message } from "./lib/message";
|
||||
import { ShallowCopy } from "./lib/source-map/merging";
|
||||
import { homedir } from "os";
|
||||
|
||||
let verbose = false;
|
||||
let debug = false;
|
||||
|
||||
function awaitable(child: ChildProcess): Promise<number> {
|
||||
return new Promise<number>((resolve, reject) => {
|
||||
child.addListener('error', reject);
|
||||
child.addListener('exit', resolve);
|
||||
child.addListener("error", reject);
|
||||
child.addListener("exit", resolve);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -62,78 +78,100 @@ async function legacyMain(autorestArgs: Array<string>): Promise<number> {
|
|||
const dataStore = new DataStore();
|
||||
let config: AutoRestConfigurationImpl = {};
|
||||
try {
|
||||
config = await CreateConfiguration(currentDirUri, dataStore.GetReadThroughScope(new RealFileSystem()), autorestArgs);
|
||||
config = await CreateConfiguration(
|
||||
currentDirUri,
|
||||
dataStore.GetReadThroughScope(new RealFileSystem()),
|
||||
autorestArgs,
|
||||
);
|
||||
} catch (e) {
|
||||
console.error(color('!Error: You have provided legacy command line arguments (single-dash syntax) that seem broken.'));
|
||||
console.error('');
|
||||
console.error(color(
|
||||
'> While AutoRest keeps on supporting the old CLI by converting it over to the new one internally, \n' +
|
||||
'> it does not have crazy logic determining *what* is wrong with arguments, should conversion fail. \n' +
|
||||
'> Please try fixing your arguments or consider moving to the new CLI. \n' +
|
||||
'> isit https://github.com/Azure/autorest/blob/master/docs/user/cli.md for information about the new CLI.'));
|
||||
console.error('');
|
||||
console.error(color('!Internal error: ' + e));
|
||||
console.error(
|
||||
color("!Error: You have provided legacy command line arguments (single-dash syntax) that seem broken."),
|
||||
);
|
||||
console.error("");
|
||||
console.error(
|
||||
color(
|
||||
"> While AutoRest keeps on supporting the old CLI by converting it over to the new one internally, \n" +
|
||||
"> it does not have crazy logic determining *what* is wrong with arguments, should conversion fail. \n" +
|
||||
"> Please try fixing your arguments or consider moving to the new CLI. \n" +
|
||||
"> isit https://github.com/Azure/autorest/blob/master/docs/user/cli.md for information about the new CLI.",
|
||||
),
|
||||
);
|
||||
console.error("");
|
||||
console.error(color("!Internal error: " + e));
|
||||
await showHelp();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// autorest init
|
||||
if (autorestArgs[0] === 'init') {
|
||||
const clientNameGuess = (config['override-info'] || {}).title || Parse<any>(await ReadUri((<any>config['input-file'])[0])).info.title;
|
||||
await autorestInit(clientNameGuess, Array.isArray(config['input-file']) ? <any>config['input-file'] : []);
|
||||
if (autorestArgs[0] === "init") {
|
||||
const clientNameGuess =
|
||||
(config["override-info"] || {}).title || Parse<any>(await ReadUri((<any>config["input-file"])[0])).info.title;
|
||||
await autorestInit(clientNameGuess, Array.isArray(config["input-file"]) ? <any>config["input-file"] : []);
|
||||
return 0;
|
||||
}
|
||||
// autorest init-min
|
||||
if (autorestArgs[0] === 'init-min') {
|
||||
console.log(`# AutoRest Configuration (auto-generated, please adjust title)
|
||||
if (autorestArgs[0] === "init-min") {
|
||||
console.log(
|
||||
`# AutoRest Configuration (auto-generated, please adjust title)
|
||||
|
||||
> see https://aka.ms/autorest
|
||||
|
||||
The following configuration was auto-generated and can be adjusted.
|
||||
|
||||
~~~ yaml
|
||||
${Stringify(config).replace(/^---\n/, '')}
|
||||
${Stringify(config).replace(/^---\n/, "")}
|
||||
~~~
|
||||
|
||||
`.replace(/~/g, '`'));
|
||||
`.replace(/~/g, "`"),
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
// autorest init-cli
|
||||
if (autorestArgs[0] === 'init-cli') {
|
||||
if (autorestArgs[0] === "init-cli") {
|
||||
const args: Array<string> = [];
|
||||
for (const node of nodes(config, '$..*')) {
|
||||
const path = node.path.join('.');
|
||||
const values = node.value instanceof Array ? node.value : (typeof node.value === 'object' ? [] : [node.value]);
|
||||
for (const node of nodes(config, "$..*")) {
|
||||
const path = node.path.join(".");
|
||||
const values = node.value instanceof Array ? node.value : typeof node.value === "object" ? [] : [node.value];
|
||||
for (const value of values) {
|
||||
args.push(`--${path}=${value}`);
|
||||
}
|
||||
}
|
||||
console.log(args.join(' '));
|
||||
console.log(args.join(" "));
|
||||
return 0;
|
||||
}
|
||||
|
||||
config['base-folder'] = currentDirUri;
|
||||
config["base-folder"] = currentDirUri;
|
||||
const api = new AutoRest(new RealFileSystem());
|
||||
api.AddConfiguration(config);
|
||||
const view = await api.view;
|
||||
let outstanding: Promise<void> = Promise.resolve();
|
||||
api.GeneratedFile.Subscribe((_: AutoRest, file: Artifact) => outstanding = outstanding.then(() => file.type === 'binary-file' ? WriteBinary(file.uri, file.content) : WriteString(file.uri, file.content)));
|
||||
api.ClearFolder.Subscribe((_: AutoRest, folder: string) => outstanding = outstanding.then(async () => {
|
||||
try { await ClearFolder(folder); } catch {
|
||||
// no worries
|
||||
}
|
||||
}));
|
||||
subscribeMessages(api, () => { });
|
||||
api.GeneratedFile.Subscribe(
|
||||
(_: AutoRest, file: Artifact) =>
|
||||
(outstanding = outstanding.then(() =>
|
||||
file.type === "binary-file" ? WriteBinary(file.uri, file.content) : WriteString(file.uri, file.content),
|
||||
)),
|
||||
);
|
||||
api.ClearFolder.Subscribe(
|
||||
(_: AutoRest, folder: string) =>
|
||||
(outstanding = outstanding.then(async () => {
|
||||
try {
|
||||
await ClearFolder(folder);
|
||||
} catch {
|
||||
// no worries
|
||||
}
|
||||
})),
|
||||
);
|
||||
subscribeMessages(api, () => {});
|
||||
|
||||
// warn about `--` arguments
|
||||
for (const arg of autorestArgs) {
|
||||
if (arg.startsWith('--')) {
|
||||
if (arg.startsWith("--")) {
|
||||
view.Message({
|
||||
Channel: Channel.Warning,
|
||||
Text:
|
||||
`The parameter ${arg} looks like it was meant for the new CLI! ` +
|
||||
'Note that you have invoked the legacy CLI (by using at least one single-dash argument). ' +
|
||||
'Please visit https://github.com/Azure/autorest/blob/master/docs/user/cli.md for information about the new CLI.'
|
||||
"Note that you have invoked the legacy CLI (by using at least one single-dash argument). " +
|
||||
"Please visit https://github.com/Azure/autorest/blob/master/docs/user/cli.md for information about the new CLI.",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -151,12 +189,16 @@ ${Stringify(config).replace(/^---\n/, '')}
|
|||
* Current AutoRest
|
||||
*/
|
||||
|
||||
interface CommandLineArgs { configFileOrFolder?: string; switches: Array<any>; rawSwitches: any }
|
||||
interface CommandLineArgs {
|
||||
configFileOrFolder?: string;
|
||||
switches: Array<any>;
|
||||
rawSwitches: any;
|
||||
}
|
||||
|
||||
function parseArgs(autorestArgs: Array<string>): CommandLineArgs {
|
||||
const result: CommandLineArgs = {
|
||||
switches: [],
|
||||
rawSwitches: {}
|
||||
rawSwitches: {},
|
||||
};
|
||||
|
||||
for (const arg of autorestArgs) {
|
||||
|
@ -173,26 +215,26 @@ function parseArgs(autorestArgs: Array<string>): CommandLineArgs {
|
|||
|
||||
// switch
|
||||
const key = match[1];
|
||||
let rawValue = match[3] || '{}';
|
||||
let rawValue = match[3] || "{}";
|
||||
|
||||
if (rawValue.startsWith('.')) {
|
||||
if (rawValue.startsWith(".")) {
|
||||
// starts with a . or .. -> this is a relative path to current directory
|
||||
rawValue = join(process.cwd(), rawValue);
|
||||
}
|
||||
|
||||
if (rawValue.startsWith('~/')) {
|
||||
if (rawValue.startsWith("~/")) {
|
||||
// starts with a ~/ this is a relative path to home directory
|
||||
rawValue = join(homedir(), rawValue.substr(1));
|
||||
}
|
||||
|
||||
// quote stuff beginning with '@', YAML doesn't think unquoted strings should start with that
|
||||
rawValue = rawValue.startsWith('@') ? `'${rawValue}'` : rawValue;
|
||||
rawValue = rawValue.startsWith("@") ? `'${rawValue}'` : rawValue;
|
||||
rawValue = rawValue.match(/20\d\d-\d+-\d+/) ? `'${rawValue}'` : rawValue;
|
||||
// quote numbers with decimal point, we don't have any use for non-integer numbers (while on the other hand version strings may look like decimal numbers)
|
||||
rawValue = !isNaN(parseFloat(rawValue)) && rawValue.includes('.') ? `'${rawValue}'` : rawValue;
|
||||
rawValue = !isNaN(parseFloat(rawValue)) && rawValue.includes(".") ? `'${rawValue}'` : rawValue;
|
||||
const value = Parse(rawValue);
|
||||
result.rawSwitches[key] = value;
|
||||
result.switches.push(CreateObject(key.split('.'), value));
|
||||
result.switches.push(CreateObject(key.split("."), value));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -230,7 +272,7 @@ function subscribeMessages(api: AutoRest, errorCounter: () => void) {
|
|||
});
|
||||
}
|
||||
|
||||
async function autorestInit(title = 'API-NAME', inputs: Array<string> = ['LIST INPUT FILES HERE']) {
|
||||
async function autorestInit(title = "API-NAME", inputs: Array<string> = ["LIST INPUT FILES HERE"]) {
|
||||
const cwdUri = CreateFolderUri(currentDirectory());
|
||||
for (let i = 0; i < inputs.length; ++i) {
|
||||
try {
|
||||
|
@ -239,7 +281,8 @@ async function autorestInit(title = 'API-NAME', inputs: Array<string> = ['LIST I
|
|||
// no worries
|
||||
}
|
||||
}
|
||||
console.log(`# ${title}
|
||||
console.log(
|
||||
`# ${title}
|
||||
> see https://aka.ms/autorest
|
||||
|
||||
This is the AutoRest configuration file for the ${title}.
|
||||
|
@ -266,7 +309,7 @@ These are the global settings for the API.
|
|||
~~~ yaml
|
||||
# list all the input OpenAPI files (may be YAML, JSON, or Literate- OpenAPI markdown)
|
||||
input-file:
|
||||
${inputs.map(x => ' - ' + x).join('\n')}
|
||||
${inputs.map((x) => " - " + x).join("\n")}
|
||||
~~~
|
||||
|
||||
---
|
||||
|
@ -279,7 +322,8 @@ csharp:
|
|||
# override the default output folder
|
||||
output-folder: generated/csharp
|
||||
~~~
|
||||
`.replace(/~/g, '`'));
|
||||
`.replace(/~/g, "`"),
|
||||
);
|
||||
}
|
||||
|
||||
let exitcode = 0;
|
||||
|
@ -288,10 +332,15 @@ let args: CommandLineArgs;
|
|||
let cleared = false;
|
||||
async function doClearFolders(protectFiles: Set<string>, clearFolders: Set<string>) {
|
||||
if (!cleared) {
|
||||
timestampDebugLog('Clearing Folders.');
|
||||
timestampDebugLog("Clearing Folders.");
|
||||
cleared = true;
|
||||
for (const folder of clearFolders) {
|
||||
try { await ClearFolder(folder, [...protectFiles].map(each => ResolveUri(folder, each))); } catch {
|
||||
try {
|
||||
await ClearFolder(
|
||||
folder,
|
||||
[...protectFiles].map((each) => ResolveUri(folder, each)),
|
||||
);
|
||||
} catch {
|
||||
// no worries
|
||||
}
|
||||
}
|
||||
|
@ -299,7 +348,7 @@ async function doClearFolders(protectFiles: Set<string>, clearFolders: Set<strin
|
|||
}
|
||||
|
||||
async function currentMain(autorestArgs: Array<string>): Promise<number> {
|
||||
if (autorestArgs[0] === 'init') {
|
||||
if (autorestArgs[0] === "init") {
|
||||
await autorestInit();
|
||||
return 0;
|
||||
}
|
||||
|
@ -317,22 +366,27 @@ async function currentMain(autorestArgs: Array<string>): Promise<number> {
|
|||
// parse the args from the command line
|
||||
args = parseArgs([...autorestArgs, ...more]);
|
||||
|
||||
if ((!args.rawSwitches['message-format']) || args.rawSwitches['message-format'] === 'regular') {
|
||||
if (!args.rawSwitches["message-format"] || args.rawSwitches["message-format"] === "regular") {
|
||||
console.log(color(`> Loading AutoRest core '${__dirname}' (${(<any>global).autorestVersion})`));
|
||||
}
|
||||
verbose = verbose || args.rawSwitches['verbose'];
|
||||
debug = debug || args.rawSwitches['debug'];
|
||||
verbose = verbose || args.rawSwitches["verbose"];
|
||||
debug = debug || args.rawSwitches["debug"];
|
||||
|
||||
// identify where we are starting from.
|
||||
const currentDirUri = CreateFolderUri(currentDirectory());
|
||||
|
||||
if (args.rawSwitches['help']) {
|
||||
// if they are asking for help, feed a false file to config so we don't load a user's configuration
|
||||
args.configFileOrFolder = 'invalid.filename.md';
|
||||
if (args.rawSwitches["help"]) {
|
||||
// if they are asking for help, feed a false file to config so we don't load a user's configuration
|
||||
args.configFileOrFolder = "invalid.filename.md";
|
||||
}
|
||||
|
||||
// get an instance of AutoRest and add the command line switches to the configuration.
|
||||
const api = new AutoRest(new EnhancedFileSystem((<any>MergeConfigurations(...args.switches))['github-auth-token'] || process.env.GITHUB_AUTH_TOKEN), ResolveUri(currentDirUri, args.configFileOrFolder || '.'));
|
||||
const api = new AutoRest(
|
||||
new EnhancedFileSystem(
|
||||
(<any>MergeConfigurations(...args.switches))["github-auth-token"] || process.env.GITHUB_AUTH_TOKEN,
|
||||
),
|
||||
ResolveUri(currentDirUri, args.configFileOrFolder || "."),
|
||||
);
|
||||
api.AddConfiguration(args.switches);
|
||||
|
||||
// listen for output messages and file writes
|
||||
|
@ -343,7 +397,7 @@ async function currentMain(autorestArgs: Array<string>): Promise<number> {
|
|||
let fastMode = false;
|
||||
const tasks = new Array<Promise<void>>();
|
||||
|
||||
const config = (await api.view);
|
||||
const config = await api.view;
|
||||
|
||||
api.GeneratedFile.Subscribe((_, artifact) => {
|
||||
if (config.HelpRequested) {
|
||||
|
@ -352,7 +406,11 @@ async function currentMain(autorestArgs: Array<string>): Promise<number> {
|
|||
}
|
||||
|
||||
protectFiles.add(artifact.uri);
|
||||
tasks.push((artifact.type === 'binary-file' ? WriteBinary(artifact.uri, artifact.content) : WriteString(artifact.uri, artifact.content)));
|
||||
tasks.push(
|
||||
artifact.type === "binary-file"
|
||||
? WriteBinary(artifact.uri, artifact.content)
|
||||
: WriteString(artifact.uri, artifact.content),
|
||||
);
|
||||
});
|
||||
api.Message.Subscribe((_, message) => {
|
||||
if (message.Channel === Channel.Protect && message.Details) {
|
||||
|
@ -362,12 +420,12 @@ async function currentMain(autorestArgs: Array<string>): Promise<number> {
|
|||
api.ClearFolder.Subscribe((_, folder) => clearFolders.add(folder));
|
||||
|
||||
// maybe a resource schema batch process
|
||||
if (config['resource-schema-batch']) {
|
||||
if (config["resource-schema-batch"]) {
|
||||
return resourceSchemaBatch(api);
|
||||
}
|
||||
fastMode = !!config['fast-mode'];
|
||||
fastMode = !!config["fast-mode"];
|
||||
|
||||
if (config['batch']) {
|
||||
if (config["batch"]) {
|
||||
await batch(api);
|
||||
} else {
|
||||
const result = await api.Process().finish;
|
||||
|
@ -379,29 +437,33 @@ async function currentMain(autorestArgs: Array<string>): Promise<number> {
|
|||
if (config.HelpRequested) {
|
||||
// no fs operations on --help! Instead, format and print artifacts to console.
|
||||
// - print boilerplate help
|
||||
console.log('');
|
||||
console.log('');
|
||||
console.log(color('**Usage**: autorest `[configuration-file.md] [...options]`'));
|
||||
console.log('');
|
||||
console.log(color(' See: https://aka.ms/autorest/cli for additional documentation'));
|
||||
console.log("");
|
||||
console.log("");
|
||||
console.log(color("**Usage**: autorest `[configuration-file.md] [...options]`"));
|
||||
console.log("");
|
||||
console.log(color(" See: https://aka.ms/autorest/cli for additional documentation"));
|
||||
// - sort artifacts by name (then content, just for stability)
|
||||
const helpArtifacts = artifacts.sort((a, b) => a.uri === b.uri ? (a.content > b.content ? 1 : -1) : (a.uri > b.uri ? 1 : -1));
|
||||
const helpArtifacts = artifacts.sort((a, b) =>
|
||||
a.uri === b.uri ? (a.content > b.content ? 1 : -1) : a.uri > b.uri ? 1 : -1,
|
||||
);
|
||||
// - format and print
|
||||
for (const helpArtifact of helpArtifacts) {
|
||||
const help: Help = Parse(helpArtifact.content, (message, index) => console.error(color(`!Parsing error at **${helpArtifact.uri}**:__${index}: ${message}__`)));
|
||||
const help: Help = Parse(helpArtifact.content, (message, index) =>
|
||||
console.error(color(`!Parsing error at **${helpArtifact.uri}**:__${index}: ${message}__`)),
|
||||
);
|
||||
if (!help) {
|
||||
continue;
|
||||
}
|
||||
const activatedBySuffix = help.activationScope ? ` (activated by --${help.activationScope})` : '';
|
||||
console.log('');
|
||||
const activatedBySuffix = help.activationScope ? ` (activated by --${help.activationScope})` : "";
|
||||
console.log("");
|
||||
console.log(color(`### ${help.categoryFriendlyName}${activatedBySuffix}`));
|
||||
if (help.description) {
|
||||
console.log(color(help.description));
|
||||
}
|
||||
console.log('');
|
||||
console.log("");
|
||||
for (const settingHelp of help.settings) {
|
||||
const keyPart = `--${settingHelp.key}`;
|
||||
const typePart = settingHelp.type ? `=<${settingHelp.type}>` : ' ';// `[=<boolean>]`;
|
||||
const typePart = settingHelp.type ? `=<${settingHelp.type}>` : " "; // `[=<boolean>]`;
|
||||
const settingPart = `${keyPart}\`${typePart}\``;
|
||||
// if (!settingHelp.required) {
|
||||
// settingPart = `[${settingPart}]`;
|
||||
|
@ -413,14 +475,16 @@ async function currentMain(autorestArgs: Array<string>): Promise<number> {
|
|||
// perform file system operations.
|
||||
await doClearFolders(protectFiles, clearFolders);
|
||||
|
||||
timestampDebugLog('Writing Outputs.');
|
||||
timestampDebugLog("Writing Outputs.");
|
||||
await Promise.all(tasks);
|
||||
|
||||
for (const artifact of artifacts) {
|
||||
await (artifact.type === 'binary-file' ? WriteBinary(artifact.uri, artifact.content) : WriteString(artifact.uri, artifact.content));
|
||||
await (artifact.type === "binary-file"
|
||||
? WriteBinary(artifact.uri, artifact.content)
|
||||
: WriteString(artifact.uri, artifact.content));
|
||||
}
|
||||
}
|
||||
timestampLog('Generation Complete');
|
||||
timestampLog("Generation Complete");
|
||||
// return the exit code to the caller.
|
||||
return exitcode;
|
||||
}
|
||||
|
@ -451,7 +515,9 @@ function getRds(schema: any, path: string): Array<string> {
|
|||
const result = new Array<any>();
|
||||
if (schema.resourceDefinitions) {
|
||||
for (const name of Object.getOwnPropertyNames(schema.resourceDefinitions)) {
|
||||
result.push(`{ "$ref": "https://schema.management.azure.com/schemas/${apiversion}/${namespace}.json#/resourceDefinitions/${name}" }, `);
|
||||
result.push(
|
||||
`{ "$ref": "https://schema.management.azure.com/schemas/${apiversion}/${namespace}.json#/resourceDefinitions/${name}" }, `,
|
||||
);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -466,11 +532,12 @@ async function resourceSchemaBatch(api: AutoRest): Promise<number> {
|
|||
|
||||
// ask for the view without
|
||||
const config = await api.RegenerateView();
|
||||
for (const batchConfig of config.GetNestedConfiguration('resource-schema-batch')) { // really, there should be only one
|
||||
for (const eachFile of batchConfig['input-file']) {
|
||||
for (const batchConfig of config.GetNestedConfiguration("resource-schema-batch")) {
|
||||
// really, there should be only one
|
||||
for (const eachFile of batchConfig["input-file"]) {
|
||||
const path = ResolveUri(config.configFileFolderUri, eachFile);
|
||||
const content = await ReadUri(path);
|
||||
if (!await IsOpenApiDocument(content)) {
|
||||
if (!(await IsOpenApiDocument(content))) {
|
||||
exitcode++;
|
||||
console.error(color(`!File ${path} is not a OpenAPI file.`));
|
||||
continue;
|
||||
|
@ -479,11 +546,13 @@ async function resourceSchemaBatch(api: AutoRest): Promise<number> {
|
|||
// Create the autorest instance for that item
|
||||
const instance = new AutoRest(new RealFileSystem(), config.configFileFolderUri);
|
||||
instance.GeneratedFile.Subscribe((_, file) => {
|
||||
if (file.uri.endsWith('.json')) {
|
||||
if (file.uri.endsWith(".json")) {
|
||||
const more = JSON.parse(file.content);
|
||||
if (!outputs.has(file.uri)) {
|
||||
outputs.set(file.uri, file.content);
|
||||
outstanding = outstanding.then(() => file.type === 'binary-file' ? WriteBinary(file.uri, file.content) : WriteString(file.uri, file.content));
|
||||
outstanding = outstanding.then(() =>
|
||||
file.type === "binary-file" ? WriteBinary(file.uri, file.content) : WriteString(file.uri, file.content),
|
||||
);
|
||||
schemas.push(...getRds(more, file.uri));
|
||||
return;
|
||||
} else {
|
||||
|
@ -494,15 +563,17 @@ async function resourceSchemaBatch(api: AutoRest): Promise<number> {
|
|||
existing.definitions = shallowMerge(existing.definitions, more.definitions);
|
||||
const content = JSON.stringify(existing, null, 2);
|
||||
outputs.set(file.uri, content);
|
||||
outstanding = outstanding.then(() => file.type === 'binary-file' ? WriteBinary(file.uri, file.content) : WriteString(file.uri, content));
|
||||
outstanding = outstanding.then(() =>
|
||||
file.type === "binary-file" ? WriteBinary(file.uri, file.content) : WriteString(file.uri, content),
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
subscribeMessages(instance, () => exitcode++);
|
||||
|
||||
// set configuration for that item
|
||||
instance.AddConfiguration(ShallowCopy(batchConfig, 'input-file'));
|
||||
instance.AddConfiguration({ 'input-file': eachFile });
|
||||
instance.AddConfiguration(ShallowCopy(batchConfig, "input-file"));
|
||||
instance.AddConfiguration({ "input-file": eachFile });
|
||||
|
||||
console.log(`Running autorest for *${path}* `);
|
||||
|
||||
|
@ -525,25 +596,35 @@ async function batch(api: AutoRest): Promise<void> {
|
|||
const config = await api.view;
|
||||
const batchTaskConfigReference: any = {};
|
||||
api.AddConfiguration(batchTaskConfigReference);
|
||||
for (const batchTaskConfig of config.GetEntry(<any>'batch')) {
|
||||
const isjson = (args.rawSwitches['message-format'] === 'json' || args.rawSwitches['message-format'] === 'yaml');
|
||||
for (const batchTaskConfig of config.GetEntry(<any>"batch")) {
|
||||
const isjson = args.rawSwitches["message-format"] === "json" || args.rawSwitches["message-format"] === "yaml";
|
||||
if (!isjson) {
|
||||
outputMessage(api, {
|
||||
Channel: Channel.Information,
|
||||
Text: `Processing batch task - ${JSON.stringify(batchTaskConfig)} .`
|
||||
}, () => { });
|
||||
outputMessage(
|
||||
api,
|
||||
{
|
||||
Channel: Channel.Information,
|
||||
Text: `Processing batch task - ${JSON.stringify(batchTaskConfig)} .`,
|
||||
},
|
||||
() => {},
|
||||
);
|
||||
}
|
||||
// update batch task config section
|
||||
for (const key of Object.keys(batchTaskConfigReference)) { delete batchTaskConfigReference[key]; }
|
||||
for (const key of Object.keys(batchTaskConfigReference)) {
|
||||
delete batchTaskConfigReference[key];
|
||||
}
|
||||
Object.assign(batchTaskConfigReference, batchTaskConfig);
|
||||
api.Invalidate();
|
||||
|
||||
const result = await api.Process().finish;
|
||||
if (result !== true) {
|
||||
outputMessage(api, {
|
||||
Channel: Channel.Error,
|
||||
Text: `Failure during batch task - ${JSON.stringify(batchTaskConfig)} -- ${result}.`
|
||||
}, () => { });
|
||||
outputMessage(
|
||||
api,
|
||||
{
|
||||
Channel: Channel.Error,
|
||||
Text: `Failure during batch task - ${JSON.stringify(batchTaskConfig)} -- ${result}.`,
|
||||
},
|
||||
() => {},
|
||||
);
|
||||
throw result;
|
||||
}
|
||||
}
|
||||
|
@ -577,7 +658,6 @@ async function mainImpl(): Promise<number> {
|
|||
return 1;
|
||||
}
|
||||
|
||||
|
||||
function timestampLog(content: string) {
|
||||
console.log(color(`[${Math.floor(process.uptime() * 100) / 100} s] ${content}`));
|
||||
}
|
||||
|
@ -587,7 +667,6 @@ function timestampDebugLog(content: string) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
async function main() {
|
||||
let exitcode = 0;
|
||||
try {
|
||||
|
@ -596,12 +675,12 @@ async function main() {
|
|||
exitcode = 102;
|
||||
} finally {
|
||||
try {
|
||||
timestampDebugLog('Shutting Down.');
|
||||
timestampDebugLog("Shutting Down.");
|
||||
await Shutdown();
|
||||
} catch {
|
||||
timestampDebugLog('Shutting Down: (trouble?)');
|
||||
} catch {
|
||||
timestampDebugLog("Shutting Down: (trouble?)");
|
||||
} finally {
|
||||
timestampDebugLog('Exiting.');
|
||||
timestampDebugLog("Exiting.");
|
||||
process.exit(exitcode);
|
||||
}
|
||||
}
|
||||
|
@ -609,12 +688,10 @@ async function main() {
|
|||
|
||||
main();
|
||||
|
||||
|
||||
process.on('exit', () => {
|
||||
process.on("exit", () => {
|
||||
Shutdown();
|
||||
});
|
||||
|
||||
|
||||
async function showHelp(): Promise<void> {
|
||||
await currentMain(['--help']);
|
||||
await currentMain(["--help"]);
|
||||
}
|
||||
|
|
|
@ -5,16 +5,29 @@
|
|||
|
||||
// load modules from static linker filesystem.
|
||||
try {
|
||||
if (process.argv.indexOf('--no-static-loader') === -1 && process.env['no-static-loader'] === undefined && require('fs').existsSync('./static-loader.js')) {
|
||||
require('./static-loader.js').load(`${__dirname}/static_modules.fs`);
|
||||
if (
|
||||
process.argv.indexOf("--no-static-loader") === -1 &&
|
||||
process.env["no-static-loader"] === undefined &&
|
||||
require("fs").existsSync("./static-loader.js")
|
||||
) {
|
||||
require("./static-loader.js").load(`${__dirname}/static_modules.fs`);
|
||||
}
|
||||
} catch {
|
||||
} catch {
|
||||
// no worries.
|
||||
}
|
||||
|
||||
export { IFileSystem } from '@azure-tools/datastore';
|
||||
export { Message, Channel } from './lib/message';
|
||||
export { Artifact } from './lib/artifact';
|
||||
export { AutoRest, ConfigurationView, IdentifyDocument, IsConfigurationExtension, IsConfigurationDocument, IsOpenApiExtension, LiterateToJson, IsOpenApiDocument } from './lib/autorest-core';
|
||||
export { DocumentFormat, DocumentExtension, DocumentPatterns, DocumentType } from './lib/document-type';
|
||||
export { GenerationResults } from './language-service/language-service';
|
||||
export { IFileSystem } from "@azure-tools/datastore";
|
||||
export { Message, Channel } from "./lib/message";
|
||||
export { Artifact } from "./lib/artifact";
|
||||
export {
|
||||
AutoRest,
|
||||
ConfigurationView,
|
||||
IdentifyDocument,
|
||||
IsConfigurationExtension,
|
||||
IsConfigurationDocument,
|
||||
IsOpenApiExtension,
|
||||
LiterateToJson,
|
||||
IsOpenApiDocument,
|
||||
} from "./lib/autorest-core";
|
||||
export { DocumentFormat, DocumentExtension, DocumentPatterns, DocumentType } from "./lib/document-type";
|
||||
export { GenerationResults } from "./language-service/language-service";
|
||||
|
|
14
core/help.ts
14
core/help.ts
|
@ -1,13 +1,13 @@
|
|||
export interface Help {
|
||||
categoryFriendlyName: string; // e.g. "Output Verbosity", "C# generator"
|
||||
activationScope?: string; // e.g. "csharp"
|
||||
description?: string; // inline markdown allowed
|
||||
categoryFriendlyName: string; // e.g. "Output Verbosity", "C# generator"
|
||||
activationScope?: string; // e.g. "csharp"
|
||||
description?: string; // inline markdown allowed
|
||||
settings: Array<SettingHelp>;
|
||||
}
|
||||
|
||||
export interface SettingHelp {
|
||||
required?: boolean; // defaults to "false"
|
||||
key: string; // e.g. "namespace"
|
||||
type?: string; // not specified => flag; otherwise, please use TypeScript syntax
|
||||
description: string; // inline markdown allowed
|
||||
required?: boolean; // defaults to "false"
|
||||
key: string; // e.g. "namespace"
|
||||
type?: string; // not specified => flag; otherwise, please use TypeScript syntax
|
||||
description: string; // inline markdown allowed
|
||||
}
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
|
||||
import { parseJsonPointer } from '@azure-tools/datastore';
|
||||
import { nodes, parse, paths, stringify, value, } from 'jsonpath';
|
||||
import { Location, Position } from 'vscode-languageserver';
|
||||
import { JsonPath, SourceMap } from './source-map';
|
||||
import { parseJsonPointer } from "@azure-tools/datastore";
|
||||
import { nodes, parse, paths, stringify, value } from "jsonpath";
|
||||
import { Location, Position } from "vscode-languageserver";
|
||||
import { JsonPath, SourceMap } from "./source-map";
|
||||
|
||||
/**
|
||||
* @internal
|
||||
|
@ -23,7 +23,8 @@ export class DocumentAnalysis {
|
|||
private documentUri: string,
|
||||
private document: string,
|
||||
private fullyResolvedAndMergedDefinition: any,
|
||||
private fullyResolvedAndMergedDefinitionMap: SourceMap) { }
|
||||
private fullyResolvedAndMergedDefinitionMap: SourceMap,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Determines the JSON query found at a given position.
|
||||
|
@ -32,7 +33,7 @@ export class DocumentAnalysis {
|
|||
* @param position The position to look at for a JSON query.
|
||||
*/
|
||||
public getJsonQueryAt(position: Position): string | null {
|
||||
const lines = this.document.split('\n');
|
||||
const lines = this.document.split("\n");
|
||||
const potentialQuery: string = (lines[position.line].match(/\B\$[.[].+/g) || [])[0];
|
||||
|
||||
try {
|
||||
|
@ -54,14 +55,13 @@ export class DocumentAnalysis {
|
|||
const fullyResolvedAndMergedDefinitionLocation = this.fullyResolvedAndMergedDefinitionMap.LookupForward(
|
||||
this.documentUri,
|
||||
position.line + 1, // VS Code deviates from the source map standard here... 0 vs. 1 based line numbers
|
||||
position.character)[0];
|
||||
position.character,
|
||||
)[0];
|
||||
if (fullyResolvedAndMergedDefinitionLocation) {
|
||||
|
||||
const path = fullyResolvedAndMergedDefinitionLocation.path;
|
||||
if (path) {
|
||||
|
||||
// is $ref?
|
||||
if (path.length > 0 && path[path.length - 1] === '$ref') {
|
||||
if (path.length > 0 && path[path.length - 1] === "$ref") {
|
||||
// lookup object
|
||||
const refValueJsonPointer: string = value(this.fullyResolvedAndMergedDefinition, stringify(path));
|
||||
const refValueJsonPath: JsonPath = parseJsonPointer(refValueJsonPointer);
|
||||
|
@ -76,7 +76,7 @@ export class DocumentAnalysis {
|
|||
/**
|
||||
* Retrieves all document locations (VS Code understands) corresponding with given JSON query.
|
||||
*/
|
||||
public * getDocumentLocations(jsonQuery: string): Iterable<Location> {
|
||||
public *getDocumentLocations(jsonQuery: string): Iterable<Location> {
|
||||
for (const path of paths(this.fullyResolvedAndMergedDefinition, jsonQuery)) {
|
||||
for (const mappingItem of this.fullyResolvedAndMergedDefinitionMap.LookupPath(path.slice(1))) {
|
||||
yield {
|
||||
|
@ -84,13 +84,13 @@ export class DocumentAnalysis {
|
|||
range: {
|
||||
start: {
|
||||
line: mappingItem.originalLine - 1, // VS Code deviates from the source map standard here... 0 vs. 1 based line numbers
|
||||
character: mappingItem.originalColumn
|
||||
character: mappingItem.originalColumn,
|
||||
},
|
||||
end: {
|
||||
line: mappingItem.originalLine - 1,
|
||||
character: mappingItem.originalColumn // TODO: room for improvement. think there even is extended information in `name`!
|
||||
}
|
||||
}
|
||||
character: mappingItem.originalColumn, // TODO: room for improvement. think there even is extended information in `name`!
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -99,11 +99,11 @@ export class DocumentAnalysis {
|
|||
/**
|
||||
* Retrieves all locations in the entire OpenAPI definition (and corresponding values) matching given JSON query.
|
||||
*/
|
||||
public * getDefinitionLocations(jsonQuery: string): Iterable<{ value: any; jsonPath: string }> {
|
||||
public *getDefinitionLocations(jsonQuery: string): Iterable<{ value: any; jsonPath: string }> {
|
||||
for (const path of nodes(this.fullyResolvedAndMergedDefinition, jsonQuery)) {
|
||||
yield {
|
||||
value: path.value,
|
||||
jsonPath: stringify(path.path)
|
||||
jsonPath: stringify(path.path),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,30 +1,57 @@
|
|||
// Ensure that if we're running in an electron process, that things will work as if it were node.
|
||||
process.env['ELECTRON_RUN_AS_NODE'] = '1';
|
||||
delete process.env['ELECTRON_NO_ATTACH_CONSOLE'];
|
||||
process.env["ELECTRON_RUN_AS_NODE"] = "1";
|
||||
delete process.env["ELECTRON_NO_ATTACH_CONSOLE"];
|
||||
|
||||
import { Artifact, AutoRest, Channel, DocumentType, IdentifyDocument, IFileSystem, IsConfigurationDocument, IsConfigurationExtension, IsOpenApiDocument, IsOpenApiExtension, LiterateToJson, Message } from '../exports';
|
||||
import { SourceMap } from './source-map';
|
||||
import {
|
||||
Artifact,
|
||||
AutoRest,
|
||||
Channel,
|
||||
DocumentType,
|
||||
IdentifyDocument,
|
||||
IFileSystem,
|
||||
IsConfigurationDocument,
|
||||
IsConfigurationExtension,
|
||||
IsOpenApiDocument,
|
||||
IsOpenApiExtension,
|
||||
LiterateToJson,
|
||||
Message,
|
||||
} from "../exports";
|
||||
import { SourceMap } from "./source-map";
|
||||
|
||||
import { isDirectory, readdir, readFile } from '@azure-tools/async-io';
|
||||
import { FileUriToPath, GetExtension, IsUri, ParentFolderUri, ResolveUri } from '@azure-tools/uri';
|
||||
import { createHash } from 'crypto';
|
||||
import { From } from 'linq-es2015';
|
||||
import { safeDump } from 'yaml-ast-parser';
|
||||
import { Configuration } from '../lib/configuration';
|
||||
import { DocumentAnalysis } from './document-analysis';
|
||||
import { isDirectory, readdir, readFile } from "@azure-tools/async-io";
|
||||
import { FileUriToPath, GetExtension, IsUri, ParentFolderUri, ResolveUri } from "@azure-tools/uri";
|
||||
import { createHash } from "crypto";
|
||||
import { From } from "linq-es2015";
|
||||
import { safeDump } from "yaml-ast-parser";
|
||||
import { Configuration } from "../lib/configuration";
|
||||
import { DocumentAnalysis } from "./document-analysis";
|
||||
|
||||
import {
|
||||
createConnection,
|
||||
Diagnostic, DiagnosticSeverity, FileEvent, Hover,
|
||||
IConnection, InitializeParams, InitializeResult, IPCMessageReader, IPCMessageWriter,
|
||||
Location, MarkedString, Position, Range,
|
||||
TextDocument, TextDocumentPositionParams, TextDocuments, TextDocumentSyncKind
|
||||
} from 'vscode-languageserver';
|
||||
Diagnostic,
|
||||
DiagnosticSeverity,
|
||||
FileEvent,
|
||||
Hover,
|
||||
IConnection,
|
||||
InitializeParams,
|
||||
InitializeResult,
|
||||
IPCMessageReader,
|
||||
IPCMessageWriter,
|
||||
Location,
|
||||
MarkedString,
|
||||
Position,
|
||||
Range,
|
||||
TextDocument,
|
||||
TextDocumentPositionParams,
|
||||
TextDocuments,
|
||||
TextDocumentSyncKind,
|
||||
} from "vscode-languageserver";
|
||||
|
||||
// TODO: adding URL here temporarily, this should be coming either in the message coming from autorest or the plugin
|
||||
const azureValidatorRulesDocUrl = 'https://github.com/Azure/azure-rest-api-specs/blob/current/documentation/openapi-authoring-automated-guidelines.md';
|
||||
const azureValidatorRulesDocUrl =
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/current/documentation/openapi-authoring-automated-guidelines.md";
|
||||
|
||||
const md5 = (content: any) => content ? createHash('md5').update(JSON.stringify(content)).digest('hex') : null;
|
||||
const md5 = (content: any) => (content ? createHash("md5").update(JSON.stringify(content)).digest("hex") : null);
|
||||
|
||||
/** private per-configuration run state */
|
||||
class Result {
|
||||
|
@ -36,52 +63,56 @@ class Result {
|
|||
private readonly AutoRest: AutoRest;
|
||||
private static active = 0;
|
||||
|
||||
public cancel: () => Promise<void> = async () => { };
|
||||
public ready = () => { };
|
||||
public cancel: () => Promise<void> = async () => {};
|
||||
public ready = () => {};
|
||||
|
||||
constructor(private readonly service: OpenApiLanguageService, private configurationUrl: string) {
|
||||
this.AutoRest = new AutoRest(service, configurationUrl);
|
||||
|
||||
this.onDispose.push(this.AutoRest.GeneratedFile.Subscribe((a, artifact) => this.artifacts.push(artifact)));
|
||||
this.onDispose.push(this.AutoRest.Message.Subscribe((au, message) => {
|
||||
switch (message.Channel) {
|
||||
case Channel.Debug:
|
||||
service.debug(message.Text);
|
||||
break;
|
||||
case Channel.Fatal:
|
||||
service.error(message.Text);
|
||||
break;
|
||||
case Channel.Verbose:
|
||||
service.verbose(message.Text);
|
||||
break;
|
||||
case Channel.Warning:
|
||||
service.pushDiagnostic(message, DiagnosticSeverity.Warning);
|
||||
break;
|
||||
case Channel.Error:
|
||||
service.pushDiagnostic(message, DiagnosticSeverity.Error);
|
||||
break;
|
||||
case Channel.Information:
|
||||
service.pushDiagnostic(message, DiagnosticSeverity.Information);
|
||||
break;
|
||||
case Channel.Hint:
|
||||
service.pushDiagnostic(message, DiagnosticSeverity.Hint);
|
||||
break;
|
||||
}
|
||||
}));
|
||||
this.onDispose.push(
|
||||
this.AutoRest.Message.Subscribe((au, message) => {
|
||||
switch (message.Channel) {
|
||||
case Channel.Debug:
|
||||
service.debug(message.Text);
|
||||
break;
|
||||
case Channel.Fatal:
|
||||
service.error(message.Text);
|
||||
break;
|
||||
case Channel.Verbose:
|
||||
service.verbose(message.Text);
|
||||
break;
|
||||
case Channel.Warning:
|
||||
service.pushDiagnostic(message, DiagnosticSeverity.Warning);
|
||||
break;
|
||||
case Channel.Error:
|
||||
service.pushDiagnostic(message, DiagnosticSeverity.Error);
|
||||
break;
|
||||
case Channel.Information:
|
||||
service.pushDiagnostic(message, DiagnosticSeverity.Information);
|
||||
break;
|
||||
case Channel.Hint:
|
||||
service.pushDiagnostic(message, DiagnosticSeverity.Hint);
|
||||
break;
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
this.onDispose.push(this.AutoRest.Finished.Subscribe((a, success) => {
|
||||
this.cancel = async () => { };
|
||||
// anything after it's done?
|
||||
service.debug(`Finished Autorest ${success}\n`);
|
||||
this.onDispose.push(
|
||||
this.AutoRest.Finished.Subscribe((a, success) => {
|
||||
this.cancel = async () => {};
|
||||
// anything after it's done?
|
||||
service.debug(`Finished Autorest ${success}\n`);
|
||||
|
||||
// clear diagnostics for next run
|
||||
this.clearDiagnostics();
|
||||
// clear diagnostics for next run
|
||||
this.clearDiagnostics();
|
||||
|
||||
// and mark us done!
|
||||
Result.active--;
|
||||
this.updateStatus();
|
||||
this.ready();
|
||||
}));
|
||||
// and mark us done!
|
||||
Result.active--;
|
||||
this.updateStatus();
|
||||
this.ready();
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
public clearDiagnostics(send = false) {
|
||||
|
@ -97,15 +128,18 @@ class Result {
|
|||
// then clear the collection it since we're sure this is the end of the run.
|
||||
diagnostics.clear(send);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private updateStatus() {
|
||||
if (Result.active === 0) {
|
||||
this.service.endActivity('autorest');
|
||||
this.service.endActivity("autorest");
|
||||
return;
|
||||
}
|
||||
this.service.startActivity('autorest', 'AutoRest is running', this.service.settings.debug ? `Validating ${Result.active} ` : 'Validating');
|
||||
this.service.startActivity(
|
||||
"autorest",
|
||||
"AutoRest is running",
|
||||
this.service.settings.debug ? `Validating ${Result.active} ` : "Validating",
|
||||
);
|
||||
}
|
||||
|
||||
public async process() {
|
||||
|
@ -118,7 +152,7 @@ class Result {
|
|||
await this.busy;
|
||||
|
||||
// reset the busy flag
|
||||
this.busy = new Promise((r) => this.ready = r);
|
||||
this.busy = new Promise((r) => (this.ready = r));
|
||||
|
||||
// ensure that we have nothing left over from before
|
||||
this.clear();
|
||||
|
@ -139,7 +173,7 @@ class Result {
|
|||
|
||||
this.cancel = async () => {
|
||||
// cancel only once!
|
||||
this.cancel = async () => { };
|
||||
this.cancel = async () => {};
|
||||
|
||||
// cancel the current process if running.
|
||||
processResult.cancel();
|
||||
|
@ -164,10 +198,10 @@ class Result {
|
|||
|
||||
// set the basic defaults we need
|
||||
this.AutoRest.AddConfiguration({
|
||||
'output-artifact': ['swagger-document.json', 'swagger-document.json.map']
|
||||
"output-artifact": ["swagger-document.json", "swagger-document.json.map"],
|
||||
// debug and verbose messages are not sent by default, turn them on so client settings can decide to show or not.
|
||||
, debug: true,
|
||||
verbose: true
|
||||
"debug": true,
|
||||
"verbose": true,
|
||||
});
|
||||
|
||||
// apply settings from the client
|
||||
|
@ -185,8 +219,7 @@ class Diagnostics {
|
|||
// map allows us to hash the diagnostics to filter out duplicates.
|
||||
private diagnostics = new Map<string, Diagnostic>();
|
||||
|
||||
public constructor(private connection: IConnection, private fileUri: string) {
|
||||
}
|
||||
public constructor(private connection: IConnection, private fileUri: string) {}
|
||||
|
||||
public clear(send = false) {
|
||||
this.diagnostics.clear();
|
||||
|
@ -200,7 +233,7 @@ class Diagnostics {
|
|||
}
|
||||
|
||||
public push(diagnostic: Diagnostic, send = true) {
|
||||
const hash = md5(diagnostic) || '';
|
||||
const hash = md5(diagnostic) || "";
|
||||
if (!this.diagnostics.has(hash)) {
|
||||
this.diagnostics.set(hash, diagnostic);
|
||||
if (send) {
|
||||
|
@ -233,8 +266,8 @@ export interface GenerationResults {
|
|||
}
|
||||
|
||||
class OpenApiLanguageService extends TextDocuments implements IFileSystem {
|
||||
private results = new Map</*configfile*/string, Result>();
|
||||
private diagnostics = new Map</*file*/string, Diagnostics>();
|
||||
private results = new Map</*configfile*/ string, Result>();
|
||||
private diagnostics = new Map</*file*/ string, Diagnostics>();
|
||||
private virtualFile = new Map<string, TextDocument>();
|
||||
public settings: any = {};
|
||||
|
||||
|
@ -261,7 +294,9 @@ class OpenApiLanguageService extends TextDocuments implements IFileSystem {
|
|||
this.onDidSave((p) => this.onSaving());
|
||||
|
||||
// subscribe to client settings changes
|
||||
connection.onDidChangeConfiguration(config => config.settings && config.settings.autorest ? this.onSettingsChanged(config.settings.autorest) : null);
|
||||
connection.onDidChangeConfiguration((config) =>
|
||||
config.settings && config.settings.autorest ? this.onSettingsChanged(config.settings.autorest) : null,
|
||||
);
|
||||
|
||||
// we also get change notifications of files on disk:
|
||||
connection.onDidChangeWatchedFiles((changes) => this.onFileEvents(changes.changes));
|
||||
|
@ -270,24 +305,23 @@ class OpenApiLanguageService extends TextDocuments implements IFileSystem {
|
|||
connection.onHover((position, _cancel) => this.onHover(position));
|
||||
connection.onDefinition((position, _cancel) => this.onDefinition(position));
|
||||
|
||||
connection.onInitialize(params => this.onInitialize(params));
|
||||
connection.onInitialize((params) => this.onInitialize(params));
|
||||
|
||||
this.setStatus('Starting Up.');
|
||||
this.setStatus("Starting Up.");
|
||||
|
||||
// expose the features that we want to give to the client
|
||||
connection.onRequest('generate', (p) => this.generate(p.documentUri, p.language, p.configuration));
|
||||
connection.onRequest('isOpenApiDocument', (p) => this.isOpenApiDocument(p.contentOrUri));
|
||||
connection.onRequest('identifyDocument', (p) => this.identifyDocument(p.contentOrUri));
|
||||
connection.onRequest('isConfigurationDocument', (p) => this.isConfigurationDocument(p.contentOrUri));
|
||||
connection.onRequest('isSupportedDocument', (p) => this.isSupportedDocument(p.languageId, p.contentOrUri));
|
||||
connection.onRequest('toJSON', (p) => this.toJSON(p.contentOrUri));
|
||||
connection.onRequest('detectConfigurationFile', p => this.detectConfigurationFile(p.documentUri));
|
||||
connection.onRequest("generate", (p) => this.generate(p.documentUri, p.language, p.configuration));
|
||||
connection.onRequest("isOpenApiDocument", (p) => this.isOpenApiDocument(p.contentOrUri));
|
||||
connection.onRequest("identifyDocument", (p) => this.identifyDocument(p.contentOrUri));
|
||||
connection.onRequest("isConfigurationDocument", (p) => this.isConfigurationDocument(p.contentOrUri));
|
||||
connection.onRequest("isSupportedDocument", (p) => this.isSupportedDocument(p.languageId, p.contentOrUri));
|
||||
connection.onRequest("toJSON", (p) => this.toJSON(p.contentOrUri));
|
||||
connection.onRequest("detectConfigurationFile", (p) => this.detectConfigurationFile(p.documentUri));
|
||||
|
||||
this.listen(connection);
|
||||
}
|
||||
|
||||
private async onClosed(documentUri: string): Promise<void> {
|
||||
|
||||
if (await this.isConfigurationDocument(documentUri)) {
|
||||
// if this is a configuration, clear it's own errors
|
||||
this.getDiagnosticCollection(documentUri).clear(true);
|
||||
|
@ -322,18 +356,18 @@ class OpenApiLanguageService extends TextDocuments implements IFileSystem {
|
|||
const autorest = new AutoRest(this, cfgFile);
|
||||
const cfg: any = {};
|
||||
cfg[language] = {
|
||||
'output-folder': '/generated'
|
||||
"output-folder": "/generated",
|
||||
};
|
||||
autorest.AddConfiguration(cfg);
|
||||
autorest.AddConfiguration(configuration);
|
||||
|
||||
const result = {
|
||||
files: <any>{},
|
||||
messages: new Array<string>()
|
||||
messages: new Array<string>(),
|
||||
};
|
||||
autorest.GeneratedFile.Subscribe((a, artifact) => result.files[artifact.uri] = artifact.content);
|
||||
autorest.GeneratedFile.Subscribe((a, artifact) => (result.files[artifact.uri] = artifact.content));
|
||||
autorest.Message.Subscribe((a, message) => result.messages.push(JSON.stringify(message, null, 2)));
|
||||
autorest.Finished.Subscribe(() => { });
|
||||
autorest.Finished.Subscribe(() => {});
|
||||
const done = autorest.Process();
|
||||
await done.finish;
|
||||
|
||||
|
@ -341,7 +375,9 @@ class OpenApiLanguageService extends TextDocuments implements IFileSystem {
|
|||
}
|
||||
public async isOpenApiDocument(contentOrUri: string): Promise<boolean> {
|
||||
try {
|
||||
return IsUri(contentOrUri) ? await IsOpenApiDocument(await this.ReadFile(contentOrUri)) : await IsOpenApiDocument(contentOrUri);
|
||||
return IsUri(contentOrUri)
|
||||
? await IsOpenApiDocument(await this.ReadFile(contentOrUri))
|
||||
: await IsOpenApiDocument(contentOrUri);
|
||||
} catch {
|
||||
// no worries
|
||||
}
|
||||
|
@ -350,7 +386,9 @@ class OpenApiLanguageService extends TextDocuments implements IFileSystem {
|
|||
|
||||
public async identifyDocument(contentOrUri: string): Promise<DocumentType> {
|
||||
try {
|
||||
return IsUri(contentOrUri) ? await IdentifyDocument(await this.ReadFile(contentOrUri)) : await IdentifyDocument(contentOrUri);
|
||||
return IsUri(contentOrUri)
|
||||
? await IdentifyDocument(await this.ReadFile(contentOrUri))
|
||||
: await IdentifyDocument(contentOrUri);
|
||||
} catch {
|
||||
// no worries
|
||||
}
|
||||
|
@ -358,7 +396,9 @@ class OpenApiLanguageService extends TextDocuments implements IFileSystem {
|
|||
}
|
||||
public async isConfigurationDocument(contentOrUri: string): Promise<boolean> {
|
||||
try {
|
||||
return IsUri(contentOrUri) ? await IsConfigurationDocument(await this.ReadFile(contentOrUri)) : await IsConfigurationDocument(contentOrUri);
|
||||
return IsUri(contentOrUri)
|
||||
? await IsConfigurationDocument(await this.ReadFile(contentOrUri))
|
||||
: await IsConfigurationDocument(contentOrUri);
|
||||
} catch {
|
||||
// no worries
|
||||
}
|
||||
|
@ -371,21 +411,22 @@ class OpenApiLanguageService extends TextDocuments implements IFileSystem {
|
|||
const content = IsUri(contentOrUri) ? await this.ReadFile(contentOrUri) : contentOrUri;
|
||||
const isSwag = IsOpenApiDocument(content);
|
||||
const isConf = IsConfigurationDocument(content);
|
||||
return await isSwag || await isConf;
|
||||
return (await isSwag) || (await isConf);
|
||||
}
|
||||
} catch {
|
||||
// no worries
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
public async toJSON(contentOrUri: string): Promise<string> {
|
||||
try {
|
||||
return IsUri(contentOrUri) ? await LiterateToJson(await this.ReadFile(contentOrUri)) : await LiterateToJson(contentOrUri);
|
||||
return IsUri(contentOrUri)
|
||||
? await LiterateToJson(await this.ReadFile(contentOrUri))
|
||||
: await LiterateToJson(contentOrUri);
|
||||
} catch {
|
||||
// no worries
|
||||
}
|
||||
return '';
|
||||
return "";
|
||||
}
|
||||
|
||||
public async detectConfigurationFile(documentUri: string): Promise<string> {
|
||||
|
@ -393,15 +434,15 @@ class OpenApiLanguageService extends TextDocuments implements IFileSystem {
|
|||
}
|
||||
|
||||
public setStatus(message: string) {
|
||||
this.connection.sendNotification('status', message);
|
||||
this.connection.sendNotification("status", message);
|
||||
}
|
||||
|
||||
public startActivity(id: string, title: string, message: string) {
|
||||
this.connection.sendNotification('startActivity', { id, title, message });
|
||||
this.connection.sendNotification("startActivity", { id, title, message });
|
||||
}
|
||||
|
||||
public endActivity(id: string) {
|
||||
this.connection.sendNotification('endActivity', id);
|
||||
this.connection.sendNotification("endActivity", id);
|
||||
}
|
||||
private async onSettingsChanged(serviceSettings: any) {
|
||||
// snapshot the current autorest configuration from the client
|
||||
|
@ -427,7 +468,7 @@ class OpenApiLanguageService extends TextDocuments implements IFileSystem {
|
|||
|
||||
// Tell the client that the server works in FULL text document sync mode
|
||||
textDocumentSync: TextDocumentSyncKind.Full,
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -441,15 +482,22 @@ class OpenApiLanguageService extends TextDocuments implements IFileSystem {
|
|||
if (result) {
|
||||
await result.busy; // wait for any current process to finish.
|
||||
const outputs = result.artifacts;
|
||||
const openapiDefinition = From(outputs).Where(x => x.type === 'swagger-document.json').Select(x => JSON.parse(x.content)).FirstOrDefault();
|
||||
const openapiDefinitionMap = From(outputs).Where(x => x.type === 'swagger-document.json.map').Select(x => JSON.parse(x.content)).FirstOrDefault();
|
||||
const openapiDefinition = From(outputs)
|
||||
.Where((x) => x.type === "swagger-document.json")
|
||||
.Select((x) => JSON.parse(x.content))
|
||||
.FirstOrDefault();
|
||||
const openapiDefinitionMap = From(outputs)
|
||||
.Where((x) => x.type === "swagger-document.json.map")
|
||||
.Select((x) => JSON.parse(x.content))
|
||||
.FirstOrDefault();
|
||||
|
||||
if (openapiDefinition && openapiDefinitionMap) {
|
||||
return new DocumentAnalysis(
|
||||
documentUri,
|
||||
await this.ReadFile(documentUri),
|
||||
openapiDefinition,
|
||||
new SourceMap(openapiDefinitionMap));
|
||||
new SourceMap(openapiDefinitionMap),
|
||||
);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -462,10 +510,17 @@ class OpenApiLanguageService extends TextDocuments implements IFileSystem {
|
|||
}
|
||||
|
||||
public pushDiagnostic(message: Message, severity: DiagnosticSeverity) {
|
||||
let moreInfo = '';
|
||||
if (message.Plugin === 'azure-validator') {
|
||||
let moreInfo = "";
|
||||
if (message.Plugin === "azure-validator") {
|
||||
if (message.Key) {
|
||||
moreInfo = '\n More info: ' + azureValidatorRulesDocUrl + '#' + [...message.Key][1].toLowerCase() + '-' + [...message.Key][0].toLowerCase() + '\n';
|
||||
moreInfo =
|
||||
"\n More info: " +
|
||||
azureValidatorRulesDocUrl +
|
||||
"#" +
|
||||
[...message.Key][1].toLowerCase() +
|
||||
"-" +
|
||||
[...message.Key][0].toLowerCase() +
|
||||
"\n";
|
||||
}
|
||||
}
|
||||
if (message.Range) {
|
||||
|
@ -477,48 +532,51 @@ class OpenApiLanguageService extends TextDocuments implements IFileSystem {
|
|||
if (file) {
|
||||
file.push({
|
||||
severity,
|
||||
range: Range.create(Position.create(each.start.line - 1, each.start.column), Position.create(each.end.line - 1, each.end.column)),
|
||||
range: Range.create(
|
||||
Position.create(each.start.line - 1, each.start.column),
|
||||
Position.create(each.end.line - 1, each.end.column),
|
||||
),
|
||||
message: message.Text + moreInfo,
|
||||
source: message.Key ? [...message.Key].join('/') : ''
|
||||
source: message.Key ? [...message.Key].join("/") : "",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private * onHoverRef(docAnalysis: DocumentAnalysis, position: Position): Iterable<MarkedString> {
|
||||
private *onHoverRef(docAnalysis: DocumentAnalysis, position: Position): Iterable<MarkedString> {
|
||||
const refValueJsonPath = docAnalysis.getJsonPathFromJsonReferenceAt(position);
|
||||
if (refValueJsonPath) {
|
||||
|
||||
for (const location of docAnalysis.getDefinitionLocations(refValueJsonPath)) {
|
||||
yield {
|
||||
language: 'yaml',
|
||||
value: safeDump(location.value, {})
|
||||
language: "yaml",
|
||||
value: safeDump(location.value, {}),
|
||||
};
|
||||
}
|
||||
} // else {console.log("found nothing that looks like a JSON reference"); return null; }
|
||||
}
|
||||
|
||||
private * onHoverJsonPath(docAnalysis: DocumentAnalysis, position: Position): Iterable<MarkedString> {
|
||||
private *onHoverJsonPath(docAnalysis: DocumentAnalysis, position: Position): Iterable<MarkedString> {
|
||||
const potentialQuery: string = <string>docAnalysis.getJsonQueryAt(position);
|
||||
if (potentialQuery) {
|
||||
|
||||
const queryNodes = [...docAnalysis.getDefinitionLocations(potentialQuery)];
|
||||
yield {
|
||||
language: 'plaintext',
|
||||
value: `${queryNodes.length} matches\n${queryNodes.map(node => node.jsonPath).join('\n')}`
|
||||
language: "plaintext",
|
||||
value: `${queryNodes.length} matches\n${queryNodes.map((node) => node.jsonPath).join("\n")}`,
|
||||
};
|
||||
} // else { console.log("found nothing that looks like a JSON path"); return null; }
|
||||
}
|
||||
|
||||
private async onHover(position: TextDocumentPositionParams): Promise<Hover> {
|
||||
const docAnalysis = await this.getDocumentAnalysis(position.textDocument.uri);
|
||||
return docAnalysis ? <Hover>{
|
||||
contents: [
|
||||
...this.onHoverRef(docAnalysis, position.position),
|
||||
...this.onHoverJsonPath(docAnalysis, position.position)
|
||||
]
|
||||
} : <Hover><any>null;
|
||||
return docAnalysis
|
||||
? <Hover>{
|
||||
contents: [
|
||||
...this.onHoverRef(docAnalysis, position.position),
|
||||
...this.onHoverJsonPath(docAnalysis, position.position),
|
||||
],
|
||||
}
|
||||
: <Hover>(<any>null);
|
||||
}
|
||||
|
||||
private onDefinitionRef(docAnalysis: DocumentAnalysis, position: Position): Iterable<Location> {
|
||||
|
@ -532,7 +590,6 @@ class OpenApiLanguageService extends TextDocuments implements IFileSystem {
|
|||
private onDefinitionJsonPath(docAnalysis: DocumentAnalysis, position: Position): Iterable<Location> {
|
||||
const potentialQuery: string = <string>docAnalysis.getJsonQueryAt(position);
|
||||
if (potentialQuery) {
|
||||
|
||||
return docAnalysis.getDocumentLocations(potentialQuery);
|
||||
} // else { console.log("found nothing that looks like a JSON path");}
|
||||
return [];
|
||||
|
@ -540,16 +597,17 @@ class OpenApiLanguageService extends TextDocuments implements IFileSystem {
|
|||
|
||||
private async onDefinition(position: TextDocumentPositionParams): Promise<Array<Location>> {
|
||||
const docAnalysis = await this.getDocumentAnalysis(position.textDocument.uri);
|
||||
return docAnalysis ? [
|
||||
...this.onDefinitionRef(docAnalysis, position.position),
|
||||
...this.onDefinitionJsonPath(docAnalysis, position.position)
|
||||
] : [];
|
||||
return docAnalysis
|
||||
? [
|
||||
...this.onDefinitionRef(docAnalysis, position.position),
|
||||
...this.onDefinitionJsonPath(docAnalysis, position.position),
|
||||
]
|
||||
: [];
|
||||
}
|
||||
|
||||
private async onFileEvents(changes: Array<FileEvent>) {
|
||||
this.debug(`onFileEvents: ${JSON.stringify(changes, null, ' ')}`);
|
||||
this.debug(`onFileEvents: ${JSON.stringify(changes, null, " ")}`);
|
||||
for (const each of changes) {
|
||||
|
||||
const doc = this.get(each.uri);
|
||||
if (doc) {
|
||||
this.onDocumentChanged(doc);
|
||||
|
@ -558,23 +616,23 @@ class OpenApiLanguageService extends TextDocuments implements IFileSystem {
|
|||
|
||||
const documentUri = each.uri;
|
||||
const txt = await this.ReadFile(each.uri);
|
||||
if (documentUri.startsWith('file://')) {
|
||||
if (documentUri.startsWith("file://")) {
|
||||
// fake out a document for us to play with
|
||||
this.onDocumentChanged({
|
||||
uri: each.uri,
|
||||
languageId: '',
|
||||
languageId: "",
|
||||
version: 1,
|
||||
getText: () => txt,
|
||||
positionAt: () => <Position>{},
|
||||
offsetAt: () => 0,
|
||||
lineCount: 1
|
||||
lineCount: 1,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// IFileSystem Implementation
|
||||
public async EnumerateFileUris(folderUri: string): Promise<Array<string>> {
|
||||
if (folderUri && folderUri.startsWith('file:')) {
|
||||
if (folderUri && folderUri.startsWith("file:")) {
|
||||
const folderPath = FileUriToPath(folderUri);
|
||||
if (await isDirectory(folderPath)) {
|
||||
const items = await readdir(folderPath);
|
||||
|
@ -658,12 +716,12 @@ class OpenApiLanguageService extends TextDocuments implements IFileSystem {
|
|||
if (!this.virtualFile.get(configFile)) {
|
||||
this.virtualFile.set(configFile, {
|
||||
uri: configFile,
|
||||
languageId: 'markdown',
|
||||
languageId: "markdown",
|
||||
version: 1,
|
||||
getText: () => '#Fake config file \n> see https://aka.ms/autorest \n``` yaml \ninput-file: \n - ' + documentUri,
|
||||
getText: () => "#Fake config file \n> see https://aka.ms/autorest \n``` yaml \ninput-file: \n - " + documentUri,
|
||||
positionAt: () => <Position>{},
|
||||
offsetAt: () => 0,
|
||||
lineCount: 1
|
||||
lineCount: 1,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -673,14 +731,14 @@ class OpenApiLanguageService extends TextDocuments implements IFileSystem {
|
|||
private async onDocumentChanged(document: TextDocument) {
|
||||
this.debug(`onDocumentChanged: ${document.uri}`);
|
||||
|
||||
if (await IsOpenApiExtension(document.languageId) && await IsOpenApiDocument(document.getText())) {
|
||||
if ((await IsOpenApiExtension(document.languageId)) && (await IsOpenApiDocument(document.getText()))) {
|
||||
// find the configuration file and activate that.
|
||||
this.process(await this.getConfiguration(document.uri));
|
||||
return;
|
||||
}
|
||||
|
||||
// is this a config file?
|
||||
if (await IsConfigurationExtension(document.languageId) && await IsConfigurationDocument(document.getText())) {
|
||||
if ((await IsConfigurationExtension(document.languageId)) && (await IsConfigurationDocument(document.getText()))) {
|
||||
this.process(document.uri);
|
||||
return;
|
||||
}
|
||||
|
@ -708,12 +766,12 @@ class OpenApiLanguageService extends TextDocuments implements IFileSystem {
|
|||
const content = await this.ReadFile(configFile);
|
||||
const document = {
|
||||
uri: configFile,
|
||||
languageId: 'markdown',
|
||||
languageId: "markdown",
|
||||
version: 1,
|
||||
getText: () => content,
|
||||
positionAt: () => <Position>{},
|
||||
offsetAt: () => 0,
|
||||
lineCount: 1
|
||||
lineCount: 1,
|
||||
};
|
||||
this.virtualFile.set(configFile, document);
|
||||
this.onDocumentChanged(document);
|
||||
|
@ -747,7 +805,7 @@ class OpenApiLanguageService extends TextDocuments implements IFileSystem {
|
|||
// Create the IPC Channel for the lanaguage service.
|
||||
const connection: IConnection = createConnection(new IPCMessageReader(process), new IPCMessageWriter(process));
|
||||
|
||||
process.on('unhandledRejection', function () {
|
||||
process.on("unhandledRejection", function () {
|
||||
//
|
||||
// @Future_Garrett - only turn this on as a desperate move of last resort.
|
||||
// You'll be sorry, and you will waste another day going down this rat hole
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
|
||||
import { RawSourceMap, SourceMapConsumer } from 'source-map';
|
||||
import { RawSourceMap, SourceMapConsumer } from "source-map";
|
||||
|
||||
/* @internal */
|
||||
export type JsonPath = Array<number | string>;
|
||||
|
@ -22,9 +22,13 @@ export class SourceMap {
|
|||
*/
|
||||
public LookupPath(path: JsonPath): Array<sourceMap.MappingItem> {
|
||||
const result: Array<sourceMap.MappingItem> = [];
|
||||
this.consumer.eachMapping(mi => {
|
||||
this.consumer.eachMapping((mi) => {
|
||||
const itemPath = this.ExtractJsonPath(mi);
|
||||
if (itemPath && itemPath.length === path.length && itemPath.every((part, index) => itemPath[index].toString() === path[index].toString())) {
|
||||
if (
|
||||
itemPath &&
|
||||
itemPath.length === path.length &&
|
||||
itemPath.every((part, index) => itemPath[index].toString() === path[index].toString())
|
||||
) {
|
||||
result.push(mi);
|
||||
}
|
||||
});
|
||||
|
@ -37,17 +41,25 @@ export class SourceMap {
|
|||
* @param line Line in the source file having influenced the generated file.
|
||||
* @param column Column in the source file having influenced the generated file.
|
||||
*/
|
||||
public LookupForward(file: string, line: number, column: number): Array<{ line: number; column: number; path: JsonPath | null }> {
|
||||
public LookupForward(
|
||||
file: string,
|
||||
line: number,
|
||||
column: number,
|
||||
): Array<{ line: number; column: number; path: JsonPath | null }> {
|
||||
const sameLineResults: Array<sourceMap.MappingItem> = [];
|
||||
this.consumer.eachMapping(mi => {
|
||||
if (((mi.source === file) || (decodeURIComponent(mi.source) === decodeURIComponent(file))) && mi.originalLine === line && mi.originalColumn <= column) {
|
||||
this.consumer.eachMapping((mi) => {
|
||||
if (
|
||||
(mi.source === file || decodeURIComponent(mi.source) === decodeURIComponent(file)) &&
|
||||
mi.originalLine === line &&
|
||||
mi.originalColumn <= column
|
||||
) {
|
||||
sameLineResults.push(mi);
|
||||
}
|
||||
});
|
||||
const maxColumn = sameLineResults.map(mi => mi.originalColumn).reduce((a, b) => Math.max(a, b), 0);
|
||||
const maxColumn = sameLineResults.map((mi) => mi.originalColumn).reduce((a, b) => Math.max(a, b), 0);
|
||||
return sameLineResults
|
||||
.filter(mi => mi.originalColumn === maxColumn)
|
||||
.map(mi => ({ line: mi.generatedLine, column: mi.generatedColumn, path: this.ExtractJsonPath(mi) }));
|
||||
.filter((mi) => mi.originalColumn === maxColumn)
|
||||
.map((mi) => ({ line: mi.generatedLine, column: mi.generatedColumn, path: this.ExtractJsonPath(mi) }));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -55,17 +67,25 @@ export class SourceMap {
|
|||
* @param line Line in the generated file having influenced the generated file.
|
||||
* @param column Column in the generated file having influenced the generated file.
|
||||
*/
|
||||
public LookupBackwards(line: number, column: number): Array<{ file: string; line: number; column: number; path: JsonPath | null }> {
|
||||
public LookupBackwards(
|
||||
line: number,
|
||||
column: number,
|
||||
): Array<{ file: string; line: number; column: number; path: JsonPath | null }> {
|
||||
const sameLineResults: Array<sourceMap.MappingItem> = [];
|
||||
this.consumer.eachMapping(mi => {
|
||||
this.consumer.eachMapping((mi) => {
|
||||
if (mi.generatedLine === line && mi.generatedColumn <= column) {
|
||||
sameLineResults.push(mi);
|
||||
}
|
||||
});
|
||||
const maxColumn = sameLineResults.map(mi => mi.generatedColumn).reduce((a, b) => Math.max(a, b), 0);
|
||||
const maxColumn = sameLineResults.map((mi) => mi.generatedColumn).reduce((a, b) => Math.max(a, b), 0);
|
||||
return sameLineResults
|
||||
.filter(mi => mi.generatedColumn === maxColumn)
|
||||
.map(mi => ({ file: mi.source, line: mi.originalLine, column: mi.originalColumn, path: this.ExtractJsonPath(mi) }));
|
||||
.filter((mi) => mi.generatedColumn === maxColumn)
|
||||
.map((mi) => ({
|
||||
file: mi.source,
|
||||
line: mi.originalLine,
|
||||
column: mi.originalColumn,
|
||||
path: this.ExtractJsonPath(mi),
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -75,10 +95,10 @@ export class SourceMap {
|
|||
*/
|
||||
private ExtractJsonPath(mi: sourceMap.MappingItem): JsonPath | null {
|
||||
try {
|
||||
const pathPart = mi.name.split('\n')[0];
|
||||
const pathPart = mi.name.split("\n")[0];
|
||||
return JSON.parse(pathPart);
|
||||
} catch (e) {
|
||||
console.warn('Failed obtaining object path from mapping item', e);
|
||||
console.warn("Failed obtaining object path from mapping item", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,32 +1,40 @@
|
|||
import { isAbsolute } from 'path';
|
||||
import { isAbsolute } from "path";
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ResolveUri, GetFilenameWithoutExtension } from '@azure-tools/uri';
|
||||
import { DataSource } from '@azure-tools/datastore';
|
||||
import { AutoRestConfigurationImpl } from './lib/configuration';
|
||||
import { ResolveUri, GetFilenameWithoutExtension } from "@azure-tools/uri";
|
||||
import { DataSource } from "@azure-tools/datastore";
|
||||
import { AutoRestConfigurationImpl } from "./lib/configuration";
|
||||
|
||||
const regexLegacyArg = /^-[^-]/;
|
||||
|
||||
/* @internal */ export function isLegacy(args: Array<string>): boolean {
|
||||
return args.some(arg => regexLegacyArg.test(arg));
|
||||
return args.some((arg) => regexLegacyArg.test(arg));
|
||||
}
|
||||
|
||||
async function ParseCompositeSwagger(inputScope: DataSource, uri: string, targetConfig: AutoRestConfigurationImpl): Promise<void> {
|
||||
async function ParseCompositeSwagger(
|
||||
inputScope: DataSource,
|
||||
uri: string,
|
||||
targetConfig: AutoRestConfigurationImpl,
|
||||
): Promise<void> {
|
||||
const compositeSwaggerFile = await inputScope.ReadStrict(uri);
|
||||
const data = await compositeSwaggerFile.ReadObject<{ info: any; documents: Array<string> }>();
|
||||
const documents = data.documents;
|
||||
targetConfig['input-file'] = documents.map(d => ResolveUri(uri, d));
|
||||
targetConfig["input-file"] = documents.map((d) => ResolveUri(uri, d));
|
||||
|
||||
// forward info section
|
||||
targetConfig['override-info'] = data.info;
|
||||
targetConfig["override-info"] = data.info;
|
||||
}
|
||||
|
||||
/* @internal */ export async function CreateConfiguration(baseFolderUri: string, inputScope: DataSource, args: Array<string>): Promise<AutoRestConfigurationImpl> {
|
||||
/* @internal */ export async function CreateConfiguration(
|
||||
baseFolderUri: string,
|
||||
inputScope: DataSource,
|
||||
args: Array<string>,
|
||||
): Promise<AutoRestConfigurationImpl> {
|
||||
const result: AutoRestConfigurationImpl = {
|
||||
'input-file': []
|
||||
"input-file": [],
|
||||
};
|
||||
|
||||
const switches: { [key: string]: string | null } = {};
|
||||
|
@ -34,7 +42,7 @@ async function ParseCompositeSwagger(inputScope: DataSource, uri: string, target
|
|||
// parse
|
||||
let lastValue: string | null = null;
|
||||
for (const arg of args.slice().reverse()) {
|
||||
if (arg.startsWith('-')) {
|
||||
if (arg.startsWith("-")) {
|
||||
switches[arg.substr(1).toLowerCase()] = lastValue;
|
||||
lastValue = null;
|
||||
} else {
|
||||
|
@ -43,56 +51,57 @@ async function ParseCompositeSwagger(inputScope: DataSource, uri: string, target
|
|||
}
|
||||
|
||||
// extract
|
||||
const inputFile = switches['i'] || switches['input'];
|
||||
const inputFile = switches["i"] || switches["input"];
|
||||
if (inputFile === null) {
|
||||
throw new Error('No input specified.');
|
||||
throw new Error("No input specified.");
|
||||
}
|
||||
|
||||
result['input-file'] = inputFile;
|
||||
result['output-folder'] = switches['o'] || switches['output'] || switches['outputdirectory'] || 'Generated';
|
||||
result['namespace'] = switches['n'] || switches['namespace'] || GetFilenameWithoutExtension(inputFile);
|
||||
result["input-file"] = inputFile;
|
||||
result["output-folder"] = switches["o"] || switches["output"] || switches["outputdirectory"] || "Generated";
|
||||
result["namespace"] = switches["n"] || switches["namespace"] || GetFilenameWithoutExtension(inputFile);
|
||||
|
||||
const modeler = switches['m'] || switches['modeler'] || 'Swagger';
|
||||
if (modeler === 'CompositeSwagger') {
|
||||
const modeler = switches["m"] || switches["modeler"] || "Swagger";
|
||||
if (modeler === "CompositeSwagger") {
|
||||
await ParseCompositeSwagger(inputScope, ResolveUri(baseFolderUri, inputFile), result);
|
||||
}
|
||||
|
||||
const codegenerator = switches['g'] || switches['codegenerator'] || 'CSharp';
|
||||
const usedCodeGenerator = codegenerator.toLowerCase().replace('azure.', '').replace('.fluent', '');
|
||||
if (codegenerator.toLowerCase() === 'none') {
|
||||
(<any>result)['azure-validator'] = true;
|
||||
(<any>result)['openapi-type'] = 'arm';
|
||||
const codegenerator = switches["g"] || switches["codegenerator"] || "CSharp";
|
||||
const usedCodeGenerator = codegenerator.toLowerCase().replace("azure.", "").replace(".fluent", "");
|
||||
if (codegenerator.toLowerCase() === "none") {
|
||||
(<any>result)["azure-validator"] = true;
|
||||
(<any>result)["openapi-type"] = "arm";
|
||||
} else {
|
||||
(<any>result)[usedCodeGenerator] = {};
|
||||
if (codegenerator.toLowerCase().startsWith('azure.')) {
|
||||
(<any>result)[usedCodeGenerator]['azure-arm'] = true;
|
||||
if (codegenerator.toLowerCase().startsWith("azure.")) {
|
||||
(<any>result)[usedCodeGenerator]["azure-arm"] = true;
|
||||
}
|
||||
if (codegenerator.toLowerCase().endsWith('.fluent')) {
|
||||
result['fluent'] = true;
|
||||
if (codegenerator.toLowerCase().endsWith(".fluent")) {
|
||||
result["fluent"] = true;
|
||||
}
|
||||
}
|
||||
|
||||
result['license-header'] = switches['header'] || undefined;
|
||||
result['payload-flattening-threshold'] = parseInt(switches['ft'] || switches['payloadflatteningthreshold'] || '0');
|
||||
result['sync-methods'] = <any>switches['syncmethods'] || undefined;
|
||||
result['add-credentials'] = switches['addcredentials'] === null || ((switches['addcredentials'] + '').toLowerCase() === 'true');
|
||||
result["license-header"] = switches["header"] || undefined;
|
||||
result["payload-flattening-threshold"] = parseInt(switches["ft"] || switches["payloadflatteningthreshold"] || "0");
|
||||
result["sync-methods"] = <any>switches["syncmethods"] || undefined;
|
||||
result["add-credentials"] =
|
||||
switches["addcredentials"] === null || (switches["addcredentials"] + "").toLowerCase() === "true";
|
||||
|
||||
if (usedCodeGenerator === 'ruby' || usedCodeGenerator === 'python' || usedCodeGenerator === 'go') {
|
||||
result['package-version'] = switches['pv'] || switches['packageversion'] || undefined;
|
||||
result['package-name'] = switches['pn'] || switches['packagename'] || undefined;
|
||||
if (usedCodeGenerator === "ruby" || usedCodeGenerator === "python" || usedCodeGenerator === "go") {
|
||||
result["package-version"] = switches["pv"] || switches["packageversion"] || undefined;
|
||||
result["package-name"] = switches["pn"] || switches["packagename"] || undefined;
|
||||
}
|
||||
|
||||
const outputFile = result['output-file'] = switches['outputfilename'] || undefined;
|
||||
const outputFile = (result["output-file"] = switches["outputfilename"] || undefined);
|
||||
if (outputFile && isAbsolute(outputFile)) {
|
||||
const splitAt = Math.max(outputFile.lastIndexOf('/'), outputFile.lastIndexOf('\\'));
|
||||
result['output-file'] = outputFile.slice(splitAt + 1);
|
||||
result['output-folder'] = outputFile.slice(0, splitAt);
|
||||
const splitAt = Math.max(outputFile.lastIndexOf("/"), outputFile.lastIndexOf("\\"));
|
||||
result["output-file"] = outputFile.slice(splitAt + 1);
|
||||
result["output-folder"] = outputFile.slice(0, splitAt);
|
||||
}
|
||||
|
||||
result['message-format'] = switches['jsonvalidationmessages'] !== undefined ? 'json' : undefined;
|
||||
result["message-format"] = switches["jsonvalidationmessages"] !== undefined ? "json" : undefined;
|
||||
|
||||
if (codegenerator.toLowerCase() === 'swaggerresolver') {
|
||||
result['output-artifact'] = 'swagger-document';
|
||||
if (codegenerator.toLowerCase() === "swaggerresolver") {
|
||||
result["output-artifact"] = "swagger-document";
|
||||
delete (<any>result)[usedCodeGenerator];
|
||||
}
|
||||
|
||||
|
|
|
@ -1,43 +1,46 @@
|
|||
import { EnhancedPosition } from '@azure-tools/datastore';
|
||||
import { PumpMessagesToConsole } from './test-utility';
|
||||
import { Artifact } from '../lib/artifact';
|
||||
import { Channel, Message, SourceLocation } from '../lib/message';
|
||||
import { AutoRest } from '../lib/autorest-core';
|
||||
import { RealFileSystem } from '@azure-tools/datastore';
|
||||
import { suite, test, slow, timeout, skip, only } from 'mocha-typescript';
|
||||
import * as assert from 'assert';
|
||||
import { EnhancedPosition } from "@azure-tools/datastore";
|
||||
import { PumpMessagesToConsole } from "./test-utility";
|
||||
import { Artifact } from "../lib/artifact";
|
||||
import { Channel, Message, SourceLocation } from "../lib/message";
|
||||
import { AutoRest } from "../lib/autorest-core";
|
||||
import { RealFileSystem } from "@azure-tools/datastore";
|
||||
import { suite, test, slow, timeout, skip, only } from "mocha-typescript";
|
||||
import * as assert from "assert";
|
||||
|
||||
import { CreateFolderUri, ResolveUri } from '@azure-tools/uri';
|
||||
import { parse } from '@azure-tools/datastore';
|
||||
import { Configuration } from '../lib/configuration';
|
||||
|
||||
@suite class Blaming {
|
||||
import { CreateFolderUri, ResolveUri } from "@azure-tools/uri";
|
||||
import { parse } from "@azure-tools/datastore";
|
||||
import { Configuration } from "../lib/configuration";
|
||||
|
||||
@suite
|
||||
class Blaming {
|
||||
// gs01/nelson : to do -- we have to come back and make sure this works.
|
||||
/* @test */ async 'end to end blaming with literate swagger'() {
|
||||
const autoRest = new AutoRest(new RealFileSystem(), ResolveUri(CreateFolderUri(__dirname), '../../test/resources/literate-example/readme-composite.md'));
|
||||
/* @test */ async "end to end blaming with literate swagger"() {
|
||||
const autoRest = new AutoRest(
|
||||
new RealFileSystem(),
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/literate-example/readme-composite.md"),
|
||||
);
|
||||
|
||||
// PumpMessagesToConsole(autoRest);
|
||||
const view = await autoRest.view;
|
||||
assert.equal(await autoRest.Process().finish, true);
|
||||
|
||||
const keys = Object.keys((<any>view.DataStore).store);
|
||||
const composed = keys.filter(x => x.endsWith('swagger-document'))[0];
|
||||
const composed = keys.filter((x) => x.endsWith("swagger-document"))[0];
|
||||
|
||||
// regular description
|
||||
{
|
||||
const blameTree = await view.DataStore.Blame(
|
||||
composed,
|
||||
{ path: parse('$.securityDefinitions.azure_auth.description') });
|
||||
const blameTree = await view.DataStore.Blame(composed, {
|
||||
path: parse("$.securityDefinitions.azure_auth.description"),
|
||||
});
|
||||
const blameInputs = blameTree.BlameLeafs();
|
||||
assert.equal(blameInputs.length, 1);
|
||||
}
|
||||
|
||||
// markdown description (blames both the swagger's json path and the markdown source of the description)
|
||||
{
|
||||
const blameTree = await view.DataStore.Blame(
|
||||
composed,
|
||||
{ path: parse('$.definitions.SearchServiceListResult.description') });
|
||||
const blameTree = await view.DataStore.Blame(composed, {
|
||||
path: parse("$.definitions.SearchServiceListResult.description"),
|
||||
});
|
||||
const blameInputs = blameTree.BlameLeafs();
|
||||
assert.equal(blameInputs.length, 1);
|
||||
// assert.equal(blameInputs.length, 2); // TODO: blame configuration file segments!
|
||||
|
@ -46,11 +49,18 @@ import { Configuration } from '../lib/configuration';
|
|||
// path with existent node in path
|
||||
{
|
||||
const msg = {
|
||||
Text: 'Phoney message to test', Channel: Channel.Warning, Source: [<SourceLocation>
|
||||
{
|
||||
Text: "Phoney message to test",
|
||||
Channel: Channel.Warning,
|
||||
Source: [
|
||||
<SourceLocation>{
|
||||
document: composed,
|
||||
Position: <EnhancedPosition>{ path: parse('$.paths["/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Search/searchServices/{serviceName}"]') }
|
||||
}]
|
||||
Position: <EnhancedPosition>{
|
||||
path: parse(
|
||||
'$.paths["/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Search/searchServices/{serviceName}"]',
|
||||
),
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
view.Message(msg);
|
||||
assert.equal((<Array<string>>msg.Source[0].Position.path).length, 2);
|
||||
|
@ -59,11 +69,18 @@ import { Configuration } from '../lib/configuration';
|
|||
// path node non existent
|
||||
{
|
||||
const msg = {
|
||||
Text: 'Phoney message to test', Channel: Channel.Warning, Source: [<SourceLocation>
|
||||
{
|
||||
Text: "Phoney message to test",
|
||||
Channel: Channel.Warning,
|
||||
Source: [
|
||||
<SourceLocation>{
|
||||
document: composed,
|
||||
Position: <EnhancedPosition>{ path: parse('$.paths["/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Search/searchServices/{serviceName}"].get') }
|
||||
}]
|
||||
Position: <EnhancedPosition>{
|
||||
path: parse(
|
||||
'$.paths["/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Search/searchServices/{serviceName}"].get',
|
||||
),
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
view.Message(msg);
|
||||
assert.equal((<Array<string>>msg.Source[0].Position.path).length, 2);
|
||||
|
@ -71,31 +88,37 @@ import { Configuration } from '../lib/configuration';
|
|||
}
|
||||
|
||||
// gs01/nelson : to do -- we have to come back and make sure this works.
|
||||
/* @test */ async 'generate resolved swagger with source map'() {
|
||||
const autoRest = new AutoRest(new RealFileSystem(), ResolveUri(CreateFolderUri(__dirname), '../../test/resources/small-input/'));
|
||||
autoRest.AddConfiguration({ 'output-artifact': ['swagger-document', 'swagger-document.map'] });
|
||||
/* @test */ async "generate resolved swagger with source map"() {
|
||||
const autoRest = new AutoRest(
|
||||
new RealFileSystem(),
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/small-input/"),
|
||||
);
|
||||
autoRest.AddConfiguration({ "output-artifact": ["swagger-document", "swagger-document.map"] });
|
||||
const files: Array<Artifact> = [];
|
||||
autoRest.GeneratedFile.Subscribe((_, a) => files.push(a));
|
||||
assert.equal(await autoRest.Process().finish, true);
|
||||
assert.strictEqual(files.length, 2);
|
||||
|
||||
// briefly inspect source map
|
||||
const sourceMap = files.filter(x => x.type === 'swagger-document.map')[0].content;
|
||||
const sourceMap = files.filter((x) => x.type === "swagger-document.map")[0].content;
|
||||
const sourceMapObj = JSON.parse(sourceMap);
|
||||
assert.ok(sourceMap.length > 100000);
|
||||
assert.ok(sourceMapObj.mappings.split(';').length > 1000);
|
||||
assert.ok(sourceMapObj.mappings.split(";").length > 1000);
|
||||
}
|
||||
|
||||
@test async 'large swagger performance'() {
|
||||
const autoRest = new AutoRest(new RealFileSystem(), ResolveUri(CreateFolderUri(__dirname), '../../test/resources/large-input/'));
|
||||
autoRest.AddConfiguration({ 'output-artifact': ['swagger-document', 'swagger-document.map'] });
|
||||
@test async "large swagger performance"() {
|
||||
const autoRest = new AutoRest(
|
||||
new RealFileSystem(),
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/large-input/"),
|
||||
);
|
||||
autoRest.AddConfiguration({ "output-artifact": ["swagger-document", "swagger-document.map"] });
|
||||
const messages: Array<Message> = [];
|
||||
autoRest.Message.Subscribe((_, m) => messages.push(m));
|
||||
assert.equal(await autoRest.Process().finish, true);
|
||||
assert.notEqual(messages.length, 0);
|
||||
}
|
||||
|
||||
static after() {
|
||||
static "after"() {
|
||||
Configuration.shutdown();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,38 +1,38 @@
|
|||
import * as assert from 'assert';
|
||||
import { only, skip, slow, suite, test, timeout } from 'mocha-typescript';
|
||||
import { Delay } from '../lib/sleep';
|
||||
|
||||
import { AutoRest } from '../lib/autorest-core';
|
||||
import { Configuration } from '../lib/configuration';
|
||||
import { RealFileSystem } from '@azure-tools/datastore';
|
||||
import * as assert from "assert";
|
||||
import { only, skip, slow, suite, test, timeout } from "mocha-typescript";
|
||||
import { Delay } from "../lib/sleep";
|
||||
|
||||
import { AutoRest } from "../lib/autorest-core";
|
||||
import { Configuration } from "../lib/configuration";
|
||||
import { RealFileSystem } from "@azure-tools/datastore";
|
||||
|
||||
/*@suite */ class Cancellation {
|
||||
private async CreateLongRunningAutoRest(): Promise<AutoRest> {
|
||||
private async "CreateLongRunningAutoRest"(): Promise<AutoRest> {
|
||||
const autoRest = new AutoRest(new RealFileSystem());
|
||||
await autoRest.AddConfiguration({
|
||||
'input-file': [
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/applicationGateway.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/checkDnsAvailability.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/expressRouteCircuit.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/loadBalancer.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/network.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/networkInterface.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/networkSecurityGroup.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/networkWatcher.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/publicIpAddress.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/routeFilter.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/routeTable.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/serviceCommunity.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/usage.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/virtualNetwork.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/virtualNetworkGateway.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/vmssNetworkInterface.json']
|
||||
"input-file": [
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/applicationGateway.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/checkDnsAvailability.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/expressRouteCircuit.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/loadBalancer.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/network.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/networkInterface.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/networkSecurityGroup.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/networkWatcher.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/publicIpAddress.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/routeFilter.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/routeTable.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/serviceCommunity.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/usage.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/virtualNetwork.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/virtualNetworkGateway.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/vmssNetworkInterface.json",
|
||||
],
|
||||
});
|
||||
return autoRest;
|
||||
}
|
||||
|
||||
private async TestCancellationAfter(delay: number): Promise<void> {
|
||||
private async "TestCancellationAfter"(delay: number): Promise<void> {
|
||||
const ar = await this.CreateLongRunningAutoRest();
|
||||
const proc = ar.Process();
|
||||
await Delay(delay);
|
||||
|
@ -45,17 +45,35 @@ import { RealFileSystem } from '@azure-tools/datastore';
|
|||
assert.ok(ms2 - ms1 < 500);
|
||||
}
|
||||
|
||||
@test async 'immediate'() { await this.TestCancellationAfter(0); }
|
||||
@test async 'after 100ms'() { await this.TestCancellationAfter(100); }
|
||||
@test async 'after 1s'() { await this.TestCancellationAfter(1000); }
|
||||
@test async 'after 2s'() { await this.TestCancellationAfter(2000); }
|
||||
@test async 'after 3s'() { await this.TestCancellationAfter(3000); }
|
||||
@test async 'after 5s'() { await this.TestCancellationAfter(5000); }
|
||||
@test async 'after 8s'() { await this.TestCancellationAfter(8000); }
|
||||
@test async 'after 10s'() { await this.TestCancellationAfter(10000); }
|
||||
@test async 'after 15s'() { await this.TestCancellationAfter(15000); }
|
||||
@test async "immediate"() {
|
||||
await this.TestCancellationAfter(0);
|
||||
}
|
||||
@test async "after 100ms"() {
|
||||
await this.TestCancellationAfter(100);
|
||||
}
|
||||
@test async "after 1s"() {
|
||||
await this.TestCancellationAfter(1000);
|
||||
}
|
||||
@test async "after 2s"() {
|
||||
await this.TestCancellationAfter(2000);
|
||||
}
|
||||
@test async "after 3s"() {
|
||||
await this.TestCancellationAfter(3000);
|
||||
}
|
||||
@test async "after 5s"() {
|
||||
await this.TestCancellationAfter(5000);
|
||||
}
|
||||
@test async "after 8s"() {
|
||||
await this.TestCancellationAfter(8000);
|
||||
}
|
||||
@test async "after 10s"() {
|
||||
await this.TestCancellationAfter(10000);
|
||||
}
|
||||
@test async "after 15s"() {
|
||||
await this.TestCancellationAfter(15000);
|
||||
}
|
||||
|
||||
static after() {
|
||||
static "after"() {
|
||||
Configuration.shutdown();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,54 +3,60 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { nodes } from '@azure-tools/datastore';
|
||||
import { CreateFolderUri, ResolveUri } from '@azure-tools/uri';
|
||||
import { RealFileSystem } from '@azure-tools/datastore';
|
||||
import { AutoRest } from '../lib/autorest-core';
|
||||
import { suite, test, slow, timeout, skip, only } from 'mocha-typescript';
|
||||
import * as assert from 'assert';
|
||||
import { nodes } from "@azure-tools/datastore";
|
||||
import { CreateFolderUri, ResolveUri } from "@azure-tools/uri";
|
||||
import { RealFileSystem } from "@azure-tools/datastore";
|
||||
import { AutoRest } from "../lib/autorest-core";
|
||||
import { suite, test, slow, timeout, skip, only } from "mocha-typescript";
|
||||
import * as assert from "assert";
|
||||
|
||||
import { Node, Parser } from 'commonmark';
|
||||
import { plainTextVersion } from '../lib/pipeline/commonmark-documentation';
|
||||
import { Node, Parser } from "commonmark";
|
||||
import { plainTextVersion } from "../lib/pipeline/commonmark-documentation";
|
||||
|
||||
@suite class Commonmark {
|
||||
|
||||
private Parse(rawCommonmark: string): Node {
|
||||
@suite
|
||||
class Commonmark {
|
||||
private "Parse"(rawCommonmark: string): Node {
|
||||
return new Parser().parse(rawCommonmark);
|
||||
}
|
||||
|
||||
@test async 'PlainTextVersion'() {
|
||||
const compare = (raw: string, expected: string) =>
|
||||
assert.strictEqual(plainTextVersion(this.Parse(raw)), expected);
|
||||
@test async "PlainTextVersion"() {
|
||||
const compare = (raw: string, expected: string) => assert.strictEqual(plainTextVersion(this.Parse(raw)), expected);
|
||||
|
||||
compare('Hello World', 'Hello World');
|
||||
compare('this\ntest\ncould\nuse\nmore\ncowbell', 'this test could use more cowbell');
|
||||
compare('actual\n\nnewline', 'actual\nnewline');
|
||||
compare('some **more** delicious *cowbell*', 'some more delicious cowbell');
|
||||
compare('add some `code` in there', 'add some code in there');
|
||||
compare('# Heading \n Body', 'Heading\nBody');
|
||||
compare('Fancy <b>html</b> features', 'Fancy html features');
|
||||
compare('Even <code>fancier</code> <i>html</i> tags<br> and<hr> stuff', 'Even fancier html tags and stuff');
|
||||
compare("Hello World", "Hello World");
|
||||
compare("this\ntest\ncould\nuse\nmore\ncowbell", "this test could use more cowbell");
|
||||
compare("actual\n\nnewline", "actual\nnewline");
|
||||
compare("some **more** delicious *cowbell*", "some more delicious cowbell");
|
||||
compare("add some `code` in there", "add some code in there");
|
||||
compare("# Heading \n Body", "Heading\nBody");
|
||||
compare("Fancy <b>html</b> features", "Fancy html features");
|
||||
compare("Even <code>fancier</code> <i>html</i> tags<br> and<hr> stuff", "Even fancier html tags and stuff");
|
||||
}
|
||||
|
||||
// gs01/nelson : to do -- we have to come back and make sure this works.
|
||||
/* @test */ async 'resolve markdown descriptions'() {
|
||||
const autoRest = new AutoRest(new RealFileSystem(), ResolveUri(CreateFolderUri(__dirname), '../../test/resources/literate-example/'));
|
||||
autoRest.AddConfiguration({ 'output-artifact': 'swagger-document' });
|
||||
/* @test */ async "resolve markdown descriptions"() {
|
||||
const autoRest = new AutoRest(
|
||||
new RealFileSystem(),
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/literate-example/"),
|
||||
);
|
||||
autoRest.AddConfiguration({ "output-artifact": "swagger-document" });
|
||||
|
||||
let swaggerDoc = '';
|
||||
autoRest.GeneratedFile.Subscribe((_, a) => { if (a.type === 'swagger-document') { swaggerDoc = a.content; } });
|
||||
let swaggerDoc = "";
|
||||
autoRest.GeneratedFile.Subscribe((_, a) => {
|
||||
if (a.type === "swagger-document") {
|
||||
swaggerDoc = a.content;
|
||||
}
|
||||
});
|
||||
assert.strictEqual(await autoRest.Process().finish, true);
|
||||
assert.notEqual(swaggerDoc, '');
|
||||
assert.notEqual(swaggerDoc, "");
|
||||
|
||||
// check that all descriptions have been resolved
|
||||
const swaggerDocObj = JSON.parse(swaggerDoc);
|
||||
for (const descrNode of nodes(swaggerDocObj, '$..description')) {
|
||||
assert.strictEqual(typeof descrNode.value, 'string');
|
||||
for (const descrNode of nodes(swaggerDocObj, "$..description")) {
|
||||
assert.strictEqual(typeof descrNode.value, "string");
|
||||
}
|
||||
|
||||
// commented out since we don't include subheadings currently
|
||||
// // check that subheading was included
|
||||
// assert.ok(swaggerDocObj.definitions.ListQueryKeysResult.description.indexOf("content under a subheading") !== -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
import { suite, test, slow, timeout, skip, only } from 'mocha-typescript';
|
||||
import * as assert from 'assert';
|
||||
import * as datastore from '@azure-tools/datastore';
|
||||
import * as aio from '@azure-tools/async-io';
|
||||
import { ComponentsCleaner } from '../lib/pipeline/plugins/components-cleaner';
|
||||
|
||||
require('source-map-support').install();
|
||||
import { suite, test, slow, timeout, skip, only } from "mocha-typescript";
|
||||
import * as assert from "assert";
|
||||
import * as datastore from "@azure-tools/datastore";
|
||||
import * as aio from "@azure-tools/async-io";
|
||||
import { ComponentsCleaner } from "../lib/pipeline/plugins/components-cleaner";
|
||||
|
||||
require("source-map-support").install();
|
||||
|
||||
const resources = `${__dirname}/../../test/resources/component-cleaner`;
|
||||
|
||||
@suite class ComponentCleanerTest {
|
||||
|
||||
async readData(...files: Array<string>) {
|
||||
@suite
|
||||
class ComponentCleanerTest {
|
||||
async "readData"(...files: Array<string>) {
|
||||
const results = new Array<datastore.DataHandle>();
|
||||
const map = new Map<string, string>();
|
||||
|
||||
|
@ -22,7 +21,15 @@ const resources = `${__dirname}/../../test/resources/component-cleaner`;
|
|||
}
|
||||
|
||||
const mfs = new datastore.MemoryFileSystem(map);
|
||||
const cts: datastore.CancellationTokenSource = { cancel() {/* unused */ }, dispose() {/* unused */ }, token: { isCancellationRequested: false, onCancellationRequested: <any>null } };
|
||||
const cts: datastore.CancellationTokenSource = {
|
||||
cancel() {
|
||||
/* unused */
|
||||
},
|
||||
dispose() {
|
||||
/* unused */
|
||||
},
|
||||
token: { isCancellationRequested: false, onCancellationRequested: <any>null },
|
||||
};
|
||||
const ds = new datastore.DataStore(cts.token);
|
||||
const scope = ds.GetReadThroughScope(mfs);
|
||||
|
||||
|
@ -36,17 +43,28 @@ const resources = `${__dirname}/../../test/resources/component-cleaner`;
|
|||
return results;
|
||||
}
|
||||
|
||||
async io(inputFile: string, outputFile: string) {
|
||||
async "io"(inputFile: string, outputFile: string) {
|
||||
const inputUri = `mem://${inputFile}`;
|
||||
const outputUri = `mem://${outputFile}`;
|
||||
|
||||
const inputText = await aio.readFile(`${resources}/${inputFile}`);
|
||||
const outputText = await aio.readFile(`${resources}/${outputFile}`);
|
||||
|
||||
const map = new Map<string, string>([[inputUri, inputText], [outputUri, outputText]]);
|
||||
const map = new Map<string, string>([
|
||||
[inputUri, inputText],
|
||||
[outputUri, outputText],
|
||||
]);
|
||||
const mfs = new datastore.MemoryFileSystem(map);
|
||||
|
||||
const cts: datastore.CancellationTokenSource = { cancel() {/* unused */ }, dispose() {/* unused */ }, token: { isCancellationRequested: false, onCancellationRequested: <any>null } };
|
||||
const cts: datastore.CancellationTokenSource = {
|
||||
cancel() {
|
||||
/* unused */
|
||||
},
|
||||
dispose() {
|
||||
/* unused */
|
||||
},
|
||||
token: { isCancellationRequested: false, onCancellationRequested: <any>null },
|
||||
};
|
||||
const ds = new datastore.DataStore(cts.token);
|
||||
const scope = ds.GetReadThroughScope(mfs);
|
||||
const input = await scope.Read(inputUri);
|
||||
|
@ -55,28 +73,29 @@ const resources = `${__dirname}/../../test/resources/component-cleaner`;
|
|||
assert(input !== null);
|
||||
assert(output !== null);
|
||||
if (input === null || output === null) {
|
||||
throw Error('Input or Output is null');
|
||||
throw Error("Input or Output is null");
|
||||
}
|
||||
return {
|
||||
input, output
|
||||
input,
|
||||
output,
|
||||
};
|
||||
}
|
||||
|
||||
@test async 'just primary-file components present'() {
|
||||
const [input, output] = await this.readData('input1.yaml', 'output1.yaml');
|
||||
@test async "just primary-file components present"() {
|
||||
const [input, output] = await this.readData("input1.yaml", "output1.yaml");
|
||||
const cleaner = new ComponentsCleaner(input);
|
||||
assert.deepStrictEqual(await cleaner.getOutput(), await output.ReadObject());
|
||||
}
|
||||
|
||||
@test async 'secondary-file components present, but all of them referenced by something in a primary-file.'() {
|
||||
const [input, output] = await this.readData('input2.yaml', 'output2.yaml');
|
||||
@test async "secondary-file components present, but all of them referenced by something in a primary-file."() {
|
||||
const [input, output] = await this.readData("input2.yaml", "output2.yaml");
|
||||
const cleaner = new ComponentsCleaner(input);
|
||||
assert.deepStrictEqual(await cleaner.getOutput(), await output.ReadObject());
|
||||
}
|
||||
|
||||
// todo: I think this fails because he changed the behavior to let all non schema/parameter components thru.
|
||||
@test @skip async 'secondary-file components not referenced by something in a primary-file.'() {
|
||||
const [input, output] = await this.readData('input3.yaml', 'output3.yaml');
|
||||
@test @skip async "secondary-file components not referenced by something in a primary-file."() {
|
||||
const [input, output] = await this.readData("input3.yaml", "output3.yaml");
|
||||
const cleaner = new ComponentsCleaner(input);
|
||||
const cleaned = await cleaner.getOutput();
|
||||
const expected = await output.ReadObject();
|
||||
|
@ -85,8 +104,10 @@ const resources = `${__dirname}/../../test/resources/component-cleaner`;
|
|||
}
|
||||
|
||||
// todo: I think this fails because he changed the behavior to let all non schema/parameter components thru.
|
||||
@test @skip async 'secondary-file components not referenced by something in a primary-file, and some referenced by something in a primary-file'() {
|
||||
const [input, output] = await this.readData('input4.yaml', 'output4.yaml');
|
||||
@test
|
||||
@skip
|
||||
async "secondary-file components not referenced by something in a primary-file, and some referenced by something in a primary-file"() {
|
||||
const [input, output] = await this.readData("input4.yaml", "output4.yaml");
|
||||
const cleaner = new ComponentsCleaner(input);
|
||||
const cleaned = await cleaner.getOutput();
|
||||
const expected = await output.ReadObject();
|
||||
|
@ -95,8 +116,8 @@ const resources = `${__dirname}/../../test/resources/component-cleaner`;
|
|||
}
|
||||
|
||||
// todo: I think this fails because he changed the behavior to let all non schema/parameter components thru.
|
||||
@test @skip async 'AnyOf, AllOf, OneOf, Not references from secondary-file-components to primary-file-components.'() {
|
||||
const [input, output] = await this.readData('input5.yaml', 'output5.yaml');
|
||||
@test @skip async "AnyOf, AllOf, OneOf, Not references from secondary-file-components to primary-file-components."() {
|
||||
const [input, output] = await this.readData("input5.yaml", "output5.yaml");
|
||||
|
||||
const cleaner = new ComponentsCleaner(input);
|
||||
const cleaned = await cleaner.getOutput();
|
||||
|
@ -104,4 +125,4 @@ const resources = `${__dirname}/../../test/resources/component-cleaner`;
|
|||
|
||||
assert.deepStrictEqual(cleaned, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
import { suite, test, slow, timeout, skip, only } from 'mocha-typescript';
|
||||
import * as assert from 'assert';
|
||||
import { IFileSystem, MemoryFileSystem } from '@azure-tools/datastore';
|
||||
import * as AutoRest from '../lib/autorest-core';
|
||||
import { suite, test, slow, timeout, skip, only } from "mocha-typescript";
|
||||
import * as assert from "assert";
|
||||
import { IFileSystem, MemoryFileSystem } from "@azure-tools/datastore";
|
||||
import * as AutoRest from "../lib/autorest-core";
|
||||
|
||||
@suite class TestConfiguration {
|
||||
|
||||
@test async 'Test config'() {
|
||||
@suite
|
||||
class TestConfiguration {
|
||||
@test async "Test config"() {
|
||||
// test out subscribe
|
||||
|
||||
const f = new MemoryFileSystem(new Map<string, string>([
|
||||
['readme.md', `
|
||||
const f = new MemoryFileSystem(
|
||||
new Map<string, string>([
|
||||
[
|
||||
"readme.md",
|
||||
`
|
||||
# this is a test
|
||||
> see https://aka.ms/autorest
|
||||
~~~ yaml
|
||||
|
@ -33,55 +36,62 @@ csharp:
|
|||
output-folder: $(output-folder)/csharp
|
||||
|
||||
~~~
|
||||
`],
|
||||
['other.md', `
|
||||
`,
|
||||
],
|
||||
[
|
||||
"other.md",
|
||||
`
|
||||
# My Doc.
|
||||
|
||||
# some text
|
||||
|
||||
`]]));
|
||||
`,
|
||||
],
|
||||
]),
|
||||
);
|
||||
|
||||
const autorest = new AutoRest.AutoRest(f, MemoryFileSystem.DefaultVirtualRootUri + 'readme.md');
|
||||
const autorest = new AutoRest.AutoRest(f, MemoryFileSystem.DefaultVirtualRootUri + "readme.md");
|
||||
let cfg = await autorest.view;
|
||||
|
||||
// output folder should be 'foo'
|
||||
assert.equal(cfg['output-folder'], 'foo');
|
||||
assert.equal(cfg["output-folder"], "foo");
|
||||
|
||||
// sample-other should get resolved to the value of sample-value
|
||||
assert.equal(cfg['sample-other'], 'one');
|
||||
assert.equal(cfg["sample-other"], "one");
|
||||
|
||||
// verify that the items object that uses a macro works too
|
||||
assert.equal(cfg['items'][3], 'one/two');
|
||||
assert.equal(cfg["items"][3], "one/two");
|
||||
|
||||
for (const each of cfg.GetNestedConfiguration('csharp')) {
|
||||
for (const each of cfg.GetNestedConfiguration("csharp")) {
|
||||
// verify the output folder is relative
|
||||
assert.equal(each.GetEntry('output-folder'), 'foo/csharp');
|
||||
assert.equal(each.GetEntry("output-folder"), "foo/csharp");
|
||||
|
||||
// verify that the items object that uses a macro works too
|
||||
// assert.equal((<any>(each.Raw))['items'][3], "two/two");
|
||||
|
||||
// now, this got resolved alot earlier.
|
||||
// dunno if we need it the other way or not.
|
||||
assert.equal(each['items'][3], 'one/two');
|
||||
assert.equal(each["items"][3], "one/two");
|
||||
}
|
||||
|
||||
// override the output-folder from the cmdline
|
||||
autorest.AddConfiguration({ 'output-folder': 'OUTPUT' });
|
||||
autorest.AddConfiguration({ "output-folder": "OUTPUT" });
|
||||
cfg = await autorest.view;
|
||||
assert.equal(cfg['output-folder'], 'OUTPUT');
|
||||
assert.equal(cfg["output-folder"], "OUTPUT");
|
||||
|
||||
for (const each of cfg.GetNestedConfiguration('csharp')) {
|
||||
assert.equal(each['output-folder'], 'OUTPUT/csharp');
|
||||
for (const each of cfg.GetNestedConfiguration("csharp")) {
|
||||
assert.equal(each["output-folder"], "OUTPUT/csharp");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@test async 'Test Guards'() {
|
||||
@test async "Test Guards"() {
|
||||
// test out subscribe
|
||||
|
||||
const f = new MemoryFileSystem(new Map<string, string>([
|
||||
['readme.md', `
|
||||
const f = new MemoryFileSystem(
|
||||
new Map<string, string>([
|
||||
[
|
||||
"readme.md",
|
||||
`
|
||||
# this is a test
|
||||
> see https://aka.ms/autorest
|
||||
|
||||
|
@ -110,23 +120,29 @@ value:
|
|||
- not_bar
|
||||
~~~
|
||||
|
||||
`],
|
||||
['other.md', `
|
||||
`,
|
||||
],
|
||||
[
|
||||
"other.md",
|
||||
`
|
||||
# My Doc.
|
||||
|
||||
# some text
|
||||
|
||||
`]]));
|
||||
`,
|
||||
],
|
||||
]),
|
||||
);
|
||||
|
||||
const autorest = new AutoRest.AutoRest(f, MemoryFileSystem.DefaultVirtualRootUri + 'readme.md');
|
||||
const autorest = new AutoRest.AutoRest(f, MemoryFileSystem.DefaultVirtualRootUri + "readme.md");
|
||||
autorest.AddConfiguration({ foo: true });
|
||||
let cfg = await autorest.view;
|
||||
|
||||
// output folder should be 'foo'
|
||||
assert.deepEqual(cfg['value'], ['foo', 'foo_and_not_bar', 'not_bar']);
|
||||
assert.deepEqual(cfg["value"], ["foo", "foo_and_not_bar", "not_bar"]);
|
||||
|
||||
autorest.AddConfiguration({ bar: true });
|
||||
cfg = await autorest.view;
|
||||
assert.deepEqual(cfg['value'], ['foo', 'foo_and_bar', 'bar']);
|
||||
assert.deepEqual(cfg["value"], ["foo", "foo_and_bar", "bar"]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import * as Mocha from 'mocha';
|
||||
import * as Mocha from "mocha";
|
||||
|
||||
declare type MochaDone = Mocha.Done;
|
||||
|
|
|
@ -1,25 +1,32 @@
|
|||
import { suite, test, slow, timeout, skip, only } from 'mocha-typescript';
|
||||
import * as assert from 'assert';
|
||||
import { suite, test, slow, timeout, skip, only } from "mocha-typescript";
|
||||
import * as assert from "assert";
|
||||
|
||||
import { AutoRest } from '../lib/autorest-core';
|
||||
import { RealFileSystem } from '@azure-tools/datastore';
|
||||
import { CreateFolderUri, ResolveUri } from '@azure-tools/uri';
|
||||
import { Message, Channel } from '../lib/message';
|
||||
|
||||
@suite class Directive {
|
||||
import { AutoRest } from "../lib/autorest-core";
|
||||
import { RealFileSystem } from "@azure-tools/datastore";
|
||||
import { CreateFolderUri, ResolveUri } from "@azure-tools/uri";
|
||||
import { Message, Channel } from "../lib/message";
|
||||
|
||||
@suite
|
||||
class Directive {
|
||||
// todo: azure-validator doesn't work on v3.
|
||||
@test @skip async 'suppression'() {
|
||||
const autoRest = new AutoRest(new RealFileSystem(), ResolveUri(CreateFolderUri(__dirname), '../../test/resources/literate-example/'));
|
||||
autoRest.Message.Subscribe((_, m) => m.Channel === Channel.Fatal ? console.error(m.Text) : '');
|
||||
@test @skip async "suppression"() {
|
||||
const autoRest = new AutoRest(
|
||||
new RealFileSystem(),
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/literate-example/"),
|
||||
);
|
||||
autoRest.Message.Subscribe((_, m) => (m.Channel === Channel.Fatal ? console.error(m.Text) : ""));
|
||||
|
||||
// reference run
|
||||
await autoRest.ResetConfiguration();
|
||||
await autoRest.AddConfiguration({ 'azure-validator': true, 'openapi-type': 'arm' });
|
||||
await autoRest.AddConfiguration({ "azure-validator": true, "openapi-type": "arm" });
|
||||
let numWarningsRef: number;
|
||||
{
|
||||
const messages: Array<Message> = [];
|
||||
const dispose = autoRest.Message.Subscribe((_, m) => { if (m.Channel == Channel.Warning) { messages.push(m); } });
|
||||
const dispose = autoRest.Message.Subscribe((_, m) => {
|
||||
if (m.Channel == Channel.Warning) {
|
||||
messages.push(m);
|
||||
}
|
||||
});
|
||||
|
||||
assert.equal(await autoRest.Process().finish, true);
|
||||
numWarningsRef = messages.length;
|
||||
|
@ -30,15 +37,23 @@ import { Message, Channel } from '../lib/message';
|
|||
|
||||
// muted run
|
||||
await autoRest.ResetConfiguration();
|
||||
await autoRest.AddConfiguration({ 'azure-validator': true, 'openapi-type': 'arm' });
|
||||
await autoRest.AddConfiguration({ directive: { suppress: ['AvoidNestedProperties', 'ModelTypeIncomplete', 'R4000', 'PutRequestResponseScheme', 'R2029'] } });
|
||||
await autoRest.AddConfiguration({ "azure-validator": true, "openapi-type": "arm" });
|
||||
await autoRest.AddConfiguration({
|
||||
directive: {
|
||||
suppress: ["AvoidNestedProperties", "ModelTypeIncomplete", "R4000", "PutRequestResponseScheme", "R2029"],
|
||||
},
|
||||
});
|
||||
{
|
||||
const messages: Array<Message> = [];
|
||||
const dispose = autoRest.Message.Subscribe((_, m) => { if (m.Channel == Channel.Warning) { messages.push(m); } });
|
||||
const dispose = autoRest.Message.Subscribe((_, m) => {
|
||||
if (m.Channel == Channel.Warning) {
|
||||
messages.push(m);
|
||||
}
|
||||
});
|
||||
|
||||
assert.equal(await autoRest.Process().finish, true);
|
||||
if (messages.length > 0) {
|
||||
console.log('Should have been muted but found:');
|
||||
console.log("Should have been muted but found:");
|
||||
console.log(JSON.stringify(messages, null, 2));
|
||||
}
|
||||
assert.strictEqual(messages.length, 0);
|
||||
|
@ -49,11 +64,15 @@ import { Message, Channel } from '../lib/message';
|
|||
// makes sure that neither all nor nothing was returned
|
||||
const pickyRun = async (directive: any) => {
|
||||
await autoRest.ResetConfiguration();
|
||||
await autoRest.AddConfiguration({ 'azure-validator': true, 'openapi-type': 'arm' });
|
||||
await autoRest.AddConfiguration({ "azure-validator": true, "openapi-type": "arm" });
|
||||
await autoRest.AddConfiguration({ directive: directive });
|
||||
{
|
||||
const messages: Array<Message> = [];
|
||||
const dispose = autoRest.Message.Subscribe((_, m) => { if (m.Channel == Channel.Warning) { messages.push(m); } });
|
||||
const dispose = autoRest.Message.Subscribe((_, m) => {
|
||||
if (m.Channel == Channel.Warning) {
|
||||
messages.push(m);
|
||||
}
|
||||
});
|
||||
|
||||
assert.equal(await autoRest.Process().finish, true);
|
||||
if (messages.length === 0 || messages.length === numWarningsRef) {
|
||||
|
@ -67,36 +86,36 @@ import { Message, Channel } from '../lib/message';
|
|||
};
|
||||
|
||||
// not all types
|
||||
await pickyRun({ suppress: ['AvoidNestedProperties'] });
|
||||
await pickyRun({ suppress: ["AvoidNestedProperties"] });
|
||||
// certain paths
|
||||
await pickyRun({ suppress: ['AvoidNestedProperties', 'ModelTypeIncomplete', 'R4000'], where: '$..properties' });
|
||||
await pickyRun({ suppress: ['AvoidNestedProperties'], where: '$..properties.properties' });
|
||||
await pickyRun({ suppress: ["AvoidNestedProperties", "ModelTypeIncomplete", "R4000"], where: "$..properties" });
|
||||
await pickyRun({ suppress: ["AvoidNestedProperties"], where: "$..properties.properties" });
|
||||
// multiple directives
|
||||
await pickyRun([{ suppress: ['AvoidNestedProperties'], where: '$..properties.properties' }]);
|
||||
await pickyRun([
|
||||
{ suppress: ['AvoidNestedProperties'] },
|
||||
{ suppress: ['ModelTypeIncomplete'] }
|
||||
]);
|
||||
await pickyRun([
|
||||
{ suppress: ['R4000'] },
|
||||
{ suppress: ['ModelTypeIncomplete'] }
|
||||
]);
|
||||
await pickyRun([{ suppress: ["AvoidNestedProperties"], where: "$..properties.properties" }]);
|
||||
await pickyRun([{ suppress: ["AvoidNestedProperties"] }, { suppress: ["ModelTypeIncomplete"] }]);
|
||||
await pickyRun([{ suppress: ["R4000"] }, { suppress: ["ModelTypeIncomplete"] }]);
|
||||
// document
|
||||
await pickyRun({ suppress: ['AvoidNestedProperties'], where: '$..properties.properties', from: 'swagger.md' });
|
||||
await pickyRun({ suppress: ["AvoidNestedProperties"], where: "$..properties.properties", from: "swagger.md" });
|
||||
}
|
||||
|
||||
@test @skip async 'set descriptions on different levels'() {
|
||||
const autoRest = new AutoRest(new RealFileSystem(), ResolveUri(CreateFolderUri(__dirname), '../../test/resources/literate-example/'));
|
||||
@test @skip async "set descriptions on different levels"() {
|
||||
const autoRest = new AutoRest(
|
||||
new RealFileSystem(),
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/literate-example/"),
|
||||
);
|
||||
|
||||
const GenerateCodeModel = async (config: any) => {
|
||||
await autoRest.ResetConfiguration();
|
||||
autoRest.AddConfiguration({ 'output-artifact': 'code-model-v1' });
|
||||
autoRest.AddConfiguration({ "output-artifact": "code-model-v1" });
|
||||
autoRest.AddConfiguration(config);
|
||||
|
||||
let resolve: (content: string) => void;
|
||||
const result = new Promise<string>(res => resolve = res);
|
||||
const result = new Promise<string>((res) => (resolve = res));
|
||||
|
||||
const dispose = autoRest.GeneratedFile.Subscribe((_, a) => { resolve(a.content); dispose(); });
|
||||
const dispose = autoRest.GeneratedFile.Subscribe((_, a) => {
|
||||
resolve(a.content);
|
||||
dispose();
|
||||
});
|
||||
assert.equal(await autoRest.Process().finish, true);
|
||||
|
||||
return result;
|
||||
|
@ -106,21 +125,34 @@ import { Message, Channel } from '../lib/message';
|
|||
const codeModelRef = await GenerateCodeModel({});
|
||||
|
||||
// set descriptions in resolved swagger
|
||||
const codeModelSetDescr1 = await GenerateCodeModel({ directive: { from: 'swagger-document', where: '$..description', set: 'cowbell' } });
|
||||
const codeModelSetDescr1 = await GenerateCodeModel({
|
||||
directive: { from: "swagger-document", where: "$..description", set: "cowbell" },
|
||||
});
|
||||
|
||||
// set descriptions in code model
|
||||
const codeModelSetDescr2 = await GenerateCodeModel({ directive: { from: 'code-model-v1', where: ['$..description', '$..documentation'], set: 'cowbell' } });
|
||||
const codeModelSetDescr2 = await GenerateCodeModel({
|
||||
directive: { from: "code-model-v1", where: ["$..description", "$..documentation"], set: "cowbell" },
|
||||
});
|
||||
|
||||
// transform descriptions in resolved swagger
|
||||
const codeModelSetDescr3 = await GenerateCodeModel({ directive: { from: 'swagger-document', where: '$..description', transform: 'return \'cowbell\'' } });
|
||||
const codeModelSetDescr3 = await GenerateCodeModel({
|
||||
directive: { from: "swagger-document", where: "$..description", transform: "return 'cowbell'" },
|
||||
});
|
||||
|
||||
assert.ok(codeModelRef.indexOf('description: cowbell') === -1 && codeModelRef.indexOf('"description": "cowbell"') === -1);
|
||||
assert.ok(codeModelSetDescr1.indexOf('description: cowbell') !== -1 || codeModelSetDescr1.indexOf('"description": "cowbell"') !== -1);
|
||||
assert.ok(
|
||||
codeModelRef.indexOf("description: cowbell") === -1 && codeModelRef.indexOf('"description": "cowbell"') === -1,
|
||||
);
|
||||
assert.ok(
|
||||
codeModelSetDescr1.indexOf("description: cowbell") !== -1 ||
|
||||
codeModelSetDescr1.indexOf('"description": "cowbell"') !== -1,
|
||||
);
|
||||
assert.strictEqual(codeModelSetDescr1, codeModelSetDescr2);
|
||||
assert.strictEqual(codeModelSetDescr1, codeModelSetDescr3);
|
||||
|
||||
// transform descriptions in resolved swagger to uppercase
|
||||
const codeModelSetDescr4 = await GenerateCodeModel({ directive: { from: 'swagger-document', where: '$..description', transform: 'return $.toUpperCase()' } });
|
||||
const codeModelSetDescr4 = await GenerateCodeModel({
|
||||
directive: { from: "swagger-document", where: "$..description", transform: "return $.toUpperCase()" },
|
||||
});
|
||||
assert.notEqual(codeModelRef, codeModelSetDescr4);
|
||||
assert.strictEqual(codeModelRef.toLowerCase(), codeModelSetDescr4.toLowerCase());
|
||||
}
|
||||
|
|
|
@ -1,40 +1,42 @@
|
|||
import * as assert from 'assert';
|
||||
import { only, skip, slow, suite, test, timeout } from 'mocha-typescript';
|
||||
import * as assert from "assert";
|
||||
import { only, skip, slow, suite, test, timeout } from "mocha-typescript";
|
||||
|
||||
import { AutoRest } from '../lib/autorest-core';
|
||||
import { RealFileSystem } from '@azure-tools/datastore';
|
||||
import { Channel, Message } from '../lib/message';
|
||||
import { CreateFolderUri, ResolveUri } from '@azure-tools/uri';
|
||||
import { PumpMessagesToConsole } from './test-utility';
|
||||
import { AutoRest } from "../lib/autorest-core";
|
||||
import { RealFileSystem } from "@azure-tools/datastore";
|
||||
import { Channel, Message } from "../lib/message";
|
||||
import { CreateFolderUri, ResolveUri } from "@azure-tools/uri";
|
||||
import { PumpMessagesToConsole } from "./test-utility";
|
||||
|
||||
@suite class EndToEnd {
|
||||
@test async 'network full game'() {
|
||||
@suite
|
||||
class EndToEnd {
|
||||
@test async "network full game"() {
|
||||
const autoRest = new AutoRest(new RealFileSystem());
|
||||
// PumpMessagesToConsole(autoRest);
|
||||
autoRest.AddConfiguration({
|
||||
'input-file': [
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/applicationGateway.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/checkDnsAvailability.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/expressRouteCircuit.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/loadBalancer.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/network.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/networkInterface.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/networkSecurityGroup.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/networkWatcher.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/publicIpAddress.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/routeFilter.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/routeTable.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/serviceCommunity.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/usage.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/virtualNetwork.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/virtualNetworkGateway.json',
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/vmssNetworkInterface.json']
|
||||
"input-file": [
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/applicationGateway.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/checkDnsAvailability.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/expressRouteCircuit.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/loadBalancer.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/network.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/networkInterface.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/networkSecurityGroup.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/networkWatcher.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/publicIpAddress.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/routeFilter.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/routeTable.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/serviceCommunity.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/usage.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/virtualNetwork.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/virtualNetworkGateway.json",
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/master/specification/network/resource-manager/Microsoft.Network/stable/2017-03-01/vmssNetworkInterface.json",
|
||||
],
|
||||
});
|
||||
|
||||
autoRest.AddConfiguration({
|
||||
'override-info': {
|
||||
title: 'Network'
|
||||
}
|
||||
"override-info": {
|
||||
title: "Network",
|
||||
},
|
||||
});
|
||||
|
||||
// TODO: generate for all, probe results
|
||||
|
@ -43,26 +45,31 @@ import { PumpMessagesToConsole } from './test-utility';
|
|||
assert.strictEqual(success, true);
|
||||
}
|
||||
|
||||
@test async 'other configuration scenario'() {
|
||||
const autoRest = new AutoRest(new RealFileSystem(), ResolveUri(CreateFolderUri(__dirname), '../../test/resources/literate-example/readme-complicated.md'));
|
||||
@test async "other configuration scenario"() {
|
||||
const autoRest = new AutoRest(
|
||||
new RealFileSystem(),
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/literate-example/readme-complicated.md"),
|
||||
);
|
||||
// PumpMessagesToConsole(autoRest);
|
||||
|
||||
const config = await autoRest.view;
|
||||
assert.strictEqual(config['shouldwork'], true);
|
||||
|
||||
assert.strictEqual(config["shouldwork"], true);
|
||||
}
|
||||
|
||||
// todo: skipping because testing is broken?
|
||||
@test @skip async 'complicated configuration scenario'() {
|
||||
const autoRest = new AutoRest(new RealFileSystem(), ResolveUri(CreateFolderUri(__dirname), '../../test/resources/literate-example/readme-complicated.md'));
|
||||
@test @skip async "complicated configuration scenario"() {
|
||||
const autoRest = new AutoRest(
|
||||
new RealFileSystem(),
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/literate-example/readme-complicated.md"),
|
||||
);
|
||||
// PumpMessagesToConsole(autoRest);
|
||||
autoRest.AddConfiguration({
|
||||
'cmd-line-true': true,
|
||||
'cmd-line-false': false,
|
||||
'cmd-line-complex': {
|
||||
'true': true,
|
||||
'false': false
|
||||
}
|
||||
"cmd-line-true": true,
|
||||
"cmd-line-false": false,
|
||||
"cmd-line-complex": {
|
||||
true: true,
|
||||
false: false,
|
||||
},
|
||||
});
|
||||
|
||||
const config = await autoRest.view;
|
||||
|
@ -70,47 +77,61 @@ import { PumpMessagesToConsole } from './test-utility';
|
|||
|
||||
const messages: Array<Message> = [];
|
||||
|
||||
autoRest.Message.Subscribe((_, m) => { if (m.Channel === Channel.Warning) { messages.push(m); } });
|
||||
autoRest.Message.Subscribe((_, m) => {
|
||||
if (m.Channel === Channel.Warning) {
|
||||
messages.push(m);
|
||||
}
|
||||
});
|
||||
assert.equal(await autoRest.Process().finish, true);
|
||||
assert.notEqual(messages.length, 0);
|
||||
}
|
||||
// testing end-to-end for non-arm type validation rules. Since all validation rules are currently defaulted to
|
||||
// ARM, non-ARM documents should show 0 validation messages
|
||||
// TODO: fix this test when validation rules are properly categorized
|
||||
@test @skip async 'non-arm type spec testing'() {
|
||||
const autoRest = new AutoRest(new RealFileSystem(), ResolveUri(CreateFolderUri(__dirname), '../../test/resources/validation-options/readme.md'));
|
||||
@test @skip async "non-arm type spec testing"() {
|
||||
const autoRest = new AutoRest(
|
||||
new RealFileSystem(),
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/validation-options/readme.md"),
|
||||
);
|
||||
autoRest.AddConfiguration({
|
||||
'openapi-type': 'default',
|
||||
'azure-validator': true
|
||||
"openapi-type": "default",
|
||||
"azure-validator": true,
|
||||
});
|
||||
|
||||
const config = await autoRest.view;
|
||||
const messages: Array<Message> = [];
|
||||
|
||||
autoRest.Message.Subscribe((_, m) => { messages.push(m); });
|
||||
autoRest.Message.Subscribe((_, m) => {
|
||||
messages.push(m);
|
||||
});
|
||||
assert.equal(await autoRest.Process().finish, true);
|
||||
assert.notEqual(messages.length, 0);
|
||||
// flag any fatal errors
|
||||
assert.equal(messages.filter(m => m.Channel === Channel.Fatal).length, 0);
|
||||
assert.equal(messages.filter((m) => m.Channel === Channel.Fatal).length, 0);
|
||||
}
|
||||
|
||||
// todo: skipping because testing is broken?
|
||||
@test @skip async 'arm type spec testing'() {
|
||||
const autoRest = new AutoRest(new RealFileSystem(), ResolveUri(CreateFolderUri(__dirname), '../../test/resources/validation-options/readme.md'));
|
||||
@test @skip async "arm type spec testing"() {
|
||||
const autoRest = new AutoRest(
|
||||
new RealFileSystem(),
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/validation-options/readme.md"),
|
||||
);
|
||||
autoRest.AddConfiguration({
|
||||
'openapi-type': 'arm',
|
||||
'azure-validator': true
|
||||
"openapi-type": "arm",
|
||||
"azure-validator": true,
|
||||
});
|
||||
|
||||
const config = await autoRest.view;
|
||||
|
||||
const messages: Array<Message> = [];
|
||||
|
||||
autoRest.Message.Subscribe((_, m) => { messages.push(m); });
|
||||
autoRest.Message.Subscribe((_, m) => {
|
||||
messages.push(m);
|
||||
});
|
||||
// PumpMessagesToConsole(autoRest);
|
||||
assert.equal(await autoRest.Process().finish, true);
|
||||
// flag any fatal errors
|
||||
assert.equal(messages.filter(m => m.Channel === Channel.Fatal).length, 0);
|
||||
assert.equal(messages.filter((m) => m.Channel === Channel.Fatal).length, 0);
|
||||
assert.notEqual(messages.length, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,25 +1,23 @@
|
|||
import { suite, test, slow, timeout, skip, only } from 'mocha-typescript';
|
||||
import * as assert from 'assert';
|
||||
import { IEvent, EventEmitter } from '../lib/events';
|
||||
import { suite, test, slow, timeout, skip, only } from "mocha-typescript";
|
||||
import * as assert from "assert";
|
||||
import { IEvent, EventEmitter } from "../lib/events";
|
||||
|
||||
export class MyClass extends EventEmitter {
|
||||
|
||||
@EventEmitter.Event public Debug!: IEvent<MyClass, string>;
|
||||
|
||||
public go() {
|
||||
this.Debug.Dispatch('Hello');
|
||||
this.Debug.Dispatch("Hello");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@suite class Eventing {
|
||||
|
||||
@test async 'Do Events Work'() {
|
||||
@suite
|
||||
class Eventing {
|
||||
@test async "Do Events Work"() {
|
||||
const instance = new MyClass();
|
||||
let worksWithSubscribe = 'no';
|
||||
let worksLikeNode = 'no';
|
||||
let worksWithSubscribe = "no";
|
||||
let worksLikeNode = "no";
|
||||
|
||||
instance.on('Debug', (inst: MyClass, s: string) => {
|
||||
instance.on("Debug", (inst: MyClass, s: string) => {
|
||||
worksLikeNode = s;
|
||||
});
|
||||
|
||||
|
@ -30,13 +28,13 @@ export class MyClass extends EventEmitter {
|
|||
instance.go();
|
||||
|
||||
// test out subscribe
|
||||
assert.equal(worksLikeNode, 'Hello');
|
||||
assert.equal(worksWithSubscribe, 'Hello');
|
||||
assert.equal(worksLikeNode, "Hello");
|
||||
assert.equal(worksWithSubscribe, "Hello");
|
||||
|
||||
// test out unsubscribe
|
||||
worksWithSubscribe = 'no';
|
||||
// test out unsubscribe
|
||||
worksWithSubscribe = "no";
|
||||
unsub();
|
||||
|
||||
assert.equal(worksWithSubscribe, 'no');
|
||||
assert.equal(worksWithSubscribe, "no");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,21 @@
|
|||
import { suite, test, slow, timeout, skip, only } from 'mocha-typescript';
|
||||
import { IFileSystem, MemoryFileSystem } from '@azure-tools/datastore';
|
||||
import * as assert from 'assert';
|
||||
import { suite, test, slow, timeout, skip, only } from "mocha-typescript";
|
||||
import { IFileSystem, MemoryFileSystem } from "@azure-tools/datastore";
|
||||
import * as assert from "assert";
|
||||
|
||||
@suite class FileSystemTests {
|
||||
@test async 'does async iterable work'() {
|
||||
const f = new MemoryFileSystem(new Map<string, string>([['readme.md', '# this is a test\n see https://aka.ms/autorest'], ['other.md', '#My Doc.']]));
|
||||
@suite
|
||||
class FileSystemTests {
|
||||
@test async "does async iterable work"() {
|
||||
const f = new MemoryFileSystem(
|
||||
new Map<string, string>([
|
||||
["readme.md", "# this is a test\n see https://aka.ms/autorest"],
|
||||
["other.md", "#My Doc."],
|
||||
]),
|
||||
);
|
||||
let n = 0;
|
||||
for (const name of await f.EnumerateFileUris()) {
|
||||
n++;
|
||||
}
|
||||
assert.equal(n, 2);
|
||||
assert.equal(await f.ReadFile(MemoryFileSystem.DefaultVirtualRootUri + 'other.md'), '#My Doc.');
|
||||
assert.equal(await f.ReadFile(MemoryFileSystem.DefaultVirtualRootUri + "other.md"), "#My Doc.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,70 +2,73 @@
|
|||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { suite, test, slow, timeout, skip, only } from 'mocha-typescript';
|
||||
import * as assert from 'assert';
|
||||
import { suite, test, slow, timeout, skip, only } from "mocha-typescript";
|
||||
import * as assert from "assert";
|
||||
|
||||
import * as jp from '@azure-tools/datastore';
|
||||
import * as jp from "@azure-tools/datastore";
|
||||
|
||||
@suite class JsonPath {
|
||||
@test async 'IsPrefix'() {
|
||||
assert.strictEqual(jp.IsPrefix(jp.parse('$.a.b.c'), jp.parse('$.a.b.c.d')), true);
|
||||
assert.strictEqual(jp.IsPrefix(jp.parse('$.a.b.c'), jp.parse('$.a.b.c')), true);
|
||||
assert.strictEqual(jp.IsPrefix(jp.parse('$.a.b.c'), jp.parse('$.a.b')), false);
|
||||
@suite
|
||||
class JsonPath {
|
||||
@test async "IsPrefix"() {
|
||||
assert.strictEqual(jp.IsPrefix(jp.parse("$.a.b.c"), jp.parse("$.a.b.c.d")), true);
|
||||
assert.strictEqual(jp.IsPrefix(jp.parse("$.a.b.c"), jp.parse("$.a.b.c")), true);
|
||||
assert.strictEqual(jp.IsPrefix(jp.parse("$.a.b.c"), jp.parse("$.a.b")), false);
|
||||
}
|
||||
|
||||
@test async 'matches'() {
|
||||
assert.strictEqual(jp.matches('$..*', jp.parse('$.a.b.c')), true);
|
||||
assert.strictEqual(jp.matches('$..c', jp.parse('$.a.b.c')), true);
|
||||
assert.strictEqual(jp.matches('$..b', jp.parse('$.a.b.c')), false);
|
||||
assert.strictEqual(jp.matches('$.a.b.c', jp.parse('$.a.b.c')), true);
|
||||
assert.strictEqual(jp.matches('$.a.b', jp.parse('$.a.b.c')), false);
|
||||
assert.strictEqual(jp.matches('$.a..*', jp.parse('$.a.b.c')), true);
|
||||
assert.strictEqual(jp.matches('$.a.b.c.d', jp.parse('$.a.b.c')), false);
|
||||
@test async "matches"() {
|
||||
assert.strictEqual(jp.matches("$..*", jp.parse("$.a.b.c")), true);
|
||||
assert.strictEqual(jp.matches("$..c", jp.parse("$.a.b.c")), true);
|
||||
assert.strictEqual(jp.matches("$..b", jp.parse("$.a.b.c")), false);
|
||||
assert.strictEqual(jp.matches("$.a.b.c", jp.parse("$.a.b.c")), true);
|
||||
assert.strictEqual(jp.matches("$.a.b", jp.parse("$.a.b.c")), false);
|
||||
assert.strictEqual(jp.matches("$.a..*", jp.parse("$.a.b.c")), true);
|
||||
assert.strictEqual(jp.matches("$.a.b.c.d", jp.parse("$.a.b.c")), false);
|
||||
}
|
||||
|
||||
@test async 'querying'() {
|
||||
assert.strictEqual(jp.nodes({ a: 1, b: 2, c: 3 }, '$..*').length, 3);
|
||||
assert.strictEqual(jp.nodes({ a: 1, b: 2, c: 3 }, '$..a').length, 1);
|
||||
assert.strictEqual(jp.nodes({ a: 1, b: 2, c: 3 }, '$.a').length, 1);
|
||||
assert.strictEqual(jp.nodes({ a: 1, b: 2, c: 3 }, '$.d').length, 0);
|
||||
@test async "querying"() {
|
||||
assert.strictEqual(jp.nodes({ a: 1, b: 2, c: 3 }, "$..*").length, 3);
|
||||
assert.strictEqual(jp.nodes({ a: 1, b: 2, c: 3 }, "$..a").length, 1);
|
||||
assert.strictEqual(jp.nodes({ a: 1, b: 2, c: 3 }, "$.a").length, 1);
|
||||
assert.strictEqual(jp.nodes({ a: 1, b: 2, c: 3 }, "$.d").length, 0);
|
||||
|
||||
assert.strictEqual(jp.paths({ a: 1, b: 2, c: 3 }, '$..*').length, 3);
|
||||
assert.strictEqual(jp.paths({ a: 1, b: 2, c: 3 }, '$..a').length, 1);
|
||||
assert.strictEqual(jp.paths({ a: 1, b: 2, c: 3 }, '$.a').length, 1);
|
||||
assert.strictEqual(jp.paths({ a: 1, b: 2, c: 3 }, '$.d').length, 0);
|
||||
assert.strictEqual(jp.paths({ a: 1, b: 2, c: 3 }, "$..*").length, 3);
|
||||
assert.strictEqual(jp.paths({ a: 1, b: 2, c: 3 }, "$..a").length, 1);
|
||||
assert.strictEqual(jp.paths({ a: 1, b: 2, c: 3 }, "$.a").length, 1);
|
||||
assert.strictEqual(jp.paths({ a: 1, b: 2, c: 3 }, "$.d").length, 0);
|
||||
|
||||
assert.strictEqual(jp.paths({ x: { $ref: 'x' }, y: { $re: 'x' } }, '$[?(@.$ref)]').length, 1);
|
||||
assert.strictEqual(jp.paths({ a: { x: { $ref: 'x' } }, b: { x: { $re: 'x' } } }, '$..*[?(@.$ref)]').length, 1);
|
||||
assert.strictEqual(jp.paths({ x: { $ref: "x" }, y: { $re: "x" } }, "$[?(@.$ref)]").length, 1);
|
||||
assert.strictEqual(jp.paths({ a: { x: { $ref: "x" } }, b: { x: { $re: "x" } } }, "$..*[?(@.$ref)]").length, 1);
|
||||
}
|
||||
|
||||
@test async 'querying features'() {
|
||||
@test async "querying features"() {
|
||||
const obj = { a: 1, b: 2, c: 3, d: { a: [1, 2, 3], b: 2, c: 3 } };
|
||||
assert.strictEqual(jp.nodes(obj, '$.*').length, 4);
|
||||
assert.strictEqual(jp.nodes(obj, '$.*.*').length, 3);
|
||||
assert.strictEqual(jp.nodes(obj, '$..*.*').length, 6);
|
||||
assert.strictEqual(jp.nodes(obj, '$..*').length, 10);
|
||||
assert.strictEqual(jp.nodes(obj, '$..[*]').length, 10);
|
||||
assert.strictEqual(jp.nodes(obj, '$..[\'d\']').length, 1);
|
||||
assert.strictEqual(jp.nodes(obj, '$..d').length, 1);
|
||||
assert.strictEqual(jp.nodes(obj, '$..[2]').length, 1);
|
||||
assert.strictEqual(jp.nodes(obj, '$..[?(@.a[2] === 3)]').length, 1);
|
||||
assert.strictEqual(jp.nodes(obj, '$..[?(@.a.reduce((x,y) => x+y, 0) === 6)]').length, 1);
|
||||
assert.strictEqual(jp.nodes(obj, "$.*").length, 4);
|
||||
assert.strictEqual(jp.nodes(obj, "$.*.*").length, 3);
|
||||
assert.strictEqual(jp.nodes(obj, "$..*.*").length, 6);
|
||||
assert.strictEqual(jp.nodes(obj, "$..*").length, 10);
|
||||
assert.strictEqual(jp.nodes(obj, "$..[*]").length, 10);
|
||||
assert.strictEqual(jp.nodes(obj, "$..['d']").length, 1);
|
||||
assert.strictEqual(jp.nodes(obj, "$..d").length, 1);
|
||||
assert.strictEqual(jp.nodes(obj, "$..[2]").length, 1);
|
||||
assert.strictEqual(jp.nodes(obj, "$..[?(@.a[2] === 3)]").length, 1);
|
||||
assert.strictEqual(jp.nodes(obj, "$..[?(@.a.reduce((x,y) => x+y, 0) === 6)]").length, 1);
|
||||
//assert.strictEqual(jp.nodes(obj, "$..[(@.length - 1)]").length, 1);
|
||||
//assert.strictEqual(jp.nodes(obj, "$..[(1 + 1)]").length, 1);
|
||||
}
|
||||
|
||||
private roundTrip(s: string): string { return jp.stringify(jp.parse(s)); }
|
||||
private "roundTrip"(s: string): string {
|
||||
return jp.stringify(jp.parse(s));
|
||||
}
|
||||
|
||||
@test 'round trip identity'() {
|
||||
@test "round trip identity"() {
|
||||
const roundTrips = (s: string) => assert.equal(this.roundTrip(s), s);
|
||||
roundTrips('$.asd.qwe[1].zxc');
|
||||
roundTrips("$.asd.qwe[1].zxc");
|
||||
roundTrips('$[1][42]["asd qwe"]');
|
||||
roundTrips('$[1]["1"]');
|
||||
}
|
||||
|
||||
@test 'round trip simplification'() {
|
||||
assert.equal(this.roundTrip('$["definitely"]["add"]["more"]["cowbell"]'), '$.definitely.add.more.cowbell');
|
||||
@test "round trip simplification"() {
|
||||
assert.equal(this.roundTrip('$["definitely"]["add"]["more"]["cowbell"]'), "$.definitely.add.more.cowbell");
|
||||
assert.equal(this.roundTrip('$[1]["even"]["more cowbell"]'), '$[1].even["more cowbell"]');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,28 +3,27 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as aio from '@azure-tools/async-io';
|
||||
import * as datastore from '@azure-tools/datastore';
|
||||
import * as aio from "@azure-tools/async-io";
|
||||
import * as datastore from "@azure-tools/datastore";
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { only, skip, slow, suite, test, timeout } from 'mocha-typescript';
|
||||
import * as assert from "assert";
|
||||
import { only, skip, slow, suite, test, timeout } from "mocha-typescript";
|
||||
|
||||
import { MultiAPIMerger } from '../lib/pipeline/plugins/merger';
|
||||
import { FastStringify } from '@azure-tools/datastore';
|
||||
import { MultiAPIMerger } from "../lib/pipeline/plugins/merger";
|
||||
import { FastStringify } from "@azure-tools/datastore";
|
||||
try {
|
||||
require('source-map-support').install();
|
||||
require("source-map-support").install();
|
||||
} catch {
|
||||
/* unused */
|
||||
}
|
||||
const resources = `${__dirname}../../../test/resources/merger`;
|
||||
|
||||
@suite class TestShaker {
|
||||
|
||||
@suite
|
||||
class TestShaker {
|
||||
// todo: not testing now.
|
||||
@test @skip async 'Test Merger'() {
|
||||
|
||||
const inputUri = 'mem://input.yaml';
|
||||
const inputUri2 = 'mem://input2.yaml';
|
||||
@test @skip async "Test Merger"() {
|
||||
const inputUri = "mem://input.yaml";
|
||||
const inputUri2 = "mem://input2.yaml";
|
||||
// const outputUri = 'mem://output.yaml';
|
||||
|
||||
const input = await aio.readFile(`${resources}/input.yaml`);
|
||||
|
@ -37,7 +36,15 @@ const resources = `${__dirname}../../../test/resources/merger`;
|
|||
const mfs = new datastore.MemoryFileSystem(map);
|
||||
const mfs2 = new datastore.MemoryFileSystem(map2);
|
||||
|
||||
const cts: datastore.CancellationTokenSource = { cancel() {/* unused */ }, dispose() {/* unused */ }, token: { isCancellationRequested: false, onCancellationRequested: <any>null } };
|
||||
const cts: datastore.CancellationTokenSource = {
|
||||
cancel() {
|
||||
/* unused */
|
||||
},
|
||||
dispose() {
|
||||
/* unused */
|
||||
},
|
||||
token: { isCancellationRequested: false, onCancellationRequested: <any>null },
|
||||
};
|
||||
const ds = new datastore.DataStore(cts.token);
|
||||
const scope = ds.GetReadThroughScope(mfs);
|
||||
const scope2 = ds.GetReadThroughScope(mfs2);
|
||||
|
@ -57,18 +64,23 @@ const resources = `${__dirname}../../../test/resources/merger`;
|
|||
const sink = ds.getDataSink();
|
||||
const output = await processor.getOutput();
|
||||
|
||||
const data = await sink.WriteObject('merged oai3 doc...', await processor.getOutput(), inputDataHandle.identity, 'merged-oai3', await processor.getSourceMappings(), [inputDataHandle, inputDataHandle2]);
|
||||
|
||||
const data = await sink.WriteObject(
|
||||
"merged oai3 doc...",
|
||||
await processor.getOutput(),
|
||||
inputDataHandle.identity,
|
||||
"merged-oai3",
|
||||
await processor.getSourceMappings(),
|
||||
[inputDataHandle, inputDataHandle2],
|
||||
);
|
||||
|
||||
// testing: dump out the converted file
|
||||
// console.log(FastStringify(processor.output));
|
||||
// console.log(JSON.stringify(data.ReadMetadata.sourceMap.Value));
|
||||
|
||||
await aio.writeFile('c:/tmp/input.yaml', input);
|
||||
await aio.writeFile('c:/tmp/output.yaml', FastStringify(await processor.getOutput()));
|
||||
await aio.writeFile("c:/tmp/input.yaml", input);
|
||||
await aio.writeFile("c:/tmp/output.yaml", FastStringify(await processor.getOutput()));
|
||||
// await aio.writeFile("c:/tmp/output.yaml.map", JSON.stringify(await data.metadata.sourceMap));
|
||||
|
||||
|
||||
// assert.deepEqual(shaker.output, outputObject, 'Should be the same');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,34 +2,83 @@
|
|||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { suite, test, slow, timeout, skip, only } from 'mocha-typescript';
|
||||
import * as assert from 'assert';
|
||||
import { suite, test, slow, timeout, skip, only } from "mocha-typescript";
|
||||
import * as assert from "assert";
|
||||
|
||||
import { matches } from '@azure-tools/datastore';
|
||||
import { MergeOverwriteOrAppend } from '../lib/source-map/merging';
|
||||
import { matches } from "@azure-tools/datastore";
|
||||
import { MergeOverwriteOrAppend } from "../lib/source-map/merging";
|
||||
|
||||
@suite class Merging {
|
||||
@test async 'MergeOverwriteOrAppend'() {
|
||||
@suite
|
||||
class Merging {
|
||||
@test async MergeOverwriteOrAppend() {
|
||||
// list overwriting and concatenation
|
||||
assert.deepStrictEqual(MergeOverwriteOrAppend(1, 2, _ => false), 1);
|
||||
assert.deepStrictEqual(MergeOverwriteOrAppend(1, 2, _ => true), [1, 2]);
|
||||
assert.deepStrictEqual(MergeOverwriteOrAppend(1, [2], _ => false), [1, 2]);
|
||||
assert.deepStrictEqual(MergeOverwriteOrAppend(1, [2], _ => true), [1, 2]);
|
||||
assert.deepStrictEqual(MergeOverwriteOrAppend([1], 2, _ => false), [1, 2]);
|
||||
assert.deepStrictEqual(MergeOverwriteOrAppend([1], 2, _ => true), [1, 2]);
|
||||
assert.deepStrictEqual(MergeOverwriteOrAppend([1], [2], _ => false), [1, 2]);
|
||||
assert.deepStrictEqual(MergeOverwriteOrAppend([1], [2], _ => true), [1, 2]);
|
||||
assert.deepStrictEqual(
|
||||
MergeOverwriteOrAppend(1, 2, (_) => false),
|
||||
1,
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
MergeOverwriteOrAppend(1, 2, (_) => true),
|
||||
[1, 2],
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
MergeOverwriteOrAppend(1, [2], (_) => false),
|
||||
[1, 2],
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
MergeOverwriteOrAppend(1, [2], (_) => true),
|
||||
[1, 2],
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
MergeOverwriteOrAppend([1], 2, (_) => false),
|
||||
[1, 2],
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
MergeOverwriteOrAppend([1], 2, (_) => true),
|
||||
[1, 2],
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
MergeOverwriteOrAppend([1], [2], (_) => false),
|
||||
[1, 2],
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
MergeOverwriteOrAppend([1], [2], (_) => true),
|
||||
[1, 2],
|
||||
);
|
||||
|
||||
// picky concatenation
|
||||
assert.deepStrictEqual(MergeOverwriteOrAppend({ a: 1, b: 1 }, { a: 2, b: 2 }, _ => false), { a: 1, b: 1 });
|
||||
assert.deepStrictEqual(MergeOverwriteOrAppend({ a: 1, b: 1 }, { a: 2, b: 2 }, _ => true), { a: [1, 2], b: [1, 2] });
|
||||
assert.deepStrictEqual(MergeOverwriteOrAppend({ a: 1, b: 1 }, { a: 2, b: 2 }, p => matches('$.a', p)), { a: [1, 2], b: 1 });
|
||||
assert.deepStrictEqual(MergeOverwriteOrAppend({ a: 1, b: 1 }, { a: 2, b: 2 }, p => matches('$.b', p)), { a: 1, b: [1, 2] });
|
||||
assert.deepStrictEqual(
|
||||
MergeOverwriteOrAppend({ a: 1, b: 1 }, { a: 2, b: 2 }, (_) => false),
|
||||
{ a: 1, b: 1 },
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
MergeOverwriteOrAppend({ a: 1, b: 1 }, { a: 2, b: 2 }, (_) => true),
|
||||
{ a: [1, 2], b: [1, 2] },
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
MergeOverwriteOrAppend({ a: 1, b: 1 }, { a: 2, b: 2 }, (p) => matches("$.a", p)),
|
||||
{ a: [1, 2], b: 1 },
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
MergeOverwriteOrAppend({ a: 1, b: 1 }, { a: 2, b: 2 }, (p) => matches("$.b", p)),
|
||||
{ a: 1, b: [1, 2] },
|
||||
);
|
||||
|
||||
// complicated object
|
||||
assert.deepStrictEqual(MergeOverwriteOrAppend(
|
||||
{ a: 1, b: 1, c: { a: 1, b: { a: 1, b: 1 } }, d: [{ a: 1, b: 1 }] },
|
||||
{ a: 2, bx: 2, c: { ax: 2, b: { c: 2 } }, d: [{ a: 2, b: 2 }] }),
|
||||
{ a: 1, b: 1, bx: 2, c: { a: 1, ax: 2, b: { a: 1, b: 1, c: 2 } }, d: [{ a: 1, b: 1 }, { a: 2, b: 2 }] });
|
||||
assert.deepStrictEqual(
|
||||
MergeOverwriteOrAppend(
|
||||
{ a: 1, b: 1, c: { a: 1, b: { a: 1, b: 1 } }, d: [{ a: 1, b: 1 }] },
|
||||
{ a: 2, bx: 2, c: { ax: 2, b: { c: 2 } }, d: [{ a: 2, b: 2 }] },
|
||||
),
|
||||
{
|
||||
a: 1,
|
||||
b: 1,
|
||||
bx: 2,
|
||||
c: { a: 1, ax: 2, b: { a: 1, b: 1, c: 2 } },
|
||||
d: [
|
||||
{ a: 1, b: 1 },
|
||||
{ a: 2, b: 2 },
|
||||
],
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,22 +2,22 @@
|
|||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { suite, test, slow, timeout, skip, only } from 'mocha-typescript';
|
||||
import * as assert from 'assert';
|
||||
import { suite, test, slow, timeout, skip, only } from "mocha-typescript";
|
||||
import * as assert from "assert";
|
||||
|
||||
import { PumpMessagesToConsole } from './test-utility';
|
||||
import { AutoRest } from '../exports';
|
||||
import { RealFileSystem } from '@azure-tools/datastore';
|
||||
import { join } from 'path';
|
||||
|
||||
@suite class Modifiers {
|
||||
import { PumpMessagesToConsole } from "./test-utility";
|
||||
import { AutoRest } from "../exports";
|
||||
import { RealFileSystem } from "@azure-tools/datastore";
|
||||
import { join } from "path";
|
||||
|
||||
@suite
|
||||
class Modifiers {
|
||||
private async generate(additionalConfig: any): Promise<{ [uri: string]: string }> {
|
||||
const autoRest = new AutoRest(new RealFileSystem());
|
||||
autoRest.AddConfiguration({
|
||||
'input-file': join(__dirname, '..', '..', 'test', 'resources', 'tiny.yaml'),
|
||||
'csharp': 'true',
|
||||
'output-artifact': ['swagger-document.yaml', 'openapi-document.yaml']
|
||||
"input-file": join(__dirname, "..", "..", "test", "resources", "tiny.yaml"),
|
||||
"csharp": "true",
|
||||
"output-artifact": ["swagger-document.yaml", "openapi-document.yaml"],
|
||||
});
|
||||
// for testing local changes:
|
||||
/* if (false as any) {
|
||||
|
@ -31,10 +31,10 @@ import { join } from 'path';
|
|||
const result: { [uri: string]: string } = {};
|
||||
|
||||
autoRest.GeneratedFile.Subscribe((sender, args) => {
|
||||
if (args.type === 'source-file-csharp') {
|
||||
result[args.uri.slice('file:///generated/'.length)] = args.content;
|
||||
if (args.type === "source-file-csharp") {
|
||||
result[args.uri.slice("file:///generated/".length)] = args.content;
|
||||
}
|
||||
if (args.type === 'swagger-document.yaml' || args.type === 'openapi-document.yaml') {
|
||||
if (args.type === "swagger-document.yaml" || args.type === "openapi-document.yaml") {
|
||||
// console.warn(args.content);
|
||||
}
|
||||
});
|
||||
|
@ -44,174 +44,174 @@ import { join } from 'path';
|
|||
return result;
|
||||
}
|
||||
|
||||
@test async 'Reference'() {
|
||||
@test async Reference() {
|
||||
const code = await this.generate({});
|
||||
assert.ok(code['CowbellOperationsExtensions.cs'].includes(' Get('));
|
||||
assert.ok(!code['CowbellOperationsExtensions.cs'].includes(' Retrieve('));
|
||||
assert.ok(!code['CowbellOperations.cs'].includes('.GetWith'));
|
||||
assert.ok(code['Models/Cowbell.cs']);
|
||||
assert.ok(code['Models/Cowbell.cs'].includes('string Name'));
|
||||
assert.ok(!code['Models/Cowbell.cs'].includes('string FirstName'));
|
||||
assert.ok(code['Models/Cowbell.cs'].includes('JsonProperty'));
|
||||
assert.ok(!code['Models/Cowbell.cs'].includes('JsonIgnore'));
|
||||
assert.ok(!code['Models/SuperCowbell.cs']);
|
||||
assert.ok(code["CowbellOperationsExtensions.cs"].includes(" Get("));
|
||||
assert.ok(!code["CowbellOperationsExtensions.cs"].includes(" Retrieve("));
|
||||
assert.ok(!code["CowbellOperations.cs"].includes(".GetWith"));
|
||||
assert.ok(code["Models/Cowbell.cs"]);
|
||||
assert.ok(code["Models/Cowbell.cs"].includes("string Name"));
|
||||
assert.ok(!code["Models/Cowbell.cs"].includes("string FirstName"));
|
||||
assert.ok(code["Models/Cowbell.cs"].includes("JsonProperty"));
|
||||
assert.ok(!code["Models/Cowbell.cs"].includes("JsonIgnore"));
|
||||
assert.ok(!code["Models/SuperCowbell.cs"]);
|
||||
}
|
||||
|
||||
@test async 'RemoveOperation'() {
|
||||
@test async RemoveOperation() {
|
||||
const code = await this.generate({
|
||||
'directive': {
|
||||
'remove-operation': 'Cowbell_Get'
|
||||
}
|
||||
directive: {
|
||||
"remove-operation": "Cowbell_Get",
|
||||
},
|
||||
});
|
||||
assert.ok(!code['CowbellOperationsExtensions.cs'].includes(' Get('));
|
||||
assert.ok(!code['CowbellOperationsExtensions.cs'].includes(' Retrieve('));
|
||||
assert.ok(!code["CowbellOperationsExtensions.cs"].includes(" Get("));
|
||||
assert.ok(!code["CowbellOperationsExtensions.cs"].includes(" Retrieve("));
|
||||
}
|
||||
|
||||
@test async 'RenameOperation'() {
|
||||
@test async RenameOperation() {
|
||||
const code = await this.generate({
|
||||
'directive': {
|
||||
'rename-operation': {
|
||||
from: 'Cowbell_Get',
|
||||
to: 'Cowbell_Retrieve'
|
||||
}
|
||||
}
|
||||
directive: {
|
||||
"rename-operation": {
|
||||
from: "Cowbell_Get",
|
||||
to: "Cowbell_Retrieve",
|
||||
},
|
||||
},
|
||||
});
|
||||
assert.ok(!code['CowbellOperationsExtensions.cs'].includes(' Get('));
|
||||
assert.ok(code['CowbellOperationsExtensions.cs'].includes(' Retrieve('));
|
||||
assert.ok(!code["CowbellOperationsExtensions.cs"].includes(" Get("));
|
||||
assert.ok(code["CowbellOperationsExtensions.cs"].includes(" Retrieve("));
|
||||
}
|
||||
|
||||
@test async 'AddOperationForward'() {
|
||||
@test async AddOperationForward() {
|
||||
const code = await this.generate({
|
||||
'components': {
|
||||
'operations': [
|
||||
components: {
|
||||
operations: [
|
||||
{
|
||||
operationId: 'Cowbell_Retrieve',
|
||||
'forward-to': 'Cowbell_Get'
|
||||
}
|
||||
]
|
||||
}
|
||||
"operationId": "Cowbell_Retrieve",
|
||||
"forward-to": "Cowbell_Get",
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
assert.ok(code['CowbellOperationsExtensions.cs'].includes(' Get('));
|
||||
assert.ok(code['CowbellOperationsExtensions.cs'].includes(' Retrieve('));
|
||||
assert.ok(code['CowbellOperations.cs'].includes('.GetWith'));
|
||||
assert.ok(code["CowbellOperationsExtensions.cs"].includes(" Get("));
|
||||
assert.ok(code["CowbellOperationsExtensions.cs"].includes(" Retrieve("));
|
||||
assert.ok(code["CowbellOperations.cs"].includes(".GetWith"));
|
||||
}
|
||||
|
||||
@test async 'AddOperationImpl'() {
|
||||
const implementation = '// implement me ' + Math.random();
|
||||
@test async AddOperationImpl() {
|
||||
const implementation = "// implement me " + Math.random();
|
||||
const code = await this.generate({
|
||||
'components': {
|
||||
'operations': [
|
||||
components: {
|
||||
operations: [
|
||||
{
|
||||
operationId: 'Cowbell_Retrieve',
|
||||
'implementation': implementation
|
||||
}
|
||||
]
|
||||
}
|
||||
operationId: "Cowbell_Retrieve",
|
||||
implementation: implementation,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
assert.ok(code['CowbellOperationsExtensions.cs'].includes(' Get('));
|
||||
assert.ok(code['CowbellOperationsExtensions.cs'].includes(' Retrieve('));
|
||||
assert.ok(!code['CowbellOperations.cs'].includes('.GetWith'));
|
||||
assert.ok(code['CowbellOperations.cs'].includes(implementation));
|
||||
assert.ok(code["CowbellOperationsExtensions.cs"].includes(" Get("));
|
||||
assert.ok(code["CowbellOperationsExtensions.cs"].includes(" Retrieve("));
|
||||
assert.ok(!code["CowbellOperations.cs"].includes(".GetWith"));
|
||||
assert.ok(code["CowbellOperations.cs"].includes(implementation));
|
||||
}
|
||||
|
||||
@test async 'RemoveModel'() {
|
||||
@test async RemoveModel() {
|
||||
const code = await this.generate({
|
||||
'directive': [
|
||||
{ 'remove-model': 'Cowbell' },
|
||||
{ 'remove-operation': 'Cowbell_Get' }, // ...or there will be
|
||||
{ 'remove-operation': 'Cowbell_Add' } // broken references
|
||||
]
|
||||
directive: [
|
||||
{ "remove-model": "Cowbell" },
|
||||
{ "remove-operation": "Cowbell_Get" }, // ...or there will be
|
||||
{ "remove-operation": "Cowbell_Add" }, // broken references
|
||||
],
|
||||
});
|
||||
assert.ok(!code['Models/Cowbell.cs']);
|
||||
assert.ok(!code['Models/SuperCowbell.cs']);
|
||||
assert.ok(!code["Models/Cowbell.cs"]);
|
||||
assert.ok(!code["Models/SuperCowbell.cs"]);
|
||||
}
|
||||
|
||||
@test async 'RenameModel'() {
|
||||
@test async RenameModel() {
|
||||
const code = await this.generate({
|
||||
'directive': {
|
||||
'rename-model': {
|
||||
from: 'Cowbell',
|
||||
to: 'SuperCowbell'
|
||||
}
|
||||
}
|
||||
directive: {
|
||||
"rename-model": {
|
||||
from: "Cowbell",
|
||||
to: "SuperCowbell",
|
||||
},
|
||||
},
|
||||
});
|
||||
assert.ok(!code['Models/Cowbell.cs']);
|
||||
assert.ok(code['Models/SuperCowbell.cs']);
|
||||
assert.ok(code['Models/SuperCowbell.cs'].includes('string Name'));
|
||||
assert.ok(!code["Models/Cowbell.cs"]);
|
||||
assert.ok(code["Models/SuperCowbell.cs"]);
|
||||
assert.ok(code["Models/SuperCowbell.cs"].includes("string Name"));
|
||||
}
|
||||
|
||||
@test async 'RemoveProperty'() {
|
||||
@test async RemoveProperty() {
|
||||
const code = await this.generate({
|
||||
'directive': {
|
||||
'where-model': 'Cowbell',
|
||||
'remove-property': 'name'
|
||||
}
|
||||
directive: {
|
||||
"where-model": "Cowbell",
|
||||
"remove-property": "name",
|
||||
},
|
||||
});
|
||||
assert.ok(code['Models/Cowbell.cs']);
|
||||
assert.ok(!code['Models/Cowbell.cs'].includes('string Name'));
|
||||
assert.ok(code["Models/Cowbell.cs"]);
|
||||
assert.ok(!code["Models/Cowbell.cs"].includes("string Name"));
|
||||
}
|
||||
|
||||
@test async 'RenameProperty'() {
|
||||
@test async RenameProperty() {
|
||||
const code = await this.generate({
|
||||
'directive': {
|
||||
'where-model': 'Cowbell',
|
||||
'rename-property': {
|
||||
from: 'name',
|
||||
to: 'firstName'
|
||||
}
|
||||
}
|
||||
directive: {
|
||||
"where-model": "Cowbell",
|
||||
"rename-property": {
|
||||
from: "name",
|
||||
to: "firstName",
|
||||
},
|
||||
},
|
||||
});
|
||||
assert.ok(code['Models/Cowbell.cs']);
|
||||
assert.ok(!code['Models/Cowbell.cs'].includes('string Name'));
|
||||
assert.ok(code['Models/Cowbell.cs'].includes('string FirstName'));
|
||||
assert.ok(code["Models/Cowbell.cs"]);
|
||||
assert.ok(!code["Models/Cowbell.cs"].includes("string Name"));
|
||||
assert.ok(code["Models/Cowbell.cs"].includes("string FirstName"));
|
||||
}
|
||||
|
||||
// GS01 / Nelson -- this fails because the deduplicator assumes that we have xms metadata on paths
|
||||
/* @test */ async 'AddPropertyForward'() {
|
||||
// GS01 / Nelson -- this fails because the deduplicator assumes that we have xms metadata on paths
|
||||
/* @test */ async AddPropertyForward() {
|
||||
const code = await this.generate({
|
||||
'components': {
|
||||
'schemas': {
|
||||
'Cowbell': {
|
||||
'properties': {
|
||||
'firstName': {
|
||||
'type': 'string',
|
||||
'forward-to': 'name'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
components: {
|
||||
schemas: {
|
||||
Cowbell: {
|
||||
properties: {
|
||||
firstName: {
|
||||
"type": "string",
|
||||
"forward-to": "name",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
assert.ok(code['Models/Cowbell.cs']);
|
||||
assert.ok(code['Models/Cowbell.cs'].includes('string Name'));
|
||||
assert.ok(code['Models/Cowbell.cs'].includes('string FirstName'));
|
||||
assert.ok(code['Models/Cowbell.cs'].includes('= value;'));
|
||||
assert.ok(code['Models/Cowbell.cs'].includes('JsonProperty'));
|
||||
assert.ok(code['Models/Cowbell.cs'].includes('JsonIgnore'));
|
||||
assert.ok(code["Models/Cowbell.cs"]);
|
||||
assert.ok(code["Models/Cowbell.cs"].includes("string Name"));
|
||||
assert.ok(code["Models/Cowbell.cs"].includes("string FirstName"));
|
||||
assert.ok(code["Models/Cowbell.cs"].includes("= value;"));
|
||||
assert.ok(code["Models/Cowbell.cs"].includes("JsonProperty"));
|
||||
assert.ok(code["Models/Cowbell.cs"].includes("JsonIgnore"));
|
||||
}
|
||||
|
||||
// GS01 / Nelson -- this fails because the deduplicator assumes that we have xms metadata on paths
|
||||
/* @test */ async 'AddPropertyImpl'() {
|
||||
const implementation = 'get; set; // implement me ' + Math.random();
|
||||
// GS01 / Nelson -- this fails because the deduplicator assumes that we have xms metadata on paths
|
||||
/* @test */ async AddPropertyImpl() {
|
||||
const implementation = "get; set; // implement me " + Math.random();
|
||||
const code = await this.generate({
|
||||
'components': {
|
||||
'schemas': {
|
||||
'Cowbell': {
|
||||
'properties': {
|
||||
'firstName': {
|
||||
'type': 'string',
|
||||
'implementation': implementation
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
components: {
|
||||
schemas: {
|
||||
Cowbell: {
|
||||
properties: {
|
||||
firstName: {
|
||||
type: "string",
|
||||
implementation: implementation,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
assert.ok(code['Models/Cowbell.cs']);
|
||||
assert.ok(code['Models/Cowbell.cs'].includes('string Name'));
|
||||
assert.ok(code['Models/Cowbell.cs'].includes('string FirstName'));
|
||||
assert.ok(code['Models/Cowbell.cs'].includes(implementation));
|
||||
assert.ok(code['Models/Cowbell.cs'].includes('JsonProperty'));
|
||||
assert.ok(code['Models/Cowbell.cs'].includes('JsonIgnore'));
|
||||
assert.ok(code["Models/Cowbell.cs"]);
|
||||
assert.ok(code["Models/Cowbell.cs"].includes("string Name"));
|
||||
assert.ok(code["Models/Cowbell.cs"].includes("string FirstName"));
|
||||
assert.ok(code["Models/Cowbell.cs"].includes(implementation));
|
||||
assert.ok(code["Models/Cowbell.cs"].includes("JsonProperty"));
|
||||
assert.ok(code["Models/Cowbell.cs"].includes("JsonIgnore"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,24 +2,23 @@
|
|||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { CancellationToken } from 'vscode-jsonrpc';
|
||||
import * as assert from 'assert';
|
||||
import { only, skip, slow, suite, test, timeout } from 'mocha-typescript';
|
||||
import { DataStore } from '@azure-tools/datastore';
|
||||
import { manipulateObject } from '../lib/pipeline/object-manipulator';
|
||||
import { createSandbox } from '@azure-tools/datastore';
|
||||
import { CancellationToken } from "vscode-jsonrpc";
|
||||
import * as assert from "assert";
|
||||
import { only, skip, slow, suite, test, timeout } from "mocha-typescript";
|
||||
import { DataStore } from "@azure-tools/datastore";
|
||||
import { manipulateObject } from "../lib/pipeline/object-manipulator";
|
||||
import { createSandbox } from "@azure-tools/datastore";
|
||||
|
||||
const safeEval = createSandbox();
|
||||
try {
|
||||
require('source-map-support').install();
|
||||
require("source-map-support").install();
|
||||
} catch {
|
||||
// no worries
|
||||
}
|
||||
|
||||
|
||||
@suite class ObjectManipulator {
|
||||
|
||||
private exampleObject = `
|
||||
@suite
|
||||
class ObjectManipulator {
|
||||
private "exampleObject" = `
|
||||
host: localhost:27332
|
||||
paths:
|
||||
"/api/circular":
|
||||
|
@ -46,61 +45,74 @@ definitions:
|
|||
child:
|
||||
"$ref": "#/definitions/NodeB"`;
|
||||
|
||||
@test async 'any hit'() {
|
||||
@test async "any hit"() {
|
||||
// setup
|
||||
const dataStore = new DataStore(CancellationToken.None);
|
||||
const input = await dataStore.WriteData('mem://input.yaml', this.exampleObject, 'input-file', ['input.yaml']);
|
||||
const input = await dataStore.WriteData("mem://input.yaml", this.exampleObject, "input-file", ["input.yaml"]);
|
||||
|
||||
const expectHit = async (jsonQuery: string, anyHit: boolean) => {
|
||||
const result = await manipulateObject(input, dataStore.getDataSink(), jsonQuery, (_, x) => x);
|
||||
assert.strictEqual(result.anyHit, anyHit, jsonQuery);
|
||||
};
|
||||
|
||||
await expectHit('$..put', false);
|
||||
await expectHit('$..post', true);
|
||||
await expectHit('$..get', true);
|
||||
await expectHit('$.parameters', false);
|
||||
await expectHit('$.definitions', true);
|
||||
await expectHit('$..summary', false);
|
||||
await expectHit('$..description', true);
|
||||
await expectHit('$.definitions[?(@.summary)]', false);
|
||||
await expectHit('$.definitions[?(@.description)]', true);
|
||||
await expectHit("$..put", false);
|
||||
await expectHit("$..post", true);
|
||||
await expectHit("$..get", true);
|
||||
await expectHit("$.parameters", false);
|
||||
await expectHit("$.definitions", true);
|
||||
await expectHit("$..summary", false);
|
||||
await expectHit("$..description", true);
|
||||
await expectHit("$.definitions[?(@.summary)]", false);
|
||||
await expectHit("$.definitions[?(@.description)]", true);
|
||||
await expectHit('$.definitions[?(@.description=="Descriptio")]', false);
|
||||
await expectHit('$.definitions[?(@.description=="Description")]', true);
|
||||
await expectHit('$..[?(@.description=="Descriptio")]', false);
|
||||
await expectHit('$..[?(@.description=="Description")]', true);
|
||||
}
|
||||
|
||||
@test async 'removal'() {
|
||||
@test async "removal"() {
|
||||
// setup
|
||||
const dataStore = new DataStore(CancellationToken.None);
|
||||
const input = await dataStore.WriteData('mem://input.yaml', this.exampleObject, 'input-file', ['input.yaml']);
|
||||
const input = await dataStore.WriteData("mem://input.yaml", this.exampleObject, "input-file", ["input.yaml"]);
|
||||
|
||||
// remove all models that don't have a description
|
||||
const result = await manipulateObject(input, dataStore.getDataSink(), '$.definitions[?(!@.description)]', (_, x) => undefined);
|
||||
const result = await manipulateObject(
|
||||
input,
|
||||
dataStore.getDataSink(),
|
||||
"$.definitions[?(!@.description)]",
|
||||
(_, x) => undefined,
|
||||
);
|
||||
assert.strictEqual(result.anyHit, true);
|
||||
const resultRaw = await result.result.ReadData();
|
||||
assert.ok(resultRaw.indexOf('NodeA') !== -1);
|
||||
assert.ok(resultRaw.indexOf('NodeB') === -1);
|
||||
assert.ok(resultRaw.indexOf("NodeA") !== -1);
|
||||
assert.ok(resultRaw.indexOf("NodeB") === -1);
|
||||
}
|
||||
|
||||
@test async 'update'() {
|
||||
@test async "update"() {
|
||||
// setup
|
||||
const dataStore = new DataStore(CancellationToken.None);
|
||||
const input = await dataStore.WriteData('mem://input.yaml', this.exampleObject, 'input-file', ['input.yaml']);
|
||||
const input = await dataStore.WriteData("mem://input.yaml", this.exampleObject, "input-file", ["input.yaml"]);
|
||||
|
||||
{
|
||||
// override all existing model descriptions
|
||||
const bestDescriptionEver = 'best description ever';
|
||||
const result = await manipulateObject(input, dataStore.getDataSink(), '$.definitions.*.description', (_, x) => bestDescriptionEver);
|
||||
const bestDescriptionEver = "best description ever";
|
||||
const result = await manipulateObject(
|
||||
input,
|
||||
dataStore.getDataSink(),
|
||||
"$.definitions.*.description",
|
||||
(_, x) => bestDescriptionEver,
|
||||
);
|
||||
assert.strictEqual(result.anyHit, true);
|
||||
const resultObject = await result.result.ReadObject<any>();
|
||||
assert.strictEqual(resultObject.definitions.NodeA.description, bestDescriptionEver);
|
||||
}
|
||||
{
|
||||
// override & insert all model descriptions
|
||||
const bestDescriptionEver = 'best description ever';
|
||||
const result = await manipulateObject(input, dataStore.getDataSink(), '$.definitions.*', (_, x) => { x.description = bestDescriptionEver; return x; });
|
||||
const bestDescriptionEver = "best description ever";
|
||||
const result = await manipulateObject(input, dataStore.getDataSink(), "$.definitions.*", (_, x) => {
|
||||
x.description = bestDescriptionEver;
|
||||
return x;
|
||||
});
|
||||
assert.strictEqual(result.anyHit, true);
|
||||
const resultObject = await result.result.ReadObject<any>();
|
||||
assert.strictEqual(resultObject.definitions.NodeA.description, bestDescriptionEver);
|
||||
|
@ -108,35 +120,39 @@ definitions:
|
|||
}
|
||||
{
|
||||
// make all descriptions upper case
|
||||
const bestDescriptionEver = 'best description ever';
|
||||
const result = await manipulateObject(input, dataStore.getDataSink(), '$..description', (_, x) => (<string>x).toUpperCase());
|
||||
const bestDescriptionEver = "best description ever";
|
||||
const result = await manipulateObject(input, dataStore.getDataSink(), "$..description", (_, x) =>
|
||||
(<string>x).toUpperCase(),
|
||||
);
|
||||
assert.strictEqual(result.anyHit, true);
|
||||
const resultObject = await result.result.ReadObject<any>();
|
||||
assert.strictEqual(resultObject.definitions.NodeA.description, 'DESCRIPTION');
|
||||
assert.strictEqual(resultObject.paths['/api/circular'].get.description, 'FUN TIME');
|
||||
assert.strictEqual(resultObject.definitions.NodeA.description, "DESCRIPTION");
|
||||
assert.strictEqual(resultObject.paths["/api/circular"].get.description, "FUN TIME");
|
||||
}
|
||||
{
|
||||
// make all descriptions upper case by using safe-eval
|
||||
const bestDescriptionEver = 'best description ever';
|
||||
const result = await manipulateObject(input, dataStore.getDataSink(), '$..description', (_, x) => safeEval('$.toUpperCase()', { $: x }));
|
||||
const bestDescriptionEver = "best description ever";
|
||||
const result = await manipulateObject(input, dataStore.getDataSink(), "$..description", (_, x) =>
|
||||
safeEval("$.toUpperCase()", { $: x }),
|
||||
);
|
||||
assert.strictEqual(result.anyHit, true);
|
||||
const resultObject = await result.result.ReadObject<any>();
|
||||
assert.strictEqual(resultObject.definitions.NodeA.description, 'DESCRIPTION');
|
||||
assert.strictEqual(resultObject.paths['/api/circular'].get.description, 'FUN TIME');
|
||||
assert.strictEqual(resultObject.definitions.NodeA.description, "DESCRIPTION");
|
||||
assert.strictEqual(resultObject.paths["/api/circular"].get.description, "FUN TIME");
|
||||
}
|
||||
}
|
||||
|
||||
@test async 'skip-transform-failure'() {
|
||||
@test async "skip-transform-failure"() {
|
||||
// setup
|
||||
const dataStore = new DataStore(CancellationToken.None);
|
||||
const input = await dataStore.WriteData('mem://input.yaml', this.exampleObject, 'input-file', ['input.yaml']);
|
||||
const input = await dataStore.WriteData("mem://input.yaml", this.exampleObject, "input-file", ["input.yaml"]);
|
||||
|
||||
{
|
||||
// the first override should fail but the second should be still executed
|
||||
const bestDescriptionEver = 'best description ever';
|
||||
let firstRun = true
|
||||
const bestDescriptionEver = "best description ever";
|
||||
let firstRun = true;
|
||||
|
||||
const result = await manipulateObject(input, dataStore.getDataSink(), '$.paths.*.*', (_, x) => {
|
||||
const result = await manipulateObject(input, dataStore.getDataSink(), "$.paths.*.*", (_, x) => {
|
||||
if (firstRun) {
|
||||
firstRun = false;
|
||||
throw Error("This error should have been suppressed in the manipulateObject(...).");
|
||||
|
@ -148,8 +164,8 @@ definitions:
|
|||
|
||||
assert.strictEqual(result.anyHit, true);
|
||||
const resultObject = await result.result.ReadObject<any>();
|
||||
assert.strictEqual(resultObject.paths['/api/circular'].get.description, "fun time");
|
||||
assert.strictEqual(resultObject.paths['/api/circular'].post.description, bestDescriptionEver);
|
||||
assert.strictEqual(resultObject.paths["/api/circular"].get.description, "fun time");
|
||||
assert.strictEqual(resultObject.paths["/api/circular"].post.description, bestDescriptionEver);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,17 +3,17 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ParseNode, ParseToAst, Stringify, StringifyAst, ToAst } from '@azure-tools/datastore';
|
||||
import { ConvertJsonx2Yaml, ConvertYaml2Jsonx } from '@azure-tools/datastore';
|
||||
import { suite, test, slow, timeout, skip, only } from 'mocha-typescript';
|
||||
import * as assert from 'assert';
|
||||
import { ParseNode, ParseToAst, Stringify, StringifyAst, ToAst } from "@azure-tools/datastore";
|
||||
import { ConvertJsonx2Yaml, ConvertYaml2Jsonx } from "@azure-tools/datastore";
|
||||
import { suite, test, slow, timeout, skip, only } from "mocha-typescript";
|
||||
import * as assert from "assert";
|
||||
|
||||
@suite class ObjectRepresentation {
|
||||
|
||||
@test async 'round trip'() {
|
||||
@suite
|
||||
class ObjectRepresentation {
|
||||
@test async "round trip"() {
|
||||
const o: any = {};
|
||||
o.a = 3;
|
||||
o.b = [1, 'a'];
|
||||
o.b = [1, "a"];
|
||||
o.c = o;
|
||||
o.d = { x: [o] };
|
||||
o.e = o.d;
|
||||
|
@ -27,5 +27,4 @@ import * as assert from 'assert';
|
|||
|
||||
assert.equal(yaml2, yaml1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import * as assert from 'assert';
|
||||
import { suite, test } from 'mocha-typescript';
|
||||
import * as assert from "assert";
|
||||
import { suite, test } from "mocha-typescript";
|
||||
|
||||
import { AutoRest } from '../lib/autorest-core';
|
||||
import { RealFileSystem } from '@azure-tools/datastore';
|
||||
import { LoadLiterateOpenAPIs } from '../lib/pipeline/plugins/loaders';
|
||||
import { CreateFolderUri, ResolveUri } from '@azure-tools/uri';
|
||||
import { AutoRest } from "../lib/autorest-core";
|
||||
import { RealFileSystem } from "@azure-tools/datastore";
|
||||
import { LoadLiterateOpenAPIs } from "../lib/pipeline/plugins/loaders";
|
||||
import { CreateFolderUri, ResolveUri } from "@azure-tools/uri";
|
||||
|
||||
@suite class OpenAPI3Loading {
|
||||
|
||||
@test async 'No input files provided'() {
|
||||
@suite
|
||||
class OpenAPI3Loading {
|
||||
@test async "No input files provided"() {
|
||||
const autoRest = new AutoRest();
|
||||
const config = await autoRest.view;
|
||||
const dataStore = config.DataStore;
|
||||
|
@ -19,64 +19,64 @@ import { CreateFolderUri, ResolveUri } from '@azure-tools/uri';
|
|||
config,
|
||||
dataStore.GetReadThroughScope(new RealFileSystem()),
|
||||
inputFilesUris,
|
||||
dataStore.getDataSink());
|
||||
dataStore.getDataSink(),
|
||||
);
|
||||
|
||||
assert.strictEqual(OpenAPIFilesLoaded.length, 0);
|
||||
|
||||
}
|
||||
|
||||
@test async 'All input files have a 3.*.* version.'() {
|
||||
@test async "All input files have a 3.*.* version."() {
|
||||
const autoRest = new AutoRest();
|
||||
const config = await autoRest.view;
|
||||
const dataStore = config.DataStore;
|
||||
|
||||
const inputFilesUris = [
|
||||
ResolveUri(CreateFolderUri(__dirname), '../../test/resources/openapi3-loading/oa3-file1.yaml'),
|
||||
ResolveUri(CreateFolderUri(__dirname), '../../test/resources/openapi3-loading/oa3-file2.yaml')
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/openapi3-loading/oa3-file1.yaml"),
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/openapi3-loading/oa3-file2.yaml"),
|
||||
];
|
||||
|
||||
const OpenAPIFilesLoaded = await LoadLiterateOpenAPIs(
|
||||
config,
|
||||
dataStore.GetReadThroughScope(new RealFileSystem()),
|
||||
inputFilesUris,
|
||||
dataStore.getDataSink());
|
||||
dataStore.getDataSink(),
|
||||
);
|
||||
|
||||
assert.strictEqual(OpenAPIFilesLoaded.length, inputFilesUris.length);
|
||||
|
||||
}
|
||||
|
||||
@test async 'All input files do not have a 3.*.* version.'() {
|
||||
@test async "All input files do not have a 3.*.* version."() {
|
||||
const autoRest = new AutoRest();
|
||||
const config = await autoRest.view;
|
||||
const dataStore = config.DataStore;
|
||||
|
||||
const inputFilesUris = [
|
||||
ResolveUri(CreateFolderUri(__dirname), '../../test/resources/openapi3-loading/non-oa3-file1.yaml'),
|
||||
ResolveUri(CreateFolderUri(__dirname), '../../test/resources/openapi3-loading/non-oa3-file2.yaml')
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/openapi3-loading/non-oa3-file1.yaml"),
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/openapi3-loading/non-oa3-file2.yaml"),
|
||||
];
|
||||
|
||||
const OpenAPIFilesLoaded = await LoadLiterateOpenAPIs(
|
||||
config,
|
||||
dataStore.GetReadThroughScope(new RealFileSystem()),
|
||||
inputFilesUris,
|
||||
dataStore.getDataSink());
|
||||
dataStore.getDataSink(),
|
||||
);
|
||||
|
||||
assert.strictEqual(OpenAPIFilesLoaded.length, 0);
|
||||
|
||||
}
|
||||
|
||||
@test async 'Some input files have a 3.*.* version and some input files do not have a 3.*.* version.'() {
|
||||
@test async "Some input files have a 3.*.* version and some input files do not have a 3.*.* version."() {
|
||||
const autoRest = new AutoRest();
|
||||
const config = await autoRest.view;
|
||||
const dataStore = config.DataStore;
|
||||
|
||||
const nonOpenAPIFileUris = [
|
||||
ResolveUri(CreateFolderUri(__dirname), '../../test/resources/openapi3-loading/non-oa3-file1.yaml'),
|
||||
ResolveUri(CreateFolderUri(__dirname), '../../test/resources/openapi3-loading/non-oa3-file2.yaml')
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/openapi3-loading/non-oa3-file1.yaml"),
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/openapi3-loading/non-oa3-file2.yaml"),
|
||||
];
|
||||
|
||||
const openAPIFileUris = [
|
||||
ResolveUri(CreateFolderUri(__dirname), '../../test/resources/openapi3-loading/oa3-file2.yaml')
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/openapi3-loading/oa3-file2.yaml"),
|
||||
];
|
||||
|
||||
const inputFilesUris = [...openAPIFileUris, ...nonOpenAPIFileUris];
|
||||
|
@ -85,7 +85,8 @@ import { CreateFolderUri, ResolveUri } from '@azure-tools/uri';
|
|||
config,
|
||||
dataStore.GetReadThroughScope(new RealFileSystem()),
|
||||
inputFilesUris,
|
||||
dataStore.getDataSink());
|
||||
dataStore.getDataSink(),
|
||||
);
|
||||
|
||||
assert.strictEqual(OpenAPIFilesLoaded.length, inputFilesUris.length - nonOpenAPIFileUris.length);
|
||||
}
|
||||
|
|
|
@ -3,38 +3,42 @@
|
|||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import { only, skip, slow, suite, test, timeout } from 'mocha-typescript';
|
||||
import { PumpMessagesToConsole } from './test-utility';
|
||||
import * as assert from "assert";
|
||||
import { only, skip, slow, suite, test, timeout } from "mocha-typescript";
|
||||
import { PumpMessagesToConsole } from "./test-utility";
|
||||
|
||||
import { DataHandle, DataStore, QuickDataSource, RealFileSystem } from '@azure-tools/datastore';
|
||||
import { Extension, ExtensionManager } from '@azure-tools/extension';
|
||||
import { CreateFolderUri, ResolveUri } from '@azure-tools/uri';
|
||||
import { homedir } from 'os';
|
||||
import { join } from 'path';
|
||||
import { CancellationToken } from 'vscode-jsonrpc';
|
||||
import { AutoRest } from '../lib/autorest-core';
|
||||
import { Channel, Message } from '../lib/message';
|
||||
import { AutoRestExtension } from '../lib/pipeline/plugin-endpoint';
|
||||
import { LoadLiterateSwagger } from '../lib/pipeline/plugins/loaders';
|
||||
import { DataHandle, DataStore, QuickDataSource, RealFileSystem } from "@azure-tools/datastore";
|
||||
import { Extension, ExtensionManager } from "@azure-tools/extension";
|
||||
import { CreateFolderUri, ResolveUri } from "@azure-tools/uri";
|
||||
import { homedir } from "os";
|
||||
import { join } from "path";
|
||||
import { CancellationToken } from "vscode-jsonrpc";
|
||||
import { AutoRest } from "../lib/autorest-core";
|
||||
import { Channel, Message } from "../lib/message";
|
||||
import { AutoRestExtension } from "../lib/pipeline/plugin-endpoint";
|
||||
import { LoadLiterateSwagger } from "../lib/pipeline/plugins/loaders";
|
||||
|
||||
async function GetAutoRestDotNetPlugin(plugin: string): Promise<AutoRestExtension> {
|
||||
const extMgr = await ExtensionManager.Create(join(homedir(), '.autorest'));
|
||||
const name = '@azure-tools/' + plugin;
|
||||
const source = '*';
|
||||
const extMgr = await ExtensionManager.Create(join(homedir(), ".autorest"));
|
||||
const name = "@azure-tools/" + plugin;
|
||||
const source = "*";
|
||||
const pack = await extMgr.findPackage(name, source);
|
||||
const ext = await extMgr.installPackage(pack);
|
||||
return AutoRestExtension.FromChildProcess(name, await ext.start());
|
||||
}
|
||||
|
||||
@suite export class Plugins {
|
||||
@suite
|
||||
export class Plugins {
|
||||
// TODO: remodel if we figure out acquisition story
|
||||
@test @skip async 'Validation Tools'() {
|
||||
@test @skip async "Validation Tools"() {
|
||||
const autoRest = new AutoRest(new RealFileSystem());
|
||||
autoRest.AddConfiguration({ 'input-file': 'https://github.com/olydis/azure-rest-api-specs/blob/amar-tests/arm-logic/2016-06-01/swagger/logic.json' });
|
||||
autoRest.AddConfiguration({ 'model-validator': true });
|
||||
autoRest.AddConfiguration({ 'semantic-validator': true });
|
||||
autoRest.AddConfiguration({ 'azure-validator': true });
|
||||
autoRest.AddConfiguration({
|
||||
"input-file":
|
||||
"https://github.com/olydis/azure-rest-api-specs/blob/amar-tests/arm-logic/2016-06-01/swagger/logic.json",
|
||||
});
|
||||
autoRest.AddConfiguration({ "model-validator": true });
|
||||
autoRest.AddConfiguration({ "semantic-validator": true });
|
||||
autoRest.AddConfiguration({ "azure-validator": true });
|
||||
|
||||
const errorMessages: Array<Message> = [];
|
||||
autoRest.Message.Subscribe((_, m) => {
|
||||
|
@ -50,22 +54,34 @@ async function GetAutoRestDotNetPlugin(plugin: string): Promise<AutoRestExtensio
|
|||
assert.strictEqual(errorMessages.length, expectedNumErrors);
|
||||
}
|
||||
|
||||
@test @skip async 'AutoRest.dll Modeler'() {
|
||||
@test @skip async "AutoRest.dll Modeler"() {
|
||||
const autoRest = new AutoRest();
|
||||
const config = await autoRest.view;
|
||||
const dataStore = config.DataStore;
|
||||
|
||||
// load swagger
|
||||
const swagger = <DataHandle>await LoadLiterateSwagger(
|
||||
config,
|
||||
dataStore.GetReadThroughScope(new RealFileSystem()),
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/fa91f9109c1e9107bb92027924ec2983b067f5ec/arm-network/2016-12-01/swagger/network.json',
|
||||
dataStore.getDataSink());
|
||||
const swagger = <DataHandle>(
|
||||
await LoadLiterateSwagger(
|
||||
config,
|
||||
dataStore.GetReadThroughScope(new RealFileSystem()),
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/fa91f9109c1e9107bb92027924ec2983b067f5ec/arm-network/2016-12-01/swagger/network.json",
|
||||
dataStore.getDataSink(),
|
||||
)
|
||||
);
|
||||
|
||||
// call modeler
|
||||
const autorestPlugin = await GetAutoRestDotNetPlugin('modeler');
|
||||
const autorestPlugin = await GetAutoRestDotNetPlugin("modeler");
|
||||
const results: Array<DataHandle> = [];
|
||||
const result = await autorestPlugin.Process('modeler', key => ({ namespace: 'SomeNamespace' } as any)[key], config, new QuickDataSource([swagger]), dataStore.getDataSink(), f => results.push(f), m => null, CancellationToken.None);
|
||||
const result = await autorestPlugin.Process(
|
||||
"modeler",
|
||||
(key) => (({ namespace: "SomeNamespace" } as any)[key]),
|
||||
config,
|
||||
new QuickDataSource([swagger]),
|
||||
dataStore.getDataSink(),
|
||||
(f) => results.push(f),
|
||||
(m) => null,
|
||||
CancellationToken.None,
|
||||
);
|
||||
assert.strictEqual(result, true);
|
||||
if (results.length !== 1) {
|
||||
throw new Error(`Modeler plugin produced '${results.length}' items. Only expected one (the code model).`);
|
||||
|
@ -73,56 +89,64 @@ async function GetAutoRestDotNetPlugin(plugin: string): Promise<AutoRestExtensio
|
|||
|
||||
// check results
|
||||
const codeModel = await results[0].ReadData();
|
||||
assert.notEqual(codeModel.indexOf('isConstant'), -1);
|
||||
assert.notEqual(codeModel.indexOf("isConstant"), -1);
|
||||
}
|
||||
|
||||
@test @skip async 'AutoRest.dll Generator'() {
|
||||
@test @skip async "AutoRest.dll Generator"() {
|
||||
const autoRest = new AutoRest(new RealFileSystem());
|
||||
autoRest.AddConfiguration({
|
||||
namespace: 'SomeNamespace',
|
||||
'license-header': null,
|
||||
'payload-flattening-threshold': 0,
|
||||
'add-credentials': false,
|
||||
'package-name': 'rubyrubyrubyruby'
|
||||
"namespace": "SomeNamespace",
|
||||
"license-header": null,
|
||||
"payload-flattening-threshold": 0,
|
||||
"add-credentials": false,
|
||||
"package-name": "rubyrubyrubyruby",
|
||||
});
|
||||
const config = await autoRest.view;
|
||||
const dataStore = new DataStore(CancellationToken.None);
|
||||
|
||||
// load swagger
|
||||
const swagger = <DataHandle>await LoadLiterateSwagger(
|
||||
config,
|
||||
dataStore.GetReadThroughScope(new RealFileSystem()),
|
||||
'https://github.com/Azure/azure-rest-api-specs/blob/fa91f9109c1e9107bb92027924ec2983b067f5ec/arm-network/2016-12-01/swagger/network.json',
|
||||
dataStore.getDataSink());
|
||||
const swagger = <DataHandle>(
|
||||
await LoadLiterateSwagger(
|
||||
config,
|
||||
dataStore.GetReadThroughScope(new RealFileSystem()),
|
||||
"https://github.com/Azure/azure-rest-api-specs/blob/fa91f9109c1e9107bb92027924ec2983b067f5ec/arm-network/2016-12-01/swagger/network.json",
|
||||
dataStore.getDataSink(),
|
||||
)
|
||||
);
|
||||
|
||||
// load code model
|
||||
const codeModelUri = ResolveUri(CreateFolderUri(__dirname), '../../test/resources/code-model.yaml');
|
||||
const codeModelUri = ResolveUri(CreateFolderUri(__dirname), "../../test/resources/code-model.yaml");
|
||||
const inputScope = dataStore.GetReadThroughScope(new RealFileSystem());
|
||||
const codeModelHandle = await inputScope.ReadStrict(codeModelUri);
|
||||
|
||||
// call generator
|
||||
const autorestPlugin = await GetAutoRestDotNetPlugin('csharp');
|
||||
const autorestPlugin = await GetAutoRestDotNetPlugin("csharp");
|
||||
const results: Array<DataHandle> = [];
|
||||
const result = await autorestPlugin.Process(
|
||||
'csharp',
|
||||
key => config.GetEntry(key as any),
|
||||
"csharp",
|
||||
(key) => config.GetEntry(key as any),
|
||||
config,
|
||||
new QuickDataSource([swagger, codeModelHandle]),
|
||||
dataStore.getDataSink(),
|
||||
f => results.push(f),
|
||||
m => { if (m.Channel === Channel.Fatal) { console.log(m.Text); } },
|
||||
CancellationToken.None);
|
||||
(f) => results.push(f),
|
||||
(m) => {
|
||||
if (m.Channel === Channel.Fatal) {
|
||||
console.log(m.Text);
|
||||
}
|
||||
},
|
||||
CancellationToken.None,
|
||||
);
|
||||
assert.strictEqual(result, true);
|
||||
|
||||
// check results
|
||||
assert.notEqual(results.length, 0);
|
||||
assert.notEqual(results.filter(file => file.Description.indexOf('Models/') !== -1).length, 0);
|
||||
assert.ok(results.every(file => file.Description.indexOf('.cs') !== -1));
|
||||
assert.notEqual(results.filter((file) => file.Description.indexOf("Models/") !== -1).length, 0);
|
||||
assert.ok(results.every((file) => file.Description.indexOf(".cs") !== -1));
|
||||
console.log(results);
|
||||
}
|
||||
|
||||
// SKIPPING because this is using a local path for now
|
||||
@test @skip async 'custom plugin module'() {
|
||||
@test @skip async "custom plugin module"() {
|
||||
/*
|
||||
const cancellationToken = CancellationToken.None;
|
||||
const dataStore = new DataStore(cancellationToken);
|
||||
|
|
|
@ -1,28 +1,40 @@
|
|||
import * as aio from '@azure-tools/async-io';
|
||||
import * as datastore from '@azure-tools/datastore';
|
||||
import * as assert from 'assert';
|
||||
import { suite, test, skip } from 'mocha-typescript';
|
||||
import { ProfileFilter } from '../lib/pipeline/plugins/profile-filter';
|
||||
import * as aio from "@azure-tools/async-io";
|
||||
import * as datastore from "@azure-tools/datastore";
|
||||
import * as assert from "assert";
|
||||
import { suite, test, skip } from "mocha-typescript";
|
||||
import { ProfileFilter } from "../lib/pipeline/plugins/profile-filter";
|
||||
|
||||
const resources = `${__dirname}../../../test/resources/profile-filter`;
|
||||
|
||||
@suite class ProfileFiltering {
|
||||
|
||||
// todo: fix test
|
||||
@test @skip async 'filter paths and schemas based on API version'() {
|
||||
const inputUri = 'mem://input1.json';
|
||||
const outputUri = 'mem://output1.json';
|
||||
const profilesUri = 'mem://profiles.yaml';
|
||||
const profilesToUse = ['2017-11-09-profile', '2018-01-01-hybrid'];
|
||||
@suite
|
||||
class ProfileFiltering {
|
||||
// todo: fix test
|
||||
@test @skip async "filter paths and schemas based on API version"() {
|
||||
const inputUri = "mem://input1.json";
|
||||
const outputUri = "mem://output1.json";
|
||||
const profilesUri = "mem://profiles.yaml";
|
||||
const profilesToUse = ["2017-11-09-profile", "2018-01-01-hybrid"];
|
||||
|
||||
const input = await aio.readFile(`${resources}/input1.json`);
|
||||
const output = await aio.readFile(`${resources}/output1.json`);
|
||||
const profiles = await aio.readFile(`${resources}/profiles.yaml`);
|
||||
|
||||
const map = new Map<string, string>([[inputUri, input], [outputUri, output], [profilesUri, profiles]]);
|
||||
const map = new Map<string, string>([
|
||||
[inputUri, input],
|
||||
[outputUri, output],
|
||||
[profilesUri, profiles],
|
||||
]);
|
||||
const mfs = new datastore.MemoryFileSystem(map);
|
||||
|
||||
const cts: datastore.CancellationTokenSource = { cancel() { /* unused */ }, dispose() {/* unused */ }, token: { isCancellationRequested: false, onCancellationRequested: <any>null } };
|
||||
const cts: datastore.CancellationTokenSource = {
|
||||
cancel() {
|
||||
/* unused */
|
||||
},
|
||||
dispose() {
|
||||
/* unused */
|
||||
},
|
||||
token: { isCancellationRequested: false, onCancellationRequested: <any>null },
|
||||
};
|
||||
const ds = new datastore.DataStore(cts.token);
|
||||
const scope = ds.GetReadThroughScope(mfs);
|
||||
const inputDataHandle = await scope.Read(inputUri);
|
||||
|
@ -37,7 +49,7 @@ const resources = `${__dirname}../../../test/resources/profile-filter`;
|
|||
const outputObject = await outputDataHandle.ReadObject();
|
||||
const processor = new ProfileFilter(inputDataHandle, await profilesDataHandle.ReadObject(), profilesToUse, []);
|
||||
const processorOutput = await processor.getOutput();
|
||||
assert.deepEqual(processorOutput, outputObject, 'Should be the same');
|
||||
assert.deepEqual(processorOutput, outputObject, "Should be the same");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,44 +1,65 @@
|
|||
import { RealFileSystem } from '@azure-tools/datastore';
|
||||
import { CreateFolderUri, ResolveUri } from '@azure-tools/uri';
|
||||
import * as assert from 'assert';
|
||||
import { suite, test, skip } from 'mocha-typescript';
|
||||
import { AutoRest } from '../lib/autorest-core';
|
||||
import { crawlReferences } from '../lib/pipeline/plugins/ref-crawling';
|
||||
|
||||
@suite class RefCrawling {
|
||||
|
||||
// todo: fix test
|
||||
@test @skip async 'Crawl files referenced, update references and mark secondary files.'() {
|
||||
import { RealFileSystem } from "@azure-tools/datastore";
|
||||
import { CreateFolderUri, ResolveUri } from "@azure-tools/uri";
|
||||
import * as assert from "assert";
|
||||
import { suite, test, skip } from "mocha-typescript";
|
||||
import { AutoRest } from "../lib/autorest-core";
|
||||
import { crawlReferences } from "../lib/pipeline/plugins/ref-crawling";
|
||||
|
||||
@suite
|
||||
class RefCrawling {
|
||||
// todo: fix test
|
||||
@test @skip async "Crawl files referenced, update references and mark secondary files."() {
|
||||
const autoRest = new AutoRest();
|
||||
const config = await autoRest.view;
|
||||
const dataStore = config.DataStore;
|
||||
const sink = dataStore.getDataSink();
|
||||
const scope = dataStore.GetReadThroughScope(new RealFileSystem());
|
||||
const file1DataHandle = await scope.ReadStrict('https://raw.githubusercontent.com/Azure/autorest/b39cc11e2577662c97a47511a08665fa6e4d712d/src/autorest-core/test/resources/ref-crawling/original-files/input-file1.yaml');
|
||||
const file2DataHandle = await scope.ReadStrict('https://raw.githubusercontent.com/Azure/autorest/b39cc11e2577662c97a47511a08665fa6e4d712d/src/autorest-core/test/resources/ref-crawling/original-files/input-file2.yaml');
|
||||
const file1DataHandle = await scope.ReadStrict(
|
||||
"https://raw.githubusercontent.com/Azure/autorest/b39cc11e2577662c97a47511a08665fa6e4d712d/src/autorest-core/test/resources/ref-crawling/original-files/input-file1.yaml",
|
||||
);
|
||||
const file2DataHandle = await scope.ReadStrict(
|
||||
"https://raw.githubusercontent.com/Azure/autorest/b39cc11e2577662c97a47511a08665fa6e4d712d/src/autorest-core/test/resources/ref-crawling/original-files/input-file2.yaml",
|
||||
);
|
||||
const files = [file1DataHandle, file2DataHandle];
|
||||
|
||||
const result = await crawlReferences(config, scope, files, sink);
|
||||
|
||||
const expectedFilesUris = [
|
||||
ResolveUri(CreateFolderUri(__dirname), '../../test/resources/ref-crawling/expected-modified-copies/input-file1.yaml'),
|
||||
ResolveUri(CreateFolderUri(__dirname), '../../test/resources/ref-crawling/expected-modified-copies/input-file2.yaml'),
|
||||
ResolveUri(CreateFolderUri(__dirname), '../../test/resources/ref-crawling/expected-modified-copies/petstore.yaml'),
|
||||
ResolveUri(CreateFolderUri(__dirname), '../../test/resources/ref-crawling/expected-modified-copies/examples/file-a.yaml'),
|
||||
ResolveUri(CreateFolderUri(__dirname), '../../test/resources/ref-crawling/expected-modified-copies/examples/file-b.yaml'),
|
||||
ResolveUri(CreateFolderUri(__dirname), '../../test/resources/ref-crawling/expected-modified-copies/examples/file-c.yaml'),
|
||||
ResolveUri(
|
||||
CreateFolderUri(__dirname),
|
||||
"../../test/resources/ref-crawling/expected-modified-copies/input-file1.yaml",
|
||||
),
|
||||
ResolveUri(
|
||||
CreateFolderUri(__dirname),
|
||||
"../../test/resources/ref-crawling/expected-modified-copies/input-file2.yaml",
|
||||
),
|
||||
ResolveUri(
|
||||
CreateFolderUri(__dirname),
|
||||
"../../test/resources/ref-crawling/expected-modified-copies/petstore.yaml",
|
||||
),
|
||||
ResolveUri(
|
||||
CreateFolderUri(__dirname),
|
||||
"../../test/resources/ref-crawling/expected-modified-copies/examples/file-a.yaml",
|
||||
),
|
||||
ResolveUri(
|
||||
CreateFolderUri(__dirname),
|
||||
"../../test/resources/ref-crawling/expected-modified-copies/examples/file-b.yaml",
|
||||
),
|
||||
ResolveUri(
|
||||
CreateFolderUri(__dirname),
|
||||
"../../test/resources/ref-crawling/expected-modified-copies/examples/file-c.yaml",
|
||||
),
|
||||
];
|
||||
|
||||
assert.strictEqual(result.length, expectedFilesUris.length);
|
||||
|
||||
for (const resultFile of result) {
|
||||
const resultFileName = resultFile.identity[0].split('/').pop();
|
||||
const resultFileName = resultFile.identity[0].split("/").pop();
|
||||
assert(resultFileName);
|
||||
const expectedFileUri = expectedFilesUris.find((element) => {
|
||||
return element.endsWith(resultFileName || '');
|
||||
return element.endsWith(resultFileName || "");
|
||||
});
|
||||
const expectedFileHandle = await scope.ReadStrict(expectedFileUri || '');
|
||||
const expectedFileHandle = await scope.ReadStrict(expectedFileUri || "");
|
||||
assert.deepStrictEqual(await resultFile.ReadObject(), await expectedFileHandle.ReadObject());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,26 +1,36 @@
|
|||
import * as aio from '@azure-tools/async-io';
|
||||
import * as datastore from '@azure-tools/datastore';
|
||||
import * as assert from 'assert';
|
||||
import { suite, test, skip } from 'mocha-typescript';
|
||||
import { ComponentKeyRenamer } from '../lib/pipeline/plugins/component-key-renamer';
|
||||
import * as aio from "@azure-tools/async-io";
|
||||
import * as datastore from "@azure-tools/datastore";
|
||||
import * as assert from "assert";
|
||||
import { suite, test, skip } from "mocha-typescript";
|
||||
import { ComponentKeyRenamer } from "../lib/pipeline/plugins/component-key-renamer";
|
||||
|
||||
const resources = `${__dirname}../../../test/resources/renamer`;
|
||||
|
||||
@suite class ComponentRenaming {
|
||||
|
||||
// todo: fix test
|
||||
@test @skip async 'Replace component keys for actual names.'() {
|
||||
|
||||
const inputUri = 'mem://input.json';
|
||||
const outputUri = 'mem://output.json';
|
||||
@suite
|
||||
class ComponentRenaming {
|
||||
// todo: fix test
|
||||
@test @skip async "Replace component keys for actual names."() {
|
||||
const inputUri = "mem://input.json";
|
||||
const outputUri = "mem://output.json";
|
||||
|
||||
const input = await aio.readFile(`${resources}/input.json`);
|
||||
const output = await aio.readFile(`${resources}/output.json`);
|
||||
|
||||
const map = new Map<string, string>([[inputUri, input], [outputUri, output]]);
|
||||
const map = new Map<string, string>([
|
||||
[inputUri, input],
|
||||
[outputUri, output],
|
||||
]);
|
||||
const mfs = new datastore.MemoryFileSystem(map);
|
||||
|
||||
const cts: datastore.CancellationTokenSource = { cancel() {/* unused */ }, dispose() {/* unused */ }, token: { isCancellationRequested: false, onCancellationRequested: <any>null } };
|
||||
const cts: datastore.CancellationTokenSource = {
|
||||
cancel() {
|
||||
/* unused */
|
||||
},
|
||||
dispose() {
|
||||
/* unused */
|
||||
},
|
||||
token: { isCancellationRequested: false, onCancellationRequested: <any>null },
|
||||
};
|
||||
const ds = new datastore.DataStore(cts.token);
|
||||
const scope = ds.GetReadThroughScope(mfs);
|
||||
const inputDataHandle = await scope.Read(inputUri);
|
||||
|
@ -34,7 +44,7 @@ const resources = `${__dirname}../../../test/resources/renamer`;
|
|||
const outputObject = await outputDataHandle.ReadObject();
|
||||
const renamer = new ComponentKeyRenamer(inputDataHandle);
|
||||
|
||||
assert.deepEqual(await renamer.getOutput(), outputObject, 'Should be the same');
|
||||
assert.deepEqual(await renamer.getOutput(), outputObject, "Should be the same");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,38 +3,48 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as aio from '@azure-tools/async-io';
|
||||
import * as datastore from '@azure-tools/datastore';
|
||||
import * as aio from "@azure-tools/async-io";
|
||||
import * as datastore from "@azure-tools/datastore";
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { only, skip, slow, suite, test, timeout } from 'mocha-typescript';
|
||||
import * as assert from "assert";
|
||||
import { only, skip, slow, suite, test, timeout } from "mocha-typescript";
|
||||
|
||||
import { OAI3Shaker } from '../lib/pipeline/plugins/tree-shaker';
|
||||
import { FastStringify } from '@azure-tools/datastore';
|
||||
import { OAI3Shaker } from "../lib/pipeline/plugins/tree-shaker";
|
||||
import { FastStringify } from "@azure-tools/datastore";
|
||||
|
||||
try {
|
||||
require('source-map-support').install();
|
||||
require("source-map-support").install();
|
||||
} catch {
|
||||
/* unused */
|
||||
}
|
||||
|
||||
const resources = `${__dirname}../../../test/resources/shaker`;
|
||||
|
||||
@suite class TestShaker {
|
||||
|
||||
// todo: fix test
|
||||
@test @skip async 'Test Shaker'() {
|
||||
|
||||
const inputUri = 'mem://input.yaml';
|
||||
const outputUri = 'mem://output.yaml';
|
||||
@suite
|
||||
class TestShaker {
|
||||
// todo: fix test
|
||||
@test @skip async "Test Shaker"() {
|
||||
const inputUri = "mem://input.yaml";
|
||||
const outputUri = "mem://output.yaml";
|
||||
|
||||
const input = await aio.readFile(`${resources}/input.yaml`);
|
||||
const output = await aio.readFile(`${resources}/output.yaml`);
|
||||
|
||||
const map = new Map<string, string>([[inputUri, input], [outputUri, output]]);
|
||||
const map = new Map<string, string>([
|
||||
[inputUri, input],
|
||||
[outputUri, output],
|
||||
]);
|
||||
const mfs = new datastore.MemoryFileSystem(map);
|
||||
|
||||
const cts: datastore.CancellationTokenSource = { cancel() {/* unused */ }, dispose() {/* unused */ }, token: { isCancellationRequested: false, onCancellationRequested: <any>null } };
|
||||
const cts: datastore.CancellationTokenSource = {
|
||||
cancel() {
|
||||
/* unused */
|
||||
},
|
||||
dispose() {
|
||||
/* unused */
|
||||
},
|
||||
token: { isCancellationRequested: false, onCancellationRequested: <any>null },
|
||||
};
|
||||
const ds = new datastore.DataStore(cts.token);
|
||||
const scope = ds.GetReadThroughScope(mfs);
|
||||
const inputDataHandle = await scope.Read(inputUri);
|
||||
|
@ -51,7 +61,7 @@ const resources = `${__dirname}../../../test/resources/shaker`;
|
|||
// testing: dump out the converted file
|
||||
// console.log(FastStringify(shaken));
|
||||
|
||||
assert.deepEqual(await shaker.getOutput(), outputObject, 'Should be the same');
|
||||
assert.deepEqual(await shaker.getOutput(), outputObject, "Should be the same");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,20 +2,21 @@
|
|||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { suite, test, slow, timeout, skip, only } from 'mocha-typescript';
|
||||
import * as assert from 'assert';
|
||||
import { suite, test, slow, timeout, skip, only } from "mocha-typescript";
|
||||
import * as assert from "assert";
|
||||
|
||||
import { NewEmptyObject } from '@azure-tools/datastore';
|
||||
import { NewEmptyObject } from "@azure-tools/datastore";
|
||||
|
||||
@suite class StableObject {
|
||||
@test async 'insert order preservation'() {
|
||||
@suite
|
||||
class StableObject {
|
||||
@test async "insert order preservation"() {
|
||||
const o = NewEmptyObject();
|
||||
o[3] = 0;
|
||||
o[1] = 1;
|
||||
o['asd'] = 2;
|
||||
o["asd"] = 2;
|
||||
o[2] = 3;
|
||||
o['zyx'] = 4;
|
||||
o['qwe'] = 5;
|
||||
o["zyx"] = 4;
|
||||
o["qwe"] = 5;
|
||||
o[-1] = 6;
|
||||
o[10] = 7;
|
||||
o[7] = 8;
|
||||
|
@ -26,24 +27,24 @@ import { NewEmptyObject } from '@azure-tools/datastore';
|
|||
}
|
||||
}
|
||||
|
||||
@test async 'mutation order preservation'() {
|
||||
@test async "mutation order preservation"() {
|
||||
const o = NewEmptyObject();
|
||||
o[8] = 'a';
|
||||
o[7] = 'a';
|
||||
o[6] = 'a';
|
||||
o[5] = 'a';
|
||||
o[4] = 'a';
|
||||
o[3] = 'a';
|
||||
o[2] = 'a';
|
||||
o[1] = 'a';
|
||||
o[0] = 'a';
|
||||
o[8] = "a";
|
||||
o[7] = "a";
|
||||
o[6] = "a";
|
||||
o[5] = "a";
|
||||
o[4] = "a";
|
||||
o[3] = "a";
|
||||
o[2] = "a";
|
||||
o[1] = "a";
|
||||
o[0] = "a";
|
||||
|
||||
o[4] = 'b';
|
||||
o[3] = 'b';
|
||||
o[2] = 'b';
|
||||
o[6] = 'b';
|
||||
o[3] = 'b';
|
||||
o[8] = 'b';
|
||||
o[4] = "b";
|
||||
o[3] = "b";
|
||||
o[2] = "b";
|
||||
o[6] = "b";
|
||||
o[3] = "b";
|
||||
o[8] = "b";
|
||||
|
||||
const keys = Object.getOwnPropertyNames(o);
|
||||
assert.strictEqual(keys.length, 9);
|
||||
|
@ -52,24 +53,24 @@ import { NewEmptyObject } from '@azure-tools/datastore';
|
|||
}
|
||||
}
|
||||
|
||||
@test async 'delete order preservation'() {
|
||||
@test async "delete order preservation"() {
|
||||
const o = NewEmptyObject();
|
||||
o[3] = 0;
|
||||
o[1] = 1;
|
||||
o['asd'] = 2;
|
||||
o['cowbell'] = 'delete me';
|
||||
o["asd"] = 2;
|
||||
o["cowbell"] = "delete me";
|
||||
o[2] = 3;
|
||||
o['zyx'] = 4;
|
||||
o['qwe'] = 5;
|
||||
o[5] = 'delete me';
|
||||
o["zyx"] = 4;
|
||||
o["qwe"] = 5;
|
||||
o[5] = "delete me";
|
||||
o[-1] = 6;
|
||||
o[10] = 7;
|
||||
o['more'] = 'delete me';
|
||||
o["more"] = "delete me";
|
||||
o[7] = 8;
|
||||
|
||||
delete o[5];
|
||||
delete o['more'];
|
||||
delete o['cowbell'];
|
||||
delete o["more"];
|
||||
delete o["cowbell"];
|
||||
|
||||
const keys = Object.getOwnPropertyNames(o);
|
||||
assert.strictEqual(keys.length, 9);
|
||||
|
@ -77,4 +78,4 @@ import { NewEmptyObject } from '@azure-tools/datastore';
|
|||
assert.strictEqual(o[keys[i]], i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,25 @@
|
|||
import * as aio from '@azure-tools/async-io';
|
||||
import * as datastore from '@azure-tools/datastore';
|
||||
import * as assert from 'assert';
|
||||
import { suite, test, skip } from 'mocha-typescript';
|
||||
import { getSubsetRelation, getSubsetSchema, getSupersetSchema, SubsetSchemaDeduplicator } from '../lib/pipeline/plugins/subset-schemas-deduplicator';
|
||||
import * as aio from "@azure-tools/async-io";
|
||||
import * as datastore from "@azure-tools/datastore";
|
||||
import * as assert from "assert";
|
||||
import { suite, test, skip } from "mocha-typescript";
|
||||
import {
|
||||
getSubsetRelation,
|
||||
getSubsetSchema,
|
||||
getSupersetSchema,
|
||||
SubsetSchemaDeduplicator,
|
||||
} from "../lib/pipeline/plugins/subset-schemas-deduplicator";
|
||||
|
||||
const resources = `${__dirname}../../../test/resources/subset-deduplication`;
|
||||
|
||||
// validation specific keys such as readOnly and required are ignored
|
||||
const skipList = ['description', 'enum', 'readOnly', 'required'];
|
||||
const expandableFieldsList = ['properties', 'allOf'];
|
||||
const skipList = ["description", "enum", "readOnly", "required"];
|
||||
const expandableFieldsList = ["properties", "allOf"];
|
||||
|
||||
@suite class SubsetDeduplication {
|
||||
@suite
|
||||
class SubsetDeduplication {
|
||||
@skip /* todo: fix test */
|
||||
@test async 'subset check function'() {
|
||||
|
||||
@test
|
||||
async "subset check function"() {
|
||||
const input = JSON.parse(await aio.readFile(`${resources}/schema1.json`));
|
||||
const input2 = JSON.parse(await aio.readFile(`${resources}/schema2.json`));
|
||||
const input3 = JSON.parse(await aio.readFile(`${resources}/schema3.json`));
|
||||
|
@ -21,60 +27,60 @@ const expandableFieldsList = ['properties', 'allOf'];
|
|||
const expected2 = JSON.parse(await aio.readFile(`${resources}/expected-check-result2.json`));
|
||||
|
||||
const result1 = getSubsetRelation(input, input2, expandableFieldsList, skipList);
|
||||
assert.deepStrictEqual(
|
||||
result1,
|
||||
expected1
|
||||
);
|
||||
assert.deepStrictEqual(result1, expected1);
|
||||
|
||||
const result2 = getSubsetRelation(input2, input3, expandableFieldsList, skipList);
|
||||
assert.deepStrictEqual(
|
||||
result2,
|
||||
expected2
|
||||
);
|
||||
assert.deepStrictEqual(result2, expected2);
|
||||
}
|
||||
|
||||
@skip /* todo: fix test */
|
||||
@test async 'superset schema construction'() {
|
||||
|
||||
@test
|
||||
async "superset schema construction"() {
|
||||
const input = JSON.parse(await aio.readFile(`${resources}/schema1.json`));
|
||||
const input2 = JSON.parse(await aio.readFile(`${resources}/schema2.json`));
|
||||
const checkResult1 = JSON.parse(await aio.readFile(`${resources}/expected-check-result1.json`));
|
||||
const updatedSchema2 = JSON.parse(await aio.readFile(`${resources}/updated-schema2.json`));
|
||||
|
||||
const result1 = getSupersetSchema(input, input2, expandableFieldsList, checkResult1, '#/definitions/subset');
|
||||
assert.deepStrictEqual(
|
||||
result1,
|
||||
updatedSchema2
|
||||
);
|
||||
const result1 = getSupersetSchema(input, input2, expandableFieldsList, checkResult1, "#/definitions/subset");
|
||||
assert.deepStrictEqual(result1, updatedSchema2);
|
||||
}
|
||||
|
||||
@skip /* todo: fix test */
|
||||
@test async 'subset schema construction'() {
|
||||
|
||||
@test
|
||||
async "subset schema construction"() {
|
||||
const input = JSON.parse(await aio.readFile(`${resources}/schema1.json`));
|
||||
const input2 = JSON.parse(await aio.readFile(`${resources}/schema2.json`));
|
||||
const checkResult1 = JSON.parse(await aio.readFile(`${resources}/expected-check-result1.json`));
|
||||
const updatedSchema2 = JSON.parse(await aio.readFile(`${resources}/updated-schema1.json`));
|
||||
|
||||
const result1 = getSubsetSchema(input, checkResult1);
|
||||
assert.deepStrictEqual(
|
||||
result1,
|
||||
updatedSchema2
|
||||
);
|
||||
assert.deepStrictEqual(result1, updatedSchema2);
|
||||
}
|
||||
|
||||
@skip /* todo: fix test */
|
||||
@test async 'subset deduplication in spec'() {
|
||||
const inputUri = 'mem://input1.json';
|
||||
const outputUri = 'mem://output1.json';
|
||||
@test
|
||||
async "subset deduplication in spec"() {
|
||||
const inputUri = "mem://input1.json";
|
||||
const outputUri = "mem://output1.json";
|
||||
|
||||
const input = await aio.readFile(`${resources}/input1.json`);
|
||||
const output = await aio.readFile(`${resources}/output1.json`);
|
||||
|
||||
const map = new Map<string, string>([[inputUri, input], [outputUri, output]]);
|
||||
const map = new Map<string, string>([
|
||||
[inputUri, input],
|
||||
[outputUri, output],
|
||||
]);
|
||||
const mfs = new datastore.MemoryFileSystem(map);
|
||||
|
||||
const cts: datastore.CancellationTokenSource = { cancel() { /* unused */ }, dispose() { /* unused */ }, token: { isCancellationRequested: false, onCancellationRequested: <any>null } };
|
||||
const cts: datastore.CancellationTokenSource = {
|
||||
cancel() {
|
||||
/* unused */
|
||||
},
|
||||
dispose() {
|
||||
/* unused */
|
||||
},
|
||||
token: { isCancellationRequested: false, onCancellationRequested: <any>null },
|
||||
};
|
||||
const ds = new datastore.DataStore(cts.token);
|
||||
const scope = ds.GetReadThroughScope(mfs);
|
||||
const inputDataHandle = await scope.Read(inputUri);
|
||||
|
@ -87,7 +93,7 @@ const expandableFieldsList = ['properties', 'allOf'];
|
|||
const outputObject = await outputDataHandle.ReadObject();
|
||||
const processor = new SubsetSchemaDeduplicator(inputDataHandle);
|
||||
const processorOutput = await processor.getOutput();
|
||||
assert.deepEqual(processorOutput, outputObject, 'Should be the same');
|
||||
assert.deepEqual(processorOutput, outputObject, "Should be the same");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import * as assert from 'assert';
|
||||
import { only, skip, slow, suite, test, timeout } from 'mocha-typescript';
|
||||
import * as assert from "assert";
|
||||
import { only, skip, slow, suite, test, timeout } from "mocha-typescript";
|
||||
|
||||
import { RealFileSystem } from '@azure-tools/datastore';
|
||||
import { CreateFolderUri, ResolveUri } from '@azure-tools/uri';
|
||||
import { AutoRest } from '../lib/autorest-core';
|
||||
import { LoadLiterateSwaggers } from '../lib/pipeline/plugins/loaders';
|
||||
import { RealFileSystem } from "@azure-tools/datastore";
|
||||
import { CreateFolderUri, ResolveUri } from "@azure-tools/uri";
|
||||
import { AutoRest } from "../lib/autorest-core";
|
||||
import { LoadLiterateSwaggers } from "../lib/pipeline/plugins/loaders";
|
||||
|
||||
@suite class SwaggerLoading {
|
||||
|
||||
@test async 'No input files provided'() {
|
||||
@suite
|
||||
class SwaggerLoading {
|
||||
@test async "No input files provided"() {
|
||||
const autoRest = new AutoRest();
|
||||
const config = await autoRest.view;
|
||||
const dataStore = config.DataStore;
|
||||
|
@ -19,67 +19,67 @@ import { LoadLiterateSwaggers } from '../lib/pipeline/plugins/loaders';
|
|||
config,
|
||||
dataStore.GetReadThroughScope(new RealFileSystem()),
|
||||
inputFilesUris,
|
||||
dataStore.getDataSink());
|
||||
dataStore.getDataSink(),
|
||||
);
|
||||
|
||||
assert.strictEqual(swaggerFilesLoaded.length, 0);
|
||||
|
||||
}
|
||||
|
||||
@test async 'All input files have a 2.0 version.'() {
|
||||
@test async "All input files have a 2.0 version."() {
|
||||
const autoRest = new AutoRest();
|
||||
const config = await autoRest.view;
|
||||
const dataStore = config.DataStore;
|
||||
|
||||
const inputFilesUris = [
|
||||
ResolveUri(CreateFolderUri(__dirname), '../../test/resources/swagger-loading/swagger-file1.json'),
|
||||
ResolveUri(CreateFolderUri(__dirname), '../../test/resources/swagger-loading/swagger-file2.json'),
|
||||
ResolveUri(CreateFolderUri(__dirname), '../../test/resources/swagger-loading/swagger-file3.yaml'),
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/swagger-loading/swagger-file1.json"),
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/swagger-loading/swagger-file2.json"),
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/swagger-loading/swagger-file3.yaml"),
|
||||
];
|
||||
|
||||
const swaggerFilesLoaded = await LoadLiterateSwaggers(
|
||||
config,
|
||||
dataStore.GetReadThroughScope(new RealFileSystem()),
|
||||
inputFilesUris,
|
||||
dataStore.getDataSink());
|
||||
dataStore.getDataSink(),
|
||||
);
|
||||
|
||||
assert.strictEqual(swaggerFilesLoaded.length, inputFilesUris.length);
|
||||
|
||||
}
|
||||
|
||||
@test async 'All input files do not have a 2.0 version.'() {
|
||||
@test async "All input files do not have a 2.0 version."() {
|
||||
const autoRest = new AutoRest();
|
||||
const config = await autoRest.view;
|
||||
const dataStore = config.DataStore;
|
||||
|
||||
const inputFilesUris = [
|
||||
ResolveUri(CreateFolderUri(__dirname), '../../test/resources/swagger-loading/non-swagger-file1.yaml'),
|
||||
ResolveUri(CreateFolderUri(__dirname), '../../test/resources/swagger-loading/non-swagger-file2.yaml')
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/swagger-loading/non-swagger-file1.yaml"),
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/swagger-loading/non-swagger-file2.yaml"),
|
||||
];
|
||||
|
||||
const swaggerFilesLoaded = await LoadLiterateSwaggers(
|
||||
config,
|
||||
dataStore.GetReadThroughScope(new RealFileSystem()),
|
||||
inputFilesUris,
|
||||
dataStore.getDataSink());
|
||||
dataStore.getDataSink(),
|
||||
);
|
||||
|
||||
assert.strictEqual(swaggerFilesLoaded.length, 0);
|
||||
|
||||
}
|
||||
|
||||
@test async 'Some input files have a 2.0 version and some input files do not have a 2.0 version.'() {
|
||||
@test async "Some input files have a 2.0 version and some input files do not have a 2.0 version."() {
|
||||
const autoRest = new AutoRest();
|
||||
const config = await autoRest.view;
|
||||
const dataStore = config.DataStore;
|
||||
|
||||
const nonSwaggerFileUris = [
|
||||
ResolveUri(CreateFolderUri(__dirname), '../../test/resources/swagger-loading/non-swagger-file1.yaml'),
|
||||
ResolveUri(CreateFolderUri(__dirname), '../../test/resources/swagger-loading/non-swagger-file2.yaml')
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/swagger-loading/non-swagger-file1.yaml"),
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/swagger-loading/non-swagger-file2.yaml"),
|
||||
];
|
||||
|
||||
const swaggerFileUris = [
|
||||
ResolveUri(CreateFolderUri(__dirname), '../../test/resources/swagger-loading/swagger-file1.json'),
|
||||
ResolveUri(CreateFolderUri(__dirname), '../../test/resources/swagger-loading/swagger-file2.json'),
|
||||
ResolveUri(CreateFolderUri(__dirname), '../../test/resources/swagger-loading/swagger-file3.yaml'),
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/swagger-loading/swagger-file1.json"),
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/swagger-loading/swagger-file2.json"),
|
||||
ResolveUri(CreateFolderUri(__dirname), "../../test/resources/swagger-loading/swagger-file3.yaml"),
|
||||
];
|
||||
|
||||
const inputFilesUris = [...swaggerFileUris, ...nonSwaggerFileUris];
|
||||
|
@ -88,7 +88,8 @@ import { LoadLiterateSwaggers } from '../lib/pipeline/plugins/loaders';
|
|||
config,
|
||||
dataStore.GetReadThroughScope(new RealFileSystem()),
|
||||
inputFilesUris,
|
||||
dataStore.getDataSink());
|
||||
dataStore.getDataSink(),
|
||||
);
|
||||
|
||||
assert.strictEqual(swaggerFilesLoaded.length, inputFilesUris.length - nonSwaggerFileUris.length);
|
||||
}
|
||||
|
|
|
@ -4,26 +4,31 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { suite, test, slow, timeout, skip, only } from 'mocha-typescript';
|
||||
import * as assert from 'assert';
|
||||
import { CancellationToken } from 'vscode-jsonrpc';
|
||||
import { DataStore } from '@azure-tools/datastore';
|
||||
import { Message, Channel } from '../lib/message';
|
||||
import { AutoRest } from '../lib/autorest-core';
|
||||
import { suite, test, slow, timeout, skip, only } from "mocha-typescript";
|
||||
import * as assert from "assert";
|
||||
import { CancellationToken } from "vscode-jsonrpc";
|
||||
import { DataStore } from "@azure-tools/datastore";
|
||||
import { Message, Channel } from "../lib/message";
|
||||
import { AutoRest } from "../lib/autorest-core";
|
||||
|
||||
import { parse } from '../lib/parsing/literate-yaml';
|
||||
import { Configuration } from '../lib/configuration';
|
||||
import { parse } from "../lib/parsing/literate-yaml";
|
||||
import { Configuration } from "../lib/configuration";
|
||||
|
||||
@suite class SyntaxValidation {
|
||||
private async GetLoaderErrors(swagger: string): Promise<Array<Message>> {
|
||||
@suite
|
||||
class SyntaxValidation {
|
||||
private async "GetLoaderErrors"(swagger: string): Promise<Array<Message>> {
|
||||
const dataStore = new DataStore(CancellationToken.None);
|
||||
const uri = 'mem:///swagger.json';
|
||||
const h = await dataStore.WriteData(uri, swagger, 'input-file', [uri]);
|
||||
const uri = "mem:///swagger.json";
|
||||
const h = await dataStore.WriteData(uri, swagger, "input-file", [uri]);
|
||||
|
||||
const autoRest = new AutoRest();
|
||||
const messages: Array<Message> = [];
|
||||
|
||||
autoRest.Message.Subscribe((_, m) => { if (m.Channel == Channel.Error) { messages.push(m); } });
|
||||
autoRest.Message.Subscribe((_, m) => {
|
||||
if (m.Channel == Channel.Error) {
|
||||
messages.push(m);
|
||||
}
|
||||
});
|
||||
try {
|
||||
await parse(await autoRest.view, h, dataStore.getDataSink());
|
||||
} catch (e) {
|
||||
|
@ -33,28 +38,44 @@ import { Configuration } from '../lib/configuration';
|
|||
return messages;
|
||||
}
|
||||
@skip /* todo: fix test */
|
||||
@test async 'syntax errors'() {
|
||||
@test
|
||||
async "syntax errors"() {
|
||||
// good
|
||||
assert.strictEqual((await this.GetLoaderErrors('{ a: 3 }')).length, 0);
|
||||
assert.strictEqual((await this.GetLoaderErrors('a: 3')).length, 0);
|
||||
assert.strictEqual((await this.GetLoaderErrors('a: [3]')).length, 0);
|
||||
assert.strictEqual((await this.GetLoaderErrors("{ a: 3 }")).length, 0);
|
||||
assert.strictEqual((await this.GetLoaderErrors("a: 3")).length, 0);
|
||||
assert.strictEqual((await this.GetLoaderErrors("a: [3]")).length, 0);
|
||||
|
||||
// bad
|
||||
assert.notEqual((await this.GetLoaderErrors('{ a: 3 ')).length, 0);
|
||||
assert.notEqual((await this.GetLoaderErrors('{ a: \'3 }')).length, 0);
|
||||
assert.notEqual((await this.GetLoaderErrors('\n\n [{ a: \'3 }]')).length, 0);
|
||||
assert.notEqual((await this.GetLoaderErrors('{ a 3 }')).length, 0);
|
||||
assert.notEqual((await this.GetLoaderErrors('a: [3')).length, 0);
|
||||
assert.notEqual((await this.GetLoaderErrors("{ a: 3 ")).length, 0);
|
||||
assert.notEqual((await this.GetLoaderErrors("{ a: '3 }")).length, 0);
|
||||
assert.notEqual((await this.GetLoaderErrors("\n\n [{ a: '3 }]")).length, 0);
|
||||
assert.notEqual((await this.GetLoaderErrors("{ a 3 }")).length, 0);
|
||||
assert.notEqual((await this.GetLoaderErrors("a: [3")).length, 0);
|
||||
|
||||
// location
|
||||
assert.deepStrictEqual(((await this.GetLoaderErrors('{ a: 3 '))[0] as any).Source[0].Position, { line: 1, column: 8 });
|
||||
assert.deepStrictEqual(((await this.GetLoaderErrors('{ a: \'3 }'))[0] as any).Source[0].Position, { line: 1, column: 10 });
|
||||
assert.deepStrictEqual(((await this.GetLoaderErrors('\n\n\n [{ a: \'3 }]'))[0] as any).Source[0].Position, { line: 4, column: 13 });
|
||||
assert.deepStrictEqual(((await this.GetLoaderErrors('{ a 3 }'))[0] as any).Source[0].Position, { line: 1, column: 5 });
|
||||
assert.deepStrictEqual(((await this.GetLoaderErrors('a: [3'))[0] as any).Source[0].Position, { line: 1, column: 6 });
|
||||
assert.deepStrictEqual(((await this.GetLoaderErrors("{ a: 3 "))[0] as any).Source[0].Position, {
|
||||
line: 1,
|
||||
column: 8,
|
||||
});
|
||||
assert.deepStrictEqual(((await this.GetLoaderErrors("{ a: '3 }"))[0] as any).Source[0].Position, {
|
||||
line: 1,
|
||||
column: 10,
|
||||
});
|
||||
assert.deepStrictEqual(((await this.GetLoaderErrors("\n\n\n [{ a: '3 }]"))[0] as any).Source[0].Position, {
|
||||
line: 4,
|
||||
column: 13,
|
||||
});
|
||||
assert.deepStrictEqual(((await this.GetLoaderErrors("{ a 3 }"))[0] as any).Source[0].Position, {
|
||||
line: 1,
|
||||
column: 5,
|
||||
});
|
||||
assert.deepStrictEqual(((await this.GetLoaderErrors("a: [3"))[0] as any).Source[0].Position, {
|
||||
line: 1,
|
||||
column: 6,
|
||||
});
|
||||
}
|
||||
|
||||
static after() {
|
||||
static "after"() {
|
||||
Configuration.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,53 +1,74 @@
|
|||
import * as cp from 'child_process';
|
||||
import * as rpc from 'vscode-jsonrpc';
|
||||
import { suite, test, slow, timeout, skip, only } from 'mocha-typescript';
|
||||
import * as cp from "child_process";
|
||||
import * as rpc from "vscode-jsonrpc";
|
||||
import { suite, test, slow, timeout, skip, only } from "mocha-typescript";
|
||||
|
||||
async function connect() {
|
||||
const childProcess = cp.spawn('dotnet', [`${__dirname}/../../../core/AutoRest/bin/netcoreapp1.0/AutoRest.dll`, '--server']);
|
||||
const childProcess = cp.spawn("dotnet", [
|
||||
`${__dirname}/../../../core/AutoRest/bin/netcoreapp1.0/AutoRest.dll`,
|
||||
"--server",
|
||||
]);
|
||||
|
||||
// Use stdin and stdout for communication:
|
||||
const connection = rpc.createMessageConnection(
|
||||
new rpc.StreamMessageReader(childProcess.stdout),
|
||||
new rpc.StreamMessageWriter(childProcess.stdin), console);
|
||||
new rpc.StreamMessageWriter(childProcess.stdin),
|
||||
console,
|
||||
);
|
||||
|
||||
// host interface
|
||||
connection.onNotification(new rpc.NotificationType4<string, string, string, any, void>('WriteFile'), (sessionId: string, filename: string, content: string, sourcemap: any) => {
|
||||
console.log(`Saving File ${sessionId}, ${filename}`);
|
||||
});
|
||||
connection.onNotification(
|
||||
new rpc.NotificationType4<string, string, string, any, void>("WriteFile"),
|
||||
(sessionId: string, filename: string, content: string, sourcemap: any) => {
|
||||
console.log(`Saving File ${sessionId}, ${filename}`);
|
||||
},
|
||||
);
|
||||
|
||||
connection.onNotification(new rpc.NotificationType3<string, any, any, void>('Message'), (sessionId: string, details: any, sourcemap: any) => {
|
||||
console.log(`You have posted message ${sessionId}, ${details}`);
|
||||
});
|
||||
connection.onNotification(
|
||||
new rpc.NotificationType3<string, any, any, void>("Message"),
|
||||
(sessionId: string, details: any, sourcemap: any) => {
|
||||
console.log(`You have posted message ${sessionId}, ${details}`);
|
||||
},
|
||||
);
|
||||
|
||||
connection.onRequest(new rpc.RequestType2<string, string, string, void, void>('ReadFile'), (sessionId: string, filename: string) => {
|
||||
return `You asked for the file ${filename} in the session ${sessionId}`;
|
||||
});
|
||||
connection.onRequest(
|
||||
new rpc.RequestType2<string, string, string, void, void>("ReadFile"),
|
||||
(sessionId: string, filename: string) => {
|
||||
return `You asked for the file ${filename} in the session ${sessionId}`;
|
||||
},
|
||||
);
|
||||
|
||||
connection.onRequest(new rpc.RequestType2<string, string, string, void, void>('GetValue'), (sessionId: string, key: string) => {
|
||||
return `You asked for the value ${key} in the session ${sessionId}`;
|
||||
});
|
||||
connection.onRequest(
|
||||
new rpc.RequestType2<string, string, string, void, void>("GetValue"),
|
||||
(sessionId: string, key: string) => {
|
||||
return `You asked for the value ${key} in the session ${sessionId}`;
|
||||
},
|
||||
);
|
||||
|
||||
connection.onRequest(new rpc.RequestType2<string,string|undefined, Array<string>, void, void>('ListInputs'), (sessionId: string) => {
|
||||
return ['a.txt', 'b.txt'];
|
||||
});
|
||||
connection.onRequest(
|
||||
new rpc.RequestType2<string, string | undefined, Array<string>, void, void>("ListInputs"),
|
||||
(sessionId: string) => {
|
||||
return ["a.txt", "b.txt"];
|
||||
},
|
||||
);
|
||||
|
||||
// extension interface
|
||||
const EnumeratePlugins = new rpc.RequestType0<Array<string>, void, void>('GetPluginNames');
|
||||
const Process = (plugin: string, session: string) => connection.sendRequest(new rpc.RequestType2<string, string, boolean, void, void>('Process'), plugin, session);
|
||||
const Shutdown = () => connection.sendNotification(new rpc.NotificationType0<void>('Shutdown'));
|
||||
const EnumeratePlugins = new rpc.RequestType0<Array<string>, void, void>("GetPluginNames");
|
||||
const Process = (plugin: string, session: string) =>
|
||||
connection.sendRequest(new rpc.RequestType2<string, string, boolean, void, void>("Process"), plugin, session);
|
||||
const Shutdown = () => connection.sendNotification(new rpc.NotificationType0<void>("Shutdown"));
|
||||
|
||||
childProcess.stderr.pipe(process.stdout);
|
||||
connection.listen();
|
||||
|
||||
console.log('before enumerate');
|
||||
console.log("before enumerate");
|
||||
const values = await connection.sendRequest(EnumeratePlugins);
|
||||
for (const each of values) {
|
||||
console.log(each);
|
||||
}
|
||||
console.log('after enumerate');
|
||||
console.log("after enumerate");
|
||||
|
||||
console.log('calling process');
|
||||
const result = await Process('Modeler', 'session1');
|
||||
console.log("calling process");
|
||||
const result = await Process("Modeler", "session1");
|
||||
console.log(`done process: ${result} `);
|
||||
|
||||
Shutdown();
|
||||
|
@ -58,12 +79,11 @@ async function connect() {
|
|||
resolve();
|
||||
}, 200);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@suite class TestConnectivity {
|
||||
@test @skip async 'E2E'() {
|
||||
@suite
|
||||
class TestConnectivity {
|
||||
@test @skip async E2E() {
|
||||
await connect();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,11 +2,10 @@
|
|||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { AutoRest } from '../lib/autorest-core';
|
||||
import { Message, Channel } from '../lib/message';
|
||||
import { AutoRest } from "../lib/autorest-core";
|
||||
import { Message, Channel } from "../lib/message";
|
||||
|
||||
export function PumpMessagesToConsole(autoRest: AutoRest): void {
|
||||
|
||||
autoRest.Message.Subscribe((_, m) => {
|
||||
switch (m.Channel) {
|
||||
case Channel.Information:
|
||||
|
@ -25,5 +24,4 @@ export function PumpMessagesToConsole(autoRest: AutoRest): void {
|
|||
break;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,27 +1,37 @@
|
|||
import * as aio from '@azure-tools/async-io';
|
||||
import * as datastore from '@azure-tools/datastore';
|
||||
import * as assert from 'assert';
|
||||
import { suite, test, skip } from 'mocha-typescript';
|
||||
import { ApiVersionParameterHandler } from '../lib/pipeline/plugins/version-param-handler';
|
||||
import * as aio from "@azure-tools/async-io";
|
||||
import * as datastore from "@azure-tools/datastore";
|
||||
import * as assert from "assert";
|
||||
import { suite, test, skip } from "mocha-typescript";
|
||||
import { ApiVersionParameterHandler } from "../lib/pipeline/plugins/version-param-handler";
|
||||
|
||||
const resources = `${__dirname}../../../test/resources/version-param-handler`;
|
||||
|
||||
@suite class ApiVersionParameterHandling {
|
||||
|
||||
|
||||
@suite
|
||||
class ApiVersionParameterHandling {
|
||||
@skip /* todo: fix test */
|
||||
@test async 'Remove api-version global parameter, remove references to said parameter and add metadata.'() {
|
||||
|
||||
const inputUri = 'mem://input.json';
|
||||
const outputUri = 'mem://output.json';
|
||||
@test
|
||||
async "Remove api-version global parameter, remove references to said parameter and add metadata."() {
|
||||
const inputUri = "mem://input.json";
|
||||
const outputUri = "mem://output.json";
|
||||
|
||||
const input = await aio.readFile(`${resources}/input.json`);
|
||||
const output = await aio.readFile(`${resources}/output.json`);
|
||||
|
||||
const map = new Map<string, string>([[inputUri, input], [outputUri, output]]);
|
||||
const map = new Map<string, string>([
|
||||
[inputUri, input],
|
||||
[outputUri, output],
|
||||
]);
|
||||
const mfs = new datastore.MemoryFileSystem(map);
|
||||
|
||||
const cts: datastore.CancellationTokenSource = { cancel() { /* unused */ }, dispose() { /* unused */ }, token: { isCancellationRequested: false, onCancellationRequested: <any>null } };
|
||||
const cts: datastore.CancellationTokenSource = {
|
||||
cancel() {
|
||||
/* unused */
|
||||
},
|
||||
dispose() {
|
||||
/* unused */
|
||||
},
|
||||
token: { isCancellationRequested: false, onCancellationRequested: <any>null },
|
||||
};
|
||||
const ds = new datastore.DataStore(cts.token);
|
||||
const scope = ds.GetReadThroughScope(mfs);
|
||||
const inputDataHandle = await scope.Read(inputUri);
|
||||
|
@ -35,7 +45,7 @@ const resources = `${__dirname}../../../test/resources/version-param-handler`;
|
|||
const outputObject = await outputDataHandle.ReadObject();
|
||||
const paramHandler = new ApiVersionParameterHandler(inputDataHandle);
|
||||
|
||||
assert.deepEqual(await paramHandler.getOutput(), outputObject, 'Should be the same');
|
||||
assert.deepEqual(await paramHandler.getOutput(), outputObject, "Should be the same");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,20 +14,10 @@
|
|||
"declaration": true,
|
||||
"stripInternal": true,
|
||||
"target": "es2018",
|
||||
"types": [
|
||||
"node",
|
||||
"mocha"
|
||||
],
|
||||
"lib": [
|
||||
"es2018"
|
||||
],
|
||||
"types": ["node", "mocha"],
|
||||
"lib": ["es2018"],
|
||||
"experimentalDecorators": true,
|
||||
"newLine": "LF",
|
||||
"newLine": "LF"
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"static_modules",
|
||||
"dist",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
||||
"exclude": ["node_modules", "static_modules", "dist", "**/*.d.ts"]
|
||||
}
|
||||
|
|
|
@ -1,171 +1,188 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<head>
|
||||
<title>AutoRest dashboard</title>
|
||||
<style>
|
||||
body, div {
|
||||
/* padding: 30px; */
|
||||
font-family: sans-serif;
|
||||
text-align: center;
|
||||
}
|
||||
h1, h2 {
|
||||
font-weight: normal;
|
||||
}
|
||||
h2 {
|
||||
text-align: left;
|
||||
min-width: 40%;
|
||||
}
|
||||
table {
|
||||
display: inline-block;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
th {
|
||||
color: #aaa;
|
||||
}
|
||||
th, td {
|
||||
font-weight: normal;
|
||||
/* font-style: italic; */
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
td {
|
||||
padding: 0px;
|
||||
}
|
||||
th, td > div {
|
||||
padding: 3px;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: blue;
|
||||
}
|
||||
body,
|
||||
div {
|
||||
/* padding: 30px; */
|
||||
font-family: sans-serif;
|
||||
text-align: center;
|
||||
}
|
||||
h1,
|
||||
h2 {
|
||||
font-weight: normal;
|
||||
}
|
||||
h2 {
|
||||
text-align: left;
|
||||
min-width: 40%;
|
||||
}
|
||||
table {
|
||||
display: inline-block;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
th {
|
||||
color: #aaa;
|
||||
}
|
||||
th,
|
||||
td {
|
||||
font-weight: normal;
|
||||
/* font-style: italic; */
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
td {
|
||||
padding: 0px;
|
||||
}
|
||||
th,
|
||||
td > div {
|
||||
padding: 3px;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.loading {
|
||||
display: inline-block;
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
background: gray;
|
||||
animation: loading 1s infinite linear;
|
||||
}
|
||||
.loading {
|
||||
display: inline-block;
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
background: gray;
|
||||
animation: loading 1s infinite linear;
|
||||
}
|
||||
|
||||
@keyframes loading {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(359.9deg);
|
||||
}
|
||||
@keyframes loading {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(359.9deg);
|
||||
}
|
||||
}
|
||||
|
||||
details tr.optional {
|
||||
display: none;
|
||||
}
|
||||
details[open] tr.optional {
|
||||
display: table-row;
|
||||
}
|
||||
details tr.optional {
|
||||
display: none;
|
||||
}
|
||||
details[open] tr.optional {
|
||||
display: table-row;
|
||||
}
|
||||
</style>
|
||||
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
|
||||
<script>
|
||||
const httpGet = (url, type) => new Promise((res, rej) => $.get(url, res, type).fail(rej));
|
||||
const delay = ms => new Promise(res => setTimeout(res, ms));
|
||||
const httpGet = (url, type) => new Promise((res, rej) => $.get(url, res, type).fail(rej));
|
||||
const delay = (ms) => new Promise((res) => setTimeout(res, ms));
|
||||
|
||||
const azureBlobContainer_coverage = "https://autorestci.blob.core.windows.net/autorest-ci-coverage-report";
|
||||
const coverageCategories = ["General", "Azure"];
|
||||
const azureBlobContainer_coverage = "https://autorestci.blob.core.windows.net/autorest-ci-coverage-report";
|
||||
const coverageCategories = ["General", "Azure"];
|
||||
|
||||
function semverCompare(v1, v2) {
|
||||
const v1parts = v1.split(/[^\d]+/).map(Number);
|
||||
const v2parts = v2.split(/[^\d]+/).map(Number);
|
||||
function semverCompare(v1, v2) {
|
||||
const v1parts = v1.split(/[^\d]+/).map(Number);
|
||||
const v2parts = v2.split(/[^\d]+/).map(Number);
|
||||
|
||||
for (var i = 0; i < Math.min(v1parts.length, v2parts.length); ++i)
|
||||
if (v1parts[i] != v2parts[i])
|
||||
return v1parts[i] > v2parts[i] ? 1 : -1;
|
||||
for (var i = 0; i < Math.min(v1parts.length, v2parts.length); ++i)
|
||||
if (v1parts[i] != v2parts[i]) return v1parts[i] > v2parts[i] ? 1 : -1;
|
||||
|
||||
if (v1parts.length != v2parts.length)
|
||||
return v1parts.length > v2parts.length ? 1 : -1;
|
||||
return 0;
|
||||
}
|
||||
if (v1parts.length != v2parts.length) return v1parts.length > v2parts.length ? 1 : -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
async function deferredUI(targetUI, operation) {
|
||||
targetUI.empty();
|
||||
targetUI.append($("<span class='loading' />"));
|
||||
// await delay(500);
|
||||
const resultUI = await operation();
|
||||
targetUI.empty();
|
||||
targetUI.append(resultUI);
|
||||
}
|
||||
async function deferredUI(targetUI, operation) {
|
||||
targetUI.empty();
|
||||
targetUI.append($("<span class='loading' />"));
|
||||
// await delay(500);
|
||||
const resultUI = await operation();
|
||||
targetUI.empty();
|
||||
targetUI.append(resultUI);
|
||||
}
|
||||
|
||||
async function refresh() {
|
||||
const generatorFeatureCoverage = $("#generatorFeatureCoverage");
|
||||
async function refresh() {
|
||||
const generatorFeatureCoverage = $("#generatorFeatureCoverage");
|
||||
|
||||
deferredUI(generatorFeatureCoverage, async () => {
|
||||
const reportsXml = await httpGet(`${azureBlobContainer_coverage}?restype=container&comp=list`, "xml");
|
||||
const reports = [...$(reportsXml).find("Name").map((i, o) => $(o).text())];
|
||||
const reportsByRepo/*: { [repo: string]: { version: string, uri: string }[]] }*/ = {};
|
||||
for (const report of reports) {
|
||||
const [match, repo, version] = /^autorest\.(.+)_(.+)\.md$/.exec(report);
|
||||
if (!reportsByRepo[repo]) reportsByRepo[repo] = [];
|
||||
reportsByRepo[repo].push({ version: version, uri: `${azureBlobContainer_coverage}/${report}` });
|
||||
}
|
||||
deferredUI(generatorFeatureCoverage, async () => {
|
||||
const reportsXml = await httpGet(`${azureBlobContainer_coverage}?restype=container&comp=list`, "xml");
|
||||
const reports = [
|
||||
...$(reportsXml)
|
||||
.find("Name")
|
||||
.map((i, o) => $(o).text()),
|
||||
];
|
||||
const reportsByRepo /*: { [repo: string]: { version: string, uri: string }[]] }*/ = {};
|
||||
for (const report of reports) {
|
||||
const [match, repo, version] = /^autorest\.(.+)_(.+)\.md$/.exec(report);
|
||||
if (!reportsByRepo[repo]) reportsByRepo[repo] = [];
|
||||
reportsByRepo[repo].push({ version: version, uri: `${azureBlobContainer_coverage}/${report}` });
|
||||
}
|
||||
|
||||
const result = $("<div>")
|
||||
for (const repo of Object.keys(reportsByRepo)) {
|
||||
let section = $("<details>").appendTo(result);
|
||||
section = $("<summary>").appendTo(section);
|
||||
const result = $("<div>");
|
||||
for (const repo of Object.keys(reportsByRepo)) {
|
||||
let section = $("<details>").appendTo(result);
|
||||
section = $("<summary>").appendTo(section);
|
||||
|
||||
const table = $("<table>");
|
||||
section.append($("<h2>").text(repo).css("display", "inline-block"));
|
||||
section.append($("<br>"));
|
||||
section.append(table);
|
||||
section.append($("<br>"));
|
||||
section.append($("<br>"));
|
||||
table.append($("<tr>")
|
||||
.append($("<th>").text("Version"))
|
||||
.append($("<th>").text("Feature Set"))
|
||||
.append(coverageCategories.map(cat => $("<th>").text(cat))));
|
||||
const table = $("<table>");
|
||||
section.append($("<h2>").text(repo).css("display", "inline-block"));
|
||||
section.append($("<br>"));
|
||||
section.append(table);
|
||||
section.append($("<br>"));
|
||||
section.append($("<br>"));
|
||||
table.append(
|
||||
$("<tr>")
|
||||
.append($("<th>").text("Version"))
|
||||
.append($("<th>").text("Feature Set"))
|
||||
.append(coverageCategories.map((cat) => $("<th>").text(cat))),
|
||||
);
|
||||
|
||||
const versions = reportsByRepo[repo].sort((a, b) => semverCompare(a.version, b.version)).reverse();
|
||||
let subsequent = false;
|
||||
for (const version of versions) {
|
||||
const request = httpGet(version.uri, "text");
|
||||
const featureSetVersion = $("<td>");
|
||||
deferredUI(featureSetVersion, async () => {
|
||||
const response = await request;
|
||||
const coverage = / (\d+\.\d+\.\d+)/.exec(response.split("\n").filter(l => l.includes("feature set version"))[0])[1];
|
||||
return coverage;
|
||||
});
|
||||
const coverages = coverageCategories.map(cat => {
|
||||
const cell = $("<td>");
|
||||
deferredUI(cell, async () => {
|
||||
const response = await request;
|
||||
const coverage = +/ (\d+)%/.exec(response.split("\n").filter(l => l.startsWith("##") && l.includes(cat))[0])[1];
|
||||
const color = `hsl(${coverage === 100 ? 120 : Math.pow(coverage / 100, 1.8) * 70 | 0},100%,60%)`;
|
||||
return $("<div>").text(coverage + "%").css("background", color).css("font-weight", "bold");
|
||||
});
|
||||
return cell;
|
||||
});
|
||||
table.append($("<tr>")
|
||||
.addClass(subsequent ? "optional" : "")
|
||||
.append($("<td>").append($("<a>").attr("href", version.uri).attr("target", "_blank").text(version.version)))
|
||||
.append(featureSetVersion)
|
||||
.append(coverages));
|
||||
subsequent = true;
|
||||
}
|
||||
}
|
||||
// alert(JSON.stringify(reportsByRepo));
|
||||
const versions = reportsByRepo[repo].sort((a, b) => semverCompare(a.version, b.version)).reverse();
|
||||
let subsequent = false;
|
||||
for (const version of versions) {
|
||||
const request = httpGet(version.uri, "text");
|
||||
const featureSetVersion = $("<td>");
|
||||
deferredUI(featureSetVersion, async () => {
|
||||
const response = await request;
|
||||
const coverage = / (\d+\.\d+\.\d+)/.exec(
|
||||
response.split("\n").filter((l) => l.includes("feature set version"))[0],
|
||||
)[1];
|
||||
return coverage;
|
||||
});
|
||||
const coverages = coverageCategories.map((cat) => {
|
||||
const cell = $("<td>");
|
||||
deferredUI(cell, async () => {
|
||||
const response = await request;
|
||||
const coverage = +/ (\d+)%/.exec(
|
||||
response.split("\n").filter((l) => l.startsWith("##") && l.includes(cat))[0],
|
||||
)[1];
|
||||
const color = `hsl(${coverage === 100 ? 120 : (Math.pow(coverage / 100, 1.8) * 70) | 0},100%,60%)`;
|
||||
return $("<div>")
|
||||
.text(coverage + "%")
|
||||
.css("background", color)
|
||||
.css("font-weight", "bold");
|
||||
});
|
||||
return cell;
|
||||
});
|
||||
table.append(
|
||||
$("<tr>")
|
||||
.addClass(subsequent ? "optional" : "")
|
||||
.append(
|
||||
$("<td>").append($("<a>").attr("href", version.uri).attr("target", "_blank").text(version.version)),
|
||||
)
|
||||
.append(featureSetVersion)
|
||||
.append(coverages),
|
||||
);
|
||||
subsequent = true;
|
||||
}
|
||||
}
|
||||
// alert(JSON.stringify(reportsByRepo));
|
||||
|
||||
// const x = await httpGet("http://registry.npmjs.org/@microsoft.azure%2Fautorest.java", "json");
|
||||
// alert(JSON.stringify(x["dist-tags"]));
|
||||
// const x = await httpGet("http://registry.npmjs.org/@microsoft.azure%2Fautorest.java", "json");
|
||||
// alert(JSON.stringify(x["dist-tags"]));
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
$(() => refresh());
|
||||
$(() => refresh());
|
||||
</script>
|
||||
</head>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<body>
|
||||
<h1>Generator Feature Coverage</h1>
|
||||
<div id="generatorFeatureCoverage"></div>
|
||||
</body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
swagger: '2.0'
|
||||
swagger: "2.0"
|
||||
info:
|
||||
title: PetStore Inc.
|
||||
description: Pets online.
|
||||
|
@ -10,25 +10,25 @@ info:
|
|||
x-ms-parameterized-host:
|
||||
hostTemplate: "{petBaseUrl}"
|
||||
parameters:
|
||||
- name: petBaseUrl
|
||||
required: true
|
||||
type: string
|
||||
in: path
|
||||
x-ms-skip-url-encoding: true
|
||||
- name: petBaseUrl
|
||||
required: true
|
||||
type: string
|
||||
in: path
|
||||
x-ms-skip-url-encoding: true
|
||||
paths:
|
||||
"/Pets/{petId}/GetPet":
|
||||
post:
|
||||
operationId: Pet_GetPetById
|
||||
description: Gets pets by id.
|
||||
parameters:
|
||||
- name: petId
|
||||
in: path
|
||||
required: true
|
||||
type: string
|
||||
description: pet id
|
||||
- name: petId
|
||||
in: path
|
||||
required: true
|
||||
type: string
|
||||
description: pet id
|
||||
responses:
|
||||
'200':
|
||||
description: ''
|
||||
"200":
|
||||
description: ""
|
||||
schema:
|
||||
"$ref": "#/definitions/Pet"
|
||||
definitions:
|
||||
|
@ -37,4 +37,4 @@ definitions:
|
|||
name:
|
||||
type: string
|
||||
readOnly: true
|
||||
description: Gets the Pet by id.
|
||||
description: Gets the Pet by id.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
swagger: '2.0'
|
||||
swagger: "2.0"
|
||||
info:
|
||||
version: 1.0.0
|
||||
title: Swagger Petstore
|
||||
|
@ -8,23 +8,23 @@ info:
|
|||
host: petstore.swagger.io
|
||||
basePath: "/v1"
|
||||
schemes:
|
||||
- https
|
||||
- https
|
||||
consumes:
|
||||
- application/json
|
||||
- application/json
|
||||
produces:
|
||||
- application/json
|
||||
- application/json
|
||||
paths:
|
||||
"/pets":
|
||||
put:
|
||||
summary: Add a pet
|
||||
operationId: addPet
|
||||
tags:
|
||||
- pets
|
||||
- pets
|
||||
parameters:
|
||||
- schema:
|
||||
"$ref": "#/definitions/Pet"
|
||||
- schema:
|
||||
"$ref": "#/definitions/Pet"
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: OK
|
||||
definitions:
|
||||
Pet:
|
||||
|
@ -35,36 +35,36 @@ definitions:
|
|||
type: string
|
||||
discriminator: petKind
|
||||
required:
|
||||
- name
|
||||
- petType
|
||||
- name
|
||||
- petType
|
||||
Cat:
|
||||
description: A representation of a cat
|
||||
x-ms-discriminator-value: Microsoft.PetStore.PetType
|
||||
allOf:
|
||||
- "$ref": "#/definitions/Pet"
|
||||
- properties:
|
||||
huntingSkill:
|
||||
type: string
|
||||
description: The measured skill for hunting
|
||||
default: lazy
|
||||
enum:
|
||||
- clueless
|
||||
- lazy
|
||||
- adventurous
|
||||
- aggressive
|
||||
required:
|
||||
- huntingSkill
|
||||
- "$ref": "#/definitions/Pet"
|
||||
- properties:
|
||||
huntingSkill:
|
||||
type: string
|
||||
description: The measured skill for hunting
|
||||
default: lazy
|
||||
enum:
|
||||
- clueless
|
||||
- lazy
|
||||
- adventurous
|
||||
- aggressive
|
||||
required:
|
||||
- huntingSkill
|
||||
Dog:
|
||||
description: A representation of a dog
|
||||
x-ms-discriminator-value: Microsoft.PetStore.PetType
|
||||
allOf:
|
||||
- "$ref": "#/definitions/Pet"
|
||||
- properties:
|
||||
packSize:
|
||||
type: integer
|
||||
format: int32
|
||||
description: the size of the pack the dog is from
|
||||
default: 0
|
||||
minimum: 0
|
||||
required:
|
||||
- packSize
|
||||
- "$ref": "#/definitions/Pet"
|
||||
- properties:
|
||||
packSize:
|
||||
type: integer
|
||||
format: int32
|
||||
description: the size of the pack the dog is from
|
||||
default: 0
|
||||
minimum: 0
|
||||
required:
|
||||
- packSize
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -121,4 +121,3 @@ SOFTWARE.
|
|||
.pl-mo /* meta.output */ {
|
||||
color: #1d3e81;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
* {
|
||||
box-sizing: border-box; }
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 0;
|
||||
|
@ -7,13 +8,16 @@ body {
|
|||
font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
color: #606c71; }
|
||||
color: #606c71;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #1e6bb8;
|
||||
text-decoration: none; }
|
||||
a:hover {
|
||||
text-decoration: underline; }
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
|
@ -24,104 +28,145 @@ a {
|
|||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-radius: 0.3rem;
|
||||
transition: color 0.2s, background-color 0.2s, border-color 0.2s; }
|
||||
.btn + .btn {
|
||||
margin-left: 1rem; }
|
||||
transition: color 0.2s, background-color 0.2s, border-color 0.2s;
|
||||
}
|
||||
.btn + .btn {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
text-decoration: none;
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
border-color: rgba(255, 255, 255, 0.3); }
|
||||
border-color: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 64em) {
|
||||
.btn {
|
||||
padding: 0.75rem 1rem; } }
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 42em) and (max-width: 64em) {
|
||||
.btn {
|
||||
padding: 0.6rem 0.9rem;
|
||||
font-size: 0.9rem; } }
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 42em) {
|
||||
.btn {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 0.75rem;
|
||||
font-size: 0.9rem; }
|
||||
.btn + .btn {
|
||||
margin-top: 1rem;
|
||||
margin-left: 0; } }
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.btn + .btn {
|
||||
margin-top: 1rem;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.page-header {
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
background-color: #159957;
|
||||
background-image: linear-gradient(120deg, #155799, #159957); }
|
||||
background-image: linear-gradient(120deg, #155799, #159957);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 64em) {
|
||||
.page-header {
|
||||
padding: 5rem 6rem; } }
|
||||
padding: 5rem 6rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 42em) and (max-width: 64em) {
|
||||
.page-header {
|
||||
padding: 3rem 4rem; } }
|
||||
padding: 3rem 4rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 42em) {
|
||||
.page-header {
|
||||
padding: 2rem 1rem; } }
|
||||
padding: 2rem 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.project-name {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.1rem; }
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 64em) {
|
||||
.project-name {
|
||||
font-size: 3.25rem; } }
|
||||
font-size: 3.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 42em) and (max-width: 64em) {
|
||||
.project-name {
|
||||
font-size: 2.25rem; } }
|
||||
font-size: 2.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 42em) {
|
||||
.project-name {
|
||||
font-size: 1.75rem; } }
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
.project-tagline {
|
||||
margin-bottom: 2rem;
|
||||
font-weight: normal;
|
||||
opacity: 0.7; }
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 64em) {
|
||||
.project-tagline {
|
||||
font-size: 1.25rem; } }
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 42em) and (max-width: 64em) {
|
||||
.project-tagline {
|
||||
font-size: 1.15rem; } }
|
||||
font-size: 1.15rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 42em) {
|
||||
.project-tagline {
|
||||
font-size: 1rem; } }
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.main-content :first-child {
|
||||
margin-top: 0; }
|
||||
margin-top: 0;
|
||||
}
|
||||
.main-content img {
|
||||
max-width: 100%; }
|
||||
.main-content h1, .main-content h2, .main-content h3, .main-content h4, .main-content h5, .main-content h6 {
|
||||
max-width: 100%;
|
||||
}
|
||||
.main-content h1,
|
||||
.main-content h2,
|
||||
.main-content h3,
|
||||
.main-content h4,
|
||||
.main-content h5,
|
||||
.main-content h6 {
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
font-weight: normal;
|
||||
color: #159957; }
|
||||
color: #159957;
|
||||
}
|
||||
.main-content p {
|
||||
margin-bottom: 1em; }
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
.main-content code {
|
||||
padding: 2px 4px;
|
||||
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
font-size: 0.9rem;
|
||||
color: #383e41;
|
||||
background-color: #f3f6fa;
|
||||
border-radius: 0.3rem; }
|
||||
border-radius: 0.3rem;
|
||||
}
|
||||
.main-content pre {
|
||||
padding: 0.8rem;
|
||||
margin-top: 0;
|
||||
|
@ -131,28 +176,35 @@ a {
|
|||
word-wrap: normal;
|
||||
background-color: #f3f6fa;
|
||||
border: solid 1px #dce6f0;
|
||||
border-radius: 0.3rem; }
|
||||
.main-content pre > code {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 0.9rem;
|
||||
color: #567482;
|
||||
word-break: normal;
|
||||
white-space: pre;
|
||||
background: transparent;
|
||||
border: 0; }
|
||||
border-radius: 0.3rem;
|
||||
}
|
||||
.main-content pre > code {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 0.9rem;
|
||||
color: #567482;
|
||||
word-break: normal;
|
||||
white-space: pre;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
}
|
||||
.main-content .highlight {
|
||||
margin-bottom: 1rem; }
|
||||
.main-content .highlight pre {
|
||||
margin-bottom: 0;
|
||||
word-break: normal; }
|
||||
.main-content .highlight pre, .main-content pre {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.main-content .highlight pre {
|
||||
margin-bottom: 0;
|
||||
word-break: normal;
|
||||
}
|
||||
.main-content .highlight pre,
|
||||
.main-content pre {
|
||||
padding: 0.8rem;
|
||||
overflow: auto;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.45;
|
||||
border-radius: 0.3rem; }
|
||||
.main-content pre code, .main-content pre tt {
|
||||
border-radius: 0.3rem;
|
||||
}
|
||||
.main-content pre code,
|
||||
.main-content pre tt {
|
||||
display: inline;
|
||||
max-width: initial;
|
||||
padding: 0;
|
||||
|
@ -161,85 +213,118 @@ a {
|
|||
line-height: inherit;
|
||||
word-wrap: normal;
|
||||
background-color: transparent;
|
||||
border: 0; }
|
||||
.main-content pre code:before, .main-content pre code:after, .main-content pre tt:before, .main-content pre tt:after {
|
||||
content: normal; }
|
||||
.main-content ul, .main-content ol {
|
||||
margin-top: 0; }
|
||||
border: 0;
|
||||
}
|
||||
.main-content pre code:before,
|
||||
.main-content pre code:after,
|
||||
.main-content pre tt:before,
|
||||
.main-content pre tt:after {
|
||||
content: normal;
|
||||
}
|
||||
.main-content ul,
|
||||
.main-content ol {
|
||||
margin-top: 0;
|
||||
}
|
||||
.main-content blockquote {
|
||||
padding: 0 1rem;
|
||||
margin-left: 0;
|
||||
color: #819198;
|
||||
border-left: 0.3rem solid #dce6f0; }
|
||||
.main-content blockquote > :first-child {
|
||||
margin-top: 0; }
|
||||
.main-content blockquote > :last-child {
|
||||
margin-bottom: 0; }
|
||||
border-left: 0.3rem solid #dce6f0;
|
||||
}
|
||||
.main-content blockquote > :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.main-content blockquote > :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.main-content table {
|
||||
display: block;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
word-break: normal;
|
||||
word-break: keep-all; }
|
||||
.main-content table th {
|
||||
font-weight: bold; }
|
||||
.main-content table th, .main-content table td {
|
||||
padding: 0.5rem 1rem;
|
||||
border: 1px solid #e9ebec; }
|
||||
word-break: keep-all;
|
||||
}
|
||||
.main-content table th {
|
||||
font-weight: bold;
|
||||
}
|
||||
.main-content table th,
|
||||
.main-content table td {
|
||||
padding: 0.5rem 1rem;
|
||||
border: 1px solid #e9ebec;
|
||||
}
|
||||
.main-content dl {
|
||||
padding: 0; }
|
||||
.main-content dl dt {
|
||||
padding: 0;
|
||||
margin-top: 1rem;
|
||||
font-size: 1rem;
|
||||
font-weight: bold; }
|
||||
.main-content dl dd {
|
||||
padding: 0;
|
||||
margin-bottom: 1rem; }
|
||||
padding: 0;
|
||||
}
|
||||
.main-content dl dt {
|
||||
padding: 0;
|
||||
margin-top: 1rem;
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
.main-content dl dd {
|
||||
padding: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.main-content hr {
|
||||
height: 2px;
|
||||
padding: 0;
|
||||
margin: 1rem 0;
|
||||
background-color: #eff0f1;
|
||||
border: 0; }
|
||||
border: 0;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 64em) {
|
||||
.main-content {
|
||||
max-width: 64rem;
|
||||
padding: 2rem 6rem;
|
||||
margin: 0 auto;
|
||||
font-size: 1.1rem; } }
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 42em) and (max-width: 64em) {
|
||||
.main-content {
|
||||
padding: 2rem 4rem;
|
||||
font-size: 1.1rem; } }
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 42em) {
|
||||
.main-content {
|
||||
padding: 2rem 1rem;
|
||||
font-size: 1rem; } }
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.site-footer {
|
||||
padding-top: 2rem;
|
||||
margin-top: 2rem;
|
||||
border-top: solid 1px #eff0f1; }
|
||||
border-top: solid 1px #eff0f1;
|
||||
}
|
||||
|
||||
.site-footer-owner {
|
||||
display: block;
|
||||
font-weight: bold; }
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.site-footer-credits {
|
||||
color: #819198; }
|
||||
color: #819198;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 64em) {
|
||||
.site-footer {
|
||||
font-size: 1rem; } }
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 42em) and (max-width: 64em) {
|
||||
.site-footer {
|
||||
font-size: 1rem; } }
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 42em) {
|
||||
.site-footer {
|
||||
font-size: 0.9rem; } }
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче