@knapsack/spec-utils 4.78.13--canary.5646.9581069.0 → 4.78.13

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 (57) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/.turbo/turbo-lint.log +4 -0
  3. package/.turbo/turbo-test.log +50 -0
  4. package/CHANGELOG.md +12 -0
  5. package/dist/align/align.vtest.d.ts +2 -0
  6. package/dist/align/align.vtest.d.ts.map +1 -0
  7. package/dist/align/align.vtest.js +46 -0
  8. package/dist/align/align.vtest.js.map +1 -0
  9. package/dist/analyze-exports.sandbox-components.vtest.d.ts +2 -0
  10. package/dist/analyze-exports.sandbox-components.vtest.d.ts.map +1 -0
  11. package/dist/analyze-exports.sandbox-components.vtest.js +51 -0
  12. package/dist/analyze-exports.sandbox-components.vtest.js.map +1 -0
  13. package/dist/analyze-exports.vtest.d.ts +2 -0
  14. package/dist/analyze-exports.vtest.d.ts.map +1 -0
  15. package/dist/analyze-exports.vtest.js +160 -0
  16. package/dist/analyze-exports.vtest.js.map +1 -0
  17. package/dist/convert-to-spec.vtest.d.ts +2 -0
  18. package/dist/convert-to-spec.vtest.d.ts.map +1 -0
  19. package/dist/convert-to-spec.vtest.js +131 -0
  20. package/dist/convert-to-spec.vtest.js.map +1 -0
  21. package/dist/get-ts-config.vtest.d.ts +2 -0
  22. package/dist/get-ts-config.vtest.d.ts.map +1 -0
  23. package/dist/get-ts-config.vtest.js +9 -0
  24. package/dist/get-ts-config.vtest.js.map +1 -0
  25. package/dist/resolve.vtest.d.ts +2 -0
  26. package/dist/resolve.vtest.d.ts.map +1 -0
  27. package/dist/resolve.vtest.js +57 -0
  28. package/dist/resolve.vtest.js.map +1 -0
  29. package/dist/utils.vtest.d.ts +2 -0
  30. package/dist/utils.vtest.d.ts.map +1 -0
  31. package/dist/utils.vtest.js +37 -0
  32. package/dist/utils.vtest.js.map +1 -0
  33. package/package.json +10 -10
  34. package/src/align/align.vtest.ts +56 -0
  35. package/src/align/get-exports.bench.ts +28 -0
  36. package/src/align/resolve.bench.ts +20 -0
  37. package/src/align/utils.ts +14 -0
  38. package/src/analyze-exports.sandbox-components.vtest.ts +53 -0
  39. package/src/analyze-exports.ts +54 -0
  40. package/src/analyze-exports.vtest.ts +178 -0
  41. package/src/analyze-symbol.ts +213 -0
  42. package/src/analyze-type.ts +316 -0
  43. package/src/boot.ts +31 -0
  44. package/src/convert-to-spec.ts +196 -0
  45. package/src/convert-to-spec.vtest.ts +136 -0
  46. package/src/get-exports.ts +70 -0
  47. package/src/get-ts-config.ts +96 -0
  48. package/src/get-ts-config.vtest.ts +9 -0
  49. package/src/index.ts +5 -0
  50. package/src/resolve.ts +54 -0
  51. package/src/resolve.vtest.ts +69 -0
  52. package/src/test-fixtures/basics.ts +17 -0
  53. package/src/test-fixtures/functions.ts +50 -0
  54. package/src/test-fixtures/index.ts +2 -0
  55. package/src/types.ts +66 -0
  56. package/src/utils.ts +61 -0
  57. package/src/utils.vtest.ts +39 -0
