diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 00000000..b9ca537b
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,14 @@
+name: CI
+
+on:
+ pull_request:
+ branches: [ $default-branch ]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ - run: node ./.scripts/validate.js
\ No newline at end of file
diff --git a/.scripts/samples.js b/.scripts/samples.js
index 4767b57c..f81914d6 100644
--- a/.scripts/samples.js
+++ b/.scripts/samples.js
@@ -164,16 +164,14 @@ const samples = [
{
description: 'webpack-sample',
path: 'webpack-sample',
- excludeFromReadme: true,
- guide: null,
+ guide: '/api/working-with-extensions/bundling-extension',
apis: [],
contributions: []
},
{
description: 'esbuild-sample',
path: 'esbuild-sample',
- excludeFromReadme: true,
- guide: null,
+ guide: '/api/working-with-extensions/bundling-extension',
apis: [],
contributions: []
},
@@ -276,6 +274,20 @@ const samples = [
apis: [],
contributions: []
},
+ {
+ description: 'Chat Sample',
+ path: 'chat-sample',
+ guide: null,
+ apis: [],
+ contributions: []
+ },
+ {
+ description: 'Notifications Sample',
+ path: 'notifications-sample',
+ guide: null,
+ apis: [],
+ contributions: []
+ },
{ description: 'configuration-sample', excludeFromReadme: true, path: 'configuration-sample', guide: null, apis: [], contributions: [] },
{ description: 'contentprovider-sample', excludeFromReadme: true, path: 'contentprovider-sample', guide: null, apis: [], contributions: [] },
{ description: 'nodefs-provider-sample', excludeFromReadme: true, path: 'nodefs-provider-sample', guide: null, apis: [], contributions: [] },
@@ -285,10 +297,14 @@ const samples = [
{ description: 'fsconsumer-sample', excludeFromReadme: true, path: 'fsconsumer-sample', guide: null, apis: [], contributions: [] },
{ description: 'github-authentication-sample', excludeFromReadme: true, path: 'github-authentication-sample', guide: null, apis: [], contributions: [] },
{ description: 'helloworld-sample', excludeFromReadme: true, path: 'helloworld-sample', guide: null, apis: [], contributions: [] },
+ { description: 'helloworld-minimal-sample', excludeFromReadme: true, path: 'helloworld-minimal-sample', guide: null, apis: [], contributions: [] },
{ description: 'helloworld-test-sample', excludeFromReadme: true, path: 'helloworld-test-sample', guide: null, apis: [], contributions: [] },
{ description: 'helloworld-web-sample', excludeFromReadme: true, path: 'helloworld-web-sample', guide: null, apis: [], contributions: [] },
+ { description: 'helloworld-test-cli-sample', excludeFromReadme: true, path: 'helloworld-test-cli-sample', guide: null, apis: [], contributions: [] },
{ description: 'inline-completions', excludeFromReadme: true, path: 'inline-completions', guide: null, apis: [], contributions: [] },
{ description: 'notebook-renderer-react-sample', excludeFromReadme: true, path: 'notebook-renderer-react-sample', guide: null, apis: [], contributions: [] },
+ { description: 'notebook-format-code-action-sample', excludeFromReadme: true, path: 'notebook-format-code-action-sample', guide: null, apis: [], contributions: [] },
+ { description: 'notebook-serializer-sample', excludeFromReadme: true, path: 'notebook-serializer-sample', guide: null, apis: [], contributions: [] },
{ description: 'proposed-api-sample', excludeFromReadme: true, path: 'proposed-api-sample', guide: null, apis: [], contributions: [] },
{ description: 'virtual-document-sample', excludeFromReadme: true, path: 'virtual-document-sample', guide: null, apis: [], contributions: [] },
{ description: 'welcome-view-content-sample', excludeFromReadme: true, path: 'welcome-view-content-sample', guide: null, apis: [], contributions: [] },
@@ -296,6 +312,10 @@ const samples = [
{ description: 'drop-on-document', excludeFromReadme: true, path: 'drop-on-document', guide: null, apis: [], contributions: [] },
{ description: 'uri-handler-sample', excludeFromReadme: true, path: 'uri-handler-sample', guide: null, apis: [], contributions: [] },
{ description: 'authenticationprovider-sample', excludeFromReadme: true, path: 'authenticationprovider-sample', guide: null, apis: [], contributions: [] },
+ { description: 'jupyter-kernel-execution-sample', excludeFromReadme: true, path: 'jupyter-kernel-execution-sample', guide: null, apis: [], contributions: [] },
+ { description: 'shell-integration-sample', excludeFromReadme: true, path: 'shell-integration-sample', guide: null, apis: [], contributions: [] },
+ { description: 'tabs-api-sample', excludeFromReadme: true, path: 'tabs-api-sample', guide: null, apis: [], contributions: [] },
+ { description: 'telemetry-sample', excludeFromReadme: true, path: 'telemetry-sample', guide: null, apis: [], contributions: [] },
]
/** LSP specific samples */
@@ -344,6 +364,13 @@ const lspSamples = [
apis: [],
contributions: []
},
+ {
+ description: 'LSP User Input Sample',
+ path: 'lsp-user-input-sample',
+ guide: null,
+ apis: [],
+ contributions: []
+ },
]
/**
* LSP specific samples
diff --git a/.scripts/update-readme.js b/.scripts/update-readme.js
index 436c6dad..440176f1 100644
--- a/.scripts/update-readme.js
+++ b/.scripts/update-readme.js
@@ -1,5 +1,5 @@
+// @ts-check
const fs = require('fs')
-
const { samples, lspSamples } = require('./samples')
const TABLE_HEAD = `
@@ -12,46 +12,66 @@ const LSP_TABLE_HEAD = `
const LSP_TABLE_END = ``
const getTableRow = sample => {
- const descriptionCell = `[${sample.description}](https://github.com/Microsoft/vscode-extension-samples/tree/main/${sample.path})`
- let guideCell
- if (!sample.guide) {
- guideCell = 'N/A'
- } else if (sample.guide && sample.guide.startsWith('http')) {
- guideCell = sample.guide
- } else {
- guideCell = `[${sample.guide}](https://code.visualstudio.com${sample.guide})`
- }
+ const descriptionCell = `[${sample.description}](https://github.com/Microsoft/vscode-extension-samples/tree/main/${sample.path})`
+ let guideCell
+ if (!sample.guide) {
+ guideCell = 'N/A'
+ } else if (sample.guide && sample.guide.startsWith('http')) {
+ guideCell = sample.guide
+ } else {
+ guideCell = `[${sample.guide}](https://code.visualstudio.com${sample.guide})`
+ }
- const apis = sample.apis.map(api => {
- return `[${api}](https://code.visualstudio.com/api/references/vscode-api#${api})`
- })
- const contributions = sample.contributions.map(c => {
- return `[contributes.${c}](https://code.visualstudio.com/api/references/contribution-points#contributes.${c})`
- })
- const apiAndContributionCell = apis.concat(contributions).join('
')
+ const apis = sample.apis.map(api => {
+ return `[${api}](https://code.visualstudio.com/api/references/vscode-api#${api})`
+ })
+ const contributions = sample.contributions.map(c => {
+ return `[contributes.${c}](https://code.visualstudio.com/api/references/contribution-points#contributes.${c})`
+ })
+ const apiAndContributionCell = apis.concat(contributions).join('
')
- return `| ${descriptionCell} | ${guideCell} | ${apiAndContributionCell} |`
+ return `| ${descriptionCell} | ${guideCell} | ${apiAndContributionCell} |`
}
const getSamplesTable = samples => {
- const samplesMd = samples.map(s => getTableRow(s)).join('\n')
+ const samplesMd = samples.map(s => getTableRow(s)).join('\n')
- return `${TABLE_HEAD.trim()}
+ return `${TABLE_HEAD.trim()}
${samplesMd}
${TABLE_END.trim()}`
}
const getLSPSamplesTable = samples => {
- const samplesMd = samples.map(s => getTableRow(s)).join('\n')
+ const samplesMd = samples.map(s => getTableRow(s)).join('\n')
- return `${LSP_TABLE_HEAD.trim()}
+ return `${LSP_TABLE_HEAD.trim()}
${samplesMd}
${LSP_TABLE_END.trim()}`
}
-const readme = fs.readFileSync('README.md', 'utf-8')
-const newReadme = readme
- .replace(/(.|\n)*/gm, getSamplesTable(samples.filter(x => !x.excludeFromReadme)))
- .replace(/(.|\n)*/gm, getLSPSamplesTable(lspSamples))
+/**
+ * Update the README with the latest samples.
+ *
+ * @returns {boolean} true if the README was updated, false otherwise.
+ */
+function updateReadme(dryRun = false) {
+ const readme = fs.readFileSync('README.md', 'utf-8')
+ const newReadme = readme
+ .replace(/(.|\n)*/gm, getSamplesTable(samples.filter(x => !x.excludeFromReadme)))
+ .replace(/(.|\n)*/gm, getLSPSamplesTable(lspSamples))
-fs.writeFileSync('README.md', newReadme)
+ if (readme !== newReadme) {
+ if (!dryRun) {
+ fs.writeFileSync('README.md', newReadme)
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+exports.updateReadme = updateReadme;
+
+if (require.main === module) {
+ updateReadme();
+}
diff --git a/.scripts/validate.js b/.scripts/validate.js
new file mode 100644
index 00000000..10b8294e
--- /dev/null
+++ b/.scripts/validate.js
@@ -0,0 +1,43 @@
+// @ts-check
+const path = require('path');
+
+const { samples, lspSamples } = require('./samples');
+const fs = require('fs');
+
+const root = path.join(__dirname, '..');
+
+/**
+ * Validates that all samples are correctly listed in `.scripts/samples.js`.
+ */
+function validateSamplesAreListed() {
+ const allSamples = samples.concat(lspSamples);
+
+ const samplesByPath = new Map();
+ for (const sample of allSamples) {
+ samplesByPath.set(sample.path, sample);
+ }
+
+ for (const fileName of fs.readdirSync(root)) {
+ if (!fileName.endsWith('-sample') || fileName.startsWith('.')) {
+ continue;
+ }
+
+ const sampleEntry = samplesByPath.get(fileName);
+ if (!sampleEntry) {
+ throw new Error(`Sample '${fileName}' is not listed in samples.js`);
+ }
+ }
+}
+
+/**
+ * Validates that all samples are correctly listed in `.scripts/samples.js`.
+ */
+function validateReadmeUpdated() {
+ const { updateReadme } = require('./update-readme');
+ if (updateReadme(true)) {
+ throw new Error(`Readme not updated. Run 'node .scripts/update-readme.js' to update the readme.`);
+ }
+}
+
+validateSamplesAreListed();
+validateReadmeUpdated();
\ No newline at end of file
diff --git a/README.md b/README.md
index 749073dc..7f38a057 100644
--- a/README.md
+++ b/README.md
@@ -51,8 +51,8 @@ You need to have [node](https://nodejs.org/en/) and [npm](https://nodejs.org/en/
| [Color Theme Sample](https://github.com/Microsoft/vscode-extension-samples/tree/main/theme-sample) | [/api/extension-guides/color-theme](https://code.visualstudio.com/api/extension-guides/color-theme) | [contributes.themes](https://code.visualstudio.com/api/references/contribution-points#contributes.themes) |
| [Product Icon Theme Sample](https://github.com/Microsoft/vscode-extension-samples/tree/main/product-icon-theme-sample) | [/api/extension-guides/product-icon-theme](https://code.visualstudio.com/api/extension-guides/product-icon-theme) | [contributes.productIconThemes](https://code.visualstudio.com/api/references/contribution-points#contributes.productIconThemes) |
| [Vim Sample](https://github.com/Microsoft/vscode-extension-samples/tree/main/vim-sample) | N/A | [commands](https://code.visualstudio.com/api/references/vscode-api#commands)
[StatusBarItem](https://code.visualstudio.com/api/references/vscode-api#StatusBarItem)
[window.createStatusBarItem](https://code.visualstudio.com/api/references/vscode-api#window.createStatusBarItem)
[TextEditorCursorStyle](https://code.visualstudio.com/api/references/vscode-api#TextEditorCursorStyle)
[window.activeTextEditor](https://code.visualstudio.com/api/references/vscode-api#window.activeTextEditor)
[Position](https://code.visualstudio.com/api/references/vscode-api#Position)
[Range](https://code.visualstudio.com/api/references/vscode-api#Range)
[Selection](https://code.visualstudio.com/api/references/vscode-api#Selection)
[TextEditor](https://code.visualstudio.com/api/references/vscode-api#TextEditor)
[TextEditorRevealType](https://code.visualstudio.com/api/references/vscode-api#TextEditorRevealType)
[TextDocument](https://code.visualstudio.com/api/references/vscode-api#TextDocument) |
-| [webpack-sample](https://github.com/Microsoft/vscode-extension-samples/tree/main/webpack-sample) | [api/working-with-extensions/bundling-extension](https://code.visualstudio.com/api/working-with-extensions/bundling-extension) | |
-| [esbuild-sample](https://github.com/Microsoft/vscode-extension-samples/tree/main/esbuild-sample) | [api/working-with-extensions/bundling-extension](https://code.visualstudio.com/api/working-with-extensions/bundling-extension) | |
+| [webpack-sample](https://github.com/Microsoft/vscode-extension-samples/tree/main/webpack-sample) | [/api/working-with-extensions/bundling-extension](https://code.visualstudio.com/api/working-with-extensions/bundling-extension) | |
+| [esbuild-sample](https://github.com/Microsoft/vscode-extension-samples/tree/main/esbuild-sample) | [/api/working-with-extensions/bundling-extension](https://code.visualstudio.com/api/working-with-extensions/bundling-extension) | |
| [Source Control Sample](https://github.com/Microsoft/vscode-extension-samples/tree/main/source-control-sample) | [/api/extension-guides/scm-provider](https://code.visualstudio.com/api/extension-guides/scm-provider) | [workspace.workspaceFolders](https://code.visualstudio.com/api/references/vscode-api#workspace.workspaceFolders)
[SourceControl](https://code.visualstudio.com/api/references/vscode-api#SourceControl)
[SourceControlResourceGroup](https://code.visualstudio.com/api/references/vscode-api#SourceControlResourceGroup)
[scm.createSourceControl](https://code.visualstudio.com/api/references/vscode-api#scm.createSourceControl)
[TextDocumentContentProvider](https://code.visualstudio.com/api/references/vscode-api#TextDocumentContentProvider)
[contributes.menus](https://code.visualstudio.com/api/references/contribution-points#contributes.menus) |
| [Commenting API Sample](https://github.com/Microsoft/vscode-extension-samples/tree/main/comment-sample) | N/A | |
| [Document Editing Sample](https://github.com/Microsoft/vscode-extension-samples/tree/main/document-editing-sample) | N/A | [commands](https://code.visualstudio.com/api/references/vscode-api#commands) |
@@ -65,6 +65,9 @@ You need to have [node](https://nodejs.org/en/) and [npm](https://nodejs.org/en/
| [Getting Started Sample](https://github.com/Microsoft/vscode-extension-samples/tree/main/getting-started-sample) | N/A | |
| [notebook-renderer-sample](https://github.com/Microsoft/vscode-extension-samples/tree/main/notebook-renderer-sample) | [/api/extension-guides/notebook#notebook-renderer](https://code.visualstudio.com/api/extension-guides/notebook#notebook-renderer) | [contributes.notebookRenderer](https://code.visualstudio.com/api/references/contribution-points#contributes.notebookRenderer) |
| [notebook-extend-markdown-renderer-sample](https://github.com/Microsoft/vscode-extension-samples/tree/main/notebook-extend-markdown-renderer-sample) | [/api/extension-guides/notebook#notebook-renderer](https://code.visualstudio.com/api/extension-guides/notebook#notebook-renderer) | [contributes.notebookRenderer](https://code.visualstudio.com/api/references/contribution-points#contributes.notebookRenderer) |
+| [jupyter-server-provider-sample](https://github.com/Microsoft/vscode-extension-samples/tree/main/jupyter-server-provider-sample) | N/A | |
+| [Chat Sample](https://github.com/Microsoft/vscode-extension-samples/tree/main/chat-sample) | N/A | |
+| [Notifications Sample](https://github.com/Microsoft/vscode-extension-samples/tree/main/notifications-sample) | N/A | |
### Language Server Protocol Samples
@@ -78,6 +81,7 @@ You need to have [node](https://nodejs.org/en/) and [npm](https://nodejs.org/en/
| [LSP Log Streaming Sample](https://github.com/Microsoft/vscode-extension-samples/tree/main/lsp-log-streaming-sample) | N/A | |
| [LSP Multi Root Server Sample](https://github.com/Microsoft/vscode-extension-samples/tree/main/lsp-multi-server-sample) | https://github.com/Microsoft/vscode/wiki/Extension-Authoring:-Adopting-Multi-Root-Workspace-APIs#language-client--language-server | |
| [LSP Web Extension Sample](https://github.com/Microsoft/vscode-extension-samples/tree/main/lsp-web-extension-sample) | [/api/language-extensions/language-server-extension-guide](https://code.visualstudio.com/api/language-extensions/language-server-extension-guide) | |
+| [LSP User Input Sample](https://github.com/Microsoft/vscode-extension-samples/tree/main/lsp-user-input-sample) | N/A | |
## License