diff --git a/.eslintrc.js b/.eslintrc.js index 0df15f19..00898b82 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -5,7 +5,6 @@ module.exports = { "**/godot_src/**", "**/js/**", ".eslintrc.js", - "tsconfig.json", ], env: { es2021: true, diff --git a/.vscode/launch.json b/.vscode/launch.json index 853eb13c..da222e4e 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,23 +5,33 @@ "version": "0.2.0", "configurations": [ { - "name": "Launch Program", + "name": "Run Example", "program": "${workspaceFolder}/js/main.js", "request": "launch", - "skipFiles": ["/**"], - "args": ["${workspaceFolder}/example/ts2gd.json"], + "skipFiles": [ + "/**" + ], + "args": [ + "${workspaceFolder}/example/ts2gd.json" + ], "type": "pwa-node", "preLaunchTask": "tsc: build - tsconfig.json", - "outFiles": ["${workspaceFolder}/js/**/*.js"] + "outFiles": [ + "${workspaceFolder}/js/**/*.js" + ] }, { - "name": "Launch Test", + "name": "Run Tests", "program": "${workspaceFolder}/js/tests/test.js", "request": "launch", - "skipFiles": ["/**"], + "skipFiles": [ + "/**" + ], "type": "pwa-node", "preLaunchTask": "tsc: build - tsconfig.json", - "outFiles": ["${workspaceFolder}/js/**/*.js"] + "outFiles": [ + "${workspaceFolder}/js/**/*.js" + ] } ] -} +} \ No newline at end of file diff --git a/example/Autoload.gd b/example/Autoload.gd new file mode 100644 index 00000000..3f3cb12c --- /dev/null +++ b/example/Autoload.gd @@ -0,0 +1,13 @@ + +# This file has been autogenerated by ts2gd. DO NOT EDIT! + + +extends Node2D +class_name Autoload + + + + +var _MyAutoload = Autoload.new() + +var hello: String = "hi" diff --git a/example/Test.gd b/example/Test.gd new file mode 100644 index 00000000..82653407 --- /dev/null +++ b/example/Test.gd @@ -0,0 +1,12 @@ + +# This file has been autogenerated by ts2gd. DO NOT EDIT! + + + +class_name Test + + + + + + diff --git a/example/Test.ts b/example/Test.ts new file mode 100644 index 00000000..0d2b0efd --- /dev/null +++ b/example/Test.ts @@ -0,0 +1,2 @@ +// this file will have dynamic content from our test infrastructure +export class Test {} diff --git a/example/autoload.ts b/example/autoload.ts new file mode 100644 index 00000000..fbb69bad --- /dev/null +++ b/example/autoload.ts @@ -0,0 +1,8 @@ +// this file will have dynamic content from our test infrastructure + +@autoload +class Autoload extends Node2D { + public hello = "hi" +} + +export const MyAutoload = new Autoload() diff --git a/example/Main.tscn b/example/main.tscn similarity index 100% rename from example/Main.tscn rename to example/main.tscn diff --git a/example/project.godot b/example/project.godot index 07202eb9..4f545dc4 100644 --- a/example/project.godot +++ b/example/project.godot @@ -8,12 +8,30 @@ config_version=4 +_global_script_classes=[ { +"base": "Reference", +"class": "Test", +"language": "GDScript", +"path": "res://Test.gd" +} ] +_global_script_class_icons={ +"Test": "" +} + [application] config/name="example" -run/main_scene="res://Main.tscn" +run/main_scene="res://main.tscn" config/icon="res://icon.png" +[autoload] + +Autoload="*res://Autoload.gd" + +[global] + +autoload=false + [physics] common/enable_pause_aware_picking=true diff --git a/example/ts2gd.json b/example/ts2gd.json index fb9fc38c..99ab8b1b 100644 --- a/example/ts2gd.json +++ b/example/ts2gd.json @@ -2,5 +2,8 @@ "destination": "./", "source": "./", "godotSourceRepoPath": "./godot_src", - "ignore": ["**/ignore_me/**", "ignore_me.ts"] -} + "ignore": [ + "**/ignore_me/**", + "ignore_me.ts" + ] +} \ No newline at end of file diff --git a/main.ts b/main.ts index 44b57c43..610c2285 100755 --- a/main.ts +++ b/main.ts @@ -240,7 +240,7 @@ const setup = (tsgdJson: Paths) => { opt.config.useCaseSensitiveFileNames = false return { - watchProgram, + program: watchProgram.getProgram().getProgram(), tsgdJson, reportWatchStatusChanged, tsInitializationFinished, @@ -266,10 +266,10 @@ export const main = async (args: ParsedArgs) => { const tsgdJson = new Paths(args) showLoadingMessage("Initializing TypeScript", args) - const { watchProgram, tsInitializationFinished } = setup(tsgdJson) + const { program, tsInitializationFinished } = setup(tsgdJson) showLoadingMessage("Scanning project", args) - let project = await makeTsGdProject(tsgdJson, watchProgram, args) + let project = await makeTsGdProject(tsgdJson, program, args) if (args.buildLibraries || project.shouldBuildLibraryDefinitions(args)) { showLoadingMessage("Building definition files", args) diff --git a/package-lock.json b/package-lock.json index c71761fe..efc0a797 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "chalk": "^4.1.2", "chokidar": "^3.5.2", + "lodash": "^4.17.21", "tsutils": "^3.21.0", "xml2js": "^0.4.23" }, @@ -18,6 +19,7 @@ "ts2gd": "bin/index.js" }, "devDependencies": { + "@types/lodash": "^4.14.178", "@types/node": "^16.11.9", "@types/xml2js": "^0.4.9", "@typescript-eslint/eslint-plugin": "^5.7.0", @@ -178,6 +180,12 @@ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, + "node_modules/@types/lodash": { + "version": "4.14.178", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz", + "integrity": "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==", + "dev": true + }, "node_modules/@types/node": { "version": "16.11.9", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.9.tgz", @@ -2156,6 +2164,11 @@ "node": ">=4" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -3543,6 +3556,12 @@ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, + "@types/lodash": { + "version": "4.14.178", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz", + "integrity": "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==", + "dev": true + }, "@types/node": { "version": "16.11.9", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.9.tgz", @@ -4960,6 +4979,11 @@ "path-exists": "^3.0.0" } }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", diff --git a/package.json b/package.json index bcb6cd89..a02fb079 100644 --- a/package.json +++ b/package.json @@ -33,18 +33,23 @@ "semi": false }, "lint-staged": { - "*.{ts,json}": [ + "*.ts": [ "eslint --fix", "prettier --write" + ], + "*.json": [ + "prettier --write" ] }, "dependencies": { "chalk": "^4.1.2", "chokidar": "^3.5.2", + "lodash": "^4.17.21", "tsutils": "^3.21.0", "xml2js": "^0.4.23" }, "devDependencies": { + "@types/lodash": "^4.14.178", "@types/node": "^16.11.9", "@types/xml2js": "^0.4.9", "@typescript-eslint/eslint-plugin": "^5.7.0", diff --git a/parse_node/parse_enum_declaration.ts b/parse_node/parse_enum_declaration.ts index ac5b62d7..31594073 100644 --- a/parse_node/parse_enum_declaration.ts +++ b/parse_node/parse_enum_declaration.ts @@ -2,6 +2,7 @@ import ts from "typescript" import { ParseNodeType, ParseState, combine } from "../parse_node" import { Test } from "../tests/test" +import { examplePath } from "../tests/test_utils" import { getImportResPathForEnum } from "./parse_import_declaration" @@ -71,17 +72,17 @@ export class Hello { type: "multiple-files", files: [ { - fileName: "/Users/johnfn/MyGame/compiled/Hello.gd", + fileName: examplePath("Hello.gd"), expected: ` class_name Hello -const MyEnum = preload("res://compiled/Test_MyEnum.gd").MyEnum +const MyEnum = preload("res://Test_MyEnum.gd").MyEnum func _ready(): print(MyEnum.A) `, }, { - fileName: "/Users/johnfn/MyGame/compiled/Test_MyEnum.gd", + fileName: examplePath("Test_MyEnum.gd"), expected: ` const MyEnum = { "A": 0, @@ -109,17 +110,17 @@ export class Hello { type: "multiple-files", files: [ { - fileName: "/Users/johnfn/MyGame/compiled/Hello.gd", + fileName: examplePath("Hello.gd"), expected: ` class_name Hello -const TestEnum = preload("res://compiled/Test_TestEnum.gd").TestEnum +const TestEnum = preload("res://Test_TestEnum.gd").TestEnum func _ready(): print(TestEnum.A) `, }, { - fileName: "/Users/johnfn/MyGame/compiled/Test_TestEnum.gd", + fileName: examplePath("Test_TestEnum.gd"), expected: ` const TestEnum = { "A": "A", diff --git a/parse_node/parse_property_declaration.ts b/parse_node/parse_property_declaration.ts index ab2434df..33db4a19 100644 --- a/parse_node/parse_property_declaration.ts +++ b/parse_node/parse_property_declaration.ts @@ -5,6 +5,7 @@ import { ErrorName } from "../project/errors" import { ParseNodeType, ParseState, combine } from "../parse_node" import { Test } from "../tests/test" import { getGodotType, getTypeHierarchy, isEnumType } from "../ts_utils" +import { examplePath } from "../tests/test_utils" export const isDecoratedAsExports = ( node: @@ -448,16 +449,16 @@ export class Test { type: "multiple-files", files: [ { - fileName: "/Users/johnfn/MyGame/compiled/Test.gd", + fileName: examplePath("Test.gd"), expected: ` class_name Test -const MyEnum = preload("res://compiled/Test_MyEnum.gd").MyEnum +const MyEnum = preload("res://Test_MyEnum.gd").MyEnum export(MyEnum) var foo `, }, { - fileName: "/Users/johnfn/MyGame/compiled/Test_MyEnum.gd", + fileName: examplePath("Test_MyEnum.gd"), expected: ` const MyEnum = { }`, diff --git a/parse_node/parse_source_file.ts b/parse_node/parse_source_file.ts index 5f2d7eb4..2df7992c 100644 --- a/parse_node/parse_source_file.ts +++ b/parse_node/parse_source_file.ts @@ -1,8 +1,9 @@ import ts, { SyntaxKind } from "typescript" -import { ErrorName } from "../project/errors" +import { ErrorName } from "../project" import { ParseNodeType, ParseState, combine, parseNode } from "../parse_node" import { Test } from "../tests/test" +import { examplePath } from "../tests/test_utils" import { LibraryFunctions } from "./library_functions" @@ -221,11 +222,11 @@ export class Test2 { } type: "multiple-files", files: [ { - fileName: "/Users/johnfn/MyGame/compiled/Test1.gd", + fileName: examplePath("Test1.gd"), expected: `class_name Test1`, }, { - fileName: "/Users/johnfn/MyGame/compiled/Test2.gd", + fileName: examplePath("Test2.gd"), expected: `class_name Test2`, }, ], diff --git a/project/assets/asset_source_file.ts b/project/assets/asset_source_file.ts index 2c7e7884..535d9381 100644 --- a/project/assets/asset_source_file.ts +++ b/project/assets/asset_source_file.ts @@ -67,15 +67,17 @@ export class AssetSourceFile extends BaseAsset { -".gd".length ) this.project = project - this._isAutoload = !!this.project.godotProject.autoloads.find( - (a) => a.resPath === this.resPath + this._isAutoload = Boolean( + this.project.godotProject.autoloads.find( + (a) => a.resPath === this.resPath + ) ) } reload() {} private getAst(): TsGdError | ts.SourceFile { - const ast = this.project.program.getProgram().getSourceFile(this.fsPath) + const ast = this.project.program.getSourceFile(this.fsPath) if (!ast) { return { @@ -319,18 +321,16 @@ Second path: ${chalk.yellow(sf.fsPath)}`, } } - async compile( - watchProgram: ts.WatchOfConfigFile - ): Promise { + async compile(watchProgram: ts.Program): Promise { const oldAutoloadClassName = this.getAutoloadNameFromExportedVariable() - let sourceFileAst = watchProgram.getProgram().getSourceFile(this.fsPath) + let sourceFileAst = watchProgram.getSourceFile(this.fsPath) let tries = 0 while (!sourceFileAst && ++tries < 50) { await new Promise((resolve) => setTimeout(resolve, 10)) - sourceFileAst = watchProgram.getProgram().getSourceFile(this.fsPath)! + sourceFileAst = watchProgram.getSourceFile(this.fsPath)! } if (!sourceFileAst) { @@ -353,17 +353,17 @@ Second path: ${chalk.yellow(sf.fsPath)}`, (await fs.readFile(this.fsPath, "utf-8")) !== sourceFileAst.getFullText() ) { await new Promise((resolve) => setTimeout(resolve, 10)) - sourceFileAst = watchProgram.getProgram().getSourceFile(this.fsPath)! + sourceFileAst = watchProgram.getSourceFile(this.fsPath)! } const parsedNode = parseNode(sourceFileAst, { indent: "", isConstructor: false, - scope: new Scope(watchProgram.getProgram().getProgram()), + scope: new Scope(watchProgram), project: this.project, mostRecentControlStructureIsSwitch: false, isAutoload: this.isProjectAutoload(), - program: watchProgram.getProgram().getProgram(), + program: watchProgram, usages: utils.collectVariableUsage(sourceFileAst), sourceFile: sourceFileAst, sourceFileAsset: this, diff --git a/project/assets/base_asset.ts b/project/assets/base_asset.ts index 0b606def..f6c09628 100644 --- a/project/assets/base_asset.ts +++ b/project/assets/base_asset.ts @@ -5,3 +5,7 @@ export abstract class BaseAsset { abstract tsType(): string | null } + +export function isBaseAsset(input?: object): input is BaseAsset { + return Boolean(input) && input instanceof BaseAsset +} diff --git a/project/godot_project_file.ts b/project/godot_project_file.ts index 749ccee0..50891c51 100644 --- a/project/godot_project_file.ts +++ b/project/godot_project_file.ts @@ -143,3 +143,7 @@ export class GodotProjectFile { } } } + +export function isProjectFile(input: object): input is GodotProjectFile { + return input instanceof GodotProjectFile +} diff --git a/project/project.ts b/project/project.ts index 8db9cbd1..3ef3615c 100644 --- a/project/project.ts +++ b/project/project.ts @@ -1,6 +1,6 @@ import fs from "fs" -import path from "path" +import _ from "lodash" import chalk from "chalk" import chokidar from "chokidar" import ts from "typescript" @@ -9,14 +9,14 @@ import LibraryBuilder from "../generate_library_defs" import { ParsedArgs } from "../parse_args" import Errors, { TsGdError } from "./errors" -import { GodotProjectFile } from "./godot_project_file" +import { GodotProjectFile, isProjectFile } from "./godot_project_file" import { Paths } from "./paths" import { AssetFont } from "./assets/asset_font" import { AssetGlb } from "./assets/asset_glb" import { AssetGodotScene } from "./assets/asset_godot_scene" import { AssetImage } from "./assets/asset_image" import { AssetSourceFile } from "./assets/asset_source_file" -import { BaseAsset } from "./assets/base_asset" +import { BaseAsset, isBaseAsset } from "./assets/base_asset" import DefinitionBuilder from "./generate_dynamic_defs" // TODO: Instead of manually scanning to find all assets, i could just import @@ -64,7 +64,8 @@ export class TsGdProject { mainScene: AssetGodotScene - program: ts.WatchOfConfigFile + //program: ts.WatchOfConfigFile + program: ts.Program public readonly args: ParsedArgs @@ -72,18 +73,18 @@ export class TsGdProject { public readonly errors: Errors - constructor( - watcher: chokidar.FSWatcher, - initialFilePaths: string[], - program: ts.WatchOfConfigFile, - ts2gdJson: Paths, + constructor(options: { + watcher?: chokidar.FSWatcher + initialFilePaths: string[] + program: ts.Program + ts2gdJson: Paths args: ParsedArgs - ) { + }) { // Initial set up - this.args = args - this.paths = ts2gdJson - this.program = program + this.args = options.args + this.paths = options.ts2gdJson + this.program = options.program this.errors = new Errors(this.args) @@ -91,33 +92,50 @@ export class TsGdProject { // Parse assets - const projectGodot = initialFilePaths.filter((path) => - path.includes("project.godot") - )[0] - - this.godotProject = this.createAsset(projectGodot)! as GodotProjectFile - - const initialAssets = initialFilePaths.map((path) => this.createAsset(path)) + const [projectFilePaths, otherAssetPaths] = _.partition( + options.initialFilePaths, + (path) => path.includes("project.godot") + ) - for (const asset of initialAssets) { - if (asset === null) { - continue + if (projectFilePaths.length !== 1) { + throw new Error( + `Need exactly one project.godot file, but found ${projectFilePaths.length}!` + ) + } else { + const project = this.createGodotProject(projectFilePaths[0]) + if (project) { + this.godotProject = project + } else { + throw new Error( + `Couldn't parse godot project from ${projectFilePaths[0]}` + ) } + } - if (asset instanceof BaseAsset) { - this.assets.push(asset) - } + this.assets = _.compact( + otherAssetPaths.map((path) => this.createAsset(path)) + ) - if (asset instanceof GodotProjectFile) { - this.godotProject = asset - } + const mainScene = this.godotScenes().find( + (scene) => scene.resPath === this.godotProject.mainScene().resPath + ) + + if (!mainScene) { + throw new Error("Main scene not found, check your Godot project!") } - this.mainScene = this.godotScenes().find( - (scene) => scene.resPath === this.godotProject.mainScene().resPath - )! + this.mainScene = mainScene + + this.monitor(options.watcher) + } - this.monitor(watcher) + createGodotProject(path: string): GodotProjectFile | null { + if (path.endsWith(".godot")) { + return new GodotProjectFile(path, this) + } + + console.error(`unhandled asset type ${path}`) + return null } createAsset( @@ -127,7 +145,6 @@ export class TsGdProject { | AssetGodotScene | AssetFont | AssetImage - | GodotProjectFile | AssetGlb | null { //TODO: move these checks to the asset classes in static methods @@ -135,8 +152,6 @@ export class TsGdProject { return new AssetSourceFile(path, this) } else if (path.endsWith(".tscn")) { return new AssetGodotScene(path, this) - } else if (path.endsWith(".godot")) { - return new GodotProjectFile(path, this) } else if (path.endsWith(".ttf")) { return new AssetFont(path, this) } else if (path.endsWith(".glb")) { @@ -151,13 +166,12 @@ export class TsGdProject { } console.error(`unhandled asset type ${path}`) - return null } - monitor(watcher: chokidar.FSWatcher) { + monitor(watcher?: chokidar.FSWatcher) { watcher - .on("add", async (path) => { + ?.on("add", async (path) => { const message = await this.onAddAsset(path) this.errors.display(message) @@ -233,26 +247,26 @@ export class TsGdProject { await script.compile(this.program) } } - } + } else { + let oldAsset = this.assets.find((asset) => asset.fsPath === path) - let oldAsset = this.assets.find((asset) => asset.fsPath === path) + if (oldAsset) { + let newAsset = this.createAsset(path) as any as BaseAsset + this.assets = this.assets.filter((a) => a.fsPath !== path) + this.assets.push(newAsset) - if (oldAsset) { - let newAsset = this.createAsset(path) as any as BaseAsset - this.assets = this.assets.filter((a) => a.fsPath !== path) - this.assets.push(newAsset) + if (newAsset instanceof AssetSourceFile) { + await newAsset.compile(this.program) - if (newAsset instanceof AssetSourceFile) { - await newAsset.compile(this.program) + this.definitionBuilder.buildAssetPathsType() + this.definitionBuilder.buildNodePathsTypeForScript(newAsset) + } else if (newAsset instanceof AssetGodotScene) { + for (const script of this.sourceFiles()) { + this.definitionBuilder.buildNodePathsTypeForScript(script) + } - this.definitionBuilder.buildAssetPathsType() - this.definitionBuilder.buildNodePathsTypeForScript(newAsset) - } else if (newAsset instanceof AssetGodotScene) { - for (const script of this.sourceFiles()) { - this.definitionBuilder.buildNodePathsTypeForScript(script) + this.definitionBuilder.buildSceneImports() } - - this.definitionBuilder.buildSceneImports() } } @@ -331,7 +345,7 @@ export class TsGdProject { export const makeTsGdProject = async ( ts2gdJson: Paths, - program: ts.WatchOfConfigFile, + program: ts.Program, args: ParsedArgs ) => { const [watcher, initialFiles] = await new Promise< @@ -351,7 +365,13 @@ export const makeTsGdProject = async ( }) }) - return new TsGdProject(watcher, initialFiles, program, ts2gdJson, args) + return new TsGdProject({ + watcher, + initialFilePaths: initialFiles, + program, + ts2gdJson, + args, + }) } export default TsGdProject diff --git a/tests/stubs.ts b/tests/stubs.ts deleted file mode 100644 index c9f26eb1..00000000 --- a/tests/stubs.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { AssetSourceFile } from "../project/assets/asset_source_file" - -export const createStubSourceFileAsset = (name: string): AssetSourceFile => { - const sourceFileAsset: AssetSourceFile = { - exportedTsClassName: () => "", - fsPath: `${name}.ts`, - name: name, - isProjectAutoload: () => false, - resPath: `res://compiled/${name}.gd`, - gdPath: `/Users/johnfn/MyGame/compiled/${name}.gd`, - tsRelativePath: "", - isAutoload: () => false, - gdContainingDirectory: "/Users/johnfn/MyGame/compiled/", - destroy: () => {}, - project: {} as any, - tsType: () => "", - compile: async () => {}, - reload: () => {}, - ...({} as any), - } - - return sourceFileAsset -} diff --git a/tests/test.ts b/tests/test.ts index 7371828e..4e549a87 100644 --- a/tests/test.ts +++ b/tests/test.ts @@ -10,8 +10,10 @@ import { Scope } from "../scope" import { baseContentForTests } from "../generate_library_defs/generate_base" import { ParsedArgs } from "../parse_args" import TsGdProject, { TsGdError, Errors } from "../project" +import { Paths } from "../project/paths" +import { AssetSourceFile } from "../project/assets/asset_source_file" -import { createStubSourceFileAsset } from "./stubs" +import { examplePath } from "./test_utils" export type Test = { expected: @@ -44,12 +46,12 @@ type TestResultFail = { export function compileTs( code: string, - isAutoload: boolean + isAutoload = false ): [ParseNodeType, TsGdError[]] { - const filename = isAutoload ? "autoload.ts" : "Test.ts" + const filename = examplePath(isAutoload ? "Autoload.ts" : "Test.ts") const sourceFile = ts.createSourceFile( - filename, + examplePath(filename), code, ts.ScriptTarget.Latest, true, @@ -95,13 +97,11 @@ export function compileTs( } const program = ts.createProgram( - ["Test.ts", "autoload.ts"], + [examplePath("Test.ts"), examplePath("Autoload.ts")], tsconfigOptions, customCompilerHost ) - const sourceFileAsset = createStubSourceFileAsset("Test") - const args: ParsedArgs = { buildLibraries: false, buildOnly: false, @@ -109,72 +109,23 @@ export function compileTs( debug: false, help: false, init: false, + tsgdPath: examplePath("ts2gd.json"), } - const project: TsGdProject = { + const project = new TsGdProject({ + program, args, - errors: new Errors(args), - buildDynamicDefinitions: async () => {}, - assets: [], - program: undefined as any, - compileAllSourceFiles: async () => true, - shouldBuildLibraryDefinitions: () => false, - validateAutoloads: () => [], - buildLibraryDefinitions: async () => {}, - paths: {} as any, - definitionBuilder: {} as any, - mainScene: { - fsPath: "", - resPath: "", - nodes: [], - resources: [], - name: "mainScene", - project: {} as any, - rootNode: {} as any, - } as any, - godotScenes: () => [], - createAsset: () => 0 as any, - godotFonts: () => [], - godotImages: () => [], - godotGlbs: () => [], - godotProject: { - fsPath: "", - autoloads: [{ resPath: "autoload.ts" }], - mainScene: {} as any, - rawConfig: 0 as any, - actionNames: [], - project: {} as any, - addAutoload: {} as any, - removeAutoload: {} as any, - }, - monitor: () => 0 as any, - onAddAsset: async () => "", - onChangeAsset: async () => "", - onRemoveAsset: async () => {}, - sourceFiles: () => [ - { - exportedTsClassName: () => "", - fsPath: "autoload.ts", - isProjectAutoload: () => true, - isAutoload: () => true, - resPath: "", - tsRelativePath: "", - gdContainingDirectory: "", - destroy: () => {}, - project: {} as any, - tsType: () => "", - compile: async () => {}, - gdPath: "", - reload: () => {}, - isDecoratedAutoload: {} as any, - ...({} as any), // ssh about private properties. - }, - sourceFileAsset, + initialFilePaths: [ + examplePath("project.godot"), + examplePath("main.tscn"), + examplePath("Test.ts"), + examplePath("Autoload.ts"), ], - } + ts2gdJson: new Paths(args), + }) + + const sourceFileAsset = new AssetSourceFile(filename, project) - // TODO: Make this less silly. - // I suppose we could actually use the example project const godotFile = parseNode(sourceFile, { indent: "", sourceFile: sourceFile, @@ -184,7 +135,7 @@ export function compileTs( project, sourceFileAsset: sourceFileAsset, mostRecentControlStructureIsSwitch: false, - isAutoload: false, + isAutoload, usages: utils.collectVariableUsage(sourceFile), }) @@ -229,7 +180,7 @@ const test = ( let errors: TsGdError[] = [] try { - let tuple = compileTs(ts, props.isAutoload ?? false) + let tuple = compileTs(ts, props.isAutoload) compiled = tuple[0] errors = tuple[1] } catch (e) { diff --git a/tests/test_utils.ts b/tests/test_utils.ts new file mode 100644 index 00000000..3f692d29 --- /dev/null +++ b/tests/test_utils.ts @@ -0,0 +1,5 @@ +import path from "path" + +export function examplePath(...segments: string[]): string { + return path.join(process.cwd(), "example/", ...segments) +} diff --git a/tsconfig.json b/tsconfig.json index a6d812da..e17647f7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -29,6 +29,7 @@ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ /* Additional Checks */ + "skipLibCheck": true, // "noUnusedLocals": true, /* Report errors on unused locals. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */