@servicetitan/startup 34.0.0 → 34.0.1

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.
@@ -19,6 +19,8 @@ export declare class RequireTsconfigReferences implements PackageRule {
19
19
  private collectTsConfigFiles;
20
20
  private findMissingDependencyReferences;
21
21
  private readonly checkTsConfigReferences;
22
+ private isDefaultTsConfig;
23
+ private isDirectory;
22
24
  }
23
25
  export {};
24
26
  //# sourceMappingURL=require-tsconfig-references.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"require-tsconfig-references.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/review/rules/require-tsconfig-references.ts"],"names":[],"mappings":"AAIA,OAAO,EAAwB,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAOpF,UAAU,SAAS;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,SAAS,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;AAEhD,qBAAa,yBAA0B,YAAW,WAAW;IACzD,OAAO,CAAC,qBAAqB,CAAuB;IACpD,OAAO,CAAC,qBAAqB,CAAuB;IACpD,OAAO,CAAC,qBAAqB,CAAe;IAE5C,IAAI,EAAE,WAEL;IAED,GAAG,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,EAAE;IAYlC,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS;IAmBvB,OAAO,CAAC,oBAAoB;IAY5B,OAAO,CAAC,qBAAqB;IAI7B,OAAO,CAAC,6BAA6B;IAuBrC,OAAO,CAAC,wBAAwB;IAQhC,OAAO,CAAC,oBAAoB;IAS5B,OAAO,CAAC,+BAA+B;IA6BvC,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAWtC;CACL"}
1
+ {"version":3,"file":"require-tsconfig-references.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/review/rules/require-tsconfig-references.ts"],"names":[],"mappings":"AAIA,OAAO,EAAwB,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAOpF,UAAU,SAAS;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,SAAS,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;AAEhD,qBAAa,yBAA0B,YAAW,WAAW;IACzD,OAAO,CAAC,qBAAqB,CAAuB;IACpD,OAAO,CAAC,qBAAqB,CAAuB;IACpD,OAAO,CAAC,qBAAqB,CAAe;IAE5C,IAAI,EAAE,WAEL;IAED,GAAG,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,EAAE;IAYlC,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS;IAgBvB,OAAO,CAAC,oBAAoB;IAY5B,OAAO,CAAC,qBAAqB;IAO7B,OAAO,CAAC,6BAA6B;IAwBrC,OAAO,CAAC,wBAAwB;IAWhC,OAAO,CAAC,oBAAoB;IAS5B,OAAO,CAAC,+BAA+B;IA6BvC,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAWtC;IAEF,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,WAAW;CAOtB"}
@@ -54,10 +54,7 @@ class RequireTsconfigReferences {
54
54
  return;
55
55
  }
56
56
  const { tsconfigPath, expectedPath } = data;
57
- const tsconfig = (0, _utils.readJsonSafe)(tsconfigPath);
58
- if (!tsconfig) {
59
- return;
60
- }
57
+ const tsconfig = (0, _utils.readJson)(tsconfigPath);
61
58
  const references = (_tsconfig_references = tsconfig.references) !== null && _tsconfig_references !== void 0 ? _tsconfig_references : [];
