This commit is contained in:
Timothee Guerin 2020-12-01 16:21:38 -08:00
Родитель 43fea261a0
Коммит 2a9ab1fde5
65 изменённых файлов: 2776 добавлений и 2058 удалений

Просмотреть файл

@ -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

65
.github/workflows/codeql.yml поставляемый
Просмотреть файл

@ -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"

Просмотреть файл

@ -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"

Просмотреть файл

@ -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";

Просмотреть файл

@ -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;
}
}