@terra-symposium/standards-quality 0.0.0-stage → 0.5.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.
Files changed (67) hide show
  1. package/README.md +89 -2
  2. package/dist/collapse.d.ts +13 -0
  3. package/dist/collapse.d.ts.map +1 -0
  4. package/dist/collapse.js +151 -0
  5. package/dist/collapse.js.map +1 -0
  6. package/dist/documentation.d.ts +84 -0
  7. package/dist/documentation.d.ts.map +1 -0
  8. package/dist/documentation.js +1244 -0
  9. package/dist/documentation.js.map +1 -0
  10. package/dist/files.d.ts +39 -0
  11. package/dist/files.d.ts.map +1 -0
  12. package/dist/files.js +90 -0
  13. package/dist/files.js.map +1 -0
  14. package/dist/github-report.d.ts +89 -0
  15. package/dist/github-report.d.ts.map +1 -0
  16. package/dist/github-report.js +469 -0
  17. package/dist/github-report.js.map +1 -0
  18. package/dist/history-report.d.ts +52 -0
  19. package/dist/history-report.d.ts.map +1 -0
  20. package/dist/history-report.js +317 -0
  21. package/dist/history-report.js.map +1 -0
  22. package/dist/imports.d.ts +19 -0
  23. package/dist/imports.d.ts.map +1 -0
  24. package/dist/imports.js +90 -0
  25. package/dist/imports.js.map +1 -0
  26. package/dist/index.d.ts +19 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +19 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/inline-if.d.ts +13 -0
  31. package/dist/inline-if.d.ts.map +1 -0
  32. package/dist/inline-if.js +48 -0
  33. package/dist/inline-if.js.map +1 -0
  34. package/dist/naming.d.ts +148 -0
  35. package/dist/naming.d.ts.map +1 -0
  36. package/dist/naming.js +642 -0
  37. package/dist/naming.js.map +1 -0
  38. package/dist/object-forwarding.d.ts +44 -0
  39. package/dist/object-forwarding.d.ts.map +1 -0
  40. package/dist/object-forwarding.js +182 -0
  41. package/dist/object-forwarding.js.map +1 -0
  42. package/dist/patterns.d.ts +85 -0
  43. package/dist/patterns.d.ts.map +1 -0
  44. package/dist/patterns.js +905 -0
  45. package/dist/patterns.js.map +1 -0
  46. package/dist/port.d.ts +21 -0
  47. package/dist/port.d.ts.map +1 -0
  48. package/dist/port.js +81 -0
  49. package/dist/port.js.map +1 -0
  50. package/dist/progress.d.ts +16 -0
  51. package/dist/progress.d.ts.map +1 -0
  52. package/dist/progress.js +30 -0
  53. package/dist/progress.js.map +1 -0
  54. package/dist/runner.d.ts +257 -0
  55. package/dist/runner.d.ts.map +1 -0
  56. package/dist/runner.js +2481 -0
  57. package/dist/runner.js.map +1 -0
  58. package/dist/security.d.ts +19 -0
  59. package/dist/security.d.ts.map +1 -0
  60. package/dist/security.js +76 -0
  61. package/dist/security.js.map +1 -0
  62. package/dist/single-use.d.ts +60 -0
  63. package/dist/single-use.d.ts.map +1 -0
  64. package/dist/single-use.js +1209 -0
  65. package/dist/single-use.js.map +1 -0
  66. package/package.json +45 -5
  67. package/quality.schema.json +130 -0