@@ -0,0 +1,196 @@
1
+ import type {
2
+ PropertyTypes,
3
+ StringProp,
4
+ BooleanProp,
5
+ NumberProp,
6
+ ObjectProp,
7
+ FunctionProp,
8
+ } from '@knapsack/types';
9
+ import { TypeInfo } from './types.js';
10
+
11
+ export function convertToSpec({
12
+ typeInfo,
13
+ trustRequiredProps,
14
+ }: {
15
+ typeInfo: TypeInfo;
16
+ trustRequiredProps: boolean;
17
+ }): {
18
+ prop: PropertyTypes | null;
19
+ isOptional: boolean;
20
+ } {
21
+ const { isOptional = false } = typeInfo;
22
+ switch (typeInfo.type) {
23
+ case 'object': {
24
+ const { properties } = typeInfo;
25
+ const required: string[] = [];
26
+ return {
27
+ isOptional,
28
+ prop: {
29
+ type: 'object',
30
+ required,
31
+ properties: Object.entries(properties).reduce(
32
+ (acc, [propName, { typeInfo: propTypeInfo, jsDoc }]) => {
33
+ const details = convertToSpec({
34
+ typeInfo: propTypeInfo,
35
+ trustRequiredProps,
36
+ });
37
+ if (!details.prop) return acc;
38
+
39
+ acc[propName] = details.prop;
40
+ if (jsDoc?.description) {
41
+ acc[propName].description = jsDoc.description;
42
+ }
43
+ if (!details.isOptional && trustRequiredProps) {
44
+ required.push(propName);
45
+ }
46
+ return acc;
47
+ },
48
+ {} as ObjectProp['properties'],
49
+ ),
50
+ } satisfies ObjectProp,
51
+ };
52
+ }
53
+ case 'array': {
54
+ const { items } = typeInfo;
55
+ const { prop } = convertToSpec({
56
+ typeInfo: items,
57
+ trustRequiredProps,
58
+ });
59
+ return {
60
+ isOptional,
61
+ prop: {
62
+ type: 'array',
63
+ // Use the converted items type if available, fallback to object type for complex types
64
+ items:
65
+ prop || ({ type: 'object', properties: {} } satisfies ObjectProp),
66
+ ...(typeInfo.tsRawType && { tsType: typeInfo.tsRawType }),
67
+ },
68
+ };
69
+ }
70
+ case 'string': {
71
+ return {
72
+ isOptional,
73
+ prop: {
74
+ type: 'string',
75
+ } satisfies StringProp,
76
+ };
77
+ }
78
+ case 'number': {
79
+ return {
80
+ isOptional,
81
+ prop: {
82
+ type: 'number',
83
+ } satisfies NumberProp,
84
+ };
85
+ }
86
+ case 'boolean': {
87
+ return {
88
+ isOptional,
89
+ prop: {
90
+ type: 'boolean',
91
+ } satisfies BooleanProp,
92
+ };
93
+ }
94
+ case 'union': {
95
+ const { items } = typeInfo;
96
+
97
+ // Handle string literal unions
98
+ const isUnionOfStrings = items.every(
99
+ (item): item is Extract<TypeInfo, { type: 'stringLiteral' }> =>
100
+ item.type === 'stringLiteral' || item.type === 'string',
101
+ );
102
+
103
+ // Handle number literal unions
104
+ const isUnionOfNumbers = items.every(
105
+ (item): item is Extract<TypeInfo, { type: 'numberLiteral' }> =>
106
+ item.type === 'numberLiteral' || item.type === 'number',
107
+ );
108
+
109
+ if (isUnionOfStrings) {
110
+ return {
111
+ isOptional,
112
+ prop: {
113
+ type: 'string',
114
+ enum: items
115
+ .filter(
116
+ (item): item is Extract<TypeInfo, { type: 'stringLiteral' }> =>
117
+ item.type === 'stringLiteral',
118
+ )
119
+ .map((item) => item.value),
120
+ },
121
+ };
122
+ }
123
+
124
+ if (isUnionOfNumbers) {
125
+ return {
126
+ isOptional,
127
+ prop: {
128
+ type: 'number',
129
+ enum: items
130
+ .filter(
131
+ (item): item is Extract<TypeInfo, { type: 'numberLiteral' }> =>
132
+ item.type === 'numberLiteral',
133
+ )
134
+ .map((item) => item.value),
135
+ },
136
+ };
137
+ }
138
+
139
+ return {
140
+ isOptional,
141
+ prop: null,
142
+ };
143
+ }
144
+ case 'function': {
145
+ return {
146
+ isOptional,
147
+ prop: {
148
+ typeof: 'function',
149
+ // ...(typeInfo.tsRawType && { tsType: typeInfo.tsRawType }),
150
+ tsType: typeInfo.tsRawType,
151
+ } satisfies FunctionProp,
152
+ };
153
+ }
154
+ case 'misc': {
155
+ // if there is type info in the tsRawType we try to convert it
156
+ if (typeInfo.tsRawType) {
157
+ // Create a new TypeInfo based on the tsRawType
158
+ const derivedTypeInfo = {
159
+ type: typeInfo.tsRawType,
160
+ isOptional,
161
+ tsRawType: typeInfo.tsRawType,
162
+ tsMetadata: typeInfo.tsMetadata,
163
+ } as TypeInfo;
164
+
165
+ return convertToSpec({
166
+ typeInfo: derivedTypeInfo,
167
+ trustRequiredProps,
168
+ });
169
+ }
170
+
171
+ return {
172
+ isOptional,
173
+ prop: null,
174
+ };
175
+ }
176
+ case 'numberLiteral':
177
+ case 'stringLiteral':
178
+ case 'class':
179
+ case 'unknown':
180
+ case 'any': {
181
+ return {
182
+ isOptional,
183
+ prop: null,
184
+ };
185
+ }
186
+
187
+ default: {
188
+ const _exhaustiveCheck: never = typeInfo;
189
+
190
+ return {
191
+ isOptional,
192
+ prop: null,
193
+ };
194
+ }
195
+ }
196
+ }
@@ -0,0 +1,136 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { convertToSpec } from './convert-to-spec.js';
3
+ import { TypeInfo, SymbolInfo } from './types.js';
4
+
5
+ // these two are up here to make TS happy
6
+ const typeInfoStubBase = {
7
+ tsRawType: '',
8
+ tsMetadata: null as unknown as TypeInfo['tsMetadata'],
9
+ };
10
+ const tsMetadata = null as unknown as SymbolInfo['tsMetadata'];
11
+
12
+ describe('convert-to-spec', () => {
13
+ it('handles string', () => {
14
+ const { prop } = convertToSpec({
15
+ typeInfo: {
16
+ type: 'string',
17
+ ...typeInfoStubBase,
18
+ },
19
+ trustRequiredProps: false,
20
+ });
21
+ expect(prop).toEqual({
22
+ type: 'string',
23
+ } satisfies typeof prop);
24
+ });
25
+
26
+ it('handles boolean', () => {
27
+ const { prop } = convertToSpec({
28
+ typeInfo: {
29
+ type: 'boolean',
30
+ ...typeInfoStubBase,
31
+ },
32
+ trustRequiredProps: false,
33
+ });
34
+ expect(prop).toEqual({
35
+ type: 'boolean',
36
+ } satisfies typeof prop);
37
+ });
38
+
39
+ it('handles object', () => {
40
+ const { prop } = convertToSpec({
41
+ typeInfo: {
42
+ type: 'object',
43
+ ...typeInfoStubBase,
44
+ properties: {
45
+ name: {
46
+ name: 'name',
47
+ typeInfo: {
48
+ type: 'string',
49
+ tsRawType: '',
50
+ tsMetadata: null as unknown as TypeInfo['tsMetadata'],
51
+ },
52
+ tsMetadata,
53
+ },
54
+ age: {
55
+ name: 'age',
56
+ typeInfo: {
57
+ isOptional: true,
58
+ type: 'number',
59
+ ...typeInfoStubBase,
60
+ },
61
+ tsMetadata,
62
+ },
63
+ shoePrefs: {
64
+ name: 'shoePrefs',
65
+ typeInfo: {
66
+ type: 'union',
67
+ ...typeInfoStubBase,
68
+ items: [
69
+ {
70
+ type: 'stringLiteral',
71
+ value: 'sandals',
72
+ ...typeInfoStubBase,
73
+ },
74
+ { type: 'stringLiteral', value: 'boots', ...typeInfoStubBase },
75
+ ],
76
+ },
77
+ tsMetadata,
78
+ },
79
+ },
80
+ },
81
+ trustRequiredProps: true,
82
+ });
83
+ expect(prop).toEqual({
84
+ type: 'object',
85
+ required: ['name', 'shoePrefs'],
86
+ properties: {
87
+ name: {
88
+ type: 'string',
89
+ },
90
+ age: {
91
+ type: 'number',
92
+ },
93
+ shoePrefs: {
94
+ type: 'string',
95
+ enum: ['sandals', 'boots'],
96
+ },
97
+ },
98
+ } satisfies typeof prop);
99
+ });
100
+
101
+ it('handles array of objects', () => {
102
+ const { prop } = convertToSpec({
103
+ typeInfo: {
104
+ type: 'array',
105
+ items: {
106
+ type: 'object',
107
+ properties: {
108
+ name: {
109
+ name: 'name',
110
+ typeInfo: {
111
+ type: 'string',
112
+ ...typeInfoStubBase,
113
+ },
114
+ tsMetadata,
115
+ },
116
+ },
117
+ ...typeInfoStubBase,
118
+ },
119
+ ...typeInfoStubBase,
120
+ },
121
+ trustRequiredProps: false,
122
+ });
123
+ expect(prop).toEqual({
124
+ type: 'array',
125
+ items: {
126
+ type: 'object',
127
+ required: [],
128
+ properties: {
129
+ name: {
130
+ type: 'string',
131
+ },
132
+ },
133
+ },
134
+ } satisfies typeof prop);
135
+ });
136
+ });
@@ -0,0 +1,70 @@
1
+ import { join } from 'node:path';
2
+ import { resolveTsModule } from './resolve.js';
3
+ import { bootTypescript } from './boot.js';
4
+
5
+ function getTsExportsUncached({
6
+ fileName,
7
+ pkgPathAliases,
8
+ resolveFromDir = process.cwd(),
9
+ }: {
10
+ fileName: string;
11
+ pkgPathAliases?: Record<string, string>;
12
+ resolveFromDir?: string;
13
+ }) {
14
+ const { resolvedFileName } = resolveTsModule({
15
+ containingFile: join(resolveFromDir, 'containing-file.ts'),
16
+ moduleName: fileName,
17
+ pkgPathAliases,
18
+ });
19
+ const { program, checker } = bootTypescript({
20
+ rootFiles: [resolvedFileName],
21
+ configSrc: {
22
+ type: 'preset',
23
+ preset: 'bundler',
24
+ },
25
+ });
26
+ const files = program.getSourceFiles();
27
+ const file = files.find((f) => f.fileName === resolvedFileName);
28
+ if (!file) {
29
+ throw new Error(`File ${fileName} not found`);
30
+ }
31
+
32
+ const moduleSymbol = checker.getSymbolAtLocation(file);
33
+ if (!moduleSymbol) {
34
+ throw new Error(`Module symbol for ${fileName} not found`);
35
+ }
36
+
37
+ return {
38
+ exports: checker.getExportsOfModule(moduleSymbol),
39
+ checker,
40
+ };
41
+ }
42
+
43
+ const cache = new Map<string, ReturnType<typeof getTsExportsUncached>>();
44
+ const timeouts = new Map<string, NodeJS.Timeout>();
45
+ // clear the timeout when the process is terminated so process.exit() doesn't hang
46
+ process.on('SIGTERM', () => {
47
+ for (const timeout of timeouts.values()) {
48
+ clearTimeout(timeout);
49
+ }
50
+ });
51
+
52
+ export function getTsExports(opt: Parameters<typeof getTsExportsUncached>[0]) {
53
+ if (process.env.NODE_ENV === 'test') {
54
+ return getTsExportsUncached(opt);
55
+ }
56
+ const key = JSON.stringify(opt);
57
+
58
+ const exports = cache.get(key);
59
+ if (exports) {
60
+ return exports;
61
+ }
62
+
63
+ const result = getTsExportsUncached(opt);
64
+ cache.set(key, result);
65
+ timeouts.set(
66
+ key,
67
+ setTimeout(() => cache.delete(key), 5_000),
68
+ );
69
+ return result;
70
+ }
@@ -0,0 +1,96 @@
1
+ import ts, {
2
+ sys as tsSys,
3
+ findConfigFile,
4
+ readConfigFile,
5
+ parseJsonConfigFileContent,
6
+ getDefaultCompilerOptions,
7
+ CompilerOptions,
8
+ } from 'typescript';
9
+ import { dirname } from 'node:path';
10
+
11
+ export function getTsConfigJson({
12
+ basePath = process.cwd(),
13
+ }: {
14
+ basePath?: string;
15
+ } = {}) {
16
+ // Find tsconfig.json file
17
+ const tsConfigPath = findConfigFile(
18
+ basePath,
19
+ tsSys.fileExists,
20
+ 'tsconfig.json',
21
+ );
22
+
23
+ if (!tsConfigPath) {
24
+ throw new Error(
25
+ `No tsconfig.json file found searching up from ${basePath} `,
26
+ );
27
+ }
28
+
29
+ // Read tsconfig.json file
30
+ const tsconfigFile = readConfigFile(tsConfigPath, tsSys.readFile);
31
+ if (tsconfigFile.error) {
32
+ throw new Error(
33
+ `Failed to read tsconfig.json file: ${tsconfigFile.error.messageText}`,
34
+ );
35
+ }
36
+
37
+ // Resolve extends
38
+ const tsConfig = parseJsonConfigFileContent(
39
+ tsconfigFile.config,
40
+ tsSys,
41
+ dirname(tsConfigPath),
42
+ );
43
+
44
+ return { tsConfig, tsConfigPath };
45
+ }
46
+
47
+ export function getTsConfigCompilerOptions(
48
+ configSrc:
49
+ | {
50
+ type: 'resolveTsConfigJson';
51
+ basePath?: string;
52
+ }
53
+ | {
54
+ type: 'inline';
55
+ config: CompilerOptions;
56
+ }
57
+ | {
58
+ type: 'preset';
59
+ preset: 'default' | 'modern' | 'bundler';
60
+ },
61
+ ): CompilerOptions {
62
+ switch (configSrc.type) {
63
+ case 'resolveTsConfigJson':
64
+ return getTsConfigJson({ basePath: configSrc.basePath }).tsConfig.options;
65
+ case 'inline': {
66
+ return configSrc.config;
67
+ }
68
+ case 'preset': {
69
+ switch (configSrc.preset) {
70
+ case 'default': {
71
+ return getDefaultCompilerOptions();
72
+ }
73
+ case 'bundler': {
74
+ return {
75
+ module: ts.ModuleKind.ESNext,
76
+ moduleResolution: ts.ModuleResolutionKind.Bundler,
77
+ };
78
+ }
79
+ case 'modern': {
80
+ return {
81
+ module: ts.ModuleKind.NodeNext,
82
+ moduleResolution: ts.ModuleResolutionKind.NodeNext,
83
+ };
84
+ }
85
+ default: {
86
+ const _exhaustiveCheck: never = configSrc.preset;
87
+ throw new Error(`Unknown preset: ${configSrc.preset}`);
88
+ }
89
+ }
90
+ }
91
+ default: {
92
+ const _exhaustiveCheck: never = configSrc;
93
+ throw new Error(`Unknown config source: ${JSON.stringify(configSrc)}`);
94
+ }
95
+ }
96
+ }
@@ -0,0 +1,9 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { getTsConfigJson } from './get-ts-config.js';
3
+
4
+ describe('get-ts-config', () => {
5
+ it('reads this pkg tsconfig.json', () => {
6
+ const { tsConfig } = getTsConfigJson({ basePath: import.meta.dirname });
7
+ expect(Object.keys(tsConfig.options).length).toBeGreaterThan(0);
8
+ });
9
+ });
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export { getTsConfigCompilerOptions } from './get-ts-config.js';
2
+ export { resolveTsModule } from './resolve.js';
3
+ export { analyzeExport, analyzeExports } from './analyze-exports.js';
4
+ export type { TypeInfo, SymbolInfo } from './types.js';
5
+ export { convertToSpec } from './convert-to-spec.js';
package/src/resolve.ts ADDED
@@ -0,0 +1,54 @@
1
+ import ts, { resolveModuleName } from 'typescript';
2
+ import { prepTypeScriptBoot } from './boot.js';
3
+
4
+ function pkgPathAliasesToPaths(pkgPathAliases: Record<string, string>) {
5
+ if (!pkgPathAliases) return undefined;
6
+ return Object.entries(pkgPathAliases).reduce((acc, [alias, path]) => {
7
+ acc[alias] = [path];
8
+ acc[`${alias}/*`] = [`${path}/*`];
9
+ return acc;
10
+ }, {} as Record<string, string[]>);
11
+ }
12
+
13
+ export function resolveTsModule({
14
+ containingFile,
15
+ moduleName,
16
+ pkgPathAliases = {},
17
+ }: {
18
+ moduleName: string;
19
+ containingFile: string;
20
+ pkgPathAliases?: Record<string, string>;
21
+ }) {
22
+ const paths = pkgPathAliasesToPaths(
23
+ Object.fromEntries(
24
+ Object.entries(pkgPathAliases).map(([alias, pkgPath]) => {
25
+ const { resolvedFileName: pkgPathResolved } = resolveTsModule({
26
+ moduleName: pkgPath,
27
+ containingFile,
28
+ });
29
+ return [alias, pkgPathResolved];
30
+ }),
31
+ ),
32
+ );
33
+
34
+ const { compilerOptions, compilerHost } = prepTypeScriptBoot({
35
+ configSrc: {
36
+ type: 'inline',
37
+ config: {
38
+ moduleResolution: ts.ModuleResolutionKind.Bundler,
39
+ module: ts.ModuleKind.NodeNext,
40
+ paths,
41
+ },
42
+ },
43
+ });
44
+ const { resolvedModule } = resolveModuleName(
45
+ moduleName,
46
+ containingFile,
47
+ compilerOptions,
48
+ compilerHost,
49
+ );
50
+ if (!resolvedModule) {
51
+ throw new Error(`Failed to resolve module: ${moduleName}`);
52
+ }
53
+ return resolvedModule;
54
+ }
@@ -0,0 +1,69 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { join } from 'node:path';
3
+ import { resolveTsModule } from './resolve.js';
4
+
5
+ describe('resolve module tests', () => {
6
+ it('resolves @knapsack/utils', () => {
7
+ const { resolvedFileName, isExternalLibraryImport } = resolveTsModule({
8
+ containingFile: import.meta.filename,
9
+ moduleName: '@knapsack/utils',
10
+ });
11
+
12
+ expect(resolvedFileName).toBeTruthy();
13
+ expect(resolvedFileName).toMatch(/\.d\.ts$/);
14
+ expect(resolvedFileName).toContain('utils/dist');
15
+ expect(isExternalLibraryImport).toBe(true);
16
+ });
17
+
18
+ it('resolves local ts file with .js extension', () => {
19
+ const { resolvedFileName } = resolveTsModule({
20
+ containingFile: import.meta.filename,
21
+ moduleName: './boot.js',
22
+ });
23
+
24
+ expect(resolvedFileName).toBe(join(import.meta.dirname, './boot.ts'));
25
+ });
26
+
27
+ it('resolves local ts file with .ts extension', () => {
28
+ const { resolvedFileName } = resolveTsModule({
29
+ containingFile: import.meta.filename,
30
+ moduleName: './boot.ts',
31
+ });
32
+
33
+ expect(resolvedFileName).toBe(join(import.meta.dirname, './boot.ts'));
34
+ });
35
+
36
+ it('resolves a local package.json', () => {
37
+ const { resolvedFileName } = resolveTsModule({
38
+ containingFile: import.meta.filename,
39
+ moduleName: '../package.json',
40
+ });
41
+
42
+ expect(resolvedFileName).toMatch(/package\.json$/);
43
+ expect(resolvedFileName).toBe(join(import.meta.dirname, '../package.json'));
44
+ });
45
+
46
+ it('resolves a local file', () => {
47
+ const { resolvedFileName } = resolveTsModule({
48
+ containingFile: import.meta.filename,
49
+ moduleName: '../.eslintrc.cjs',
50
+ });
51
+ expect(resolvedFileName).toBe(
52
+ join(import.meta.dirname, '../.eslintrc.cjs'),
53
+ );
54
+ });
55
+
56
+ it('resolves alias of @knapsack/utils', () => {
57
+ const { resolvedFileName } = resolveTsModule({
58
+ containingFile: import.meta.filename,
59
+ moduleName: 'foo',
60
+ pkgPathAliases: {
61
+ foo: '@knapsack/utils',
62
+ },
63
+ });
64
+
65
+ expect(resolvedFileName).toBeTruthy();
66
+ expect(resolvedFileName).toMatch(/\.d\.ts$/);
67
+ expect(resolvedFileName).toContain('utils/dist');
68
+ });
69
+ });
@@ -0,0 +1,17 @@
1
+ /* eslint-disable @typescript-eslint/no-inferrable-types */
2
+
3
+ export const foo = 'bar';
4
+ export type AString = string;
5
+ export const stringViaTypeAlias: AString = 'foo';
6
+ export const aNumber: number = 1;
7
+ export const aString: string = 'foo';
8
+ export const aBoolean: boolean = true;
9
+ export const anArrayOfNumbers: number[] = [1, 2, 3];
10
+ export const anArrayOfStrings: string[] = ['foo', 'bar', 'baz'];
11
+ export const anArrayOfBooleans: boolean[] = [true, false, true];
12
+ export const stringUnion: 'small' | 'medium' | 'large' = 'small';
13
+ export const anObject = {
14
+ a: 1,
15
+ b: 'Beep',
16
+ c: ['foo', 'bar', 'baz'],
17
+ };
@@ -0,0 +1,50 @@
1
+ export const aFunction = (a: number) => a;
2
+ export const asyncFunction = async (a: number) => a;
3
+
4
+ /**
5
+ * The thing to do
6
+ * @param item - The item to do
7
+ * @link https://www.example.com
8
+ * @deprecated
9
+ */
10
+ export function doIt({ item, isFast }: { isFast?: boolean; item: string }) {
11
+ return `${item} ${isFast ? 'fast' : 'slow'}`;
12
+ }
13
+
14
+ type AString = string;
15
+
16
+ /**
17
+ * Some basic types
18
+ * @link https://www.example.com
19
+ */
20
+ export function complexFuncTypes(obj: {
21
+ /** ima string */
22
+ aString: string;
23
+ aStringViaType: AString;
24
+ aNumber: number;
25
+ /** an optional string */
26
+ anOptionalString?: string;
27
+ /** a boolean */
28
+ aBoolean: boolean;
29
+ /** some sizes */
30
+ someSizes: 'small' | 'medium' | 'large';
31
+ /** an array of strings */
32
+ anArray: string[];
33
+ anObject: { aString: string };
34
+ aFunc: (a: string) => string;
35
+ anotherFunc: (opt: { foo: string; onFoo: (a: string) => string }) => {
36
+ b: string;
37
+ };
38
+ }) {
39
+ return obj;
40
+ }
41
+
42
+ export function sayHello(msg: string[]): string;
43
+ export function sayHello(msg: string): string;
44
+ export function sayHello(msg: unknown): string {
45
+ return `Hello ${Array.isArray(msg) ? msg.join(' ') : msg}`;
46
+ }
47
+
48
+ export const sayBye = <T>(msg: T): string => {
49
+ return `Bye ${msg}`;
50
+ };