@electron/lint-roller 2.4.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/markdown.ts CHANGED
@@ -2,7 +2,7 @@ import * as fs from 'node:fs';
2
2
  import * as path from 'node:path';
3
3
 
4
4
  import * as glob from 'glob';
5
- import * as MarkdownIt from 'markdown-it';
5
+ import MarkdownIt from 'markdown-it';
6
6
  import {
7
7
  githubSlugifier,
8
8
  resolveInternalDocumentLink,
@@ -17,16 +17,14 @@ import {
17
17
  MdLink,
18
18
  MdLinkKind,
19
19
  } from '@dsanders11/vscode-markdown-languageservice';
20
+ import { visit } from 'unist-util-visit';
21
+ import { fromMarkdown } from 'mdast-util-from-markdown';
20
22
  import { Emitter, Range } from 'vscode-languageserver';
21
23
  import { TextDocument } from 'vscode-languageserver-textdocument';
22
24
  import { URI } from 'vscode-uri';
23
25
 
24
- import { dynamicImport } from './helpers';
25
-
26
26
  import type { Code, Definition, ImageReference, Link, LinkReference } from 'mdast';
27
- import type { fromMarkdown as FromMarkdownFunction } from 'mdast-util-from-markdown';
28
27
  import type { Node, Position } from 'unist';
29
- import type { visit as VisitFunction } from 'unist-util-visit';
30
28
 
31
29
  export type { Code };
32
30
 
@@ -186,10 +184,6 @@ export class MarkdownLinkComputer implements IMdLinkComputer {
186
184
  }
187
185
 
188
186
  async getAllLinks(document: ITextDocument): Promise<MdLink[]> {
189
- const { fromMarkdown } = (await dynamicImport('mdast-util-from-markdown')) as {
190
- fromMarkdown: typeof FromMarkdownFunction;
191
- };
192
-
193
187
  const tree = fromMarkdown(document.getText());
194
188
 
195
189
  const links = [
@@ -202,158 +196,123 @@ export class MarkdownLinkComputer implements IMdLinkComputer {
202
196
  }
203
197
 
204
198
  async #getInlineLinks(document: ITextDocument, tree: Node): Promise<MdLink[]> {
205
- const { visit } = (await dynamicImport('unist-util-visit')) as {
206
- visit: typeof VisitFunction;
207
- };
208
-
209
199
  const documentUri = URI.parse(document.uri);
210
200
  const links: MdLink[] = [];
211
201
 
212
- visit(
213
- tree,
214
- (node) => node.type === 'link',
215
- (node: Node) => {
216
- const link = node as Link;
217
- const href = createHref(documentUri, link.url, this.workspace);
218
-
219
- if (href) {
220
- const range = positionToRange(link.position!);
221
-
222
- // NOTE - These haven't been implemented properly, but their
223
- // values aren't used for the link linting use-case
224
- const targetRange = range;
225
- const hrefRange = range;
226
- const fragmentRange = undefined;
227
-
228
- links.push({
229
- kind: MdLinkKind.Link,
230
- href,
231
- source: {
232
- hrefText: link.url,
233
- resource: documentUri,
234
- range,
235
- targetRange,
236
- hrefRange,
237
- fragmentRange,
238
- pathText: link.url.split('#')[0],
239
- },
240
- });
241
- }
242
- },
243
- );
244
-
245
- return links;
246
- }
247
-
248
- async #getReferenceLinks(document: ITextDocument, tree: Node): Promise<MdLink[]> {
249
- const { visit } = (await dynamicImport('unist-util-visit')) as {
250
- visit: typeof VisitFunction;
251
- };
252
-
253
- const links: MdLink[] = [];
202
+ visit(tree, 'link', (node: Node) => {
203
+ const link = node as Link;
204
+ const href = createHref(documentUri, link.url, this.workspace);
254
205
 
255
- visit(
256
- tree,
257
- (node) => ['imageReference', 'linkReference'].includes(node.type),
258
- (node: Node) => {
259
- const link = node as ImageReference | LinkReference;
206
+ if (href) {
260
207
  const range = positionToRange(link.position!);
261
208
 
262
209
  // NOTE - These haven't been implemented properly, but their
263
210
  // values aren't used for the link linting use-case
264
211
  const targetRange = range;
265
212
  const hrefRange = range;
213
+ const fragmentRange = undefined;
266
214
 
267
215
  links.push({
268
216
  kind: MdLinkKind.Link,
269
- href: {
270
- kind: HrefKind.Reference,
271
- ref: link.label!,
272
- },
217
+ href,
273
218
  source: {
274
- hrefText: link.label!,
275
- resource: URI.parse(document.uri),
219
+ hrefText: link.url,
220
+ resource: documentUri,
276
221
  range,
277
222
  targetRange,
278
223
  hrefRange,
279
- fragmentRange: undefined,
280
- pathText: link.label!,
224
+ fragmentRange,
225
+ pathText: link.url.split('#')[0],
281
226
  },
282
227
  });
283
- },
284
- );
228
+ }
229
+ });
285
230
 
286
231
  return links;
287
232
  }
288
233
 
289
- async #getLinkDefinitions(document: ITextDocument, tree: Node): Promise<MdLink[]> {
290
- const { visit } = (await dynamicImport('unist-util-visit')) as {
291
- visit: typeof VisitFunction;
292
- };
234
+ async #getReferenceLinks(document: ITextDocument, tree: Node): Promise<MdLink[]> {
235
+ const links: MdLink[] = [];
293
236
 
237
+ visit(tree, ['imageReference', 'linkReference'], (node: Node) => {
238
+ const link = node as ImageReference | LinkReference;
239
+ const range = positionToRange(link.position!);
240
+
241
+ // NOTE - These haven't been implemented properly, but their
242
+ // values aren't used for the link linting use-case
243
+ const targetRange = range;
244
+ const hrefRange = range;
245
+
246
+ links.push({
247
+ kind: MdLinkKind.Link,
248
+ href: {
249
+ kind: HrefKind.Reference,
250
+ ref: link.label!,
251
+ },
252
+ source: {
253
+ hrefText: link.label!,
254
+ resource: URI.parse(document.uri),
255
+ range,
256
+ targetRange,
257
+ hrefRange,
258
+ fragmentRange: undefined,
259
+ pathText: link.label!,
260
+ },
261
+ });
262
+ });
263
+
264
+ return links;
265
+ }
266
+
267
+ async #getLinkDefinitions(document: ITextDocument, tree: Node): Promise<MdLink[]> {
294
268
  const documentUri = URI.parse(document.uri);
