Skip to content

Commit aced042

Browse files
committed
Bail out early for (compiled) JSON files (resolves #883)
1 parent 17f2224 commit aced042

File tree

8 files changed

+46
-5
lines changed

8 files changed

+46
-5
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import identifier from './module.mdx';
22
import Component from './Component.vue';
33
import { createApp } from 'vue';
4+
import data from './compiled.json';
45

56
identifier;
67
createApp(Component);
8+
data;

packages/knip/fixtures/compilers/knip.ts

+6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ export default {
66
if (!path) throw new Error('Path not passed to compiler');
77
return '';
88
},
9+
json: (content, fileName) => {
10+
if (fileName.includes('compiled')) {
11+
return `export default ${content}`;
12+
}
13+
return content;
14+
},
915
css: async (text: string) => {
1016
return [...text.matchAll(/(?<=@)import[^;]+/g)].join('\n');
1117
},
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
{
22
"compilerOptions": {
33
"target": "ES2015",
4-
"jsx": "preserve"
4+
"jsx": "preserve",
5+
"resolveJsonModule": true,
6+
"module": "nodenext",
7+
"moduleResolution": "nodenext"
58
}
69
}

packages/knip/src/ProjectPrincipal.ts

+10
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ import type { SourceFileManager } from './typescript/SourceFileManager.js';
1111
import { createHosts } from './typescript/create-hosts.js';
1212
import { _getImportsAndExports } from './typescript/get-imports-and-exports.js';
1313
import type { ResolveModuleNames } from './typescript/resolve-module-names.js';
14+
import { isJSON } from './typescript/visitors/helpers.js';
1415
import { timerify } from './util/Performance.js';
1516
import { compact } from './util/array.js';
17+
import { createExport, createFileNode } from './util/dependency-graph.js';
1618
import { getPackageNameFromModuleSpecifier, isStartsLikePackageName, sanitizeSpecifier } from './util/modules.js';
1719
import { dirname, extname, isInNodeModules, join } from './util/path.js';
1820
import type { ToSourceFilePath } from './util/to-source-path.js';
@@ -244,6 +246,14 @@ export class ProjectPrincipal {
244246

245247
const skipExports = this.skipExportsAnalysis.has(filePath);
246248

249+
if (isJSON(sourceFile)) {
250+
// Exception to allow .json files to be imported + compiled conditionally
251+
const fileNode = createFileNode();
252+
if (/^\s*[[{]/.test(sourceFile.text)) return fileNode;
253+
fileNode.exports.set('default', createExport({ identifier: 'default' }));
254+
return fileNode;
255+
}
256+
247257
const resolve = (specifier: string) => this.backend.resolveModuleNames([specifier], sourceFile.fileName)[0];
248258

249259
const { imports, ...rest } = _getImportsAndExports(sourceFile, resolve, typeChecker, { ...options, skipExports });

packages/knip/src/typescript/visitors/helpers.ts

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ export const isJS = (sourceFile: BoundSourceFile) =>
99

1010
export const isModule = (sourceFile: BoundSourceFile) => ts.isExternalModule(sourceFile);
1111

12+
export const isJSON = (sourceFile: BoundSourceFile) => sourceFile.scriptKind === ts.ScriptKind.JSON;
13+
1214
export function getImportsFromPragmas(sourceFile: BoundSourceFile) {
1315
const importNodes: ImportNode[] = [];
1416

packages/knip/src/util/dependency-graph.ts

+16-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import type {
22
DependencyGraph,
3+
Export,
34
FileNode,
45
IdToFileMap,
56
IdToNsToFileMap,
67
ImportDetails,
78
ImportMap,
89
} from '../types/dependency-graph.js';
10+
import { SymbolType } from '../types/issues.js';
911

1012
export const getOrCreateFileNode = (graph: DependencyGraph, filePath: string) =>
1113
graph.get(filePath) ?? createFileNode();
@@ -34,7 +36,7 @@ export const updateImportMap = (file: FileNode, importMap: ImportMap, graph: Dep
3436
}
3537
};
3638

37-
const createFileNode = (): FileNode => ({
39+
export const createFileNode = (): FileNode => ({
3840
imports: {
3941
internal: new Map(),
4042
external: new Set(),
@@ -46,6 +48,19 @@ const createFileNode = (): FileNode => ({
4648
traceRefs: new Set(),
4749
});
4850

51+
export const createExport = ({ identifier }: { identifier: string }): Export => ({
52+
identifier,
53+
pos: 0,
54+
line: 1,
55+
col: 1,
56+
type: SymbolType.UNKNOWN,
57+
members: [],
58+
jsDocTags: new Set(),
59+
refs: [0, false],
60+
fixes: [],
61+
isReExport: false,
62+
});
63+
4964
export const createImports = (): ImportDetails => ({
5065
refs: new Set(),
5166
imported: new Map(),

packages/knip/test/compilers.test.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ test('Support compiler functions in config', async () => {
1515

1616
assert(issues.files.has(join(cwd, 'unused.css')));
1717
assert(issues.files.has(join(cwd, 'unused.md')));
18+
assert(issues.files.has(join(cwd, 'package.json')));
19+
assert(issues.files.has(join(cwd, 'tsconfig.json')));
1820

1921
assert.deepEqual(counters, {
2022
...baseCounters,
21-
files: 2,
22-
processed: 11,
23-
total: 11,
23+
files: 4,
24+
processed: 14,
25+
total: 14,
2426
});
2527
});

0 commit comments

Comments
 (0)