Skip to content
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
4 changes: 2 additions & 2 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: npm install
run: npm install
- name: Compile
run: npm install && npm run build
- name: Run the linter
run: ./lint
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Ignore hidden Mac OS directory files
**/.DS_Store
node_modules/
support/dist/
2 changes: 1 addition & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1 +1 @@
/dist/
/support/dist/
99 changes: 99 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "./lint",
"detail": "Runs all supplied linters. This is the same check that runs on all pull requests.",
"type": "npm",
"script": "lint",
"problemMatcher": {
"fileLocation": ["relative", "${workspaceFolder}"],
"severity": "error",
"owner": "lint-owner",
"source": "lint-source",
"pattern": {
"regexp": "^(.*?):(\\d+)(?::(\\d+))? ((?:MD|VL)\\S+) (.*)$",
"file": 1,
"line": 2,
"column": 3,
"code": 4,
"message": 5
}
}
},
{
"label": "./lint (watch)",
"detail": "Runs all linters. This is the same check that runs on all pull requests.",
"type": "npm",
"script": "lint:watch",
"isBackground": true,
"problemMatcher": {
"fileLocation": ["relative", "${workspaceFolder}"],
"severity": "error",
"owner": "lint-owner",
"source": "lint-source",
"pattern": {
"regexp": "^(.*?):(\\d+)(?::(\\d+))? ((?:MD|VL)\\S+) (.*)$",
"file": 1,
"line": 2,
"column": 3,
"code": 4,
"message": 5
},
"background": {
"activeOnStart": true,
"beginsPattern": "^lint: RUN$",
"endsPattern": "^lint: (PASS|FAIL)$"
}
}
},
{
"label": "./lint validate-links",
"detail": "Check markdown for broken internal links & images",
"type": "npm",
"script": "lint:validate-links",
"problemMatcher": {
"fileLocation": ["relative", "${workspaceFolder}"],
"severity": "error",
"owner": "lint-owner",
"source": "lint-source",
"pattern": {
"regexp": "^(.*?):(\\d+)(?::(\\d+))? ((?:MD|VL)\\S+) (.*)$",
"file": 1,
"line": 2,
"column": 3,
"code": 4,
"message": 5
}
}
},
{
"label": "./lint validate-links (watch)",
"detail": "Check markdown for broken internal links & images",
"type": "npm",
"script": "lint:validate-links:watch",
"isBackground": true,
"problemMatcher": {
"fileLocation": ["relative", "${workspaceFolder}"],
"severity": "error",
"owner": "lint-owner",
"source": "lint-source",
"pattern": {
"regexp": "^(.*?):(\\d+)(?::(\\d+))? ((?:MD|VL)\\S+) (.*)$",
"file": 1,
"line": 2,
"column": 3,
"code": 4,
"message": 5
},
"background": {
"activeOnStart": true,
"beginsPattern": "^validate-links: RUN$",
"endsPattern": "^validate-links: (PASS|FAIL)$"
}
}
}
]
}
35 changes: 0 additions & 35 deletions dist/parse.js

This file was deleted.

80 changes: 0 additions & 80 deletions dist/validateLinks.js

This file was deleted.

63 changes: 40 additions & 23 deletions lint
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,58 @@

set -eu

if [ "${1:-}" == "--fix" ] ; then
npm exec -- markdownlint --ignore 'node_modules/' --fix '**/*.md'
npm exec -- prettier --write .
else
trap '
if [ $? -ne 0 ] ; then
echo "Try '\''./lint --fix'\'' to see if any automatic fixes are possible"
validate-links() {
echo "validate-links: RUN"
if npm exec -- node support/dist/validateLinks.js ; then
echo validate-links: PASS
else
echo validate-links: FAIL
return 1
fi
' 0
}

rc=0

echo "validateLinks: ..."
if npm exec -- node dist/validateLinks.js ; then
echo validateLinks: PASS
else
echo validateLinks: FAIL
rc=1
fi

echo "markdownlint: ..."
markdownlint() {
echo "markdownlint: RUN"
if npm exec -- markdownlint --ignore 'node_modules/' '**/*.md' ; then
echo "markdownlint: PASS"
else
echo "markdownlint: FAIL"
rc=1
return 1
fi
}

echo "prettier: ..."
prettier() {
echo "prettier: RUN"
if npm exec -- prettier --check . ; then
echo "prettier: PASS"
else
echo "prettier: FAIL"
rc=1
return 1
fi
}

all() {
local rc=0
echo "lint: RUN"
validate-links || rc=1
markdownlint || rc=1
prettier || rc=1

exit $rc
if [ $rc -eq 0 ] ; then
echo "lint: PASS"
else
echo "lint: FAIL"
echo "Try './lint --fix' to see if any automatic fixes are possible"
fi

return $rc
}

if [ "${1:-}" == "--fix" ] ; then
npm exec -- markdownlint --ignore 'node_modules/' --fix '**/*.md' || :
npm exec -- prettier --write . || :
elif [ "${1:-}" == "validate-links" ] ; then
validate-links
else
all
fi
8 changes: 8 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,13 @@
"@types/markdown-it": "^14.1.2",
"@types/node": "^22.14.1",
"typescript": "^5.8.3"
},
"scripts": {
"build": "tsc -p support/tsconfig.json",
"lint": "./lint",
"lint:fix": "./lint --fix",
"lint:validate-links": "./lint validate-links",
"lint:validate-links:watch": "node support/dist/watch.js ./lint validate-links",
"lint:watch": "node support/dist/watch.js ./lint"
}
}
14 changes: 11 additions & 3 deletions parse.ts → support/src/parse.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import mit from "markdown-it";
import type { Token } from "markdown-it/index.js";
import { sourceLocationOf, type SourceLocation } from "./sourceLocation.js";

export type ParsedLink = {
readonly target: string;
readonly content: string;
readonly sourceLocation: SourceLocation | null;
};

export type ParsedImage = {
readonly src: string;
readonly alt: string;
readonly sourceLocation: SourceLocation | null;
};

export type ParseResult = {
Expand All @@ -31,21 +34,26 @@ export const parse = (content: string): ParseResult => {
);

if (indexOfNextClose > index) {
const target = token.attrGet("href") as string;
parsedLinks.push({
target: token.attrGet("href") as string,
target,
content: tokens
.slice(index + 1, indexOfNextClose)
.map((t) => t.content)
.join(""),
sourceLocation: sourceLocationOf(`(${target})`, content),
});
}
}

if (token.type === "image")
if (token.type === "image") {
const src = token.attrGet("src") as string;
parsedImages.push({
src: token.attrGet("src") as string,
src,
alt: token.content,
sourceLocation: sourceLocationOf(`(${src})`, content),
});
}

if (token.children) scan(token.children);
});
Expand Down
Loading