@ryanatkn/gro 0.169.1 → 0.171.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.
- package/dist/build.task.d.ts +6 -1
- package/dist/build.task.d.ts.map +1 -1
- package/dist/build.task.js +86 -5
- package/dist/build_cache.d.ts +100 -0
- package/dist/build_cache.d.ts.map +1 -0
- package/dist/build_cache.js +289 -0
- package/dist/deploy.task.d.ts.map +1 -1
- package/dist/deploy.task.js +13 -10
- package/dist/esbuild_plugin_svelte.js +1 -1
- package/dist/gen.d.ts.map +1 -1
- package/dist/gro_config.d.ts +30 -1
- package/dist/gro_config.d.ts.map +1 -1
- package/dist/gro_config.js +28 -4
- package/dist/hash.d.ts +1 -1
- package/dist/hash.d.ts.map +1 -1
- package/dist/hash.js +1 -2
- package/dist/invoke_task.d.ts.map +1 -1
- package/dist/invoke_task.js +2 -1
- package/dist/package.d.ts.map +1 -1
- package/dist/package.js +34 -25
- package/dist/package_json.js +1 -1
- package/package.json +14 -14
- package/src/lib/build.task.ts +110 -6
- package/src/lib/build_cache.ts +362 -0
- package/src/lib/changelog.ts +1 -1
- package/src/lib/changeset.task.ts +1 -1
- package/src/lib/commit.task.ts +1 -1
- package/src/lib/deploy.task.ts +14 -10
- package/src/lib/esbuild_plugin_svelte.ts +1 -1
- package/src/lib/gen.ts +2 -1
- package/src/lib/gro_config.ts +62 -3
- package/src/lib/hash.ts +2 -4
- package/src/lib/invoke_task.ts +5 -2
- package/src/lib/package.ts +34 -25
- package/src/lib/package_json.ts +2 -2
- package/src/lib/parse_exports_context.ts +2 -2
- package/src/lib/parse_imports.ts +1 -1
- package/src/lib/upgrade.task.ts +1 -1
- package/dist/test_helpers.d.ts +0 -22
- package/dist/test_helpers.d.ts.map +0 -1
- package/dist/test_helpers.js +0 -123
- package/src/lib/test_helpers.ts +0 -161
package/src/lib/package.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type {Src_Json} from '@ryanatkn/belt/src_json.js';
|
|
|
5
5
|
|
|
6
6
|
export const package_json: Package_Json = {
|
|
7
7
|
name: '@ryanatkn/gro',
|
|
8
|
-
version: '0.
|
|
8
|
+
version: '0.171.0',
|
|
9
9
|
description: 'task runner and toolkit extending SvelteKit',
|
|
10
10
|
motto: 'generate, run, optimize',
|
|
11
11
|
glyph: '🌰',
|
|
@@ -44,7 +44,6 @@ export const package_json: Package_Json = {
|
|
|
44
44
|
'typescript',
|
|
45
45
|
],
|
|
46
46
|
dependencies: {
|
|
47
|
-
'@ryanatkn/belt': '^0.35.1',
|
|
48
47
|
chokidar: '^4.0.3',
|
|
49
48
|
dotenv: '^17.2.2',
|
|
50
49
|
'esm-env': '^1.2.2',
|
|
@@ -54,36 +53,37 @@ export const package_json: Package_Json = {
|
|
|
54
53
|
'prettier-plugin-svelte': '^3.4.0',
|
|
55
54
|
'ts-blank-space': '^0.6.2',
|
|
56
55
|
tslib: '^2.8.1',
|
|
57
|
-
zod: '^4.1.
|
|
56
|
+
zod: '^4.1.12',
|
|
58
57
|
},
|
|
59
58
|
peerDependencies: {
|
|
59
|
+
'@ryanatkn/belt': '^0.36.0',
|
|
60
60
|
'@sveltejs/kit': '^2',
|
|
61
61
|
esbuild: '^0.25',
|
|
62
62
|
svelte: '^5',
|
|
63
63
|
typescript: '^5',
|
|
64
|
-
vitest: '^3',
|
|
64
|
+
vitest: '^3 || ^4',
|
|
65
65
|
},
|
|
66
66
|
peerDependenciesMeta: {'@sveltejs/kit': {optional: true}, vitest: {optional: true}},
|
|
67
|
-
optionalDependencies: {vitest: '^3'},
|
|
67
|
+
optionalDependencies: {vitest: '^3 || ^4'},
|
|
68
68
|
devDependencies: {
|
|
69
69
|
'@changesets/changelog-git': '^0.2.1',
|
|
70
70
|
'@changesets/types': '^6.1.0',
|
|
71
71
|
'@ryanatkn/eslint-config': '^0.8.0',
|
|
72
72
|
'@ryanatkn/fuz': '^0.147.0',
|
|
73
73
|
'@ryanatkn/moss': '^0.36.0',
|
|
74
|
-
'@sveltejs/adapter-static': '^3.0.
|
|
75
|
-
'@sveltejs/kit': '^2.
|
|
76
|
-
'@sveltejs/package': '^2.5.
|
|
77
|
-
'@sveltejs/vite-plugin-svelte': '^6.1
|
|
74
|
+
'@sveltejs/adapter-static': '^3.0.10',
|
|
75
|
+
'@sveltejs/kit': '^2.47.2',
|
|
76
|
+
'@sveltejs/package': '^2.5.4',
|
|
77
|
+
'@sveltejs/vite-plugin-svelte': '^6.2.1',
|
|
78
78
|
'@types/node': '^24.3.1',
|
|
79
79
|
esbuild: '^0.25.9',
|
|
80
80
|
eslint: '^9.35.0',
|
|
81
|
-
'eslint-plugin-svelte': '^3.12.
|
|
82
|
-
svelte: '^5.
|
|
83
|
-
'svelte-check': '^4.3.
|
|
84
|
-
typescript: '^5.9.
|
|
81
|
+
'eslint-plugin-svelte': '^3.12.5',
|
|
82
|
+
svelte: '^5.41.2',
|
|
83
|
+
'svelte-check': '^4.3.3',
|
|
84
|
+
typescript: '^5.9.3',
|
|
85
85
|
'typescript-eslint': '^8.42.0',
|
|
86
|
-
vitest: '^
|
|
86
|
+
vitest: '^4.0.3',
|
|
87
87
|
},
|
|
88
88
|
prettier: {
|
|
89
89
|
plugins: ['prettier-plugin-svelte'],
|
|
@@ -105,7 +105,7 @@ export const package_json: Package_Json = {
|
|
|
105
105
|
|
|
106
106
|
export const src_json: Src_Json = {
|
|
107
107
|
name: '@ryanatkn/gro',
|
|
108
|
-
version: '0.
|
|
108
|
+
version: '0.171.0',
|
|
109
109
|
modules: {
|
|
110
110
|
'.': {
|
|
111
111
|
path: 'index.ts',
|
|
@@ -138,10 +138,28 @@ export const src_json: Src_Json = {
|
|
|
138
138
|
{name: 'print_command_args', kind: 'function'},
|
|
139
139
|
],
|
|
140
140
|
},
|
|
141
|
+
'./build_cache.js': {
|
|
142
|
+
path: 'build_cache.ts',
|
|
143
|
+
declarations: [
|
|
144
|
+
{name: 'BUILD_CACHE_METADATA_FILENAME', kind: 'variable'},
|
|
145
|
+
{name: 'BUILD_CACHE_VERSION', kind: 'variable'},
|
|
146
|
+
{name: 'Build_Output_Entry', kind: 'variable'},
|
|
147
|
+
{name: 'Build_Cache_Metadata', kind: 'variable'},
|
|
148
|
+
{name: 'compute_build_cache_key', kind: 'function'},
|
|
149
|
+
{name: 'load_build_cache_metadata', kind: 'function'},
|
|
150
|
+
{name: 'save_build_cache_metadata', kind: 'function'},
|
|
151
|
+
{name: 'validate_build_cache', kind: 'function'},
|
|
152
|
+
{name: 'is_build_cache_valid', kind: 'function'},
|
|
153
|
+
{name: 'collect_build_outputs', kind: 'function'},
|
|
154
|
+
{name: 'discover_build_output_dirs', kind: 'function'},
|
|
155
|
+
{name: 'create_build_cache_metadata', kind: 'function'},
|
|
156
|
+
],
|
|
157
|
+
},
|
|
141
158
|
'./build.task.js': {
|
|
142
159
|
path: 'build.task.ts',
|
|
143
160
|
declarations: [
|
|
144
161
|
{name: 'Args', kind: 'variable'},
|
|
162
|
+
{name: 'GIT_SHORT_HASH_LENGTH', kind: 'variable'},
|
|
145
163
|
{name: 'task', kind: 'variable'},
|
|
146
164
|
],
|
|
147
165
|
},
|
|
@@ -414,6 +432,7 @@ export const src_json: Src_Json = {
|
|
|
414
432
|
'./gro_config.js': {
|
|
415
433
|
path: 'gro_config.ts',
|
|
416
434
|
declarations: [
|
|
435
|
+
{name: 'EMPTY_BUILD_CACHE_CONFIG_HASH', kind: 'variable'},
|
|
417
436
|
{name: 'Gro_Config', kind: 'type'},
|
|
418
437
|
{name: 'Raw_Gro_Config', kind: 'type'},
|
|
419
438
|
{name: 'Create_Gro_Config', kind: 'type'},
|
|
@@ -826,16 +845,6 @@ export const src_json: Src_Json = {
|
|
|
826
845
|
{name: 'validate_task_module', kind: 'function'},
|
|
827
846
|
],
|
|
828
847
|
},
|
|
829
|
-
'./test_helpers.js': {
|
|
830
|
-
path: 'test_helpers.ts',
|
|
831
|
-
declarations: [
|
|
832
|
-
{name: 'TEST_TIMEOUT_MD', kind: 'variable'},
|
|
833
|
-
{name: 'SOME_PUBLIC_ENV_VAR_NAME', kind: 'variable'},
|
|
834
|
-
{name: 'SOME_PUBLIC_ENV_VAR_VALUE', kind: 'variable'},
|
|
835
|
-
{name: 'init_test_env', kind: 'function'},
|
|
836
|
-
{name: 'create_ts_test_env', kind: 'function'},
|
|
837
|
-
],
|
|
838
|
-
},
|
|
839
848
|
'./test.task.js': {
|
|
840
849
|
path: 'test.task.ts',
|
|
841
850
|
declarations: [
|
package/src/lib/package_json.ts
CHANGED
|
@@ -34,7 +34,7 @@ export const load_package_json = (
|
|
|
34
34
|
): Package_Json => {
|
|
35
35
|
let package_json: Package_Json;
|
|
36
36
|
if (cache && dir in cache) {
|
|
37
|
-
return cache[dir]
|
|
37
|
+
return cache[dir]!;
|
|
38
38
|
}
|
|
39
39
|
try {
|
|
40
40
|
package_json = JSON.parse(load_package_json_contents(dir));
|
|
@@ -194,7 +194,7 @@ export const parse_repo_url = (
|
|
|
194
194
|
return;
|
|
195
195
|
}
|
|
196
196
|
const [, owner, repo] = parsed_repo_url;
|
|
197
|
-
return {owner
|
|
197
|
+
return {owner: owner!, repo: repo!};
|
|
198
198
|
};
|
|
199
199
|
|
|
200
200
|
/**
|
|
@@ -130,7 +130,7 @@ export class Parse_Exports_Context {
|
|
|
130
130
|
|
|
131
131
|
// If no direct match from flags, look at declarations
|
|
132
132
|
if (symbol.declarations && symbol.declarations.length > 0) {
|
|
133
|
-
const decl = symbol.declarations[0]
|
|
133
|
+
const decl = symbol.declarations[0]!;
|
|
134
134
|
const kind_from_decl = this.#infer_kind_from_declaration(decl);
|
|
135
135
|
if (kind_from_decl) {
|
|
136
136
|
return kind_from_decl;
|
|
@@ -348,7 +348,7 @@ export class Parse_Exports_Context {
|
|
|
348
348
|
*/
|
|
349
349
|
#get_export_name(node: ts.Node): string | undefined {
|
|
350
350
|
if (ts.isVariableStatement(node) && node.declarationList.declarations.length > 0) {
|
|
351
|
-
const decl = node.declarationList.declarations[0]
|
|
351
|
+
const decl = node.declarationList.declarations[0]!;
|
|
352
352
|
if (ts.isIdentifier(decl.name)) {
|
|
353
353
|
return decl.name.text;
|
|
354
354
|
}
|
package/src/lib/parse_imports.ts
CHANGED
|
@@ -159,7 +159,7 @@ export const parse_imports = (
|
|
|
159
159
|
// If we're not nested (no HTML tag nesting), process this script
|
|
160
160
|
if (!(contains_opening_tag && !contains_closing_tag)) {
|
|
161
161
|
script_blocks.push({
|
|
162
|
-
content: match[1]
|
|
162
|
+
content: match[1]!,
|
|
163
163
|
start,
|
|
164
164
|
end,
|
|
165
165
|
});
|
package/src/lib/upgrade.task.ts
CHANGED
|
@@ -135,7 +135,7 @@ const to_upgrade_items = (deps: Array<Package_Json_Dep>): Array<string> =>
|
|
|
135
135
|
}
|
|
136
136
|
const custom_tag_matches = CUSTOM_TAG_MATCHER.exec(dep.version);
|
|
137
137
|
if (custom_tag_matches) {
|
|
138
|
-
return dep.name + '@' + custom_tag_matches[1]
|
|
138
|
+
return dep.name + '@' + custom_tag_matches[1]!.split('.')[0]; // I tried adding `\.?` to the end but doesn't work and I'm being lazy so I'm just splitting
|
|
139
139
|
}
|
|
140
140
|
return dep.name + '@latest';
|
|
141
141
|
});
|
package/dist/test_helpers.d.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import ts from 'typescript';
|
|
2
|
-
export declare const TEST_TIMEOUT_MD = 20000;
|
|
3
|
-
export declare const SOME_PUBLIC_ENV_VAR_NAME = "PUBLIC_SOME_PUBLIC_ENV_VAR";
|
|
4
|
-
export declare const SOME_PUBLIC_ENV_VAR_VALUE = "SOME_PUBLIC_ENV_VAR";
|
|
5
|
-
/**
|
|
6
|
-
* Hacky global helper to init the test env.
|
|
7
|
-
*
|
|
8
|
-
* @returns boolean indicating if the env file was created or not
|
|
9
|
-
*/
|
|
10
|
-
export declare const init_test_env: (dir?: string, env_filename?: string) => boolean;
|
|
11
|
-
/**
|
|
12
|
-
* Creates a TypeScript environment for testing.
|
|
13
|
-
* Change to `typescript-go` when it's more ready.
|
|
14
|
-
* @see https://github.com/microsoft/typescript-go?tab=readme-ov-file#what-works-so-far
|
|
15
|
-
*/
|
|
16
|
-
export declare const create_ts_test_env: (source_code: string, dir?: string, virtual_files?: Record<string, string>) => {
|
|
17
|
-
source_file: ts.SourceFile;
|
|
18
|
-
checker: ts.TypeChecker;
|
|
19
|
-
program: ts.Program;
|
|
20
|
-
exports: Array<ts.Symbol>;
|
|
21
|
-
};
|
|
22
|
-
//# sourceMappingURL=test_helpers.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"test_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/test_helpers.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,eAAO,MAAM,eAAe,QAAS,CAAC;AAEtC,eAAO,MAAM,wBAAwB,+BAA+B,CAAC;AACrE,eAAO,MAAM,yBAAyB,wBAAwB,CAAC;AAM/D;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,YAAmB,EAAE,qBAAqB,KAAG,OA6B1E,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAC9B,aAAa,MAAM,EACnB,MAAK,MAAsB,EAC3B,gBAAe,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,KACxC;IACF,WAAW,EAAE,EAAE,CAAC,UAAU,CAAC;IAC3B,OAAO,EAAE,EAAE,CAAC,WAAW,CAAC;IACxB,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC;IACpB,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;CAkG1B,CAAC"}
|
package/dist/test_helpers.js
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
import ts from 'typescript';
|
|
4
|
-
export const TEST_TIMEOUT_MD = 20_000;
|
|
5
|
-
export const SOME_PUBLIC_ENV_VAR_NAME = 'PUBLIC_SOME_PUBLIC_ENV_VAR';
|
|
6
|
-
export const SOME_PUBLIC_ENV_VAR_VALUE = 'SOME_PUBLIC_ENV_VAR';
|
|
7
|
-
const name_equals = SOME_PUBLIC_ENV_VAR_NAME + '=';
|
|
8
|
-
const line = name_equals + SOME_PUBLIC_ENV_VAR_VALUE;
|
|
9
|
-
let inited = false;
|
|
10
|
-
/**
|
|
11
|
-
* Hacky global helper to init the test env.
|
|
12
|
-
*
|
|
13
|
-
* @returns boolean indicating if the env file was created or not
|
|
14
|
-
*/
|
|
15
|
-
export const init_test_env = (dir = process.cwd(), env_filename = '.env') => {
|
|
16
|
-
if (inited)
|
|
17
|
-
return false;
|
|
18
|
-
inited = true;
|
|
19
|
-
const env_file = join(dir, env_filename);
|
|
20
|
-
if (!existsSync(env_file)) {
|
|
21
|
-
writeFileSync(env_file, line + '\n', 'utf8');
|
|
22
|
-
return true;
|
|
23
|
-
}
|
|
24
|
-
const contents = readFileSync(env_file, 'utf8');
|
|
25
|
-
const lines = contents.split('\n');
|
|
26
|
-
if (lines.includes(line)) {
|
|
27
|
-
return false; // already exists
|
|
28
|
-
}
|
|
29
|
-
let new_contents;
|
|
30
|
-
const found_index = lines.findIndex((l) => l.startsWith(name_equals));
|
|
31
|
-
if (found_index === -1) {
|
|
32
|
-
// if the line does not exist, add it
|
|
33
|
-
new_contents = contents + (contents.endsWith('\n') ? '' : '\n') + line + '\n';
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
// if the line exists but with a different value, replace it
|
|
37
|
-
new_contents = contents.replace(new RegExp(`${SOME_PUBLIC_ENV_VAR_NAME}=.*`), line);
|
|
38
|
-
}
|
|
39
|
-
writeFileSync(env_file, new_contents, 'utf8');
|
|
40
|
-
return true;
|
|
41
|
-
};
|
|
42
|
-
/**
|
|
43
|
-
* Creates a TypeScript environment for testing.
|
|
44
|
-
* Change to `typescript-go` when it's more ready.
|
|
45
|
-
* @see https://github.com/microsoft/typescript-go?tab=readme-ov-file#what-works-so-far
|
|
46
|
-
*/
|
|
47
|
-
export const create_ts_test_env = (source_code, dir = process.cwd(), virtual_files = {}) => {
|
|
48
|
-
// Create a virtual file path for testing
|
|
49
|
-
const file_path = join(dir, 'virtual_test_file.ts');
|
|
50
|
-
// Create a compiler host with custom module resolution
|
|
51
|
-
const host = ts.createCompilerHost({});
|
|
52
|
-
const original_get_source_file = host.getSourceFile.bind(host);
|
|
53
|
-
// Override getSourceFile to return our test files
|
|
54
|
-
host.getSourceFile = (fileName, languageVersion) => {
|
|
55
|
-
if (fileName === file_path) {
|
|
56
|
-
return ts.createSourceFile(fileName, source_code, languageVersion);
|
|
57
|
-
}
|
|
58
|
-
// Check if we have a virtual file for this path
|
|
59
|
-
for (const [virtual_path, content] of Object.entries(virtual_files)) {
|
|
60
|
-
const full_path = join(dir, virtual_path);
|
|
61
|
-
if (fileName === full_path) {
|
|
62
|
-
return ts.createSourceFile(fileName, content, languageVersion);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return original_get_source_file(fileName, languageVersion);
|
|
66
|
-
};
|
|
67
|
-
// TODO simplify?
|
|
68
|
-
// Add custom module resolution using resolveModuleNameLiterals
|
|
69
|
-
host.resolveModuleNameLiterals = (module_literals, containing_file, _redirected_reference, options) => {
|
|
70
|
-
return module_literals.map((module_literal) => {
|
|
71
|
-
const module_name = module_literal.text;
|
|
72
|
-
// Handle relative imports that might be in our virtual files
|
|
73
|
-
if (module_name.startsWith('./') || module_name.startsWith('../')) {
|
|
74
|
-
const module_path = join(containing_file, '..', module_name);
|
|
75
|
-
// Normalize the path handling for the virtual files
|
|
76
|
-
for (const virtual_path of Object.keys(virtual_files)) {
|
|
77
|
-
const full_path = join(dir, virtual_path);
|
|
78
|
-
const normalized_module_path = module_path.replace(/\.ts$/, '') + '.ts';
|
|
79
|
-
if (normalized_module_path === full_path) {
|
|
80
|
-
return {
|
|
81
|
-
resolvedModule: {
|
|
82
|
-
resolvedFileName: full_path,
|
|
83
|
-
isExternalLibraryImport: false,
|
|
84
|
-
extension: ts.Extension.Ts,
|
|
85
|
-
},
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
// If it's our main file
|
|
91
|
-
if (join(dir, module_name) === file_path) {
|
|
92
|
-
return {
|
|
93
|
-
resolvedModule: {
|
|
94
|
-
resolvedFileName: file_path,
|
|
95
|
-
isExternalLibraryImport: false,
|
|
96
|
-
extension: ts.Extension.Ts,
|
|
97
|
-
},
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
// For non-virtual modules, try standard resolution
|
|
101
|
-
return ts.resolveModuleName(module_name, containing_file, options, host);
|
|
102
|
-
});
|
|
103
|
-
};
|
|
104
|
-
// Include all virtual files in the program files list
|
|
105
|
-
const program_files = [file_path, ...Object.keys(virtual_files).map((path) => join(dir, path))];
|
|
106
|
-
// TODO get from tsconfig?
|
|
107
|
-
// Create program options
|
|
108
|
-
const compiler_options = {
|
|
109
|
-
target: ts.ScriptTarget.ESNext,
|
|
110
|
-
module: ts.ModuleKind.ESNext,
|
|
111
|
-
moduleResolution: ts.ModuleResolutionKind.NodeNext,
|
|
112
|
-
verbatimModuleSyntax: true,
|
|
113
|
-
isolatedModules: true,
|
|
114
|
-
};
|
|
115
|
-
// Create a program with our virtual files
|
|
116
|
-
const program = ts.createProgram(program_files, compiler_options, host);
|
|
117
|
-
const source_file = program.getSourceFile(file_path);
|
|
118
|
-
const checker = program.getTypeChecker();
|
|
119
|
-
// Get the exports from the source file
|
|
120
|
-
const symbol = checker.getSymbolAtLocation(source_file);
|
|
121
|
-
const exports = symbol ? checker.getExportsOfModule(symbol) : [];
|
|
122
|
-
return { source_file, checker, program, exports };
|
|
123
|
-
};
|
package/src/lib/test_helpers.ts
DELETED
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import {existsSync, readFileSync, writeFileSync} from 'node:fs';
|
|
2
|
-
import {join} from 'node:path';
|
|
3
|
-
import ts from 'typescript';
|
|
4
|
-
|
|
5
|
-
export const TEST_TIMEOUT_MD = 20_000;
|
|
6
|
-
|
|
7
|
-
export const SOME_PUBLIC_ENV_VAR_NAME = 'PUBLIC_SOME_PUBLIC_ENV_VAR';
|
|
8
|
-
export const SOME_PUBLIC_ENV_VAR_VALUE = 'SOME_PUBLIC_ENV_VAR';
|
|
9
|
-
const name_equals = SOME_PUBLIC_ENV_VAR_NAME + '=';
|
|
10
|
-
const line = name_equals + SOME_PUBLIC_ENV_VAR_VALUE;
|
|
11
|
-
|
|
12
|
-
let inited = false;
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Hacky global helper to init the test env.
|
|
16
|
-
*
|
|
17
|
-
* @returns boolean indicating if the env file was created or not
|
|
18
|
-
*/
|
|
19
|
-
export const init_test_env = (dir = process.cwd(), env_filename = '.env'): boolean => {
|
|
20
|
-
if (inited) return false;
|
|
21
|
-
inited = true;
|
|
22
|
-
|
|
23
|
-
const env_file = join(dir, env_filename);
|
|
24
|
-
|
|
25
|
-
if (!existsSync(env_file)) {
|
|
26
|
-
writeFileSync(env_file, line + '\n', 'utf8');
|
|
27
|
-
return true;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const contents = readFileSync(env_file, 'utf8');
|
|
31
|
-
const lines = contents.split('\n');
|
|
32
|
-
if (lines.includes(line)) {
|
|
33
|
-
return false; // already exists
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
let new_contents: string;
|
|
37
|
-
const found_index = lines.findIndex((l) => l.startsWith(name_equals));
|
|
38
|
-
if (found_index === -1) {
|
|
39
|
-
// if the line does not exist, add it
|
|
40
|
-
new_contents = contents + (contents.endsWith('\n') ? '' : '\n') + line + '\n';
|
|
41
|
-
} else {
|
|
42
|
-
// if the line exists but with a different value, replace it
|
|
43
|
-
new_contents = contents.replace(new RegExp(`${SOME_PUBLIC_ENV_VAR_NAME}=.*`), line);
|
|
44
|
-
}
|
|
45
|
-
writeFileSync(env_file, new_contents, 'utf8');
|
|
46
|
-
|
|
47
|
-
return true;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Creates a TypeScript environment for testing.
|
|
52
|
-
* Change to `typescript-go` when it's more ready.
|
|
53
|
-
* @see https://github.com/microsoft/typescript-go?tab=readme-ov-file#what-works-so-far
|
|
54
|
-
*/
|
|
55
|
-
export const create_ts_test_env = (
|
|
56
|
-
source_code: string,
|
|
57
|
-
dir: string = process.cwd(),
|
|
58
|
-
virtual_files: Record<string, string> = {},
|
|
59
|
-
): {
|
|
60
|
-
source_file: ts.SourceFile;
|
|
61
|
-
checker: ts.TypeChecker;
|
|
62
|
-
program: ts.Program;
|
|
63
|
-
exports: Array<ts.Symbol>;
|
|
64
|
-
} => {
|
|
65
|
-
// Create a virtual file path for testing
|
|
66
|
-
const file_path = join(dir, 'virtual_test_file.ts');
|
|
67
|
-
|
|
68
|
-
// Create a compiler host with custom module resolution
|
|
69
|
-
const host = ts.createCompilerHost({});
|
|
70
|
-
const original_get_source_file = host.getSourceFile.bind(host);
|
|
71
|
-
|
|
72
|
-
// Override getSourceFile to return our test files
|
|
73
|
-
host.getSourceFile = (fileName: string, languageVersion: ts.ScriptTarget) => {
|
|
74
|
-
if (fileName === file_path) {
|
|
75
|
-
return ts.createSourceFile(fileName, source_code, languageVersion);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Check if we have a virtual file for this path
|
|
79
|
-
for (const [virtual_path, content] of Object.entries(virtual_files)) {
|
|
80
|
-
const full_path = join(dir, virtual_path);
|
|
81
|
-
if (fileName === full_path) {
|
|
82
|
-
return ts.createSourceFile(fileName, content, languageVersion);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return original_get_source_file(fileName, languageVersion);
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
// TODO simplify?
|
|
90
|
-
// Add custom module resolution using resolveModuleNameLiterals
|
|
91
|
-
host.resolveModuleNameLiterals = (
|
|
92
|
-
module_literals: ReadonlyArray<ts.StringLiteralLike>,
|
|
93
|
-
containing_file: string,
|
|
94
|
-
_redirected_reference: ts.ResolvedProjectReference | undefined,
|
|
95
|
-
options: ts.CompilerOptions,
|
|
96
|
-
): Array<ts.ResolvedModuleWithFailedLookupLocations> => {
|
|
97
|
-
return module_literals.map((module_literal) => {
|
|
98
|
-
const module_name = module_literal.text;
|
|
99
|
-
|
|
100
|
-
// Handle relative imports that might be in our virtual files
|
|
101
|
-
if (module_name.startsWith('./') || module_name.startsWith('../')) {
|
|
102
|
-
const module_path = join(containing_file, '..', module_name);
|
|
103
|
-
|
|
104
|
-
// Normalize the path handling for the virtual files
|
|
105
|
-
for (const virtual_path of Object.keys(virtual_files)) {
|
|
106
|
-
const full_path = join(dir, virtual_path);
|
|
107
|
-
const normalized_module_path = module_path.replace(/\.ts$/, '') + '.ts';
|
|
108
|
-
|
|
109
|
-
if (normalized_module_path === full_path) {
|
|
110
|
-
return {
|
|
111
|
-
resolvedModule: {
|
|
112
|
-
resolvedFileName: full_path,
|
|
113
|
-
isExternalLibraryImport: false,
|
|
114
|
-
extension: ts.Extension.Ts,
|
|
115
|
-
},
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// If it's our main file
|
|
122
|
-
if (join(dir, module_name) === file_path) {
|
|
123
|
-
return {
|
|
124
|
-
resolvedModule: {
|
|
125
|
-
resolvedFileName: file_path,
|
|
126
|
-
isExternalLibraryImport: false,
|
|
127
|
-
extension: ts.Extension.Ts,
|
|
128
|
-
},
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// For non-virtual modules, try standard resolution
|
|
133
|
-
return ts.resolveModuleName(module_name, containing_file, options, host);
|
|
134
|
-
});
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
// Include all virtual files in the program files list
|
|
138
|
-
const program_files = [file_path, ...Object.keys(virtual_files).map((path) => join(dir, path))];
|
|
139
|
-
|
|
140
|
-
// TODO get from tsconfig?
|
|
141
|
-
// Create program options
|
|
142
|
-
const compiler_options: ts.CompilerOptions = {
|
|
143
|
-
target: ts.ScriptTarget.ESNext,
|
|
144
|
-
module: ts.ModuleKind.ESNext,
|
|
145
|
-
moduleResolution: ts.ModuleResolutionKind.NodeNext,
|
|
146
|
-
verbatimModuleSyntax: true,
|
|
147
|
-
isolatedModules: true,
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
// Create a program with our virtual files
|
|
151
|
-
const program = ts.createProgram(program_files, compiler_options, host);
|
|
152
|
-
|
|
153
|
-
const source_file = program.getSourceFile(file_path)!;
|
|
154
|
-
const checker = program.getTypeChecker();
|
|
155
|
-
|
|
156
|
-
// Get the exports from the source file
|
|
157
|
-
const symbol = checker.getSymbolAtLocation(source_file);
|
|
158
|
-
const exports = symbol ? checker.getExportsOfModule(symbol) : [];
|
|
159
|
-
|
|
160
|
-
return {source_file, checker, program, exports};
|
|
161
|
-
};
|