295
269
  const links: MdLink[] = [];
296
270
 
297
- visit(
298
- tree,
299
- (node) => node.type === 'definition',
300
- (node: Node) => {
301
- const definition = node as Definition;
302
- const href = createHref(documentUri, definition.url, this.workspace);
303
-
304
- if (href) {
305
- const range = positionToRange(definition.position!);
306
-
307
- // NOTE - These haven't been implemented properly, but their
308
- // values aren't used for the link linting use-case
309
- const targetRange = range;
310
- const hrefRange = range;
311
- const fragmentRange = undefined;
312
-
313
- links.push({
314
- kind: MdLinkKind.Definition,
315
- href,
316
- ref: {
317
- range,
318
- text: definition.label!,
319
- },
320
- source: {
321
- hrefText: definition.url,
322
- resource: documentUri,
323
- range,
324
- targetRange,
325
- hrefRange,
326
- fragmentRange,
327
- pathText: definition.url.split('#')[0],
328
- },
329
- });
330
- }
331
- },
332
- );
271
+ visit(tree, 'definition', (node: Node) => {
272
+ const definition = node as Definition;
273
+ const href = createHref(documentUri, definition.url, this.workspace);
274
+
275
+ if (href) {
276
+ const range = positionToRange(definition.position!);
277
+
278
+ // NOTE - These haven't been implemented properly, but their
279
+ // values aren't used for the link linting use-case
280
+ const targetRange = range;
281
+ const hrefRange = range;
282
+ const fragmentRange = undefined;
283
+
284
+ links.push({
285
+ kind: MdLinkKind.Definition,
286
+ href,
287
+ ref: {
288
+ range,
289
+ text: definition.label!,
290
+ },
291
+ source: {
292
+ hrefText: definition.url,
293
+ resource: documentUri,
294
+ range,
295
+ targetRange,
296
+ hrefRange,
297
+ fragmentRange,
298
+ pathText: definition.url.split('#')[0],
299
+ },
300
+ });
301
+ }
302
+ });
333
303
 
