Skip to content

Commit

Permalink
Merge pull request #42 from GlassBricks/factorio-v2.0
Browse files Browse the repository at this point in the history
Update to Factorio v2.0!!
  • Loading branch information
GlassBricks authored Oct 30, 2024
2 parents 3e94577 + 417ed7d commit eff9f5b
Show file tree
Hide file tree
Showing 38 changed files with 147,612 additions and 102,267 deletions.
8 changes: 8 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# v3.0.0

- Updated to factorio 2.0!! SPAAACE!!
- Simplified types for ChooseElemButtonSpec; it is no longer a discriminated union for each subtype.
- Iteration key type for `LuaCustomTable`s are now accurate.

The major version has been bumped to reflect breaking changes in the API. However, the way the api is accessed has not changed.

# v2.14.0

- Updated to a newer revision of factorio version 1.1.110
Expand Down
9 changes: 6 additions & 3 deletions generator/FactorioPrototypeApiJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,28 @@ import { Expansions } from "./FactorioRuntimeApiJson"

export interface FactorioPrototypeApiJson {
application: "factorio"
stage: "prototype"
application_version: string
api_version: 5
api_version: 6
stage: "prototype"

prototypes: Prototype[]
types: PrototypeConcept[]
}

export interface BasicMember {
name: string
order: number
readonly description: string
}

export interface PrototypeWithExamples {
lists?: string[]
examples?: string[]
images?: Image[]
}