@@ -0,0 +1,317 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import { readFileSync, writeFileSync } from 'node:fs';
3
+ import { resolve } from 'node:path';
4
+ /*//////////////////////////////////////////////////
5
+ REGEX
6
+ //////////////////////////////////////////////////*/
7
+ const S_REGEX = /\s+/;
8
+ const GIT_I_REGEX = /\.git$/i;
9
+ const A_F_D_40_I_REGEX = /^[a-f\d]{40}$/i;
10
+ const SRC_EXT = /\.(?:astro|c|cc|cpp|cs|css|go|html|java|js|jsx|jsonl|kt|less|m|mdx|php|py|rb|rs|scss|sh|sql|svelte|swift|ts|tsx|vue)$/i;
11
+ const EXCLUDED_DIR = /^(?:\.git|\.github|\.next|\.nuxt|\.output|\.turbo|\.vercel|\.netlify|\.astro|\.cache|build|coverage|dist|docs?|documentation|generated|vendor|node_modules|bower_components|target|out|public|static|storybook-static|test-results)$/i;
12
+ const EXCLUDED_FILE = /^(?:package(?:-lock)?\.json|pnpm-lock\.yaml|yarn\.lock|tsconfig(?:\.[^.]+)?\.json|(?:astro|eslint|prettier|vite|vitest|webpack|rollup|tailwind|postcss|jest|playwright|babel|next|netlify)\.config\.[^.]+|Dockerfile|Makefile)$/i;
13
+ const HISTORY_BATCH_SIZE = 50;
14
+ const BLOB_BATCH_SIZE = 250;
15
+ const GIT_OUTPUT_LIMIT = 128 * 1024 * 1024;
16
+ /**
17
+ * Return whether a tracked path belongs to the dashboard's source and test scope.
18
+ *
19
+ * @param path Repository-relative tracked file path.
20
+ * @return Whether the path contributes to history metrics.
21
+ */
22
+ export function isHistorySourcePath(path) {
23
+ const parts = path.split('/');
24
+ if (!parts.length || parts.some((part) => part === '..' || part === ''))
25
+ return false;
26
+ if (parts.slice(0, -1).some((part) => EXCLUDED_DIR.test(part)))
27
+ return false;
28
+ const file = parts.at(-1) ?? '';
29
+ return SRC_EXT.test(file) && !EXCLUDED_FILE.test(file) && !/\.(?:config|generated|gen|min|map|snap|lock)\.[^.]+$/i.test(file) && !/^\./.test(file);
30
+ }
31
+ /**
32
+ * Run Git in the selected checkout and return UTF-8 output.
33
+ *
34
+ * @param root Git checkout path.
35
+ * @param args Git command arguments.
36
+ * @param input Optional standard input for the command.
37
+ * @return The command's UTF-8 output.
38
+ */
39
+ function git(root, args, input) {
40
+ return execFileSync('git', args, { cwd: root, encoding: 'utf8', input, maxBuffer: GIT_OUTPUT_LIMIT, stdio: ['pipe', 'pipe', 'pipe'] });
41
+ }
42
+ /**
43
+ * Run Git in the selected checkout and preserve binary object output.
44
+ *
45
+ * @param root Git checkout path.
46
+ * @param args Git command arguments.
47
+ * @param input Standard input for the command.
48
+ * @return The command's binary output.
49
+ */
50
+ function gitBuffer(root, args, input) {
51
+ return execFileSync('git', args, { cwd: root, input, maxBuffer: GIT_OUTPUT_LIMIT, stdio: ['pipe', 'pipe', 'pipe'] });
52
+ }
53
+ /**
54
+ * Resolve the GitHub repository name from Actions metadata or the origin remote.
55
+ *
56
+ * @param root Git checkout path.
57
+ * @return The owner/repository name.
58
+ */
59
+ function repoName(root) {
60
+ const fromEnvironment = process.env.GITHUB_REPOSITORY;
61
+ if (fromEnvironment && /^[^/]+\/[^/]+$/.test(fromEnvironment))
62
+ return fromEnvironment.replace(GIT_I_REGEX, '');
63
+ const remote = git(root, ['config', '--get', 'remote.origin.url']).trim();
64
+ const match = remote.match(/(?:github\.com[:/])([^/]+\/[^/]+?)(?:\.git)?$/i);
65
+ if (!match)
66
+ throw new Error('Set GITHUB_REPOSITORY or use a GitHub origin remote to generate a history report.');
67
+ return match[1].replace(GIT_I_REGEX, '');
68
+ }
69
+ /**
70
+ * Read the before SHA from a GitHub push event when it is available.
71
+ *
72
+ * @return The push base SHA, or null when no usable base is present.
73
+ */
74
+ function pushBase() {
75
+ const ePath = process.env.GITHUB_EVENT_PATH;
76
+ if (!ePath)
77
+ return null;
78
+ try {
79
+ const e = JSON.parse(readFileSync(ePath, 'utf8'));
80
+ return typeof e.before === 'string' && A_F_D_40_I_REGEX.test(e.before) && !/^0{40}$/.test(e.before) ? e.before : null;
81
+ }
82
+ catch {
83
+ return null;
84
+ }
85
+ }
86
+ /**
87
+ * Calculate source-line additions and deletions against a commit's first parent.
88
+ *
89
+ * @param root Git checkout path.
90
+ * @param head Commit whose source changes are measured.
91
+ * @param parents Commit parent SHAs.
92
+ * @param stats Per-commit source line totals to update.
93
+ */
94
+ function srcChanges(root, head, parents, stats) {
95
+ if (!parents.length)
96
+ return;
97
+ const output = git(root, ['diff', '--numstat', '--no-renames', '--no-ext-diff', parents[0], head, '--']);
98
+ for (const line of output.split('\n')) {
99
+ if (!line)
100
+ continue;
101
+ const firstTab = line.indexOf('\t');
102
+ const secondTab = line.indexOf('\t', firstTab + 1);
103
+ if (firstTab < 0 || secondTab < 0)
104
+ continue;
105
+ const path = line.slice(secondTab + 1);
106
+ if (!isHistorySourcePath(path))
107
+ continue;
108
+ const additions = line.slice(0, firstTab) === '-' ? 0 : Number(line.slice(0, firstTab));
109
+ const deletions = line.slice(firstTab + 1, secondTab) === '-' ? 0 : Number(line.slice(firstTab + 1, secondTab));
110
+ const curr = stats.get(head) ?? { additions: 0, deletions: 0 };
111
+ curr.additions += additions;
112
+ curr.deletions += deletions;
113
+ stats.set(head, curr);
114
+ }
115
+ }
116
+ /**
117
+ * Read source-line stats for each commit and return merge commits for first-parent handling.
118
+ *
119
+ * @param root Git checkout path.
120
+ * @param range Git revision range to inspect.
121
+ * @param stats Per-commit source line totals to update.
122
+ * @return Merge commit SHAs requiring first-parent stats.
123
+ */
124
+ function readNumstatLog(root, range, stats) {
125
+ const output = git(root, ['log', '-z', '--format=%x1e%H%x00%P%x00', '--numstat', '--no-renames', '--root', '--reverse', '--topo-order', range]);
126
+ const merges = new Set();
127
+ for (const block of output.split('\x1e')) {
128
+ if (!block)
129
+ continue;
130
+ const headerEnd = block.indexOf('\n');
131
+ const header = headerEnd < 0 ? block : block.slice(0, headerEnd);
132
+ const [sha, parents = ''] = header.replace(/^\n/, '').split('\x00');
133
+ if (!A_F_D_40_I_REGEX.test(sha))
134
+ continue;
135
+ const parentList = parents.trim().split(S_REGEX).filter(Boolean);
136
+ if (parentList.length > 1) {
137
+ merges.add(sha);
138
+ continue;
139
+ }
140
+ const curr = { additions: 0, deletions: 0 };
141
+ const body = headerEnd < 0 ? '' : block.slice(headerEnd + 1);
142
+ for (const entry of body.split('\x00')) {
143
+ const firstTab = entry.indexOf('\t');
144
+ const secondTab = entry.indexOf('\t', firstTab + 1);
145
+ if (firstTab < 0 || secondTab < 0 || !isHistorySourcePath(entry.slice(secondTab + 1)))
146
+ continue;
147
+ const added = entry.slice(0, firstTab);
148
+ const removed = entry.slice(firstTab + 1, secondTab);
149
+ curr.additions += added === '-' ? 0 : Number(added);
150
+ curr.deletions += removed === '-' ? 0 : Number(removed);
151
+ }
152
+ stats.set(sha, curr);
153
+ }
154
+ return merges;
155
+ }
156
+ /**
157
+ * Return eligible source blob IDs from a commit's tree.
158
+ *
159
+ * @param root Git checkout path.
160
+ * @param sha Commit SHA to inspect.
161
+ * @return Eligible blob IDs in the commit tree.
162
+ */
163
+ function parseTree(root, sha) {
164
+ const tree = git(root, ['ls-tree', '-r', '-z', '--full-tree', sha]);
165
+ const blobs = [];
166
+ for (const entry of tree.split('\0')) {
167
+ const tab = entry.indexOf('\t');
168
+ if (tab < 0)
169
+ continue;
170
+ const [mode, type, blob] = entry.slice(0, tab).split(' ');
171
+ const path = entry.slice(tab + 1);
172
+ if (type === 'blob' && mode !== '120000' && isHistorySourcePath(path))
173
+ blobs.push(blob);
174
+ }
175
+ return blobs;
176
+ }
177
+ /**
178
+ * Count newline-terminated and final unterminated source lines.
179
+ *
180
+ * @param content Source blob bytes.
181
+ * @return The number of source lines.
182
+ */
183
+ function lineCount(content) {
184
+ if (!content.length)
185
+ return 0;
186
+ let lines = 0;
187
+ for (const byte of content)
188
+ if (byte === 10)
189
+ lines++;
190
+ return content.at(-1) === 10 ? lines : lines + 1;
191
+ }
192
+ /**
193
+ * Read blob contents in bounded batches and cache their line counts by object ID.
194
+ *
195
+ * @param root Git checkout path.
196
+ * @param blobs Blob object IDs to count.
197
+ * @param cache Blob line counts already computed.
198
+ */
199
+ function blobLineCounts(root, blobs, cache) {
200
+ const unknown = [...new Set(blobs)].filter((sha) => !cache.has(sha));
201
+ for (let start = 0; start < unknown.length; start += BLOB_BATCH_SIZE) {
202
+ const batch = unknown.slice(start, start + BLOB_BATCH_SIZE);
203
+ const output = gitBuffer(root, ['cat-file', '--batch'], `${batch.join('\n')}\n`);
204
+ let offset = 0;
205
+ for (const sha of batch) {
206
+ const headerEnd = output.indexOf(10, offset);
207
+ if (headerEnd < 0)
208
+ throw new Error(`Git did not return blob ${sha}.`);
209
+ const header = output.toString('utf8', offset, headerEnd).split(' ');
210
+ if (header[0] !== sha || header[1] !== 'blob')
211
+ throw new Error(`Git returned an invalid object for ${sha}.`);
212
+ const size = Number(header[2]);
213
+ const contentStart = headerEnd + 1;
214
+ const contentEnd = contentStart + size;
215
+ cache.set(sha, lineCount(output.subarray(contentStart, contentEnd)));
216
+ offset = contentEnd + 1;
217
+ }
218
+ }
219
+ }
220
+ /**
221
+ * Read author dates and parent IDs for commits in chronological topological order.
222
+ *
223
+ * @param root Git checkout path.
224
+ * @param range Git revision range to inspect.
225
+ * @return Commit SHAs, author dates, and parent SHAs.
226
+ */
227
+ function commitMetadata(root, range) {
228
+ return git(root, ['log', '--format=%H%x00%aI%x00%P', '--reverse', '--topo-order', range])
229
+ .trim()
230
+ .split('\n')
231
+ .filter(Boolean)
232
+ .map((line) => {
233
+ const [sha, authorDate, parents = ''] = line.split('\x00');
234
+ if (!A_F_D_40_I_REGEX.test(sha) || !Number.isFinite(Date.parse(authorDate)))
235
+ throw new Error('Git returned invalid commit metadata.');
236
+ return { sha, authorDate, parents: parents.trim().split(S_REGEX).filter(Boolean) };
237
+ });
238
+ }
239
+ /**
240
+ * Check whether a push base is reachable from the checked-out head.
241
+ *
242
+ * @param root Git checkout path.
243
+ * @param base Push base SHA.
244
+ * @param head Checked-out head SHA.
245
+ * @return Whether base is an ancestor of head.
246
+ */
247
+ function isAncestor(root, base, head) {
248
+ try {
249
+ execFileSync('git', ['merge-base', '--is-ancestor', base, head], { cwd: root, stdio: 'ignore' });
250
+ return true;
251
+ }
252
+ catch {
253
+ return false;
254
+ }
255
+ }
256
+ /**
257
+ * Build a complete snapshot or push delta from the local Git object database.
258
+ *
259
+ * @param root Path to the full Git checkout.
260
+ * @param opts Optional repository, branch, or push-base overrides.
261
+ * @return A versioned history report with normalized commit counts.
262
+ */
263
+ export function createHistoryReport(root, opts = {}) {
264
+ const headSha = git(root, ['rev-parse', 'HEAD']).trim();
265
+ const branch = opts.branch ?? process.env.GITHUB_REF_NAME ?? git(root, ['branch', '--show-current']).trim();
266
+ if (!branch)
267
+ throw new Error('Set GITHUB_REF_NAME or pass a checked-out branch to generate a history report.');
268
+ const base = opts.baseSha === undefined ? pushBase() : opts.baseSha;
269
+ const delta = !!base && isAncestor(root, base, headSha);
270
+ const range = delta ? `${base}..${headSha}` : headSha;
271
+ const commits = commitMetadata(root, range);
272
+ const changes = new Map();
273
+ const merges = readNumstatLog(root, range, changes);
274
+ for (const commit of commits)
275
+ if (merges.has(commit.sha))
276
+ srcChanges(root, commit.sha, commit.parents, changes);
277
+ const lineCounts = new Map();
278
+ const reportCommits = [];
279
+ for (let start = 0; start < commits.length; start += HISTORY_BATCH_SIZE) {
280
+ const batch = commits.slice(start, start + HISTORY_BATCH_SIZE).map((commit) => ({ commit, blobs: parseTree(root, commit.sha) }));
281
+ blobLineCounts(root, batch.flatMap((i) => i.blobs), lineCounts);
282
+ for (const { commit, blobs } of batch) {
283
+ const changed = changes.get(commit.sha) ?? { additions: 0, deletions: 0 };
284
+ reportCommits.push({
285
+ sha: commit.sha,
286
+ authorDate: commit.authorDate,
287
+ additions: changed.additions,
288
+ deletions: changed.deletions,
289
+ sourceLines: blobs.reduce((total, blob) => total + (lineCounts.get(blob) ?? 0), 0),
290
+ });
291
+ }
292
+ }
293
+ return {
294
+ schemaVersion: 1,
295
+ mode: delta ? 'delta' : 'snapshot',
296
+ repository: opts.repository ?? repoName(root),
297
+ branch,
298
+ headSha,
299
+ baseSha: delta ? base : null,
300
+ generatedAt: new Date().toISOString(),
301
+ commits: reportCommits,
302
+ };
303
+ }
304
+ /**
305
+ * Write a generated report to a JSON file in the checkout.
306
+ *
307
+ * @param root Path to the full Git checkout.
308
+ * @param path Output path relative to the checkout.
309
+ * @param opts Optional repository, branch, or push-base overrides.
310
+ * @return The generated history report.
311
+ */
312
+ export function writeHistoryReport(root, path, opts) {
313
+ const report = createHistoryReport(root, opts);
314
+ writeFileSync(resolve(root, path), `${JSON.stringify(report, null, 2)}\n`);
315
+ return report;
316
+ }
317
+ //# sourceMappingURL=history-report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history-report.js","sourceRoot":"","sources":["../src/history-report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * packages/quality/src/imports.ts
3
+ * Resolves import specifiers to their corresponding files.
4
+ */
5
+ import type { QualityCfg } from './runner.js';
6
+ /** An unresolved local import specifier and the file that contains it. */
7
+ export type ImportFailure = {
8
+ importer: string;
9
+ specifier: string;
10
+ };
11
+ /**
12
+ * Checks all configured internal imports, including assets and extensionless modules.
13
+ *
14
+ * @param cfg Quality configuration defining the source scope and alias rules.
15
+ *
16
+ * @return Internal import failures whose specifiers could not be resolved.
17
+ */
18
+ export declare function checkImports(cfg: QualityCfg): ImportFailure[];
19
+ //# sourceMappingURL=imports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"imports.d.ts","sourceRoot":"","sources":["../src/imports.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAO9C,0EAA0E;AAC1E,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAkDpE;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,aAAa,EAAE,CAW7D"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * packages/quality/src/imports.ts
3
+ * Resolves import specifiers to their corresponding files.
4
+ */
5
+ /*//////////////////////////////////////////////////
6
+ IMPORTS
7
+ //////////////////////////////////////////////////*/
8
+ // API
9
+ import ts from 'typescript';
10
+ import { dirname, extname, join, resolve } from 'node:path';
11
+ import { displayPath, isFile, srcFiles } from './files.js';
12
+ import { readFileSync } from 'node:fs';
13
+ /*//////////////////////////////////////////////////
14
+ CONFIG
15
+ //////////////////////////////////////////////////*/
16
+ const MODULE_EXTS = ['', '.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.mts', '.cts', '.astro', '.mdx', '.json', '.css', '.scss', '.svg', '.png', '.jpg', '.jpeg', '.webp'];
17
+ /*//////////////////////////////////////////////////
18
+ HELPERS
19
+ //////////////////////////////////////////////////*/
20
+ /**
21
+ * Resolves a relative or configured alias import against the repository filesystem.
22
+ *
23
+ * @param specifier Module specifier written by the importing source file.
24
+ * @param importer Absolute path of the file containing the import.
25
+ * @param cfg Quality configuration containing aliases and the repository root.
26
+ *
27
+ * @return The resolved file path, or `null` when no supported target exists.
28
+ */
29
+ function resolveImport(specifier, importer, cfg) {
30
+ const alias = Object.entries(cfg.aliases ?? {}).find(([p]) => specifier.startsWith(p));
31
+ const raw = alias ? resolve(cfg.root, alias[1], specifier.slice(alias[0].length)) : specifier.startsWith('.') ? resolve(dirname(importer), specifier) : null;
32
+ if (!raw)
33
+ return null;
34
+ const stripped = /\.(?:c|m)?(?:j|t)sx?$/.test(raw) ? raw.slice(0, raw.lastIndexOf('.')) : raw;
35
+ for (const b of [...new Set([raw, stripped])])
36
+ for (const ext of MODULE_EXTS) {
37
+ const candidate = b + ext;
38
+ if (isFile(candidate))
39
+ return candidate;
40
+ const idx = join(b, `index${ext}`);
41
+ if (isFile(idx))
42
+ return idx;
43
+ }
44
+ return null;
45
+ }
46
+ /**
47
+ * Extracts static import, export, dynamic-import, and CommonJS require specifiers from a source file.
48
+ *
49
+ * @param fileName Absolute path to the source file to parse.
50
+ *
51
+ * @return Module specifiers found in the file.
52
+ */
53
+ function specifiers(fileName) {
54
+ const src = readFileSync(fileName, 'utf8');
55
+ const file = ts.createSourceFile(fileName, src, ts.ScriptTarget.Latest, true);
56
+ const vals = [];
57
+ ts.forEachChild(file, (n) => {
58
+ if (ts.isImportDeclaration(n) && ts.isStringLiteral(n.moduleSpecifier))
59
+ vals.push(n.moduleSpecifier.text);
60
+ if (ts.isExportDeclaration(n) && n.moduleSpecifier && ts.isStringLiteral(n.moduleSpecifier))
61
+ vals.push(n.moduleSpecifier.text);
62
+ if (ts.isCallExpression(n) && n.arguments.length === 1 && ts.isStringLiteral(n.arguments[0]) && (n.expression.kind === ts.SyntaxKind.ImportKeyword || n.expression.getText(file) === 'require'))
63
+ vals.push(n.arguments[0].text);
64
+ });
65
+ return vals;
66
+ }
67
+ /**
68
+ * Checks all configured internal imports, including assets and extensionless modules.
69
+ *
70
+ * @param cfg Quality configuration defining the source scope and alias rules.
71
+ *
72
+ * @return Internal import failures whose specifiers could not be resolved.
73
+ */
74
+ export function checkImports(cfg) {
75
+ const failures = [];
76
+ for (const i of srcFiles(cfg)) {
77
+ for (const s of specifiers(i)) {
78
+ if (cfg.externalPrefixes?.some((p) => s.startsWith(p)))
79
+ continue;
80
+ if (!s.startsWith('.') && !Object.keys(cfg.aliases ?? {}).some((p) => s.startsWith(p)))
81
+ continue;
82
+ if (s.startsWith('.') && extname(s) && !MODULE_EXTS.includes(extname(s)))
83
+ continue;
84
+ if (!resolveImport(s, i, cfg))
85
+ failures.push({ importer: displayPath(cfg, i), specifier: s });
86
+ }
87
+ }
88
+ return failures;
89
+ }
90
+ //# sourceMappingURL=imports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"imports.js","sourceRoot":"","sources":["../src/imports.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * packages/quality/src/index.ts
3
+ * Public API for the consolidated Terra quality package.
4
+ */
5
+ export * from './collapse.js';
6
+ export * from './files.js';
7
+ export * from './history-report.js';
8
+ export * from './github-report.js';
9
+ export * from './imports.js';
10
+ export * from './inline-if.js';
11
+ export * from './documentation.js';
12
+ export * from './naming.js';
13
+ export * from './object-forwarding.js';
14
+ export * from './port.js';
15
+ export * from './runner.js';
16
+ export * from './single-use.js';
17
+ export * from './security.js';
18
+ export * from './patterns.js';
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,wBAAwB,CAAC;AACvC,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ /**
2
+ * packages/quality/src/index.ts
3
+ * Public API for the consolidated Terra quality package.
4
+ */
5
+ export * from './collapse.js';
6
+ export * from './files.js';
7
+ export * from './history-report.js';
8
+ export * from './github-report.js';
9
+ export * from './imports.js';
10
+ export * from './inline-if.js';
11
+ export * from './documentation.js';
12
+ export * from './naming.js';
13
+ export * from './object-forwarding.js';
14
+ export * from './port.js';
15
+ export * from './runner.js';
16
+ export * from './single-use.js';
17
+ export * from './security.js';
18
+ export * from './patterns.js';
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,wBAAwB,CAAC;AACvC,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * packages/quality/src/inline-if.ts
3
+ * Inlines single-statement conditional blocks without changing nested blocks.
4
+ */
5
+ /**
6
+ * Collapses single-statement conditional blocks without changing nested blocks.
7
+ *
8
+ * @param fileName Absolute path to the source file to rewrite.
9
+ *
10
+ * @return `true` when at least one eligible conditional was collapsed.
11
+ */
12
+ export declare function collapseInlineIfs(fileName: string): boolean;
13
+ //# sourceMappingURL=inline-if.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inline-if.d.ts","sourceRoot":"","sources":["../src/inline-if.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAcH;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAyB3D"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * packages/quality/src/inline-if.ts
3
+ * Inlines single-statement conditional blocks without changing nested blocks.
4
+ */
5
+ /*//////////////////////////////////////////////////
6
+ IMPORTS
7
+ //////////////////////////////////////////////////*/
8
+ // API
9
+ import ts from 'typescript';
10
+ import { readFileSync, writeFileSync } from 'node:fs';
11
+ /*//////////////////////////////////////////////////
12
+ HELPERS
13
+ //////////////////////////////////////////////////*/
14
+ /**
15
+ * Collapses single-statement conditional blocks without changing nested blocks.
16
+ *
17
+ * @param fileName Absolute path to the source file to rewrite.
18
+ *
19
+ * @return `true` when at least one eligible conditional was collapsed.
20
+ */
21
+ export function collapseInlineIfs(fileName) {
22
+ const src = readFileSync(fileName, 'utf8');
23
+ const parsed = ts.createSourceFile(fileName, src, ts.ScriptTarget.Latest, true, fileName.endsWith('x') ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
24
+ const edits = [];
25
+ const visit = (node) => {
26
+ if (ts.isIfStatement(node) && ts.isBlock(node.thenStatement) && node.thenStatement.statements.length === 1) {
27
+ const statement = node.thenStatement.statements[0];
28
+ const sStatement = ts.isExpressionStatement(statement) || ts.isReturnStatement(statement) || ts.isThrowStatement(statement) || ts.isBreakStatement(statement) || ts.isContinueStatement(statement);
29
+ const danglingElse = Boolean(node.elseStatement && ts.isIfStatement(statement) && !statement.elseStatement);
30
+ const body = src.slice(node.thenStatement.getStart(parsed) + 1, node.thenStatement.end - 1);
31
+ if (sStatement && !danglingElse && !body.includes('//') && !body.includes('/*')) {
32
+ edits.push({ start: node.thenStatement.getStart(parsed), end: statement.getStart(parsed), text: '' });
33
+ edits.push({ start: statement.end, end: node.thenStatement.end, text: '' });
34
+ }
35
+ }
36
+ // Nested conditionals are deliberately retained. Removing their braces can
37
+ // change which conditional owns a following else even when the result parses.
38
+ if (!ts.isIfStatement(node))
39
+ ts.forEachChild(node, visit);
40
+ };
41
+ visit(parsed);
42
+ const n = edits.sort((a, b) => b.start - a.start).reduce((text, edit) => `${text.slice(0, edit.start)}${edit.text}${text.slice(edit.end)}`, src);
43
+ if (n === src)
44
+ return false;
45
+ writeFileSync(fileName, n);
46
+ return true;
47
+ }
48
+ //# sourceMappingURL=inline-if.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inline-if.js","sourceRoot":"","sources":["../src/inline-if.ts"],"names":[],"mappings":"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"}