Skip to content

Commit 3f6cdcb

Browse files
authored
feat: migrate to W3C Spec Generator API and implement error handling for validation failures (#9)
* ci: add automated release workflow and bump version to 0.0.3 * feat: migrate to W3C Spec Generator API and implement error handling for validation failures * feat: add vsce package dependency and build script for extension packaging * style: fix indentation and formatting in release workflow YAML * ci: update release workflow to trigger on tag creation
1 parent 4f10015 commit 3f6cdcb

4 files changed

Lines changed: 3567 additions & 302 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ This plugin is currently in Beta and under active development. There may be bugs
99
## Features
1010

1111
- Bikeshed side-by-side preview within Visual Studio Code. Bring up Visual Studio Code [Command Palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) (⇧⌘P on Macs) and select `Open Bikeshed Preview` while editing a Bikeshed file.
12-
- Compilation support via [local Bikeshed install](https://speced.github.io/bikeshed/#installing) or through [a remote CGI](https://api.csswg.org/bikeshed/).
12+
- Compilation support via [local Bikeshed install](https://speced.github.io/bikeshed/#installing) or through the [W3C Spec Generator](https://www.w3.org/publications/spec-generator/).
1313
- IntelliSense / autocompletion support for W3C webref definitions and definitions within the document.
1414

1515
## Requirements
@@ -23,7 +23,7 @@ This extension contributes the following settings:
2323
- `visualBikeshed.autoUpdate`: Automatically update the preview when the document changes.
2424
- `visualBikeshed.compilerOption`: Selects a compilation method (URL or Bikeshed binary path).
2525
- `visualBikeshed.commandPath`: Path to the Bikeshed binary, for local compilation.
26-
- `visualBikeshed.processorUrl`: URL of the Bikeshed processor (defaults to `https://api.csswg.org/bikeshed/`).
26+
- `visualBikeshed.processorUrl`: URL of the Bikeshed processor (defaults to `https://www.w3.org/publications/spec-generator/`).
2727

2828
## Known Issues
2929

client/src/extension-preview.ts

Lines changed: 59 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ import { parseStringPromise } from 'xml2js';
1111

1212
const PREVIEW_UPDATE_DEBOUNCE_TIME = 500;
1313

14+
type SpecGeneratorError = {
15+
lineNum: string | null;
16+
messageType: 'fatal' | 'warning' | 'linkerror' | 'message' | 'failure';
17+
text: string;
18+
};
19+
1420
type BikeshedErrorOutput = {
1521
root: {
1622
warning?: string[];
@@ -39,7 +45,7 @@ async function updateWebview(
3945
const commandPath = config.get<string>('commandPath', 'bikeshed');
4046
const processorUrl = config.get<string>(
4147
'processorUrl',
42-
'https://api.csswg.org/bikeshed/'
48+
'https://www.w3.org/publications/spec-generator/'
4349
);
4450
let htmlContent = '';
4551
try {
@@ -166,6 +172,19 @@ async function parseErrors(xml: string): Promise<BikeshedErrorOutput> {
166172
}
167173
}
168174

175+
function notifyUserOfJSONErrors(errors: SpecGeneratorError[]): void {
176+
for (const err of errors) {
177+
let status: VSCodeNotifyType = 'info';
178+
if (err.messageType === 'fatal' || err.messageType === 'failure') {
179+
status = 'error';
180+
} else if (err.messageType === 'warning') {
181+
status = 'warning';
182+
}
183+
const msg = `${err.lineNum ? `[${err.lineNum}] ` : ''}${err.text}`;
184+
notify(msg, status);
185+
}
186+
}
187+
169188
function notifyUserOfErrors(errors: BikeshedErrorOutput): void {
170189
const messages: [string, VSCodeNotifyType][] = [];
171190
if (errors.root.fatal) {
@@ -216,35 +235,45 @@ async function getProcessedContent(
216235
): Promise<string> {
217236
const formData = new FormData();
218237
formData.append('file', new Blob([content]), 'file.bs');
219-
formData.append('force', '1');
220-
const response = await axios.post(processorUrl, formData, {
221-
headers: {
222-
'Content-Type': 'multipart/form-data',
223-
},
224-
onUploadProgress: (progressEvent) => {
225-
const percentCompleted = Math.round(
226-
progressEvent.total
227-
? (progressEvent.loaded / progressEvent.total) * 50
228-
: 0
229-
);
230-
progress.report({
231-
increment: percentCompleted,
232-
message: `Uploading to ${processorUrl}`,
233-
});
234-
},
235-
onDownloadProgress: (progressEvent) => {
236-
const percentCompleted = Math.round(
237-
progressEvent.total
238-
? (progressEvent.loaded / progressEvent.total) * 50
239-
: 0
240-
);
241-
progress.report({
242-
increment: 50 + percentCompleted,
243-
message: `Downloading compiled output from ${processorUrl}`,
244-
});
245-
},
246-
});
247-
return response.data;
238+
formData.append('type', 'bikeshed-spec');
239+
240+
try {
241+
const response = await axios.post(processorUrl, formData, {
242+
headers: {
243+
'Content-Type': 'multipart/form-data',
244+
},
245+
onUploadProgress: (progressEvent) => {
246+
const percentCompleted = Math.round(
247+
progressEvent.total
248+
? (progressEvent.loaded / progressEvent.total) * 50
249+
: 0
250+
);
251+
progress.report({
252+
increment: percentCompleted,
253+
message: `Uploading to ${processorUrl}`,
254+
});
255+
},
256+
onDownloadProgress: (progressEvent) => {
257+
const percentCompleted = Math.round(
258+
progressEvent.total
259+
? (progressEvent.loaded / progressEvent.total) * 50
260+
: 0
261+
);
262+
progress.report({
263+
increment: 50 + percentCompleted,
264+
message: `Downloading compiled output from ${processorUrl}`,
265+
});
266+
},
267+
});
268+
return response.data;
269+
} catch (error) {
270+
if (axios.isAxiosError(error) && error.response?.status === 422) {
271+
const apiErrors = error.response.data as SpecGeneratorError[];
272+
notifyUserOfJSONErrors(apiErrors);
273+
throw new Error('Compilation failed with errors.');
274+
}
275+
throw error;
276+
}
248277
}
249278

250279
async function getProcessedContentWithShell(

0 commit comments

Comments
 (0)