* Added doc lens links #227 * Test updates * Fix test * Update dependencies
This commit is contained in:
Родитель
87863de218
Коммит
2d06322c43
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -14,6 +14,18 @@ Continue reading to see the changes included in the latest version.
|
|||
|
||||
## Unreleased
|
||||
|
||||
What's changed since v2.0.0:
|
||||
|
||||
- New features:
|
||||
- **Experimental:** CodeLens provides links to open or create rule documentation.
|
||||
[#227](https://github.com/microsoft/PSRule-vscode/issues/227)
|
||||
- Link from rules allows markdown documentation to be created or edited.
|
||||
- When existing markdown documentation exists, file is opened in editor.
|
||||
- When documentation for a rule does not exist, a new file is created from a snippet.
|
||||
- Added settings to configure the location for storing documentation,
|
||||
and the snippet used to create documentation.
|
||||
- To use try this feature, install the preview channel with experimental features enabled.
|
||||
|
||||
## v2.0.0
|
||||
|
||||
What's changed since v1.7.0:
|
||||
|
|
41
README.md
41
README.md
|
@ -14,10 +14,24 @@ Channel | Description | Version/ downloads
|
|||
|
||||
## Features
|
||||
|
||||
### CodeLens
|
||||
|
||||
<p align="center">
|
||||
<img src="./docs/images/codelens-doc-link.png" alt="CodeLens showing link to create documentation" width="640px" />
|
||||
</p>
|
||||
|
||||
- CodeLens shows links to create or edit markdown documentation from rules in YAML, JSON, or PowerShell.
|
||||
- **Open documentation** — Opens rule markdown documentation in the editor.
|
||||
- The location for storing documentation is configurable in the extension settings.
|
||||
- By default, a locale specific folder is created in the same directory as the rule file.
|
||||
- **Create documentation** — Creates a new markdown file for the rule based on a snippet.
|
||||
- New markdown documentation is created with the built-in _Rule Doc_ snippet.
|
||||
- An alternative snippet can be specified by configuring extension settings.
|
||||
|
||||
### IntelliSense
|
||||
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/microsoft/PSRule-vscode/main/docs/images/options-schema-flyout.png" alt="Options suggestion context menu" />
|
||||
<img src="./docs/images/options-schema-flyout.png" alt="Options suggestion context menu" width="640px" />
|
||||
</p>
|
||||
|
||||
- Adds IntelliSense and validation support for configuring options and resources.
|
||||
|
@ -26,7 +40,7 @@ Channel | Description | Version/ downloads
|
|||
- **Create resources** — define _baselines_ and _selectors_ by using pre-built snippets and IntelliSense.
|
||||
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/microsoft/PSRule-vscode/main/docs/images/snippet-rule-type.png" alt="Rule definition snippet" />
|
||||
<img src="./docs/images/snippet-rule-type.png" alt="Rule definition snippet" width="520px" />
|
||||
</p>
|
||||
|
||||
- Adds snippets for defining new rules.
|
||||
|
@ -35,7 +49,7 @@ Channel | Description | Version/ downloads
|
|||
IntelliSense can also be triggered by using the shortcut `Ctrl+Space`.
|
||||
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/microsoft/PSRule-vscode/main/docs/images/snippet-markdown.png" alt="Rule markdown documentation snippet" />
|
||||
<img src="./docs/images/snippet-markdown.png" alt="Rule markdown documentation snippet" width="640px" />
|
||||
</p>
|
||||
|
||||
- Adds snippets for creating markdown documentation.
|
||||
|
@ -46,7 +60,7 @@ Channel | Description | Version/ downloads
|
|||
### Quick tasks
|
||||
|
||||
<p align="center">
|
||||
<img src="./docs/images/tasks-provider.png" alt="Built-in tasks shown in task list" />
|
||||
<img src="./docs/images/tasks-provider.png" alt="Built-in tasks shown in task list" width="640px" />
|
||||
</p>
|
||||
|
||||
- Adds quick tasks for analysis directly from Visual Studio Code.
|
||||
|
@ -59,13 +73,18 @@ Channel | Description | Version/ downloads
|
|||
|
||||
In addition to configuring the [ps-rule.yaml] options file, the following settings are available.
|
||||
|
||||
Name | Description
|
||||
---- | -----------
|
||||
`PSRule.execution.notProcessedWarning` | Warn when objects are not processed by any rule.
|
||||
`PSRule.experimental.enabled` | Enables experimental features in the PSRule extension.
|
||||
`PSRule.notifications.showChannelUpgrade` | Determines if a notification to switch to the stable channel is shown on start up.
|
||||
`PSRule.notifications.showPowerShellExtension` | Determines if a notification to install the PowerShell extension is shown on start up.
|
||||
`PSRule.output.as` | Configures the output of analysis tasks, either summary or detailed.
|
||||
Name | Description
|
||||
---- | -----------
|
||||
`PSRule.codeLens.ruleDocumentationLinks` | Enables Code Lens that displays links to rule documentation. This is an experimental feature that requires experimental features to be enabled.
|
||||
`PSRule.documentation.path` | The path to look for rule documentation. When not set, the path containing rules will be used.
|
||||
`PSRule.documentation.localePath` | The locale path to use for locating rule documentation. The VS Code locale will be used by default.
|
||||
`PSRule.documentation.customSnippetPath` | The path to a file containing a rule documentation snippet. When not set, built-in PSRule snippets will be used.
|
||||
`PSRule.documentation.snippet` | The name of a snippet to use when creating new rule documentation. By default, the built-in `Rule Doc` snippet will be used.
|
||||
`PSRule.execution.notProcessedWarning` | Warn when objects are not processed by any rule.
|
||||
`PSRule.experimental.enabled` | Enables experimental features in the PSRule extension.
|
||||
`PSRule.notifications.showChannelUpgrade` | Determines if a notification to switch to the stable channel is shown on start up.
|
||||
`PSRule.notifications.showPowerShellExtension` | Determines if a notification to install the PowerShell extension is shown on start up.
|
||||
`PSRule.output.as` | Configures the output of analysis tasks, either summary or detailed.
|
||||
|
||||
## Support
|
||||
|
||||
|
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 56 KiB |
|
@ -9,15 +9,17 @@
|
|||
"version": "0.0.1",
|
||||
"license": "SEE LICENSE IN LICENSE",
|
||||
"dependencies": {
|
||||
"fs-extra": "^10.0.0",
|
||||
"vscode-languageclient": "^7.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/fs-extra": "^9.0.13",
|
||||
"@types/glob": "^7.2.0",
|
||||
"@types/mocha": "^9.1.0",
|
||||
"@types/node": "^17.0.23",
|
||||
"@types/vscode": "1.66.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.17.0",
|
||||
"@typescript-eslint/parser": "^5.17.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.18.0",
|
||||
"@typescript-eslint/parser": "^5.18.0",
|
||||
"@vscode/test-electron": "^2.1.3",
|
||||
"ansi-regex": ">=6.0.1",
|
||||
"esbuild": "^0.14.34",
|
||||
|
@ -119,6 +121,15 @@
|
|||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/fs-extra": {
|
||||
"version": "9.0.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz",
|
||||
"integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/glob": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz",
|
||||
|
@ -1868,6 +1879,19 @@
|
|||
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fs-extra": {
|
||||
"version": "10.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz",
|
||||
"integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
|
@ -2063,8 +2087,7 @@
|
|||
"node_modules/graceful-fs": {
|
||||
"version": "4.2.10",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
|
||||
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="
|
||||
},
|
||||
"node_modules/growl": {
|
||||
"version": "1.10.5",
|
||||
|
@ -2135,6 +2158,18 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/hosted-git-info/node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/htmlparser2": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz",
|
||||
|
@ -2368,6 +2403,17 @@
|
|||
"integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/jsonfile": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
|
||||
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
|
||||
"dependencies": {
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/keytar": {
|
||||
"version": "7.9.0",
|
||||
"resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz",
|
||||
|
@ -2460,14 +2506,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"version": "7.7.3",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.3.tgz",
|
||||
"integrity": "sha512-WY9wjJNQt9+PZilnLbuFKM+SwDull9+6IAguOrarOMoOHTcJ9GnXSO11+Gw6c7xtDkBkthR57OZMtZKYr+1CEw==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/markdown-it": {
|
||||
|
@ -3220,17 +3263,17 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.3.5",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
|
||||
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
|
||||
"version": "7.3.6",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.6.tgz",
|
||||
"integrity": "sha512-HZWqcgwLsjaX1HBD31msI/rXktuIhS+lWvdE4kN9z+8IVT4Itc7vqU2WvYsyD6/sjYCt4dEKH/m1M3dwI9CC5w==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
"lru-cache": "^7.4.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
"node": "^10.0.0 || ^12.0.0 || ^14.0.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/serialize-javascript": {
|
||||
|
@ -3627,6 +3670,14 @@
|
|||
"integrity": "sha512-ekY1NhRzq0B08g4bGuX4wd2jZx5GnKz6mKSqFL4nqBlfyMGiG10gDFhDTMEfYmDL6Jy0FUIZp7wiRB+0BP7J2g==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/universalify": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
||||
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/unzipper": {
|
||||
"version": "0.10.11",
|
||||
"resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz",
|
||||
|
@ -3940,7 +3991,8 @@
|
|||
"node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/yargs": {
|
||||
"version": "16.2.0",
|
||||
|
@ -4106,6 +4158,15 @@
|
|||
"integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/fs-extra": {
|
||||
"version": "9.0.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz",
|
||||
"integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/glob": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz",
|
||||
|
@ -5289,6 +5350,16 @@
|
|||
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
|
||||
"dev": true
|
||||
},
|
||||
"fs-extra": {
|
||||
"version": "10.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz",
|
||||
"integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==",
|
||||
"requires": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
|
@ -5442,8 +5513,7 @@
|
|||
"graceful-fs": {
|
||||
"version": "4.2.10",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
|
||||
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="
|
||||
},
|
||||
"growl": {
|
||||
"version": "1.10.5",
|
||||
|
@ -5491,6 +5561,17 @@
|
|||
"dev": true,
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"htmlparser2": {
|
||||
|
@ -5660,6 +5741,15 @@
|
|||
"integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
|
||||
"dev": true
|
||||
},
|
||||
"jsonfile": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
|
||||
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.6",
|
||||
"universalify": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"keytar": {
|
||||
"version": "7.9.0",
|
||||
"resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz",
|
||||
|
@ -5733,12 +5823,9 @@
|
|||
}
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"requires": {
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
"version": "7.7.3",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.3.tgz",
|
||||
"integrity": "sha512-WY9wjJNQt9+PZilnLbuFKM+SwDull9+6IAguOrarOMoOHTcJ9GnXSO11+Gw6c7xtDkBkthR57OZMtZKYr+1CEw=="
|
||||
},
|
||||
"markdown-it": {
|
||||
"version": "12.3.2",
|
||||
|
@ -6288,11 +6375,11 @@
|
|||
"dev": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.3.5",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
|
||||
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
|
||||
"version": "7.3.6",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.6.tgz",
|
||||
"integrity": "sha512-HZWqcgwLsjaX1HBD31msI/rXktuIhS+lWvdE4kN9z+8IVT4Itc7vqU2WvYsyD6/sjYCt4dEKH/m1M3dwI9CC5w==",
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
"lru-cache": "^7.4.0"
|
||||
}
|
||||
},
|
||||
"serialize-javascript": {
|
||||
|
@ -6590,6 +6677,11 @@
|
|||
"integrity": "sha512-ekY1NhRzq0B08g4bGuX4wd2jZx5GnKz6mKSqFL4nqBlfyMGiG10gDFhDTMEfYmDL6Jy0FUIZp7wiRB+0BP7J2g==",
|
||||
"dev": true
|
||||
},
|
||||
"universalify": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
||||
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ=="
|
||||
},
|
||||
"unzipper": {
|
||||
"version": "0.10.11",
|
||||
"resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz",
|
||||
|
@ -6847,7 +6939,8 @@
|
|||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
},
|
||||
"yargs": {
|
||||
"version": "16.2.0",
|
||||
|
|
46
package.json
46
package.json
|
@ -53,10 +53,48 @@
|
|||
}
|
||||
},
|
||||
"contributes": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "PSRule.createOrEditDocumentation",
|
||||
"title": "Create or edit documentation",
|
||||
"shortTitle": "Edit documentation",
|
||||
"category": "PSRule"
|
||||
}
|
||||
],
|
||||
"configuration": [
|
||||
{
|
||||
"title": "PSRule",
|
||||
"properties": {
|
||||
"PSRule.codeLens.ruleDocumentationLinks": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enables Code Lens that displays links to rule documentation. This is an experimental feature that requires experimental features to be enabled.",
|
||||
"scope": "application"
|
||||
},
|
||||
"PSRule.documentation.path": {
|
||||
"type": "string",
|
||||
"default": null,
|
||||
"description": "The path to look for rule documentation. When not set, the path containing rules will be used.",
|
||||
"scope": "window"
|
||||
},
|
||||
"PSRule.documentation.localePath": {
|
||||
"type": "string",
|
||||
"default": null,
|
||||
"description": "The locale path to use for locating rule documentation. The VS Code locale will be used by default.",
|
||||
"scope": "window"
|
||||
},
|
||||
"PSRule.documentation.customSnippetPath": {
|
||||
"type": "string",
|
||||
"default": null,
|
||||
"description": "The path to a file containing a rule documentation snippet. When not set, built-in PSRule snippets will be used.",
|
||||
"scope": "window"
|
||||
},
|
||||
"PSRule.documentation.snippet": {
|
||||
"type": "string",
|
||||
"default": "Rule Doc",
|
||||
"markdownDescription": "The name of a snippet to use when creating new rule documentation. By default, the built-in `Rule Doc` snippet will be used.",
|
||||
"scope": "window"
|
||||
},
|
||||
"PSRule.execution.notProcessedWarning": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
|
@ -277,7 +315,8 @@
|
|||
"esbuild-watch": "npm run -S esbuild-base -- --sourcemap --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-languageclient": "^7.0.0"
|
||||
"vscode-languageclient": "^7.0.0",
|
||||
"fs-extra": "^10.0.0"
|
||||
},
|
||||
"extensionDependencies": [
|
||||
"vscode.powershell",
|
||||
|
@ -288,8 +327,9 @@
|
|||
"@types/mocha": "^9.1.0",
|
||||
"@types/node": "^17.0.23",
|
||||
"@types/vscode": "1.66.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.17.0",
|
||||
"@typescript-eslint/parser": "^5.17.0",
|
||||
"@types/fs-extra": "^9.0.13",
|
||||
"@typescript-eslint/eslint-plugin": "^5.18.0",
|
||||
"@typescript-eslint/parser": "^5.18.0",
|
||||
"esbuild": "^0.14.34",
|
||||
"eslint": "^8.12.0",
|
||||
"glob": "^7.2.0",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"rule-doc": {
|
||||
"Rule Doc": {
|
||||
"prefix": "rule",
|
||||
"description": "Rule documentation",
|
||||
"body": [
|
||||
|
@ -19,7 +19,7 @@
|
|||
""
|
||||
]
|
||||
},
|
||||
"rule-doc-extended": {
|
||||
"Rule Doc Extended": {
|
||||
"prefix": "rule",
|
||||
"description": "Extended rule documentation",
|
||||
"body": [
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import * as path from 'path';
|
||||
import * as fse from 'fs-extra';
|
||||
import { Position, TextDocument, Uri, window, workspace } from 'vscode';
|
||||
import { logger } from '../logger';
|
||||
import { getDocumentationPath, readDocumentationSnippet } from '../utils';
|
||||
import { configuration } from '../configuration';
|
||||
|
||||
const validNameExpression =
|
||||
/[^<>:/\\|?*"'`+@._\-\x00-\x1F][^<>:/\\|?*"'`+@\x00-\x1F]{1,126}[^<>:/\\|?*"'`+@._\-\x00-\x1F]+/g;
|
||||
|
||||
export async function createOrEditDocumentation(name: string | undefined): Promise<void> {
|
||||
if (name === '' || name === undefined) {
|
||||
name = await window.showInputBox({
|
||||
prompt: 'Enter the name of the rule to create documentation for.',
|
||||
validateInput: (value: string) => {
|
||||
return validNameExpression.test(value) ? undefined : 'Must be a valid rule name.';
|
||||
},
|
||||
});
|
||||
}
|
||||
if (name === '' || name === undefined) return;
|
||||
|
||||
let uri = await getDocumentationPath(name);
|
||||
|
||||
if (uri) {
|
||||
let parent = Uri.file(path.dirname(uri.fsPath));
|
||||
|
||||
logger.verbose(`Using documentation path ${uri.fsPath}`);
|
||||
|
||||
let exists = await fse.pathExists(uri.fsPath);
|
||||
if (!exists) {
|
||||
await fse.ensureDir(parent.fsPath);
|
||||
await fse.writeFile(uri.fsPath, '', { encoding: 'utf-8' });
|
||||
}
|
||||
const document: TextDocument = await workspace.openTextDocument(uri);
|
||||
const editor = await window.showTextDocument(document);
|
||||
|
||||
// Populate new documentation with a snippet
|
||||
const snippetConfig = configuration.get().documentationSnippet;
|
||||
const snippetPathConfig = configuration.get().documentationCustomSnippetPath;
|
||||
if (!exists && snippetConfig !== '') {
|
||||
let snippet = await readDocumentationSnippet(snippetPathConfig, snippetConfig);
|
||||
if (snippet) {
|
||||
editor.insertSnippet(snippet, new Position(0, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,21 +3,26 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
import { ConfigurationChangeEvent, ExtensionContext, workspace } from 'vscode';
|
||||
import { ConfigurationChangeEvent, ExtensionContext, env, workspace } from 'vscode';
|
||||
import { configurationItemPrefix } from './consts';
|
||||
|
||||
/**
|
||||
* The output of analysis tasks.
|
||||
*/
|
||||
export enum OutputAs {
|
||||
Detail = 0,
|
||||
Summary = 1,
|
||||
Detail = 'Detail',
|
||||
Summary = 'Summary',
|
||||
}
|
||||
|
||||
/**
|
||||
* PSRule extension settings.
|
||||
*/
|
||||
export interface ISetting {
|
||||
codeLensRuleDocumentationLinks: boolean;
|
||||
documentationCustomSnippetPath: string | undefined;
|
||||
documentationSnippet: string;
|
||||
documentationPath: string | undefined;
|
||||
documentationLocalePath: string;
|
||||
executionNotProcessedWarning: boolean;
|
||||
experimentalEnabled: boolean;
|
||||
outputAs: OutputAs;
|
||||
|
@ -29,6 +34,11 @@ export interface ISetting {
|
|||
* Default configuration for PSRule extension settings.
|
||||
*/
|
||||
const globalDefaults: ISetting = {
|
||||
codeLensRuleDocumentationLinks: true,
|
||||
documentationCustomSnippetPath: undefined,
|
||||
documentationSnippet: 'Rule Doc',
|
||||
documentationPath: undefined,
|
||||
documentationLocalePath: env.language,
|
||||
executionNotProcessedWarning: false,
|
||||
experimentalEnabled: false,
|
||||
outputAs: OutputAs.Summary,
|
||||
|
@ -50,7 +60,7 @@ export class ConfigurationManager {
|
|||
|
||||
constructor(setting?: ISetting) {
|
||||
this.default = setting ?? globalDefaults;
|
||||
this.current = this.default;
|
||||
this.current = { ...this.default };
|
||||
this.loadSettings();
|
||||
}
|
||||
|
||||
|
@ -82,23 +92,49 @@ export class ConfigurationManager {
|
|||
private loadSettings(): void {
|
||||
const config = workspace.getConfiguration(configurationItemPrefix);
|
||||
|
||||
// Experimental
|
||||
let experimental = (this.current.experimentalEnabled = config.get<boolean>(
|
||||
'experimental.enabled',
|
||||
this.default.experimentalEnabled
|
||||
));
|
||||
|
||||
// Read settings
|
||||
this.current.executionNotProcessedWarning =
|
||||
config.get<boolean>('execution.notProcessedWarning') ??
|
||||
this.default.executionNotProcessedWarning;
|
||||
this.current.documentationCustomSnippetPath =
|
||||
config.get<string>('documentation.customSnippetPath') ??
|
||||
this.default.documentationCustomSnippetPath;
|
||||
|
||||
this.current.experimentalEnabled =
|
||||
config.get<boolean>('experimental.enabled') ?? this.default.experimentalEnabled;
|
||||
this.current.documentationSnippet =
|
||||
config.get<string>('documentation.snippet') ?? this.default.documentationSnippet;
|
||||
|
||||
this.current.outputAs = config.get<OutputAs>('output.as') ?? this.default.outputAs;
|
||||
this.current.documentationPath =
|
||||
config.get<string>('documentation.path') ?? this.default.documentationPath;
|
||||
|
||||
this.current.notificationsShowChannelUpgrade =
|
||||
config.get<boolean>('notifications.showChannelUpgrade') ??
|
||||
this.default.notificationsShowChannelUpgrade;
|
||||
this.current.documentationLocalePath =
|
||||
config.get<string>('documentation.localePath') ?? this.default.documentationLocalePath;
|
||||
|
||||
this.current.notificationsShowPowerShellExtension =
|
||||
config.get<boolean>('notifications.showPowerShellExtension') ??
|
||||
this.default.notificationsShowPowerShellExtension;
|
||||
this.current.codeLensRuleDocumentationLinks = !experimental
|
||||
? false
|
||||
: config.get<boolean>(
|
||||
'codeLens.ruleDocumentationLinks',
|
||||
this.default.codeLensRuleDocumentationLinks
|
||||
);
|
||||
|
||||
this.current.executionNotProcessedWarning = config.get<boolean>(
|
||||
'execution.notProcessedWarning',
|
||||
this.default.executionNotProcessedWarning
|
||||
);
|
||||
|
||||
this.current.outputAs = config.get<OutputAs>('output.as', this.default.outputAs);
|
||||
|
||||
this.current.notificationsShowChannelUpgrade = config.get<boolean>(
|
||||
'notifications.showChannelUpgrade',
|
||||
this.default.notificationsShowChannelUpgrade
|
||||
);
|
||||
|
||||
this.current.notificationsShowPowerShellExtension = config.get<boolean>(
|
||||
'notifications.showPowerShellExtension',
|
||||
this.default.notificationsShowPowerShellExtension
|
||||
);
|
||||
|
||||
// Clear dirty settings flag
|
||||
this.pendingLoad = false;
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as fse from 'fs-extra';
|
||||
import {
|
||||
CancellationToken,
|
||||
CodeLens,
|
||||
CodeLensProvider,
|
||||
Command,
|
||||
Disposable,
|
||||
Event,
|
||||
EventEmitter,
|
||||
ExtensionContext,
|
||||
Position,
|
||||
Range,
|
||||
TextDocument,
|
||||
commands,
|
||||
languages,
|
||||
workspace,
|
||||
} from 'vscode';
|
||||
import { DocumentSelector } from 'vscode-languageclient';
|
||||
import { createOrEditDocumentation } from './commands/createOrEditDocumentation';
|
||||
import { configuration } from './configuration';
|
||||
import { ILogger } from './logger';
|
||||
import { getDocumentationPath } from './utils';
|
||||
|
||||
interface IContext {
|
||||
readonly logger: ILogger;
|
||||
readonly extensionContext: ExtensionContext;
|
||||
}
|
||||
|
||||
export class DocumentationLensProvider implements CodeLensProvider, Disposable {
|
||||
// Fields
|
||||
private readonly context: IContext;
|
||||
|
||||
private codeLenses: CodeLens[] = [];
|
||||
private regexPowerShell: RegExp;
|
||||
private regexYaml: RegExp;
|
||||
private regexJson: RegExp;
|
||||
private _registration: Disposable | undefined;
|
||||
private _onDidChangeCodeLenses: EventEmitter<void> = new EventEmitter<void>();
|
||||
public readonly onDidChangeCodeLenses: Event<void> = this._onDidChangeCodeLenses.event;
|
||||
|
||||
constructor(logger: ILogger, extensionContext: ExtensionContext) {
|
||||
this.context = { logger, extensionContext };
|
||||
this.regexPowerShell =
|
||||
/(?<rule>Rule )(?:-Name\s)?(?<name>['"]?[^<>:/\\|?*"'`+@._\-\x00-\x1F][^<>:/\\|?*"'`+@\x00-\x1F]{1,126}[^<>:/\\|?*"'`+@._\-\x00-\x1F]+['"]?)(?:.+)/gi;
|
||||
this.regexYaml =
|
||||
/(?<version>apiVersion: github\.com\/microsoft\/PSRule\/v1)(?:\s+kind: Rule\s+metadata:\s+)(?: name: ?)(?<name>['"]?[^<>:/\\|?*"'`+@._\-\x00-\x1F][^<>:/\\|?*"'`+@\x00-\x1F]{1,126}[^<>:/\\|?*"'`+@._\-\x00-\x1F]+['"]?)/gi;
|
||||
this.regexJson =
|
||||
/("apiVersion":\s*"github\.com\/microsoft\/PSRule\/v1",)(?:\s*"kind":\s*"Rule",\s*"metadata":\s*{\s*)(?:"name":\s)(?<name>"[^<>:/\\|?*"'`+@._\-\x00-\x1F][^<>:/\\|?*"'`+@\x00-\x1F]{1,126}[^<>:/\\|?*"'`+@._\-\x00-\x1F]+")/gi;
|
||||
|
||||
workspace.onDidChangeConfiguration((_) => {
|
||||
this._onDidChangeCodeLenses.fire();
|
||||
});
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._registration?.dispose();
|
||||
}
|
||||
|
||||
public register(): void {
|
||||
let filter: DocumentSelector = [
|
||||
{ language: 'yaml', pattern: '**/*.Rule.yaml' },
|
||||
{ language: 'json', pattern: '**/*.Rule.json' },
|
||||
{ language: 'jsonc', pattern: '**/*.Rule.jsonc' },
|
||||
{ language: 'powershell', pattern: '**/*.Rule.ps1' },
|
||||
];
|
||||
this._registration = languages.registerCodeLensProvider(filter, this);
|
||||
commands.registerCommand('PSRule.createOrEditDocumentation', (name: string) => {
|
||||
createOrEditDocumentation(name);
|
||||
});
|
||||
}
|
||||
|
||||
public async provideCodeLenses(
|
||||
document: TextDocument,
|
||||
token: CancellationToken
|
||||
): Promise<CodeLens[]> {
|
||||
if (configuration.get().codeLensRuleDocumentationLinks) {
|
||||
const regex = this.getLanguageExpression(document.languageId);
|
||||
if (regex === undefined) return [];
|
||||
|
||||
this.codeLenses = [];
|
||||
const text = document.getText();
|
||||
let matches;
|
||||
while ((matches = regex.exec(text)) !== null) {
|
||||
let name =
|
||||
matches.groups !== undefined ? matches.groups['name'].replace(/\'/g, '') : '';
|
||||
const line = document.lineAt(document.positionAt(matches.index).line);
|
||||
const indexOf = line.text.indexOf(matches[1]);
|
||||
const position = new Position(line.lineNumber, indexOf);
|
||||
const range = document.getWordRangeAtPosition(position);
|
||||
if (range && name) {
|
||||
this.codeLenses.push(await this.createCodeLens(range, name));
|
||||
}
|
||||
}
|
||||
return this.codeLenses;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
private getLanguageExpression(language: string): RegExp | undefined {
|
||||
if (language === 'powershell') return this.regexPowerShell;
|
||||
if (language === 'yaml') return this.regexYaml;
|
||||
if (language === 'json' || language === 'jsonc') return this.regexJson;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a rule code lens.
|
||||
* @param range The range in the document the code lens applies to.
|
||||
* @param name The name of the rule.
|
||||
* @returns A code lens object.
|
||||
*/
|
||||
private async createCodeLens(range: Range, name: string): Promise<CodeLens> {
|
||||
let uri = await getDocumentationPath(name);
|
||||
let exists = uri !== undefined && (await fse.pathExists(uri.fsPath));
|
||||
let title = exists ? 'Open documentation' : 'Create documentation';
|
||||
let tooltip = exists ? 'Open documentation for rule' : 'Create documentation for rule';
|
||||
|
||||
return new CodeLens(range, {
|
||||
title: title,
|
||||
tooltip: tooltip,
|
||||
command: 'PSRule.createOrEditDocumentation',
|
||||
arguments: [name],
|
||||
});
|
||||
}
|
||||
|
||||
public async resolveCodeLens(
|
||||
codeLens: CodeLens,
|
||||
token: CancellationToken
|
||||
): Promise<CodeLens | undefined> {
|
||||
return undefined;
|
||||
}
|
||||
}
|
|
@ -9,13 +9,16 @@ import { logger } from './logger';
|
|||
import { PSRuleTaskProvider } from './tasks';
|
||||
import { ConfigurationManager } from './configuration';
|
||||
import { pwsh } from './powershell';
|
||||
import { DocumentationLensProvider } from './docLens';
|
||||
|
||||
export let taskManager: PSRuleTaskProvider | undefined;
|
||||
export let docLensProvider: DocumentationLensProvider | undefined;
|
||||
|
||||
export interface ExtensionInfo {
|
||||
id: string;
|
||||
version: string;
|
||||
channel: string;
|
||||
path: string;
|
||||
}
|
||||
|
||||
export class ExtensionManager implements vscode.Disposable {
|
||||
|
@ -52,6 +55,9 @@ export class ExtensionManager implements vscode.Disposable {
|
|||
}
|
||||
|
||||
public dispose(): void {
|
||||
if (docLensProvider) {
|
||||
docLensProvider.dispose();
|
||||
}
|
||||
if (taskManager) {
|
||||
taskManager.dispose();
|
||||
}
|
||||
|
@ -77,6 +83,11 @@ export class ExtensionManager implements vscode.Disposable {
|
|||
private switchMode(): void {
|
||||
ConfigurationManager.configure(this._context);
|
||||
|
||||
if (!docLensProvider) {
|
||||
docLensProvider = new DocumentationLensProvider(logger, this._context);
|
||||
docLensProvider.register();
|
||||
}
|
||||
|
||||
if (this.isTrusted) {
|
||||
pwsh.configure(this._info);
|
||||
}
|
||||
|
@ -160,6 +171,7 @@ export class ExtensionManager implements vscode.Disposable {
|
|||
id: extensionId,
|
||||
version: extensionVersion,
|
||||
channel: extensionChannel,
|
||||
path: context.extensionPath,
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -299,7 +299,7 @@ export class PSRuleTaskProvider implements vscode.TaskProvider {
|
|||
shellArgs: ['-NoLogo', '-NoProfile', '-NonInteractive', '-Command'],
|
||||
env: {
|
||||
PSRULE_OUTPUT_STYLE: 'VisualStudioCode',
|
||||
PSRULE_OUTPUT_AS: outputAs.toString(),
|
||||
PSRULE_OUTPUT_AS: outputAs,
|
||||
PSRULE_OUTPUT_CULTURE: vscode.env.language,
|
||||
PSRULE_OUTPUT_BANNER: 'Minimal',
|
||||
PSRULE_EXECUTION_NOTPROCESSEDWARNING: executionNotProcessedWarning
|
||||
|
|
|
@ -1,15 +1,22 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import * as assert from 'assert/strict';
|
||||
import { configuration, OutputAs } from '../../configuration';
|
||||
import * as assert from 'assert';
|
||||
import { configuration, ConfigurationManager, ISetting, OutputAs } from '../../configuration';
|
||||
|
||||
suite('ConfigurationManager tests', () => {
|
||||
test('Defaults', () => {
|
||||
assert.strictEqual(configuration.get().executionNotProcessedWarning, false);
|
||||
assert.strictEqual(configuration.get().experimentalEnabled, false);
|
||||
assert.strictEqual<OutputAs>(configuration.get().outputAs, OutputAs.Summary);
|
||||
assert.strictEqual(configuration.get().notificationsShowChannelUpgrade, true);
|
||||
assert.strictEqual(configuration.get().notificationsShowPowerShellExtension, true);
|
||||
const config = new ConfigurationManager(undefined);
|
||||
|
||||
assert.equal(config.get().codeLensRuleDocumentationLinks, false);
|
||||
assert.equal(config.get().documentationCustomSnippetPath, undefined);
|
||||
assert.equal(config.get().documentationLocalePath, 'en');
|
||||
assert.equal(config.get().documentationPath, undefined);
|
||||
assert.equal(config.get().documentationSnippet, 'Rule Doc');
|
||||
assert.equal(config.get().executionNotProcessedWarning, false);
|
||||
assert.equal(config.get().experimentalEnabled, false);
|
||||
assert.equal(config.get().outputAs, OutputAs.Summary);
|
||||
assert.equal(config.get().notificationsShowChannelUpgrade, true);
|
||||
assert.equal(config.get().notificationsShowPowerShellExtension, true);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import * as fse from 'fs-extra';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import { SnippetString, Uri, WorkspaceFolder, window, workspace } from 'vscode';
|
||||
import { configuration } from './configuration';
|
||||
import { ext } from './extension';
|
||||
|
||||
/**
|
||||
* Calculates the file path of rule documentation for a specific rule based on settings.
|
||||
* @param name The name of the rule.
|
||||
* @returns The path where the rule markdown documentation should be created/ edited from.
|
||||
*/
|
||||
export async function getDocumentationPath(name: string): Promise<Uri | undefined> {
|
||||
const workspaceRoot = getActiveOrFirstWorkspace()?.uri;
|
||||
const docConfigPath = configuration.get().documentationPath;
|
||||
let docRootPath =
|
||||
docConfigPath && workspaceRoot ? path.join(workspaceRoot.fsPath, docConfigPath) : undefined;
|
||||
let lang = configuration.get().documentationLocalePath;
|
||||
|
||||
if (!docRootPath && window.activeTextEditor?.document.uri) {
|
||||
docRootPath = path.dirname(window.activeTextEditor.document.uri.path);
|
||||
}
|
||||
if (docRootPath) {
|
||||
let uri = Uri.file(path.join(docRootPath, lang, `${name}.md`));
|
||||
return uri;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a snippet from disk.
|
||||
* @param file The path to a file containing a snippet. When not set, the default extension snippets will be used.
|
||||
* @param name The name of the snippet to use. When name is an empty string no snippet is returned.
|
||||
* @returns A possible matching snippet string.
|
||||
*/
|
||||
export async function readDocumentationSnippet(
|
||||
file: string | undefined,
|
||||
name: string
|
||||
): Promise<SnippetString | undefined> {
|
||||
if (name === '') return undefined;
|
||||
|
||||
// Try custom snippet file
|
||||
const workspaceRoot = getActiveOrFirstWorkspace()?.uri;
|
||||
let snippetFile = file && workspaceRoot ? path.join(workspaceRoot.fsPath, file) : undefined;
|
||||
|
||||
// Try built-in snippet file
|
||||
if (!snippetFile) {
|
||||
const info = await ext.info;
|
||||
snippetFile = info ? path.join(info.path, 'snippets/markdown.json') : undefined;
|
||||
}
|
||||
|
||||
if (snippetFile && (await fse.pathExists(snippetFile))) {
|
||||
let json = await fse.readJson(snippetFile, { encoding: 'utf-8' });
|
||||
if (json) {
|
||||
let body: string[] = json[name].body;
|
||||
return new SnippetString(body.join(os.EOL));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getActiveOrFirstWorkspace(): WorkspaceFolder | undefined {
|
||||
if (window.activeTextEditor) {
|
||||
return workspace.getWorkspaceFolder(window.activeTextEditor.document.uri);
|
||||
}
|
||||
return workspace.workspaceFolders && workspace.workspaceFolders.length > 0
|
||||
? workspace.workspaceFolders[0]
|
||||
: undefined;
|
||||
}
|
Загрузка…
Ссылка в новой задаче