334
304
  return links;
335
305
  }
336
306
  }
337
307
 
338
308
  export async function getCodeBlocks(content: string): Promise<Code[]> {
339
- const { fromMarkdown } = (await dynamicImport('mdast-util-from-markdown')) as {
340
- fromMarkdown: typeof FromMarkdownFunction;
341
- };
342
- const { visit } = (await dynamicImport('unist-util-visit')) as {
343
- visit: typeof VisitFunction;
344
- };
345
-
346
309
  const tree = fromMarkdown(content);
347
310
 
348
311
  const codeBlocks: Code[] = [];
349
312
 
350
- visit(
351
- tree,
352
- (node) => node.type === 'code',
353
- (node: Node) => {
354
- codeBlocks.push(node as Code);
355
- },
356
- );
313
+ visit(tree, 'code', (node: Node) => {
314
+ codeBlocks.push(node as Code);
315
+ });
357
316
 
358
317
  return codeBlocks;
359
318
  }
@@ -1,5 +1,3 @@
1
- import { addError, filterTokens } from 'markdownlint/helpers';
2
-
3
1
  import { fromMarkdown } from 'mdast-util-from-markdown';
4
2
  import { visit } from 'unist-util-visit';
5
3
 
@@ -11,7 +9,9 @@ export const tags = ['brackets'];
11
9
  const UNESCAPED_REGEX = /(?<!\\)<(?!\s)/g;
12
10
 
13
11
  function EMD002(params, onError) {
14
- filterTokens(params, 'inline', (token) => {
12
+ const tokens = params.parsers.markdownit.tokens.filter((token) => token.type === 'inline');
13
+
14
+ for (const token of tokens) {
15
15
  for (const childToken of token.children) {
16
16
  // childToken.line has the raw content, but may also contain
17
17
  // more content than just childToken.content. Since we need
@@ -41,19 +41,17 @@ function EMD002(params, onError) {
41
41
  const matches = rawContent.matchAll(UNESCAPED_REGEX);
42
42
 
43
43
  for (const match of matches) {
44
- addError(
45
- onError,
46
- childToken.lineNumber,
47
- 'Unescaped opening angle bracket',
48
- undefined,
49
- [node.position.start.offset + 1 + match.index, 1],
50
- );
44
+ onError({
45
+ lineNumber: childToken.lineNumber,
46
+ detail: 'Unescaped opening angle bracket',
47
+ range: [node.position.start.offset + 1 + match.index, 1],
48
+ });
51
49
  }
52
50
  },
53
51
  );
54
52
  }
55
53
  }
56
- });
54
+ }
57
55
  }
58
56
 
59
57
  export { EMD002 as function };
@@ -1,5 +1,3 @@
1
- import { addError, filterTokens } from 'markdownlint/helpers';
2
-
3
1
  import { fromMarkdown } from 'mdast-util-from-markdown';
4
2
  import { visit } from 'unist-util-visit';
5
3
 
@@ -11,7 +9,9 @@ export const tags = ['braces'];
11
9
  const UNESCAPED_REGEX = /(?<!\\){/g;
12
10
 
13
11
  function EMD003(params, onError) {
14
- filterTokens(params, 'inline', (token) => {
12
+ const tokens = params.parsers.markdownit.tokens.filter((token) => token.type === 'inline');
13
+
14
+ for (const token of tokens) {
15
15
  for (const childToken of token.children) {
16
16
  // childToken.line has the raw content, but may also contain
17
17
  // more content than just childToken.content. Since we need
@@ -40,16 +40,17 @@ function EMD003(params, onError) {
40
40
  const matches = rawContent.matchAll(UNESCAPED_REGEX);
41
41
 
42
42
  for (const match of matches) {
43
- addError(onError, childToken.lineNumber, 'Unescaped opening curly brace', undefined, [
44
- node.position.start.offset + 1 + match.index,
45
- 1,
46
- ]);
43
+ onError({
44
+ lineNumber: childToken.lineNumber,
45
+ detail: 'Unescaped opening curly brace',
46
+ range: [node.position.start.offset + 1 + match.index, 1],
47
+ });
47
48
  }
48
49
  },
49
50
  );
50
51
  }
51
52
  }
52
- });
53
+ }
53
54
  }
