deno.land / std@0.166.0 / _tools / check_doc_imports.ts

check_doc_imports.ts
نووسراو ببینە
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
import { blue, red, yellow } from "../fmt/colors.ts";import { walk } from "../fs/walk.ts";import { createSourceFile, ImportDeclaration, ScriptTarget, StringLiteral, SyntaxKind,} from "https://esm.sh/typescript@4.8.4";
const EXTENSIONS = [".mjs", ".js", ".ts", ".md"];const EXCLUDED_PATHS = [ ".git", ".github", "_tools", "node",];
const ROOT = new URL("../", import.meta.url);const ROOT_LENGTH = ROOT.pathname.slice(0, -1).length;const FAIL_FAST = Deno.args.includes("--fail-fast");const TEST_MODE = Deno.args.includes("--test-mode");
const RX_JSDOC_COMMENT = /\*\*[^*]*\*+(?:[^/*][^*]*\*+)*/mg;const RX_JSDOC_REMOVE_LEADING_ASTERISK = /^\s*\* ?/gm;const RX_CODE_BLOCK = /`{3}([\w]*)\n([\S\s]+?)\n`{3}/gm;
const root = TEST_MODE ? new URL("./_tools/testdata", ROOT) : ROOT;
let shouldFail = false;let countChecked = 0;
function checkImportStatements( codeBlock: string, filePath: string, lineNumber: number,): void { const sourceFile = createSourceFile( "doc-imports-checker$", codeBlock, ScriptTarget.Latest, ); const importDeclarations = sourceFile.statements.filter((s) => s.kind === SyntaxKind.ImportDeclaration ) as ImportDeclaration[];
for (const importDeclaration of importDeclarations) { const { moduleSpecifier } = importDeclaration; const importPath = (moduleSpecifier as StringLiteral).text; const isRelative = importPath.startsWith("."); const isInternal = importPath.startsWith( "https://deno.land/std@$STD_VERSION/", ); const { line } = sourceFile.getLineAndCharacterOfPosition( moduleSpecifier.pos, );
if (isRelative || !isInternal) { console.log( yellow("Warn ") + (isRelative ? "relative import path" : "external or incorrectly versioned dependency") + ": " + red(`"${importPath}"`) + " at " + blue( filePath.substring(ROOT_LENGTH + 1), ) + yellow(":" + (lineNumber + line)), );
if (FAIL_FAST) { Deno.exit(1); } shouldFail = true; } }}
function checkCodeBlocks( content: string, filePath: string, lineNumber = 1,): void { for (const codeBlockMatch of content.matchAll(RX_CODE_BLOCK)) { const [, language, codeBlock] = codeBlockMatch; const shortFilePath = filePath.substring(ROOT_LENGTH + 1); const codeBlockLineNumber = content.slice(0, codeBlockMatch.index).split("\n").length;
switch (language.toLowerCase()) { case "ts": case "js": case "typescript": case "javascript": case "": if (language === "") { console.log( yellow("Warn") + " codeblock with no language specified at " + blue(shortFilePath) + yellow(":" + codeBlockLineNumber), ); }
checkImportStatements( codeBlock, filePath, lineNumber + codeBlockLineNumber, ); break;
default: console.log( yellow("Warn") + " skipping code block with language " + blue(language) + " at " + blue(shortFilePath) + yellow(":" + codeBlockLineNumber), ); break; } }}
for await ( const { path } of walk(root, { exts: EXTENSIONS, includeDirs: false, skip: EXCLUDED_PATHS.map((p) => new RegExp(p + "$")), })) { const content = await Deno.readTextFile(path); countChecked++;
if (path.endsWith(".md")) { checkCodeBlocks(content, path); } else { for (const jsdocMatch of content.matchAll(RX_JSDOC_COMMENT)) { const comment = jsdocMatch[0].replaceAll( RX_JSDOC_REMOVE_LEADING_ASTERISK, "", ); const commentLineNumber = content.slice(0, jsdocMatch.index).split("\n").length;
checkCodeBlocks(comment, path, commentLineNumber); } }}
console.log(`Checked ${countChecked} files`);if (shouldFail) Deno.exit(1);
std

Version Info

Tagged at
a year ago