diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0d9ff0b..9bd398a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,12 @@ All notable changes to this project are documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [1.6.0] - 2023-11-18
+
+### Changed
+
+- Ensure that all of the content from snippets files are escaped before being output in the view.
+
## [1.5.1] - 2023-11-18
### Fixed
diff --git a/package.json b/package.json
index ffb870a..add0955 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,7 @@
},
"description": "View and edit all your snippets in one purty place. Yee-haw!",
"icon": "img/logo.webp",
- "version": "1.5.1",
+ "version": "1.6.0",
"engines": {
"vscode": "^1.4.0",
"node": ">=12.0.0"
diff --git a/src/helper/format.js b/src/helper/format.js
index e217fdf..58d318a 100644
--- a/src/helper/format.js
+++ b/src/helper/format.js
@@ -32,17 +32,17 @@ function escapeHtml(text) {
}
/**
- * Escapes all the HTML content in the items of an array and concatenates it into a string
- * that can be consumed by a web page. Each item is appended with a HTML line break (BR tag).
+ * Escapes all the HTML content in the items of an array/string that can be consumed by a web page.
+ * Each item in the array is appended with a HTML line break (BR tag) and returned as a single string.
* @param {string|Array} array Array of values
*/
-function escapeBody(body) {
+function escape(content) {
let str = "";
- if (typeof body === "string") {
- str = escapeHtml(body);
- } else if (Array.isArray(body)) {
- body.forEach((element) => {
+ if (typeof content === "string") {
+ str = escapeHtml(content);
+ } else if (Array.isArray(content)) {
+ content.forEach((element) => {
str += escapeHtml(element);
str += "
";
});
@@ -82,7 +82,7 @@ function slugify(text) {
module.exports = {
capitalize,
escapeHtml,
- escapeBody,
+ escape,
convertToArray,
slugify,
};
diff --git a/src/model/snippet.js b/src/model/snippet.js
index 6984e83..2f0fde5 100644
--- a/src/model/snippet.js
+++ b/src/model/snippet.js
@@ -1,5 +1,4 @@
const format = require("../helper/format");
-const util = require("../helper/util");
/**
* The body can be a string or an array. This formats it to be an array internally always.
@@ -64,7 +63,6 @@ function Snippet(
let formattedPrefix = formatPrefix(prefix);
let formattedBody = formatBody(body);
let formattedScope = formatScope(scope);
- let endOfLineDelimiter = util.getEndOfLineDelimiter();
return {
name,
diff --git a/src/view/snippets-table.js b/src/view/snippets-table.js
index 2b122ef..d13bdf9 100644
--- a/src/view/snippets-table.js
+++ b/src/view/snippets-table.js
@@ -58,14 +58,14 @@ const createTableBody = (snippetsFile) => {
body += `
`;
body += `${createPrefixList(snippet.prefix)} | `;
- body += `${snippet.name} | `;
- body += `${snippet.description} | `;
+ body += `${format.escape(snippet.name)} | `;
+ body += `${format.escape(snippet.description)} | `;
body += "";
- body += format.escapeBody(snippet.body);
+ body += format.escape(snippet.body);
body += " | ";
if (snippetsFile.isScoped() === true) {
- body += `${snippet.scope} | `;
+ body += `${format.escape(snippet.scope)} | `;
}
body += `${editButton}${deleteButton} |
`;
@@ -83,7 +83,7 @@ function createPrefixList(prefix) {
list = ``;
prefix.forEach((item) => {
- list += `${item}
`;
+ list += `${format.escape(item)}
`;
});
list += `
`;
diff --git a/src/view/table-of-contents.js b/src/view/table-of-contents.js
index ad8861f..1b8b652 100644
--- a/src/view/table-of-contents.js
+++ b/src/view/table-of-contents.js
@@ -55,7 +55,7 @@ const createSnippetsFileEntry = (snippetsFile) => {
};
const createExtensionEntry = (extensions) => {
- let html = "";
+ let html = `Extension Snippets`;
let entries = "";
extensions.forEach((extension) => {
@@ -70,9 +70,11 @@ const createExtensionEntry = (extensions) => {
});
if (entries !== "") {
- html += `Extension Snippets`;
+ html += ``;
}
+ html += ``;
+
return html;
};
diff --git a/test/suite/helper/format.test.js b/test/suite/helper/format.test.js
index 7527474..4e41bf9 100644
--- a/test/suite/helper/format.test.js
+++ b/test/suite/helper/format.test.js
@@ -80,18 +80,15 @@ describe("format.js", () => {
});
});
- describe("escapeBody()", () => {
+ describe("escape()", () => {
it("should replace html elements with a HTML-safe equivalent for a string", () => {
- let body = format.escapeBody(`This is the tag.`);
+ let body = format.escape(`This is the tag.`);
assert.strictEqual(body, "This is the <html> tag.");
});
it("should replace html elements with a HTML-safe equivalent for an array", () => {
- let text1 = format.escapeBody([
- `This is the tag.`,
- `\t let x = 1;`,
- ]);
+ let text1 = format.escape([`This is the tag.`, `\t let x = 1;`]);
assert.strictEqual(
text1,
diff --git a/test/suite/view/snippets-table.test.js b/test/suite/view/snippets-table.test.js
index 4f0bd8d..cde5902 100644
--- a/test/suite/view/snippets-table.test.js
+++ b/test/suite/view/snippets-table.test.js
@@ -68,5 +68,25 @@ describe("snippets-table.js", () => {
assert.strictEqual(table.startsWith(expected), true);
});
+
+ it("should create a table when a snippet contains reserved HTML characters", () => {
+ let snippet = {
+ name: "test",
+ prefix: ["", "test"],
+ body: ["This is "],
+ description: "Testing ",
+ scope: "
",
+ };
+
+ let snippetsFile = new SnippetsFile("/somepath/a.code-snippets", [
+ snippet,
+ ]);
+
+ let table = createSnippetsTable(snippetsFile);
+
+ let expected = ` | test | Testing <div> | This is <i>
| <bogus> | `;
+
+ assert.strictEqual(table.includes(expected), true);
+ });
});
});
diff --git a/test/suite/view/table-of-contents.test.js b/test/suite/view/table-of-contents.test.js
index d62e668..6edbc79 100644
--- a/test/suite/view/table-of-contents.test.js
+++ b/test/suite/view/table-of-contents.test.js
@@ -7,10 +7,14 @@ const Extension = require("../../../src/model/extension");
describe("table-of-contents.js", () => {
describe("createTableOfContents()", () => {
- it("should create an empty table if an empty outline is provided", () => {
+ it("should create a table with category entries", () => {
let toc = createTableOfContents(); // OR createTableOfContents([], [], [], []);
- assert.strictEqual(toc, "");
+ let expected = ``;
+
+ assert.strictEqual(toc, expected);
});
it("should create a table with an entry for a collection of snippets files", () => {
@@ -24,14 +28,16 @@ describe("table-of-contents.js", () => {
[]
);
- let expectedOutput = `Table of Contents
`;
- expectedOutput += `- Project Snippets
`;
- expectedOutput += `- a
`;
- expectedOutput += `- b
`;
- expectedOutput += `
`;
- expectedOutput += `
`;
+ let expected = ``;
- assert.strictEqual(toc, expectedOutput);
+ assert.strictEqual(toc, expected);
});
it("should create a table with an entry for an extension and its snippets files", () => {
@@ -46,15 +52,18 @@ describe("table-of-contents.js", () => {
let toc = createTableOfContents([], [], [], [extension]);
- let expectedOutput = `Table of Contents
`;
- expectedOutput += `- Extension Snippets
`;
- expectedOutput += `- Snippets Ranger
`;
- expectedOutput += `- a
`;
- expectedOutput += `- b
`;
- expectedOutput += `
`;
- expectedOutput += `
`;
+ let expected = ``;
- assert.strictEqual(toc, expectedOutput);
+ assert.strictEqual(toc, expected);
});
});
});
diff --git a/todo.md b/todo.md
index e9dd752..af22b6e 100644
--- a/todo.md
+++ b/todo.md
@@ -1,8 +1,5 @@
# To Do
-1. Can I make the extension more resilient? What about funky data?
-1. This snippet extension - https://open-vsx.org/extension/hollowtree/vue-snippets - appears to cause an error. Why?
-
## Changes to consider
1. Support for multi-root workspaces. For multi-root workspaces, a sub workspace can have its own snippets in its *.vscode* folder. You would need look in the `.code-workspace` to discover the sub workspaces and inspect them.