54
55
 
55
56
  export { EMD003 as function };
@@ -0,0 +1,31 @@
1
+ export const names = ['EMD004', 'no-newline-in-links'];
2
+ export const description = 'Newlines inside link text';
3
+ export const tags = ['newline', 'links'];
4
+ export const parser = 'markdownit';
5
+
6
+ function EMD004(params, onError) {
7
+ const tokens = params.parsers.markdownit.tokens.filter((token) => token.type === 'inline');
8
+
9
+ for (const token of tokens) {
10
+ const { children } = token;
11
+ let { lineNumber } = token;
12
+ let inLink = false;
13
+ for (const child of children) {
14
+ const { type } = child;
15
+ if (type === 'link_open') {
16
+ inLink = true;
17
+ } else if (type === 'link_close') {
18
+ inLink = false;
19
+ } else if (type === 'softbreak') {
20
+ if (inLink) {
21
+ onError({ lineNumber });
22
+ break;
23
+ } else {
24
+ lineNumber++;
25
+ }
26
+ }
27
+ }
28
+ }
29
+ }
30
+
31
+ export { EMD004 as function };
@@ -0,0 +1,5 @@
1
+ import * as EMD002 from './emd002.mjs';
2
+ import * as EMD003 from './emd003.mjs';
3
+ import * as EMD004 from './emd004.mjs';
4
+
5
+ export default [EMD002, EMD003, EMD004];
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@electron/lint-roller",
3
- "version": "2.4.0",
3
+ "version": "3.1.0",
4
4
  "description": "Markdown linting helpers for Electron org repos",
5
+ "type": "module",
5
6
  "engines": {
6
- "node": ">=18.0.0"
7
+ "node": ">=20.16.0 || >=22.4.0"
7
8
  },
8
9
  "bin": {
9
- "electron-markdownlint": "./dist/bin/markdownlint-cli-wrapper.js",
10
10
  "lint-roller-markdown-links": "./dist/bin/lint-markdown-links.js",
11
11
  "lint-roller-markdown-standard": "./dist/bin/lint-markdown-standard.js",
12
12
  "lint-roller-markdown-ts-check": "./dist/bin/lint-markdown-ts-check.js",
@@ -22,13 +22,11 @@
22
22
  "lib": "lib"
23
23
  },
24
24
  "scripts": {
25
- "build": "tsc && yarn run build:emd002 && yarn run build:emd003",
26
- "build:emd002": "esbuild --platform=node --target=node18 --format=cjs --bundle --outfile=markdownlint-rules/emd002.js markdownlint-rules/emd002.mjs",
27
- "build:emd003": "esbuild --platform=node --target=node18 --format=cjs --bundle --outfile=markdownlint-rules/emd003.js markdownlint-rules/emd003.mjs",
25
+ "build": "tsc",
28
26
  "prepublishOnly": "yarn run build",
29
27
  "lint:eslint": "eslint \"{bin,lib,markdownlint-rules,tests}/**/*.{js,mjs,ts}\"",
30
28
  "lint:eslint:fix": "eslint --fix \"{bin,lib,markdownlint-rules,tests}/**/*.{js,mjs,ts}\"",
31
- "lint:markdown": "yarn run build && node ./dist/bin/markdownlint-cli-wrapper.js \"*.md\" && node ./dist/bin/lint-markdown-links.js \"*.md\"",
29
+ "lint:markdown": "yarn run build && markdownlint-cli2 \"*.md\" && node ./dist/bin/lint-markdown-links.js \"*.md\"",
32
30
  "lint:prettier": "prettier --check \"{bin,lib,markdownlint-rules,tests}/**/*.{js,mjs,ts}\"",
33
31
  "lint:prettier:fix": "prettier --write \"{bin,lib,markdownlint-rules,tests}/**/*.{js,mjs,ts}\"",
34
32
  "lint": "yarn run lint:prettier && yarn run lint:markdown",
@@ -45,37 +43,36 @@
45
43
  "url": "https://github.com/electron/lint-roller/issues"
46
44
  },
