GlassBricks / typed-factorio

Complete and featureful Typescript defintions for the Factorio modding API
MIT License
33 stars 3 forks source link

Issue with import in scenario. #5

Closed jfmmm closed 2 years ago

jfmmm commented 2 years ago

Hi,

I have a problem that I can't seem to find a solution for when trying to add a scenario to a mod with import in it.

Factorio scenarios are placed in a scenarios folder and have their own control.lua.

There I have the following files.

./scenarios/ScenarioName/control.ts

/** @noResolution */
import main from './main';

import handler from 'event_handler';

handler.add_lib(main);

Which compile to

local ____exports = {}
local ____main = require("scenarios.ScenarioName.main") // THIS IS WRONG
local main = ____main.default
local ____event_handler = require("event_handler")
local handler = ____event_handler.default
handler.add_lib(main)
return ____exports

./scenarios/ScenarioName/main.ts

import * as util from 'util';

type EventHandlerSubscription = {
    events?: { [x: number]: (event: any) => void; },
};

const main: EventHandlerSubscription = {};

main.events = {
    [defines.events.on_player_created]: function(event: OnPlayerCreatedEvent) {
        game.print('Player was created' + util.color('red')); // this is just to test importing util
    },
    [defines.events.on_player_respawned]: function(event: OnPlayerRespawnedEvent) {
        game.print('Player was respawned');
    }
};

export default main;

Which compile to

local ____exports = {}
local util = require("util")
local main = {}
main.events = {
    [defines.events.on_player_created] = function(event)
        game.print(
            "Player was created caliss" .. tostring(
                util.color("red")
            )
        )
    end,
    [defines.events.on_player_respawned] = function(event)
        game.print("Player was respawned caliss")
    end
}
____exports.default = main
return ____exports

Notice how scenarios.ScenarioName.main is the required path when I import main instead of just being main.

@noResolution should force it to stay what it was in the ­.ts file but that won't work there for some reason.

I also tryed setting a rootdir for it in my tsconfig but not luck there either

{
  "compilerOptions": {
    "target": "esnext",
    "lib": [
      "esnext"
    ],
    "moduleResolution": "node",
    "strict": true,
    "sourceMap": true,
    "types": [ "typed-factorio/runtime"  ],
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "rootDirs": [
      "scenarios/ScenarioName"       <<--------
    ]
  },
  "tstl": {
    "luaTarget": "JIT",
    "noHeader": false,
    "noImplicitSelf": true,
    "sourceMapTraceback": false
  },
  "include": [
    "./**/*",
  ]
}

any idea?

GlassBricks commented 2 years ago

Due to the way typescript/tstl works, I don't think there's a "built-in" solution to this. However, one way to handle this is have the control.lua file "redirect" to another file in your mod. You would need require("__modname__.path.to.file") to import a mod file from a scenario script anyways; scenarios are run independently of the mod, and so relative require won't work.

//  scenario control.ts

if (!script.active_mods["your_mod_name"]) {
    error("<<your mod>> is requried to run this scenario")
}
/** @noResolution */
declare module "__modname__/scenarioControl" {}
import "__modname__/scenarioControl";

// You can also use a .lua file directly and skip the .ts file
//  scenarioControl.ts
import ...
// business as usual
GlassBricks commented 2 years ago

Another solution is to have a separate tsconfig.json file for each scenario, treating it like a separate project. However, this will make it harder to import files from the mod files. This would be the better option if you are making a "soft" mod/scenario script only.

@noResolution should force it to stay what it was in the ­.ts file but that won't work there for some reason.

I believe @noResolution is supposed to be used on declare module statements. As a side note, you may want to check out the "noResolvePaths" option introduced in TSTL v1.1.0: https://github.com/TypeScriptToLua/TypeScriptToLua/blob/master/CHANGELOG.md#110.

jfmmm commented 2 years ago

I knew scenario were run separately but I though relative import would work in that folder like it was it's own mod.

I ended up just having a .lua file in the scenarios folder and having the rest at the root. I plan on sharing stuff between the scenario and the rest of my mod so this is perfect.

Thanks for your help!