export interface Prototype extends BasicMember, PrototypeWithExamples {
visibility: Expansions
visibility?: Expansions[]
parent?: string
abstract: boolean
typename?: string
Expand Down Expand Up @@ -56,6 +58,7 @@ export interface ArrayType {
complex_type: "array"
value: Type
}

export interface DictionaryType {
complex_type: "dictionary"
key: Type
Expand Down
10 changes: 6 additions & 4 deletions generator/FactorioRuntimeApiJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
export interface FactorioRuntimeApiJson {
application: "factorio"
application_version: string
api_version: 5
api_version: 6
stage: "runtime"

classes: Class[]
Expand All @@ -27,6 +27,7 @@ export interface BasicMember extends BasicObject {
}

export type Expansions = "space_age"

export interface Class extends BasicMember {
visibility?: Expansions[]
parent: string
Expand Down Expand Up @@ -170,10 +171,12 @@ export interface Method extends BasicMember, WithVariantParameterGroups {

return_values: Omit<Parameter, "name">[]
}

export interface VariadicParameter {
type?: Type
description: string
}

export interface MethodFormat {
takes_table: boolean
table_optional?: boolean
Expand All @@ -183,10 +186,9 @@ export interface Attribute extends BasicMember {
visibility?: Expansions[]
raises?: EventRaised[]
subclasses?: string[]
type: Type
optional: boolean
read: boolean
write: boolean
read_type?: Type
write_type?: Type
}

export interface EventRaised extends BasicMember {
Expand Down
21 changes: 9 additions & 12 deletions generator/GenerationContext.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import chalk from "chalk"
import ts from "typescript"
import { ModuleType, OutputFile, OutputFileBuilder, OutputFileBuilderImpl } from "./OutputFile.js"
import { checkManualDefinitions, processManualDefinitions } from "./manualDefinitions.js"
Expand All @@ -8,7 +7,7 @@ import * as prototype from "./FactorioPrototypeApiJson.js"
export interface AnyApiJson {
application: "factorio"
stage: string
api_version: 5
api_version: 6
application_version: string
}

Expand All @@ -22,13 +21,16 @@ export abstract class GenerationContext<A extends AnyApiJson = AnyApiJson> {

hasWarnings = false

public readonly manualDefs = processManualDefinitions(this.manualDefinitionsSource)
public readonly manualDefs

constructor(
public readonly apiDocs: A,
public readonly manualDefinitionsSource: ts.SourceFile,
public readonly checker: ts.TypeChecker,
public readonly options: Options,
) {}
) {
this.manualDefs = processManualDefinitions(this.manualDefinitionsSource)
}

abstract get stageName(): string

Expand Down Expand Up @@ -59,12 +61,13 @@ export abstract class GenerationContext<A extends AnyApiJson = AnyApiJson> {
}

protected abstract preprocessAll(): void

protected abstract generateAll(): void

private checkApiDocs() {
for (const [k, v] of Object.entries({
application: "factorio",
api_version: 5,
api_version: 6,
stage: this.stageName,
})) {
if (this.apiDocs[k as keyof AnyApiJson] !== v) {
Expand All @@ -74,16 +77,10 @@ export abstract class GenerationContext<A extends AnyApiJson = AnyApiJson> {
}

warning(...args: unknown[]): void {
console.log(chalk.yellow(...args))
console.error(...args)
this.hasWarnings = true
}

warnIfHasVisibility(obj: { visibility?: string[] }): void {
if (obj.visibility && obj.visibility.length > 1) {
this.warning("Visibility not implemented yet")
}
}

generate(): OutputFile[] {
this.checkApiDocs()
this.preprocessAll()
Expand Down
2 changes: 1 addition & 1 deletion generator/OutputFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export enum ModuleType {
export class OutputFileBuilderImpl implements OutputFileBuilder {
private statements: ts.Statement[] = []
private endStatements: ts.Statement[] = []
private imports = new Map<string, Set<string>>()
private imports = new Map<ModuleType, Set<string>>()

constructor(
private manualDefs: ManualDefinitions,
Expand Down
22 changes: 22 additions & 0 deletions generator/builtin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { GenerationContext } from "./GenerationContext"
import type * as runtime from "./FactorioRuntimeApiJson"
import type * as prototype from "./FactorioPrototypeApiJson"
import { addJsDoc } from "./documentation"

export function generateBuiltinType(
context: GenerationContext,
concept: runtime.Concept | prototype.PrototypeConcept,
): void {
const name = concept.name
if (name === "boolean" || name === "string" || name === "number") return
const existing = context.manualDefs.getDeclaration(name)
if (!existing) {
context.warning(`No existing definition for builtin ${name}`)
return undefined
}
if (existing.annotations.omit) {
return undefined
}
addJsDoc(context, existing.node, concept, name)
context.currentFile.add(existing.node)
}
67 changes: 41 additions & 26 deletions generator/documentation.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import ts from "typescript"
import { EventRaised } from "./FactorioRuntimeApiJson.js"
import { EventRaised, Expansions } from "./FactorioRuntimeApiJson.js"
import { getMappedEventName } from "./runtime/events.js"
import { addFakeJSDoc } from "./genUtil.js"
import { byOrder } from "./util.js"
Expand All @@ -15,25 +15,26 @@ export interface Documentable extends PrototypeWithExamples {
instance_limit?: number
default?: string | LiteralType
deprecated?: boolean
visibility?: Expansions[]
}
const pageLinks = new Set([
"global",

const auxiliaryPages = new Set([
"storage",
"data-lifecycle",
"migrations",
"classes",
"concepts",
"events",
"defines",
"prototypes",
"libraries",
"prototype-tree",
"noise-expressions",
"instrument",
])
const otherPages = new Set(["classes", "concepts", "events", "defines", "prototypes"])

function mapLink(context: GenerationContext, origLink: string): string | undefined {
if (origLink.match(/^http(s?):\/\//)) {
return origLink
}
// hardcoded exception
if (origLink === "libraries.html") {
return context.docUrlBase() + "libraries.html"
if (origLink.endsWith(".html") && auxiliaryPages.has(origLink.slice(0, -5))) {
return `${context.docUrlBase()}auxiliary/${origLink}`
}

const match = origLink.match(/(.*?):(.*?)(?:::(.*))?$/)
Expand All @@ -43,8 +44,11 @@ function mapLink(context: GenerationContext, origLink: string): string | undefin
}
const [, stage, name, member] = match

if (pageLinks.has(name)) {
return context.docUrlBase() + name + ".html"
if (auxiliaryPages.has(name)) {
return `${context.docUrlBase()}auxiliary/${name}.html`
}
if (otherPages.has(name)) {
return `${context.docUrlBase()}${name}.html`
}

if (stage !== "runtime" && stage !== "prototype") {
Expand Down Expand Up @@ -86,6 +90,7 @@ export function processDescription(
if (!description) return undefined
let result = ""

// Warning: ugly regex ahead
for (const [, text, codeBlock] of description.matchAll(/((?:(?!```).)*)(?:$|```((?:(?!```).)*)```)/gs)) {
let withLinks = text.replace(/\[(?!\[)(.+?)]\((.+?)\)/g, (_, name: string, origLink: string) => {
if (name === "string" || name === "number" || name === "boolean") {
Expand All @@ -101,7 +106,6 @@ export function processDescription(
return `{@${tag} ${link} ${name}}`
}
})
// .replace("__1__\n ", "__1__") // fix for LocalisedString description
if (normalizeNewlines) {
withLinks = withLinks.replace(/\n(?!([\n-]))/g, "\n\n")
}
Expand All @@ -113,14 +117,14 @@ export function processDescription(
return result
}

function getDefaultComment(element: Documentable): string | undefined {
function getCommentForDefaultValue(element: Documentable): string | undefined {
const defaultValue = element.default
if (defaultValue === undefined) return
const defaultAsStr = typeof defaultValue === "string" ? defaultValue : JSON.stringify(defaultValue.value)
return `**Default:** \`${defaultAsStr}\``
}

function getRaisesComment(context: GenerationContext, raises: EventRaised[] | undefined): string | undefined {
function getCommentForEventRaised(context: GenerationContext, raises: EventRaised[] | undefined): string | undefined {
if (!raises || raises.length === 0) return
let result = "## Raised events\n"
for (const event of raises.sort(byOrder)) {
Expand All @@ -135,7 +139,7 @@ function getRaisesComment(context: GenerationContext, raises: EventRaised[] | un
return result
}

function getSubclassesComment(subclasses: string[] | undefined): string | undefined {
function getCommentForSubclasses(subclasses: string[] | undefined): string | undefined {
if (!subclasses || subclasses.length === 0) return
return `_Can only be used if this is ${
subclasses.length === 1
Expand All @@ -144,12 +148,12 @@ function getSubclassesComment(subclasses: string[] | undefined): string | undefi
}_`
}

function getInstanceLimitComment(instanceLimit: number | undefined): string | undefined {
function getCommentForInstanceLimit(instanceLimit: number | undefined): string | undefined {
if (!instanceLimit) return
return `_Prototype limited to **${instanceLimit}** total instances_`
}

function getListsComment(element: Documentable, onlineReference: string | undefined): string | undefined {
function getCommentForDocLists(element: Documentable, onlineReference: string | undefined): string | undefined {
if (!element.lists) return
assert(onlineReference)
return element.lists
Expand All @@ -161,7 +165,7 @@ function getListsComment(element: Documentable, onlineReference: string | undefi
.join("\n\n")
}

function getImages(context: GenerationContext, element: Documentable): string | undefined {
function getCommentForDocImages(context: GenerationContext, element: Documentable): string | undefined {
if (!element.images) return
return element.images
.map((image) => {
Expand All @@ -178,6 +182,16 @@ function processExample(context: GenerationContext, example: string): string {
return result.replaceAll("\n", "\n * ")
}

const expansionComments: Record<Expansions, string> = {
space_age:
"![Space Age](https://wiki.factorio.com/images/thumb/Space_age_icon.png/16px-Space_age_icon.png) ***Space Age*** required to use.",
}

function getCommentForExpansions(element: Documentable): string | undefined {
if (!element.visibility || element.visibility.length === 0) return
return element.visibility.map((expansion) => expansionComments[expansion]).join("\n\n")
}

export function createTag(tag: string, comment?: string): ts.JSDocUnknownTag {
return ts.factory.createJSDocUnknownTag(ts.factory.createIdentifier(tag), comment)
}
Expand All @@ -197,15 +211,16 @@ export function addJsDoc<T extends ts.Node>(
const onlineDocUrl = onlineReferenceName && context.getOnlineDocUrl(onlineReferenceName)

const comment = [
getDefaultComment(element),
getCommentForExpansions(element),
getCommentForDefaultValue(element),
additions.pre && processDescription(context, additions.pre),
processDescription(context, element.description),
additions.post && processDescription(context, additions.post),
getRaisesComment(context, element.raises),
getSubclassesComment(element.subclasses),
getInstanceLimitComment(element.instance_limit),
getListsComment(element, onlineDocUrl),
getImages(context, element),
getCommentForEventRaised(context, element.raises),
getCommentForSubclasses(element.subclasses),
getCommentForInstanceLimit(element.instance_limit),
getCommentForDocLists(element, onlineDocUrl),
getCommentForDocImages(context, element),
]
.filter((x) => x)
.join("\n\n")
Expand Down
12 changes: 6 additions & 6 deletions generator/input/manual-defs-prototype.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@ export type float = number
export type int8 = number
export type int16 = number
export type int32 = number
export type int64 = number
export type uint8 = number
export type uint16 = number
export type uint32 = number
export type uint64 = number

/** @omit */
export type DataExtendMethod = unknown
export interface DataExtendMethod {}

export interface Data {
raw: {
readonly [Type in keyof PrototypeMap]: {
readonly [Type in PrototypeType]: {
readonly [Name in string]?: PrototypeMap[Type]
}
}
Expand All @@ -27,16 +28,15 @@ export interface Data {
extend<P extends AnyPrototype>(prototypes: readonly P[]): void
}

/** @unionAdd */
export type CollisionMaskLayer = `layer-${bigint}`

/** @replace */
export type LocalisedString = string | number | boolean | undefined | readonly [string, ...LocalisedString[]]

interface PrototypeMap {}

type PrototypeType = keyof PrototypeMap

interface PrototypeBase {
type: keyof PrototypeMap
type: PrototypeType
}

interface FluidBox {}
Expand Down
Loading

0 comments on commit eff9f5b

Please sign in to comment.