47
45
  "homepage": "https://github.com/electron/lint-roller#readme",
46
+ "publishConfig": {
47
+ "provenance": true
48
+ },
48
49
  "devDependencies": {
49
50
  "@electron-internal/eslint-config": "^1.0.1",
50
- "@types/balanced-match": "^1.0.3",
51
+ "@types/balanced-match": "^3.0.2",
51
52
  "@types/glob": "^8.1.0",
52
- "@types/markdown-it": "^13.0.6",
53
- "@types/minimist": "^1.2.5",
54
- "@types/node": "20.1.2",
55
- "esbuild": "^0.21.0",
53
+ "@types/markdown-it": "^14.1.2",
54
+ "@types/node": "22.8.7",
56
55
  "eslint": "^8.54.0",
57
56
  "eslint-config-prettier": "^9.1.0",
58
57
  "eslint-plugin-node": "^11.1.0",
58
+ "markdownlint-cli2": "^0.18.0",
59
59
  "prettier": "^3.2.5",
60
60
  "typescript": "^5.4.5",
61
- "vitest": "^1.5.3"
61
+ "vitest": "^3.0.6"
62
62
  },
63
63
  "dependencies": {
64
64
  "@dsanders11/vscode-markdown-languageservice": "^0.3.0",
65
65
  "ajv": "^8.16.0",
66
- "balanced-match": "^2.0.0",
67
- "glob": "^8.1.0",
66
+ "balanced-match": "^3.0.1",
67
+ "glob": "^10.4.5",
68
68
  "hast-util-from-html": "^2.0.1",
69
- "markdown-it": "^13.0.1",
70
- "markdownlint-cli": "^0.40.0",
71
- "mdast-util-from-markdown": "^1.3.0",
72
- "minimist": "^1.2.8",
73
- "rimraf": "^4.4.1",
69
+ "markdown-it": "^14.1.0",
70
+ "mdast-util-from-markdown": "^2.0.2",
74
71
  "standard": "^17.0.0",
75
- "unist-util-visit": "^4.1.2",
72
+ "unist-util-visit": "^5.0.0",
76
73
  "vscode-languageserver": "^8.1.0",
77
74
  "vscode-languageserver-textdocument": "^1.0.8",
78
- "vscode-uri": "^3.0.7",
75
+ "vscode-uri": "^3.0.8",
79
76
  "yaml": "^2.4.5"
80
77
  },
81
78
  "peerDependencies": {
@@ -85,8 +82,5 @@
85
82
  "typescript": {
86
83
  "optional": true
87
84
  }
88
- },
89
- "resolutions": {
90
- "jackspeak": "2.1.1"
91
85
  }
92
86
  }
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
@@ -1,16 +0,0 @@
1
- #!/usr/bin/env node
2
- "use strict";
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- const cp = require("node:child_process");
5
- const path = require("node:path");
6
- if (require.main === module) {
7
- const { status } = cp.spawnSync(process.execPath, [
8
- require.resolve('markdownlint-cli'),
9
- '-r',
10
- path.resolve(__dirname, '../../markdownlint-rules/index.js'),
11
- ...process.argv.slice(2),
12
- ], { stdio: 'inherit' });
13
- if (status)
14
- process.exit(status);
15
- }
16
- //# sourceMappingURL=markdownlint-cli-wrapper.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"markdownlint-cli-wrapper.js","sourceRoot":"","sources":["../../bin/markdownlint-cli-wrapper.ts"],"names":[],"mappings":";;;AAEA,yCAAyC;AACzC,kCAAkC;AAElC,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;IAC5B,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,SAAS,CAC7B,OAAO,CAAC,QAAQ,EAChB;QACE,OAAO,CAAC,OAAO,CAAC,kBAAkB,CAAC;QACnC,IAAI;QACJ,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,mCAAmC,CAAC;QAC5D,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;KACzB,EACD,EAAE,KAAK,EAAE,SAAS,EAAE,CACrB,CAAC;IACF,IAAI,MAAM;QAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACnC,CAAC"}