62
59
  references.push({
63
60
  path: expectedPath
@@ -75,6 +72,9 @@ class RequireTsconfigReferences {
75
72
  return Object.keys(dependencies).filter((dependency)=>this.workspacePackageNames.has(dependency));
76
73
  }
77
74
  normalizeTsConfigPath(filePath) {
75
+ if (this.isDirectory(filePath)) {
76
+ return _nodepath.default.join(filePath, 'tsconfig.json');
77
+ }
78
78
  return filePath.endsWith('.json') ? filePath : `${filePath}.json`;
79
79
  }
80
80
  getTsConfigReferencedPackages(tsconfigPath) {
@@ -85,8 +85,7 @@ class RequireTsconfigReferences {
85
85
  const tsconfigDir = _nodepath.default.dirname(tsconfigPath);
86
86
  const referencedPackages = new Set();
87
87
  for (const reference of config.references){
88
- const normalizedPath = this.normalizeTsConfigPath(reference.path);
89
- const resolvedRefPath = _nodepath.default.resolve(tsconfigDir, normalizedPath);
88
+ const resolvedRefPath = this.normalizeTsConfigPath(_nodepath.default.resolve(tsconfigDir, reference.path));
90
89
  const refDir = _nodepath.default.dirname(resolvedRefPath);
91
90
  const packageName = this.locationToPackageName.get(refDir);
92
91
  if (packageName) {
@@ -99,7 +98,8 @@ class RequireTsconfigReferences {
99
98
  const relativePath = _nodepath.default.relative(fromLocation, toLocation);
100
99
  const tsconfigFile = (0, _utils.getTsConfig)(toLocation);
101
100
  const tsconfigName = _nodepath.default.basename(tsconfigFile);
102
- return _nodepath.default.join(relativePath, tsconfigName).replaceAll('\\', '/');
101
+ const referencePath = this.isDefaultTsConfig(tsconfigName) ? relativePath : _nodepath.default.join(relativePath, tsconfigName);
102
+ return referencePath.replaceAll('\\', '/');
103
103
  }
104
104
  collectTsConfigFiles(location) {
105
105
  const tsconfigFiles = (0, _glob.globSync)([
@@ -128,6 +128,16 @@ class RequireTsconfigReferences {
128
128
  };
129
129
  });
130
130
  }
131
+ isDefaultTsConfig(name) {
132
+ return name === 'tsconfig.json';
133
+ }
134
+ isDirectory(file) {
135
+ try {
136
+ return _nodefs.default.statSync(file).isDirectory();
137
+ } catch (unused) {
138
+ return false;
139
+ }
140
+ }
131
141
  constructor(){
132
142
  _define_property(this, "packageNameToLocation", void 0);
133
143
  _define_property(this, "locationToPackageName", void 0);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/cli/commands/review/rules/require-tsconfig-references.ts"],"sourcesContent":["import { globSync } from 'glob';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { getTsConfig, prettifySync, readJsonSafe } from '../../../../utils';\nimport { FixCategory, Package, PackageError, PackageRule, Project } from '../types';\nimport { checkPackages } from '../utils';\n\ninterface TsConfig {\n references?: { path: string }[];\n}\n\ninterface ErrorData {\n tsconfigPath: string;\n missingReference: string;\n expectedPath: string;\n}\n\nexport type RuleError = PackageError<ErrorData>;\n\nexport class RequireTsconfigReferences implements PackageRule {\n private packageNameToLocation!: Map<string, string>;\n private locationToPackageName!: Map<string, string>;\n private workspacePackageNames!: Set<string>;\n\n get id() {\n return 'require-tsconfig-references';\n }\n\n run(project: Project): RuleError[] {\n this.packageNameToLocation = new Map(\n project.packages.map(({ name, location }) => [name, location])\n );\n this.locationToPackageName = new Map(\n project.packages.map(({ name, location }) => [path.resolve(location), name])\n );\n this.workspacePackageNames = new Set(project.packages.map(({ name }) => name));\n\n return checkPackages(this, project, this.checkTsConfigReferences);\n }\n\n fix({ data }: RuleError) {\n if (!data) {\n return;\n }\n\n const { tsconfigPath, expectedPath } = data;\n const tsconfig = readJsonSafe<TsConfig>(tsconfigPath);\n if (!tsconfig) {\n return;\n }\n\n const references = tsconfig.references ?? [];\n references.push({ path: expectedPath });\n tsconfig.references = references;\n\n fs.writeFileSync(tsconfigPath, JSON.stringify(tsconfig) + '\\n', 'utf-8');\n prettifySync(tsconfigPath);\n }\n\n private getLocalDependencies(pkg: Package) {\n const dependencies = {\n ...pkg.dependencies,\n ...pkg.devDependencies,\n ...pkg.peerDependencies,\n };\n\n return Object.keys(dependencies).filter(dependency =>\n this.workspacePackageNames.has(dependency)\n );\n }\n\n private normalizeTsConfigPath(filePath: string): string {\n return filePath.endsWith('.json') ? filePath : `${filePath}.json`;\n }\n\n private getTsConfigReferencedPackages(tsconfigPath: string) {\n const config = readJsonSafe<TsConfig>(tsconfigPath);\n if (!config?.references) {\n return new Set<string>();\n }\n\n const tsconfigDir = path.dirname(tsconfigPath);\n const referencedPackages = new Set<string>();\n\n for (const reference of config.references) {\n const normalizedPath = this.normalizeTsConfigPath(reference.path);\n const resolvedRefPath = path.resolve(tsconfigDir, normalizedPath);\n const refDir = path.dirname(resolvedRefPath);\n const packageName = this.locationToPackageName.get(refDir);\n\n if (packageName) {\n referencedPackages.add(packageName);\n }\n }\n\n return referencedPackages;\n }\n\n private getExpectedReferencePath(fromLocation: string, toLocation: string) {\n const relativePath = path.relative(fromLocation, toLocation);\n const tsconfigFile = getTsConfig(toLocation);\n const tsconfigName = path.basename(tsconfigFile);\n\n return path.join(relativePath, tsconfigName).replaceAll('\\\\', '/');\n }\n\n private collectTsConfigFiles(location: string): string[] {\n const tsconfigFiles = globSync(['tsconfig.json', 'tsconfig.*.json'], {\n absolute: false,\n cwd: location,\n });\n\n return tsconfigFiles.map(tsconfigFile => path.join(location, tsconfigFile));\n }\n\n private findMissingDependencyReferences(\n pkg: Package,\n tsconfigPath: string,\n localDependencies: string[]\n ): RuleError[] {\n const referencedPackages = this.getTsConfigReferencedPackages(tsconfigPath);\n\n return localDependencies\n .filter(dependency => !referencedPackages.has(dependency))\n .map(dependency => {\n const dependencyLocation = this.packageNameToLocation.get(dependency)!;\n\n return {\n id: this.id,\n message: `missing reference for dependency: ${dependency}`,\n location: tsconfigPath,\n fixable: FixCategory.normal,\n data: {\n tsconfigPath,\n missingReference: dependency,\n expectedPath: this.getExpectedReferencePath(\n pkg.location,\n dependencyLocation\n ),\n },\n };\n });\n }\n\n private readonly checkTsConfigReferences = (pkg: Package) => {\n if (pkg.location === '.') {\n return [];\n }\n\n const tsconfigFiles = this.collectTsConfigFiles(pkg.location);\n const localDependencies = this.getLocalDependencies(pkg);\n\n return tsconfigFiles.flatMap(tsconfigPath =>\n this.findMissingDependencyReferences(pkg, tsconfigPath, localDependencies)\n );\n };\n}\n"],"names":["RequireTsconfigReferences","id","run","project","packageNameToLocation","Map","packages","map","name","location","locationToPackageName","path","resolve","workspacePackageNames","Set","checkPackages","checkTsConfigReferences","fix","data","tsconfig","tsconfigPath","expectedPath","readJsonSafe","references","push","fs","writeFileSync","JSON","stringify","prettifySync","getLocalDependencies","pkg","dependencies","devDependencies","peerDependencies","Object","keys","filter","dependency","has","normalizeTsConfigPath","filePath","endsWith","getTsConfigReferencedPackages","config","tsconfigDir","dirname","referencedPackages","reference","normalizedPath","resolvedRefPath","refDir","packageName","get","add","getExpectedReferencePath","fromLocation","toLocation","relativePath","relative","tsconfigFile","getTsConfig","tsconfigName","basename","join","replaceAll","collectTsConfigFiles","tsconfigFiles","globSync","absolute","cwd","findMissingDependencyReferences","localDependencies","dependencyLocation","message","fixable","FixCategory","normal","missingReference","flatMap"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../src/cli/commands/review/rules/require-tsconfig-references.ts"],"sourcesContent":["import { globSync } from 'glob';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { getTsConfig, prettifySync, readJson, readJsonSafe } from '../../../../utils';\nimport { FixCategory, Package, PackageError, PackageRule, Project } from '../types';\nimport { checkPackages } from '../utils';\n\ninterface TsConfig {\n references?: { path: string }[];\n}\n\ninterface ErrorData {\n tsconfigPath: string;\n missingReference: string;\n expectedPath: string;\n}\n\nexport type RuleError = PackageError<ErrorData>;\n\nexport class RequireTsconfigReferences implements PackageRule {\n private packageNameToLocation!: Map<string, string>;\n private locationToPackageName!: Map<string, string>;\n private workspacePackageNames!: Set<string>;\n\n get id() {\n return 'require-tsconfig-references';\n }\n\n run(project: Project): RuleError[] {\n this.packageNameToLocation = new Map(\n project.packages.map(({ name, location }) => [name, location])\n );\n this.locationToPackageName = new Map(\n project.packages.map(({ name, location }) => [path.resolve(location), name])\n );\n this.workspacePackageNames = new Set(project.packages.map(({ name }) => name));\n\n return checkPackages(this, project, this.checkTsConfigReferences);\n }\n\n fix({ data }: RuleError) {\n if (!data) {\n return;\n }\n\n const { tsconfigPath, expectedPath } = data;\n const tsconfig = readJson<TsConfig>(tsconfigPath);\n\n const references = tsconfig.references ?? [];\n references.push({ path: expectedPath });\n tsconfig.references = references;\n\n fs.writeFileSync(tsconfigPath, JSON.stringify(tsconfig) + '\\n', 'utf-8');\n prettifySync(tsconfigPath);\n }\n\n private getLocalDependencies(pkg: Package) {\n const dependencies = {\n ...pkg.dependencies,\n ...pkg.devDependencies,\n ...pkg.peerDependencies,\n };\n\n return Object.keys(dependencies).filter(dependency =>\n this.workspacePackageNames.has(dependency)\n );\n }\n\n private normalizeTsConfigPath(filePath: string): string {\n if (this.isDirectory(filePath)) {\n return path.join(filePath, 'tsconfig.json');\n }\n return filePath.endsWith('.json') ? filePath : `${filePath}.json`;\n }\n\n private getTsConfigReferencedPackages(tsconfigPath: string) {\n const config = readJsonSafe<TsConfig>(tsconfigPath);\n if (!config?.references) {\n return new Set<string>();\n }\n\n const tsconfigDir = path.dirname(tsconfigPath);\n const referencedPackages = new Set<string>();\n\n for (const reference of config.references) {\n const resolvedRefPath = this.normalizeTsConfigPath(\n path.resolve(tsconfigDir, reference.path)\n );\n const refDir = path.dirname(resolvedRefPath);\n const packageName = this.locationToPackageName.get(refDir);\n\n if (packageName) {\n referencedPackages.add(packageName);\n }\n }\n\n return referencedPackages;\n }\n\n private getExpectedReferencePath(fromLocation: string, toLocation: string) {\n const relativePath = path.relative(fromLocation, toLocation);\n const tsconfigFile = getTsConfig(toLocation);\n const tsconfigName = path.basename(tsconfigFile);\n const referencePath = this.isDefaultTsConfig(tsconfigName)\n ? relativePath\n : path.join(relativePath, tsconfigName);\n\n return referencePath.replaceAll('\\\\', '/');\n }\n\n private collectTsConfigFiles(location: string): string[] {\n const tsconfigFiles = globSync(['tsconfig.json', 'tsconfig.*.json'], {\n absolute: false,\n cwd: location,\n });\n\n return tsconfigFiles.map(tsconfigFile => path.join(location, tsconfigFile));\n }\n\n private findMissingDependencyReferences(\n pkg: Package,\n tsconfigPath: string,\n localDependencies: string[]\n ): RuleError[] {\n const referencedPackages = this.getTsConfigReferencedPackages(tsconfigPath);\n\n return localDependencies\n .filter(dependency => !referencedPackages.has(dependency))\n .map(dependency => {\n const dependencyLocation = this.packageNameToLocation.get(dependency)!;\n\n return {\n id: this.id,\n message: `missing reference for dependency: ${dependency}`,\n location: tsconfigPath,\n fixable: FixCategory.normal,\n data: {\n tsconfigPath,\n missingReference: dependency,\n expectedPath: this.getExpectedReferencePath(\n pkg.location,\n dependencyLocation\n ),\n },\n };\n });\n }\n\n private readonly checkTsConfigReferences = (pkg: Package) => {\n if (pkg.location === '.') {\n return [];\n }\n\n const tsconfigFiles = this.collectTsConfigFiles(pkg.location);\n const localDependencies = this.getLocalDependencies(pkg);\n\n return tsconfigFiles.flatMap(tsconfigPath =>\n this.findMissingDependencyReferences(pkg, tsconfigPath, localDependencies)\n );\n };\n\n private isDefaultTsConfig(name: string) {\n return name === 'tsconfig.json';\n }\n\n private isDirectory(file: string) {\n try {\n return fs.statSync(file).isDirectory();\n } catch {\n return false;\n }\n }\n}\n"],"names":["RequireTsconfigReferences","id","run","project","packageNameToLocation","Map","packages","map","name","location","locationToPackageName","path","resolve","workspacePackageNames","Set","checkPackages","checkTsConfigReferences","fix","data","tsconfig","tsconfigPath","expectedPath","readJson","references","push","fs","writeFileSync","JSON","stringify","prettifySync","getLocalDependencies","pkg","dependencies","devDependencies","peerDependencies","Object","keys","filter","dependency","has","normalizeTsConfigPath","filePath","isDirectory","join","endsWith","getTsConfigReferencedPackages","config","readJsonSafe","tsconfigDir","dirname","referencedPackages","reference","resolvedRefPath","refDir","packageName","get","add","getExpectedReferencePath","fromLocation","toLocation","relativePath","relative","tsconfigFile","getTsConfig","tsconfigName","basename","referencePath","isDefaultTsConfig","replaceAll","collectTsConfigFiles","tsconfigFiles","globSync","absolute","cwd","findMissingDependencyReferences","localDependencies","dependencyLocation","message","fixable","FixCategory","normal","missingReference","file","statSync","flatMap"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@servicetitan/startup",
3
- "version": "34.0.0",
3
+ "version": "34.0.1",
4
4
  "description": "CLI to create multi-package Lerna projects with TypeScript and React",
5
5
  "homepage": "https://docs.st.dev/docs/frontend/uikit/startup",
6
6
  "repository": {
@@ -54,10 +54,10 @@
54
54
  "@jest/core": "~30.2.0",
55
55
  "@jest/types": "~30.2.0",
56
56
  "@jsdevtools/coverage-istanbul-loader": "^3.0.5",
57
- "@servicetitan/eslint-config": "34.0.0",
58
- "@servicetitan/install": "34.0.0",
59
- "@servicetitan/startup-utils": "34.0.0",
60
- "@servicetitan/stylelint-config": "34.0.0",
57
+ "@servicetitan/eslint-config": "34.0.1",
58
+ "@servicetitan/install": "34.0.1",
59
+ "@servicetitan/startup-utils": "34.0.1",
60
+ "@servicetitan/stylelint-config": "34.0.1",
61
61
  "@svgr/webpack": "^8.1.0",
62
62
  "@swc/cli": "^0.5.0",
63
63
  "@swc/core": "1.15.10",
@@ -142,5 +142,5 @@
142
142
  "cli": {
143
143
  "webpack": false
144
144
  },
145
- "gitHead": "e193dc22703963f67099874a24de535d0696b6e2"
145
+ "gitHead": "e42375d199bbc11b2f0b8881c26a8f0229446256"
146
146
  }
@@ -1,9 +1,9 @@
1
1
  import { fs, vol } from 'memfs';
2
2
  import path from 'node:path';
3
- import { Package, ReviewConfiguration } from '../../types';
4
- import { mockProject } from '../__mocks__';
5
-
3
+ import { createPackage } from '../../../../../__mocks__';
6
4
  import { prettifySync } from '../../../../../utils';
5
+ import { Package } from '../../types';
6
+ import { mockProject } from '../__mocks__';
7
7
  import { RequireTsconfigReferences } from '../require-tsconfig-references';
8
8
 
9
9
  jest.mock('node:fs', () => fs);
@@ -17,299 +17,177 @@ jest.mock('../../../../../utils', () => ({
17
17
 
18
18
  describe(`[startup] Review ${RequireTsconfigReferences.name}`, () => {
19
19
  let rule: RequireTsconfigReferences;
20
- let config: ReviewConfiguration;
21
20
  let packages: Package[];
22
21
 
23
22
  beforeEach(() => {
24
23
  rule = new RequireTsconfigReferences();
25
- config = {};
26
- packages = [];
24
+ packages = [
25
+ // Note, tests assume the "app" that depends on local package(s) is first
26
+ createPackage({ name: 'app', dependencies: { utils: '1.0.0' } }),
27
+ createPackage({ name: 'utils' }),
28
+ ];
27
29
  });
28
30
 
29
31
  afterEach(() => vol.reset());
30
32
 
31
- const subject = () => rule.run(mockProject({ config, packages }));
32
- const fixSubject = () => {
33
- const ruleErrors = subject();
33
+ const subject = () => rule.run(mockProject({ packages }));
34
34
 
35
- ruleErrors.forEach(rule.fix);
36
- };
35
+ function appTsConfig() {
36
+ return path.join(packages[0].location, 'tsconfig.json');
37
+ }
37
38
 
38
- function setupPackages(pkgs: Package[], tsconfigFiles: Record<string, object>) {
39
- packages = pkgs;
39
+ function volFromJSON(json: Record<string, any>) {
40
40
  vol.fromJSON(
41
41
  Object.fromEntries(
42
- Object.entries(tsconfigFiles).map(([filePath, content]) => [
42
+ Object.entries(json).map(([filePath, content]) => [
43
43
  filePath,
44
- JSON.stringify(content, null, 4),
44
+ JSON.stringify(content),
45
45
  ])
46
46
  )
47
47
  );
48
48
  }
49
49
 
50
- describe('when package has local dependency with correct tsconfig reference', () => {
51
- beforeEach(() => {
52
- setupPackages(
53
- [
54
- {
55
- name: '@servicetitan/runtime',
56
- location: path.normalize('packages/runtime'),
57
- dependencies: {
58
- '@servicetitan/log-service': '1.0.0',
59
- },
60
- },
61
- {
62
- name: '@servicetitan/log-service',
63
- location: path.normalize('packages/log-service'),
64
- },
65
- ],
66
- {
67
- [path.normalize('packages/runtime/tsconfig.json')]: {
68
- references: [{ path: '../log-service/tsconfig.json' }],
69
- },
70
- [path.normalize('packages/log-service/tsconfig.json')]: {},
71
- }
72
- );
73
- });
74
-
50
+ function itReportsNoErrors() {
75
51
  test('reports no errors', () => {
76
52
  expect(subject()).toEqual([]);
77
53
  });
78
- });
54
+ }
79
55
 
80
- describe('when tsconfig files are missing references', () => {
56
+ describe('when package has correct tsconfig reference', () => {
81
57
  beforeEach(() => {
82
- setupPackages(
83
- [
84
- {
85
- name: '@servicetitan/runtime',
86
- location: path.normalize('packages/runtime'),
87
- dependencies: {
88
- '@servicetitan/log-service': '1.0.0',
89
- },
90
- },
91
- {
92
- name: '@servicetitan/log-service',
93
- location: path.normalize('packages/log-service'),
94
- },
95
- ],
96
- {
97
- [path.normalize('packages/runtime/tsconfig.json')]: {},
98
- [path.normalize('packages/runtime/tsconfig.build.json')]: {},
99
- [path.normalize('packages/log-service/tsconfig.json')]: {},
100
- }
101
- );
58
+ volFromJSON({
59
+ [appTsConfig()]: { references: [{ path: '../utils/tsconfig.json' }] },
60
+ });
102
61
  });
103
62
 
104
- test('reports errors for tsconfig files', () => {
105
- expect(subject()).toEqual(
106
- expect.arrayContaining([
107
- {
108
- id: 'require-tsconfig-references',
109
- message: 'missing reference for dependency: @servicetitan/log-service',
110
- location: path.normalize('packages/runtime/tsconfig.json'),
111
- fixable: 'normal',
112
- data: {
113
- tsconfigPath: path.normalize('packages/runtime/tsconfig.json'),
114
- missingReference: '@servicetitan/log-service',
115
- expectedPath: '../log-service/tsconfig.json',
116
- },
117
- },
118
- {
119
- id: 'require-tsconfig-references',
120
- message: 'missing reference for dependency: @servicetitan/log-service',
121
- location: path.normalize('packages/runtime/tsconfig.build.json'),
122
- fixable: 'normal',
123
- data: {
124
- tsconfigPath: path.normalize('packages/runtime/tsconfig.build.json'),
125
- missingReference: '@servicetitan/log-service',
126
- expectedPath: '../log-service/tsconfig.json',
127
- },
128
- },
129
- ])
130
- );
131
- });
63
+ itReportsNoErrors();
132
64
  });
133
65
 
134
- describe('when package dependencies are in devDependencies and peerDependencies', () => {
66
+ describe('when reference is build config', () => {
135
67
  beforeEach(() => {
136
- setupPackages(
137
- [
138
- {
139
- name: '@servicetitan/runtime',
140
- location: path.normalize('packages/runtime'),
141
- devDependencies: { '@servicetitan/log-service': '1.0.0' },
142
- },
143
- {
144
- name: '@servicetitan/examples',
145
- location: path.normalize('packages/examples'),
146
- peerDependencies: { '@servicetitan/log-service': '1.0.0' },
147
- },
148
- {
149
- name: '@servicetitan/log-service',
150
- location: path.normalize('packages/log-service'),
151
- },
152
- ],
153
- {
154
- [path.normalize('packages/runtime/tsconfig.json')]: {},
155
- [path.normalize('packages/examples/tsconfig.json')]: {},
156
- [path.normalize('packages/log-service/tsconfig.json')]: {},
157
- }
158
- );
68
+ volFromJSON({
69
+ [appTsConfig()]: { references: [{ path: '../utils/tsconfig.build.json ' }] },
70
+ });
159
71
  });
160
72
 
161
- test('reports missing reference errors', () => {
162
- expect(subject()).toEqual([
163
- {
164
- id: 'require-tsconfig-references',
165
- message: 'missing reference for dependency: @servicetitan/log-service',
166
- location: path.normalize('packages/runtime/tsconfig.json'),
167
- fixable: 'normal',
168
- data: {
169
- tsconfigPath: path.normalize('packages/runtime/tsconfig.json'),
170
- missingReference: '@servicetitan/log-service',
171
- expectedPath: '../log-service/tsconfig.json',
172
- },
173
- },
174
- {
175
- id: 'require-tsconfig-references',
176
- message: 'missing reference for dependency: @servicetitan/log-service',
177
- location: path.normalize('packages/examples/tsconfig.json'),
178
- fixable: 'normal',
179
- data: {
180
- tsconfigPath: path.normalize('packages/examples/tsconfig.json'),
181
- missingReference: '@servicetitan/log-service',
182
- expectedPath: '../log-service/tsconfig.json',
183
- },
184
- },
185
- ]);
186
- });
73
+ itReportsNoErrors();
187
74
  });
188
75
 
189
- describe('when fix is called with non-existent tsconfig file', () => {
190
- const tsconfigPath = path.normalize('packages/nonexistent/tsconfig.json');
191
-
76
+ describe('when reference omits .json extension', () => {
192
77
  beforeEach(() => {
193
- setupPackages(
194
- [
195
- {
196
- name: '@servicetitan/runtime',
197
- location: path.normalize('packages/runtime'),
198
- devDependencies: { '@servicetitan/log-service': '1.0.0' },
199
- },
200
- {
201
- name: '@servicetitan/log-service',
202
- location: path.normalize('packages/log-service'),
203
- },
204
- ],
205
- {}
206
- );
78
+ volFromJSON({
79
+ [appTsConfig()]: { references: [{ path: '../utils/tsconfig' }] },
80
+ });
207
81
  });
208
82
 
209
- test('file remains non-existent', () => {
210
- fixSubject();
83
+ itReportsNoErrors();
84
+ });
211
85
 
212
- expect(fs.existsSync(tsconfigPath)).toBe(false);
86
+ describe('when reference is directory', () => {
87
+ beforeEach(() => {
88
+ volFromJSON({
89
+ [appTsConfig()]: { references: [{ path: '../utils' }] },
90
+ 'packages/utils/tsconfig.json': {}, // ensures directory exists
91
+ });
213
92
  });
214
- });
215
93
 
216
- describe('when fix is called on tsconfig that already has references', () => {
217
- const tsconfigFilePath = path.normalize('packages/runtime/tsconfig.json');
94
+ itReportsNoErrors();
95
+ });
218
96
 
97
+ describe('when package is missing reference', () => {
219
98
  beforeEach(() => {
220
- setupPackages(
221
- [
222
- {
223
- name: '@servicetitan/runtime',
224
- location: path.normalize('packages/runtime'),
225
- dependencies: {
226
- '@servicetitan/log-service': '1.0.0',
227
- },
228
- },
229
- {
230
- name: '@servicetitan/log-service',
231
- location: path.normalize('packages/log-service'),
232
- },
233
- ],
234
- {
235
- [tsconfigFilePath]: {
236
- references: [{ path: '../existing/tsconfig.json' }],
237
- },
238
- }
239
- );
99
+ volFromJSON({ [appTsConfig()]: {} });
240
100
  });
241
101
 
242
- test('appends to existing references', () => {
243
- fixSubject();
102
+ function itReportsError() {
103
+ test('reports error', () => {
104
+ expect(subject()).toEqual([
105
+ expect.objectContaining({
106
+ id: 'require-tsconfig-references',
107
+ message: 'missing reference for dependency: utils',
108
+ location: appTsConfig(),
109
+ fixable: 'normal',
110
+ }),
111
+ ]);
112
+ });
113
+ }
114
+
115
+ itReportsError();
116
+
117
+ describe.each(['devDependencies', 'peerDependencies'])(
118
+ 'when dependency is in %s',
119
+ (key: keyof Package) => {
120
+ beforeEach(() => {
121
+ const appPackage = packages[0];
122
+ appPackage[key] = appPackage.dependencies;
123
+ delete appPackage.dependencies;
124
+ });
125
+
126
+ itReportsError();
127
+ }
128
+ );
129
+
130
+ describe('when package is workspace root', () => {
131
+ beforeEach(() => (packages[0].location = '.'));
244
132
 
245
- const content = JSON.parse(fs.readFileSync(tsconfigFilePath, 'utf8') as string);
246
- expect(content.references).toContainEqual({ path: '../existing/tsconfig.json' });
247
- expect(content.references).toContainEqual({ path: '../log-service/tsconfig.json' });
133
+ itReportsNoErrors();
248
134
  });
249
135
 
250
- test('runs prettier on the modified file', () => {
251
- fixSubject();
136
+ describe('fix', () => {
137
+ const fixSubject = () => {
138
+ const ruleErrors = subject();
139
+ ruleErrors.forEach(rule.fix);
140
+ };
252
141
 
253
- expect(prettifySync).toHaveBeenCalled();
254
- });
255
- });
142
+ function expectReferences(references: Record<string, string>[]) {
143
+ const json = fs.readFileSync(appTsConfig(), { encoding: 'utf-8' }).toString();
144
+ expect(JSON.parse(json)).toEqual({ references });
145
+ }
256
146
 
257
- describe('when tsconfig reference omits .json extension', () => {
258
- beforeEach(() => {
259
- setupPackages(
260
- [
261
- {
262
- name: '@servicetitan/runtime',
263
- location: path.normalize('packages/runtime'),
264
- dependencies: {
265
- '@servicetitan/log-service': '1.0.0',
266
- },
267
- },
268
- {
269
- name: '@servicetitan/log-service',
270
- location: path.normalize('packages/log-service'),
271
- },
272
- ],
273
- {
274
- [path.normalize('packages/runtime/tsconfig.json')]: {
275
- references: [{ path: '../log-service/tsconfig' }],
276
- },
277
- [path.normalize('packages/log-service/tsconfig.json')]: {},
278
- }
279
- );
280
- });
147
+ test('fixes error', () => {
148
+ fixSubject();
281
149
 
282
- test('reports no errors', () => {
283
- expect(subject()).toEqual([]);
284
- });
285
- });
150
+ expectReferences([{ path: '../utils' }]);
151
+ });
286
152
 
287
- describe('when package is a workspace root', () => {
288
- beforeEach(() => {
289
- setupPackages(
290
- [
291
- {
292
- name: 'my-monorepo',
293
- location: '.',
294
- workspaces: ['packages/*'],
295
- dependencies: {
296
- '@servicetitan/log-service': '1.0.0',
297
- },
298
- },
299
- {
300
- name: '@servicetitan/log-service',
301
- location: path.normalize('packages/log-service'),
302
- },
303
- ],
304
- {
305
- 'tsconfig.json': {},
306
- [path.normalize('packages/log-service/tsconfig.json')]: {},
307
- }
308
- );
309
- });
153
+ test('prettifies output', () => {
154
+ fixSubject();
310
155
 
311
- test('skips the workspace root package', () => {
312
- expect(subject()).toEqual([]);
156
+ expect(prettifySync).toHaveBeenCalledWith(appTsConfig());
157
+ });
158
+
159
+ describe('when reference is build config', () => {
160
+ beforeEach(() => {
161
+ volFromJSON({
162
+ [appTsConfig()]: {},
163
+ 'packages/utils/tsconfig.build.json': {},
164
+ });
165
+ });
166
+
167
+ test('references build config', () => {
168
+ fixSubject();
169
+
170
+ expectReferences([{ path: '../utils/tsconfig.build.json' }]);
171
+ });
172
+ });
173
+
174
+ describe('when package has other references', () => {
175
+ const references = [{ path: '../foo' }];
176
+
177
+ beforeEach(() => {
178
+ volFromJSON({ [appTsConfig()]: { references } });
179
+ });
180
+
181
+ test('preserves other references', () => {
182
+ fixSubject();
183
+
184
+ expectReferences([...references, { path: '../utils' }]);
185
+ });
186
+ });
187
+
188
+ test('ignores invalid data', () => {
189
+ expect(() => rule.fix({} as any)).not.toThrow();
190
+ });
313
191
  });
314
192
  });
315
193
  });
@@ -1,7 +1,7 @@
1
1
  import { globSync } from 'glob';
2
2
  import fs from 'node:fs';
3
3
  import path from 'node:path';
4
- import { getTsConfig, prettifySync, readJsonSafe } from '../../../../utils';
4
+ import { getTsConfig, prettifySync, readJson, readJsonSafe } from '../../../../utils';
5
5
  import { FixCategory, Package, PackageError, PackageRule, Project } from '../types';
6
6
  import { checkPackages } from '../utils';
7
7
 
@@ -44,10 +44,7 @@ export class RequireTsconfigReferences implements PackageRule {
44
44
  }
45
45
 
46
46
  const { tsconfigPath, expectedPath } = data;
47
- const tsconfig = readJsonSafe<TsConfig>(tsconfigPath);
48
- if (!tsconfig) {
49
- return;
50
- }
47
+ const tsconfig = readJson<TsConfig>(tsconfigPath);
51
48
 
52
49
  const references = tsconfig.references ?? [];
53
50
  references.push({ path: expectedPath });
@@ -70,6 +67,9 @@ export class RequireTsconfigReferences implements PackageRule {
70
67
  }
71
68
 
72
69
  private normalizeTsConfigPath(filePath: string): string {
70
+ if (this.isDirectory(filePath)) {
71
+ return path.join(filePath, 'tsconfig.json');
72
+ }
73
73
  return filePath.endsWith('.json') ? filePath : `${filePath}.json`;
74
74
  }
75
75
 
@@ -83,8 +83,9 @@ export class RequireTsconfigReferences implements PackageRule {
83
83
  const referencedPackages = new Set<string>();
84
84
 
85
85
  for (const reference of config.references) {
86
- const normalizedPath = this.normalizeTsConfigPath(reference.path);
87
- const resolvedRefPath = path.resolve(tsconfigDir, normalizedPath);
86
+ const resolvedRefPath = this.normalizeTsConfigPath(
87
+ path.resolve(tsconfigDir, reference.path)
88
+ );
88
89
  const refDir = path.dirname(resolvedRefPath);
89
90
  const packageName = this.locationToPackageName.get(refDir);
90
91
 
@@ -100,8 +101,11 @@ export class RequireTsconfigReferences implements PackageRule {
100
101
  const relativePath = path.relative(fromLocation, toLocation);
101
102
  const tsconfigFile = getTsConfig(toLocation);
102
103
  const tsconfigName = path.basename(tsconfigFile);
104
+ const referencePath = this.isDefaultTsConfig(tsconfigName)
105
+ ? relativePath
106
+ : path.join(relativePath, tsconfigName);
103
107
 
104
- return path.join(relativePath, tsconfigName).replaceAll('\\', '/');
108
+ return referencePath.replaceAll('\\', '/');
105
109
  }
106
110
 
107
111
  private collectTsConfigFiles(location: string): string[] {
@@ -154,4 +158,16 @@ export class RequireTsconfigReferences implements PackageRule {
154
158
  this.findMissingDependencyReferences(pkg, tsconfigPath, localDependencies)
155
159
  );
156
160
  };
161
+
162
+ private isDefaultTsConfig(name: string) {
163
+ return name === 'tsconfig.json';
164
+ }
165
+
166
+ private isDirectory(file: string) {
167
+ try {
168
+ return fs.statSync(file).isDirectory();
169
+ } catch {
170
+ return false;
171
+ }
172
+ }
157
173
  }