Skip to content

Validate article folder names #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jun 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions .github/workflows/jest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: Jest
on: push
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v1
with:
node-version: "14"

# Speed up subsequent runs with caching
- name: Cache node modules
uses: actions/cache@v2
env:
cache-name: cache-node-modules
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-

# Install required deps for action
- name: Install Dependencies
run: npm install

# Finally, run our tests
- name: Run the tests
run: npm test

- name: Tests ✅
if: ${{ success() }}
run: |
curl --request POST \
--url https://api.github.com/repos/${{ github.repository }}/statuses/${{ github.sha }} \
--header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' \
--header 'content-type: application/json' \
--data '{
"context": "tests",
"state": "success",
"description": "Tests passed",
"target_url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
}'

- name: Tests 🚨
if: ${{ failure() }}
run: |
curl --request POST \
--url https://api.github.com/repos/${{ github.repository }}/statuses/${{ github.sha }} \
--header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' \
--header 'content-type: application/json' \
--data '{
"context": "tests",
"state": "failure",
"description": "Tests failed",
"target_url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
}'
23 changes: 23 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Jest Tests",
"type": "node",
"request": "launch",
"runtimeArgs": [
"--inspect-brk",
"--experimental-vm-modules"
],
"program": "${workspaceRoot}/node_modules/.bin/jest",
"args": [
"--runInBand"
],
"skipFiles": [
"<node_internals>/**"
],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
},
]
}
10 changes: 10 additions & 0 deletions domain/article.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ export class Article {
this.contentFilePath = contentFilePath;
}

/**
* Resets the cached properties.
* This is useful if the content of an article is changed through one of the setters.
*/
clearData(){
this._html = null;
this._markdown = null;
Expand All @@ -21,6 +25,9 @@ export class Article {
this._emphasizedTextData = null;
}

/**
* Returns the path of the folder containg an article
*/
get path(){
if(this._basePath) return this._basePath;
this._basePath = this._contentFilePath ? path.dirname(this._contentFilePath) : null;
Expand Down Expand Up @@ -57,6 +64,9 @@ export class Article {
this._rawData = data;
}

/**
* Returns the raw text of an article document.
*/
get rawData(){
if(this._rawData) return this._rawData;

Expand Down
3 changes: 2 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ import { validateSyntaxSpecifiers } from './validations/code-blocks.js';
import { validateNestedLists } from './validations/lists.js';
import { validateBrokenLinks } from './validations/links.js';
import { ConfigManager } from './logic/config-manager.js';
import { validateFolderName } from './validations/naming.js';

export { Validator, ArticleManager, validateDuplicatedOpeningHeading, validateHeadingsNesting, validateMaxLength, validateNumberedHeadings, validateOpeningHeadingLevel, validateSpacing, validateTitleCase, validateMetaData, validateRules, validateImageDescriptions, validateImagePaths, validateReferencedAssets, validateSVGFiles, validateSyntaxSpecifiers, validateNestedLists, validateBrokenLinks, ConfigManager }
export { Validator, ArticleManager, validateDuplicatedOpeningHeading, validateHeadingsNesting, validateMaxLength, validateNumberedHeadings, validateOpeningHeadingLevel, validateSpacing, validateTitleCase, validateMetaData, validateRules, validateImageDescriptions, validateImagePaths, validateReferencedAssets, validateSVGFiles, validateSyntaxSpecifiers, validateNestedLists, validateBrokenLinks, ConfigManager, validateFolderName }
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "content-lint",
"version": "1.0.0",
"version": "1.1.0",
"type": "module",
"main": "index.js",
"description": "A node.js infrastructure to validate markdown content.",
Expand Down
2 changes: 1 addition & 1 deletion test/metadata.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ articleA.rawData = contentA;

const articleB = new Article();
articleB.rawData = contentB;
const schemaPath = "./rules/tutorial-metadata-schema.json";
const schemaPath = "./test/resources/tutorial-metadata-schema.json";

test('Tests if missing/superfluous property is detected', () => {
const errors = validateMetaData(articleA, schemaPath);
Expand Down
20 changes: 20 additions & 0 deletions test/naming.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Article } from '../domain/article.js'
import { validateFolderName } from '../validations/naming.js';

const articleA = new Article();
articleA.path = "./demo/this_is_Not_compliant";

const articleB = new Article();
articleB.path = "./demo/this-should-pass";

test('Tests if non-compliant article folder name is detected', () => {
const errors = validateFolderName(articleA);
console.log(errors);
expect(errors.length).toBe(2);
});

test('Tests if compliant article folder name passes validation', () => {
const errors = validateFolderName(articleB);
console.log(errors);
expect(errors.length).toBe(0);
});
89 changes: 89 additions & 0 deletions test/resources/tutorial-metadata-schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"beta": {
"type": "boolean"
},
"source" : {
"type": "string"
},
"title": {
"type": "string",
"maxLength": 60
},
"coverImage": {
"type": "string"
},
"author": {
"type": "string"
},
"tags": {
"type": "array",
"items": [
{
"type": "string"
}
]
},
"description": {
"type": "string"
},
"difficulty": {
"type": "string"
},
"hero_position": {
"type": "integer"
},
"featuredImage": {
"type": "string"
},
"software": {
"type": "array",
"items": [
{
"type": "string"
}
]
},
"compatible-products":{
"type": "array",
"items": [
{
"type": "string"
}
]
},
"hardware": {
"type": "array",
"items": [
{
"type": "string"
}
]
},
"libraries": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"name" : {
"type" : "string"
},
"url" : {
"type" : "string"
}
}
}
]
}
},
"required": [
"title",
"tags",
"description",
"author"
],
"additionalProperties" : false
}
30 changes: 30 additions & 0 deletions validations/naming.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { ValidationIssue } from '../domain/validation-issue.js';

/**
* Checks if the foldername contains any discouraged underscores, spaces or upper-case letters.
* @param {Article} article
* @returns an array containg the occurred validation errors
*/
function validateFolderName(article) {
let errorsOccurred = [];
const issueType = ValidationIssue.Type.WARNING;

if(article.path.indexOf("_") != -1){
const errorMessage = "Folder path uses discouraged underscore.";
errorsOccurred.push(new ValidationIssue(errorMessage, article.path, issueType));
}

if(article.path.indexOf(" ") != -1){
const errorMessage = "Folder path uses discouraged blanks.";
errorsOccurred.push(new ValidationIssue(errorMessage, article.path, issueType));
}

if(article.path != article.path.toLowerCase()){
const errorMessage = "Folder path uses discouraged non-lower case characters.";
errorsOccurred.push(new ValidationIssue(errorMessage, article.path, issueType));
}

return errorsOccurred;
}

export { validateFolderName }